[binutils-gdb] gdb/dwarf: scan DWARF 5 DWO CUs by just reading the header

Simon Marchi simark@sourceware.org
Tue Apr 29 19:50:22 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e352e8b044ebfe2a0ed31be43f6d57cf1a041a7e

commit e352e8b044ebfe2a0ed31be43f6d57cf1a041a7e
Author: Simon Marchi <simon.marchi@efficios.com>
Date:   Thu Apr 24 13:36:26 2025 -0400

    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 <tom@tromey.com>

Diff:
---
 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, &section, 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, &section, 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, &section, 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),


More information about the Gdb-cvs mailing list