From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 9352 invoked by alias); 9 Sep 2011 12:32:22 -0000 Received: (qmail 9343 invoked by uid 22791); 9 Sep 2011 12:32:20 -0000 X-SWARE-Spam-Status: No, hits=2.5 required=5.0 tests=AWL,BAYES_00,KAM_STOCKTIP,SARE_SUB_IMPROVE,SPF_FAIL,TO_NO_BRKTS_DIRECT,TW_YM X-Spam-Check-By: sourceware.org Received: from gbenson.demon.co.uk (HELO gbenson.demon.co.uk) (80.177.220.214) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 09 Sep 2011 12:32:00 +0000 Date: Fri, 09 Sep 2011 14:25:00 -0000 From: Gary Benson To: gdb-patches@sourceware.org Subject: [RFA] Improve performance with lots of shared libraries Message-ID: <20110909123156.GA1503@redhat.com> Mail-Followup-To: gdb-patches@sourceware.org MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="+HP7ph2BbKc20aGI" Content-Disposition: inline X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-09/txt/msg00157.txt.bz2 --+HP7ph2BbKc20aGI Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 1544 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/ --+HP7ph2BbKc20aGI Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="solib-break-disabler-1.patch" Content-length: 8490 2011-09-09 Gary Benson * 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 . */ + +#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 . */ + +#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 */ --+HP7ph2BbKc20aGI--