Demangle minsyms in parallel
authorTom Tromey <tom@tromey.com>
Sun, 3 Mar 2019 17:15:30 +0000 (10:15 -0700)
committerTom Tromey <tom@tromey.com>
Tue, 26 Nov 2019 21:02:58 +0000 (14:02 -0700)
This patch introduces a simple parallel for_each and changes the
minimal symbol reader to use it when computing the demangled name for
a minimal symbol.  This yields a speedup when reading minimal symbols.

2019-11-26  Christian Biesinger  <cbiesinger@google.com>
    Tom Tromey  <tom@tromey.com>

* minsyms.c (minimal_symbol_reader::install): Use
parallel_for_each.
* gdbsupport/parallel-for.h: New file.
* Makefile.in (HFILES_NO_SRCDIR): Add gdbsupport/parallel-for.h.

Change-Id: I220341f70e94dd02df5dd424272c50a5afb64978

gdb/ChangeLog
gdb/Makefile.in
gdb/gdbsupport/parallel-for.h [new file with mode: 0644]
gdb/minsyms.c
gdb/symtab.c
gdb/symtab.h

index 7c4e2b845827547c0e56d9cafa5e2c765660203e..b73ae8dd813ff08f1814c4095a4f9a4933626fc1 100644 (file)
@@ -1,3 +1,11 @@
+2019-11-26  Christian Biesinger  <cbiesinger@google.com>
+           Tom Tromey  <tom@tromey.com>
+
+       * minsyms.c (minimal_symbol_reader::install): Use
+       parallel_for_each.
+       * gdbsupport/parallel-for.h: New file.
+       * Makefile.in (HFILES_NO_SRCDIR): Add gdbsupport/parallel-for.h.
+
 2019-11-26  Christian Biesinger  <cbiesinger@google.com>
            Tom Tromey  <tom@tromey.com>
 
index b07b11ec56941cc05a274d63f4a9d0da5adc5aca..58f5f93c54f015382f7d1fdc0e10a6dd58a3aa3a 100644 (file)
@@ -1491,6 +1491,7 @@ HFILES_NO_SRCDIR = \
        gdbsupport/common-inferior.h \
        gdbsupport/netstuff.h \
        gdbsupport/host-defs.h \
+       gdbsupport/parallel-for.h \
        gdbsupport/pathstuff.h \
        gdbsupport/print-utils.h \
        gdbsupport/ptid.h \
diff --git a/gdb/gdbsupport/parallel-for.h b/gdb/gdbsupport/parallel-for.h
new file mode 100644 (file)
index 0000000..70fdacd
--- /dev/null
@@ -0,0 +1,86 @@
+/* Parallel for loops
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDBSUPPORT_PARALLEL_FOR_H
+#define GDBSUPPORT_PARALLEL_FOR_H
+
+#include <algorithm>
+#if CXX_STD_THREAD
+#include <thread>
+#include "gdbsupport/thread-pool.h"
+#endif
+
+namespace gdb
+{
+
+/* A very simple "parallel for".  This splits the range of iterators
+   into subranges, and then passes each subrange to the callback.  The
+   work may or may not be done in separate threads.
+
+   This approach was chosen over having the callback work on single
+   items because it makes it simple for the caller to do
+   once-per-subrange initialization and destruction.  */
+
+template<class RandomIt, class RangeFunction>
+void
+parallel_for_each (RandomIt first, RandomIt last, RangeFunction callback)
+{
+#if CXX_STD_THREAD
+  /* So we can use a local array below.  */
+  const size_t local_max = 16;
+  size_t n_threads = std::min (thread_pool::g_thread_pool->thread_count (),
+                              local_max);
+  size_t n_actual_threads = 0;
+  std::future<void> futures[local_max];
+
+  size_t n_elements = last - first;
+  if (n_threads > 1)
+    {
+      /* Arbitrarily require that there should be at least 10 elements
+        in a thread.  */
+      if (n_elements / n_threads < 10)
+       n_threads = std::max (n_elements / 10, (size_t) 1);
+      size_t elts_per_thread = n_elements / n_threads;
+      n_actual_threads = n_threads - 1;
+      for (int i = 0; i < n_actual_threads; ++i)
+       {
+         RandomIt end = first + elts_per_thread;
+         auto task = [=] ()
+                     {
+                       callback (first, end);
+                     };
+
+         futures[i] = gdb::thread_pool::g_thread_pool->post_task (task);
+         first = end;
+       }
+    }
+#endif /* CXX_STD_THREAD */
+
+  /* Process all the remaining elements in the main thread.  */
+  callback (first, last);
+
+#if CXX_STD_THREAD
+  for (int i = 0; i < n_actual_threads; ++i)
+    futures[i].wait ();
+#endif /* CXX_STD_THREAD */
+}
+
+}
+
+#endif /* GDBSUPPORT_PARALLEL_FOR_H */
index 6e7021a6809ed8710ce5a4417654d15313a910ab..03a193270e5acb1521728fc8be82f8ddc59a2d57 100644 (file)
 #include "gdbsupport/symbol.h"
 #include <algorithm>
 #include "safe-ctype.h"
+#include "gdbsupport/parallel-for.h"
+
+#if CXX_STD_THREAD
+#include <mutex>
+#endif
 
 /* See minsyms.h.  */
 
@@ -1359,16 +1364,43 @@ minimal_symbol_reader::install ()
       m_objfile->per_bfd->minimal_symbol_count = mcount;
       m_objfile->per_bfd->msymbols = std::move (msym_holder);
 
+#if CXX_STD_THREAD
+      /* Mutex that is used when modifying or accessing the demangled
+        hash table.  */
+      std::mutex demangled_mutex;
+#endif
+
       msymbols = m_objfile->per_bfd->msymbols.get ();
-      for (int i = 0; i < mcount; ++i)
-       {
-         if (!msymbols[i].name_set)
-           {
-             symbol_set_names (&msymbols[i], msymbols[i].name,
-                               false, m_objfile->per_bfd);
-             msymbols[i].name_set = 1;
-           }
-       }
+      gdb::parallel_for_each
+       (&msymbols[0], &msymbols[mcount],
+        [&] (minimal_symbol *start, minimal_symbol *end)
+        {
+          for (minimal_symbol *msym = start; msym < end; ++msym)
+            {
+              if (!msym->name_set)
+                {
+                  /* This will be freed later, by symbol_set_names.  */
+                  char *demangled_name
+                    = symbol_find_demangled_name (msym, msym->name);
+                  symbol_set_demangled_name
+                    (msym, demangled_name,
+                     &m_objfile->per_bfd->storage_obstack);
+                  msym->name_set = 1;
+                }
+            }
+          {
+            /* To limit how long we hold the lock, we only acquire it here
+               and not while we demangle the names above.  */
+#if CXX_STD_THREAD
+            std::lock_guard<std::mutex> guard (demangled_mutex);
+#endif
+            for (minimal_symbol *msym = start; msym < end; ++msym)
+              {
+                symbol_set_names (msym, msym->name, false,
+                                  m_objfile->per_bfd);
+              }
+          }
+        });
 
       build_minimal_symbol_hash_tables (m_objfile);
     }
index 711f8ef196a784e2a0ba84c7210f9a6b8b560310..b5c8109fde327d698a3180b2f8e5cddf38989f79 100644 (file)
@@ -787,13 +787,9 @@ create_demangled_names_hash (struct objfile_per_bfd_storage *per_bfd)
      free_demangled_name_entry, xcalloc, xfree));
 }
 
-/* Try to determine the demangled name for a symbol, based on the
-   language of that symbol.  If the language is set to language_auto,
-   it will attempt to find any demangling algorithm that works and
-   then set the language appropriately.  The returned name is allocated
-   by the demangler and should be xfree'd.  */
+/* See symtab.h  */
 
-static char *
+char *
 symbol_find_demangled_name (struct general_symbol_info *gsymbol,
                            const char *mangled)
 {
@@ -894,8 +890,15 @@ symbol_set_names (struct general_symbol_info *gsymbol,
       else
        linkage_name_copy = linkage_name;
 
-      gdb::unique_xmalloc_ptr<char> demangled_name_ptr
-       (symbol_find_demangled_name (gsymbol, linkage_name_copy.data ()));
+      /* The const_cast is safe because the only reason it is already
+         initialized is if we purposefully set it from a background
+         thread to avoid doing the work here.  However, it is still
+         allocated from the heap and needs to be freed by us, just
+         like if we called symbol_find_demangled_name here.  */
+      gdb::unique_xmalloc_ptr<char> demangled_name
+       (gsymbol->language_specific.demangled_name
+        ? const_cast<char *> (gsymbol->language_specific.demangled_name)
+        : symbol_find_demangled_name (gsymbol, linkage_name_copy.data ()));
 
       /* Suppose we have demangled_name==NULL, copy_name==0, and
         linkage_name_copy==linkage_name.  In this case, we already have the
@@ -929,7 +932,7 @@ symbol_set_names (struct general_symbol_info *gsymbol,
          new (*slot) demangled_name_entry
            (gdb::string_view (mangled_ptr, linkage_name.length ()));
        }
-      (*slot)->demangled = std::move (demangled_name_ptr);
+      (*slot)->demangled = std::move (demangled_name);
       (*slot)->language = gsymbol->language;
     }
   else if (gsymbol->language == language_unknown
index bcbc9c825e6f6e10a5c41acf9705a5428b64846f..9c2aea7cf74a9ab668dc7f4bdd8e4f17f6a50d1f 100644 (file)
@@ -528,6 +528,16 @@ extern void symbol_set_language (struct general_symbol_info *symbol,
                                  enum language language,
                                 struct obstack *obstack);
 
+
+/* Try to determine the demangled name for a symbol, based on the
+   language of that symbol.  If the language is set to language_auto,
+   it will attempt to find any demangling algorithm that works and
+   then set the language appropriately.  The returned name is allocated
+   by the demangler and should be xfree'd.  */
+
+extern char *symbol_find_demangled_name (struct general_symbol_info *gsymbol,
+                                        const char *mangled);
+
 /* Set just the linkage name of a symbol; do not try to demangle
    it.  Used for constructs which do not have a mangled name,
    e.g. struct tags.  Unlike SYMBOL_SET_NAMES, linkage_name must
This page took 0.034265 seconds and 4 git commands to generate.