From 1989505ac76a2fb386050a7116f1f61a0ec37bfd Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 17 Sep 2003 13:59:32 +0000 Subject: [PATCH] more performance hunting reducing memory allocation and free and avoiding * SAX2.c xmlreader.c include/libxml/parser.h: more performance hunting reducing memory allocation and free and avoiding expensive routines Daniel --- ChangeLog | 5 ++ SAX2.c | 110 ++++++++++++++++++++++++++++++---------- include/libxml/parser.h | 2 + xmlreader.c | 18 +++++-- 4 files changed, 104 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc91395d..79368aac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Sep 17 15:57:44 CEST 2003 Daniel Veillard + + * SAX2.c xmlreader.c include/libxml/parser.h: more performance hunting + reducing memory allocation and free and avoiding expensive routines + Wed Sep 17 12:23:41 CEST 2003 Daniel Veillard * SAX2.c parser.c parserInternals.c xmlreader.c: started messing diff --git a/SAX2.c b/SAX2.c index ff26fcf4..82bc4a76 100644 --- a/SAX2.c +++ b/SAX2.c @@ -1564,6 +1564,47 @@ xmlSAX2EndElement(void *ctx, const xmlChar *name ATTRIBUTE_UNUSED) nodePop(ctxt); } +/* + * xmlSAX2TextNode: + * @ctxt: the parser context + * @str: the input string + * @len: the string length + * + * Remove the entities from an attribute value + * + * Returns the newly allocated string or NULL if not needed or error + */ +static xmlNodePtr +xmlSAX2TextNode(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) { + xmlNodePtr ret; + + if (ctxt->freeElems != NULL) { + ret = ctxt->freeElems; + ctxt->freeElems = ret->next; + ctxt->freeElemsNr--; + memset(ret, 0, sizeof(xmlNode)); + ret->type = XML_TEXT_NODE; + + ret->name = xmlStringText; + ret->content = xmlStrndup(str, len); + + if ((__xmlRegisterCallbacks) && (xmlRegisterNodeDefaultValue)) + xmlRegisterNodeDefaultValue(ret); + } else { + ret = xmlNewTextLen(str, len); + } + if (ret == NULL) { + if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) + ctxt->sax->error(ctxt->userData, + "SAX.xmlSAX2Characters(): out of memory\n"); + ctxt->errNo = XML_ERR_NO_MEMORY; + ctxt->instate = XML_PARSER_EOF; + ctxt->disableSAX = 1; + return(NULL); + } + return(ret); +} + /* * xmlSAX2DecodeAttrEntities: * @ctxt: the parser context @@ -1630,6 +1671,7 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, if (ctxt->freeAttrs != NULL) { ret = ctxt->freeAttrs; ctxt->freeAttrs = ret->next; + ctxt->freeAttrsNr--; memset(ret, 0, sizeof(xmlAttr)); ret->type = XML_ATTRIBUTE_NODE; @@ -1672,21 +1714,40 @@ xmlSAX2AttributeNs(xmlParserCtxtPtr ctxt, if ((ctxt->replaceEntities == 0) && (!ctxt->html)) { xmlNodePtr tmp; - ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value, - valueend - value); - tmp = ret->children; - while (tmp != NULL) { - tmp->parent = (xmlNodePtr) ret; - if (tmp->next == NULL) - ret->last = tmp; - tmp = tmp->next; + /* + * We know that if there is an entity reference, then + * the string has been dup'ed and terminates with 0 + * otherwise with ' or " + */ + if (*valueend != 0) { + tmp = xmlSAX2TextNode(ctxt, value, valueend - value); + ret->children = tmp; + ret->last = tmp; + if (tmp != NULL) { + tmp->doc = ret->doc; + tmp->parent = (xmlNodePtr) ret; + } + } else { + ret->children = xmlStringLenGetNodeList(ctxt->myDoc, value, + valueend - value); + tmp = ret->children; + while (tmp != NULL) { + tmp->parent = (xmlNodePtr) ret; + if (tmp->next == NULL) + ret->last = tmp; + tmp = tmp->next; + } } } else if (value != NULL) { - ret->children = xmlNewDocTextLen(ctxt->myDoc, value, - valueend - value); - ret->last = ret->children; - if (ret->children != NULL) - ret->children->parent = (xmlNodePtr) ret; + xmlNodePtr tmp; + + tmp = xmlSAX2TextNode(ctxt, value, valueend - value); + ret->children = tmp; + ret->last = tmp; + if (tmp != NULL) { + tmp->doc = ret->doc; + tmp->parent = (xmlNodePtr) ret; + } } if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed && @@ -1837,6 +1898,7 @@ xmlSAX2StartElementNs(void *ctx, if (ctxt->freeElems != NULL) { ret = ctxt->freeElems; ctxt->freeElems = ret->next; + ctxt->freeElemsNr--; memset(ret, 0, sizeof(xmlNode)); ret->type = XML_ELEMENT_NODE; @@ -2056,7 +2118,7 @@ xmlSAX2Characters(void *ctx, const xmlChar *ch, int len) #endif return; } - lastChild = xmlGetLastChild(ctxt->node); + lastChild = ctxt->node->last; #ifdef DEBUG_SAX_TREE xmlGenericError(xmlGenericErrorContext, "add chars to %s \n", ctxt->node->name); @@ -2067,9 +2129,12 @@ xmlSAX2Characters(void *ctx, const xmlChar *ch, int len) * elements. Use an attribute in the structure !!! */ if (lastChild == NULL) { - /* first node, first time */ - xmlNodeAddContentLen(ctxt->node, ch, len); - if (ctxt->node->children != NULL) { + lastChild = xmlSAX2TextNode(ctxt, ch, len); + if (lastChild != NULL) { + ctxt->node->children = lastChild; + ctxt->node->last = lastChild; + lastChild->parent = ctxt->node; + lastChild->doc = ctxt->node->doc; ctxt->nodelen = len; ctxt->nodemem = len + 1; } @@ -2122,15 +2187,8 @@ xmlSAX2Characters(void *ctx, const xmlChar *ch, int len) } } else { /* Mixed content, first time */ - lastChild = xmlNewTextLen(ch, len); - if (lastChild == NULL) { - if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) - ctxt->sax->error(ctxt->userData, - "SAX.xmlSAX2Characters(): out of memory\n"); - ctxt->errNo = XML_ERR_NO_MEMORY; - ctxt->instate = XML_PARSER_EOF; - ctxt->disableSAX = 1; - } else { + lastChild = xmlSAX2TextNode(ctxt, ch, len); + if (lastChild != NULL) { xmlAddChild(ctxt->node, lastChild); if (ctxt->node->children != NULL) { ctxt->nodelen = len; diff --git a/include/libxml/parser.h b/include/libxml/parser.h index 74e31850..974d0d0e 100644 --- a/include/libxml/parser.h +++ b/include/libxml/parser.h @@ -267,7 +267,9 @@ struct _xmlParserCtxt { * Those fields are needed only for treaming parsing so far */ int dictNames; /* Use dictionary names for the tree */ + int freeElemsNr; /* number of freed element nodes */ xmlNodePtr freeElems; /* List of freed element nodes */ + int freeAttrsNr; /* number of freed attributes nodes */ xmlAttrPtr freeAttrs; /* List of freed attributes nodes */ }; diff --git a/xmlreader.c b/xmlreader.c index eea9a287..eb8e6a29 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -263,9 +263,11 @@ xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) { (xmlDictOwns(reader->ctxt->dict, cur->name) != 1) && (cur->name != NULL)) xmlFree((xmlChar *)cur->name); - if ((reader != NULL) && (reader->ctxt != NULL)) { + if ((reader != NULL) && (reader->ctxt != NULL) && + (reader->ctxt->freeAttrsNr < 100)) { cur->next = reader->ctxt->freeAttrs; reader->ctxt->freeAttrs = cur; + reader->ctxt->freeAttrsNr++; } else { xmlFree(cur); } @@ -347,10 +349,13 @@ xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { (cur->type != XML_COMMENT_NODE) && (cur->name != NULL)) xmlFree((xmlChar *)cur->name); - if ((cur->type == XML_ELEMENT_NODE) && - (reader != NULL) && (reader->ctxt != NULL)) { + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_TEXT_NODE)) && + (reader != NULL) && (reader->ctxt != NULL) && + (reader->ctxt->freeElemsNr < 100)) { cur->next = reader->ctxt->freeElems; reader->ctxt->freeElems = cur; + reader->ctxt->freeElemsNr++; } else { xmlFree(cur); } @@ -414,10 +419,13 @@ xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) { (cur->type != XML_COMMENT_NODE) && (cur->name != NULL)) xmlFree((xmlChar *)cur->name); - if ((cur->type == XML_ELEMENT_NODE) && - (reader != NULL) && (reader->ctxt != NULL)) { + if (((cur->type == XML_ELEMENT_NODE) || + (cur->type == XML_TEXT_NODE)) && + (reader != NULL) && (reader->ctxt != NULL) && + (reader->ctxt->freeElemsNr < 100)) { cur->next = reader->ctxt->freeElems; reader->ctxt->freeElems = cur; + reader->ctxt->freeElemsNr++; } else { xmlFree(cur); }