From: Julian Seward Date: Thu, 20 Nov 2008 23:17:01 +0000 (+0000) Subject: event_map_maybe_GC: use a flat array when computing the distribution X-Git-Tag: svn/VALGRIND_3_4_0~101 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=468ca56d5dd7bcd7ee7a79817d19142ca043e1ff;p=thirdparty%2Fvalgrind.git event_map_maybe_GC: use a flat array when computing the distribution (counts) of generation numbers in the oldrefTree, instead of using a WordFM as an associative array. This significantly accelerates the event map garbage collector. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8794 --- diff --git a/helgrind/libhb_core.c b/helgrind/libhb_core.c index 73f3278ad6..689f89123c 100644 --- a/helgrind/libhb_core.c +++ b/helgrind/libhb_core.c @@ -2218,6 +2218,7 @@ static void show_vts_stats ( HChar* caller ) } /* NOT TO BE CALLED FROM WITHIN libzsm. */ +__attribute__((noinline)) static void vts_tab__do_GC ( Bool show_stats ) { UWord i, nTab, nLive, nFreed; @@ -3008,14 +3009,18 @@ static void event_map__check_reference_counts ( Bool before ) } } +__attribute__((noinline)) static void event_map_maybe_GC ( void ) { OldRef* oldref; UWord keyW, valW, retained, maxGen; - WordFM* genMap; XArray* refs2del; Word i, j, n2del; + UWord* genMap = NULL; + UWord genMap_min = 0; + UWord genMap_size = 0; + if (LIKELY(oldrefTreeN < EVENT_MAP_GC_AT)) return; @@ -3028,29 +3033,113 @@ static void event_map_maybe_GC ( void ) /* Check the reference counts */ event_map__check_reference_counts( True/*before*/ ); - /* Compute the distribution of generation values in the ref tree */ + /* Compute the distribution of generation values in the ref tree. + There are likely only to be a few different generation numbers + in the whole tree, but we don't know what they are. Hence use a + dynamically resized array of counters. The array is genMap[0 + .. genMap_size-1], where genMap[0] is the count for the + generation number genMap_min, genMap[1] is the count for + genMap_min+1, etc. If a new number is seen outside the range + [genMap_min .. genMap_min + genMap_size - 1] then the array is + copied into a larger array, and genMap_min and genMap_size are + adjusted accordingly. */ + /* genMap :: generation-number -> count-of-nodes-with-that-number */ - genMap = VG_(newFM)( HG_(zalloc), "libhb.emmG.1", - HG_(free), NULL ); VG_(OSetGen_ResetIter)( oldrefTree ); while ( (oldref = VG_(OSetGen_Next)( oldrefTree )) ) { + + UWord ea; UWord key = oldref->gen; - keyW = valW = 0; - if (VG_(lookupFM)(genMap, &keyW, &valW, key )) { - tl_assert(keyW == key); - tl_assert(valW > 0); + + /* BEGIN find 'ea', which is the index in genMap holding the + count for generation number 'key'. */ + if (UNLIKELY(genMap == NULL)) { + /* deal with the first key to be seen, so that the following + cases don't need to handle the complexity of a NULL count + array. */ + genMap_min = key; + genMap_size = 1; + genMap = HG_(zalloc)( "libhb.emmG.1a", + genMap_size * sizeof(UWord) ); + ea = 0; + if (0) VG_(printf)("(%lu) case 1 [%lu .. %lu]\n", + key, genMap_min, genMap_min+genMap_size- 1 ); + } + else + if (LIKELY(key >= genMap_min && key < genMap_min + genMap_size)) { + /* this is the expected (almost-always-happens) case: 'key' + is already mapped in the array. */ + ea = key - genMap_min; } - /* now valW is the old count for generation 'key' */ - VG_(addToFM)(genMap, key, valW+1); + else + if (key < genMap_min) { + /* 'key' appears before the start of the current array. + Extend the current array by allocating a larger one and + copying the current one to the upper end of it. */ + Word more; + UWord* map2; + more = genMap_min - key; + tl_assert(more > 0); + map2 = HG_(zalloc)( "libhb.emmG.1b", + (genMap_size + more) * sizeof(UWord) ); + VG_(memcpy)( &map2[more], genMap, genMap_size * sizeof(UWord) ); + HG_(free)( genMap ); + genMap = map2; + genMap_size += more; + genMap_min -= more; + ea = 0; + tl_assert(genMap_min == key); + if (0) VG_(printf)("(%lu) case 2 [%lu .. %lu]\n", + key, genMap_min, genMap_min+genMap_size- 1 ); + } + else { + /* 'key' appears after the end of the current array. Extend + the current array by allocating a larger one and copying + the current one to the lower end of it. */ + Word more; + UWord* map2; + tl_assert(key >= genMap_min + genMap_size); + more = key - (genMap_min + genMap_size) + 1; + tl_assert(more > 0); + map2 = HG_(zalloc)( "libhb.emmG.1c", + (genMap_size + more) * sizeof(UWord) ); + VG_(memcpy)( &map2[0], genMap, genMap_size * sizeof(UWord) ); + HG_(free)( genMap ); + genMap = map2; + genMap_size += more; + ea = genMap_size - 1;; + tl_assert(genMap_min + genMap_size - 1 == key); + if (0) VG_(printf)("(%lu) case 3 [%lu .. %lu]\n", + key, genMap_min, genMap_min+genMap_size- 1 ); + } + /* END find 'ea' from 'key' */ + + tl_assert(ea >= 0 && ea < genMap_size); + /* and the whole point of this elaborate compuation of 'ea' is .. */ + genMap[ea]++; } - tl_assert(VG_(sizeFM)(genMap) > 0); + tl_assert(genMap); + tl_assert(genMap_size > 0); + + /* Sanity check what we just computed */ + { UWord sum = 0; + for (i = 0; i < genMap_size; i++) { + if (0) VG_(printf)(" xxx: gen %ld has %lu\n", + i + genMap_min, genMap[i] ); + sum += genMap[i]; + } + tl_assert(sum == oldrefTreeN); + } + /* Figure out how many generations to throw away */ retained = oldrefTreeN; maxGen = 0; - VG_(initIterFM)( genMap ); - while (VG_(nextIterFM)( genMap, &keyW, &valW )) { + + for (i = 0; i < genMap_size; i++) { + keyW = i + genMap_min; + valW = genMap[i]; tl_assert(keyW > 0); /* can't allow a generation # 0 */ if (0) VG_(printf)(" XXX: gen %lu has %lu\n", keyW, valW ); tl_assert(keyW >= maxGen); @@ -3063,9 +3152,8 @@ static void event_map_maybe_GC ( void ) break; } } - VG_(doneIterFM)( genMap ); - VG_(deleteFM)( genMap, NULL, NULL ); + HG_(free)(genMap); tl_assert(retained >= 0 && retained <= oldrefTreeN); @@ -3073,7 +3161,7 @@ static void event_map_maybe_GC ( void ) delete. We can't simultaneously traverse the tree and delete stuff from it, so first we need to copy them off somewhere else. (sigh) */ - refs2del = VG_(newXA)( HG_(zalloc), "libhb.emmG.1", + refs2del = VG_(newXA)( HG_(zalloc), "libhb.emmG.2", HG_(free), sizeof(OldRef*) ); if (retained < oldrefTreeN) {