Giter Club home page Giter Club logo

benchee_html's Introduction

benchee_html Hex Version Hex Docs CI Coverage Status Total Download License

Formatter for benchee to produce some standalone HTML with nice graphs, a data table etc. from your benchee benchmarking results :) Also allows you to export PNG images, the graphs are also somewhat explorable thanks to plotly.js!

To get a taste of what this is like you can check out an online example report or look at this little screenshot:

ips

It not only generates HTML but also assets and into the same folder. You can just take it and drop it on your server, github pages or public dropbox directory if you want it to be accessible to someone else :)

Installation

Add :benchee_html to your list of dependencies in mix.exs:

def deps do
  [
    {:benchee_html, "~> 1.0", only: :dev}
  ]
end

Usage

Just use it as a formatter for benchee:

list = Enum.to_list(1..10_000)
map_fun = fn(i) -> [i, i * i] end

Benchee.run(%{
  "flat_map"    => fn -> Enum.flat_map(list, map_fun) end,
  "map.flatten" => fn -> list |> Enum.map(map_fun) |> List.flatten end
},
  formatters: [
    Benchee.Formatters.HTML,
    Benchee.Formatters.Console
  ]
  # override defaults:
  # formatters: [{Benchee.Formatters.HTML, file: "output/my.html", auto_open: false}]
)

The report index page will be written to "benchmarks/output/results.html" and opened in your standard browser automatically. Of course you can also optionally specify a tuple of {Module, options} to specify a different destination for the reports: [{Benchee.Formatters.HTML, file: "your_file.html"}]. Auto open behaviour can be overridden in the same manner: html: [{Benchee.Formatters.HTML, auto_open: false}]

Of course it also works with multiple inputs, in that case one file per input is generated:

map_fun = fn(i) -> [i, i * i] end

Benchee.run(%{
  "flat_map"    => fn(list) -> Enum.flat_map(list, map_fun) end,
  "map.flatten" => fn(list) -> list |> Enum.map(map_fun) |> List.flatten end
},
  formatters: [
    {Benchee.Formatters.HTML, file: "samples_output/my.html"},
    Benchee.Formatters.Console
  ],
  time: 7,
  warmup: 3,
  inputs: %{
    "Smaller List" => Enum.to_list(1..1_000),
    "Bigger List"  => Enum.to_list(1..100_000),
  }
)

When you hover the graphs in the HTML report, quite some plotly.js controls and links appear with which you can navigate in the graph and more.

Be aware, that currently when too many samples are recorded (> 100_000 usually) rendering might break as plotly can't handle all that data. See this issue on how to quick fix it and what could be done in the future.

PNG image export/download

When you hover the graph the controls appear and the left most of those is a camera and says "Download plot as png" - and it does what you'd expect. Refer to the image below if you need more guidance :)

download

A look at graphs

In the wiki there is a page providing an overview of the differnt chart types benchee_html produces.

For the ones that just want to scroll through, here they are once more.

IPS Bar Chart

ips

Run Time Boxplot

boxplot

Run Time Histogram

histo

Raw run times

raw_run_times

Contributing

Contributions to benchee_html are very welcome! Bug reports, documentation, spelling corrections, whole features, feature ideas, bugfixes, new plugins, fancy graphics... all of those (and probably more) are much appreciated contributions!

Please respect the Code of Conduct.

You can get started with a look at the open issues.

A couple of (hopefully) helpful points:

  • Feel free to ask for help and guidance on an issue/PR ("How can I implement this?", "How could I test this?", ...)
  • Feel free to open early/not yet complete pull requests to get some early feedback
  • When in doubt if something is a good idea open an issue first to discuss it
  • In case I don't respond feel free to bump the issue/PR or ping me on other places

Development

  • mix deps.get to install dependencies
  • mix test to run tests
  • mix credo or mix credo --strict to find code style problems (not too strict with the 80 width limit for sample output in the docs)

Copyright and License

Copyright (c) 2016 Tobias Pfeiffer

This library is released under the MIT License. See the LICENSE.md file for further details.

benchee_html's People

Contributors

devonestes avatar elpikel avatar jalyna avatar kinson avatar nscyclone avatar pragtob avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

benchee_html's Issues

Show System data

Part of the Benchee Suite is system data including information about CPU, Memory, OS, Elixir and Erlang version.

We already display the Elixir and Erlang version on the top right. It'd be nice to add the other information as well. The top right isn't big enough for it so we'd need another place.

As it's part of the main content I'd suggest another panel with that information perhaps as a table or something else. Not entirely sure tbh.

Also not sure if that panel should come first or last or where it should appear. In the console formatter that information comes first but only because we can get it right away, I think the benchmark results are still most important :)

Names can get cut off in graphs

When the names are rather long and we scale the graph down from width it seems they can end up cut off. Maybe the height can be set higher or some other layout option?

newplot

Deal with big sample sizes and the slow down they produce in the page

When particularly fast functions are benchmarked for long, the sample size gets too large and plotly.js basically crashes or takes VERY LONG to render.

Current work arounds:

  • reduce :time to indirectly reduce sample size
  • remove the individual graphs from the resulting HTML by hand (they are most of the cause of this happening) and maybe also the box plot (is also fed raw run times)

Proposed solutions (might go into separate issues)

  • print a warning when sample sizes exceed a certain threshold (like say 100_000)
  • provide the option to split the individual graphs into separate files and then link to them
  • render the box plot giving manually calculated quadrilles on the elixir side see this thread

Option to give same scale to graphs

From twitter:

Would it be possible to set a scale of each chart the same by default ?

What I think this would/could entail is to set the scale of all raw tun time charts to be the same, probably also the same for the box plots. To do this effectively, it'd be convenient if benchee provided some meta statistics aka what are the minimum/maximum over the whole sample set (or well minimum of minimums/maximum of maximums).

Probably best implemented as an option, setting it as the default might also cause problems if the different jobs are wildly differing in how fast/slow they are.

Also, maybe @fazibear has some input as to what exactly he wishes for.

Graph execution time as a function of the size of the input

There should be a way of graphing the execution time as a function of the size of the input, so that one can demonstrate the time complexity of the algorithm empirically in graphs like this:

image

The size of the input can't be determined automatically, but it could given by the user in the form of a tuple: {input_size, input_value} or some similar API. I understand that this might require a new top-level Benchee function, and that might be a change too big to implement.

But even if this change isn't possible, just plotting the execution time of all the inputs in the same graph would be a big improvement.

In my concrete example, I want to show that a an implementation of a programming language lexer (let's say, implementation 1) has complexity roughly linear on the size of the file while the alternative impelmentation (say, implementation 2) has supralinear complexity. I can see how, as the input size rows, implementation 2 gets slower and slower than implementation 1, but I can't compare the execution time of the implementation 1 with itself as the input grows.

Compare Inputs in Results HTML

Is there any way to configure benchee or benchee_html to compare the inputs on one graph?

I can do this with something like the following:

Benchee.run(
  %{
    "tx_benchmark 100" => fn -> TraditionalLedger.run_benchmark_file("./data/transactions_100.csv") end,
    "tx_benchmark 1000" => fn -> TraditionalLedger.run_benchmark_file("./data/transactions_1000.csv") end,
    "tx_benchmark 10000" => fn -> TraditionalLedger.run_benchmark_file("./data/transactions_10000.csv") end,
  },
  formatters: [
    {Benchee.Formatters.Console, extended_statistics: true},
    {Benchee.Formatters.HTML, file: "benchmarks/results.html"},
  ],
  after_each: fn _input -> reset_database() end,
)

But doing it like the following "feels" better in terms of the code, but the HTML comparison charts will put these on separate pages:

Benchee.run(
  %{
    "tx_benchmark" => fn input -> TraditionalLedger.run_benchmark_file(input) end,
  },
  formatters: [
    {Benchee.Formatters.Console, extended_statistics: true},
    {Benchee.Formatters.HTML, file: "benchmarks/results.html"},
  ],
  inputs: %{
    "100" => "./data/transactions_100.csv",
    "1_000" => "./data/transactions_1000.csv",
    "10_000" => "./data/transactions_10000.csv",
  },
  after_each: fn _input -> reset_database() end,
)

And output the following:

Screen Shot 2021-12-04 at 11 25 59 AM

But I think this may just be a personal preference, but I could see there a use case for comparing inputs against each other in this fashion for benchmarking performance for different applications.

(with Poison 2.2) ** (Poison.EncodeError) expected string or atom key, got: 50

Seems I finally found one of the differences of poison 3 vs. poison 2.

The problem is our new percentiles that have integers as keys in the maps:

iex(1)> Poison.encode! %{1 => "lol"}
** (Poison.EncodeError) expected string or atom key, got: 1
    (poison) lib/poison/encoder.ex:188: Poison.Encoder.Map.encode_name/1
    (poison) lib/poison/encoder.ex:212: anonymous fn/4 in Poison.Encoder.Map.encode/3
    (poison) lib/poison/encoder.ex:214: Poison.Encoder.Map."-encode/3-lists^foldl/2-0-"/3
    (poison) lib/poison/encoder.ex:214: Poison.Encoder.Map.encode/3
    (poison) lib/poison.ex:41: Poison.encode!/2

vs.

iex(1)> Poison.encode! %{1 => "lol"}
"{\"1\":\"lol\"}"

This should trigger in benchee_json, but right now this code is still inlined in benchee_html:

job_json = JSON.encode!(%{
        statistics: scenario.run_time_statistics,
        run_times: scenario.run_times
      })

We can't switch to a newer poison version as lots of people rely on Poison < 3 in some phoenix versions etc.

Mitigation:

  • manually stringify keys
  • switch to a different json library that handles these things like jason (not sure if it handles them/worth a try)

Set custom y0 for raw run time charts

Right now the raw run time charts all go up to a certain level which is understandable as there is a minimum execution time. I think it'd be better if benchee_html set a custom start value for the y-axis that is something like minimum - 10% * minimum so that the height of the chart is used more effectively to show the differences.

what might help here from plotly.js (oe well hopefully will) is setting y0.

Example of what's "broken":

image

Make auto opening report in browser configurable

Need a new formatter_option like auto_open or something that is either true or false. If it's false open_report should just not open the report in a browser.

Most importantly, please set the option to false in all tests so that my test don't open all the browser tabs all the time :D

Customize the HTML template

I'm thinking of including some benchmarks as part of the docs as a way of justifying some implementation choices and a s a teaching tool on how to extend my library.

You can access Benchee's HTML pages form the README (here). I'd like to change the template so that I could add other information, such as a title for the benchmark.

Option to inline all assets

An option inline all assets (CSS/JavaScript) would be great. This way the files could be totally independent moved and copied around without worrying that all the appropriate asset folders have to be present.

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.