The GDB Performance Testsuite ============================= This README contains notes on hacking on GDB's performance testsuite. For notes on GDB's regular testsuite or how to run the performance testsuite, see ../README. Generated tests *************** The testcase generator lets us easily test GDB on large programs. The "monster" tests are mocks of real programs where GDB's performance has been a problem. Often it is difficult to build these monster programs, but when measuring performance one doesn't need the "real" program, all one needs is something that looks like the real program along the axis one is measuring; for example, the number of CUs (compilation units). Structure of generated tests **************************** Generated tests consist of a binary and potentially any number of shared libraries. One of these shared libraries, called "tail", is special. It is used to provide mocks of system provided code, and contains no generated code. Typically system-provided libraries are searched last which can have significant performance consequences, so we provide a means to exercise that. The binary and the generated shared libraries can have a mix of manually written and generated code. Manually written code is specified with the {binary,gen_shlib}_extra_sources config parameters, which are lists of source files in testsuite/gdb.perf. Generated files are controlled with various configuration knobs. Once a large test program is built, it makes sense to use it as much as possible (i.e., with multiple tests). Therefore perf data collection for generated tests is split into two passes: the first pass builds all the generated tests, and the second pass runs all the performance tests. The first pass is called "build-perf" and the second pass is called "check-perf". See ../README for instructions on running the tests. Generated test directory layout ******************************* All output lives under testsuite/gdb.perf in the build directory. Because some of the tests can get really large (and take potentially minutes to compile), parallelism is built into their compilation. Note however that we don't run the tests in parallel as it can skew the results. To keep things simple and stay consistent, we use the same mechanism used by "make check-parallel". There is one catch: we need one .exp for each "worker" but the .exp file must come from the source tree. To avoid generating .exp files for each worker we invoke lib/build-piece.exp for each worker with different arguments. The file build.piece.exp lives in "lib" to prevent dejagnu from finding it when it goes to look for .exp scripts to run. Another catch is that each parallel build worker needs its own directory so that their gdb.{log,sum} files don't collide. On the other hand its easier if their output (all the object files and shared libraries) are in the same directory. The above considerations yield the resulting layout: $objdir/testsuite/gdb.perf/ gdb.log, gdb.sum: result of doing final link and running tests workers/ gdb.log, gdb.sum: result of gen-workers step $program_name/ ${program_name}-0.worker ... ${program_name}-N.worker: input to build-pieces step outputs/ ${program_name}/ ${program_name}-0/ ... ${program_name}-N/ gdb.log, gdb.sum: for each build-piece worker pieces/ generated sources, object files, shlibs ${run_name_1}: binary for test config #1 ... ${run_name_N}: binary for test config #N Generated test configuration knobs ********************************** The monster program generator provides various knobs for building various kinds of monster programs. For a list of the knobs see function GenPerfTest::init_testcase in testsuite/lib/perftest.exp. Most knobs are self-explanatory. Here is a description of the less obvious ones. binary_extra_sources This is the list of non-machine generated sources that go into the test binary. There must be at least one: the one with main. class_specs List of pairs of keys and values. Supported keys are: count: number of classes Default: 1 name: list of namespaces and class name prefix E.g., { ns0 ns1 foo } -> ns0::ns1::foo_<cu#>_{0,1,...} There is no default, this value must be specified. nr_members: number of members Default: 0 nr_static_members: number of static members Default: 0 nr_methods: number of methods Default: 0 nr_inline_methods: number of inline methods Default: 0 nr_static_methods: number of static methods Default: 0 nr_static_inline_methods: number of static inline methods Default: 0 E.g., class foo {}; namespace ns1 { class bar {}; } would be represented as: { { count 1 name { foo } } { count 1 name { ns1 bar } } } The naming of each class is "class_<cu_nr>_<class_nr>", where <cu_nr> is the number of the compilation unit the class is defined in. There's currently no support for nesting classes in classes, or for specifying baseclasses or templates. Misc. configuration knobs ************************* These knobs control building or running of the test and are specified like any global Tcl variable. CAT_PROGRAM Default is /bin/cat, you shouldn't need to change this. SHA1SUM_PROGRAM Default is /usr/bin/sha1sum. PERF_TEST_COMPILE_PARALLELISM An integer, specifies the amount of parallelism in the builds. Akin to make's -j flag. The default is 10. Writing a generated test program ******************************** The best way to write a generated test program is to take an existing one as boilerplate. Two good examples are gmonster1.exp and gmonster2.exp. gmonster1.exp builds a big binary with various custom manually written code, and gmonster2 is (essentially) the equivalent binary split up over several shared libraries. Writing a performance test that uses a generated program ******************************************************** The best way to write a test is to take an existing one as boilerplate. Good examples are gmonster1-*.exp and gmonster2-*.exp. The naming used thus far is that "foo.exp" builds the test program and there is one "foo-bar.exp" file for each performance test that uses test program "foo". In addition to writing the test driver .exp script, one must also write a python script that is used to run the test. This contents of this script is defined by the performance testsuite harness. It defines a class, which is a subclass of one of the classes in gdb.perf/lib/perftest/perftest.py. See gmonster-null-lookup.py for an example. Note: Since gmonster1 and gmonster2 are treated as being variations of the same program, each test shares the same python script. E.g., gmonster1-null-lookup.exp and gmonster2-null-lookup.exp both use gmonster-null-lookup.py. Running performance tests for generated programs ************************************************ There are two steps: build and run. Example: bash$ make -j10 build-perf RUNTESTFLAGS="gmonster1.exp" bash$ make -j10 check-perf RUNTESTFLAGS="gmonster1-null-lookup.exp" \ GDB_PERFTEST_MODE=run