create_dwo_cus_hash_table is implemented by creating a cutu_reader
(which is somewhat heavy) for all units in a .dwo file. The purpose of
this cutu_reader is to be able to get the DWO ID, if it is specified by
a DW_AT_GNU_dwo_id attribute.
In DWARF 5, however, the DWO ID is available in the CU header. We can
access it without accessing the DIEs, by just reading the header, which
is more lightweight. Add a new code path to create_dwo_cus_hash_table
that does that. The logic is copied from
create_dwo_debug_type_hash_table, which does this already.
This change helps circumvent a performance problem I want to fix (the
same I was trying to fix in this patch [1]) when loading a file built
with -gdwarf-5, -gsplit-dwarf and -fdebug-types-section. In this
configuration, the produced .dwo files contain one compile unit and many
type units each. All units in a given .dwo share the same abbrev table.
Creating a cutu_reader for each unit meant re-reading the same abbrev
table over and over. What's particularly bad is that this is done with
the dwo_lock held, preventing other indexing threads from making
progress.
To give a rough idea, here's the time take by each worker to index units
before this patch (on a rather large program):
Time for "DWARF indexing worker": wall 18.627, user 0.885, sys 0.042, user+sys 0.927, 5.0 % CPU
Time for "DWARF indexing worker": wall 18.888, user 0.862, sys 0.042, user+sys 0.904, 4.8 % CPU
Time for "DWARF indexing worker": wall 19.172, user 1.848, sys 0.069, user+sys 1.917, 10.0 % CPU
Time for "DWARF indexing worker": wall 19.297, user 1.544, sys 0.051, user+sys 1.595, 8.3 % CPU
Time for "DWARF indexing worker": wall 19.545, user 3.408, sys 0.084, user+sys 3.492, 17.9 % CPU
Time for "DWARF indexing worker": wall 19.759, user 4.221, sys 0.117, user+sys 4.338, 22.0 % CPU
Time for "DWARF indexing worker": wall 19.789, user 4.187, sys 0.105, user+sys 4.292, 21.7 % CPU
Time for "DWARF indexing worker": wall 19.825, user 4.933, sys 0.135, user+sys 5.068, 25.6 % CPU
And the times with this patch:
Time for "DWARF indexing worker": wall 0.163, user 0.089, sys 0.029, user+sys 0.118, 72.4 % CPU
Time for "DWARF indexing worker": wall 0.176, user 0.096, sys 0.041, user+sys 0.137, 77.8 % CPU
Time for "DWARF indexing worker": wall 0.265, user 0.167, sys 0.054, user+sys 0.221, 83.4 % CPU
Time for "DWARF indexing worker": wall 0.353, user 0.257, sys 0.060, user+sys 0.317, 89.8 % CPU
Time for "DWARF indexing worker": wall 0.524, user 0.399, sys 0.088, user+sys 0.487, 92.9 % CPU
Time for "DWARF indexing worker": wall 0.648, user 0.517, sys 0.107, user+sys 0.624, 96.3 % CPU
Time for "DWARF indexing worker": wall 0.657, user 0.523, sys 0.107, user+sys 0.630, 95.9 % CPU
Time for "DWARF indexing worker": wall 0.753, user 0.612, sys 0.120, user+sys 0.732, 97.2 % CPU
[1] https://inbox.sourceware.org/gdb-patches/
20250326200002.136200-8-simon.marchi@efficios.com/
Change-Id: I34a422577e4c3ad7d478ec6df12a0e44d284c249
Approved-By: Tom Tromey <tom@tromey.com>
while (info_ptr < end_ptr)
{
sect_offset sect_off = (sect_offset) (info_ptr - section.buffer);
+ ULONGEST signature;
+ unsigned int length;
- /* The length of the CU gets set by the cutu_reader just below. */
- dwarf2_per_cu per_cu (per_bfd, §ion, sect_off, 0 /* length */,
- false /* is_dwz */);
- cutu_reader reader (per_cu, *per_objfile, language_minimal,
- *cu, dwo_file);
+ if (cu->header.version < 5)
+ {
+ /* The length of the CU gets set by the cutu_reader just below. */
+ dwarf2_per_cu per_cu (per_bfd, §ion, sect_off, 0 /* length */,
+ false /* is_dwz */);
+ cutu_reader reader (per_cu, *per_objfile, language_minimal, *cu,
+ dwo_file);
- info_ptr += per_cu.length ();
+ info_ptr += per_cu.length ();
- if (reader.is_dummy())
- continue;
+ if (reader.is_dummy ())
+ continue;
- /* DWARF 5 .debug_info.dwo sections may contain some type units. Skip
- everything that is not a compile unit. */
- if (const auto ut = reader.cu ()->header.unit_type;
- ut != DW_UT_compile && ut != DW_UT_split_compile)
- continue;
+ std::optional<ULONGEST> opt_signature
+ = lookup_dwo_id (reader.cu (), reader.top_level_die ());
+ if (!opt_signature.has_value ())
+ {
+ complaint (_(DWARF_ERROR_PREFIX
+ "debug entry at offset %s is missing its dwo_id"
+ " [in module %s]"),
+ sect_offset_str (sect_off),
+ dwo_file.dwo_name.c_str ());
+ continue;
+ }
- std::optional<ULONGEST> signature
- = lookup_dwo_id (reader.cu (), reader.top_level_die ());
- if (!signature.has_value ())
+ signature = *opt_signature;
+ length = per_cu.length ();
+ }
+ else
{
- complaint (_(DWARF_ERROR_PREFIX
- "debug entry at offset %s is missing its dwo_id"
- " [in module %s]"),
- sect_offset_str (sect_off),
- dwo_file.dwo_name.c_str ());
- continue;
+ unit_head header;
+ dwarf2_section_info *abbrev_section = &dwo_file.sections.abbrev;
+ const gdb_byte *info_ptr_post_header
+ = read_and_check_unit_head (&header, §ion, abbrev_section,
+ info_ptr, ruh_kind::COMPILE);
+
+ length = header.get_length_with_initial ();
+ info_ptr += length;
+
+ /* Skip dummy units. */
+ if (info_ptr_post_header >= info_ptr
+ || peek_abbrev_code (section.get_bfd_owner (),
+ info_ptr_post_header) == 0)
+ continue;
+
+ /* DWARF 5 .debug_info.dwo sections may contain some type units. Skip
+ everything that is not a compile unit. */
+ if (header.unit_type != DW_UT_split_compile)
+ continue;
+
+ signature = header.signature;
}
dwo_unit *dwo_unit = OBSTACK_ZALLOC (&per_bfd->obstack, struct dwo_unit);
dwo_unit->dwo_file = &dwo_file;
- dwo_unit->signature = *signature;
+ dwo_unit->signature = signature;
dwo_unit->section = §ion;
dwo_unit->sect_off = sect_off;
- dwo_unit->length = per_cu.length ();
+ dwo_unit->length = length;
dwarf_read_debug_printf (" offset %s, dwo_id %s",
sect_offset_str (sect_off),