mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
This optimisation divides by 2.5 the time (user+sys) needed to read
the inlined info of a big executable. On a slow pentium, reading the inline info now takes 5.5 seconds. The optimisation consists in having per dw3 abbreviation a structure allowing to skip efficiently the non interesting DIEs (i.e. the DIEs the parse_inl_DIE is not interested in). Mostly, the idea is to avoid calling the image abstraction, and replace this by just advancing the cursor (i.e. addition rather than a bunch of function calls to read the data). git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14075
This commit is contained in:
parent
083986d244
commit
cdfd3be6b7
@ -217,6 +217,10 @@ static inline void set_position_of_Cursor ( Cursor* c, ULong pos ) {
|
|||||||
c->sli_next = c->sli.ioff + pos;
|
c->sli_next = c->sli.ioff + pos;
|
||||||
vg_assert(is_sane_Cursor(c));
|
vg_assert(is_sane_Cursor(c));
|
||||||
}
|
}
|
||||||
|
static inline void advance_position_of_Cursor ( Cursor* c, ULong delta ) {
|
||||||
|
c->sli_next += delta;
|
||||||
|
vg_assert(is_sane_Cursor(c));
|
||||||
|
}
|
||||||
|
|
||||||
static /*signed*/Long get_remaining_length_Cursor ( Cursor* c ) {
|
static /*signed*/Long get_remaining_length_Cursor ( Cursor* c ) {
|
||||||
vg_assert(is_sane_Cursor(c));
|
vg_assert(is_sane_Cursor(c));
|
||||||
@ -380,9 +384,24 @@ static ULong get_Initial_Length ( /*OUT*/Bool* is64,
|
|||||||
|
|
||||||
typedef
|
typedef
|
||||||
struct _name_form {
|
struct _name_form {
|
||||||
ULong at_name;
|
ULong at_name; // Dwarf Attribute name
|
||||||
ULong at_form;
|
ULong at_form; // Dward Attribute form
|
||||||
|
UInt skip_szB; // Nr of bytes skippable from here ...
|
||||||
|
UInt next_nf; // ... to reach this attr/form index in the g_abbv.nf
|
||||||
} name_form;
|
} name_form;
|
||||||
|
/* skip_szB and n_nf are used to optimise the skipping of uninteresting DIEs.
|
||||||
|
Each name_form maintains how many (fixed) nr of bytes can be skipped from
|
||||||
|
the beginning of this form till the next attr/form to look at.
|
||||||
|
The next form to look can be:
|
||||||
|
an 'interesting' attr/form to read while skipping a DIE
|
||||||
|
(currently, this is only DW_AT_sibling)
|
||||||
|
or
|
||||||
|
a variable length form which must be read to be skipped.
|
||||||
|
For a variable length form, the skip_szB will be equal to VARSZ_FORM.
|
||||||
|
|
||||||
|
Note: this technique could also be used to speed up the parsing
|
||||||
|
of DIEs : for each parser kind, we could have the nr of bytes
|
||||||
|
to skip to directly reach the interesting form(s) for the parser. */
|
||||||
|
|
||||||
typedef
|
typedef
|
||||||
struct _g_abbv {
|
struct _g_abbv {
|
||||||
@ -392,7 +411,9 @@ typedef
|
|||||||
ULong has_children;
|
ULong has_children;
|
||||||
name_form nf[0];
|
name_form nf[0];
|
||||||
/* Variable-length array of name/form pairs, terminated
|
/* Variable-length array of name/form pairs, terminated
|
||||||
by a 0/0 pair. */
|
by a 0/0 pair.
|
||||||
|
The skip_szB/next_nf allows to skip efficiently a DIE
|
||||||
|
described by this g_abbv; */
|
||||||
} g_abbv;
|
} g_abbv;
|
||||||
|
|
||||||
/* Holds information that is constant through the parsing of a
|
/* Holds information that is constant through the parsing of a
|
||||||
@ -865,6 +886,9 @@ static XArray* /* of AddrRange */
|
|||||||
return xa;
|
return xa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define VARSZ_FORM 0xffffffff
|
||||||
|
static UInt get_Form_szB (CUConst* cc, DW_FORM form );
|
||||||
|
|
||||||
/* Initialises the hash table of abbreviations.
|
/* Initialises the hash table of abbreviations.
|
||||||
We do a single scan of the abbv slice to parse and
|
We do a single scan of the abbv slice to parse and
|
||||||
build all abbreviations, for the following reasons:
|
build all abbreviations, for the following reasons:
|
||||||
@ -880,7 +904,8 @@ static void init_ht_abbvs (CUConst* cc,
|
|||||||
g_abbv *ta; // temporary abbreviation, reallocated if needed.
|
g_abbv *ta; // temporary abbreviation, reallocated if needed.
|
||||||
UInt ta_nf_maxE; // max nr of pairs in ta.nf[], doubled when reallocated.
|
UInt ta_nf_maxE; // max nr of pairs in ta.nf[], doubled when reallocated.
|
||||||
UInt ta_nf_n; // nr of pairs in ta->nf that are initialised.
|
UInt ta_nf_n; // nr of pairs in ta->nf that are initialised.
|
||||||
g_abbv *ht_ta; // abbv to insert in hash table.
|
g_abbv *ht_ta; // abbv to insert in hash table.
|
||||||
|
Int i;
|
||||||
|
|
||||||
#define SZ_G_ABBV(_nf_szE) (sizeof(g_abbv) + _nf_szE * sizeof(name_form))
|
#define SZ_G_ABBV(_nf_szE) (sizeof(g_abbv) + _nf_szE * sizeof(name_form))
|
||||||
|
|
||||||
@ -914,13 +939,42 @@ static void init_ht_abbvs (CUConst* cc,
|
|||||||
}
|
}
|
||||||
ta_nf_n++;
|
ta_nf_n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialises the skip_szB/next_nf elements : an element at position
|
||||||
|
// i must contain the sum of its own size + the sizes of all elements
|
||||||
|
// following i till either the next variable size element, the next
|
||||||
|
// sibling element or the end of the DIE.
|
||||||
|
ta->nf[ta_nf_n - 1].skip_szB = 0;
|
||||||
|
ta->nf[ta_nf_n - 1].next_nf = 0;
|
||||||
|
for (i = ta_nf_n - 2; i >= 0; i--) {
|
||||||
|
const UInt form_szB = get_Form_szB (cc, (DW_FORM)ta->nf[i].at_form);
|
||||||
|
|
||||||
|
if (ta->nf[i+1].at_name == DW_AT_sibling
|
||||||
|
|| ta->nf[i+1].skip_szB == VARSZ_FORM) {
|
||||||
|
ta->nf[i].skip_szB = form_szB;
|
||||||
|
ta->nf[i].next_nf = i+1;
|
||||||
|
} else if (form_szB == VARSZ_FORM) {
|
||||||
|
ta->nf[i].skip_szB = form_szB;
|
||||||
|
ta->nf[i].next_nf = i+1;
|
||||||
|
} else {
|
||||||
|
ta->nf[i].skip_szB = ta->nf[i+1].skip_szB + form_szB;
|
||||||
|
ta->nf[i].next_nf = ta->nf[i+1].next_nf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ht_ta = ML_(dinfo_zalloc) ("di.readdwarf3.ht_ta", SZ_G_ABBV(ta_nf_n));
|
ht_ta = ML_(dinfo_zalloc) ("di.readdwarf3.ht_ta", SZ_G_ABBV(ta_nf_n));
|
||||||
VG_(memcpy) (ht_ta, ta, SZ_G_ABBV(ta_nf_n));
|
VG_(memcpy) (ht_ta, ta, SZ_G_ABBV(ta_nf_n));
|
||||||
VG_(HT_add_node) ( cc->ht_abbvs, ht_ta );
|
VG_(HT_add_node) ( cc->ht_abbvs, ht_ta );
|
||||||
TRACE_D3(" Adding abbv_code %llu TAG %s [%s] nf %d\n",
|
if (TD3) {
|
||||||
(ULong) ht_ta->abbv_code, ML_(pp_DW_TAG)(ht_ta->atag),
|
TRACE_D3(" Adding abbv_code %llu TAG %s [%s] nf %d ",
|
||||||
ML_(pp_DW_children)(ht_ta->has_children),
|
(ULong) ht_ta->abbv_code, ML_(pp_DW_TAG)(ht_ta->atag),
|
||||||
ta_nf_n);
|
ML_(pp_DW_children)(ht_ta->has_children),
|
||||||
|
ta_nf_n);
|
||||||
|
TRACE_D3(" ");
|
||||||
|
for (i = 0; i < ta_nf_n; i++)
|
||||||
|
TRACE_D3("[%u,%u] ", ta->nf[i].skip_szB, ta->nf[i].next_nf);
|
||||||
|
TRACE_D3("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ML_(dinfo_free) (ta);
|
ML_(dinfo_free) (ta);
|
||||||
@ -1082,6 +1136,9 @@ void get_Form_contents ( /*OUT*/FormContents* cts,
|
|||||||
Bool td3, DW_FORM form )
|
Bool td3, DW_FORM form )
|
||||||
{
|
{
|
||||||
VG_(bzero_inline)(cts, sizeof(*cts));
|
VG_(bzero_inline)(cts, sizeof(*cts));
|
||||||
|
// !!! keep switch in sync with get_Form_szB. The nr of characters read below
|
||||||
|
// must be computed similarly in get_Form_szB.
|
||||||
|
// The consistency is verified in trace_DIE.
|
||||||
switch (form) {
|
switch (form) {
|
||||||
case DW_FORM_data1:
|
case DW_FORM_data1:
|
||||||
cts->u.val = (ULong)(UChar)get_UChar(c);
|
cts->u.val = (ULong)(UChar)get_UChar(c);
|
||||||
@ -1372,6 +1429,119 @@ void get_Form_contents ( /*OUT*/FormContents* cts,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline UInt sizeof_Dwarfish_UWord (Bool is_dw64)
|
||||||
|
{
|
||||||
|
if (is_dw64)
|
||||||
|
return sizeof(ULong);
|
||||||
|
else
|
||||||
|
return sizeof(UInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VARSZ_FORM 0xffffffff
|
||||||
|
/* If the form is a fixed length form, return the nr of bytes for this form.
|
||||||
|
If the form is a variable length form, return VARSZ_FORM. */
|
||||||
|
static
|
||||||
|
UInt get_Form_szB (CUConst* cc, DW_FORM form )
|
||||||
|
{
|
||||||
|
// !!! keep switch in sync with get_Form_contents : the nr of bytes
|
||||||
|
// read from a cursor by get_Form_contents must be returned by
|
||||||
|
// the below switch.
|
||||||
|
// The consistency is verified in trace_DIE.
|
||||||
|
switch (form) {
|
||||||
|
case DW_FORM_data1: return 1;
|
||||||
|
case DW_FORM_data2: return 2;
|
||||||
|
case DW_FORM_data4: return 4;
|
||||||
|
case DW_FORM_data8: return 8;
|
||||||
|
case DW_FORM_sec_offset:
|
||||||
|
if (cc->is_dw64)
|
||||||
|
return 8;
|
||||||
|
else
|
||||||
|
return 4;
|
||||||
|
case DW_FORM_sdata:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_udata:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_addr: // See hack in get_Form_contents
|
||||||
|
return sizeof(UWord);
|
||||||
|
case DW_FORM_ref_addr: // See hack in get_Form_contents
|
||||||
|
if (cc->version == 2)
|
||||||
|
return sizeof(UWord);
|
||||||
|
else
|
||||||
|
return sizeof_Dwarfish_UWord (cc->is_dw64);
|
||||||
|
case DW_FORM_strp:
|
||||||
|
return sizeof_Dwarfish_UWord (cc->is_dw64);
|
||||||
|
case DW_FORM_string:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_ref1:
|
||||||
|
return 1;
|
||||||
|
case DW_FORM_ref2:
|
||||||
|
return 2;
|
||||||
|
case DW_FORM_ref4:
|
||||||
|
return 4;
|
||||||
|
case DW_FORM_ref8:
|
||||||
|
return 8;
|
||||||
|
case DW_FORM_ref_udata:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_flag:
|
||||||
|
return 1;
|
||||||
|
case DW_FORM_flag_present:
|
||||||
|
return 0; // !!! special case, no data.
|
||||||
|
case DW_FORM_block1:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_block2:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_block4:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_exprloc:
|
||||||
|
case DW_FORM_block:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_ref_sig8:
|
||||||
|
return 8 + 8;
|
||||||
|
case DW_FORM_indirect:
|
||||||
|
return VARSZ_FORM;
|
||||||
|
case DW_FORM_GNU_ref_alt:
|
||||||
|
return sizeof_Dwarfish_UWord(cc->is_dw64);
|
||||||
|
case DW_FORM_GNU_strp_alt:
|
||||||
|
return sizeof_Dwarfish_UWord(cc->is_dw64);
|
||||||
|
default:
|
||||||
|
VG_(printf)(
|
||||||
|
"get_Form_szB: unhandled %d (%s)\n",
|
||||||
|
form, ML_(pp_DW_FORM)(form));
|
||||||
|
cc->barf("get_Form_contents: unhandled DW_FORM");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip a DIE as described by abbv.
|
||||||
|
If the DIE has a sibling, *sibling is set to the skipped DIE sibling value. */
|
||||||
|
static
|
||||||
|
void skip_DIE (UWord *sibling,
|
||||||
|
Cursor* c_die,
|
||||||
|
g_abbv *abbv,
|
||||||
|
CUConst* cc)
|
||||||
|
{
|
||||||
|
UInt nf_i;
|
||||||
|
FormContents cts;
|
||||||
|
nf_i = 0;
|
||||||
|
while (True) {
|
||||||
|
if (abbv->nf[nf_i].at_name == DW_AT_sibling) {
|
||||||
|
get_Form_contents( &cts, cc, c_die, False /*td3*/,
|
||||||
|
(DW_FORM)abbv->nf[nf_i].at_form );
|
||||||
|
if ( cts.szB > 0 )
|
||||||
|
*sibling = cts.u.val;
|
||||||
|
nf_i++;
|
||||||
|
} else if (abbv->nf[nf_i].skip_szB == VARSZ_FORM) {
|
||||||
|
get_Form_contents( &cts, cc, c_die, False /*td3*/,
|
||||||
|
(DW_FORM)abbv->nf[nf_i].at_form );
|
||||||
|
nf_i++;
|
||||||
|
} else {
|
||||||
|
advance_position_of_Cursor (c_die, (ULong)abbv->nf[nf_i].skip_szB);
|
||||||
|
nf_i = abbv->nf[nf_i].next_nf;
|
||||||
|
}
|
||||||
|
if (nf_i == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------*/
|
/*------------------------------------------------------------*/
|
||||||
/*--- ---*/
|
/*--- ---*/
|
||||||
@ -1586,8 +1756,8 @@ void read_filename_table( /*MOD*/XArray* /* of UChar* */ filenameTable,
|
|||||||
"Overrun whilst reading .debug_line section(1)" );
|
"Overrun whilst reading .debug_line section(1)" );
|
||||||
|
|
||||||
/* unit_length = */
|
/* unit_length = */
|
||||||
get_Initial_Length( &is_dw64, &c,
|
get_Initial_Length( &is_dw64, &c,
|
||||||
"read_filename_table: invalid initial-length field" );
|
"read_filename_table: invalid initial-length field" );
|
||||||
version = get_UShort( &c );
|
version = get_UShort( &c );
|
||||||
if (version != 2 && version != 3 && version != 4)
|
if (version != 2 && version != 3 && version != 4)
|
||||||
cc->barf("read_filename_table: Only DWARF version 2, 3 and 4 line info "
|
cc->barf("read_filename_table: Only DWARF version 2, 3 and 4 line info "
|
||||||
@ -1685,9 +1855,12 @@ static void trace_DIE(
|
|||||||
{
|
{
|
||||||
Cursor c;
|
Cursor c;
|
||||||
FormContents cts;
|
FormContents cts;
|
||||||
|
UWord sibling = 0;
|
||||||
UInt nf_i;
|
UInt nf_i;
|
||||||
Bool debug_types_flag;
|
Bool debug_types_flag;
|
||||||
Bool alt_flag;
|
Bool alt_flag;
|
||||||
|
Cursor check_skip;
|
||||||
|
UWord check_sibling = 0;
|
||||||
|
|
||||||
posn = uncook_die( cc, posn, &debug_types_flag, &alt_flag );
|
posn = uncook_die( cc, posn, &debug_types_flag, &alt_flag );
|
||||||
init_Cursor (&c,
|
init_Cursor (&c,
|
||||||
@ -1695,6 +1868,7 @@ static void trace_DIE(
|
|||||||
alt_flag ? cc->escn_debug_info_alt : cc->escn_debug_info,
|
alt_flag ? cc->escn_debug_info_alt : cc->escn_debug_info,
|
||||||
saved_die_c_offset, cc->barf,
|
saved_die_c_offset, cc->barf,
|
||||||
"Overrun trace_DIE");
|
"Overrun trace_DIE");
|
||||||
|
check_skip = c;
|
||||||
VG_(printf)(" <%d><%lx>: Abbrev Number: %llu (%s)%s%s\n",
|
VG_(printf)(" <%d><%lx>: Abbrev Number: %llu (%s)%s%s\n",
|
||||||
level, posn, (ULong) abbv->abbv_code, ML_(pp_DW_TAG)( dtag ),
|
level, posn, (ULong) abbv->abbv_code, ML_(pp_DW_TAG)( dtag ),
|
||||||
debug_types_flag ? " (in .debug_types)" : "",
|
debug_types_flag ? " (in .debug_types)" : "",
|
||||||
@ -1708,8 +1882,22 @@ static void trace_DIE(
|
|||||||
VG_(printf)(" %18s: ", ML_(pp_DW_AT)(attr));
|
VG_(printf)(" %18s: ", ML_(pp_DW_AT)(attr));
|
||||||
/* Get the form contents, so as to print them */
|
/* Get the form contents, so as to print them */
|
||||||
get_Form_contents( &cts, cc, &c, True, form );
|
get_Form_contents( &cts, cc, &c, True, form );
|
||||||
|
if (attr == DW_AT_sibling && cts.szB > 0) {
|
||||||
|
sibling = cts.u.val;
|
||||||
|
}
|
||||||
VG_(printf)("\t\n");
|
VG_(printf)("\t\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Verify that skipping a DIE gives the same displacement as
|
||||||
|
tracing (i.e. reading) a DIE. If there is an inconsistency in
|
||||||
|
the nr of bytes read by get_Form_contents and get_Form_szB, this
|
||||||
|
should be detected by the below. Using --trace-symtab=yes
|
||||||
|
--read-var-info=yes will ensure all DIEs are systematically
|
||||||
|
verified. */
|
||||||
|
skip_DIE (&check_sibling, &check_skip, abbv, cc);
|
||||||
|
vg_assert (check_sibling == sibling);
|
||||||
|
vg_assert (get_position_of_Cursor (&check_skip)
|
||||||
|
== get_position_of_Cursor (&c));
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
@ -3823,26 +4011,11 @@ static void read_DIE (
|
|||||||
// DIE was read by a parser above, so we know where the DIE ends.
|
// DIE was read by a parser above, so we know where the DIE ends.
|
||||||
set_position_of_Cursor( c, after_die_c_offset );
|
set_position_of_Cursor( c, after_die_c_offset );
|
||||||
} else {
|
} else {
|
||||||
/* No parser has parsed this DIE. So, we need to read the DIE
|
/* No parser has parsed this DIE. So, we need to skip the DIE,
|
||||||
to skip its data, in order to read the next DIE.
|
in order to read the next DIE.
|
||||||
At the same time, establish sibling value if the DIE has one. */
|
At the same time, establish sibling value if the DIE has one. */
|
||||||
UInt nf_i;
|
TRACE_D3(" uninteresting DIE -> skipping ...\n");
|
||||||
|
skip_DIE (&sibling, c, abbv, cc);
|
||||||
TRACE_D3(" (skipped DIE)\n");
|
|
||||||
nf_i = 0;
|
|
||||||
while (True) {
|
|
||||||
FormContents cts;
|
|
||||||
ULong at_name = abbv->nf[nf_i].at_name;
|
|
||||||
ULong at_form = abbv->nf[nf_i].at_form;
|
|
||||||
nf_i++;
|
|
||||||
if (at_name == 0 && at_form == 0) break;
|
|
||||||
/* Get the form contents, but ignore them; the only purpose is
|
|
||||||
to skip the data or get the DIE sibling, if it has one. */
|
|
||||||
get_Form_contents( &cts, cc, c, False /*td3*/, (DW_FORM)at_form );
|
|
||||||
if (UNLIKELY(at_name == DW_AT_sibling && cts.szB > 0)) {
|
|
||||||
sibling = cts.u.val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Now recurse into its children, if any
|
/* --- Now recurse into its children, if any
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user