Skip to content

Commit 6f97311

Browse files
committed
feat: optimize inline table lookups using hashtable and binary search
1 parent 1f4889c commit 6f97311

File tree

6 files changed

+156
-7
lines changed

6 files changed

+156
-7
lines changed

coregrind/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ COREGRIND_SOURCES_COMMON = \
363363
m_debuginfo/d3basics.c \
364364
m_debuginfo/debuginfo.c \
365365
m_debuginfo/image.c \
366+
m_debuginfo/inltab_lookup.c \
366367
m_debuginfo/minilzo-inl.c \
367368
m_debuginfo/readdwarf.c \
368369
m_debuginfo/readdwarf3.c \

coregrind/m_debuginfo/debuginfo.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include "priv_d3basics.h" /* ML_(pp_GX) */
5757
#include "priv_tytypes.h"
5858
#include "priv_storage.h"
59+
#include "priv_inltab_lookup.h"
5960
#include "priv_readdwarf.h"
6061
#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd)
6162
# include "priv_readelf.h"
@@ -345,6 +346,7 @@ static void free_DebugInfo ( DebugInfo* di )
345346
if (di->loctab) ML_(dinfo_free)(di->loctab);
346347
if (di->loctab_fndn_ix) ML_(dinfo_free)(di->loctab_fndn_ix);
347348
if (di->inltab) ML_(dinfo_free)(di->inltab);
349+
if (di->inltab_lookup) VG_(inltab_lookup_cleanup)(di->inltab_lookup);
348350
if (di->cfsi_base) ML_(dinfo_free)(di->cfsi_base);
349351
if (di->cfsi_m_ix) ML_(dinfo_free)(di->cfsi_m_ix);
350352
if (di->cfsi_rd) ML_(dinfo_free)(di->cfsi_rd);
@@ -2388,13 +2390,12 @@ Bool VG_(get_inline_fnname) ( DiEpoch ep, Addr a, const HChar** inl_fnname )
23882390
return False;
23892391

23902392
/* Search the inline table for an entry containing this address */
2391-
/* We search from the end backwards to find the innermost inline function first */
2392-
for (Word i = si->inltab_used - 1; i >= 0; i--) {
2393-
if (si->inltab[i].addr_lo <= a && a < si->inltab[i].addr_hi) {
2394-
/* Found it! Return the inline function name */
2395-
*inl_fnname = si->inltab[i].inlinedfn;
2396-
return True;
2397-
}
2393+
/* Lookup with hash table cache and binary search fallback */
2394+
Word inl_idx;
2395+
if (VG_(inltab_lookup_get)(si->inltab_lookup, a, &inl_idx, si)) {
2396+
/* Found it! Return the inline function name */
2397+
*inl_fnname = si->inltab[inl_idx].inlinedfn;
2398+
return True;
23982399
}
23992400

24002401
return False;
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/* VgHashTable-based implementation for inline lookup table.
2+
Maps addresses to inline function info indices. */
3+
4+
#include "pub_core_basics.h"
5+
#include "pub_core_libcbase.h"
6+
#include "pub_core_libcassert.h"
7+
#include "pub_core_mallocfree.h"
8+
#include "pub_core_hashtable.h"
9+
#include "priv_storage.h"
10+
11+
/* Node structure for VgHashTable
12+
Extends VgHashNode with our key (Addr) and value (Word) */
13+
typedef struct {
14+
VgHashNode node; /* Must be first for VgHashTable API */
15+
Word value; /* The inline table index */
16+
} InlLookupNode;
17+
18+
/* Binary search for an inline function entry containing address 'a'.
19+
Uses the sorted inltab array to efficiently find candidates.
20+
Returns the index of the matching entry, or -1 if not found.
21+
22+
The inltab is sorted by addr_lo, so we:
23+
1. Binary search to find entries where addr_lo <= a
24+
2. Scan backwards to find an entry that contains address a
25+
(this finds the innermost inline function if multiple are nested)
26+
*/
27+
static Word binary_search_inltab(const DebugInfo* di, Addr a) {
28+
if (di == NULL || di->inltab == NULL || di->inltab_used == 0)
29+
return -1;
30+
31+
Word lo = 0, hi = di->inltab_used;
32+
33+
/* Binary search: find the first entry where addr_lo > a */
34+
while (lo < hi) {
35+
Word mid = lo + (hi - lo) / 2;
36+
if (a < di->inltab[mid].addr_lo) {
37+
hi = mid;
38+
} else {
39+
lo = mid + 1;
40+
}
41+
}
42+
43+
/* lo now points to the first entry where addr_lo > a.
44+
Search backwards from lo-1 to find an entry that contains address a */
45+
for (Word i = lo - 1; i >= 0; i--) {
46+
if (di->inltab[i].addr_lo <= a && a < di->inltab[i].addr_hi) {
47+
/* Found it! Return the index */
48+
return i;
49+
}
50+
/* Since we're scanning backwards through sorted addr_lo entries,
51+
if we encounter an addr_hi <= a, we can stop as we've passed
52+
the potential range */
53+
if (di->inltab[i].addr_hi <= a) {
54+
break;
55+
}
56+
}
57+
58+
return -1;
59+
}
60+
61+
/* Public API for inline lookup table */
62+
63+
VgHashTable *VG_(inltab_lookup_new)(void) {
64+
return VG_(HT_construct)("inltab_lookup");
65+
}
66+
67+
void VG_(inltab_lookup_insert)(VgHashTable *ht, Addr addr, Word inl_idx) {
68+
if (ht == NULL)
69+
ht = VG_(inltab_lookup_new)();
70+
71+
/* Check if entry already exists */
72+
InlLookupNode *existing = VG_(HT_lookup)(ht, (UWord)addr);
73+
if (existing) {
74+
/* Update existing value */
75+
existing->value = inl_idx;
76+
return;
77+
}
78+
79+
/* Allocate new node */
80+
InlLookupNode *node = VG_(malloc)("di.inltab_vghash.node", sizeof(InlLookupNode));
81+
if (!node)
82+
return;
83+
node->node.key = (UWord)addr;
84+
node->value = inl_idx;
85+
86+
VG_(HT_add_node)(ht, node);
87+
}
88+
89+
/* Enhanced lookup that combines hash table lookup with binary search fallback.
90+
First tries the hash table for exact addr_lo matches.
91+
If not found, uses binary search on the sorted inltab array.
92+
If found via binary search, caches the result in the hash table.
93+
*/
94+
Bool VG_(inltab_lookup_get)(VgHashTable *ht, Addr addr, Word *inl_idx,
95+
const DebugInfo* di) {
96+
if (ht == NULL)
97+
return False;
98+
99+
/* Try hash table lookup first */
100+
InlLookupNode *node = VG_(HT_lookup)(ht, (UWord)addr);
101+
if (node) {
102+
*inl_idx = node->value;
103+
return True;
104+
}
105+
106+
/* Hash table miss, try binary search on the inltab array */
107+
Word idx = binary_search_inltab(di, addr);
108+
if (idx >= 0) {
109+
/* Found via binary search, cache it for future lookups */
110+
*inl_idx = idx;
111+
VG_(inltab_lookup_insert)(ht, addr, idx);
112+
return True;
113+
}
114+
115+
return False;
116+
}
117+
118+
void VG_(inltab_lookup_cleanup)(VgHashTable *ht) {
119+
if (ht == NULL)
120+
return;
121+
122+
/* Free all nodes */
123+
VG_(HT_destruct)(ht, VG_(free));
124+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef __PRIV_INLTAB_LOOKUP_H
2+
#define __PRIV_INLTAB_LOOKUP_H
3+
4+
#include "pub_core_basics.h"
5+
#include "pub_tool_hashtable.h"
6+
7+
extern VgHashTable *VG_(inltab_lookup_new)(void);
8+
extern void VG_(inltab_lookup_insert)(VgHashTable *ht, Addr addr, Word inl_idx);
9+
extern Bool VG_(inltab_lookup_get)(VgHashTable *ht, Addr addr, Word *inl_idx,
10+
const DebugInfo *di);
11+
extern void VG_(inltab_lookup_cleanup)(VgHashTable *ht);
12+
13+
#endif

coregrind/m_debuginfo/priv_storage.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "pub_core_basics.h" // Addr
4545
#include "pub_core_xarray.h" // XArray
4646
#include "pub_core_deduppoolalloc.h" // DedupPoolAlloc
47+
#include "pub_tool_hashtable.h" // VgHashTable
4748
#include "priv_d3basics.h" // GExpr et al.
4849
#include "priv_image.h" // DiCursor
4950

@@ -953,6 +954,10 @@ struct _DebugInfo {
953954
UWord inltab_size;
954955
SizeT maxinl_codesz;
955956

957+
/* Hash table for O(1) inline lookups by address.
958+
Maps arbitrary addresses to indices in inltab; populated on-demand during lookups for cache efficiency. */
959+
VgHashTable* inltab_lookup;
960+
956961
/* A set of expandable arrays to store CFI summary info records.
957962
The machine specific information (i.e. the DiCfSI_m struct)
958963
are stored in cfsi_m_pool, as these are highly duplicated.

coregrind/m_debuginfo/storage.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "priv_d3basics.h" /* ML_(pp_GX) */
5252
#include "priv_tytypes.h"
5353
#include "priv_storage.h" /* self */
54+
#include "priv_inltab_lookup.h"
5455

5556

5657
/*------------------------------------------------------------*/
@@ -2164,6 +2165,10 @@ static void canonicaliseInltab ( struct _DebugInfo* di )
21642165

21652166
/* Free up unused space at the end of the table. */
21662167
shrinkInlTab(di);
2168+
2169+
if (di->inltab_lookup == NULL) {
2170+
di->inltab_lookup = VG_(inltab_lookup_new)();
2171+
}
21672172
}
21682173

21692174

0 commit comments

Comments
 (0)