scripts: Optimize expensive xml lookups
4x speedup in codegen by fetching type information ahead of time instead
of doing repeated ad-hoc queries on the whole tree
Change-Id: Iba5625b830aa09baaf21f1eb16957d2f67d5d24a
diff --git a/scripts/common_codegen.py b/scripts/common_codegen.py
index d9fcbed..4adb329 100644
--- a/scripts/common_codegen.py
+++ b/scripts/common_codegen.py
@@ -21,7 +21,7 @@
import os,re,sys,string
import xml.etree.ElementTree as etree
from generator import *
-from collections import namedtuple
+from collections import namedtuple, OrderedDict
# Copyright text prefixing all headers (list of strings).
prefixStrings = [
@@ -72,13 +72,24 @@
protect = platform_dict[platform]
return protect
-# Check if an object is a non-dispatchable handle
-def IsHandleTypeNonDispatchable(tree, handletype):
- handle = tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
- return True
- else:
- return False
+# Return a dict containing the dispatchable/non-dispatchable type of every handle
+def GetHandleTypes(tree):
+ handles = OrderedDict()
+ for elem in tree.findall("types/type/[@category='handle']"):
+ if not elem.get('alias'):
+ name = elem.get('name')
+ handles[name] = elem.find('type').text
+ return handles
+
+# Return a dict containing the category attribute of every type
+def GetTypeCategories(tree):
+ type_categories = OrderedDict()
+ for elem in tree.findall("types/type"):
+ if not elem.get('alias'):
+ # name is either an attribute or the text of a child <name> tag
+ name = elem.get('name') or (elem.find("name") and elem.find('name').text)
+ type_categories[name] = elem.get('category')
+ return type_categories
# Treats outdents a multiline string by the leading whitespace on the first line
# Optionally indenting by the given prefix
diff --git a/scripts/dispatch_table_helper_generator.py b/scripts/dispatch_table_helper_generator.py
index 0fb8f53..8d202c9 100644
--- a/scripts/dispatch_table_helper_generator.py
+++ b/scripts/dispatch_table_helper_generator.py
@@ -79,6 +79,10 @@
# Called once at the beginning of each run
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
+
write("#pragma once", file=self.outFile)
# User-supplied prefix text, if any (list of strings)
if (genOpts.prefixText):
@@ -168,8 +172,7 @@
#
# Determine if this API should be ignored or added to the instance or device dispatch table
def AddCommandToDispatchList(self, name, handle_type, protect, cmdinfo):
- handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
- if handle is None:
+ if handle_type not in self.handle_types:
return
if handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice' and name != 'vkGetInstanceProcAddr':
self.device_dispatch_list.append((name, self.featureExtraProtect))
diff --git a/scripts/helper_file_generator.py b/scripts/helper_file_generator.py
index 9a8b60f..4e2aa47 100644
--- a/scripts/helper_file_generator.py
+++ b/scripts/helper_file_generator.py
@@ -106,6 +106,8 @@
# Called once at the beginning of each run
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
# User-supplied prefix text, if any (list of strings)
self.helper_file_type = genOpts.helper_file_type
self.library_name = genOpts.library_name
@@ -305,16 +307,14 @@
type_key = 'VK_DEFINE_HANDLE'
else:
type_key = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'
- handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
- if handle is not None and handle.find('type').text == type_key:
+ if self.handle_types.get(handle_type) == type_key:
return True
# if handle_type is a struct, search its members
if handle_type in self.structNames:
member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == handle_type), None)
if member_index is not None:
for item in self.structMembers[member_index].members:
- handle = self.registry.tree.find("types/type/[name='" + item.type + "'][@category='handle']")
- if handle is not None and handle.find('type').text == type_key:
+ if self.handle_types.get(item.type) == type_key:
return True
return False
#
@@ -687,7 +687,7 @@
type_list.append(enum_entry)
object_type_info[enum_entry] = { 'VkType': item }
# We'll want lists of the dispatchable and non dispatchable handles below with access to the same info
- if IsHandleTypeNonDispatchable(self.registry.tree, item) :
+ if self.handle_types.get(item) == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
non_dispatchable[item] = enum_entry
else:
dispatchable[item] = enum_entry
diff --git a/scripts/layer_chassis_dispatch_generator.py b/scripts/layer_chassis_dispatch_generator.py
index 481a214..59875d5 100644
--- a/scripts/layer_chassis_dispatch_generator.py
+++ b/scripts/layer_chassis_dispatch_generator.py
@@ -1083,6 +1083,10 @@
#
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
+ self.type_categories = GetTypeCategories(self.registry.tree)
+ # Output Copyright
self.appendSection('header_file', self.inline_copyright_message)
# Multiple inclusion protection & C++ namespace.
self.header = False
@@ -1179,20 +1183,9 @@
ispointer = True
return ispointer
#
- # Get the category of a type
- def getTypeCategory(self, typename):
- types = self.registry.tree.findall("types/type")
- for elem in types:
- if (elem.find("name") is not None and elem.find('name').text == typename) or elem.attrib.get('name') == typename:
- return elem.attrib.get('category')
- #
# Check if a parent object is dispatchable or not
def isHandleTypeNonDispatchable(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
- return True
- else:
- return False
+ return self.handle_types.get(handletype) == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'
#
# Retrieve the type and name for a parameter
def getTypeNameTuple(self, param):
@@ -1304,7 +1297,7 @@
struct_list = set()
for item in item_list:
paramtype = item.find('type')
- typecategory = self.getTypeCategory(paramtype.text)
+ typecategory = self.type_categories[paramtype.text]
if typecategory == 'struct':
if self.struct_contains_ndo(paramtype.text) == True:
struct_list.add(item)
diff --git a/scripts/layer_chassis_generator.py b/scripts/layer_chassis_generator.py
index 82a2486..ca9c31b 100644
--- a/scripts/layer_chassis_generator.py
+++ b/scripts/layer_chassis_generator.py
@@ -1502,23 +1502,17 @@
# Check if an object is a non-dispatchable handle
def isHandleTypeNonDispatchable(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
- return True
- else:
- return False
+ return self.handle_types.get(handletype) == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'
# Check if an object is a dispatchable handle
def isHandleTypeDispatchable(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
- return True
- else:
- return False
+ return self.handle_types.get(handletype) == 'VK_DEFINE_HANDLE'
#
#
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
# Output Copyright
write(self.inline_copyright_message, file=self.outFile)
# Multiple inclusion protection
diff --git a/scripts/layer_dispatch_table_generator.py b/scripts/layer_dispatch_table_generator.py
index 058598d..85b9cd7 100644
--- a/scripts/layer_dispatch_table_generator.py
+++ b/scripts/layer_dispatch_table_generator.py
@@ -93,6 +93,9 @@
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
+
# User-supplied prefix text, if any (list of strings)
if (genOpts.prefixText):
for s in genOpts.prefixText:
@@ -198,8 +201,6 @@
#
# Determine if this API should be ignored or added to the instance or device dispatch table
def AddCommandToDispatchList(self, extension_name, extension_type, name, cmdinfo, handle_type):
- handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']")
-
return_type = cmdinfo.elem.find('proto/type')
if (return_type is not None and return_type.text == 'void'):
return_type = None
@@ -223,7 +224,7 @@
cmd_params.append(self.CommandParam(type=param_type, name=param_name,
cdecl=param_cdecl))
- if handle is not None and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
+ if handle_type in self.handle_types and handle_type != 'VkInstance' and handle_type != 'VkPhysicalDevice':
# The Core Vulkan code will be wrapped in a feature called VK_VERSION_#_#
# For example: VK_VERSION_1_0 wraps the core 1.0 Vulkan functionality
if 'VK_VERSION_' in extension_name:
diff --git a/scripts/object_tracker_generator.py b/scripts/object_tracker_generator.py
index 60ffdea..e0a2afa 100644
--- a/scripts/object_tracker_generator.py
+++ b/scripts/object_tracker_generator.py
@@ -346,6 +346,10 @@
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
+ self.type_categories = GetTypeCategories(self.registry.tree)
+
header_file = (genOpts.filename == 'object_tracker.h')
source_file = (genOpts.filename == 'object_tracker.cpp')
@@ -498,28 +502,13 @@
ispointer = True
return ispointer
#
- # Get the category of a type
- def getTypeCategory(self, typename):
- types = self.registry.tree.findall("types/type")
- for elem in types:
- if (elem.find("name") is not None and elem.find('name').text == typename) or elem.attrib.get('name') == typename:
- return elem.attrib.get('category')
- #
# Check if a parent object is dispatchable or not
def isHandleTypeObject(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None:
- return True
- else:
- return False
+ return handletype in self.handle_types
#
# Check if a parent object is dispatchable or not
def isHandleTypeNonDispatchable(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
- return True
- else:
- return False
+ return self.handle_types.get(handletype) == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'
#
# Retrieve the type and name for a parameter
def getTypeNameTuple(self, param):
@@ -628,7 +617,7 @@
struct_list = set()
for item in item_list:
paramtype = item.find('type')
- typecategory = self.getTypeCategory(paramtype.text)
+ typecategory = self.type_categories[paramtype.text]
if typecategory == 'struct':
if self.struct_contains_object(paramtype.text) == True:
struct_list.add(item)
diff --git a/scripts/thread_safety_generator.py b/scripts/thread_safety_generator.py
index 91afab2..54cef56 100644
--- a/scripts/thread_safety_generator.py
+++ b/scripts/thread_safety_generator.py
@@ -683,19 +683,11 @@
# Check if an object is a non-dispatchable handle
def isHandleTypeNonDispatchable(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE':
- return True
- else:
- return False
+ return self.handle_types.get(handletype) == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE'
# Check if an object is a dispatchable handle
def isHandleTypeDispatchable(self, handletype):
- handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']")
- if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE':
- return True
- else:
- return False
+ return self.handle_types.get(handletype) == 'VK_DEFINE_HANDLE'
def makeThreadUseBlock(self, cmd, functionprefix):
"""Generate C function pointer typedef for <command> Element"""
@@ -808,7 +800,10 @@
return paramdecl
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
- #
+
+ # Initialize members that require the tree
+ self.handle_types = GetHandleTypes(self.registry.tree)
+
# TODO: LUGMAL -- remove this and add our copyright
# User-supplied prefix text, if any (list of strings)
write(self.inline_copyright_message, file=self.outFile)