Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion callgrind/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,25 @@ static int debug_cache_line[DEBUG_CACHE_SIZE];
static Bool debug_cache_info[DEBUG_CACHE_SIZE];
static const HChar* debug_cache_inlfn[DEBUG_CACHE_SIZE];

/* One-entry memo for the last file_node looked up by get_debug_pos().
*
* The cache above is keyed by instruction address, so it never hits while a
* dump walks the (all distinct) addresses of a basic block. Every one of
* those misses ends in CLG_(get_file_node), which rebuilds the absolute
* source path on the stack and hashes it character by character - even
* though consecutive addresses nearly always belong to the same source file.
*
* The (dir, file) strings come from the debug info and are interned per
* DebugInfo, so the same source file always yields the same pointers and
* comparing pointers is enough. The memo is only used within one dump: no
* guest code runs while dumping, so no debug info can be loaded or discarded
* in between, and init_debug_cache() resets it at the start of every dump.
*/
static obj_node* debug_last_obj;
static const HChar* debug_last_dir;
static const HChar* debug_last_file;
static file_node* debug_last_node;

static __inline__
void init_debug_cache(void)
{
Expand All @@ -372,6 +391,10 @@ void init_debug_cache(void)
debug_cache_info[i] = 0;
debug_cache_inlfn[i] = 0;
}
debug_last_obj = 0;
debug_last_dir = 0;
debug_last_file = 0;
debug_last_node = 0;
}

static /* __inline__ */
Expand All @@ -397,7 +420,21 @@ Bool get_debug_pos(BBCC* bbcc, Addr addr, AddrPos* p)
file = "???";
p->line = 0;
}
p->file = CLG_(get_file_node)(bbcc->bb->obj, dir, file);
/* Same source file as the previous lookup? Then reuse its node
* instead of rebuilding and rehashing the absolute path. */
if ((bbcc->bb->obj == debug_last_obj) &&
(dir == debug_last_dir) &&
(file == debug_last_file)) {
p->file = debug_last_node;
}
else {
p->file = CLG_(get_file_node)(bbcc->bb->obj, dir, file);

debug_last_obj = bbcc->bb->obj;
debug_last_dir = dir;
debug_last_file = file;
debug_last_node = p->file;
}

debug_cache_info[cachepos] = found_file_line;
debug_cache_addr[cachepos] = addr;
Expand Down
59 changes: 59 additions & 0 deletions coregrind/m_debuginfo/debuginfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,13 @@ inline DiEpoch VG_(current_DiEpoch) ( void ) {
DiEpoch dep; dep.n = current_epoch; return dep;
}

/* Forward */
static void invalidate_loctab_cache ( void );

static void advance_current_DiEpoch ( const HChar* msg ) {
current_epoch++;
/* Anything cached about the previous epoch's DebugInfos is now stale. */
invalidate_loctab_cache();
if (DEBUG_EPOCHS)
VG_(printf)("Advancing current epoch to %u due to %s\n",
current_epoch, msg);
Expand Down Expand Up @@ -2138,6 +2143,35 @@ static void search_all_symtabs ( DiEpoch ep, Addr ptr,
}


/* One-entry cache for search_all_loctabs().
*
* Callers query addresses with strong locality: dumping a profile asks for
* every instruction of a basic block in turn, and one source line usually
* covers several instructions, so consecutive queries land in the same
* loctab entry or in the one right after it, of the same DebugInfo.
* Remembering the last hit turns those queries into a couple of compares
* instead of a walk over all DebugInfos plus a binary search of the loctab.
*
* The entry is only reused for the epoch it was found in, and it is dropped
* whenever the epoch advances (see advance_current_DiEpoch), i.e. whenever
* debug info is loaded or discarded, so a stale DebugInfo is never read. */
static DiEpoch loctab_cache_ep; /* zeroed => invalid epoch */
static DebugInfo* loctab_cache_di = NULL;
static Word loctab_cache_locno = 0;

static void invalidate_loctab_cache ( void )
{
loctab_cache_di = NULL;
}

/* Does loctab entry `lno` of `di` cover `ptr`? */
static inline
Bool loctab_entry_covers ( const DebugInfo* di, Word lno, Addr ptr )
{
Addr lo = di->loctab[lno].addr;
return ptr >= lo && ptr - lo < (Addr)di->loctab[lno].size;
}

/* Search all loctabs that we know about to locate ptr at epoch ep. If
*found, set pdi to the relevant DebugInfo, and *locno to the loctab entry
*number within that. If not found, *pdi is set to NULL. */
Expand All @@ -2146,6 +2180,25 @@ static void search_all_loctabs ( DiEpoch ep, Addr ptr,
{
Word lno;
DebugInfo* di;

/* Same entry as last time, or the one following it? */
if (LIKELY(loctab_cache_di != NULL && eq_DiEpoch(ep, loctab_cache_ep))) {
di = loctab_cache_di;
lno = loctab_cache_locno;
if (LIKELY(loctab_entry_covers(di, lno, ptr))) {
*locno = lno;
*pdi = di;
return;
}
lno++;
if (lno < di->loctab_used && loctab_entry_covers(di, lno, ptr)) {
loctab_cache_locno = lno;
*locno = lno;
*pdi = di;
return;
}
}

for (di = debugInfo_list; di != NULL; di = di->next) {
if (!is_DI_valid_for_epoch(di, ep))
continue;
Expand All @@ -2155,6 +2208,9 @@ static void search_all_loctabs ( DiEpoch ep, Addr ptr,
&& ptr < di->text_avma + di->text_size) {
lno = ML_(search_one_loctab) ( di, ptr );
if (lno == -1) goto not_found;
loctab_cache_ep = ep;
loctab_cache_di = di;
loctab_cache_locno = lno;
*locno = lno;
*pdi = di;
return;
Expand Down Expand Up @@ -2384,6 +2440,9 @@ Bool VG_(get_inline_fnname) ( DiEpoch ep, Addr a, const HChar** inl_fnname )
DebugInfo* si;
Word locno;

if (!VG_(clo_read_inline_info))
return False; // No inltab was built, so no way to find inlined calls.

/* Find the DebugInfo for this address */
search_all_loctabs(ep, a, &si, &locno);
if (si == NULL || si->inltab == NULL)
Expand Down
Loading