• Stars
    star
    510
  • Rank 83,273 (Top 2 %)
  • Language
    Elixir
  • License
    MIT License
  • Created almost 10 years ago
  • Updated 11 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Microbenchmarking tool for Elixir

Benchfella

Module Version Hex Docs Total Download License Last Updated

Microbenchmarking tool for Elixir.

Overview

With Benchfella you can define small tests and it will intelligently run each individual one to obtain a more or less reliable estimate of the average run time for each test.

The key features of Benchfella:

  • very easy to write and run microbenchmarks
  • compare measurements between multiple runs
  • plot results of multiple runs

If you are looking for a more elaborate treatment of the measurements, take a look at bmark which employs mathematical statistics to compare benchmarking results and determine their credibility.

Installation

Add :benchfella as a dependency to your project:

# in your mix.exs

defp deps do
  [
    {:benchfella, "~> 0.3.0"}
  ]
end

This will make the new tasks available in the root directory of your Mix project.

Any project will do, so if you just want to measure a snippet of code quickly, create a bare-bones Mix project with mix new, create a subdirectory called bench in it and put your benchmark definitions there. See examples below.

Usage

Take a moment to study the output of running mix help bench and mix help bench.cmp inside your Mix project to see all supported options.

In order to start writing tests, add a directory called bench and put files with names that match the pattern *_bench.exs in it. Then run mix bench in the root directory of your project. Benchfella will then load each test and execute it for as many iterations as necessary so that the total running time is at least the specified duration.

Example:

# bench/basic_bench.exs
defmodule BasicBench do
  use Benchfella

  @list Enum.to_list(1..1000)

  bench "hello list" do
    Enum.reverse @list
  end
end
$ mix bench
Settings:
  duration:      1.0 s

## BasicBench
[13:23:58] 0/1: hello list

Finished in 3.15 seconds

## BasicBench
hello list      500000   5.14 ยตs/op

In the end, the number of iterations and the average time of a single iteration are printed to the standard output. Additionally, the output in machine format is written to a snapshot file in bench/snapshots/.

setup_all and teardown_all

setup_all/0 lets you perform some code before the first test in a module is run. It takes no arguments and should return {:ok, <context>} where <context> is any term, it will be passed into before_each_bench/1 and teardown_all/1 if they are defined. Returning any other value will raise an error and cause the whole module to be skipped.

teardown_all/1 lets you do some cleanup after the last test in a module has finished running. It takes the context returned from setup_all/0 (nil by default) as its argument.

# bench/sys_bench.exs
defmodule SysBench do
  use Benchfella

  setup_all do
    depth = :erlang.system_flag(:backtrace_depth, 100)
    {:ok, depth}
  end

  teardown_all depth do
    :erlang.system_flag(:backtrace_depth, depth)
  end

  @list Enum.to_list(1..10000)

  bench "list reverse" do
    Enum.reverse(@list)
  end
end

before_each_bench and after_each_bench

before_each_bench/1 runs before each individual test is executed. It takes the context returned from setup_all/0 and should return {:ok, <bench_context>} where <bench_context> is any term. Returning any other value will raise an error and cause the current test to be skipped.

<bench_context> returned from before_each_bench/1 will be available as the bench_context variable in each test.

after_each_bench/1 runs after each individual test has been executed. It takes the context returned from before_each_bench/1 as its argument.

# bench/ets_bench.exs
defmodule ETSBench do
  use Benchfella

  before_each_bench _ do
    tid = :ets.new(:my_table, [:public])
    {:ok, tid}
  end

  after_each_bench tid do
    IO.inspect length(:ets.tab2list(tid))
    :ets.delete(tid)
  end

  bench "ets insert", [_unused: inspect_table(bench_context)] do
    tid = bench_context
    :ets.insert(tid, {:rand.uniform(1000), :x})
    :ok
  end

  defp inspect_table(tid) do
    IO.inspect :ets.info(tid)
  end
end

Run time values

When you need to generate inputs for tests at run time without affecting the measurements and you can't use before_each_bench/1 hook for that, the following trick can be used:

# bench/string_bench.exs
defmodule StringBench do
  use Benchfella

  bench "reverse string", [str: gen_string()] do
    String.reverse(str)
  end

  defp gen_string() do
    String.duplicate("abc", 10000)
  end
end

mix bench.cmp

To compare results between multiple runs, use mix bench.cmp.

# Run 'mix bench' one more time.
# Each run automatically saves a snapshot in bench/snapshots.
$ mix bench
...

# 'mix bench.cmp' will read the two latest snapshots by default.
# You could also pass the snapshot files to compare as arguments.
$ mix bench.cmp -d percent
bench/snapshots/2015-03-26_01-17-17.snapshot vs
bench/snapshots/2015-03-26_01-19-30.snapshot

## ListBench
reverse list              -10.32%

## StringBench
reverse string dynamic    +2.26%
reverse string            +3.33%

mix bench.graph

Benchfella can produce an HTML page with graphs providing various insights into the raw data obtained from running mix bench.

# run the benchmarks twice
$ mix bench
...
$ mix bench
...

# 'mix bench.graph' works similarly to 'mix bench.cmp' except it can display
# all given snapshots on one graph.
$ mix bench.graph
Wrote bench/graphs/index.html

$ open bench/graphs/index.html

Graph example

Copyright and License

Copyright (c) 2014 Alexei Sholik

This software is licensed under the MIT license.

More Repositories

1

gostart

A getting started guide for Go newcomers
1,827
star
2

porcelain

Work with external processes like a boss
Elixir
917
star
3

hashids-elixir

Stringify your ids
Elixir
270
star
4

psdump

Extract layout from Photoshop files into one of several text-based formats.
C
85
star
5

goon

Middleman implementation for Porcelain
Go
53
star
6

chatty

Basic IRC client for writing bots
Elixir
35
star
7

pipespect

Auto-inspect for pipes
Elixir
29
star
8

ExReminder

A simple reminder app written in Elixir
Elixir
25
star
9

elixir-datetime

Elixir
23
star
10

erlang-mix-project

A sample Erlang project that uses Mix
Erlang
19
star
11

phoenix-docker-example

A demo showing how to run a Phoenix app within a docker container
Elixir
19
star
12

mix-erlang-tasks

Common tasks for Erlang projects that use Mix
Elixir
18
star
13

EGL_mac_ios

A port of the EGL API to Mac OS X (OpenGL) and iOS (OpenGL ES 1 & 2)
Objective-C
12
star
14

beamie_bot

Find beamie on #elixir-lang on irc.freenode.net
Elixir
11
star
15

commando

Advanced command-line argument parsing
Elixir
10
star
16

muweb

A minimalistic web framework
Elixir
9
star
17

miniweb

Web-related utilities
Elixir
8
star
18

TastyKVO

A simpler key-value observing API (with blocks!)
Objective-C
7
star
19

numspell

A simple python module for number spelling
Python
6
star
20

go_pil

Go
6
star
21

blog

My blog
Shell
5
star
22

gochan

Implementation of Go channels in Elixir
Elixir
5
star
23

cloaked-octo-robot

Elixir
4
star
24

EGL_samples

Sample apps for the EGL_mac_ios port
Objective-C
4
star
25

porcelain_example

Example project showing how to use Porcelain
Elixir
4
star
26

dayton-talk-cli-apps

Slides and code for my Dayton talk about command-line apps in Elixir
Elixir
3
star
27

wyvern

Versatile view engine for Elixir
Elixir
3
star
28

Remotely

A set of Objective-C classes to simplify downloading/uploading/syncing files and directories
Objective-C
2
star
29

objc.string

Self-contained library for efficient string manipulation in Objective-C.
Objective-C
2
star
30

mix-run

A sample project showing how to teach Mix to behave
Elixir
2
star
31

rust-digest

Implementations of missing hash/digest/checksum algorithms for Rust
Rust
2
star
32

simpleweb

A simple web framework in Elixir
Elixir
2
star
33

2048-elixir

Sliding tile puzzle game implemented in Elixir.
Elixir
2
star
34

french-cards

Flash cards for studying French
Python
2
star
35

ace-mode-elixir

Elixir mode for Ace editor
JavaScript
1
star
36

elixir-datefmt

Elixir
1
star
37

99-lisp-problems

My solutions
Clojure
1
star
38

Numerissimo

Client-side web app for aspired foreign language learners
JavaScript
1
star
39

bingo

Parse binary data in Go like a boss
Go
1
star
40

elixir-docs

The Unofficial Elixir Documentation
Python
1
star
41

exdoc_sphinx_formatter

Custom formatter for ExDoc
Elixir
1
star
42

ansi-progress

Elixir
1
star
43

PhotoJS

A collection of scripts for automating common gamedev related tasks in Photoshop
JavaScript
1
star
44

3d

3d
JavaScript
1
star
45

perseus

Perseus persist HTML nodes, form fields and your custom objects
JavaScript
1
star
46

Funjective

Functional programming with blocks for Objective-C
Objective-C
1
star
47

parallax

A rudimentary parallax test
JavaScript
1
star
48

requestanimationframedemo

JavaScript
1
star
49

wyvern-examples

WIP, check back later
Elixir
1
star