Giter Site home page Giter Site logo

benchdb's Introduction

benchdb - A database and query tool for JMH results

When you run benchmarks with JMH you usually look at the results table printed after the run or maybe generate a JSON file and feed it into JMH Visualizer for immediate consumption. This approach does not scale well when you benchmark lots of different changes or want to compare historical data or visualize more complex benchmark results graphically.

benchdb takes a JMH result file plus some captured environment data (platform, Java environment, git data for git-based projects) and stores it in a relational database of your choice. You can later list and retrieve these results and run queries over a single result or combining multiple results. Thanks to the stored environment data you always know when, what and where you ran a benchmark.

Installation (PRELIMINARY)

  • Clone benchdb and run sbt core/publishLocal.

  • Create the command line app with Coursier, e.g.:

    > cs bootstrap com.lightbend.benchdb::benchdb-core:latest.release com.h2database:h2:1.4.200 -o benchdb
    

    Note that the second dependency is the database JDBC driver, in this case an H2 embedded database which is recommended for local use on a single machine. You should replace this with the database driver of your choice (e.g. mysql:mysql-connector-java:8.0.19 for MySQL/MariaDB). benchdb doesn't use any advanced database features. Any database supported by Slick should work.

  • In order to use an embedded H2 database you can run benchdb create-config to create a default configuration file .benchdb.conf in your home directory. benchdb config files use HOCON syntax for Typesafe Config. You can also specify a path for additional configurations or ignore the user config file with command line options.

    For a multi-machine setup with a database server, you need to create the configuration manually. It needs to contain at least a DatabaseConfig for Slick under the name db. Here is an example for connecting to a MySQL/MariaDB server:

    db {
      profile = "slick.jdbc.MySQLProfile$"
      db {
        connectionPool = disabled
        dataSourceClass = "com.mysql.cj.jdbc.MysqlDataSource"
        properties = {
          serverName = "hostname"
          portNumber = "3307"
          databaseName = "benchdb"
          user = "benchdb"
          password = "password"
          serverTimezone = "UTC"
        }
      }
    }
    
  • Run benchdb init-db --force to initialize the database schema.

Usage

  • benchdb --help shows the list of supported commands. Specifying a command name followed by --help shows further options and parameters for that command.

  • First you need to insert some benchmark results into the database, e.g.:

    > benchdb insert-run --project-dir ../scala --msg "Test 1" --jmh-args "-wm bulk" ../scala/test/benchmarks/jmh-result.json
    

    The specified project directory (default: current directory) is used to determine git environment data.

  • benchdb list lists the benchmark runs in the database, e.g.:

    > benchdb list --git-data
    /----+---------------------+----------+---------+---------------------+----------------------------------+------------------------------------\
    | ID | Timestamp           | Msg      | Git SHA | Git Timestamp       | Git Origin                       | Git Upstream                       |
    |----+---------------------+----------+---------+---------------------+----------------------------------+------------------------------------|
    |  4 | 2020-03-24 14:15:15 | Test 3   | d335189 | 2020-03-09 16:06:23 | [email protected]:szeiger/scala.git | https://github.com/scala/scala.git |
    |  3 | 2020-03-24 14:14:57 | Test 3   | d335189 | 2020-03-09 16:06:23 | [email protected]:szeiger/scala.git | https://github.com/scala/scala.git |
    |  2 | 2020-03-24 13:18:38 | Test 2   | d335189 | 2020-03-09 16:06:23 | [email protected]:szeiger/scala.git | https://github.com/scala/scala.git |
    |  1 | 2020-03-24 13:07:30 | Test job | d335189 | 2020-03-09 16:06:23 | [email protected]:szeiger/scala.git | https://github.com/scala/scala.git |
    \----+---------------------+----------+---------+---------------------+----------------------------------+------------------------------------/
    4 test runs found.
    
  • benchdb results generates a table similar to the one produced by JMH itself. You can specify one or more run IDs to show (defaulting to the latest run if no ID is given) and also filter benchmark names with glob patterns:

    > benchdb results -r1 -b*100p*
    /----------------------------------------------------------+--------+------+-----+------------+----------+-------\
    | Benchmark                                                | (size) | Mode | Cnt |      Score |    Error | Units |
    |----------------------------------------------------------+--------+------+-----+------------+----------+-------|
    | scala.collection.immutable.VectorBenchmark2.nvFilter100p |      1 | avgt |  20 |      9.046 |    0.073 | ns/op |
    | scala.collection.immutable.VectorBenchmark2.nvFilter100p |     10 | avgt |  20 |     11.558 |    0.099 | ns/op |
    | scala.collection.immutable.VectorBenchmark2.nvFilter100p |    100 | avgt |  20 |    503.222 |   11.211 | ns/op |
    | scala.collection.immutable.VectorBenchmark2.nvFilter100p |   1000 | avgt |  20 |   6163.309 |  278.645 | ns/op |
    | scala.collection.immutable.VectorBenchmark2.nvFilter100p |  10000 | avgt |  20 |  41181.090 | 1407.833 | ns/op |
    | scala.collection.immutable.VectorBenchmark2.nvFilter100p |  50000 | avgt |  20 | 195477.388 | 4077.424 | ns/op |
    \----------------------------------------------------------+--------+------+-----+------------+----------+-------/
    

Secondary metrics can be used in place of the primary metric with -metric, (for instance, -metric ·gc.alloc.rate.norm shows the the per-operation allocations recorded by JMH's -prof gc.

  • Extractor patterns can be used to extract additional parameters from benchmark names. They are glob patterns with regular expression-like capture groups. Unnamed groups are discarded, named groups are extracted into parameters. For example:

    > benchdb results -r1 --extract (*2.)nvFilter(percent=*)p
    /--------------------+--------+-----------+------+-----+------------+----------+-------\
    | Benchmark          | (size) | (percent) | Mode | Cnt |      Score |    Error | Units |
    |--------------------+--------+-----------+------+-----+------------+----------+-------|
    | nvFilter(percent)p |      1 |         0 | avgt |  20 |      8.824 |    0.381 | ns/op |
    | nvFilter(percent)p |     10 |         0 | avgt |  20 |      8.902 |    0.075 | ns/op |
    | nvFilter(percent)p |    100 |         0 | avgt |  20 |     40.800 |    0.544 | ns/op |
    | nvFilter(percent)p |   1000 |         0 | avgt |  20 |    134.629 |    1.996 | ns/op |
    | nvFilter(percent)p |  10000 |         0 | avgt |  20 |   1712.683 |   31.730 | ns/op |
    | nvFilter(percent)p |  50000 |         0 | avgt |  20 |   8186.502 |  130.088 | ns/op |
    | nvFilter(percent)p |      1 |       100 | avgt |  20 |      9.046 |    0.073 | ns/op |
    | nvFilter(percent)p |     10 |       100 | avgt |  20 |     11.558 |    0.099 | ns/op |
    | nvFilter(percent)p |    100 |       100 | avgt |  20 |    503.222 |   11.211 | ns/op |
    | nvFilter(percent)p |   1000 |       100 | avgt |  20 |   6163.309 |  278.645 | ns/op |
    | nvFilter(percent)p |  10000 |       100 | avgt |  20 |  41181.090 | 1407.833 | ns/op |
    | nvFilter(percent)p |  50000 |       100 | avgt |  20 | 195477.388 | 4077.424 | ns/op |
    | nvFilter(percent)p |      1 |        50 | avgt |  20 |     13.321 |    0.302 | ns/op |
    | nvFilter(percent)p |     10 |        50 | avgt |  20 |     62.017 |    1.439 | ns/op |
    | nvFilter(percent)p |    100 |        50 | avgt |  20 |    595.161 |   34.352 | ns/op |
    | nvFilter(percent)p |   1000 |        50 | avgt |  20 |   5951.751 |   56.474 | ns/op |
    | nvFilter(percent)p |  10000 |        50 | avgt |  20 |  43305.200 | 1221.533 | ns/op |
    | nvFilter(percent)p |  50000 |        50 | avgt |  20 | 196567.912 | 8389.588 | ns/op |
    \--------------------+--------+-----------+------+-----+------------+----------+-------/
    
  • You can then pivot one or more parameters to compare their results side by side:

    > benchdb results -r1 --extract (*2.)nvFilter(percent=*)p --pivot percent
    /--------------------+--------+------+-----+----------+---------+------------+----------+------------+----------+-------\
    |          (percent) |        |      |     |         0          |          50           |          100          |       |
    | Benchmark          | (size) | Mode | Cnt |    Score |   Error |      Score |    Error |      Score |    Error | Units |
    |--------------------+--------+------+-----+----------+---------+------------+----------+------------+----------+-------|
    | nvFilter(percent)p |      1 | avgt |  20 |    8.824 |   0.381 |     13.321 |    0.302 |      9.046 |    0.073 | ns/op |
    | nvFilter(percent)p |     10 | avgt |  20 |    8.902 |   0.075 |     62.017 |    1.439 |     11.558 |    0.099 | ns/op |
    | nvFilter(percent)p |    100 | avgt |  20 |   40.800 |   0.544 |    595.161 |   34.352 |    503.222 |   11.211 | ns/op |
    | nvFilter(percent)p |   1000 | avgt |  20 |  134.629 |   1.996 |   5951.751 |   56.474 |   6163.309 |  278.645 | ns/op |
    | nvFilter(percent)p |  10000 | avgt |  20 | 1712.683 |  31.730 |  43305.200 | 1221.533 |  41181.090 | 1407.833 | ns/op |
    | nvFilter(percent)p |  50000 | avgt |  20 | 8186.502 | 130.088 | 196567.912 | 8389.588 | 195477.388 | 4077.424 | ns/op |
    \--------------------+--------+------+-----+----------+---------+------------+----------+------------+----------+-------/
    
  • benchdb chart generates line charts (using the Google Charts library). The parameters are the same as for results. Charts require a single free parameter which must be Long-valued (i.e. all instances can be parsed into a Long -- the actual types of the benchmark parameters are not preserved by JMH; it stores everything as a string), like size in the example above. In case of pivoted results, all pivoted columns are rendered together as individual series in a single chart. The result of benchdb chart is a single, self-contained HTML file. If no output file is specified, it is written to a temporary file and opened in the default browser.

Maintenance notes

benchdb is NOT supported under the Lightbend subscription.

Contributions to this project are very welcome!

benchdb's People

Contributors

scala-steward avatar szeiger avatar lrytz avatar retronym avatar sethtisue avatar odd avatar

Stargazers

Jules Ivanic avatar Shafqat Ullah avatar George Kontridze avatar Juan Antonio Breña Moral avatar Artsiom Chuiko avatar Lucas Romero avatar Nils Liebelt avatar Guang YANG avatar Florian Latifi avatar Boris Bokan avatar André Meira avatar José Wenceslao Castillo avatar Mihai Soloi avatar Michael Werle avatar Ahir Reddy avatar Zhange avatar Ivan Dyachenko avatar Hariharan Ramanathan avatar Thomas Skjølberg avatar Mikhail Korotin avatar sudotty avatar Anastasios Skarlatidis avatar Will Sargent avatar ravila avatar Mohammed Abdulrazeg avatar Lorenzo Gabriele avatar Andrea Peruffo avatar Ziλ∀ avatar Konrad `ktoso` Malawski avatar Carfield Yim avatar Christopher Coco avatar Filipe Regadas avatar Erik Osheim avatar Joao Azevedo avatar Ricardo M. Vilchis avatar Michael Wizner avatar Pedro Tavares avatar Ivano Pagano avatar  avatar Jens avatar Tien Bui avatar Chen Yinghua avatar Daniel Robbins avatar Alfonso Roa avatar Piotr Wittchen avatar Marek Prochera avatar Zakharov Roman avatar Chris Heikkinen avatar Eugene Golovan avatar Ruslans Tarasovs avatar Yüce Tekol avatar Ilya avatar James Fielder avatar Kaspar Fischer avatar Lukasz Stefaniak avatar ShankarShastri avatar Andriy Plokhotnyuk avatar Marissa | April avatar timothy avatar  avatar

Watchers

Christopher Lewis avatar Michael Nash avatar James Cloos avatar Andriy Plokhotnyuk avatar  avatar

benchdb's Issues

scalaVersion handling in sbt plugin is broken

I haven't found any way to prevent sbt from putting the containing project's scalaVersion artifacts on the benchdb classpath. This needs to be resolved before the sbt plugin will be useful and can be used the way I envisioned it (i.e. added to your local sbt setup as a global plugin, never added to a project's build definition).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.