From 81514ba47868793ad27ed344294f48d6a2d3ced9 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Tue, 16 Sep 2003 23:17:26 +0000 Subject: [PATCH] do string allocations in large pools, allowing to find if a string pertain * dict.c include/libxml/dict.h: do string allocations in large pools, allowing to find if a string pertain to a dict quickly * xmllint.c: fix --stream --repeat --timing * Makefile.am: the testThreads run output should be seen. Daniel --- ChangeLog | 7 +++ Makefile.am | 4 +- dict.c | 102 +++++++++++++++++++++++++++++++++++++++--- include/libxml/dict.h | 3 ++ xmllint.c | 8 ++-- 5 files changed, 113 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6bf85617..1bb2fb9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Wed Sep 17 01:07:56 CEST 2003 Daniel Veillard + + * dict.c include/libxml/dict.h: do string allocations in large + pools, allowing to find if a string pertain to a dict quickly + * xmllint.c: fix --stream --repeat --timing + * Makefile.am: the testThreads run output should be seen. + Mon Sep 15 16:46:28 CEST 2003 Daniel Veillard * SAX2.c include/libxml/parser.h: starting work on reusing the diff --git a/Makefile.am b/Makefile.am index 05bb587a..6fd1879d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -566,10 +566,10 @@ Threadtests : testThreads$(EXEEXT) @echo "##" @echo "## Threaded regression tests" @echo "##" - -@($(CHECKER) $(top_builddir)/testThreads ; \ + -($(CHECKER) $(top_builddir)/testThreads ; \ grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";) -Readertests : testReader$(EXEEXT) +Readertests : xmllint$(EXEEXT) @(echo > .memdump) @echo "##" @echo "## Reader regression tests" diff --git a/dict.c b/dict.c index 380e9088..20d1efb5 100644 --- a/dict.c +++ b/dict.c @@ -40,11 +40,21 @@ typedef struct _xmlDictEntry xmlDictEntry; typedef xmlDictEntry *xmlDictEntryPtr; struct _xmlDictEntry { struct _xmlDictEntry *next; - xmlChar *name; + const xmlChar *name; int len; int valid; }; +typedef struct _xmlDictStrings xmlDictStrings; +typedef xmlDictStrings *xmlDictStringsPtr; +struct _xmlDictStrings { + xmlDictStringsPtr next; + xmlChar *free; + xmlChar *end; + int size; + int nbStrings; + xmlChar array[1]; +}; /* * The entire dictionnary */ @@ -52,8 +62,58 @@ struct _xmlDict { struct _xmlDictEntry *dict; int size; int nbElems; + xmlDictStringsPtr strings; }; +/* + * xmlDictAddString: + * @dict: the dictionnary + * @name: the name of the userdata + * @len: the length of the name, if -1 it is recomputed + * + * Add the string to the array[s] + * + * Returns the pointer of the local string, or NULL in case of error. + */ +static const xmlChar * +xmlDictAddString(xmlDictPtr dict, const xmlChar *name, int namelen) { + xmlDictStringsPtr pool; + const xmlChar *ret; + int size = 0; /* + sizeof(_xmlDictStrings) == 1024 */ + + pool = dict->strings; + while (pool != NULL) { + if (pool->end - pool->free > namelen) + goto found_pool; + if (pool->size > size) size = pool->size; + pool = pool->next; + } + /* + * Not found, need to allocate + */ + if (pool == NULL) { + if (size == 0) size = 1000; + else size *= 4; /* exponential growth */ + if (size < 4 * namelen) + size = 4 * namelen; /* just in case ! */ + pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size); + if (pool == NULL) + return(NULL); + pool->size = size; + pool->nbStrings = 0; + pool->free = &pool->array[0]; + pool->end = &pool->array[size]; + pool->next = dict->strings; + dict->strings = pool; + } +found_pool: + ret = pool->free; + memcpy(pool->free, name, namelen); + pool->free += namelen; + *(pool->free++) = 0; + return(ret); +} + /* * xmlDictComputeKey: * Calculate the hash key @@ -110,6 +170,7 @@ xmlDictCreate(void) { dict->size = MIN_DICT_SIZE; dict->nbElems = 0; dict->dict = xmlMalloc(MIN_DICT_SIZE * sizeof(xmlDictEntry)); + dict->strings = NULL; if (dict->dict) { memset(dict->dict, 0, MIN_DICT_SIZE * sizeof(xmlDictEntry)); return(dict); @@ -226,6 +287,7 @@ xmlDictFree(xmlDictPtr dict) { xmlDictEntryPtr iter; xmlDictEntryPtr next; int inside_dict = 0; + xmlDictStringsPtr pool, nextp; if (dict == NULL) return; @@ -237,8 +299,6 @@ xmlDictFree(xmlDictPtr dict) { inside_dict = 1; while (iter) { next = iter->next; - if (iter->name) - xmlFree(iter->name); if (!inside_dict) xmlFree(iter); dict->nbElems--; @@ -249,6 +309,12 @@ xmlDictFree(xmlDictPtr dict) { } xmlFree(dict->dict); } + pool = dict->strings; + while (pool != NULL) { + nextp = pool->next; + xmlFree(pool); + pool = nextp; + } xmlFree(dict); } @@ -294,6 +360,9 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { return(insert->name); } + ret = xmlDictAddString(dict, name, len); + if (ret == NULL) + return(NULL); if (insert == NULL) { entry = &(dict->dict[key]); } else { @@ -301,8 +370,7 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { if (entry == NULL) return(NULL); } - - ret = entry->name = xmlStrndup(name, len); + entry->name = ret; entry->len = len; entry->next = NULL; entry->valid = 1; @@ -321,6 +389,30 @@ xmlDictLookup(xmlDictPtr dict, const xmlChar *name, int len) { return(ret); } +/** + * xmlDictOwns: + * @dict: the dictionnary + * @str: the string + * + * check if a string is owned by the disctionary + * + * Returns 1 if true, 0 if false and -1 in case of error + * -1 in case of error + */ +int +xmlDictOwns(xmlDictPtr dict, const xmlChar *str) { + xmlDictStringsPtr pool; + + if ((dict == NULL) || (str == NULL)) + return(-1); + pool = dict->strings; + while (pool != NULL) { + if ((str >= pool->array) && (str <= pool->free)) + return(1); + pool = pool->next; + } + return(0); +} /** * xmlDictSize: * @dict: the dictionnary diff --git a/include/libxml/dict.h b/include/libxml/dict.h index 5b4a59aa..551a7d81 100644 --- a/include/libxml/dict.h +++ b/include/libxml/dict.h @@ -47,6 +47,9 @@ XMLPUBFUN const xmlChar * XMLCALL xmlDictLookup (xmlDictPtr dict, const xmlChar *name, int len); +XMLPUBFUN int XMLCALL + xmlDictOwns (xmlDictPtr dict, + const xmlChar *str); XMLPUBFUN int XMLCALL xmlDictSize (xmlDictPtr dict); #ifdef __cplusplus diff --git a/xmllint.c b/xmllint.c index 1151bf71..21e3201a 100644 --- a/xmllint.c +++ b/xmllint.c @@ -618,7 +618,7 @@ static void streamFile(char *filename) { xmlTextReaderSetParserProp(reader, XML_PARSER_LOADDTD, 1); #ifdef LIBXML_SCHEMAS_ENABLED if (relaxng != NULL) { - if (timing) { + if ((timing) && (!repeat)) { startTimer(); } ret = xmlTextReaderRelaxNGValidate(reader, relaxng); @@ -627,7 +627,7 @@ static void streamFile(char *filename) { "Relax-NG schema %s failed to compile\n", relaxng); relaxng = NULL; } - if (timing) { + if ((timing) && (!repeat)) { endTimer("Compiling the schemas"); } } @@ -636,7 +636,7 @@ static void streamFile(char *filename) { /* * Process all nodes in sequence */ - if (timing) { + if ((timing) && (!repeat)) { startTimer(); } ret = xmlTextReaderRead(reader); @@ -645,7 +645,7 @@ static void streamFile(char *filename) { processNode(reader); ret = xmlTextReaderRead(reader); } - if (timing) { + if ((timing) && (!repeat)) { #ifdef LIBXML_SCHEMAS_ENABLED if ((valid) || (relaxng != NULL)) #else