From 6155d8aafa3cc60b5fdaaf75b423e489ea8280c4 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Tue, 19 Aug 2003 15:01:28 +0000 Subject: [PATCH] optimization when freeing hash tables. some tuning of buffer allocations * dict.c hash.c: optimization when freeing hash tables. * parser.c xmlIO.c include/libxml/tree.h: some tuning of buffer allocations * parser.c parserInternals.c include/libxml/parser.h: keep a single allocated block for all the attributes callbacks, avoid useless malloc()/free() * tree.c: do not realloc() when growing a buffer if the buffer ain't full, malloc/memcpy/free avoid copying memory. Daniel --- ChangeLog | 11 +++++++++++ dict.c | 3 ++- hash.c | 5 ++++- include/libxml/parser.h | 2 ++ include/libxml/tree.h | 2 +- parser.c | 32 ++++++++++++++++++++------------ parserInternals.c | 3 +++ tree.c | 14 +++++++++++++- xmlIO.c | 9 ++++----- 9 files changed, 60 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2f46709a..590df85c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Tue Aug 19 16:54:18 CEST 2003 Daniel Veillard + + * dict.c hash.c: optimization when freeing hash tables. + * parser.c xmlIO.c include/libxml/tree.h: some tuning of buffer + allocations + * parser.c parserInternals.c include/libxml/parser.h: keep a + single allocated block for all the attributes callbacks, + avoid useless malloc()/free() + * tree.c: do not realloc() when growing a buffer if the buffer + ain't full, malloc/memcpy/free avoid copying memory. + Mon Aug 18 18:37:01 CEST 2003 Daniel Veillard * xmllint.c doc/xmllint.xml doc/xmllint.1: added option diff --git a/dict.c b/dict.c index 10022340..eaa40063 100644 --- a/dict.c +++ b/dict.c @@ -232,7 +232,7 @@ xmlDictFree(xmlDictPtr dict) { if (dict == NULL) return; if (dict->dict) { - for(i = 0; i < dict->size; i++) { + for(i = 0; ((i < dict->size) && (dict->nbElems > 0)); i++) { iter = &(dict->dict[i]); if (iter->valid == 0) continue; @@ -243,6 +243,7 @@ xmlDictFree(xmlDictPtr dict) { xmlFree(iter->name); if (!inside_dict) xmlFree(iter); + dict->nbElems--; inside_dict = 0; iter = next; } diff --git a/hash.c b/hash.c index 2a4d0008..b4b86561 100644 --- a/hash.c +++ b/hash.c @@ -218,11 +218,13 @@ xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { xmlHashEntryPtr iter; xmlHashEntryPtr next; int inside_table = 0; + int nbElems; if (table == NULL) return; if (table->table) { - for(i = 0; i < table->size; i++) { + nbElems = table->nbElems; + for(i = 0; (i < table->size) && (nbElems > 0); i++) { iter = &(table->table[i]); if (iter->valid == 0) continue; @@ -240,6 +242,7 @@ xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) { iter->payload = NULL; if (!inside_table) xmlFree(iter); + nbElems--; inside_table = 0; iter = next; } diff --git a/include/libxml/parser.h b/include/libxml/parser.h index b0803845..ac3f055d 100644 --- a/include/libxml/parser.h +++ b/include/libxml/parser.h @@ -236,6 +236,8 @@ struct _xmlParserCtxt { int recovery; /* run in recovery mode */ int progressive; /* is this a progressive parsing */ xmlDictPtr dict; /* dictionnary for the parser */ + const xmlChar * *atts; /* array for the attributes callbacks */ + int maxatts; /* the size of the array */ }; /** diff --git a/include/libxml/tree.h b/include/libxml/tree.h index 4ca3c9ae..b029ffc1 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -50,7 +50,7 @@ typedef xmlEntity *xmlEntityPtr; * * default buffer size 4000. */ -#define BASE_BUFFER_SIZE 4000 +#define BASE_BUFFER_SIZE 4096 /** * XML_XML_NAMESPACE: diff --git a/parser.c b/parser.c index 535df1e0..4eb5265c 100644 --- a/parser.c +++ b/parser.c @@ -369,8 +369,8 @@ static int spacePop(xmlParserCtxtPtr ctxt) { } while (0) #define SHRINK if ((ctxt->progressive == 0) && \ - (ctxt->input->cur - ctxt->input->base > INPUT_CHUNK) && \ - (ctxt->input->end - ctxt->input->cur < INPUT_CHUNK)) \ + (ctxt->input->cur - ctxt->input->base > 2 * INPUT_CHUNK) && \ + (ctxt->input->end - ctxt->input->cur < 2 * INPUT_CHUNK)) \ xmlSHRINK (ctxt); static void xmlSHRINK (xmlParserCtxtPtr ctxt) { @@ -2363,6 +2363,7 @@ xmlParseAttValue(xmlParserCtxtPtr ctxt) { xmlChar limit = 0; const xmlChar *in = NULL; xmlChar *ret = NULL; + SHRINK; GROW; in = (xmlChar *) CUR_PTR; @@ -2412,8 +2413,6 @@ xmlParseAttValueComplex(xmlParserCtxtPtr ctxt) { xmlChar *current = NULL; xmlEntityPtr ent; - - SHRINK; if (NXT(0) == '"') { ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE; limit = '"'; @@ -6612,9 +6611,9 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { const xmlChar *name; const xmlChar *attname; xmlChar *attvalue; - const xmlChar **atts = NULL; + const xmlChar **atts = ctxt->atts; int nbatts = 0; - int maxatts = 0; + int maxatts = ctxt->maxatts; int i; if (RAW != '<') return(NULL); @@ -6670,8 +6669,9 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { * Add the pair to atts */ if (atts == NULL) { - maxatts = 10; - atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *)); + maxatts = 22; /* allow for 10 attrs by default */ + atts = (const xmlChar **) + xmlMalloc(maxatts * sizeof(xmlChar *)); if (atts == NULL) { xmlGenericError(xmlGenericErrorContext, "malloc of %ld byte failed\n", @@ -6683,12 +6683,14 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { ctxt->disableSAX = 1; goto failed; } + ctxt->atts = atts; + ctxt->maxatts = maxatts; } else if (nbatts + 4 > maxatts) { const xmlChar **n; maxatts *= 2; n = (const xmlChar **) xmlRealloc((void *) atts, - maxatts * sizeof(xmlChar *)); + maxatts * sizeof(const xmlChar *)); if (n == NULL) { xmlGenericError(xmlGenericErrorContext, "realloc of %ld byte failed\n", @@ -6701,6 +6703,8 @@ xmlParseStartTag(xmlParserCtxtPtr ctxt) { goto failed; } atts = n; + ctxt->atts = atts; + ctxt->maxatts = maxatts; } atts[nbatts++] = attname; atts[nbatts++] = attvalue; @@ -6735,6 +6739,7 @@ failed: if (ctxt->recovery == 0) ctxt->disableSAX = 1; break; } + SHRINK; GROW; } @@ -6742,15 +6747,18 @@ failed: * SAX: Start of Element ! */ if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL) && - (!ctxt->disableSAX)) - ctxt->sax->startElement(ctxt->userData, name, atts); + (!ctxt->disableSAX)) { + if (nbatts > 0) + ctxt->sax->startElement(ctxt->userData, name, atts); + else + ctxt->sax->startElement(ctxt->userData, name, NULL); + } if (atts != NULL) { /* Free only the content strings */ for (i = 1;i < nbatts;i+=2) if (atts[i] != NULL) xmlFree((xmlChar *) atts[i]); - xmlFree((void *) atts); } return(name); } diff --git a/parserInternals.c b/parserInternals.c index 5c85cbc4..ea0a5d05 100644 --- a/parserInternals.c +++ b/parserInternals.c @@ -2218,6 +2218,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt) else memcpy(ctxt->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler)); + ctxt->maxatts = 0; + ctxt->atts = NULL; /* Allocate the Input stack */ ctxt->inputTab = (xmlParserInputPtr *) xmlMalloc(5 * sizeof(xmlParserInputPtr)); @@ -2369,6 +2371,7 @@ xmlFreeParserCtxt(xmlParserCtxtPtr ctxt) xmlFree(ctxt->sax); if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory); if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab); + if (ctxt->atts != NULL) xmlFree(ctxt->atts); if (ctxt->dict != NULL) xmlDictFree(ctxt->dict); #ifdef LIBXML_CATALOG_ENABLED if (ctxt->catalogs != NULL) diff --git a/tree.c b/tree.c index 4dd1027e..135c92bb 100644 --- a/tree.c +++ b/tree.c @@ -6413,9 +6413,21 @@ xmlBufferResize(xmlBufferPtr buf, unsigned int size) if (buf->content == NULL) rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar)); - else + else if (buf->size - buf->use < 100) { rebuf = (xmlChar *) xmlRealloc(buf->content, newSize * sizeof(xmlChar)); + } else { + /* + * if we are reallocating a buffer far from being full, it's + * better to make a new allocation and copy only the used range + * and free the old one. + */ + rebuf = (xmlChar *) xmlMallocAtomic(newSize * sizeof(xmlChar)); + if (rebuf != NULL) { + memcpy(rebuf, buf->content, buf->use); + xmlFree(buf->content); + } + } if (rebuf == NULL) { xmlGenericError(xmlGenericErrorContext, "xmlBufferResize : out of memory!\n"); diff --git a/xmlIO.c b/xmlIO.c index 715cec5d..83907f90 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -1574,7 +1574,7 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) { return(NULL); } memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); - ret->buffer = xmlBufferCreate(); + ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize); if (ret->buffer == NULL) { xmlFree(ret); return(NULL); @@ -1582,7 +1582,7 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) { ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; ret->encoder = xmlGetCharEncodingHandler(enc); if (ret->encoder != NULL) - ret->raw = xmlBufferCreate(); + ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize); else ret->raw = NULL; ret->readcallback = NULL; @@ -2173,16 +2173,15 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { int buffree; unsigned int needSize; - if ((len <= MINLEN) && (len != 4)) + if ((len <= MINLEN) && (len != 4)) len = MINLEN; + buffree = in->buffer->size - in->buffer->use; if (buffree <= 0) { xmlGenericError(xmlGenericErrorContext, "xmlParserInputBufferGrow : buffer full !\n"); return(0); } - if (len > buffree) - len = buffree; needSize = in->buffer->use + len + 1; if (needSize > in->buffer->size){