/* Because each sector contains a hash table of TTEntries, we need to
specify the maximum allowable loading, after which the sector is
deemed full. */
-#define SECTOR_TT_LIMIT_PERCENT 80
+#define SECTOR_TT_LIMIT_PERCENT 65
/* The sector is deemed full when this many entries are in it. */
#define N_TTES_PER_SECTOR_USABLE \
static Int tc_sector_szQ;
+/* A list of sector numbers, in the order which they should be
+ searched to find translations. This is an optimisation to be used
+ when searching for translations and should not affect
+ correctness. -1 denotes "no entry". */
+static Int sector_search_order[N_SECTORS];
+
+
/* Fast helper for the TC. A direct-mapped cache which holds a set of
recently used (guest address, host address) pairs. This array is
referred to directly from m_dispatch/dispatch-<platform>.S.
static Bool sanity_check_redir_tt_tc ( void );
static Bool sanity_check_fastcache ( void );
+static Bool sanity_check_sector_search_order ( void )
+{
+ Int i, j, nListed;
+ /* assert the array is the right size */
+ vg_assert(N_SECTORS == (sizeof(sector_search_order)
+ / sizeof(sector_search_order[0])));
+ /* Check it's of the form valid_sector_numbers ++ [-1, -1, ..] */
+ for (i = 0; i < N_SECTORS; i++) {
+ if (sector_search_order[i] < 0 || sector_search_order[i] >= N_SECTORS)
+ break;
+ }
+ nListed = i;
+ for (/* */; i < N_SECTORS; i++) {
+ if (sector_search_order[i] != -1)
+ break;
+ }
+ if (i != N_SECTORS)
+ return False;
+ /* Check each sector number only appears once */
+ for (i = 0; i < N_SECTORS; i++) {
+ if (sector_search_order[i] == -1)
+ continue;
+ for (j = i+1; j < N_SECTORS; j++) {
+ if (sector_search_order[j] == sector_search_order[i])
+ return False;
+ }
+ }
+ /* Check that the number of listed sectors equals the number
+ in use, by counting nListed back down. */
+ for (i = 0; i < N_SECTORS; i++) {
+ if (sectors[i].tc != NULL)
+ nListed--;
+ }
+ if (nListed != 0)
+ return False;
+ return True;
+}
+
static Bool sanity_check_all_sectors ( void )
{
Int sno;
return False;
if ( !sanity_check_fastcache() )
return False;
+ if ( !sanity_check_sector_search_order() )
+ return False;
return True;
}
+
/*-------------------------------------------------------------*/
/*--- Add/find translations ---*/
/*-------------------------------------------------------------*/
Sector* sec;
vg_assert(isValidSector(sno));
+ { Bool sane = sanity_check_sector_search_order();
+ vg_assert(sane);
+ }
sec = §ors[sno];
if (sec->tc == NULL) {
sec->tt[i].n_tte2ec = 0;
}
+ /* Add an entry in the sector_search_order */
+ for (i = 0; i < N_SECTORS; i++) {
+ if (sector_search_order[i] == -1)
+ break;
+ }
+ vg_assert(i >= 0 && i < N_SECTORS);
+ sector_search_order[i] = sno;
+
if (VG_(clo_verbosity) > 2)
VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d\n", sno);
}
}
+ /* Sanity check: ensure it is already in
+ sector_search_order[]. */
+ for (i = 0; i < N_SECTORS; i++) {
+ if (sector_search_order[i] == sno)
+ break;
+ }
+ vg_assert(i >= 0 && i < N_SECTORS);
+
if (VG_(clo_verbosity) > 2)
VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d\n", sno);
}
sec->tt_n_inuse = 0;
invalidateFastCache();
+
+ { Bool sane = sanity_check_sector_search_order();
+ vg_assert(sane);
+ }
}
static void invalidate_icache ( void *ptr, Int nbytes )
kstart = HASH_TT(guest_addr);
vg_assert(kstart >= 0 && kstart < N_TTES_PER_SECTOR);
- /* Search in all the sectors. Although the order should not matter,
- it might be most efficient to search in the order youngest to
- oldest. */
- sno = youngest_sector;
+ /* Search in all the sectors,using sector_search_order[] as a
+ heuristic guide as to what order to visit the sectors. */
for (i = 0; i < N_SECTORS; i++) {
- if (sectors[sno].tc == NULL)
- goto notfound; /* sector not in use. */
+ sno = sector_search_order[i];
+ if (UNLIKELY(sno == -1))
+ return False; /* run out of sectors to search */
k = kstart;
for (j = 0; j < N_TTES_PER_SECTOR; j++) {
§ors[sno].tt[k].count );
if (result)
*result = (AddrH)sectors[sno].tt[k].tcptr;
+ /* pull this one one step closer to the front. For large
+ apps this more or less halves the number of required
+ probes. */
+ if (i > 0) {
+ Int tmp = sector_search_order[i-1];
+ sector_search_order[i-1] = sector_search_order[i];
+ sector_search_order[i] = tmp;
+ }
return True;
}
if (sectors[sno].tt[k].status == Empty)
/* If we fall off the end, all entries are InUse and not
matching, or Deleted. In any case we did not find it in this
sector. */
-
- notfound:
- /* move to the next oldest sector */
- sno = sno==0 ? (N_SECTORS-1) : (sno-1);
}
/* Not found in any sector. */
}
}
+ /* Initialise the sector_search_order hint table. */
+ for (i = 0; i < N_SECTORS; i++)
+ sector_search_order[i] = -1;
+
/* Initialise the fast caches. If not profiling (the usual case),
we have to explicitly invalidate the fastN cache as
invalidateFastCache() won't do that for us. */