Re: [PATCH 4/4] Test on solib load and unload

Doug Evans
2013-10-25T07:17:33Z

Hi.
A couple of nit, otherwise seems ok to me.

On Wed, Oct 16, 2013 at 12:09 AM, Yao Qi <yao@codesourcery.com> wrote:
> This patch is to add a test case to on the performance of GDB handling
> load and unload of shared library.
>
> In V3, there are some changes,
>
> - Adapt to perf test framework changes.
> - Measure load and unload separately.
>
> In V2, there are some changes,
>
> - A new proc gdb_produce_source to produce source files. I tried to
> move all source file generation code out of solib.exp, but
> compilation step still needs to know the generated file names. I
> have to hard-code the file names in compilation step, which is not
> good to me, so I give up on this moving.
> - SOLIB_NUMBER -> SOLIB_COUNT
> - New variable SOLIB_DLCLOSE_REVERSED_ORDER to control the order of
> iterating a list of shared libs to dlclose them.
> - New variable GDB_PERFORMANCE to enable these perf test cases.
> - Remove dlsym call in solib.c.
> - Update solib.py for the updated framework.
>
> gdb/testsuite/
>
> * lib/gdb.exp (gdb_produce_source): New procedure.
> * gdb.perf/solib.c: New.
> * gdb.perf/solib.exp: New.
> * gdb.perf/solib.py: New.
> ---
> gdb/testsuite/gdb.perf/solib.c | 78 ++++++++++++++++++++++++++++++++++++++
> gdb/testsuite/gdb.perf/solib.exp | 78 ++++++++++++++++++++++++++++++++++++++
> gdb/testsuite/gdb.perf/solib.py | 73 +++++++++++++++++++++++++++++++++++
> gdb/testsuite/lib/gdb.exp | 16 ++++++++
> 4 files changed, 245 insertions(+), 0 deletions(-)
> create mode 100644 gdb/testsuite/gdb.perf/solib.c
> create mode 100644 gdb/testsuite/gdb.perf/solib.exp
> create mode 100644 gdb/testsuite/gdb.perf/solib.py
>
> diff --git a/gdb/testsuite/gdb.perf/solib.c b/gdb/testsuite/gdb.perf/solib.c
> new file mode 100644
> index 0000000..42973d6
> --- /dev/null
> +++ b/gdb/testsuite/gdb.perf/solib.c
> @@ -0,0 +1,78 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright (C) 2013 Free Software Foundation, Inc.
> +
> + 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 <stdio.h>
> +#include <stdlib.h>
> +
> +#ifdef __WIN32__
> +#include <windows.h>
> +#define dlopen(name, mode) LoadLibrary (TEXT (name))
> +# define dlsym(handle, func) GetProcAddress (handle, func)
> +#define dlclose(handle) FreeLibrary (handle)
> +#else
> +#include <dlfcn.h>
> +#endif
> +
> +static void **handles;
> +
> +void
> +do_test_load (int number)
> +{
> + char libname[40];
> + int i;
> +
> + handles = malloc (sizeof (void *) * number);

Check malloc result?

> +
> + for (i = 0; i < number; i++)
> + {
> + sprintf (libname, "solib-lib%d", i);
> + handles[i] = dlopen (libname, RTLD_LAZY);
> + if (handles[i] == NULL)
> + {
> + printf ("ERROR on dlopen %s\n", libname);
> + return;
> + }
> + }
> +}
> +
> +void
> +do_test_unload (int number)
> +{
> + int i;
> +
> + /* Unload shared libraries in different orders. */
> +#ifndef SOLIB_DLCLOSE_REVERSED_ORDER
> + for (i = 0; i < number; i++)
> +#else
> + for (i = number - 1; i >= 0; i--)
> +#endif
> + dlclose (handles[i]);
> +
> + free (handles);
> +}
> +
> +static void
> +end (void)
> +{}
> +
> +int
> +main (void)
> +{
> + end ();
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.perf/solib.exp b/gdb/testsuite/gdb.perf/solib.exp
> new file mode 100644
> index 0000000..fc66f77
> --- /dev/null
> +++ b/gdb/testsuite/gdb.perf/solib.exp
> @@ -0,0 +1,78 @@
> +# Copyright (C) 2013 Free Software Foundation, Inc.
> +
> +# 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/>.
> +
> +# This test case is to test the performance of GDB when it is handling
> +# the shared libraries of inferior are loaded and unloaded.
> +load_lib perftest.exp
> +
> +if [skip_perf_tests] {
> + return 0
> +}
> +
> +standard_testfile .c
> +set executable $testfile
> +set expfile $testfile.exp
> +
> +# make check-perf RUNTESTFLAGS='solib.exp SOLIB_COUNT=1024'
> +if ![info exists SOLIB_COUNT] {
> + set SOLIB_COUNT 128
> +}
> +
> +PerfTest::assemble {
> + compile {
> + for {set i 0} {$i < $SOLIB_COUNT} {incr i} {
> +
> + # Produce source files.
> + set libname "solib-lib$i"
> + set src [standard_output_file $libname.c]
> + set exe [standard_output_file $libname]
> +
> + gdb_produce_source $src { "int shr$i (void) {return 0;}" }
> +
> + # Compile.
> + if { [gdb_compile_shlib $src $exe {debug}] != "" } {
> + untested "Couldn't compile $src."
> + return -1
> + }
> +
> + # Delete object files to save some space.
> + file delete [standard_output_file "solib-lib$i.c.o"]
> + }
> +
> + set compile_flags {debug shlib_load}
> + global SOLIB_DLCLOSE_REVERSED_ORDER

IWBN to have a convention to document all the test parameters in one
place, e.g. at the top of the .exp file or some such.
SOLIB_DLCLOSE_REVERSED_ORDER is kinda buried in the test.

> +
> + if [info exists SOLIB_DLCLOSE_REVERSED_ORDER] {
> + lappend compile_flags "additional_flags=-DSOLIB_DLCLOSE_REVERSED_ORDER"
> + }
> +
> + if { [gdb_compile "$srcdir/$subdir/$srcfile" ${binfile} executable $compile_flags] == "" } {
> + PerfTest::compiled
> + }
> + }
> +} {
> + startup_gdb {
> + clean_restart $binfile
> +
> + if ![runto_main] {
> + fail "Can't run to main"
> + return -1
> + }
> + }
> +} {
> + run {
> + gdb_test_no_output "python SolibLoadUnload\($SOLIB_COUNT\).run()"
> + }
> +}
> diff --git a/gdb/testsuite/gdb.perf/solib.py b/gdb/testsuite/gdb.perf/solib.py
> new file mode 100644
> index 0000000..91393b1
> --- /dev/null
> +++ b/gdb/testsuite/gdb.perf/solib.py
> @@ -0,0 +1,73 @@
> +# Copyright (C) 2013 Free Software Foundation, Inc.
> +
> +# 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/>.
> +
> +# This test case is to test the speed of GDB when it is handling the
> +# shared libraries of inferior are loaded and unloaded.
> +
> +from perftest import perftest
> +from perftest import measure
> +
> +class SolibLoadUnload1(perftest.TestCaseWithBasicMeasurements):
> + def __init__(self, solib_count, measure_load):
> + if measure_load:
> + name = "solib_load"
> + else:
> + name = "solib_unload"
> + # We want to measure time in this test.
> + super (SolibLoadUnload1, self).__init__ (name)
> + self.solib_count = solib_count
> + self.measure_load = measure_load
> +
> + def warm_up(self):
> + do_test_load = "call do_test_load (%d)" % self.solib_count
> + do_test_unload = "call do_test_unload (%d)" % self.solib_count
> + gdb.execute(do_test_load)
> + gdb.execute(do_test_unload)
> +
> + def execute_test(self):
> + num = self.solib_count
> + iteration = 5;
> +
> + while num > 0 and iteration > 0:
> + # Do inferior calls to do_test_load and do_test_unload in pairs,
> + # but measure differently.
> + if self.measure_load:
> + do_test_load = "call do_test_load (%d)" % num
> + func = lambda: gdb.execute (do_test_load)
> +
> + self.measure.measure(func, num)
> +
> + do_test_unload = "call do_test_unload (%d)" % num
> + gdb.execute (do_test_unload)
> +
> + else:
> + do_test_load = "call do_test_load (%d)" % num
> + gdb.execute (do_test_load)
> +
> + do_test_unload = "call do_test_unload (%d)" % num
> + func = lambda: gdb.execute (do_test_unload)
> +
> + self.measure.measure(func, num)
> +
> + num = num / 2
> + iteration -= 1
> +
> +class SolibLoadUnload(object):
> + def __init__(self, solib_count):
> + self.solib_count = solib_count;
> +
> + def run(self):
> + SolibLoadUnload1(self.solib_count, True).run()
> + SolibLoadUnload1(self.solib_count, False).run()
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 3efd539..28aca53 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -1796,6 +1796,22 @@ proc supports_reverse {} {
> return 0
> }
>
> +# Produce source file NAME and write SOURCES into it.
> +
> +proc gdb_produce_source { name sources } {
> + set index 0
> + set f [open $name "w"]
> +
> + while { ${index} < [llength ${sources}] } {
> + set line [lindex ${sources} ${index}]
> + set index [expr ${index} + 1]
> +
> + set line [uplevel list $line]
> + puts $f $line
> + }
> + close $f
> +}
> +
> # Return 1 if target is ILP32.
> # This cannot be decided simply from looking at the target string,
> # as it might depend on externally passed compiler options like -m64.
> --
> 1.7.7.6
>