mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-05 03:07:56 +00:00
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
This commit is contained in:
parent
36ca6df95a
commit
468ca56d5d
@ -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 );
|
||||
}
|
||||
/* now valW is the old count for generation 'key' */
|
||||
VG_(addToFM)(genMap, key, valW+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;
|
||||
}
|
||||
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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user