From: Philippe Waroquiers Date: Fri, 11 Nov 2016 13:30:08 +0000 (+0000) Subject: Support pool of unique string in pub_tool_deduppoolalloc.h X-Git-Tag: svn/VALGRIND_3_13_0~301 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=599a062f615145908c6cf9aa2491e565b3ede68b;p=thirdparty%2Fvalgrind.git Support pool of unique string in pub_tool_deduppoolalloc.h This is support code for the xtree implementation. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@16120 --- diff --git a/coregrind/m_deduppoolalloc.c b/coregrind/m_deduppoolalloc.c index f7ebd27183..b8f10c72d6 100644 --- a/coregrind/m_deduppoolalloc.c +++ b/coregrind/m_deduppoolalloc.c @@ -41,6 +41,7 @@ struct _DedupPoolAlloc { SizeT poolSzB; /* Minimum size of a pool. */ SizeT fixedSzb; /* If using VG_(allocFixedEltDedupPA), size of elements */ + Bool strPA; /* True if this is a string dedup pool */ SizeT eltAlign; void* (*alloc_fn)(const HChar*, SizeT); /* pool allocator */ const HChar* cc; /* pool allocator's cost centre */ @@ -75,7 +76,8 @@ typedef struct _ht_node { struct _ht_node *next; // Read/Write by hashtable (pub_tool_hashtable.h) UWord key; // Read by hashtable (pub_tool_hashtable.h) - SizeT eltSzB; + SizeT eltSzBorStrNr; // for a normal pool, elt size + // for a string pool, the unique str number const void *elt; } ht_node; @@ -97,6 +99,7 @@ DedupPoolAlloc* VG_(newDedupPA) ( SizeT poolSzB, VG_(memset)(ddpa, 0, sizeof(*ddpa)); ddpa->poolSzB = poolSzB; ddpa->fixedSzb = 0; + ddpa->strPA = False; ddpa->eltAlign = eltAlign; ddpa->alloc_fn = alloc_fn; ddpa->cc = cc; @@ -189,14 +192,24 @@ static Word cmp_pool_elt (const void* node1, const void* node2 ) /* As this function is called by hashtable, that has already checked for key equality, it is likely that it is the 'good' element. So, we handle the equal case first. */ - if (hnode1->eltSzB == hnode2->eltSzB) - return VG_(memcmp) (hnode1->elt, hnode2->elt, hnode1->eltSzB); - else if (hnode1->eltSzB < hnode2->eltSzB) + if (hnode1->eltSzBorStrNr == hnode2->eltSzBorStrNr) + return VG_(memcmp) (hnode1->elt, hnode2->elt, hnode1->eltSzBorStrNr); + else if (hnode1->eltSzBorStrNr < hnode2->eltSzBorStrNr) return -1; else return 1; } +/* String compare function for 'gen' hash table. + Similarly to cmp_pool_elt, no need to compare the key. */ +static Word cmp_pool_str (const void* node1, const void* node2 ) +{ + const ht_node* hnode1 = node1; + const ht_node* hnode2 = node2; + + return VG_(strcmp)(hnode1->elt, hnode2->elt); +} + /* Print some stats. */ static void print_stats (DedupPoolAlloc *ddpa) { @@ -209,7 +222,10 @@ static void print_stats (DedupPoolAlloc *ddpa) VG_(sizeXA)(ddpa->pools), ddpa->curpool ? (long int) (ddpa->curpool_limit - ddpa->curpool_free + 1) : 0); - VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_elt); + if (ddpa->strPA) + VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_str); + else + VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_elt); } /* Dummy free, as the ht elements are allocated in a pool, and @@ -247,8 +263,8 @@ static UInt sdbm_hash (const UChar* buf, UInt len ) return h; } -const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB, - const void *elt) +static ht_node* allocEltDedupPA (DedupPoolAlloc *ddpa, SizeT eltSzB, + const void *elt) { ht_node ht_elt; void* elt_ins; @@ -260,12 +276,16 @@ const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB, ht_elt.key = sdbm_hash (elt, eltSzB); - ht_elt.eltSzB = eltSzB; ht_elt.elt = elt; - ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_elt); + if (ddpa->strPA) + ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_str); + else { + ht_elt.eltSzBorStrNr = eltSzB; + ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_elt); + } if (ht_ins) - return ht_ins->elt; + return ht_ins; /* Not found -> we need to allocate a new element from the pool and insert it in the hash table of inserted elements. */ @@ -291,10 +311,37 @@ const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB, VG_(memcpy)(elt_ins, elt, eltSzB); ht_ins = VG_(allocEltPA) (ddpa->ht_node_pa); ht_ins->key = ht_elt.key; - ht_ins->eltSzB = eltSzB; + if (ddpa->strPA) + ht_ins->eltSzBorStrNr = VG_(HT_count_nodes)(ddpa->ht_elements) + 1; + else + ht_ins->eltSzBorStrNr = eltSzB; ht_ins->elt = elt_ins; VG_(HT_add_node)(ddpa->ht_elements, ht_ins); - return elt_ins; + return ht_ins; +} + +const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB, + const void *elt) +{ + return allocEltDedupPA(ddpa, eltSzB, elt)->elt; +} + +UInt VG_(allocStrDedupPA) (DedupPoolAlloc *ddpa, + const HChar* str, + Bool* newStr) +{ + if (!ddpa->strPA) { + // First insertion in this ddpa + vg_assert (ddpa->nr_alloc_calls == 0); + vg_assert (ddpa->fixedSzb == 0); + ddpa->strPA = True; + } + + const UInt nr_str = VG_(HT_count_nodes)(ddpa->ht_elements); + const ht_node* ht_ins = allocEltDedupPA(ddpa, VG_(strlen)(str)+1, str); + + *newStr = nr_str < VG_(HT_count_nodes)(ddpa->ht_elements); + return ht_ins->eltSzBorStrNr; } static __inline__ @@ -311,6 +358,7 @@ UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc *ddpa, { if (ddpa->fixedSzb == 0) { // First insertion in this ddpa + vg_assert (!ddpa->strPA); vg_assert (ddpa->nr_alloc_calls == 0); vg_assert (eltSzB > 0); ddpa->fixedSzb = eltSzB; diff --git a/include/pub_tool_deduppoolalloc.h b/include/pub_tool_deduppoolalloc.h index a4c1a098cd..969c42cc98 100644 --- a/include/pub_tool_deduppoolalloc.h +++ b/include/pub_tool_deduppoolalloc.h @@ -44,8 +44,8 @@ // individually. // Once allocated, an element must not be modified anymore. // -// Elements can be inserted in the pool using VG_(allocEltDedupPA) -// or using VG_(allocFixedEltDedupPA). +// Elements can be inserted in the pool using VG_(allocEltDedupPA), +// VG_(allocFixedEltDedupPA) or VG_(allocStrDedupPA). // // Use VG_(allocFixedEltDedupPA) to allocate elements that are all of // the same size and that you want to identify with a (small) number: @@ -65,6 +65,10 @@ // The address of an element allocated with VG_(allocEltDedupPA) does // not change, even if new elements are inserted in the pool. // +// Use VG_(allocStrDedupPA) to create a pool of strings (in other words, a +// dictionnary of strings). Similarly to VG_(allocFixedEltDedupPA), strings +// inserted in a dedup pool can be identified by an element number. +// // In the same pool, you can only use one of the allocate element functions. // // A dedup pool allocator has significantly less memory overhead than @@ -93,29 +97,42 @@ extern DedupPoolAlloc* VG_(newDedupPA) ( SizeT poolSzB, const HChar* cc, void (*free_fn)(void*) ); -/* Allocates a new element from ddpa with eltSzB bytes to store elt. +/* Allocates or retrieve element from ddpa with eltSzB bytes to store elt. This function never returns NULL. If ddpa already contains an element equal to elt, then the address of the already existing element is returned. Equality between elements is done by comparing all bytes. So, if void *elt points to a struct, be sure to initialise all components and the holes between components. */ -extern const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, - SizeT eltSzB, const void *elt); +extern const void* VG_(allocEltDedupPA) (DedupPoolAlloc* ddpa, + SizeT eltSzB, const void* elt); -/* Allocates a new (fixed size) element from ddpa. Returns the - unique number identifying this element. This function never returns NULL. +/* Allocates or retrieve a (fixed size) element from ddpa. Returns the + unique number identifying this element. Similarly to VG_(allocEltDedupPA), this will return the unique number of an already existing identical element to elt. */ -extern UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc *ddpa, - SizeT eltSzB, const void *elt); +extern UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc* ddpa, + SizeT eltSzB, const void* elt); /* Translate an element number to its address. Note that the address corresponding to eltNr can change if new elements are inserted in the pool. */ -extern void* VG_(indexEltNumber) (DedupPoolAlloc *ddpa, +extern void* VG_(indexEltNumber) (DedupPoolAlloc* ddpa, UInt eltNr); +/* Allocates or retrieve a string element from ddpa. Returns the + unique number identifying this string. + newStr is set to True if the str is a newly inserted string, False + if the str was already present in the pool. + Similarly to VG_(allocEltDedupPA), this will return the unique number + of an already existing identical string. */ +extern UInt VG_(allocStrDedupPA) (DedupPoolAlloc *ddpa, + const HChar* str, + Bool* newStr); +/* Note: Implementing a function to return the string value from its strNr + implies some overhead, so will be done only if/when needed. */ + + /* The Dedup Pool Allocator must maintain a data structure to avoid duplicates as long as new elements can be allocated from the pool. Once no new elements will be allocated, this dedup data structure @@ -123,14 +140,14 @@ extern void* VG_(indexEltNumber) (DedupPoolAlloc *ddpa, it is an error to call VG_(allocEltDedupPA) or VG_(allocFixedEltDedupPA). If shrink_block is not NULL, the last pool will be shrunk using shrink_block. */ -extern void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa, +extern void VG_(freezeDedupPA) (DedupPoolAlloc* ddpa, void (*shrink_block)(void*, SizeT)); /* How many (unique) elements are there in this ddpa now? */ -extern UInt VG_(sizeDedupPA) (DedupPoolAlloc *ddpa); +extern UInt VG_(sizeDedupPA) (DedupPoolAlloc* ddpa); /* Free all memory associated with a DedupPoolAlloc. */ -extern void VG_(deleteDedupPA) ( DedupPoolAlloc *ddpa); +extern void VG_(deleteDedupPA) ( DedupPoolAlloc* ddpa); #endif // __PUB_TOOL_DEDUPPOOLALLOC_