No Description

Kevin Pouget 30d44df5fa improve 5 years ago
gdb_testing a41506bd22 improve 5 years ago
mcgdb_testing 023eb38cd0 improve 5 years ago
openmp_testing ce0a753242 improve 5 years ago
.gitignore ce0a753242 improve 5 years ago
LICENSE 42e7e2bf1f add readme and licence 5 years ago
README.md 19b5214b6a fix and improve 5 years ago
__init__.py 30d44df5fa improve 5 years ago
__main__.py 9acb8b06de improve 5 years ago
testing.py 48dd351f11 start working 5 years ago
to_import_from_mcgdb ce0a753242 improve 5 years ago

README.md

gdb.tester.py is a Python framework for writing unit tests and benchmarks for gdb. It is basically a wrapper around gdb CLI interface to automate execution and drive it from Python.

Don't get me wrong, this is nothing related to GDB Python interface. This API is for extending GDB, whereas GDB Tester is for scripting it.

Try it

This command should benchmark GDB breakpoints:

python3 -c 'import gdb_tester; gdb_tester.main(pkg_prefix="gdb_tester.gdb_testing")'

Where and how to specify unit-tests and benchmarks

gdb.tester.py test files should be stored in a subpackage called [*_]testing, inside the Python package tree. gdb.tester.py walks through that tree, and runs alls the modules of that package.

Inside the modules, gdb.tester.py expects to find functions called benchmark or test.

How to write unit-tests and benchmarks

Here is a template of a unit-testing and benchmarking module:

 def benchmark(gdb):

   def init_hook():
     # this code is run at start and reset
     pass

   # benchmark.c is in the same directory,
   # benchmark is build by `make`

   gdb.start(CSource("benchmark.c"), init_hook)
   gdb.set_title("my empty benchmark")
   gdb.execute("break finish_data_ready")
   gdb.execute("run")

   # inside benchmark.c we measure the execution time
   # and save it into `us_busy_once`.
   gdb.save_value("us_busy_once", "%1.f", "us")

   # if we had other measures to do
   gdb.reset(hard=False) # hard means quit and restart

   gdb.quit()

 def test(gdb):
   # second parameter is text expected in ouput   
   gdb.execute("where", "No stack.")

   gdb.start(CSource("parallel-demo.c"))

   gdb.execute_many(["start", "next", "next"])

   gdb.execute("where", "in main")
   gdb.execute("cont", "exited normally", may_fail=True)

Example

You'll find examples in the _testing subpackages. However, they are specific to my mcgdb project, so they won't work out of the box. Only mcgdb_testing.native_gdb benchmark was written for a vanilla GDB:

 from gdb_tester import *

 gdb = None

 def run(what, run="run"):
     gdb.set_title(what)
     gdb.execute("break finish_data_ready")
     gdb.execute(run)
     gdb.execute("up")

     gdb.save_value("us_busy_once", "%1.f", "us")

 def nominal_time():
     run("Nominal time")

 def gdb_watchpoint():
     gdb.execute("break benchmark")
     gdb.execute("run")
     gdb.execute("print &i")
     gdb.execute("watch *$1")
     gdb.execute("""command
 silent
 continue
 end""")
     gdb.execute("py [b for b in gdb.breakpoints() if b.location == 'benchmark'][0].delete()")

     run("HW Watchpoint command", run="continue")

 def gdb_breakpoint():
     gdb.execute("break action")
     gdb.execute("""command
 silent
 continue
 end""")
     run("Breakpoint command")

 PARAMETERS = [
     'int(gdb.parse_and_eval("it"))',
     'int(gdb.newest_frame().older().read_var("i"))'
     ]
 def gdb_py_breakpoint_parameter(params_choice):
     params = [par for i, par in enumerate(PARAMETERS) if params_choice & (1 << i)]

     def to_run():
         gdb.execute("""python
 class TestBP(gdb.Breakpoint):
   def __init__(self):
     gdb.Breakpoint.__init__(self, "action")
     self.silent=True

   def stop(self):
     {params}
     return False

 TestBP()
 end
 """.format(params="\n    ".join(params)))
         run("Py BP param {:02b}".format(params_choice)[2:])

     return to_run

 def benchmark(_gdb, what=None, no_mcgdb=True):
     global gdb
     gdb = _gdb

     if what is None:
         what = [nominal_time, gdb_breakpoint, gdb_watchpoint] + \
                 list(map(lambda x: gdb_py_breakpoint_parameter(x), (0b0, 0b1, 0b10, 0b11)))

     gdb.start(CSource("benchmark.c"), None if no_mcgdb else mcgdb.testing.gdb__init_mcgdb)
     for prepare_and_run in what:
         prepare_and_run()
         gdb.reset(hard=(not no_mcgdb))

     gdb.quit()