Move loop inside a function to reduce the number of calls

In a profile of scour on a given input file,
removeDefaultAttributeValue is one of the top 3 most frequent function
being called with 332288 calls (with minidom.getAttribute and
minidom.hasAttribute being the only ones with similar number of
calls).

The high number of calls occurs because removeDefaultAttributeValue
only removes a single attribute at a time.  Given it is always called
in a trivial for loop, we can just move the loop inside
removeDefaultAttributeValue to reduce the number of calls.  At the
same time, rename the function to better reflect that it works on
multiple attributes.

Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
Niels Thykier 2018-02-17 13:44:44 +00:00
parent c182faba0d
commit 8c9c6253b9

View file

@ -1896,34 +1896,38 @@ def taint(taintedSet, taintedAttribute):
return taintedSet return taintedSet
def removeDefaultAttributeValue(node, attribute): def removeDefaultAttributeValuesFromNode(node, attributes):
""" """
Removes the DefaultAttribute 'attribute' from 'node' if specified conditions are fulfilled Removes each of the 'DefaultAttribute's from 'node' if specified conditions are fulfilled
""" """
if not node.hasAttribute(attribute.name): count = 0
return 0 for attribute in attributes:
if not node.hasAttribute(attribute.name):
continue
if (attribute.elements is not None) and (node.nodeName not in attribute.elements): if (attribute.elements is not None) and (node.nodeName not in attribute.elements):
return 0 continue
# differentiate between text and numeric values # differentiate between text and numeric values
if isinstance(attribute.value, str): if isinstance(attribute.value, str):
if node.getAttribute(attribute.name) == attribute.value: if node.getAttribute(attribute.name) == attribute.value:
if (attribute.conditions is None) or attribute.conditions(node):
node.removeAttribute(attribute.name)
return 1
else:
nodeValue = SVGLength(node.getAttribute(attribute.name))
if ((attribute.value is None)
or ((nodeValue.value == attribute.value) and not (nodeValue.units == Unit.INVALID))):
if ((attribute.units is None)
or (nodeValue.units == attribute.units)
or (isinstance(attribute.units, list) and nodeValue.units in attribute.units)):
if (attribute.conditions is None) or attribute.conditions(node): if (attribute.conditions is None) or attribute.conditions(node):
node.removeAttribute(attribute.name) node.removeAttribute(attribute.name)
return 1 count += 1
continue
else:
nodeValue = SVGLength(node.getAttribute(attribute.name))
if ((attribute.value is None)
or ((nodeValue.value == attribute.value) and not (nodeValue.units == Unit.INVALID))):
if ((attribute.units is None)
or (nodeValue.units == attribute.units)
or (isinstance(attribute.units, list) and nodeValue.units in attribute.units)):
if (attribute.conditions is None) or attribute.conditions(node):
node.removeAttribute(attribute.name)
count += 1
continue
return 0 return count
def removeDefaultAttributeValues(node, options, tainted=set()): def removeDefaultAttributeValues(node, options, tainted=set()):
@ -1935,8 +1939,7 @@ def removeDefaultAttributeValues(node, options, tainted=set()):
return 0 return 0
# Conditionally remove all default attributes defined in 'default_attributes' (a list of 'DefaultAttribute's) # Conditionally remove all default attributes defined in 'default_attributes' (a list of 'DefaultAttribute's)
for attribute in default_attributes: num += removeDefaultAttributeValuesFromNode(node, default_attributes)
num += removeDefaultAttributeValue(node, attribute)
# Summarily get rid of default properties # Summarily get rid of default properties
attributes = [node.attributes.item(i).nodeName for i in range(node.attributes.length)] attributes = [node.attributes.item(i).nodeName for i in range(node.attributes.length)]