CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: pytest-benchmark でベンチマークテストを書く

最近は Python のテストフレームワークとして pytest がデファクトになりつつある。 今回は、そんな pytest のプラグインの一つである pytest-benchmark を使ってベンチマークテストを書いてみることにする。

ここで、ベンチマークテストというのはプログラムの特定部位のパフォーマンスを計測するためのテストを指す。 ベンチマークテストを使うことで、チューニングの成果を定量的に把握したり、加えた変更によって別の場所で性能がデグレードしていないかを確かめることができる。

なお、チューニングする前のボトルネック探しについては別途プロファイラを使うのが良いと思う。

blog.amedama.jp

blog.amedama.jp

使った環境は次の通り。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.4
BuildVersion:   18E226
$ python -V         
Python 3.7.3

下準備

まずはパッケージをインストールしておく。

$ pip install pytest-benchmark

まずは試してみる

すごく単純なベンチマークテストを書いて動きを確認してみよう。

一般的に pytest を使うときはプロジェクトのルートに tests というディレクトリを用意することが多い。

$ mkdir -p tests

そして、作成したディレクトリに test_ から始まるテストコードを記述したファイルを用意する。 以下のサンプルコードでは test_example.py という名前でベンチマークテストのファイルを用意している。 サンプルコードの中では something() という関数を仮想的なベンチマーク対象としている。 テスト自体は test_ から始まる関数として記述することが一般的で test_something_benchmark() という名前で定義している。 pytest-benchmark を使ったベンチマークテストでは引数に benchmark を指定すると、必要なオブジェクトがインジェクトされる。

$ cat << 'EOF' > tests/test_example.py 
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

import pytest


def something(duration=0.1):
    """ベンチマークしたい対象"""
    time.sleep(duration)
    return True


def test_something_benchmark(benchmark):
    """ベンチマークを実施するテスト

    :param benchmark: pytest-benchmark がインジェクトするフィクスチャ
    """
    # テスト対象を引数として benchmark を実行する
    ret = benchmark(something)
    # 返り値を検証する
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])
EOF

あまり説明が長くなっても何なので実際に動かしてみよう。 実行は通常通りテストランナーである pytest コマンドを起動するだけ。

$ pytest
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 1 item                                                                                                                           

tests/test_example.py .                                                                                                              [100%]


--------------------------------------------------- benchmark: 1 tests --------------------------------------------------
Name (time in ms)                 Min       Max      Mean  StdDev    Median     IQR  Outliers     OPS  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------
test_something_benchmark     100.2115  105.2357  102.0071  1.9180  101.5772  2.3150       2;0  9.8032      10           1
-------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
========================================================= 1 passed in 2.28 seconds =========================================================

見慣れた表示の中にベンチマークの結果として実行にかかった時間に関する統計量が表示されている。 表示からは、概ね一回の実行に 100ms 前後かかっていることが分かる。 これはテスト対象の something() がデフォルトで 100ms のスリープを入れることから直感にも則している。

実行回数などを制御する

先ほどは 1 回の試行 (iteration) でテスト対象 10 回の呼び出し (rounds) をしていた。

上記の回数を変更したいときは、次のように benchmark#pedantic() 関数を使う。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

import pytest


def something(duration=0.1):
    time.sleep(duration)
    return True


def test_something_benchmark(benchmark):
    # コードで実行内容を制御したいときは benchmark#pedantic() を使う
    ret = benchmark.pedantic(something,
                             kwargs={'duration': 0.0001},  # テスト対象に渡す引数 (キーワード付き)
                             rounds=100,  # テスト対象の呼び出し回数
                             iterations=10)  # 試行回数
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])

上記を実行してみよう。 今度は 10 回の試行 (iteration) で各 100 回の呼び出し (rounds) になった。 なお、スリープする時間を短くしたにも関わらず数字が変わっていないように見えるが、単位がミリ秒からマイクロ秒に変化している。

$ pytest
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 1 item                                                                                                                           

tests/test_example.py .                                                                                                              [100%]


------------------------------------------------------ benchmark: 1 tests ------------------------------------------------------
Name (time in us)                 Min       Max      Mean   StdDev    Median     IQR  Outliers  OPS (Kops/s)  Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------
test_something_benchmark     134.3719  266.8602  143.7150  15.9095  138.1588  8.6015       6;7        6.9582     100          10
--------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
========================================================= 1 passed in 0.19 seconds =========================================================

ベンチマークだけ実行する・スキップする

一般的に、ベンチマークテストは実行に時間がかかるものが多い。 通常のユニットテストと混ぜて実行してしまうと、全体のかかる時間が伸びて使い勝手が悪くなる恐れがある。 そうした場合のために pytest-benchmark はベンチマークテストだけ実行したりスキップしたりできる。

次のサンプルコードでは通常のユニットテストとベンチマークテストが混在している。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

import pytest


def something(duration=0.1):
    time.sleep(duration)
    return True


def test_something():
    """通常のテスト"""
    ret = something()
    assert ret


def test_something_benchmark(benchmark):
    """ベンチマークテスト"""
    ret = benchmark(something)
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])

こうした状況下で、もしベンチマークテストを実行したくないときは --benchmark-skip オプションを指定してテストランナーを走らせよう。

$ pytest --benchmark-skip
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 2 items                                                                                                                          

tests/test_example.py .s                                                                                                             [100%]

=================================================== 1 passed, 1 skipped in 0.14 seconds ====================================================

ベンチマークテストがスキップされていることが分かる。

反対に、ベンチマークテストだけ実行したいときは、次のように --benchmark-only オプションを指定する。

$ pytest --benchmark-only
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 2 items                                                                                                                          

tests/test_example.py s.                                                                                                             [100%]


--------------------------------------------------- benchmark: 1 tests --------------------------------------------------
Name (time in ms)                 Min       Max      Mean  StdDev    Median     IQR  Outliers     OPS  Rounds  Iterations
-------------------------------------------------------------------------------------------------------------------------
test_something_benchmark     100.0697  105.2460  103.0371  2.1262  102.9510  4.5859       7;0  9.7052      10           1
-------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
=================================================== 1 passed, 1 skipped in 2.26 seconds ====================================================

特定のベンチマークだけ実行したい

前述した通りベンチマークテストは実行に時間がかかることが多い。 プロジェクトに数多くベンチマークテストがあるとピンポイントで走らせたくなることが多い。

例えば次のサンプルコードには二つの実行時間が異なるテストが書かれている。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

import pytest


def something(duration=0.1):
    time.sleep(duration)
    return True


def test_something_benchmark_quick(benchmark):
    ret = benchmark(something, duration=0.01)
    assert ret


def test_something_benchmark_slow(benchmark):
    ret = benchmark(something, duration=1.0)
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])

上記のような状況で、毎回どちらも実行していては時間を浪費してしまう。

$ pytest                 
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 2 items                                                                                                                          

tests/test_example.py ..                                                                                                             [100%]


--------------------------------------------------------------------------------------------- benchmark: 2 tests ---------------------------------------------------------------------------------------------
Name (time in ms)                         Min                   Max                  Mean            StdDev                Median               IQR            Outliers      OPS            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_something_benchmark_quick        10.0496 (1.0)         12.7429 (1.0)         11.7022 (1.0)      0.9845 (1.0)         11.8118 (1.0)      1.8297 (1.0)          27;0  85.4542 (1.0)          79           1
test_something_benchmark_slow      1,000.7044 (99.58)    1,005.1836 (78.88)    1,002.3219 (85.65)    1.9021 (1.93)     1,001.7429 (84.81)    2.9902 (1.63)          1;0   0.9977 (0.01)          5           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
========================================================= 2 passed in 9.03 seconds =========================================================

ピンポイントでテストを実行したいときは pytest の基本的な機能を使えば良い。 例えば、ファイル名やテストの関数名を元に実行する対象を絞りたいときは pytest コマンドで -k オプションを指定する。

$ pytest -k test_something_benchmark_quick
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 2 items / 1 deselected / 1 selected                                                                                              

tests/test_example.py .                                                                                                              [100%]


---------------------------------------------------- benchmark: 1 tests ----------------------------------------------------
Name (time in ms)                      Min      Max     Mean  StdDev   Median     IQR  Outliers      OPS  Rounds  Iterations
----------------------------------------------------------------------------------------------------------------------------
test_something_benchmark_quick     10.0454  12.7581  11.8572  0.9654  12.5086  1.6299      20;0  84.3367      90           1
----------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
================================================== 1 passed, 1 deselected in 2.12 seconds ==================================================

あるいは、次のように実行するモジュールとテスト名を指定する。

$ pytest tests/test_example.py::test_something_benchmark_quick
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench
plugins: benchmark-3.2.2
collected 1 item                                                                                                                           

tests/test_example.py .                                                                                                              [100%]


---------------------------------------------------- benchmark: 1 tests ----------------------------------------------------
Name (time in ms)                      Min      Max     Mean  StdDev   Median     IQR  Outliers      OPS  Rounds  Iterations
----------------------------------------------------------------------------------------------------------------------------
test_something_benchmark_quick     10.0478  12.7498  11.6334  1.0232  11.6050  2.0731      57;0  85.9594      91           1
----------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
========================================================= 1 passed in 2.11 seconds =========================================================

デフォルトではベンチマークテストが実行されないようにする

なお、オプションを毎回指定するのが面倒なときは pytest の設定ファイルを用意しておくと良い。 例えば次のように pytest.ini を用意しておくとデフォルトではベンチマークテストが実行されなくなる。

$ cat << 'EOF' > pytest.ini 
[pytest]
addopts =
    --benchmark-skip
EOF

オプションを何も付けずに実行すると、たしかにベンチマークテストが走らない。

$ pytest
=========================================================== test session starts ============================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench, inifile: pytest.ini
plugins: benchmark-3.2.2
collected 2 items                                                                                                                          

tests/test_example.py ss                                                                                                             [100%]

======================================================== 2 skipped in 0.02 seconds =========================================================

なお、ベンチマークを実行したいときは --benchmark-only オプションでオーバーライドできる。

$ pytest --benchmark-only                                               
======================================================================== test session starts =========================================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench, inifile: pytest.ini
plugins: benchmark-3.2.2
collected 2 items                                                                                                                                                    

tests/test_example.py ..                                                                                                                                       [100%]


--------------------------------------------------------------------------------------------- benchmark: 2 tests ---------------------------------------------------------------------------------------------
Name (time in ms)                         Min                   Max                  Mean            StdDev                Median               IQR            Outliers      OPS            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_something_benchmark_quick        10.0553 (1.0)         12.7456 (1.0)         11.4637 (1.0)      1.0267 (1.37)        11.5810 (1.0)      2.2422 (2.07)         48;0  87.2316 (1.0)          84           1
test_something_benchmark_slow      1,003.0797 (99.76)    1,004.7923 (78.83)    1,003.6242 (87.55)    0.7500 (1.0)      1,003.1852 (86.62)    1.0816 (1.0)           1;0   0.9964 (0.01)          5           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
====================================================================== 2 passed in 9.06 seconds ======================================================================

表示する統計量を絞る

デフォルトでは結構色々な統計量が表示されるけど、正直そんなに細かくいらないという感じもある。 そういうときは --benchmark-column オプションを使って必要なものだけに絞れる。

以下では試しに平均 (mean)、標準偏差 (stddev)、最小 (min)、最大 (max)だけ表示させてみた。

$ pytest --benchmark-only --benchmark-column=mean,stddev,min,max
======================================================================== test session starts =========================================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench, inifile: pytest.ini
plugins: benchmark-3.2.2
collected 2 items                                                                                                                                                    

tests/test_example.py ..                                                                                                                                       [100%]


------------------------------------------------- benchmark: 2 tests ------------------------------------------------
Name (time in ms)                        Mean            StdDev                   Min                   Max          
---------------------------------------------------------------------------------------------------------------------
test_something_benchmark_quick        11.4288 (1.0)      1.0626 (1.0)         10.1003 (1.0)         12.7667 (1.0)    
test_something_benchmark_slow      1,002.7103 (87.74)    1.9938 (1.88)     1,000.2403 (99.03)    1,005.2477 (78.74)  
---------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
====================================================================== 2 passed in 9.04 seconds ======================================================================

表示される順番を変更する

pytest-benchmark では、デフォルトでテストの項目が平均実行時間 (mean) にもとづいて昇順ソートされる。 大抵の場合はデフォルトのままで問題ないはず。 とはいえ、念のため変更する方法についても確認しておく。

以下はテストごとに実行にかかる時間の分散を変更している。 テストの実行時間は対数正規分布にもとづいたランダムな時間になる。 ただし test_something_benchmark_high_stddev()test_something_benchmark_low_stddev() よりもかかる時間の分散が大きくなるように設定している。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import random
from functools import partial

import pytest


def something(duration_func):
    time.sleep(duration_func())
    return True


def test_something_benchmark_high_stddev(benchmark):
    f = partial(random.lognormvariate, 0.01, 0.1)
    ret = benchmark(something, duration_func=f)
    assert ret


def test_something_benchmark_low_stddev(benchmark):
    f = partial(random.lognormvariate, 0.1, 0.01)
    ret = benchmark(something, duration_func=f)
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])

上記で、試しに実行時間の標準偏差 (stddev) にもとづいたソートにしてみよう。 ソートの順番を変更するには --benchmark-sort オプションでソートに使いたいカラムを指定する。

$ pytest --benchmark-only --benchmark-column=mean,stddev,min,max --benchmark-sort=stddev
======================================================================== test session starts =========================================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench, inifile: pytest.ini
plugins: benchmark-3.2.2
collected 2 items                                                                                                                                                    

tests/test_example.py ..                                                                                                                                       [100%]


---------------------------------------------------- benchmark: 2 tests ----------------------------------------------------
Name (time in ms)                              Mean             StdDev                   Min                   Max          
----------------------------------------------------------------------------------------------------------------------------
test_something_benchmark_low_stddev      1,118.5442 (1.12)     11.9663 (1.0)      1,101.5850 (1.22)     1,132.8983 (1.03)   
test_something_benchmark_high_stddev     1,002.3322 (1.0)      75.4297 (6.30)       900.1284 (1.0)      1,099.5439 (1.0)    
----------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean
===================================================================== 2 passed in 15.86 seconds ======================================================================

上記を見ると、たしかに実行時間の標準偏差にもとづいて昇順ソートされている。

ある時点に比べてテストのパフォーマンスが低下していないか確認する

よくあるニーズとして、ある時点に比べてパフォーマンスが低下していないか確認したいというものがある。 pytest-benchmark では、もちろんこれも確認できる。

まずはシンプルなテストを用意する。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

import pytest


def something():
    time.sleep(0.1)
    return True


def test_something_benchmark(benchmark):
    ret = benchmark(something)
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])

テストを実行するときに --benchmark-autosave オプションをつけると結果が保存される。

$ pytest --benchmark-only --benchmark-autosave
...(snip)...
=========================== 1 passed in 3.56 seconds ===========================

結果は .benchmarks というディレクトリに JSON で保存される。

$ find .benchmarks
.benchmarks
.benchmarks/Darwin-CPython-3.7-64bit
.benchmarks/Darwin-CPython-3.7-64bit/0001_unversioned_20190520_123557.json

なお、複数回実行すると、その都度結果が記録されていく。

$ pytest --benchmark-only --benchmark-autosave
...(snip)...
=========================== 1 passed in 3.56 seconds ===========================
$ find .benchmarks
.benchmarks
.benchmarks/Darwin-CPython-3.7-64bit
.benchmarks/Darwin-CPython-3.7-64bit/0001_unversioned_20190520_123557.json
.benchmarks/Darwin-CPython-3.7-64bit/0002_unversioned_20190520_123739.json

ここで例えば、テストにかかる時間が 2 倍になるような変更をしてみよう。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

import pytest


def something():
    time.sleep(0.2)
    return True


def test_something_benchmark(benchmark):
    ret = benchmark(something)
    assert ret


if __name__ == '__main__':
    pytest.main(['-v', __file__])

この状況で、過去のベンチマークとパフォーマンスを比較してみる。 次のように --benchmark-compare オプションを使うと比較対象とするベンチマークを選べる。 また、--benchmark-compare-fail オプションを併用することで、パフォーマンスが低下したときに結果をエラーにできる。 ここでは mean:5% としているので、平均実行時間が 5% 悪化するとエラーになる。

$ pytest --benchmark-only --benchmark-compare=0002 --benchmark-compare-fail=mean:5%
Comparing against benchmarks from: Darwin-CPython-3.7-64bit/0002_unversioned_20190520_123739.json
======================================================================== test session starts =========================================================================
platform darwin -- Python 3.7.3, pytest-4.4.1, py-1.8.0, pluggy-0.11.0
benchmark: 3.2.2 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /Users/amedama/Documents/temporary/pybench, inifile: pytest.ini
plugins: benchmark-3.2.2
collected 1 item                                                                                                                                                     

tests/test_example.py .                                                                                                                                        [100%]


--------------------------------------------------------------------------------------------- benchmark: 2 tests ---------------------------------------------------------------------------------------------
Name (time in ms)                                Min                 Max                Mean            StdDev              Median               IQR            Outliers     OPS            Rounds  Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_something_benchmark (0002_unversi)     100.1851 (1.0)      105.1182 (1.0)      102.8839 (1.0)      2.0469 (1.0)      103.4094 (1.0)      3.9875 (1.0)           5;0  9.7197 (1.0)          10           1
test_something_benchmark (NOW)              200.9856 (2.01)     205.1931 (1.95)     202.8940 (1.97)     2.1267 (1.04)     201.9794 (1.95)     4.0872 (1.02)          2;0  4.9287 (0.51)          5           1
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  Outliers: 1 Standard Deviation from Mean; 1.5 IQR (InterQuartile Range) from 1st Quartile and 3rd Quartile.
  OPS: Operations Per Second, computed as 1 / Mean

----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Performance has regressed:
    test_something_benchmark (0002_unversi) - Field 'mean' has failed PercentageRegressionCheck: 97.206794028 > 5.000000000
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
ERROR: Performance has regressed.

実行時間が 2 倍になっていることを考えれば当たり前だけどエラーになる。

いじょう。