hi, I am still not happy with the time it takes for gtk-doc to generate the html. I did some profiling and tired various changes. Its not too impressive. Just posting them here for feedback and comment on the directions of what would be acceptable or not. I technically have commit rights, so I can push things once they are ready. If patch 0002 looks like a good idea, I can extend it for other accessors.
Stefan Test case was generating the html for gstreamer-core api docs real user sys ------------------------------ before 1m22.872s 1m17.317s 0m1.444s 1m19.261s 1m17.437s 0m1.384s 1m19.770s 1m17.417s 0m1.264s ------------------------------ 0001-xpath-annotate-branch-prediction.patch 1m18.123s 1m16.677s 0m1.256s 1m18.684s 1m17.181s 0m1.292s 1m18.887s 1m17.217s 0m1.364s ------------------------------ 0002-xpath-split-traversal-into-init-and-next-functions.patch 1m18.537s 1m16.925s 0m1.388s 1m18.616s 1m16.913s 0m1.412s 1m18.249s 1m16.653s 0m1.328s ------------------------------ 0003-xpath-avoid-a-memcpy-on-the-expense-of-temporarily-w.patch 1m17.481s 1m16.137s 0m1.208s 1m17.977s 1m16.481s 0m1.328s 1m17.791s 1m16.413s 0m1.232s
>From 144d36fbdd4ff3fec27f50189617bdeb8979a4bf Mon Sep 17 00:00:00 2001 From: Stefan Kost <[email protected]> Date: Tue, 3 May 2011 17:21:57 +0300 Subject: [PATCH 1/4] xpath: annotate branch prediction --- include/libxml/xpathInternals.h | 29 ++++++++++++++------ xpath.c | 56 ++++++++++++++++++++------------------ 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/include/libxml/xpathInternals.h b/include/libxml/xpathInternals.h index dcd5243..f384e1a 100644 --- a/include/libxml/xpathInternals.h +++ b/include/libxml/xpathInternals.h @@ -21,6 +21,17 @@ extern "C" { #endif +/* + * Ideally have this for whole libxml2 + */ +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define XML_LIKELY(expr) (__builtin_expect ((expr), 1)) +#define XML_UNLIKELY(expr) (__builtin_expect ((expr), 0)) +#else +#define XML_LIKELY(expr) (expr) +#define XML_UNLIKELY(expr) (expr) +#endif + /************************************************************************ * * * Helpers * @@ -237,7 +248,7 @@ XMLPUBFUN void * XMLCALL * Macro to return from the function if an XPath error was detected. */ #define CHECK_ERROR \ - if (ctxt->error != XPATH_EXPRESSION_OK) return + if (XML_UNLIKELY (ctxt->error != XPATH_EXPRESSION_OK)) return /** * CHECK_ERROR0: @@ -245,7 +256,7 @@ XMLPUBFUN void * XMLCALL * Macro to return 0 from the function if an XPath error was detected. */ #define CHECK_ERROR0 \ - if (ctxt->error != XPATH_EXPRESSION_OK) return(0) + if (XML_UNLIKELY (ctxt->error != XPATH_EXPRESSION_OK)) return(0) /** * XP_ERROR: @@ -273,7 +284,7 @@ XMLPUBFUN void * XMLCALL * type. */ #define CHECK_TYPE(typeval) \ - if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + if (XML_UNLIKELY ((ctxt->value == NULL) || (ctxt->value->type != typeval))) \ XP_ERROR(XPATH_INVALID_TYPE) /** @@ -284,7 +295,7 @@ XMLPUBFUN void * XMLCALL * type. Return(0) in case of failure */ #define CHECK_TYPE0(typeval) \ - if ((ctxt->value == NULL) || (ctxt->value->type != typeval)) \ + if (XML_UNLIKELY ((ctxt->value == NULL) || (ctxt->value->type != typeval))) \ XP_ERROR0(XPATH_INVALID_TYPE) /** @@ -294,8 +305,8 @@ XMLPUBFUN void * XMLCALL * Macro to check that the number of args passed to an XPath function matches. */ #define CHECK_ARITY(x) \ - if (ctxt == NULL) return; \ - if (nargs != (x)) \ + if (XML_UNLIKELY (ctxt == NULL)) return; \ + if (XML_UNLIKELY (nargs != (x))) \ XP_ERROR(XPATH_INVALID_ARITY); /** @@ -304,7 +315,7 @@ XMLPUBFUN void * XMLCALL * Macro to try to cast the value on the top of the XPath stack to a string. */ #define CAST_TO_STRING \ - if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING)) \ + if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING))) \ xmlXPathStringFunction(ctxt, 1); /** @@ -313,7 +324,7 @@ XMLPUBFUN void * XMLCALL * Macro to try to cast the value on the top of the XPath stack to a number. */ #define CAST_TO_NUMBER \ - if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER)) \ + if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER))) \ xmlXPathNumberFunction(ctxt, 1); /** @@ -322,7 +333,7 @@ XMLPUBFUN void * XMLCALL * Macro to try to cast the value on the top of the XPath stack to a boolean. */ #define CAST_TO_BOOLEAN \ - if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN)) \ + if (XML_LIKELY ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN))) \ xmlXPathBooleanFunction(ctxt, 1); /* diff --git a/xpath.c b/xpath.c index 608fe00..579db1b 100644 --- a/xpath.c +++ b/xpath.c @@ -2410,7 +2410,7 @@ valuePop(xmlXPathParserContextPtr ctxt) { xmlXPathObjectPtr ret; - if ((ctxt == NULL) || (ctxt->valueNr <= 0)) + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->valueNr <= 0))) return (NULL); ctxt->valueNr--; if (ctxt->valueNr > 0) @@ -2433,8 +2433,9 @@ valuePop(xmlXPathParserContextPtr ctxt) int valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value) { - if ((ctxt == NULL) || (value == NULL)) return(-1); - if (ctxt->valueNr >= ctxt->valueMax) { + if (XML_UNLIKELY((ctxt == NULL) || (value == NULL))) + return(-1); + if (XML_UNLIKELY(ctxt->valueNr >= ctxt->valueMax)) { xmlXPathObjectPtr *tmp; tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab, @@ -7524,7 +7525,7 @@ typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction) */ xmlNodePtr xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (cur == NULL) return(ctxt->context->node); return(NULL); @@ -7542,10 +7543,11 @@ xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); - if (cur == NULL) { - if (ctxt->context->node == NULL) return(NULL); - switch (ctxt->context->node->type) { + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); + if (XML_UNLIKELY(cur == NULL)) { + cur = ctxt->context->node; + if (XML_UNLIKELY(cur == NULL)) return(NULL); + switch (cur->type) { case XML_ELEMENT_NODE: case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: @@ -7555,7 +7557,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { case XML_COMMENT_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: - return(ctxt->context->node->children); + return(cur->children); case XML_DOCUMENT_NODE: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: @@ -7563,7 +7565,7 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif - return(((xmlDocPtr) ctxt->context->node)->children); + return(((xmlDocPtr) cur)->children); case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: @@ -7575,8 +7577,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { } return(NULL); } - if ((cur->type == XML_DOCUMENT_NODE) || - (cur->type == XML_HTML_DOCUMENT_NODE)) + if (XML_UNLIKELY((cur->type == XML_DOCUMENT_NODE) || + (cur->type == XML_HTML_DOCUMENT_NODE))) return(NULL); return(cur->next); } @@ -7593,8 +7595,8 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ static xmlNodePtr xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); - if (cur == NULL) { + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); + if (XML_UNLIKELY(cur == NULL)) { cur = ctxt->context->node; if (cur == NULL) return(NULL); /* @@ -7745,7 +7747,7 @@ next_sibling: */ xmlNodePtr xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (cur == NULL) { if (ctxt->context->node == NULL) return(NULL); @@ -7808,7 +7810,7 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (cur == NULL) { if (ctxt->context->node == NULL) return(NULL); @@ -7833,7 +7835,7 @@ xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); /* * the parent of an attribute or namespace node is the element * to which the attribute or namespace node is attached @@ -7906,7 +7908,7 @@ xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); /* * the parent of an attribute or namespace node is the element * to which the attribute or namespace node is attached @@ -8030,7 +8032,7 @@ xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (cur == NULL) return(ctxt->context->node); return(xmlXPathNextAncestor(ctxt, cur)); @@ -8049,7 +8051,7 @@ xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || (ctxt->context->node->type == XML_NAMESPACE_DECL)) return(NULL); @@ -8074,7 +8076,7 @@ xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) || (ctxt->context->node->type == XML_NAMESPACE_DECL)) return(NULL); @@ -8105,7 +8107,7 @@ xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) && (cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL)) return(cur->children); @@ -8169,7 +8171,7 @@ xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) { xmlNodePtr xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (cur == NULL) { cur = ctxt->context->node; if (cur->type == XML_NAMESPACE_DECL) @@ -8215,7 +8217,7 @@ static xmlNodePtr xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (cur == NULL) { cur = ctxt->context->node; if (cur == NULL) @@ -8258,7 +8260,7 @@ xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt, */ xmlNodePtr xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL); if (ctxt->context->tmpNsList == NULL && cur != (xmlNodePtr) xmlXPathXMLNamespace) { if (ctxt->context->tmpNsList != NULL) @@ -8295,7 +8297,7 @@ xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ xmlNodePtr xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); if (ctxt->context->node == NULL) return(NULL); if (ctxt->context->node->type != XML_ELEMENT_NODE) @@ -9740,7 +9742,7 @@ xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) { xmlChar *ret; int count = 0; - if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL); + if (XML_UNLIKELY((ctxt == NULL) || (ctxt->cur == NULL))) return(NULL); /* * Accelerator for simple ASCII names */ -- 1.7.1
>From c25ad12939a227dd0ae7cb0c4efd3e27f6e05e8b Mon Sep 17 00:00:00 2001 From: Stefan Kost <[email protected]> Date: Tue, 3 May 2011 17:22:40 +0300 Subject: [PATCH 2/4] xpath: split traversal into init and next functions This avoid us checking cur=NULL in next(). --- xpath.c | 98 ++++++++++++++++++++++++++++++++++++-------------------------- 1 files changed, 57 insertions(+), 41 deletions(-) diff --git a/xpath.c b/xpath.c index 579db1b..476ac9d 100644 --- a/xpath.c +++ b/xpath.c @@ -7487,6 +7487,12 @@ xmlXPathModValues(xmlXPathParserContextPtr ctxt) { * * ************************************************************************/ + /* + * A function to initialize traversal. + */ +typedef xmlNodePtr (*xmlXPathTraversalStartFunction) + (xmlXPathParserContextPtr ctxt); + /* * A traversal function enumerates nodes along an axis. * Initially it must be called with NULL, and it indicates @@ -7584,6 +7590,51 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { } /** + * xmlXPathFirstChildElement: + * @ctxt: the XPath Parser context + * + * Init traversal for the "child" direction and nodes of type element. + * The child axis contains the children of the context node in document order. + * + * Returns the first element following that axis + */ +static xmlNodePtr +xmlXPathFirstChildElement(xmlXPathParserContextPtr ctxt) { + xmlNodePtr cur = ctxt->context->node; + + if (XML_UNLIKELY(cur == NULL)) return(NULL); + /* + * Get the first element child. + */ + switch (cur->type) { + case XML_ELEMENT_NODE: + case XML_DOCUMENT_FRAG_NODE: + case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ + case XML_ENTITY_NODE: + cur = cur->children; + if (cur != NULL) { + if (cur->type == XML_ELEMENT_NODE) + return(cur); + do { + cur = cur->next; + } while ((cur != NULL) && + (cur->type != XML_ELEMENT_NODE)); + return(cur); + } + return(NULL); + case XML_DOCUMENT_NODE: + case XML_HTML_DOCUMENT_NODE: +#ifdef LIBXML_DOCB_ENABLED + case XML_DOCB_DOCUMENT_NODE: +#endif + return(xmlDocGetRootElement((xmlDocPtr) cur)); + default: + return(NULL); + } + return(NULL); +} + +/** * xmlXPathNextChildElement: * @ctxt: the XPath Parser context * @cur: the current node in the traversal @@ -7595,40 +7646,6 @@ xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { */ static xmlNodePtr xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) { - if (XML_UNLIKELY((ctxt == NULL) || (ctxt->context == NULL))) return(NULL); - if (XML_UNLIKELY(cur == NULL)) { - cur = ctxt->context->node; - if (cur == NULL) return(NULL); - /* - * Get the first element child. - */ - switch (cur->type) { - case XML_ELEMENT_NODE: - case XML_DOCUMENT_FRAG_NODE: - case XML_ENTITY_REF_NODE: /* URGENT TODO: entify-refs as well? */ - case XML_ENTITY_NODE: - cur = cur->children; - if (cur != NULL) { - if (cur->type == XML_ELEMENT_NODE) - return(cur); - do { - cur = cur->next; - } while ((cur != NULL) && - (cur->type != XML_ELEMENT_NODE)); - return(cur); - } - return(NULL); - case XML_DOCUMENT_NODE: - case XML_HTML_DOCUMENT_NODE: -#ifdef LIBXML_DOCB_ENABLED - case XML_DOCB_DOCUMENT_NODE: -#endif - return(xmlDocGetRootElement((xmlDocPtr) cur)); - default: - return(NULL); - } - return(NULL); - } /* * Get the next sibling element node. */ @@ -11979,6 +11996,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, int hasPredicateRange, hasAxisRange, pos, size, newSize; int breakOnFirstHit; + xmlXPathTraversalStartFunction next_i = NULL; xmlXPathTraversalFunction next = NULL; /* compound axis traversal */ xmlXPathTraversalFunctionExt outerNext = NULL; @@ -12044,6 +12062,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, /* * Optimization if an element node type is 'element'. */ + next_i = xmlXPathFirstChildElement; next = xmlXPathNextChildElement; } else next = xmlXPathNextChild; @@ -12205,13 +12224,9 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, * Traverse the axis and test the nodes. */ pos = 0; - cur = NULL; + cur = next_i ? next_i(ctxt) : next(ctxt, NULL); hasNsNodes = 0; - do { - cur = next(ctxt, cur); - if (cur == NULL) - break; - + while (cur) { /* * QUESTION TODO: What does the "first" and "last" stuff do? */ @@ -12390,7 +12405,8 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, } break; } /* switch(test) */ - } while (cur != NULL); + cur = next(ctxt, cur); + }; goto apply_predicates; -- 1.7.1
>From 7066379eb1ef02f68f1cf66168771e13b39cc765 Mon Sep 17 00:00:00 2001 From: Stefan Kost <[email protected]> Date: Tue, 3 May 2011 17:25:39 +0300 Subject: [PATCH 4/4] xpath: avoid a memcpy on the expense of temporarily wasting memory Just allocate a target buffer and fill, instead of printing to a temp buffer and then dup'ing. --- xpath.c | 7 +++---- 1 files changed, 3 insertions(+), 4 deletions(-) diff --git a/xpath.c b/xpath.c index 6b2f627..384a36c 100644 --- a/xpath.c +++ b/xpath.c @@ -5586,10 +5586,9 @@ xmlXPathCastNumberToString (double val) { ret = xmlStrdup((const xmlChar *) "0"); } else { /* could be improved */ - char buf[100]; - xmlXPathFormatNumber(val, buf, 99); - buf[99] = 0; - ret = xmlStrdup((const xmlChar *) buf); + ret = xmlMalloc(100); + xmlXPathFormatNumber(val, ret, 99); + ret[99] = 0; } } return(ret); -- 1.7.1
_______________________________________________ xslt mailing list, project page http://xmlsoft.org/XSLT/ [email protected] http://mail.gnome.org/mailman/listinfo/xslt
