From e352e8b044ebfe2a0ed31be43f6d57cf1a041a7e Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Thu, 24 Apr 2025 13:36:26 -0400 Subject: [PATCH] gdb/dwarf: scan DWARF 5 DWO CUs by just reading the header 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 --- gdb/dwarf2/read.c | 74 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 281cf118eb8..9a5e3b10a2c 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -6339,43 +6339,69 @@ cutu_reader::create_dwo_cus_hash_table (dwarf2_cu *cu, dwo_file &dwo_file) 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 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 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), -- 2.39.5