If .vts == NULL, then this entry is not in use, so:
- .rc == 0
- this entry is on the freelist (unfortunately, does not imply
- any constraints on value for .freelink)
+ any constraints on value for u.freelink)
If .vts != NULL, then this entry is in use:
- .vts is findable in vts_set
- .vts->id == this entry number
- no specific value for .rc (even 0 is OK)
- - this entry is not on freelist, so .freelink == VtsID_INVALID
+ - this entry is not on freelist, so u.freelink == VtsID_INVALID
*/
typedef
struct {
VTS* vts; /* vts, in vts_set */
UWord rc; /* reference count - enough for entire aspace */
- VtsID freelink; /* chain for free entries, VtsID_INVALID at end */
- VtsID remap; /* used only during pruning */
+ union {
+ VtsID freelink; /* chain for free entries, VtsID_INVALID at end */
+ VtsID remap; /* used only during pruning, for used entries */
+ } u;
+ /* u.freelink only used when vts == NULL,
+ u.remap only used when vts != NULL, during pruning. */
}
VtsTE;
VtsTE* ie = VG_(indexXA)( vts_tab, ii );
tl_assert(ie->vts == NULL);
tl_assert(ie->rc == 0);
- tl_assert(ie->freelink == VtsID_INVALID);
- ie->freelink = vts_tab_freelist;
+ tl_assert(ie->u.freelink == VtsID_INVALID);
+ ie->u.freelink = vts_tab_freelist;
vts_tab_freelist = ii;
}
ie = VG_(indexXA)( vts_tab, ii );
tl_assert(ie->vts == NULL);
tl_assert(ie->rc == 0);
- vts_tab_freelist = ie->freelink;
+ vts_tab_freelist = ie->u.freelink;
return ii;
}
return ii;
te.vts = NULL;
te.rc = 0;
- te.freelink = VtsID_INVALID;
- te.remap = VtsID_INVALID;
+ te.u.freelink = VtsID_INVALID;
ii = (VtsID)VG_(addToXA)( vts_tab, &te );
return ii;
}
VtsTE* ie = VG_(indexXA)( vts_tab, ii );
ie->vts = in_tab;
ie->rc = 0;
- ie->freelink = VtsID_INVALID;
+ ie->u.freelink = VtsID_INVALID;
in_tab->id = ii;
return ii;
}
old_id = *ii;
old_te = VG_(indexXA)( old_tab, old_id );
old_te->rc--;
- new_id = old_te->remap;
+ new_id = old_te->u.remap;
new_te = VG_(indexXA)( new_tab, new_id );
new_te->rc++;
*ii = new_id;
VTS__delete(te->vts);
te->vts = NULL;
/* and finally put this entry on the free list */
- tl_assert(te->freelink == VtsID_INVALID); /* can't already be on it */
+ tl_assert(te->u.freelink == VtsID_INVALID); /* can't already be on it */
add_to_free_list( i );
nFreed++;
}
verydead_thread_table_sort_and_check (verydead_thread_table_not_pruned);
/* We will run through the old table, and create a new table and
- set, at the same time setting the .remap entries in the old
+ set, at the same time setting the u.remap entries in the old
table to point to the new entries. Then, visit every VtsID in
the system, and replace all of them with new ones, using the
- .remap entries in the old table. Finally, we can delete the old
+ u.remap entries in the old table. Finally, we can delete the old
table and set. */
XArray* /* of VtsTE */ new_tab
/* For each old VTS .. */
VtsTE* old_te = VG_(indexXA)( vts_tab, i );
VTS* old_vts = old_te->vts;
- tl_assert(old_te->remap == VtsID_INVALID);
/* Skip it if not in use */
if (old_te->rc == 0) {
tl_assert(old_vts == NULL);
continue;
}
+ tl_assert(old_te->u.remap == VtsID_INVALID);
tl_assert(old_vts != NULL);
tl_assert(old_vts->id == i);
tl_assert(old_vts->ts != NULL);
VtsTE new_te;
new_te.vts = new_vts;
new_te.rc = 0;
- new_te.freelink = VtsID_INVALID;
- new_te.remap = VtsID_INVALID;
+ new_te.u.freelink = VtsID_INVALID;
Word j = VG_(addToXA)( new_tab, &new_te );
tl_assert(j <= i);
tl_assert(j == new_VtsID_ctr - 1);
nAfterPruning++;
nSTSsAfter += new_vts->usedTS;
}
- old_te->remap = new_vts->id;
+ old_te->u.remap = new_vts->id;
} /* for (i = 0; i < nTab; i++) */
}
/* At this point, we have:
- * the old VTS table, with its .remap entries set,
+ * the old VTS table, with its u.remap entries set,
and with all .vts == NULL.
* the old VTS tree should be empty, since it and the old VTSs
it contained have been incrementally deleted was we worked
through the old table.
- * the new VTS table, with all .rc == 0, all .freelink and .remap
+ * the new VTS table, with all .rc == 0, all u.freelink and u.remap
== VtsID_INVALID.
* the new VTS tree.
*/
Nowhere else, AFAICS. Not in the zsm cache, because that just
got invalidated.
- Using the .remap fields in vts_tab, map each old VtsID to a new
+ Using the u.remap fields in vts_tab, map each old VtsID to a new
VtsID. For each old VtsID, dec its rc; and for each new one,
inc it. This sets up the new refcounts, and it also gives a
cheap sanity check of the old ones: all old refcounts should be
VtsTE* te = VG_(indexXA)( vts_tab, i );
tl_assert(te->vts == NULL);
/* This is the assert proper. Note we're also asserting
- zeroness for old entries which are unmapped (hence have
- .remap == VtsID_INVALID). That's OK. */
+ zeroness for old entries which are unmapped. That's OK. */
tl_assert(te->rc == 0);
}
tl_assert(te->vts);
tl_assert(te->vts->id == i);
tl_assert(te->rc > 0); /* 'cos we just GC'd */
- tl_assert(te->freelink == VtsID_INVALID); /* in use */
- tl_assert(te->remap == VtsID_INVALID); /* not relevant */
+ tl_assert(te->u.freelink == VtsID_INVALID); /* in use */
+ /* value of te->u.remap not relevant */
}
/* And we're done. Bwahahaha. Ha. Ha. Ha. */
stats__vts_set__focaa, stats__vts_set__focaa_a );
VG_(printf)( " libhb: VTSops: indexAt_SLOW %'lu\n",
stats__vts__indexat_slow );
+ show_vts_stats ("libhb stats");
VG_(printf)("%s","\n");
VG_(printf)(
// model e.g. multiple threads, many different stack traces touching
// the memory, better working set distribution, ...
-static int nr_mb = 0; // total nr of mb used by the program
-static int nr_mb_ws = 0; // nr_mb in program working set
-static int nr_loops = 0; // nr of loops reading or writing the ws
+static int sz_b; // size of a block
+static int nr_b; // total nr of blocks used by the program
+static int nr_b_ws; // nr_b in program working set
+static int nr_loops; // nr of loops reading or writing the ws
static int nr_thr; // nr of threads (hardcoded to 1 currently)
+static int nr_repeat; // nr of times we will allocate, use, then free total+ws
-// Note: the total nr of mb is what is explicitely allocated.
+// Note: the total nr of MB is what is explicitely allocated.
// On top of that, we have the stacks, local vars, lib vars, ...
-// The working set is just the first nr_mb_ws of nr_mb.
+// The working set is just the first nr_b_ws blocks of nr_b.
static int verbose = 0;
-static unsigned char **mb;
+static unsigned char **t_b; // Pointers to all blocks
static void *memrw_fn(void *v)
{
// Note: in case of multiple threads, we will have
// to add lock/unlock somewhere in the below, maybe to lock
// the MB we are reading or writing.
- for (m = 0; m < nr_mb_ws; m++) {
- for (b = 0; b < 1024 * 1024; b++) {
+ for (m = 0; m < nr_b_ws; m++) {
+ for (b = 0; b < sz_b; b++) {
dowrite = b % 5 == 0;
// Do some write or read operations.
if (dowrite) {
- if (mb[m][b] < 255)
- mb[m][b] += differs;
+ if (t_b[m][b] < 255)
+ t_b[m][b] += differs;
else
- mb[m][b] = 0;
+ t_b[m][b] = 0;
} else {
- differs = mb[m][b] != prev;
- prev = mb[m][b];
+ differs = t_b[m][b] != prev;
+ prev = t_b[m][b];
}
}
}
int a;
int ret;
int i;
+ int r;
pthread_t thr;
- // usage: memrw [-t nr_mb default 10] [-w nr_mb_ws default 10]
+ // usage: memrw [-b blocksize default 1MB ]
+ // [-t nr_b default 10] [-w nr_b_ws default 10]
// [-l nr_loops_on_ws default 3]
+ // [-r nr_repeat default 1]
// [-f fan_out default 0]
// [-v verbosity default 0]
- nr_mb = 10;
- nr_mb_ws = 10;
+ sz_b = 1024 * 1024;
+ nr_b = 10;
+ nr_b_ws = 10;
nr_loops = 3;
+ nr_repeat = 1;
verbose = 0;
for (a = 1; a < argc; a+=2) {
- if (strcmp(argv[a], "-t") == 0) {
- nr_mb = atoi(argv[a+1]);
+ if (strcmp(argv[a], "-b") == 0) {
+ sz_b = atoi(argv[a+1]);
+ } else if (strcmp(argv[a], "-t") == 0) {
+ nr_b = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-w") == 0) {
- nr_mb_ws = atoi(argv[a+1]);
+ nr_b_ws = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-l") == 0) {
nr_loops = atoi(argv[a+1]);
+ } else if (strcmp(argv[a], "-r") == 0) {
+ nr_repeat = atoi(argv[a+1]);
} else if (strcmp(argv[a], "-v") == 0) {
verbose = atoi(argv[a+1]);
} else {
printf("unknown arg %s\n", argv[a]);
}
}
- if (nr_mb_ws > nr_mb)
- nr_mb_ws = nr_mb; // to make it easy to do loops combining values
+ if (nr_b_ws > nr_b)
+ nr_b_ws = nr_b; // to make it easy to do loops combining values
nr_thr = 1;
printf ("total program memory -t %d MB"
- " working set -w %d MB"
- " working set R or W -l %d times"
- "\n",
- nr_mb,
- nr_mb_ws,
- nr_loops);
+ " working set -w %d MB\n",
+ (nr_b * sz_b) / (1024*1024),
+ (nr_b_ws * sz_b) / (1024*1024));
+ printf (" working set R or W -l %d times"
+ " repeat the whole stuff -r %d times\n",
+ nr_loops,
+ nr_repeat);
- printf ("creating and initialising the total program memory\n");
- mb = malloc(nr_mb * sizeof(char*));
- if (mb == NULL)
- perror("malloc mb");
- for (i = 0; i < nr_mb; i++) {
- mb[i] = calloc(1024*1024, 1);
- if (mb[i] == NULL)
- perror("malloc mb[i]");
- }
-
- printf("starting thread that will read or write the working set\n");
- ret = pthread_create(&thr, NULL, memrw_fn, &nr_thr);
- if (ret != 0)
- perror("pthread_create");
- printf("waiting for thread termination\n");
+ for (r = 0; r < nr_repeat; r++) {
+ printf ("creating and initialising the total program memory\n");
+ t_b = malloc(nr_b * sizeof(char*));
+ if (t_b == NULL)
+ perror("malloc t_b");
+ for (i = 0; i < nr_b; i++) {
+ t_b[i] = calloc(sz_b, 1);
+ if (t_b[i] == NULL)
+ perror("malloc t_b[i]");
+ }
+
+ printf("starting thread that will read or write the working set\n");
+ ret = pthread_create(&thr, NULL, memrw_fn, &nr_thr);
+ if (ret != 0)
+ perror("pthread_create");
+ printf("waiting for thread termination\n");
+
+ ret = pthread_join(thr, NULL);
+ if (ret != 0)
+ perror("pthread_join");
+ printf("thread terminated\n");
- ret = pthread_join(thr, NULL);
- if (ret != 0)
- perror("pthread_join");
- printf("thread terminated\n");
+ /* Now, free the memory used, for the next repeat */
+ for (i = 0; i < nr_b; i++)
+ free (t_b[i]);
+ free (t_b);
+ printf("memory freed\n");
+ }
return 0;
}