This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Improve handling of file names with .gdb_index support


Hi.

This patch is a follow-on to
http://sourceware.org/ml/gdb-patches/2010-12/msg00090.html
and
http://sourceware.org/ml/gdb-patches/2010-12/msg00091.html

It creates a hash table of per-CU/TU file names.
TUs can share the same line_header data as CUs,
and in a program with 5000 CUs and 95000 TUs,
that's a lot of sharing!
Plus the "quick" functions only need the file names, they no longer need
line_header once the file names are obtained, so this patch
frees line_header once done.

Regression tested on amd64-linux with
bash$ runtest \
  CC_FOR_TARGET="/bin/sh $srcdir/cc-with-index.sh gcc" \
  CXX_FOR_TARGET="/bin/sh $srcdir/cc-with-index.sh g++"

I plan to check this in tomorrow.

2010-12-10  Doug Evans  <dje@google.com>

	* dwarf2read.c (dwarf2_per_objfile): New member quick_file_names_table.
	(dwarf2_per_cu_quick_data): Move definition down to "quick functions"
	section.  Delete members lines full_names.  Rename read_lines to
	no_file_data.
	(quick_file_names): New struct.
	(hash_file_name_entry, eq_file_name_entry): New functions.
	(delete_file_name_entry, create_quick_file_names_table): New functions.
	(dwarf2_read_index): Initialize quick_file_names_table.
	(dw2_get_file_names): Renamed from dw2_require_line_header.
	Return pointer to quick_file_names entry.  All callers updated.
	(dw2_get_real_path): Renamed from dw2_require_full_path.
	Replace per_cu arg with pointer to quick_file_names entry.
	All callers updated.
	(dw2_free_cached_file_names): New function.
	(dw2_forget_cached_source_info): Call it (via htab_traverse_noresize).
	(dwarf2_initialize_objfile): Initialize quick_file_names_table in
	the OBJF_READNOW case.
	(dwarf2_free_objfile): Rewrite freeing of quick file names tables.

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.488
diff -u -p -r1.488 dwarf2read.c
--- dwarf2read.c	10 Dec 2010 22:00:00 -0000	1.488
+++ dwarf2read.c	10 Dec 2010 22:03:36 -0000
@@ -211,6 +211,12 @@ struct dwarf2_per_objfile
   /* The mapped index, or NULL if .gdb_index is missing or not being used.  */
   struct mapped_index *index_table;
 
+  /* When using index_table, this keeps track of all quick_file_names entries.
+     TUs can share line table entries with CUs or other TUs, and there can be
+     a lot more TUs than unique line tables, so we maintain a separate table
+     of all line table entries to support the sharing.  */
+  htab_t quick_file_names_table;
+
   /* Set during partial symbol reading, to prevent queueing of full
      symbols.  */
   int reading_partial_symbols;
@@ -391,32 +397,6 @@ struct dwarf2_cu
   unsigned int has_namespace_info : 1;
 };
 
-/* When using the index (and thus not using psymtabs), each CU has an
-   object of this type.  This is used to hold information needed by
-   the various "quick" methods.  */
-struct dwarf2_per_cu_quick_data
-{
-  /* The line table.  This can be NULL if there was no line table.  */
-  struct line_header *lines;
-
-  /* The file names from the line table.  */
-  const char **file_names;
-  /* The file names from the line table after being run through
-     gdb_realpath.  */
-  const char **full_names;
-
-  /* The corresponding symbol table.  This is NULL if symbols for this
-     CU have not yet been read.  */
-  struct symtab *symtab;
-
-  /* A temporary mark bit used when iterating over all CUs in
-     expand_symtabs_matching.  */
-  unsigned int mark : 1;
-
-  /* True if we've tried to read the line table.  */
-  unsigned int read_lines : 1;
-};
-
 /* Persistent data held for a compilation unit, even when not
    processing it.  We put a pointer to this structure in the
    read_symtab_private field of the psymtab.  If we encounter
@@ -1644,6 +1624,102 @@ dwarf2_get_section_info (struct objfile 
 }
 
 
+/* DWARF quick_symbols_functions support.  */
+
+/* TUs can share .debug_line entries, and there can be a lot more TUs than
+   unique line tables, so we maintain a separate table of all .debug_line
+   derived entries to support the sharing.
+   All the quick functions need is the list of file names.  We discard the
+   line_header when we're done and don't need to record it here.  */
+struct quick_file_names
+{
+  /* The offset in .debug_line of the line table.  We hash on this.  */
+  unsigned int offset;
+
+  /* The number of entries in file_names, real_names.  */
+  unsigned int num_file_names;
+
+  /* The file names from the line table, after being run through
+     file_full_name.  */
+  const char **file_names;
+
+  /* The file names from the line table after being run through
+     gdb_realpath.  These are computed lazily.  */
+  const char **real_names;
+};
+
+/* When using the index (and thus not using psymtabs), each CU has an
+   object of this type.  This is used to hold information needed by
+   the various "quick" methods.  */
+struct dwarf2_per_cu_quick_data
+{
+  /* The file table.  This can be NULL if there was no file table
+     or it's currently not read in.
+     NOTE: This points into dwarf2_per_objfile->quick_file_names_table.  */
+  struct quick_file_names *file_names;
+
+  /* The corresponding symbol table.  This is NULL if symbols for this
+     CU have not yet been read.  */
+  struct symtab *symtab;
+
+  /* A temporary mark bit used when iterating over all CUs in
+     expand_symtabs_matching.  */
+  unsigned int mark : 1;
+
+  /* True if we've tried to read the file table and found there isn't one.
+     There will be no point in trying to read it again next time.  */
+  unsigned int no_file_data : 1;
+};
+
+/* Hash function for a quick_file_names.  */
+
+static hashval_t
+hash_file_name_entry (const void *e)
+{
+  const struct quick_file_names *file_data = e;
+
+  return file_data->offset;
+}
+
+/* Equality function for a quick_file_names.  */
+
+static int
+eq_file_name_entry (const void *a, const void *b)
+{
+  const struct quick_file_names *ea = a;
+  const struct quick_file_names *eb = b;
+
+  return ea->offset == eb->offset;
+}
+
+/* Delete function for a quick_file_names.  */
+
+static void
+delete_file_name_entry (void *e)
+{
+  struct quick_file_names *file_data = e;
+  int i;
+
+  for (i = 0; i < file_data->num_file_names; ++i)
+    {
+      xfree ((void*) file_data->file_names[i]);
+      if (file_data->real_names)
+	xfree ((void*) file_data->real_names[i]);
+    }
+
+  /* The space for the struct itself lives on objfile_obstack,
+     so we don't free it here.  */
+}
+
+/* Create a quick_file_names hash table.  */
+
+static htab_t
+create_quick_file_names_table (unsigned int nr_initial_entries)
+{
+  return htab_create_alloc (nr_initial_entries,
+			    hash_file_name_entry, eq_file_name_entry,
+			    delete_file_name_entry, xcalloc, xfree);
+}
 
 /* Read in the symbols for PER_CU.  OBJFILE is the objfile from which
    this CU came.  */
@@ -1993,6 +2069,8 @@ dwarf2_read_index (struct objfile *objfi
 
   dwarf2_per_objfile->index_table = map;
   dwarf2_per_objfile->using_index = 1;
+  dwarf2_per_objfile->quick_file_names_table =
+    create_quick_file_names_table (dwarf2_per_objfile->n_comp_units);
 
   return 1;
 }
@@ -2010,12 +2088,12 @@ dw2_setup (struct objfile *objfile)
 /* A helper for the "quick" functions which attempts to read the line
    table for THIS_CU.  */
 
-static void
-dw2_require_line_header (struct objfile *objfile,
-			 struct dwarf2_per_cu_data *this_cu)
+static struct quick_file_names *
+dw2_get_file_names (struct objfile *objfile,
+		    struct dwarf2_per_cu_data *this_cu)
 {
   bfd *abfd = objfile->obfd;
-  struct line_header *lh = NULL;
+  struct line_header *lh;
   struct attribute *attr;
   struct cleanup *cleanups;
   struct die_info *comp_unit_die;
@@ -2026,10 +2104,15 @@ dw2_require_line_header (struct objfile 
   unsigned int bytes_read, buffer_size;
   struct die_reader_specs reader_specs;
   char *name, *comp_dir;
+  void **slot;
+  struct quick_file_names *qfn;
+  unsigned int line_offset;
 
-  if (this_cu->v.quick->read_lines)
-    return;
-  this_cu->v.quick->read_lines = 1;
+  if (this_cu->v.quick->file_names != NULL)
+    return this_cu->v.quick->file_names;
+  /* If we know there is no line data, no point in looking again.  */
+  if (this_cu->v.quick->no_file_data)
+    return NULL;
 
   init_one_comp_unit (&cu, objfile);
   cleanups = make_cleanup (free_stack_comp_unit, &cu);
@@ -2064,52 +2147,73 @@ dw2_require_line_header (struct objfile 
   info_ptr = read_full_die (&reader_specs, &comp_unit_die, info_ptr,
 			    &has_children);
 
+  lh = NULL;
+  slot = NULL;
+  line_offset = 0;
   attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, &cu);
   if (attr)
     {
-      unsigned int line_offset = DW_UNSND (attr);
+      struct quick_file_names find_entry;
+
+      line_offset = DW_UNSND (attr);
+
+      /* We may have already read in this line header (TU line header sharing).
+	 If we have we're done.  */
+      find_entry.offset = line_offset;
+      slot = htab_find_slot (dwarf2_per_objfile->quick_file_names_table,
+			     &find_entry, INSERT);
+      if (*slot != NULL)
+	{
+	  do_cleanups (cleanups);
+	  this_cu->v.quick->file_names = *slot;
+	  return *slot;
+	}
+
       lh = dwarf_decode_line_header (line_offset, abfd, &cu);
     }
   if (lh == NULL)
     {
       do_cleanups (cleanups);
-      return;
+      this_cu->v.quick->no_file_data = 1;
+      return NULL;
     }
 
-  find_file_and_directory (comp_unit_die, &cu, &name, &comp_dir);
+  qfn = obstack_alloc (&objfile->objfile_obstack, sizeof (*qfn));
+  qfn->offset = line_offset;
+  gdb_assert (slot != NULL);
+  *slot = qfn;
 
-  this_cu->v.quick->lines = lh;
+  find_file_and_directory (comp_unit_die, &cu, &name, &comp_dir);
 
-  this_cu->v.quick->file_names
-    = obstack_alloc (&objfile->objfile_obstack,
-		     lh->num_file_names * sizeof (char *));
+  qfn->num_file_names = lh->num_file_names;
+  qfn->file_names = obstack_alloc (&objfile->objfile_obstack,
+				   lh->num_file_names * sizeof (char *));
   for (i = 0; i < lh->num_file_names; ++i)
-    this_cu->v.quick->file_names[i] = file_full_name (i + 1, lh, comp_dir);
+    qfn->file_names[i] = file_full_name (i + 1, lh, comp_dir);
+  qfn->real_names = NULL;
 
+  free_line_header (lh);
   do_cleanups (cleanups);
+
+  this_cu->v.quick->file_names = qfn;
+  return qfn;
 }
 
 /* A helper for the "quick" functions which computes and caches the
-   real path for a given file name from the line table.
-   dw2_require_line_header must have been called before this is
-   invoked.  */
+   real path for a given file name from the line table.  */
 
 static const char *
-dw2_require_full_path (struct objfile *objfile,
-		       struct dwarf2_per_cu_data *per_cu,
-		       int index)
-{
-  if (!per_cu->v.quick->full_names)
-    per_cu->v.quick->full_names
-      = OBSTACK_CALLOC (&objfile->objfile_obstack,
-			per_cu->v.quick->lines->num_file_names,
-			sizeof (char *));
-
-  if (!per_cu->v.quick->full_names[index])
-    per_cu->v.quick->full_names[index]
-      = gdb_realpath (per_cu->v.quick->file_names[index]);
+dw2_get_real_path (struct objfile *objfile,
+		   struct quick_file_names *qfn, int index)
+{
+  if (qfn->real_names == NULL)
+    qfn->real_names = OBSTACK_CALLOC (&objfile->objfile_obstack,
+				      qfn->num_file_names, sizeof (char *));
+
+  if (qfn->real_names[index] == NULL)
+    qfn->real_names[index] = gdb_realpath (qfn->file_names[index]);
 
-  return per_cu->v.quick->full_names[index];
+  return qfn->real_names[index];
 }
 
 static struct symtab *
@@ -2122,28 +2226,34 @@ dw2_find_last_source_symtab (struct objf
   return dw2_instantiate_symtab (objfile, dw2_get_cu (index));
 }
 
-static void
-dw2_forget_cached_source_info (struct objfile *objfile)
+/* Traversal function for dw2_forget_cached_source_info.  */
+
+static int
+dw2_free_cached_file_names (void **slot, void *info)
 {
-  int i;
+  struct quick_file_names *file_data = (struct quick_file_names *) *slot;
 
-  dw2_setup (objfile);
-  for (i = 0; i < (dwarf2_per_objfile->n_comp_units
-		   + dwarf2_per_objfile->n_type_comp_units); ++i)
+  if (file_data->real_names)
     {
-      struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      int i;
 
-      if (per_cu->v.quick->full_names)
+      for (i = 0; i < file_data->num_file_names; ++i)
 	{
-	  int j;
-
-	  for (j = 0; j < per_cu->v.quick->lines->num_file_names; ++j)
-	    {
-	      xfree ((void *) per_cu->v.quick->full_names[j]);
-	      per_cu->v.quick->full_names[j] = NULL;
-	    }
+	  xfree ((void*) file_data->real_names[i]);
+	  file_data->real_names[i] = NULL;
 	}
     }
+
+  return 1;
+}
+
+static void
+dw2_forget_cached_source_info (struct objfile *objfile)
+{
+  dw2_setup (objfile);
+
+  htab_traverse_noresize (dwarf2_per_objfile->quick_file_names_table,
+			  dw2_free_cached_file_names, NULL);
 }
 
 static int
@@ -2162,17 +2272,18 @@ dw2_lookup_symtab (struct objfile *objfi
     {
       int j;
       struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      struct quick_file_names *file_data;
 
       if (per_cu->v.quick->symtab)
 	continue;
 
-      dw2_require_line_header (objfile, per_cu);
-      if (!per_cu->v.quick->lines)
+      file_data = dw2_get_file_names (objfile, per_cu);
+      if (file_data == NULL)
 	continue;
 
-      for (j = 0; j < per_cu->v.quick->lines->num_file_names; ++j)
+      for (j = 0; j < file_data->num_file_names; ++j)
 	{
-	  const char *this_name = per_cu->v.quick->file_names[j];
+	  const char *this_name = file_data->file_names[j];
 
 	  if (FILENAME_CMP (name, this_name) == 0)
 	    {
@@ -2186,11 +2297,11 @@ dw2_lookup_symtab (struct objfile *objfi
 
 	  if (full_path != NULL)
 	    {
-	      const char *this_full_name = dw2_require_full_path (objfile,
-								  per_cu, j);
+	      const char *this_real_name = dw2_get_real_path (objfile,
+							      file_data, j);
 
-	      if (this_full_name
-		  && FILENAME_CMP (full_path, this_full_name) == 0)
+	      if (this_real_name != NULL
+		  && FILENAME_CMP (full_path, this_real_name) == 0)
 		{
 		  *result = dw2_instantiate_symtab (objfile, per_cu);
 		  return 1;
@@ -2199,11 +2310,11 @@ dw2_lookup_symtab (struct objfile *objfi
 
 	  if (real_path != NULL)
 	    {
-	      const char *this_full_name = dw2_require_full_path (objfile,
-								  per_cu, j);
+	      const char *this_real_name = dw2_get_real_path (objfile,
+							      file_data, j);
 
-	      if (this_full_name != NULL
-		  && FILENAME_CMP (real_path, this_full_name) == 0)
+	      if (this_real_name != NULL
+		  && FILENAME_CMP (real_path, this_real_name) == 0)
 		{
 		  *result = dw2_instantiate_symtab (objfile, per_cu);
 		  return 1;
@@ -2337,17 +2448,18 @@ dw2_expand_symtabs_with_filename (struct
     {
       int j;
       struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      struct quick_file_names *file_data;
 
       if (per_cu->v.quick->symtab)
 	continue;
 
-      dw2_require_line_header (objfile, per_cu);
-      if (!per_cu->v.quick->lines)
+      file_data = dw2_get_file_names (objfile, per_cu);
+      if (file_data == NULL)
 	continue;
 
-      for (j = 0; j < per_cu->v.quick->lines->num_file_names; ++j)
+      for (j = 0; j < file_data->num_file_names; ++j)
 	{
-	  const char *this_name = per_cu->v.quick->file_names[j];
+	  const char *this_name = file_data->file_names[j];
 	  if (FILENAME_CMP (this_name, filename) == 0)
 	    {
 	      dw2_instantiate_symtab (objfile, per_cu);
@@ -2362,6 +2474,7 @@ dw2_find_symbol_file (struct objfile *ob
 {
   struct dwarf2_per_cu_data *per_cu;
   offset_type *vec;
+  struct quick_file_names *file_data;
 
   dw2_setup (objfile);
 
@@ -2380,11 +2493,11 @@ dw2_find_symbol_file (struct objfile *ob
   /* vec[0] is the length, which must always be >0.  */
   per_cu = dw2_get_cu (MAYBE_SWAP (vec[1]));
 
-  dw2_require_line_header (objfile, per_cu);
-  if (!per_cu->v.quick->lines)
+  file_data = dw2_get_file_names (objfile, per_cu);
+  if (file_data == NULL)
     return NULL;
 
-  return per_cu->v.quick->file_names[per_cu->v.quick->lines->num_file_names - 1];
+  return file_data->file_names[file_data->num_file_names - 1];
 }
 
 static void
@@ -2423,18 +2536,19 @@ dw2_expand_symtabs_matching (struct objf
     {
       int j;
       struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      struct quick_file_names *file_data;
 
       per_cu->v.quick->mark = 0;
       if (per_cu->v.quick->symtab)
 	continue;
 
-      dw2_require_line_header (objfile, per_cu);
-      if (!per_cu->v.quick->lines)
+      file_data = dw2_get_file_names (objfile, per_cu);
+      if (file_data == NULL)
 	continue;
 
-      for (j = 0; j < per_cu->v.quick->lines->num_file_names; ++j)
+      for (j = 0; j < file_data->num_file_names; ++j)
 	{
-	  if (file_matcher (per_cu->v.quick->file_names[j], data))
+	  if (file_matcher (file_data->file_names[j], data))
 	    {
 	      per_cu->v.quick->mark = 1;
 	      break;
@@ -2541,19 +2655,20 @@ dw2_map_symbol_filenames (struct objfile
     {
       int j;
       struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      struct quick_file_names *file_data;
 
       if (per_cu->v.quick->symtab)
 	continue;
 
-      dw2_require_line_header (objfile, per_cu);
-      if (!per_cu->v.quick->lines)
+      file_data = dw2_get_file_names (objfile, per_cu);
+      if (file_data == NULL)
 	continue;
 
-      for (j = 0; j < per_cu->v.quick->lines->num_file_names; ++j)
+      for (j = 0; j < file_data->num_file_names; ++j)
 	{
-	  const char *this_full_name = dw2_require_full_path (objfile, per_cu,
-							      j);
-	  (*fun) (per_cu->v.quick->file_names[j], this_full_name, data);
+	  const char *this_real_name = dw2_get_real_path (objfile, file_data,
+							  j);
+	  (*fun) (file_data->file_names[j], this_real_name, data);
 	}
     }
 }
@@ -2603,6 +2718,8 @@ dwarf2_initialize_objfile (struct objfil
       dwarf2_per_objfile->using_index = 1;
       create_all_comp_units (objfile);
       create_debug_types_hash_table (objfile);
+      dwarf2_per_objfile->quick_file_names_table =
+	create_quick_file_names_table (dwarf2_per_objfile->n_comp_units);
 
       for (i = 0; i < (dwarf2_per_objfile->n_comp_units
 		       + dwarf2_per_objfile->n_type_comp_units); ++i)
@@ -14536,30 +14653,8 @@ dwarf2_free_objfile (struct objfile *obj
   /* Cached DIE trees use xmalloc and the comp_unit_obstack.  */
   free_cached_comp_units (NULL);
 
-  if (dwarf2_per_objfile->using_index)
-    {
-      int i;
-
-      for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
-	{
-	  int j;
-	  struct dwarf2_per_cu_data *per_cu =
-	    dwarf2_per_objfile->all_comp_units[i];
-
-	  if (!per_cu->v.quick->lines)
-	    continue;
-
-	  for (j = 0; j < per_cu->v.quick->lines->num_file_names; ++j)
-	    {
-	      if (per_cu->v.quick->file_names)
-		xfree ((void *) per_cu->v.quick->file_names[j]);
-	      if (per_cu->v.quick->full_names)
-		xfree ((void *) per_cu->v.quick->full_names[j]);
-	    }
-
-	  free_line_header (per_cu->v.quick->lines);
-	}
-    }
+  if (dwarf2_per_objfile->quick_file_names_table)
+    htab_delete (dwarf2_per_objfile->quick_file_names_table);
 
   /* Everything else should be on the objfile obstack.  */
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]