|
From: <sv...@va...> - 2005-05-13 23:40:57
|
Author: njn
Date: 2005-05-14 00:40:55 +0100 (Sat, 14 May 2005)
New Revision: 3703
Added:
trunk/coregrind/m_transtab.c
trunk/coregrind/pub_core_transtab.h
Removed:
trunk/coregrind/vg_transtab.c
Modified:
trunk/coregrind/Makefile.am
trunk/coregrind/core.h
trunk/coregrind/m_aspacemgr/aspacemgr.c
trunk/coregrind/m_translate.c
trunk/coregrind/vg_main.c
trunk/coregrind/vg_redir.c
trunk/coregrind/vg_scheduler.c
Log:
Modularised vg_transtab.c as m_transtab.
Renamed add_to_trans_tab() as add_to_transtab() for consistency
with the other names.
Modified: trunk/coregrind/Makefile.am
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/Makefile.am 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/Makefile.am 2005-05-13 23:40:55 UTC (rev 3703)
@@ -53,6 +53,7 @@
pub_core_syscalls.h \
pub_core_tooliface.h \
pub_core_translate.h \
+ pub_core_transtab.h \
ume.h \
vg_symtab2.h \
vg_symtypes.h
@@ -80,6 +81,7 @@
m_stacktrace.c \
m_tooliface.c \
m_translate.c \
+ m_transtab.c \
ume.c \
\
vg_scheduler.c \
@@ -95,8 +97,7 @@
vg_redir.c \
vg_dwarf.c \
vg_stabs.c \
- vg_symtypes.c \
- vg_transtab.c
+ vg_symtypes.c
=20
## libplatform.a must be before libarch.a and libos.a, it seems.
stage2_extra=3D \
Modified: trunk/coregrind/core.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/core.h 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/core.h 2005-05-13 23:40:55 UTC (rev 3703)
@@ -759,38 +759,6 @@
=20
=20
/* ---------------------------------------------------------------------
- Exports of vg_transtab.c
- ------------------------------------------------------------------ */
-
-/* The fast-cache for tt-lookup, and for finding counters. */
-extern ULong* VG_(tt_fast) [VG_TT_FAST_SIZE];
-extern UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
-
-
-extern void VG_(init_tt_tc) ( void );
-
-extern
-void VG_(add_to_trans_tab)( VexGuestExtents* vge,
- Addr64 entry,
- AddrH code,
- UInt code_len );
-
-extern Bool VG_(search_transtab) ( /*OUT*/AddrH* result,
- Addr64 guest_addr,=20
- Bool upd_cache );
-
-extern void VG_(discard_translations) ( Addr64 start, UInt range );
-
-extern void VG_(sanity_check_tt_tc) ( Char* caller );
-
-extern void VG_(print_tt_tc_stats) ( void );
-
-extern UInt VG_(get_bbs_translated) ( void );
-
-extern void VG_(show_BB_profile) ( void );
-
-
-/* ---------------------------------------------------------------------
Exports of vg_syscall.S
------------------------------------------------------------------ */
=20
Modified: trunk/coregrind/m_aspacemgr/aspacemgr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_aspacemgr/aspacemgr.c 2005-05-13 23:32:43 UTC (rev =
3702)
+++ trunk/coregrind/m_aspacemgr/aspacemgr.c 2005-05-13 23:40:55 UTC (rev =
3703)
@@ -34,6 +34,7 @@
#include "pub_core_aspacemgr.h"
#include "pub_core_syscalls.h"
#include "pub_core_tooliface.h"
+#include "pub_core_transtab.h"
#include "vki_unistd.h"
=20
=20
Modified: trunk/coregrind/m_translate.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_translate.c 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/m_translate.c 2005-05-13 23:40:55 UTC (rev 3703)
@@ -32,6 +32,8 @@
#include "core.h"
#include "pub_core_aspacemgr.h"
#include "pub_core_tooliface.h"
+#include "pub_core_translate.h"
+#include "pub_core_transtab.h"
=20
=20
/*------------------------------------------------------------*/
@@ -496,10 +498,10 @@
if (!debugging_translation) {
// Note that we use orig_addr0, not orig_addr, which might have be=
en
// changed by the redirection
- VG_(add_to_trans_tab)( &vge,
- orig_addr0,
- (Addr)(&tmpbuf[0]),=20
- tmpbuf_used );
+ VG_(add_to_transtab)( &vge,
+ orig_addr0,
+ (Addr)(&tmpbuf[0]),=20
+ tmpbuf_used );
}
=20
VGP_POPCC(VgpTranslate);
Copied: trunk/coregrind/m_transtab.c (from rev 3700, trunk/coregrind/vg_t=
ranstab.c)
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_transtab.c 2005-05-13 23:11:40 UTC (rev 3700)
+++ trunk/coregrind/m_transtab.c 2005-05-13 23:40:55 UTC (rev 3703)
@@ -0,0 +1,810 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Management of the translation table and cache. ---*/
+/*--- m_transtab.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2005 Julian Seward=20
+ js...@ac...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "core.h"
+#include "pub_core_tooliface.h"
+// XXX: this module should not depend on m_translate!
+#include "pub_core_translate.h"
+#include "pub_core_transtab.h"
+
+/* #define DEBUG_TRANSTAB */
+
+
+/*-------------------------------------------------------------*/
+/*--- Management of the FIFO-based translation table+cache. ---*/
+/*-------------------------------------------------------------*/
+
+/*------------------ CONSTANTS ------------------*/
+
+/* Number of sectors the TC is divided into. If you need a larger
+ overall translation cache, increase this value. */
+#define N_SECTORS 8
+
+/* Number of TC entries in each sector. This needs to be a prime
+ number to work properly, and it is strongly recommended not to
+ change this. */
+#define N_TTES_PER_SECTOR /*30011*/ 40009
+
+/* 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 60
+
+/* The sector is deemed full when this many entries are in it. */
+#define N_TTES_PER_SECTOR_USABLE \
+ ((N_TTES_PER_SECTOR * SECTOR_TT_LIMIT_PERCENT) / 100)
+
+
+/*------------------ TYPES ------------------*/
+
+/* A translation-cache entry is two parts:
+ - The guest address of the first (entry) bb in the translation,
+ as a 64-bit word.
+ - One or more 64-bit words containing the code.
+ It is supposed to be 64-bit aligned.
+*/
+/*
+typedef
+ struct {
+ Addr64 orig_addr;
+ ULong code[0];
+ }
+ TCEntry;
+*/
+
+/* A translation-table entry. This indicates precisely which areas of
+ guest code are included in the translation, and contains all other
+ auxiliary info too. */
+typedef
+ struct {
+ /* Profiling only: the count and weight (arbitrary meaning) for
+ this translation. Weight is a property of the translation
+ itself and computed once when the translation is created.
+ Count is an entry count for the translation and is
+ incremented by 1 every time the translation is used, if we
+ are profiling. */
+ UInt count;
+ UShort weight;
+
+ /* Status of the slot. Note, we need to be able to do lazy
+ deletion, hence the Deleted state. */
+ enum { InUse, Deleted, Empty } status;
+
+ /* Pointer to the corresponding TCEntry (must be in the same
+ sector!) */
+ ULong* tce;
+
+ /* This is the original guest address that purportedly is the
+ entry point of the translation. You might think that .entry
+ should be the same as .vge->base[0], and most of the time it
+ is. However, when doing redirections, that is not the case.
+ .vge must always correctly describe the guest code sections
+ from which this translation was made. However, .entry may or
+ may not be a lie, depending on whether or not we're doing
+ redirection. */
+ Addr64 entry;
+
+ /* This structure describes precisely what ranges of guest code
+ the translation covers, so we can decide whether or not to
+ delete it when translations of a given address range are
+ invalidated. */
+ VexGuestExtents vge;
+ }
+ TTEntry;
+
+
+/* Finally, a sector itself. Each sector contains an array of
+ TCEntries, which hold code, and an array of TTEntries, containing
+ all required administrative info. Profiling is supported using the
+ TTEntry .count and .weight fields, if required. Each sector is
+ independent in that no cross-sector references are allowed.
+
+ If the sector is not in use, all three pointers are NULL and
+ tt_n_inuse is zero. =20
+*/
+typedef
+ struct {
+ /* The TCEntry area. Size of this depends on the average
+ translation size. We try and size it so it becomes full
+ precisely when this sector's translation table (tt) reaches
+ its load limit (SECTOR_TT_LIMIT_PERCENT). */
+ ULong* tc;
+
+ /* The TTEntry array. This is a fixed size, always containing
+ exactly N_TTES_PER_SECTOR entries. */
+ TTEntry* tt;
+
+ /* This points to the current allocation point in tc. */
+ ULong* tc_next;
+
+ /* The count of tt entries with state InUse. */
+ Int tt_n_inuse;
+ }
+ Sector;
+
+
+/*------------------ DECLS ------------------*/
+
+/* The root data structure is an array of sectors. The index of the
+ youngest sector is recorded, and new translations are put into that
+ sector. When it fills up, we move along to the next sector and
+ start to fill that up, wrapping around at the end of the array.
+ That way, once all N_TC_SECTORS have been bought into use for the
+ first time, and are full, we then re-use the oldest sector,
+ endlessly.=20
+
+ When running, youngest sector should be between >=3D 0 and <
+ N_TC_SECTORS. The initial -1 value indicates the TT/TC system is
+ not yet initialised.=20
+*/
+static Sector sectors[N_SECTORS];
+static Int youngest_sector =3D -1;
+
+/* The number of ULongs in each TCEntry area. This is computed once
+ at startup and does not change. */
+static Int tc_sector_szQ;
+
+
+/* Fast helper for the TC. A direct-mapped cache which holds a
+ pointer to a TC entry which may or may not be the correct one, but
+ which we hope usually is. This array is referred to directly from
+ <arch>/dispatch.S.
+
+ Entries in tt_fast may point to any valid TC entry, regardless of
+ which sector it's in. Consequently we must be very careful to
+ invalidate this cache when TC entries are changed or disappear.
+
+ A special TCEntry -- bogus_tc_entry -- must be pointed at to cause
+ that cache entry to miss. This relies on the assumption that no
+ guest code actually has an address of 0x1.
+*/
+/*global*/ ULong* VG_(tt_fast)[VG_TT_FAST_SIZE];
+
+static ULong bogus_tc_entry =3D (Addr64)1;
+
+
+/* For profiling, we have a parallel array of pointers to .count
+ fields in TT entries. Again, these pointers must be invalidated
+ when translations disappear. A NULL pointer suffices to indicate
+ an unused slot.
+
+ tt_fast and tt_fastN change together: if tt_fast[i] points to
+ bogus_tc_entry then the corresponding tt_fastN[i] must be null. If
+ tt_fast[i] points to some TC entry somewhere, then tt_fastN[i]
+ *must* point to the .count field of the corresponding TT entry.
+
+ tt_fast and tt_fastN are referred to from assembly code
+ (dispatch.S).
+*/
+/*global*/ UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
+
+
+/* Make sure we're not used before initialisation. */
+static Bool init_done =3D False;
+
+
+/*------------------ STATS DECLS ------------------*/
+
+/* Number of fast-cache updates and flushes done. */
+ULong n_fast_flushes =3D 0;
+ULong n_fast_updates =3D 0;
+
+/* Number of full lookups done. */
+ULong n_full_lookups =3D 0;
+ULong n_lookup_probes =3D 0;
+
+/* Number/osize/tsize of translations entered. */
+ULong n_in_count =3D 0;
+ULong n_in_osize =3D 0;
+ULong n_in_tsize =3D 0;
+
+/* Number/osize of translations discarded due to lack of space. */
+ULong n_dump_count =3D 0;
+ULong n_dump_osize =3D 0;
+
+/* Number/osize of translations discarded due to requests to do so. */
+ULong n_disc_count =3D 0;
+ULong n_disc_osize =3D 0;
+
+
+
+/*-------------------------------------------------------------*/
+/*--- Add/delete/find translations ---*/
+/*-------------------------------------------------------------*/
+
+static UInt vge_osize ( VexGuestExtents* vge )
+{
+ UInt i, n =3D 0;
+ for (i =3D 0; i < vge->n_used; i++)
+ n +=3D (UInt)vge->len[i];
+ return n;
+}
+
+static Bool isValidSector ( Int sector )
+{
+ if (sector < 0 || sector >=3D N_SECTORS)
+ return False;
+ return True;
+}
+
+static inline UInt HASH_TT ( Addr64 key )
+{
+ UInt kHi =3D (UInt)(key >> 32);
+ UInt kLo =3D (UInt)key;
+ return (kHi ^ kLo) % N_TTES_PER_SECTOR;
+}
+
+static void setFastCacheEntry ( Addr64 key, ULong* tce, UInt* count )
+{
+ UInt cno =3D ((UInt)key) & VG_TT_FAST_MASK;
+ VG_(tt_fast)[cno] =3D tce;
+ VG_(tt_fastN)[cno] =3D count;
+ n_fast_updates++;
+}
+
+static void invalidateFastCache ( void )
+{
+ UInt j;
+ for (j =3D 0; j < VG_TT_FAST_SIZE; j++) {
+ VG_(tt_fast)[j] =3D &bogus_tc_entry;
+ VG_(tt_fastN)[j] =3D NULL;
+ }
+ n_fast_flushes++;
+}
+
+static void initialiseSector ( Int sno )
+{
+ Int i;
+ vg_assert(isValidSector(sno));
+
+ if (sectors[sno].tc =3D=3D NULL) {
+ /* Sector has never been used before. Need to allocate tt and
+ tc. */
+ vg_assert(sectors[sno].tt =3D=3D NULL);
+ vg_assert(sectors[sno].tc_next =3D=3D NULL);
+ vg_assert(sectors[sno].tt_n_inuse =3D=3D 0);
+ sectors[sno].tc=20
+ =3D VG_(get_memory_from_mmap)
+ ( 8 * tc_sector_szQ, "sectors[sno].tc" );
+ sectors[sno].tt=20
+ =3D VG_(get_memory_from_mmap)=20
+ ( N_TTES_PER_SECTOR * sizeof(TTEntry), "sectors[sno].tt" )=
;
+ if (VG_(clo_verbosity) > 2)
+ VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d", sno);
+ } else {
+ /* Sector has been used before. */
+ vg_assert(sectors[sno].tt !=3D NULL);
+ vg_assert(sectors[sno].tc_next !=3D NULL);
+ n_dump_count +=3D sectors[sno].tt_n_inuse;
+ for (i =3D 0; i < N_TTES_PER_SECTOR; i++) {
+ if (sectors[sno].tt[i].status =3D=3D InUse) {
+ n_dump_osize +=3D vge_osize(§ors[sno].tt[i].vge);
+ }
+ }
+ if (VG_(clo_verbosity) > 2)
+ VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d", sno);
+ }
+
+ sectors[sno].tc_next =3D sectors[sno].tc;
+ sectors[sno].tt_n_inuse =3D 0;
+ for (i =3D 0; i < N_TTES_PER_SECTOR; i++)
+ sectors[sno].tt[i].status =3D Empty;
+
+ invalidateFastCache();
+}
+
+
+/* Add a translation of vge to TT/TC. The translation is temporarily
+ in code[0 .. code_len-1].
+
+ pre: youngest_sector points to a valid (although possibly full)
+ sector.
+*/
+void VG_(add_to_transtab)( VexGuestExtents* vge,
+ Addr64 entry,
+ AddrH code,
+ UInt code_len )
+{
+ Int tcAvailQ, reqdQ, y, i;
+ ULong *tce, *tce2;
+ UChar* srcP;
+ UChar* dstP;
+
+ vg_assert(init_done);
+ vg_assert(vge->n_used >=3D 1 && vge->n_used <=3D 3);
+ vg_assert(code_len > 0 && code_len < 20000);
+
+ if (0)
+ VG_(printf)("add_to_transtab(entry =3D 0x%llx, len =3D %d)\n",
+ entry, code_len);
+
+ n_in_count++;
+ n_in_tsize +=3D code_len;
+ n_in_osize +=3D vge_osize(vge);
+
+ y =3D youngest_sector;
+ vg_assert(isValidSector(y));
+
+ if (sectors[y].tc =3D=3D NULL)
+ initialiseSector(y);
+
+ /* Try putting the translation in this sector. */
+ reqdQ =3D 1 + ((code_len + 7) >> 3);
+
+ /* Will it fit in tc? */
+ tcAvailQ =3D ((ULong*)(§ors[y].tc[tc_sector_szQ]))
+ - ((ULong*)(sectors[y].tc_next));
+ vg_assert(tcAvailQ >=3D 0);
+ vg_assert(tcAvailQ <=3D tc_sector_szQ);
+
+ if (tcAvailQ < reqdQ=20
+ || sectors[y].tt_n_inuse >=3D N_TTES_PER_SECTOR_USABLE) {
+ /* No. So move on to the next sector. Either it's never been
+ used before, in which case it will get its tt/tc allocated
+ now, or it has been used before, in which case it is set to be
+ empty, hence throwing out the oldest sector. */
+ youngest_sector++;
+ if (youngest_sector >=3D N_SECTORS)
+ youngest_sector =3D 0;
+ y =3D youngest_sector;
+ initialiseSector(y);
+ }
+
+ /* Be sure ... */
+ tcAvailQ =3D ((ULong*)(§ors[y].tc[tc_sector_szQ]))
+ - ((ULong*)(sectors[y].tc_next));
+ vg_assert(tcAvailQ >=3D 0);
+ vg_assert(tcAvailQ <=3D tc_sector_szQ);
+ vg_assert(tcAvailQ >=3D reqdQ);
+ vg_assert(sectors[y].tt_n_inuse < N_TTES_PER_SECTOR_USABLE);
+ vg_assert(sectors[y].tt_n_inuse >=3D 0);
+=20
+ /* Copy into tc. */
+ tce =3D sectors[y].tc_next;
+ vg_assert(tce >=3D §ors[y].tc[0]);
+ vg_assert(tce <=3D §ors[y].tc[tc_sector_szQ]);
+
+ tce[0] =3D entry;
+ dstP =3D (UChar*)(&tce[1]);
+ srcP =3D (UChar*)code;
+ for (i =3D 0; i < code_len; i++)
+ dstP[i] =3D srcP[i];
+ sectors[y].tc_next +=3D reqdQ;
+ sectors[y].tt_n_inuse++;
+
+ /* more paranoia */
+ tce2 =3D sectors[y].tc_next;
+ vg_assert(tce2 >=3D §ors[y].tc[0]);
+ vg_assert(tce2 <=3D §ors[y].tc[tc_sector_szQ]);
+
+ /* Find an empty tt slot, and use it. There must be such a slot
+ since tt is never allowed to get completely full. */
+ i =3D HASH_TT(entry);
+ vg_assert(i >=3D 0 && i < N_TTES_PER_SECTOR);
+ while (True) {
+ if (sectors[y].tt[i].status =3D=3D Empty
+ || sectors[y].tt[i].status =3D=3D Deleted)
+ break;
+ i++;
+ if (i >=3D N_TTES_PER_SECTOR)
+ i =3D 0;
+ }
+
+ sectors[y].tt[i].status =3D InUse;
+ sectors[y].tt[i].tce =3D tce;
+ sectors[y].tt[i].count =3D 0;
+ sectors[y].tt[i].weight =3D 1;
+ sectors[y].tt[i].vge =3D *vge;
+ sectors[y].tt[i].entry =3D entry;
+
+ setFastCacheEntry( entry, tce, §ors[y].tt[i].count );
+}
+
+
+/* Search for the translation of the given guest address. If
+ requested, a successful search can also cause the fast-caches to be
+ updated. =20
+*/
+Bool VG_(search_transtab) ( /*OUT*/AddrH* result,
+ Addr64 guest_addr,=20
+ Bool upd_cache )
+{
+ Int i, j, k, kstart, sno;
+
+ vg_assert(init_done);
+ /* Find the initial probe point just once. It will be the same in
+ all sectors and avoids multiple expensive % operations. */
+ n_full_lookups++;
+ k =3D -1;
+ kstart =3D HASH_TT(guest_addr);
+ vg_assert(kstart >=3D 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 =3D youngest_sector;
+ for (i =3D 0; i < N_SECTORS; i++) {
+
+ if (sectors[sno].tc =3D=3D NULL)
+ goto notfound; /* sector not in use. */
+
+ k =3D kstart;
+ for (j =3D 0; j < N_TTES_PER_SECTOR; j++) {
+ n_lookup_probes++;
+ if (sectors[sno].tt[k].status =3D=3D InUse
+ && sectors[sno].tt[k].entry =3D=3D guest_addr) {
+ /* found it */
+ if (upd_cache)
+ setFastCacheEntry(=20
+ guest_addr, sectors[sno].tt[k].tce,=20
+ §ors[sno].tt[k].count );
+ if (result)
+ *result =3D sizeof(Addr64) + (AddrH)sectors[sno].tt[k].tc=
e;
+ return True;
+ }
+ if (sectors[sno].tt[k].status =3D=3D Empty)
+ break; /* not found in this sector */
+ k++;
+ if (k =3D=3D N_TTES_PER_SECTOR)
+ k =3D 0;
+ }
+
+ /* 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 =3D sno=3D=3D0 ? (N_SECTORS-1) : (sno-1);
+ }
+
+ /* Not found in any sector. */
+ return False;
+}
+
+
+/* Delete all translations which intersect with any part of the
+ specified guest address range. Note, this is SLOW.=20
+*/
+
+static inline
+Bool overlap1 ( Addr64 s1, UInt r1, Addr64 s2, UInt r2 )
+{
+ Addr64 e1 =3D s1 + (ULong)r1 - 1ULL;
+ Addr64 e2 =3D s2 + (ULong)r1 - 1ULL;
+ if (e1 < s2 || e2 < s1)=20
+ return False;
+ return True;
+}
+
+static inline
+Bool overlaps ( Addr64 start, UInt range, VexGuestExtents* vge )
+{
+ if (overlap1(start, range, vge->base[0], (UInt)vge->len[0]))
+ return True;
+ if (vge->n_used < 2)
+ return False;
+ if (overlap1(start, range, vge->base[1], (UInt)vge->len[1]))
+ return True;
+ if (vge->n_used < 3)
+ return False;
+ if (overlap1(start, range, vge->base[2], (UInt)vge->len[2]))
+ return True;
+ return False;
+}
+
+
+void VG_(discard_translations) ( Addr64 guest_start, UInt range )
+{
+ Int sno, i;
+ Bool anyDeleted =3D False;
+
+ vg_assert(init_done);
+
+ for (sno =3D 0; sno < N_SECTORS; sno++) {
+ if (sectors[sno].tc =3D=3D NULL)
+ continue;
+ for (i =3D 0; i < N_TTES_PER_SECTOR; i++) {
+ if (sectors[sno].tt[i].status =3D=3D InUse
+ && overlaps( guest_start, range, §ors[sno].tt[i].vge ))=
{
+ sectors[sno].tt[i].status =3D Deleted;
+ sectors[sno].tt_n_inuse--;
+ anyDeleted =3D True;
+ n_disc_count++;
+ n_disc_osize +=3D vge_osize(§ors[sno].tt[i].vge);
+ }
+ } =20
+ }
+
+ if (anyDeleted)
+ invalidateFastCache();
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Sanity checking ---*/
+/*------------------------------------------------------------*/
+
+void VG_(sanity_check_tt_tc) ( Char* who )
+{
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Initialisation. ---*/
+/*------------------------------------------------------------*/
+
+void VG_(init_tt_tc) ( void )
+{
+ Int i, avg_codeszQ;
+
+ vg_assert(!init_done);
+ init_done =3D True;
+
+ /* Otherwise lots of things go wrong... */
+ vg_assert(sizeof(ULong) =3D=3D 8);
+ vg_assert(sizeof(Addr64) =3D=3D 8);
+
+ if (VG_(clo_verbosity) > 2)
+ VG_(message)(Vg_DebugMsg,=20
+ "TT/TC: VG_(init_tt_tc) "
+ "(startup of code management)");
+
+ /* Figure out how big each tc area should be. */
+ avg_codeszQ =3D (VG_(details).avg_translation_sizeB + 7) / 8;
+ tc_sector_szQ =3D N_TTES_PER_SECTOR_USABLE * (1 + avg_codeszQ);
+
+ /* Ensure the calculated value is not way crazy. */
+ vg_assert(tc_sector_szQ >=3D 2 * N_TTES_PER_SECTOR_USABLE);
+ vg_assert(tc_sector_szQ <=3D 50 * N_TTES_PER_SECTOR_USABLE);
+
+ /* Initialise the sectors */
+ youngest_sector =3D 0;
+ for (i =3D 0; i < N_SECTORS; i++) {
+ sectors[i].tc =3D NULL;
+ sectors[i].tt =3D NULL;
+ sectors[i].tc_next =3D NULL;
+ sectors[i].tt_n_inuse =3D 0;
+ }
+
+ /* and the fast caches. */
+ invalidateFastCache();
+
+ if (VG_(clo_verbosity) > 2) {
+ VG_(message)(Vg_DebugMsg,
+ "TT/TC: cache: %d sectors of %d bytes each =3D %d total",=20
+ N_SECTORS, 8 * tc_sector_szQ,
+ N_SECTORS * 8 * tc_sector_szQ );
+ VG_(message)(Vg_DebugMsg,
+ "TT/TC: table: %d total entries, max occupancy %d (%d%%)",
+ N_SECTORS * N_TTES_PER_SECTOR,
+ N_SECTORS * N_TTES_PER_SECTOR_USABLE,=20
+ SECTOR_TT_LIMIT_PERCENT );
+ }
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Printing out statistics. ---*/
+/*------------------------------------------------------------*/
+
+static ULong safe_idiv( ULong a, ULong b )
+{
+ return (b =3D=3D 0 ? 0 : a / b);
+}
+
+UInt VG_(get_bbs_translated) ( void )
+{
+ return n_in_count;
+}
+
+void VG_(print_tt_tc_stats) ( void )
+{
+ VG_(message)(Vg_DebugMsg,
+ " tt/tc: %llu tt lookups requiring %llu probes",=20
+ n_full_lookups, n_lookup_probes );
+ VG_(message)(Vg_DebugMsg,
+ " tt/tc: %llu fast-cache updates, %llu flushes",=20
+ n_fast_updates, n_fast_flushes );
+
+ VG_(message)(Vg_DebugMsg,
+ "translate: new %lld (%lld -> %lld; ratio %lld:10=
)",
+ n_in_count, n_in_osize, n_in_tsize,
+ safe_idiv(10*n_in_tsize, n_in_osize));
+ VG_(message)(Vg_DebugMsg,
+ "translate: dumped %lld (%lld -> ?" "?)",
+ n_dump_count, n_dump_osize );
+ VG_(message)(Vg_DebugMsg,
+ "translate: discarded %lld (%lld -> ?" "?)",
+ n_disc_count, n_disc_osize );
+}
+
+/*------------------------------------------------------------*/
+/*--- Printing out of profiling results. ---*/
+/*------------------------------------------------------------*/
+
+/* Only the top N_MAX bbs will be displayed. */
+#define N_MAX 200
+
+static TTEntry* tops[N_MAX];
+
+static ULong score ( TTEntry* tte )
+{
+ return ((ULong)tte->weight) * ((ULong)tte->count);
+}
+
+static Bool heavier ( TTEntry* t1, TTEntry* t2 )
+{
+ return score(t1) > score(t2);
+}
+
+/* Print n/m in form xx.yy% */
+static
+void percentify ( ULong n, ULong m, Int field_width, Char* buf)
+{
+ Int i, len, space;
+ ULong lo, hi;
+ if (m =3D=3D 0) m =3D 1; /* stay sane */
+ hi =3D (n * 100) / m;
+ lo =3D (((n * 100) - hi * m) * 100) / m;
+ vg_assert(lo < 100);
+ if (lo < 10)
+ VG_(sprintf)(buf, "%lld.0%lld%%", hi, lo);
+ else
+ VG_(sprintf)(buf, "%lld.%lld%%", hi, lo);
+
+ len =3D VG_(strlen)(buf);
+ space =3D field_width - len;
+ if (space < 0) space =3D 0; /* Allow for v. small field_width */
+ i =3D len;
+
+ /* Right justify in field */
+ for ( ; i >=3D 0; i--) buf[i + space] =3D buf[i];
+ for (i =3D 0; i < space; i++) buf[i] =3D ' ';
+}
+
+
+void VG_(show_BB_profile) ( void )
+{
+ Char name[64];
+ Int sno, i, r, s;
+ ULong score_total, score_cumul, score_here;
+ Char buf_cumul[10];
+ Char buf_here[10];
+
+ /* First, compute the total weighted count, and find the top N
+ ttes. tops contains pointers to the most-used N_MAX blocks, in
+ descending order (viz, tops[0] is the highest scorer). */
+ for (i =3D 0; i < N_MAX; i++)
+ tops[i] =3D NULL;
+
+ score_total =3D 0;
+
+ for (sno =3D 0; sno < N_SECTORS; sno++) {
+ if (sectors[sno].tc =3D=3D NULL)
+ continue;
+ for (i =3D 0; i < N_TTES_PER_SECTOR; i++) {
+ if (sectors[sno].tt[i].status !=3D InUse)
+ continue;
+ score_total +=3D score(§ors[sno].tt[i]);
+ /* Find the rank for sectors[sno].tt[i]. */
+ r =3D N_MAX-1;
+ while (True) {
+ if (r =3D=3D -1)
+ break;
+ if (tops[r] =3D=3D NULL) {
+ r--;=20
+ continue;
+ }
+ if (heavier(§ors[sno].tt[i], tops[r])) {
+ r--;
+ continue;
+ }
+ break;
+ }
+ r++;
+ vg_assert(r >=3D 0 && r <=3D N_MAX);
+ /* This bb should be placed at r, and bbs above it shifted
+ upwards one slot. */
+ if (r < N_MAX) {
+ for (s =3D N_MAX-1; s > r; s--)
+ tops[s] =3D tops[s-1];
+ tops[r] =3D §ors[sno].tt[i];
+ }
+ }
+ }
+
+ VG_(printf)("\n");
+ VG_(printf)("--------------------------------------------------------=
----\n");
+ VG_(printf)("--- BEGIN BB Profile (summary of scores) =
---\n");
+ VG_(printf)("--------------------------------------------------------=
----\n");
+ VG_(printf)("\n");
+
+ VG_(printf)("Total score =3D %lld\n\n", score_total);
+
+ score_cumul =3D 0;
+ for (r =3D 0; r < N_MAX; r++) {
+ if (tops[r] =3D=3D NULL)
+ continue;
+ name[0] =3D 0;
+ VG_(get_fnname_w_offset)(tops[r]->entry, name, 64);
+ name[63] =3D 0;
+ score_here =3D score(tops[r]);
+ score_cumul +=3D score_here;
+ percentify(score_cumul, score_total, 6, buf_cumul);
+ percentify(score_here, score_total, 6, buf_here);
+ VG_(printf)("%3d: (%9lld %s) %9lld %s 0x%llx %s\n",
+ r,
+ score_cumul, buf_cumul,
+ score_here, buf_here, tops[r]->entry, name );
+ }
+
+ VG_(printf)("\n");
+ VG_(printf)("--------------------------------------------------------=
----\n");
+ VG_(printf)("--- BB Profile (BB details) =
---\n");
+ VG_(printf)("--------------------------------------------------------=
----\n");
+ VG_(printf)("\n");
+
+ score_cumul =3D 0;
+ for (r =3D 0; r < N_MAX; r++) {
+ if (tops[r] =3D=3D NULL)
+ continue;
+ name[0] =3D 0;
+ VG_(get_fnname_w_offset)(tops[r]->entry, name, 64);
+ name[63] =3D 0;
+ score_here =3D score(tops[r]);
+ score_cumul +=3D score_here;
+ percentify(score_cumul, score_total, 6, buf_cumul);
+ percentify(score_here, score_total, 6, buf_here);
+ VG_(printf)("\n");
+ VG_(printf)("=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
begin BB rank %d "
+ "=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
\n\n", r);
+ VG_(printf)("%3d: (%9lld %s) %9lld %s 0x%llx %s\n",
+ r,
+ score_cumul, buf_cumul,
+ score_here, buf_here, tops[r]->entry, name );
+ VG_(printf)("\n");
+ VG_(translate)(0, tops[r]->entry, True, VG_(clo_profile_flags));
+ VG_(printf)("=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
end BB rank %d "
+ "=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D=
\n\n", r);
+ }
+
+ VG_(printf)("\n");
+ VG_(printf)("--------------------------------------------------------=
----\n");
+ VG_(printf)("--- END BB Profile =
---\n");
+ VG_(printf)("--------------------------------------------------------=
----\n");
+ VG_(printf)("\n");
+}
+
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
Added: trunk/coregrind/pub_core_transtab.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_transtab.h 2005-05-13 23:32:43 UTC (rev 3702=
)
+++ trunk/coregrind/pub_core_transtab.h 2005-05-13 23:40:55 UTC (rev 3703=
)
@@ -0,0 +1,71 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The translation table and cache. ---*/
+/*--- pub_core_transtab.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2005 Julian Seward
+ js...@ac...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_TRANSTAB_H
+#define __PUB_CORE_TRANSTAB_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module is responsible for caching translations, and
+// enabling fast look-ups of them.
+//--------------------------------------------------------------------
+
+/* The fast-cache for tt-lookup, and for finding counters. */
+extern ULong* VG_(tt_fast) [VG_TT_FAST_SIZE];
+extern UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
+
+extern void VG_(init_tt_tc) ( void );
+
+extern
+void VG_(add_to_transtab)( VexGuestExtents* vge,
+ Addr64 entry,
+ AddrH code,
+ UInt code_len );
+
+extern Bool VG_(search_transtab) ( /*OUT*/AddrH* result,
+ Addr64 guest_addr,=20
+ Bool upd_cache );
+
+extern void VG_(discard_translations) ( Addr64 start, UInt range );
+
+extern void VG_(sanity_check_tt_tc) ( Char* caller );
+
+extern void VG_(print_tt_tc_stats) ( void );
+
+extern UInt VG_(get_bbs_translated) ( void );
+
+extern void VG_(show_BB_profile) ( void );
+
+
+#endif // __PUB_CORE_TRANSTAB_H
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
Modified: trunk/coregrind/vg_main.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_main.c 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/vg_main.c 2005-05-13 23:40:55 UTC (rev 3703)
@@ -38,6 +38,7 @@
#include "pub_core_execontext.h"
#include "pub_core_syscalls.h"
#include "pub_core_tooliface.h"
+#include "pub_core_transtab.h"
=20
#include <dirent.h>
#include <dlfcn.h>
Modified: trunk/coregrind/vg_redir.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_redir.c 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/vg_redir.c 2005-05-13 23:40:55 UTC (rev 3703)
@@ -34,6 +34,7 @@
=20
#include "pub_core_aspacemgr.h"
#include "pub_core_skiplist.h"
+#include "pub_core_transtab.h"
=20
/*------------------------------------------------------------*/
/*--- General purpose redirection. ---*/
Modified: trunk/coregrind/vg_scheduler.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_scheduler.c 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/vg_scheduler.c 2005-05-13 23:40:55 UTC (rev 3703)
@@ -67,6 +67,7 @@
#include "pub_core_syscalls.h"
#include "pub_core_tooliface.h"
#include "pub_core_translate.h"
+#include "pub_core_transtab.h"
#include "vki_unistd.h"
=20
/* ---------------------------------------------------------------------
Deleted: trunk/coregrind/vg_transtab.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_transtab.c 2005-05-13 23:32:43 UTC (rev 3702)
+++ trunk/coregrind/vg_transtab.c 2005-05-13 23:40:55 UTC (rev 3703)
@@ -1,808 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Management of the translation table and cache. ---*/
-/*--- vg_transtab.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2000-2005 Julian Seward=20
- js...@ac...
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307, USA.
-
- The GNU General Public License is contained in the file COPYING.
-*/
-
-#include "core.h"
-#include "pub_core_tooliface.h"
-#include "pub_core_translate.h"
-
-/* #define DEBUG_TRANSTAB */
-
-
-/*-------------------------------------------------------------*/
-/*--- Management of the FIFO-based translation table+cache. ---*/
-/*-------------------------------------------------------------*/
-
-/*------------------ CONSTANTS ------------------*/
-
-/* Number of sectors the TC is divided into. If you need a larger
- overall translation cache, increase this value. */
-#define N_SECTORS 8
-
-/* Number of TC entries in each sector. This needs to be a prime
- number to work properly, and it is strongly recommended not to
- change this. */
-#define N_TTES_PER_SECTOR /*30011*/ 40009
-
-/* 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 60
-
-/* The sector is deemed full when this many entries are in it. */
-#define N_TTES_PER_SECTOR_USABLE \
- ((N_TTES_PER_SECTOR * SECTOR_TT_LIMIT_PERCENT) / 100)
-
-
-/*------------------ TYPES ------------------*/
-
-/* A translation-cache entry is two parts:
- - The guest address of the first (entry) bb in the translation,
- as a 64-bit word.
- - One or more 64-bit words containing the code.
- It is supposed to be 64-bit aligned.
-*/
-/*
-typedef
- struct {
- Addr64 orig_addr;
- ULong code[0];
- }
- TCEntry;
-*/
-
-/* A translation-table entry. This indicates precisely which areas of
- guest code are included in the translation, and contains all other
- auxiliary info too. */
-typedef
- struct {
- /* Profiling only: the count and weight (arbitrary meaning) for
- this translation. Weight is a property of the translation
- itself and computed once when the translation is created.
- Count is an entry count for the translation and is
- incremented by 1 every time the translation is used, if we
- are profiling. */
- UInt count;
- UShort weight;
-
- /* Status of the slot. Note, we need to be able to do lazy
- deletion, hence the Deleted state. */
- enum { InUse, Deleted, Empty } status;
-
- /* Pointer to the corresponding TCEntry (must be in the same
- sector!) */
- ULong* tce;
-
- /* This is the original guest address that purportedly is the
- entry point of the translation. You might think that .entry
- should be the same as .vge->base[0], and most of the time it
- is. However, when doing redirections, that is not the case.
- .vge must always correctly describe the guest code sections
- from which this translation was made. However, .entry may or
- may not be a lie, depending on whether or not we're doing
- redirection. */
- Addr64 entry;
-
- /* This structure describes precisely what ranges of guest code
- the translation covers, so we can decide whether or not to
- delete it when translations of a given address range are
- invalidated. */
- VexGuestExtents vge;
- }
- TTEntry;
-
-
-/* Finally, a sector itself. Each sector contains an array of
- TCEntries, which hold code, and an array of TTEntries, containing
- all required administrative info. Profiling is supported using the
- TTEntry .count and .weight fields, if required. Each sector is
- independent in that no cross-sector references are allowed.
-
- If the sector is not in use, all three pointers are NULL and
- tt_n_inuse is zero. =20
-*/
-typedef
- struct {
- /* The TCEntry area. Size of this depends on the average
- translation size. We try and size it so it becomes full
- precisely when this sector's translation table (tt) reaches
- its load limit (SECTOR_TT_LIMIT_PERCENT). */
- ULong* tc;
-
- /* The TTEntry array. This is a fixed size, always containing
- exactly N_TTES_PER_SECTOR entries. */
- TTEntry* tt;
-
- /* This points to the current allocation point in tc. */
- ULong* tc_next;
-
- /* The count of tt entries with state InUse. */
- Int tt_n_inuse;
- }
- Sector;
-
-
-/*------------------ DECLS ------------------*/
-
-/* The root data structure is an array of sectors. The index of the
- youngest sector is recorded, and new translations are put into that
- sector. When it fills up, we move along to the next sector and
- start to fill that up, wrapping around at the end of the array.
- That way, once all N_TC_SECTORS have been bought into use for the
- first time, and are full, we then re-use the oldest sector,
- endlessly.=20
-
- When running, youngest sector should be between >=3D 0 and <
- N_TC_SECTORS. The initial -1 value indicates the TT/TC system is
- not yet initialised.=20
-*/
-static Sector sectors[N_SECTORS];
-static Int youngest_sector =3D -1;
-
-/* The number of ULongs in each TCEntry area. This is computed once
- at startup and does not change. */
-static Int tc_sector_szQ;
-
-
-/* Fast helper for the TC. A direct-mapped cache which holds a
- pointer to a TC entry which may or may not be the correct one, but
- which we hope usually is. This array is referred to directly from
- <arch>/dispatch.S.
-
- Entries in tt_fast may point to any valid TC entry, regardless of
- which sector it's in. Consequently we must be very careful to
- invalidate this cache when TC entries are changed or disappear.
-
- A special TCEntry -- bogus_tc_entry -- must be pointed at to cause
- that cache entry to miss. This relies on the assumption that no
- guest code actually has an address of 0x1.
-*/
-/*global*/ ULong* VG_(tt_fast)[VG_TT_FAST_SIZE];
-
-static ULong bogus_tc_entry =3D (Addr64)1;
-
-
-/* For profiling, we have a parallel array of pointers to .count
- fields in TT entries. Again, these pointers must be invalidated
- when translations disappear. A NULL pointer suffices to indicate
- an unused slot.
-
- tt_fast and tt_fastN change together: if tt_fast[i] points to
- bogus_tc_entry then the corresponding tt_fastN[i] must be null. If
- tt_fast[i] points to some TC entry somewhere, then tt_fastN[i]
- *must* point to the .count field of the corresponding TT entry.
-
- tt_fast and tt_fastN are referred to from assembly code
- (dispatch.S).
-*/
-/*global*/ UInt* VG_(tt_fastN)[VG_TT_FAST_SIZE];
-
-
-/* Make sure we're not used before initialisation. */
-static Bool init_done =3D False;
-
-
-/*------------------ STATS DECLS ------------------*/
-
-/* Number of fast-cache updates and flushes done. */
-ULong n_fast_flushes =3D 0;
-ULong n_fast_updates =3D 0;
-
-/* Number of full lookups done. */
-ULong n_full_lookups =3D 0;
-ULong n_lookup_probes =3D 0;
-
-/* Number/osize/tsize of translations entered. */
-ULong n_in_count =3D 0;
-ULong n_in_osize =3D 0;
-ULong n_in_tsize =3D 0;
-
-/* Number/osize of translations discarded due to lack of space. */
-ULong n_dump_count =3D 0;
-ULong n_dump_osize =3D 0;
-
-/* Number/osize of translations discarded due to requests to do so. */
-ULong n_disc_count =3D 0;
-ULong n_disc_osize =3D 0;
-
-
-
-/*-------------------------------------------------------------*/
-/*--- Add/delete/find translations ---*/
-/*-------------------------------------------------------------*/
-
-static UInt vge_osize ( VexGuestExtents* vge )
-{
- UInt i, n =3D 0;
- for (i =3D 0; i < vge->n_used; i++)
- n +=3D (UInt)vge->len[i];
- return n;
-}
-
-static Bool isValidSector ( Int sector )
-{
- if (sector < 0 || sector >=3D N_SECTORS)
- return False;
- return True;
-}
-
-static inline UInt HASH_TT ( Addr64 key )
-{
- UInt kHi =3D (UInt)(key >> 32);
- UInt kLo =3D (UInt)key;
- return (kHi ^ kLo) % N_TTES_PER_SECTOR;
-}
-
-static void setFastCacheEntry ( Addr64 key, ULong* tce, UInt* count )
-{
- UInt cno =3D ((UInt)key) & VG_TT_FAST_MASK;
- VG_(tt_fast)[cno] =3D tce;
- VG_(tt_fastN)[cno] =3D count;
- n_fast_updates++;
-}
-
-static void invalidateFastCache ( void )
-{
- UInt j;
- for (j =3D 0; j < VG_TT_FAST_SIZE; j++) {
- VG_(tt_fast)[j] =3D &bogus_tc_entry;
- VG_(tt_fastN)[j] =3D NULL;
- }
- n_fast_flushes++;
-}
-
-static void initialiseSector ( Int sno )
-{
- Int i;
- vg_assert(isValidSector(sno));
-
- if (sectors[sno].tc =3D=3D NULL) {
- /* Sector has never been used before. Need to allocate tt and
- tc. */
- vg_assert(sectors[sno].tt =3D=3D NULL);
- vg_assert(sectors[sno].tc_next =3D=3D NULL);
- vg_assert(sectors[sno].tt_n_inuse =3D=3D 0);
- sectors[sno].tc=20
- =3D VG_(get_memory_from_mmap)
- ( 8 * tc_sector_szQ, "sectors[sno].tc" );
- sectors[sno].tt=20
- =3D VG_(get_memory_from_mmap)=20
- ( N_TTES_PER_SECTOR * sizeof(TTEntry), "sectors[sno].tt" )=
;
- if (VG_(clo_verbosity) > 2)
- VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d", sno);
- } else {
- /* Sector has been used before. */
- vg_assert(sectors[sno].tt !=3D NULL);
- vg_assert(sectors[sno].tc_next !=3D NULL);
- n_dump_count +=3D sectors[sno].tt_n_inuse;
- for (i =3D 0; i < N_TTES_PER_SECTOR; i++) {
- if (sectors[sno].tt[i].status =3D=3D InUse) {
- n_dump_osize +=3D vge_osize(§ors[sno].tt[i].vge);
- }
- }
- if (VG_(clo_verbosity) > 2)
- VG_(message)(Vg_DebugMsg, "TT/TC: recycle sector %d", sno);
- }
-
- sectors[sno].tc_next =3D sectors[sno].tc;
- sectors[sno].tt_n_inuse =3D 0;
- for (i =3D 0; i < N_TTES_PER_SECTOR; i++)
- sectors[sno].tt[i].status =3D Empty;
-
- invalidateFastCache();
-}
-
-
-/* Add a translation of vge to TT/TC. The translation is temporarily
- in code[0 .. code_len-1].
-
- pre: youngest_sector points to a valid (although possibly full)
- sector.
-*/
-void VG_(add_to_trans_tab)( VexGuestExtents* vge,
- Addr64 entry,
- AddrH code,
- UInt code_len )
-{
- Int tcAvailQ, reqdQ, y, i;
- ULong *tce, *tce2;
- UChar* srcP;
- UChar* dstP;
-
- vg_assert(init_done);
- vg_assert(vge->n_used >=3D 1 && vge->n_used <=3D 3);
- vg_assert(code_len > 0 && code_len < 20000);
-
- if (0)
- VG_(printf)("add_to_trans_tab(entry =3D 0x%llx, len =3D %d)\n",
- entry, code_len);
-
- n_in_count++;
- n_in_tsize +=3D code_len;
- n_in_osize +=3D vge_osize(vge);
-
- y =3D youngest_sector;
- vg_assert(isValidSector(y));
-
- if (sectors[y].tc =3D=3D NULL)
- initialiseSector(y);
-
- /* Try putting the translation in this sector. */
- reqdQ =3D 1 + ((code_len + 7) >> 3);
-
- /* Will it fit in tc? */
- tcAvailQ =3D ((ULong*)(§ors[y].tc[tc_sector_szQ]))
- - ((ULong*)(sectors[y].tc_next));
- vg_assert(tcAvailQ >=3D 0);
- vg_assert(tcAvailQ <=3D tc_sector_szQ);
-
- if (tcAvailQ < reqdQ=20
- || sectors[y].tt_n_inuse >=3D N_TTES_PER_SECTOR_USABLE) {
- /* No. So move on to the next sector. Either it's never been
- used before, in which case it will get its tt/tc allocated
- now, or it has been used before, in which case it is set to be
- empty, hence throwing out the oldest sector. */
- youngest_sector++;
- if (youngest_sector >=3D N_SECTORS)
- youngest_sector =3D 0;
- y =3D youngest_sector;
- initialiseSector(y);
- }
-
- /* Be sure ... */
- tcAvailQ =3D ((ULong*)(§ors[y].tc[tc_sector_szQ]))
- - ((ULong*)(sectors[y].tc_next));
- vg_assert(tcAvailQ >=3D 0);
- vg_assert(tcAvailQ <=3D tc_sector_szQ);
- vg_assert(tcAvailQ >=3D reqdQ);
- vg_assert(sectors[y].tt_n_inuse < N_TTES_PER_SECTOR_USABLE);
- vg_assert(sectors[y].tt_n_inuse >=3D 0);
-=20
- /* Copy into tc. */
- tce =3D sectors[y].tc_next;
- vg_assert(tce >=3D §ors[y].tc[0]);
- vg_assert(tce <=3D §ors[y].tc[tc_sector_szQ]);
-
- tce[0] =3D entry;
- dstP =3D (UChar*)(&tce[1]);
- srcP =3D (UChar*)code;
- for (i =3D 0; i < code_len; i++)
- dstP[i] =3D srcP[i];
- sectors[y].tc_next +=3D reqdQ;
- sectors[y].tt_n_inuse++;
-
- /* more paranoia */
- tce2 =3D sectors[y].tc_next;
- vg_assert(tce2 >=3D §ors[y].tc[0]);
- vg_assert(tce2 <=3D §ors[y].tc[tc_sector_szQ]);
-
- /* Find an empty tt slot, and use it. There must be such a slot
- since tt is never allowed to get completely full. */
- i =3D HASH_TT(entry);
- vg_assert(i >=3D 0 && i < N_TTES_PER_SECTOR);
- while (True) {
- if (sectors[y].tt[i].status =3D=3D Empty
- || sectors[y].tt[i].status =3D=3D Deleted)
- break;
- i++;
- if (i >=3D N_TTES_PER_SECTOR)
- i =3D 0;
- }
-
- sectors[y].tt[i].status =3D InUse;
- sectors[y].tt[i].tce =3D tce;
- sectors[y].tt[i].count =3D 0;
- sectors[y].tt[i].weight =3D 1;
- sectors[y].tt[i].vge =3D *vge;
- sectors[y].tt[i].entry =3D entry;
-
- setFastCacheEntry( entry, tce, §ors[y].tt[i].count );
-}
-
-
-/* Search for the translation of the given guest address. If
- requested, a successful search can also cause the fast-caches to be
- updated. =20
-*/
-Bool VG_(search_transtab) ( /*OUT*/AddrH* result,
- Addr64 guest_addr,=20
- Bool upd_cache )
-{
- Int i, j, k, kstart, sno;
-
- vg_assert(init_done);
- /* Find the initial probe point just once. It will be the same in
- all sectors and avoids multiple expensive % operations. */
- n_full_lookups++;
- k =3D -1;
- kstart =3D HASH_TT(guest_addr);
- vg_assert(kstart >=3D 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 =3D youngest_sector;
- for (i =3D 0; i < N_SECTORS; i++) {
-
- if (sectors[sno].tc =3D=3D NULL)
- goto notfound; /* sector not in use. */
-
- k =3D kstart;
- for (j =3D 0; j < N_TTES_PER_SECTOR; j++) {
- n_lookup_probes++;
- if (sectors[sno].tt[k].status =3D=3D InUse
- && sectors[sno].tt[k].entry =3D=3D guest_addr) {
- /* found it */
- if (upd_cache)
- setFastCacheEntry(=20
- guest_addr, sectors[sno].tt[k].tce,=20
- §ors[sno].tt[k].count );
- if (result)
- *result =3D sizeof(Addr64) + (AddrH)sectors[sno].tt[k].tc=
e;
- return True;
- }
- if (sectors[sno].tt[k].status =3D=3D Empty)
- break; /* not found in this sector */
- k++;
- if (k =3D=3D N_TTES_PER_SECTOR)
- k =3D 0;
- }
-
- /* 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 =3D sno=3D=3D0 ? (N_SECTORS-1) : (sno-1);
- }
-
- /* Not found in any sector. */
- return False;
-}
-
-
-/* Delete all translations which intersect with any part of the
- specified guest address range. Note, this is SLOW.=20
-*/
-
-static inline
-Bool overlap1 ( Addr64 s1, UInt r1, Addr64 s2, UInt r2 )
-{
- Addr64 e1 =3D s1 + (ULong)r1 - 1ULL;
- Addr64 e2 =3D s2 + (ULong)r1 - 1ULL;
- if (e1 < s2 || e2 < s1)=20
- return False;
- return True;
-}
-
-static inline
-Bool overlaps ( Addr64 start, UInt range, VexGuestExtents* vge )
-{
- if (overlap1(start, range, vge->base[0], (UInt)vge->len[0]))
- return True;
- if (vge->n_used < 2)
- return False;
- if (overlap1(start, range, vge->base[1], (UInt)vge->len[1]))
- return True;
- if (vge->n_used < 3)
- return False;
- if (overlap1(start, range, vge->base[2], (UInt)vge->len[2]))
- return True;
- return False;
-}
-
-
-void VG_(discard_translations) ( Addr64 guest_start, UInt range )
-{
- Int sno, i;
- Bool anyDeleted =3D False;
-
- vg_assert(init_done);
-
- for (sno =3D 0; sno < N_SECTORS; sno++) {
- if (sectors[sno].tc =3D=3D NULL)
- continue;
- for (i =3D 0; i < N_TTES_PER_SECTOR; i++) {
- if (sectors[sno].tt[i].status =3D=3D InUse
- && overlaps( guest_start, range, §ors[sno].tt[i].vge ))=
{
- sectors[sno].tt[i].status =3D Deleted;
- sectors[sno].tt_n_inuse--;
- anyDeleted =3D True;
- n_disc_count++;
- n_disc_osize +=3D vge_osize(§ors[sno].tt[i].vge);
- }
- } =20
- }
-
- if (anyDeleted)
- invalidateFastCache();
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Sanity checking ---*/
-/*------------------------------------------------------------*/
-
-void VG_(sanity_check_tt_tc) ( Char* who )
-{
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Initialisation. ---*/
-/*------------------------------------------------------------*/
-
-void VG_(init_tt_tc) ( void )
-{
- Int i, avg_codeszQ;
-
- vg_assert(!init_done);
- init_done =3D True;
-
- /* Otherwise lots of things go wrong... */
- vg_assert(sizeof(ULong) =3D=3D 8);
- vg_assert(sizeof(Addr64) =3D=3D 8);
-
- if (VG_(clo_verbosity) > 2)
- VG_(message)(Vg_DebugMsg,=20
- "TT/TC: VG_(init_tt_tc) "
- "(startup of code management)");
-
- /* Figure out how big each tc area should be. */
- avg_codeszQ =3D (VG_(details).avg_translation_sizeB + 7) / 8;
- tc_sector_szQ =3D N_TTES_PER_SECTOR_USABLE * (1 + avg_codeszQ);
-
- /* Ensure the calculated value is not way crazy. */
- vg_assert(tc_sector_szQ >=3D 2 * N_TTES_PER_SECTOR_USABLE);
- vg_assert(tc_sector_szQ <=3D 50 * N_TTES_PER_SECTOR_USABLE);
-
- /* Initialise the sectors */
- youngest_sector =3D 0;
- for (i =3D 0; i < N_SECTORS; i++) {
- sectors[i].tc =3D NULL;
- sectors[i].tt =3D NULL;
- sectors[i].tc_next =3D NULL;
- sectors[i].tt_n_inuse =3D 0;
- }
-
- /* and the fast caches. */
- invalidateFastCache();
-
- if (VG_(clo_verbosity) > 2) {
- VG_(message)(Vg_DebugMsg,
- "TT/TC: cache: %d sectors of %d bytes each =3D %d total",=20
- N_SECTORS, 8 * tc_sector_szQ,
- N_SECTORS * 8 * tc_sector_szQ );
- VG_(message)(Vg_DebugMsg,
- "TT/TC: table: %d total entries, max occupancy %d (%d%%)",
- N_SECTORS * N_TTES_PER_SECTOR,
- N_SECTORS * N_TTES_PER_SECTOR_USABLE,=20
- SECTOR_TT_LIMIT_PERCENT );
- }
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Printing out statistics. ---*/
-/*------------------------------------------------------------*/
-
-static ULong safe_idiv( ULong a, ULong b )
-{
- return (b =3D=3D 0 ? 0 : a / b);
-}
-
-UInt VG_(get_bbs_translated) ( void )
-{
- return n_in_count;
-}
-
-void VG_(print_tt_tc_stats) ( void )
-{
- VG_(message)(Vg_DebugMsg,
- " tt/tc: %llu tt lookups requiring %llu probes",=20
- n_full_lookups, n_lookup_probes );
- VG_(message)(Vg_DebugMsg,
- " tt/tc: %llu fast-cache updates, %llu flushes",=20
- n_fast_updates, n_fast_flushes );
-
- VG_(message)(Vg_DebugMsg,
- "translate: new %lld (%lld -> %lld; ratio %lld:10=
)",
- n_in_count, n_in_osize, n_in_tsize,
- safe_idiv(10*n_in_tsize, n_in_osize));
- VG_(message)(Vg_DebugMsg,
- "translate: dumped %lld (%lld -> ?" "?)",
- n_dump_count, n_dump_osize );
- VG_(message)(Vg_DebugMsg,
- "translate: discarded %lld (%lld -> ?" "?)",
- n_disc_count, n_disc_osize );
-}
-
-/*------------------------------------------------------------*/
-/*--- Printing out of profiling results. ---*/
-/*------------------------------------------------------------*/
-
-/* Only the top N_MAX bbs will be displayed. */
-#define N_MAX 200
-
-static TTEntry* tops[N_MAX];
-
-static ULong score ( TTEntry* tte )
-{
- return ((ULong)tte->weight) * ((ULong)tte->count);
-}
-
-static Bool heavier ( TTEntry* t1, TTEntry* t2 )
-{
- return score(t1) > score(t2);
-}
-
-/* Print n/m in form xx.yy% */
-static
-void percentify ( ULong n, ULong m, Int field_width, Char* buf)
-{
- Int i, len, space;
- ULong lo, hi;
- if (m =3D=3D 0) m =3D 1; /* stay sane */
- hi =3D (n * 100) / m;
- lo =3D (((n * 100) - hi * m) * 100) / m;
- vg_assert(lo < 100);
- if (lo < 10)
- VG_(sprintf)(buf, "%lld.0%lld%%", hi, lo);
- else
- VG_(sprintf)(buf, "%lld.%lld%%", hi, lo);
-
- len =3D VG_(strlen)(buf);
- space =3D field_width - len;
- if (space < 0) space =3D 0; /* Allow for v. small field_width */
- i =3D len;
-
- /* Right justify in field */
- for ( ; i >=3D 0; i--) buf[i + space] =3D buf[i];
- for (i =3D 0; i < space; i++) buf[i] =3D ' ';
-}
-
-
-void VG_(show_BB_profile) ( void )
-{
- Char name[64];
- Int sno, i, r, s;
- ULong score_total, score_cumul, score_here;
- Char buf_cumul[10];
- Char buf_here[10];
-
- /* First, compute the total weighted count, and find the top N
- ttes. tops contains pointers to the most-used N_MAX blocks, in
- descending order (viz, tops[0] is the highest scorer). */
- for (i =3D 0; i < N_MAX; i++)
- tops[i] =3D NULL;
-
- score_total =3D 0;
-
- for (sno =...
[truncated message content] |