Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Gary Benson <gbenson@redhat.com>
To: gdb-patches@sourceware.org
Subject: [RFA] Improve performance with lots of shared libraries
Date: Fri, 09 Sep 2011 14:25:00 -0000	[thread overview]
Message-ID: <20110909123156.GA1503@redhat.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1544 bytes --]

Hi all,

When inferiors load a lot of shared libraries gdb spends a lot of
time processing shared library breakpoint events.  These have a lot
of associated bookkeeping that is not easily avoided.

This patch modifies gdb to disable the shared library breakpoint
when it is not required, specifically:

 * when stop-on-solib-events is off,
 * when there are no pending breakpoints,
 * and when libthread_db is loaded

I have a simple test which dlopens 1000 shared libraries.  On my
machine it runs instantly outside of gdb, but takes roughly a minute
when run within gdb.  With this patch, it runs instantly in gdb too.

The idea for this was not mine, it was Jan Kratochvil's, and he
very definitely deserves the credit for it.  I wrote the code though,
so the bugs are all my fault :)

There are two things I'm not sure about with it as it stands.  One is
to do with program spaces: I noticed that breakpoints have a program
space, but breakpoint locations also have a program space.  Is the way
I have used these correct?

The other issue I have is the way it detects whether libthread_db is
loaded.  This should work fine on platforms that use a libthread_db,
but some platforms will have this optimization disabled.  Nothing will
get worse, but some platforms will not get better when they could.
Have I gone about this the wrong way?

I would definitely appreciate feedback from those of you who are using
gdb on applications with many shared libraries, to know if you are
getting any improvement.

Cheers,
Gary

-- 
http://gbenson.net/

[-- Attachment #2: solib-break-disabler-1.patch --]
[-- Type: text/plain, Size: 8490 bytes --]

2011-09-09  Gary Benson  <gbenson@redhat.com>

	* Makefile.in (SFILES): Add solib-bp-disable.c.
	(HFILES_NO_SRCDIR): Add solib-bp-disable.h.
	(COMMON_OBS): Add solib-bp-disable.o.
	* infrun.c: Include solib-bp-disable.h.
	(set_stop_on_solib_events): New function.
	(_initialize_infrun): Add set_stop_on_solib_events.
	* solib-bp-disable.c: New file.
	* solib-bp-disable.h: Likewise.

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 826d339..9e947d4 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -720,7 +720,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	regcache.c reggroups.c remote.c remote-fileio.c reverse.c \
 	sentinel-frame.c \
 	serial.c ser-base.c ser-unix.c \
-	solib.c solib-target.c source.c \
+	solib.c solib-bp-disable.c solib-target.c source.c \
 	stabsread.c stack.c std-regs.c symfile.c symfile-mem.c symmisc.c \
 	symtab.c \
 	target.c target-descriptions.c target-memory.c \
@@ -821,7 +821,7 @@ solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
 gnulib/stddef.in.h inline-frame.h \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
-common/linux-osdata.h
+common/linux-osdata.h solib-bp-disable.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -902,7 +902,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	reggroups.o regset.o \
 	trad-frame.o \
 	tramp-frame.o \
-	solib.o solib-target.o \
+	solib.o solib-bp-disable.o solib-target.o \
 	prologue-value.o memory-map.o memrange.o \
 	xml-support.o xml-syscall.o xml-utils.o \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2b4f6db..fd57f49 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -56,6 +56,7 @@
 #include "tracepoint.h"
 #include "continuations.h"
 #include "interps.h"
+#include "solib-bp-disable.h"
 
 /* Prototypes for local functions */
 
@@ -320,6 +321,13 @@ static struct symbol *step_start_function;
 /* Nonzero if we want to give control to the user when we're notified
    of shared library events by the dynamic linker.  */
 int stop_on_solib_events;
+
+static void
+set_stop_on_solib_events (char *args, int from_tty, struct cmd_list_element *c)
+{
+  update_solib_breakpoints ();
+} 
+
 static void
 show_stop_on_solib_events (struct ui_file *file, int from_tty,
 			   struct cmd_list_element *c, const char *value)
@@ -7096,7 +7104,7 @@ Show stopping for shared library events."), _("\
 If nonzero, gdb will give control to the user when the dynamic linker\n\
 notifies gdb of shared library events.  The most common event of interest\n\
 to the user would be loading/unloading of a new library."),
-			    NULL,
+			    set_stop_on_solib_events,
 			    show_stop_on_solib_events,
 			    &setlist, &showlist);
 
diff --git a/gdb/solib-bp-disable.c b/gdb/solib-bp-disable.c
new file mode 100644
index 0000000..c243a73
--- /dev/null
+++ b/gdb/solib-bp-disable.c
@@ -0,0 +1,153 @@
+/* Disable the shared library event breakpoint when unnecessary.
+
+   Copyright (C) 2011 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/>.  */
+
+#include "defs.h"
+
+#include "breakpoint.h"
+#include "inferior.h"
+#include "observer.h"
+#include "solib-bp-disable.h"
+#include "solist.h"
+#include "target.h"
+
+/* Nonzero if multi-threaded inferior support is present.  */
+
+static int
+multi_thread_support_availabie (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_find_new_threads != NULL)
+      return 1;
+
+  return 0;
+}
+
+/* Nonzero if this breakpoint is pending in the current program space.  */
+
+static int
+breakpoint_is_pending (struct breakpoint *b, void *arg)
+{
+  struct bp_location *loc;
+
+  if (b->pspace != current_program_space)
+    return 0;
+
+  if (b->loc == NULL)
+    return 1;
+
+  for (loc = b->loc; loc; loc = loc->next)
+    if (loc->shlib_disabled && loc->pspace == current_program_space)
+      return 1;
+
+  return 0;
+}
+
+/* Nonzero if pending breakpoints exist in the current program space.  */
+
+static int
+pending_breakpoints_exist (void)
+{
+  return iterate_over_breakpoints (breakpoint_is_pending, NULL) != NULL;
+}
+
+/* Enable or disable a single solib event breakpoint as appropriate.  */
+
+static int
+update_solib_breakpoint (struct breakpoint *b, void *arg)
+{
+  int enable = *(int *) arg;
+  struct bp_location *loc;
+
+  if (b->pspace != current_program_space)
+    return 0;
+
+  if (b->type != bp_shlib_event)
+    return 0;
+  
+  for (loc = b->loc; loc; loc = loc->next)
+    if (loc->pspace == current_program_space)
+      {
+	if (enable && b->enable_state == bp_disabled)
+	  b->enable_state = bp_enabled;
+	else if (!enable && b->enable_state == bp_enabled)
+	  b->enable_state = bp_disabled;
+      }
+
+  return 0;
+}
+
+/* Enable or disable solib event breakpoints as appropriate.  */
+
+void
+update_solib_breakpoints ()
+{
+  int enable = stop_on_solib_events
+    || !multi_thread_support_availabie ()
+    || pending_breakpoints_exist ();
+
+  iterate_over_breakpoints (update_solib_breakpoint, &enable);
+}
+
+/* Wrappers to match the observer function pointer prototypes.  */
+
+static void
+breakpoint_event (struct breakpoint *b)
+{
+  update_solib_breakpoints ();
+}
+
+static void
+inferior_event (struct target_ops *ops, int from_tty)
+{
+  update_solib_breakpoints ();
+}
+
+static void
+solib_event (struct so_list *s)
+{
+  update_solib_breakpoints ();
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_solib_bp_disable;
+
+void
+_initialize_solib_bp_disable (void)
+{
+  /* Observe breakpoint operations so we can enable the shared
+     library event breakpoint if there are breakpoints pending
+     on shared library loads.  */
+  observer_attach_breakpoint_created (breakpoint_event);
+  observer_attach_breakpoint_modified (breakpoint_event);
+  observer_attach_breakpoint_deleted (breakpoint_event);
+
+  /* We also need to watch for inferior creation, because the
+     creation of the shared library event breakpoint does not
+     cause a breakpoint_created notification so inferior_created
+     is the next best thing.  */
+  observer_attach_inferior_created (inferior_event);
+
+  /* Observe shared libraries being loaded and unloaded so we
+     can disable the shared library event breakpoint once a
+     thread debugging library has been loaded.  */
+  observer_attach_solib_loaded (solib_event);
+  observer_attach_solib_unloaded (solib_event);
+}
diff --git a/gdb/solib-bp-disable.h b/gdb/solib-bp-disable.h
new file mode 100644
index 0000000..da883ab
--- /dev/null
+++ b/gdb/solib-bp-disable.h
@@ -0,0 +1,27 @@
+/* Disable the shared library event breakpoint when unnecessary.
+
+   Copyright (C) 2011 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 SOLIB_BP_DISABLE_H
+#define SOLIB_BP_DISABLE_H
+
+/* Enable or disable solib event breakpoints as appropriate.  */
+
+extern void update_solib_breakpoints (void);
+
+#endif /* SOLIB_BP_DISABLE_H */

             reply	other threads:[~2011-09-09 12:32 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-09 14:25 Gary Benson [this message]
2011-09-09 14:35 ` Daniel Jacobowitz
2011-09-09 14:51   ` Jan Kratochvil
2011-09-09 15:04     ` Pedro Alves
2011-09-09 19:41       ` Jan Kratochvil
2011-09-12 12:44         ` Pedro Alves
2011-09-12 16:44           ` Jan Kratochvil
2011-09-14  9:28             ` Gary Benson
2011-10-04 19:46               ` Tom Tromey
2011-09-09 15:11     ` Pedro Alves
2011-09-09 14:53 ` Jan Kratochvil
2011-10-04 20:03   ` Tom Tromey
  -- strict thread matches above, loose matches on Subject: below --
2011-09-22 17:35 Gary Benson
2011-07-01 16:51 Gary Benson
2011-07-01 17:19 ` Tom Tromey
2011-07-04 14:10   ` Gary Benson
2011-07-01 17:32 ` Joel Brobecker
2011-07-04 14:21   ` Gary Benson
2011-07-01 17:45 ` Pedro Alves
2011-07-01 17:57   ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20110909123156.GA1503@redhat.com \
    --to=gbenson@redhat.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox