mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-07-30 07:44:13 +02:00
XmlElementCollection::child(): linear sibling walk instead of item(i)
The child lookup iterated parent_element.childNodes() via item(i), and
QDomNodeList::item() walks the sibling chain from the start on every
call - making the loop quadratic in the number of children, with an
extra QList allocation and a second pass on top. This lookup runs
several times per element instance while loading a project, against the
"import" category that holds every embedded definition, so the cost
scales with (instances x embedded definitions).
Replace it with a firstChildElement()/nextSiblingElement() walk with an
early return. Same semantics (first tag+name match in document order).
Measured on the Kaefer_1303 reference project (3.9 MB, 23 folios,
432 instances, media of 6 runs, Windows/MinGW, same GCC for both):
before after
Qt5 5.116 s 5.068 s
Qt6 6.683 s 4.640 s (-31 %)
This removes the entire Qt6 load-time regression discussed in #553 -
Qt6 goes from +31 % slower to 8 % faster than Qt5 on the very project
that exposed it (Qt6''s QDom makes the quadratic pattern much more
expensive than Qt5''s did). Smaller projects gain too (3.4 MB example:
-9 % on Qt6).
(cherry picked from commit 0d4ef8eca27601c37ba2b75d7c058e9d8e2beea4)
This commit is contained in:
@@ -186,23 +186,22 @@ QDomElement XmlElementCollection::child(const QDomElement &parent_element,
|
|||||||
if (parent_element.ownerDocument() != m_dom_document)
|
if (parent_element.ownerDocument() != m_dom_document)
|
||||||
return QDomElement();
|
return QDomElement();
|
||||||
|
|
||||||
//Get all childs element of parent_element
|
/* Walk the siblings directly instead of the previous
|
||||||
QDomNodeList child_list = parent_element.childNodes();
|
* childNodes()+item(i) double pass: QDomNodeList::item(i) restarts
|
||||||
QString tag_name(child_name.endsWith(".elmt")? "element" : "category");
|
* from the first child every call, which made this loop quadratic
|
||||||
QList <QDomElement> found_dom_element;
|
* in the number of children. This lookup runs several times per
|
||||||
for (int i=0 ; i<child_list.length() ; i++)
|
* element instance while loading a project, on the "import"
|
||||||
|
* category that holds every embedded definition. */
|
||||||
|
const QString tag_name = child_name.endsWith(QLatin1String(".elmt"))
|
||||||
|
? QStringLiteral("element") : QStringLiteral("category");
|
||||||
|
for (QDomElement child_element = parent_element.firstChildElement(tag_name) ;
|
||||||
|
!child_element.isNull() ;
|
||||||
|
child_element = child_element.nextSiblingElement(tag_name))
|
||||||
{
|
{
|
||||||
QDomElement child_element = child_list.item(i).toElement();
|
if (child_element.attribute(QStringLiteral("name")) == child_name)
|
||||||
if (child_element.tagName() == tag_name)
|
return child_element;
|
||||||
found_dom_element << child_element;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_dom_element.isEmpty()) return QDomElement();
|
|
||||||
|
|
||||||
foreach (QDomElement elmt, found_dom_element)
|
|
||||||
if (elmt.attribute("name") == child_name)
|
|
||||||
return elmt;
|
|
||||||
|
|
||||||
return QDomElement();
|
return QDomElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user