build_type_unit_groups and moved closer to only caller and renamed
* dwarf2read.c (build_type_psymtabs_1): Renamed from build_type_unit_groups and moved closer to only caller. Remove arguments. All references updated. Remove outdated .gdb_index comment. (struct tu_abbrev_offset, sort_tu_by_abbrev_offset): Move with build_type_psymtabs_1.
This commit is contained in:
parent
c4e54771f8
commit
7305118224
|
@ -3,6 +3,15 @@
|
||||||
* gdbtypes.c (rank_function): Use XNEWVEC.
|
* gdbtypes.c (rank_function): Use XNEWVEC.
|
||||||
* mi/mi-cmds.c (build_table): Use XCNEWVEC.
|
* mi/mi-cmds.c (build_table): Use XCNEWVEC.
|
||||||
|
|
||||||
|
2014-05-19 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
|
* dwarf2read.c (build_type_psymtabs_1): Renamed from
|
||||||
|
build_type_unit_groups and moved closer to only caller. Remove
|
||||||
|
arguments. All references updated. Remove outdated .gdb_index
|
||||||
|
comment.
|
||||||
|
(struct tu_abbrev_offset, sort_tu_by_abbrev_offset): Move with
|
||||||
|
build_type_psymtabs_1.
|
||||||
|
|
||||||
2014-05-19 Doug Evans <dje@google.com>
|
2014-05-19 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
* dwarf2read.c (struct dwarf2_per_objfile): Delete unused members
|
* dwarf2read.c (struct dwarf2_per_objfile): Delete unused members
|
||||||
|
|
313
gdb/dwarf2read.c
313
gdb/dwarf2read.c
|
@ -5731,162 +5731,6 @@ get_type_unit_group (struct dwarf2_cu *cu, const struct attribute *stmt_list)
|
||||||
|
|
||||||
return tu_group;
|
return tu_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Struct used to sort TUs by their abbreviation table offset. */
|
|
||||||
|
|
||||||
struct tu_abbrev_offset
|
|
||||||
{
|
|
||||||
struct signatured_type *sig_type;
|
|
||||||
sect_offset abbrev_offset;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Helper routine for build_type_unit_groups, passed to qsort. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
sort_tu_by_abbrev_offset (const void *ap, const void *bp)
|
|
||||||
{
|
|
||||||
const struct tu_abbrev_offset * const *a = ap;
|
|
||||||
const struct tu_abbrev_offset * const *b = bp;
|
|
||||||
unsigned int aoff = (*a)->abbrev_offset.sect_off;
|
|
||||||
unsigned int boff = (*b)->abbrev_offset.sect_off;
|
|
||||||
|
|
||||||
return (aoff > boff) - (aoff < boff);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Efficiently read all the type units, calling init_cutu_and_read_dies on
|
|
||||||
each one passing FUNC,DATA.
|
|
||||||
|
|
||||||
The efficiency is because we sort TUs by the abbrev table they use and
|
|
||||||
only read each abbrev table once. In one program there are 200K TUs
|
|
||||||
sharing 8K abbrev tables.
|
|
||||||
|
|
||||||
The main purpose of this function is to support building the
|
|
||||||
dwarf2_per_objfile->type_unit_groups table.
|
|
||||||
TUs typically share the DW_AT_stmt_list of the CU they came from, so we
|
|
||||||
can collapse the search space by grouping them by stmt_list.
|
|
||||||
The savings can be significant, in the same program from above the 200K TUs
|
|
||||||
share 8K stmt_list tables.
|
|
||||||
|
|
||||||
FUNC is expected to call get_type_unit_group, which will create the
|
|
||||||
struct type_unit_group if necessary and add it to
|
|
||||||
dwarf2_per_objfile->type_unit_groups. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
build_type_unit_groups (die_reader_func_ftype *func, void *data)
|
|
||||||
{
|
|
||||||
struct objfile *objfile = dwarf2_per_objfile->objfile;
|
|
||||||
struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats;
|
|
||||||
struct cleanup *cleanups;
|
|
||||||
struct abbrev_table *abbrev_table;
|
|
||||||
sect_offset abbrev_offset;
|
|
||||||
struct tu_abbrev_offset *sorted_by_abbrev;
|
|
||||||
struct type_unit_group **iter;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* It's up to the caller to not call us multiple times. */
|
|
||||||
gdb_assert (dwarf2_per_objfile->type_unit_groups == NULL);
|
|
||||||
|
|
||||||
if (dwarf2_per_objfile->n_type_units == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* TUs typically share abbrev tables, and there can be way more TUs than
|
|
||||||
abbrev tables. Sort by abbrev table to reduce the number of times we
|
|
||||||
read each abbrev table in.
|
|
||||||
Alternatives are to punt or to maintain a cache of abbrev tables.
|
|
||||||
This is simpler and efficient enough for now.
|
|
||||||
|
|
||||||
Later we group TUs by their DW_AT_stmt_list value (as this defines the
|
|
||||||
symtab to use). Typically TUs with the same abbrev offset have the same
|
|
||||||
stmt_list value too so in practice this should work well.
|
|
||||||
|
|
||||||
The basic algorithm here is:
|
|
||||||
|
|
||||||
sort TUs by abbrev table
|
|
||||||
for each TU with same abbrev table:
|
|
||||||
read abbrev table if first user
|
|
||||||
read TU top level DIE
|
|
||||||
[IWBN if DWO skeletons had DW_AT_stmt_list]
|
|
||||||
call FUNC */
|
|
||||||
|
|
||||||
if (dwarf2_read_debug)
|
|
||||||
fprintf_unfiltered (gdb_stdlog, "Building type unit groups ...\n");
|
|
||||||
|
|
||||||
/* Sort in a separate table to maintain the order of all_type_units
|
|
||||||
for .gdb_index: TU indices directly index all_type_units. */
|
|
||||||
sorted_by_abbrev = XNEWVEC (struct tu_abbrev_offset,
|
|
||||||
dwarf2_per_objfile->n_type_units);
|
|
||||||
for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
|
|
||||||
{
|
|
||||||
struct signatured_type *sig_type = dwarf2_per_objfile->all_type_units[i];
|
|
||||||
|
|
||||||
sorted_by_abbrev[i].sig_type = sig_type;
|
|
||||||
sorted_by_abbrev[i].abbrev_offset =
|
|
||||||
read_abbrev_offset (sig_type->per_cu.section,
|
|
||||||
sig_type->per_cu.offset);
|
|
||||||
}
|
|
||||||
cleanups = make_cleanup (xfree, sorted_by_abbrev);
|
|
||||||
qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units,
|
|
||||||
sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset);
|
|
||||||
|
|
||||||
/* Note: In the .gdb_index case, get_type_unit_group may have already been
|
|
||||||
called any number of times, so we don't reset tu_stats here. */
|
|
||||||
|
|
||||||
abbrev_offset.sect_off = ~(unsigned) 0;
|
|
||||||
abbrev_table = NULL;
|
|
||||||
make_cleanup (abbrev_table_free_cleanup, &abbrev_table);
|
|
||||||
|
|
||||||
for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
|
|
||||||
{
|
|
||||||
const struct tu_abbrev_offset *tu = &sorted_by_abbrev[i];
|
|
||||||
|
|
||||||
/* Switch to the next abbrev table if necessary. */
|
|
||||||
if (abbrev_table == NULL
|
|
||||||
|| tu->abbrev_offset.sect_off != abbrev_offset.sect_off)
|
|
||||||
{
|
|
||||||
if (abbrev_table != NULL)
|
|
||||||
{
|
|
||||||
abbrev_table_free (abbrev_table);
|
|
||||||
/* Reset to NULL in case abbrev_table_read_table throws
|
|
||||||
an error: abbrev_table_free_cleanup will get called. */
|
|
||||||
abbrev_table = NULL;
|
|
||||||
}
|
|
||||||
abbrev_offset = tu->abbrev_offset;
|
|
||||||
abbrev_table =
|
|
||||||
abbrev_table_read_table (&dwarf2_per_objfile->abbrev,
|
|
||||||
abbrev_offset);
|
|
||||||
++tu_stats->nr_uniq_abbrev_tables;
|
|
||||||
}
|
|
||||||
|
|
||||||
init_cutu_and_read_dies (&tu->sig_type->per_cu, abbrev_table, 0, 0,
|
|
||||||
func, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* type_unit_groups can be NULL if there is an error in the debug info.
|
|
||||||
Just create an empty table so the rest of gdb doesn't have to watch
|
|
||||||
for this error case. */
|
|
||||||
if (dwarf2_per_objfile->type_unit_groups == NULL)
|
|
||||||
{
|
|
||||||
dwarf2_per_objfile->type_unit_groups =
|
|
||||||
allocate_type_unit_groups_table ();
|
|
||||||
}
|
|
||||||
|
|
||||||
do_cleanups (cleanups);
|
|
||||||
|
|
||||||
if (dwarf2_read_debug)
|
|
||||||
{
|
|
||||||
fprintf_unfiltered (gdb_stdlog, "Done building type unit groups:\n");
|
|
||||||
fprintf_unfiltered (gdb_stdlog, " %d TUs\n",
|
|
||||||
dwarf2_per_objfile->n_type_units);
|
|
||||||
fprintf_unfiltered (gdb_stdlog, " %d uniq abbrev tables\n",
|
|
||||||
tu_stats->nr_uniq_abbrev_tables);
|
|
||||||
fprintf_unfiltered (gdb_stdlog, " %d symtabs from stmt_list entries\n",
|
|
||||||
tu_stats->nr_symtabs);
|
|
||||||
fprintf_unfiltered (gdb_stdlog, " %d symtab sharers\n",
|
|
||||||
tu_stats->nr_symtab_sharers);
|
|
||||||
fprintf_unfiltered (gdb_stdlog, " %d type units without a stmt_list\n",
|
|
||||||
tu_stats->nr_stmt_less_type_units);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Partial symbol tables. */
|
/* Partial symbol tables. */
|
||||||
|
|
||||||
|
@ -6144,6 +5988,159 @@ build_type_psymtabs_reader (const struct die_reader_specs *reader,
|
||||||
sort_pst_symbols (objfile, pst);
|
sort_pst_symbols (objfile, pst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Struct used to sort TUs by their abbreviation table offset. */
|
||||||
|
|
||||||
|
struct tu_abbrev_offset
|
||||||
|
{
|
||||||
|
struct signatured_type *sig_type;
|
||||||
|
sect_offset abbrev_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper routine for build_type_psymtabs_1, passed to qsort. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
sort_tu_by_abbrev_offset (const void *ap, const void *bp)
|
||||||
|
{
|
||||||
|
const struct tu_abbrev_offset * const *a = ap;
|
||||||
|
const struct tu_abbrev_offset * const *b = bp;
|
||||||
|
unsigned int aoff = (*a)->abbrev_offset.sect_off;
|
||||||
|
unsigned int boff = (*b)->abbrev_offset.sect_off;
|
||||||
|
|
||||||
|
return (aoff > boff) - (aoff < boff);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Efficiently read all the type units.
|
||||||
|
This does the bulk of the work for build_type_psymtabs.
|
||||||
|
|
||||||
|
The efficiency is because we sort TUs by the abbrev table they use and
|
||||||
|
only read each abbrev table once. In one program there are 200K TUs
|
||||||
|
sharing 8K abbrev tables.
|
||||||
|
|
||||||
|
The main purpose of this function is to support building the
|
||||||
|
dwarf2_per_objfile->type_unit_groups table.
|
||||||
|
TUs typically share the DW_AT_stmt_list of the CU they came from, so we
|
||||||
|
can collapse the search space by grouping them by stmt_list.
|
||||||
|
The savings can be significant, in the same program from above the 200K TUs
|
||||||
|
share 8K stmt_list tables.
|
||||||
|
|
||||||
|
FUNC is expected to call get_type_unit_group, which will create the
|
||||||
|
struct type_unit_group if necessary and add it to
|
||||||
|
dwarf2_per_objfile->type_unit_groups. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
build_type_psymtabs_1 (void)
|
||||||
|
{
|
||||||
|
struct objfile *objfile = dwarf2_per_objfile->objfile;
|
||||||
|
struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats;
|
||||||
|
struct cleanup *cleanups;
|
||||||
|
struct abbrev_table *abbrev_table;
|
||||||
|
sect_offset abbrev_offset;
|
||||||
|
struct tu_abbrev_offset *sorted_by_abbrev;
|
||||||
|
struct type_unit_group **iter;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* It's up to the caller to not call us multiple times. */
|
||||||
|
gdb_assert (dwarf2_per_objfile->type_unit_groups == NULL);
|
||||||
|
|
||||||
|
if (dwarf2_per_objfile->n_type_units == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* TUs typically share abbrev tables, and there can be way more TUs than
|
||||||
|
abbrev tables. Sort by abbrev table to reduce the number of times we
|
||||||
|
read each abbrev table in.
|
||||||
|
Alternatives are to punt or to maintain a cache of abbrev tables.
|
||||||
|
This is simpler and efficient enough for now.
|
||||||
|
|
||||||
|
Later we group TUs by their DW_AT_stmt_list value (as this defines the
|
||||||
|
symtab to use). Typically TUs with the same abbrev offset have the same
|
||||||
|
stmt_list value too so in practice this should work well.
|
||||||
|
|
||||||
|
The basic algorithm here is:
|
||||||
|
|
||||||
|
sort TUs by abbrev table
|
||||||
|
for each TU with same abbrev table:
|
||||||
|
read abbrev table if first user
|
||||||
|
read TU top level DIE
|
||||||
|
[IWBN if DWO skeletons had DW_AT_stmt_list]
|
||||||
|
call FUNC */
|
||||||
|
|
||||||
|
if (dwarf2_read_debug)
|
||||||
|
fprintf_unfiltered (gdb_stdlog, "Building type unit groups ...\n");
|
||||||
|
|
||||||
|
/* Sort in a separate table to maintain the order of all_type_units
|
||||||
|
for .gdb_index: TU indices directly index all_type_units. */
|
||||||
|
sorted_by_abbrev = XNEWVEC (struct tu_abbrev_offset,
|
||||||
|
dwarf2_per_objfile->n_type_units);
|
||||||
|
for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
|
||||||
|
{
|
||||||
|
struct signatured_type *sig_type = dwarf2_per_objfile->all_type_units[i];
|
||||||
|
|
||||||
|
sorted_by_abbrev[i].sig_type = sig_type;
|
||||||
|
sorted_by_abbrev[i].abbrev_offset =
|
||||||
|
read_abbrev_offset (sig_type->per_cu.section,
|
||||||
|
sig_type->per_cu.offset);
|
||||||
|
}
|
||||||
|
cleanups = make_cleanup (xfree, sorted_by_abbrev);
|
||||||
|
qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units,
|
||||||
|
sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset);
|
||||||
|
|
||||||
|
abbrev_offset.sect_off = ~(unsigned) 0;
|
||||||
|
abbrev_table = NULL;
|
||||||
|
make_cleanup (abbrev_table_free_cleanup, &abbrev_table);
|
||||||
|
|
||||||
|
for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
|
||||||
|
{
|
||||||
|
const struct tu_abbrev_offset *tu = &sorted_by_abbrev[i];
|
||||||
|
|
||||||
|
/* Switch to the next abbrev table if necessary. */
|
||||||
|
if (abbrev_table == NULL
|
||||||
|
|| tu->abbrev_offset.sect_off != abbrev_offset.sect_off)
|
||||||
|
{
|
||||||
|
if (abbrev_table != NULL)
|
||||||
|
{
|
||||||
|
abbrev_table_free (abbrev_table);
|
||||||
|
/* Reset to NULL in case abbrev_table_read_table throws
|
||||||
|
an error: abbrev_table_free_cleanup will get called. */
|
||||||
|
abbrev_table = NULL;
|
||||||
|
}
|
||||||
|
abbrev_offset = tu->abbrev_offset;
|
||||||
|
abbrev_table =
|
||||||
|
abbrev_table_read_table (&dwarf2_per_objfile->abbrev,
|
||||||
|
abbrev_offset);
|
||||||
|
++tu_stats->nr_uniq_abbrev_tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_cutu_and_read_dies (&tu->sig_type->per_cu, abbrev_table, 0, 0,
|
||||||
|
build_type_psymtabs_reader, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* type_unit_groups can be NULL if there is an error in the debug info.
|
||||||
|
Just create an empty table so the rest of gdb doesn't have to watch
|
||||||
|
for this error case. */
|
||||||
|
if (dwarf2_per_objfile->type_unit_groups == NULL)
|
||||||
|
{
|
||||||
|
dwarf2_per_objfile->type_unit_groups =
|
||||||
|
allocate_type_unit_groups_table ();
|
||||||
|
}
|
||||||
|
|
||||||
|
do_cleanups (cleanups);
|
||||||
|
|
||||||
|
if (dwarf2_read_debug)
|
||||||
|
{
|
||||||
|
fprintf_unfiltered (gdb_stdlog, "Done building type unit groups:\n");
|
||||||
|
fprintf_unfiltered (gdb_stdlog, " %d TUs\n",
|
||||||
|
dwarf2_per_objfile->n_type_units);
|
||||||
|
fprintf_unfiltered (gdb_stdlog, " %d uniq abbrev tables\n",
|
||||||
|
tu_stats->nr_uniq_abbrev_tables);
|
||||||
|
fprintf_unfiltered (gdb_stdlog, " %d symtabs from stmt_list entries\n",
|
||||||
|
tu_stats->nr_symtabs);
|
||||||
|
fprintf_unfiltered (gdb_stdlog, " %d symtab sharers\n",
|
||||||
|
tu_stats->nr_symtab_sharers);
|
||||||
|
fprintf_unfiltered (gdb_stdlog, " %d type units without a stmt_list\n",
|
||||||
|
tu_stats->nr_stmt_less_type_units);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Traversal function for build_type_psymtabs. */
|
/* Traversal function for build_type_psymtabs. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -6186,7 +6183,7 @@ build_type_psymtabs (struct objfile *objfile)
|
||||||
if (! create_all_type_units (objfile))
|
if (! create_all_type_units (objfile))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
build_type_unit_groups (build_type_psymtabs_reader, NULL);
|
build_type_psymtabs_1 ();
|
||||||
|
|
||||||
/* Now that all TUs have been processed we can fill in the dependencies. */
|
/* Now that all TUs have been processed we can fill in the dependencies. */
|
||||||
htab_traverse_noresize (dwarf2_per_objfile->type_unit_groups,
|
htab_traverse_noresize (dwarf2_per_objfile->type_unit_groups,
|
||||||
|
@ -14969,7 +14966,7 @@ abbrev_table_free (struct abbrev_table *abbrev_table)
|
||||||
/* Same as abbrev_table_free but as a cleanup.
|
/* Same as abbrev_table_free but as a cleanup.
|
||||||
We pass in a pointer to the pointer to the table so that we can
|
We pass in a pointer to the pointer to the table so that we can
|
||||||
set the pointer to NULL when we're done. It also simplifies
|
set the pointer to NULL when we're done. It also simplifies
|
||||||
build_type_unit_groups. */
|
build_type_psymtabs_1. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
abbrev_table_free_cleanup (void *table_ptr)
|
abbrev_table_free_cleanup (void *table_ptr)
|
||||||
|
|
Loading…
Reference in New Issue