pytest-benchmarkを使用してPythonコードをベンチマークする方法

Everett Pompeii

Everett Pompeii


ベンチマークとは?

ベンチマークとは、コードの性能をテストして、その処理速度(レイテンシ)や処理量(スループット)を確認することを指します。 この、ソフトウェア開発において見落とされがちなステップは、高速で高性能なコードを作成および維持するために重要です。 ベンチマークは開発者がコードがさまざまな作業負荷や条件下でどれだけうまく動作するかを理解するために必要な指標を提供します。 機能のリグレッションを防ぐためにユニットテストや統合テストを書くのと同様に、 パフォーマンスのリグレッションを防ぐためにもベンチマークを書くべきです。 パフォーマンスのバグもバグです!

PythonでFizzBuzzを書く

ベンチマークを書くためには、ベンチマークするソースコードが必要です。 まず、非常にシンプルなプログラム、 FizzBuzz を書いてみましょう。

FizzBuzzのルールは以下の通りです:

1から100までの整数を印刷するプログラムを書く:

  • 三の倍数の場合は、Fizzを印刷します
  • 五の倍数の場合は、Buzzを印刷します
  • 三と五の両方の倍数の場合は、FizzBuzzを印刷します
  • それ以外の場合は、数字を印刷します

FizzBuzzは多くの方法で書くことができます。 なので、私のお気に入りの方法で進めることにしましょう。

for i in range(1, 101):
if n % 15 == 0:
print("FizzBuzz")
elif n % 3 == 0:
print("Fizz")
elif n % 5 == 0:
print("Buzz")
else:
print(i)
  • 1から100まで繰り返し、範囲を101に設定します。
  • 各数について、35の剰余(除算後の余り)を計算します。
  • 余りが0の場合、その数は指定された因数の倍数です。
    • 余りが015の場合、FizzBuzzと表示します。
    • 余りが03の場合、Fizzと表示します。
    • 余りが05の場合、Buzzと表示します。
  • それ以外の場合は、その数をそのまま表示します。

手順を順を追ってフォロー

この手順ごとのチュートリアルをフォローするには、Pythonをインストールし、 pipenv をインストールする必要があります。

🐰 この投稿のソースコードはGitHubで利用可能です。

game.pyという名前のPythonファイルを作成し、その内容を上記のFizzBuzz実装に設定します。

次に、python game.pyを実行します。 出力は次のようになります:

$ python game.py
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
97
98
Fizz
Buzz

🐰 バム!コーディングインタビューを突破していますね!

さらに進む前に、マイクロベンチマークとマクロベンチマークの違いについて話し合うことが重要です。

マイクロベンチマークとマクロベンチマーク

ソフトウェアベンチマークには、マイクロベンチマークとマクロベンチマークの2つの主要なカテゴリーがあります。 マイクロベンチマークは、ユニットテストと同様のレベルで動作します。 例えば、単一の数値に対してFizzBuzz、またはFizzBuzzを決定する関数のベンチマークはマイクロベンチマークになります。 一方、マクロベンチマークは、統合テストと同様のレベルで動作します。 例えば、1から100までの全ゲームをプレイするFizzBuzzの関数のベンチマークは、マクロベンチマークになります。

一般的に、可能な限り低い抽象レベルでテストすることが最善です。 ベンチマークの場合、これにより保守性が向上し、測定値のノイズを減らすことに役立ちます。 しかし、エンドツーエンドテストがシステム全体が予想通りに組み合わさるかのサニチェックに非常に役立つように、 マクロベンチマークがあると、ソフトウェアを通る重要なパスが性能を維持するために非常に役立ちます。

Python におけるベンチマーク

Python でのベンチマークの一般的な選択肢は次の2つです: pytest-benchmark および airspeed velocity (asv)

pytest-benchmark は、人気のあるpytest テストフレームワークと統合された強力なベンチマークツールです。 開発者は、ユニットテストと並行してベンチマークを実行することで、自分のコードのパフォーマンスを測定し比較することができます。 ユーザーは、ローカルでベンチマーク結果を簡単に比較でき、JSON などの様々な形式で結果をエクスポートすることも可能です。

airspeed velocity (asv) は、Python エコシステム内のもう1つの高度なベンチマークツールです。 asv の主な利点の1つは、詳細でインタラクティブな HTML レポートを生成する機能であり、パフォーマンストレンドを視覚化し、リグレッションを特定するのが容易になります。 さらに、asv相対的継続的ベンチマークを標準でサポートしています。

両方ともBencherによるサポートがあります。 では、なぜpytest-benchmarkを選ぶのでしょうか? pytest-benchmarkは、Pythonエコシステムにおけるデファクトスタンダードなユニットテストハーネスであるpytestとシームレスに統合されます。 特にすでにpytestを使用している場合は、コードのレイテンシをベンチマークするためにpytest-benchmarkを使用することをお勧めします。つまり、pytest-benchmarkはウォールクロック時間を測定するのに優れています。

フィズバズのリファクタリング

フィズバズアプリケーションをテストするためには、 ロジックをプログラムのメイン実行から切り離す必要があります。 ベンチマークハーネスはメイン実行をベンチマークすることができません。 これを行うために、いくつかの変更を行う必要があります。

フィズバズのロジックをいくつかの関数にリファクタリングしましょう:

def play_game(n, should_print):
result = fizz_buzz(n)
if should_print:
print(result)
return result
def fizz_buzz(n):
if n % 15 == 0:
return "FizzBuzz"
elif n % 3 == 0:
return "Fizz"
elif n % 5 == 0:
return "Buzz"
else:
return str(n)
  • play_game: 整数 n を受け取り、その数で fizz_buzz を呼び出し、should_printTrue の場合は結果を出力します。
  • fizz_buzz: 整数 n を受け取り、実際の FizzBuzzFizzBuzz、または数のロジックを実行し、結果を文字列として返します。

次に、メインの実行を次のように更新します:

game.py
for i in range(1, 101):
play_game(i, True)

プログラムのメイン実行は、1 から 100 までの数を含む範囲を繰り返し、各数に対して play_gameshould_printTrue に設定して呼び出します。

FizzBuzzのベンチマーク

コードのベンチマークを行うためには、ベンチマークを実行するテスト関数を作成する必要があります。game.pyの最後に次のコードを追加します:

def test_game(benchmark):
def run_game():
for i in range(1, 101):
play_game(i, False)
benchmark(run_game)
  • pytest-benchmarkbenchmarkフィクスチャを取るtest_gameという名前の関数を作成します。
  • 1から100までを含めて反復するrun_game関数を作成します。
    • 各数字に対して、should_printFalseに設定してplay_gameを呼び出します。
  • benchmarkランナーにrun_game関数を渡します。

次に、プロジェクトを構成してベンチマークを実行できるようにしましょう。

pipenvで新しい仮想環境を作成します:

$ pipenv shell
Creating a Pipfile for this project...
Launching subshell in virtual environment...
source /usr/bencher/.local/share/virtualenvs/test-xnizGmtA/bin/activate

その新しいpipenv環境内にpytest-benchmarkをインストールします:

$ pipenv install pytest-benchmark
Creating a Pipfile for this project...
Installing pytest-benchmark...
Resolving pytest-benchmark...
Added pytest-benchmark to Pipfile's [packages] ...
✔ Installation Succeeded
Pipfile.lock not found, creating...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
✔ Success!
Locking [dev-packages] dependencies...
Updated Pipfile.lock (be953321071292b6175f231c7e2e835a3cd26169a0d52b7b781b344d65e8cce3)!
Installing dependencies from Pipfile.lock (e8cce3)...

これでコードのベンチマークを実行する準備が整いました。pytest game.pyを実行します:

$ pytest game.py
======================================================= test session starts ========================================================
platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0
benchmark: 4.0.0 (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: /usr/bencher/examples/python/pytest_benchmark
plugins: benchmark-4.0.0
collected 1 item
game.py . [100%]
------------------------------------------------- benchmark: 1 tests -------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
----------------------------------------------------------------------------------------------------------------------
test_game 10.5416 237.7499 10.8307 1.3958 10.7088 0.1248 191;10096 92.3304 57280 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 1.68s =========================================================

🐰 レタスをターンアップします!最初のベンチマークメトリックが得られました!

最後に、疲れた開発者の頭を休めることができます… 冗談です、ユーザーは新しい機能を望んでいます!

PythonでFizzBuzzFibonacciを書く

私たちの主要業績評価指標(KPI)が減少しているため、プロダクトマネージャー(PM)は新しい機能を追加するよう求めています。 多くのブレインストーミングと多数のユーザーインタビューの結果、 昔ながらのFizzBuzzだけでは十分ではないと決まりました。 今どきの子供たちは新しいゲーム、FizzBuzzFibonacciを望んでいます。

FizzBuzzFibonacciの規則は以下の通りです:

1から100までの整数を印刷するプログラムを書く:

  • 3の倍数にはFizzを印刷
  • 5の倍数にはBuzzを印刷
  • 三と五の倍数にはFizzBuzzを印刷
  • フィボナッチ数列の一部である数には、Fibonacciだけを印刷
  • それ以外のすべてには、その数値を印刷

フィボナッチ数列は、それぞれの数が前の二つの数の和である数列です。 例えば、01から始めると、フィボナッチ数列の次の数は1になります。 そして、それに続く数は:2, 3, 5, 8 と続きます。 フィボナッチ数列の一部である数はフィボナッチ数として知られています。なので、フィボナッチ数を検出する関数を書く必要があります。

フィボナッチ数列を書く方法はたくさんありますし、同様にフィボナッチ数を検出する方法もたくさんあります。 だから私のお気に入りを選びます:

def is_fibonacci_number(n):
for i in range(n + 1):
previous, current = 0, 1
while current < i:
next_value = previous + current
previous = current
current = next_value
if current == n:
return True
return False
  • 整数を受け取り、ブール値を返すis_fibonacci_numberという関数を作成します。
  • すべての数値を0から与えられた数値nまで含めて反復します。
  • フィボナッチ数列を01から開始し、それぞれpreviouscurrentの数字として初期化します。
  • currentの数が現在のイテレーションiより小さい間反復します。
  • previouscurrentの数字を加えてnext_valueの数字を得ます。
  • previousの数字をcurrentの数字に更新します。
  • currentの数字をnext_valueの数字に更新します。
  • currentが与えられた数値n以上になったらループを終了します。
  • currentの数が与えられた数値nと等しいか確認し、そうであればTrueを返します。
  • そうでなければ、Falseを返します。

次に、fizz_buzz関数を更新する必要があります:

def fizz_buzz_fibonacci(n):
if is_fibonacci_number(n):
return "Fibonacci"
elif n % 15 == 0:
return "FizzBuzz"
elif n % 3 == 0:
return "Fizz"
elif n % 5 == 0:
return "Buzz"
else:
return str(n)
  • fizz_buzz関数の名前をより説明的にするためにfizz_buzz_fibonacciに変更します。
  • is_fibonacci_numberヘルパー関数を呼び出します。
  • is_fibonacci_numberの結果がTrueの場合は、Fibonacciを返します。
  • is_fibonacci_numberの結果がFalseの場合は同じFizzBuzzFizzBuzz、または数字のロジックを実行して結果を返します。

fizz_buzzfizz_buzz_fibonacciに名前を変更したので、play_game関数も更新する必要があります:

def play_game(n, should_print):
result = fizz_buzz_fibonacci(n)
if should_print:
print(result)
return result

メインの実行とtest_game関数はまったく同じままです。

FizzBuzzFibonacciのベンチマーク

これでベンチマークを再度実行することができます:

$ pytest game.py
======================================================= test session starts ========================================================
platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0
benchmark: 4.0.0 (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: /usr/bencher/examples/python/pytest_benchmark
plugins: benchmark-4.0.0
collected 1 item
game.py . [100%]
--------------------------------------------------- benchmark: 1 tests --------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
-------------------------------------------------------------------------------------------------------------------------
test_game 726.9592 848.2919 735.5682 13.4925 731.4999 4.7078 146;192 1.3595 1299 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 1.97s =========================================================

ターミナル履歴をスクロールして、 FizzBuzzとFizzBuzzFibonacciゲームのパフォーマンスを目視で比較してみましょう: 10.8307 us vs 735.5682 us。 あなたの数値は私のとは少し異なるでしょう。 しかし、2つのゲームの差はおそらく50倍の範囲になると思われます。 私にはこれが良いと思います! 特に、ゲームに_Fibonacci_という響きの良い機能を追加する際には。 子供たちはそれを気に入るでしょう!

PythonでのFizzBuzzFibonacciの拡張

我々のゲームは大ヒットです!子供たちは本当にFizzBuzzFibonacciを楽しんでいます。 その人気ぶりから、経営陣からの要望で続編を求められています。 しかし、これは現代の世界です。我々は一度の購入ではなく、年間繰り返し収入(ARR)が必要です! 我々のゲームの新しいビジョンは、境界のないオープンエンド形式にすることです。1から100までの範囲内に収まっていてはいけません(たとえそれが包括的であっても)。 いいえ、私たちは新しいフロンティアへと進んでいます!

Open World FizzBuzzFibonacciのルールは次のとおりです:

以下のように、任意の 正の整数を受け取って印刷するプログラムを書きます:

  • 3の倍数の場合、Fizzを出力する
  • 5の倍数の場合、Buzzを出力する
  • 3と5の両方の倍数の場合、FizzBuzzを出力する
  • フィボナッチ数列の一部である数値は、Fibonacciのみを出力する
  • それ以外の場合は、数値を出力する

ゲームをどのような数でも動作させるために、コマンドライン引数を受け入れる必要があります。 メイン実行を次のように更新してください:

game.py
import sys
args = sys.argv
if len(args) > 1 and args[1].isdigit():
i = int(args[1])
play_game(i, True)
else:
print("Please, enter a positive integer to play...")
  • sysパッケージをインポートします。
  • コマンドラインからゲームに渡されたすべての引数(args)を収集します。
  • ゲームに渡された最初の引数を取得し、それが数字かどうかを確認します。
    • もしそうなら、最初の引数を整数としてパースし、iとします。
    • 新しくパースした整数iを使ってゲームをプレイします。
  • パースに失敗するか、または引数が渡されない場合は、有効な入力を促すデフォルトに戻ります。

これで、任意の数でゲームをプレイできます! ゲームをプレイするには、python game.pyの後に整数を入力してください:

$ python game.py 9
Fizz
$ python game.py 10
Buzz
$ python game.py 13
Fibonacci

無視するか無効な数を提供した場合:

$ python game.py
Please, enter a positive integer to play...
$ python game.py bad
Please, enter a positive integer to play...

素晴らしい、徹底的なテストでした!CIが通過しました。上司たちは大喜びです。 出荷しましょう!🚀

終わり


SpongeBob SquarePants Three Weeks Later
This is Fine meme

🐰 … あなたのキャリアの終わりかもしれない?


冗談じゃない!全てが炎上しています!🔥

最初は全てうまく行っているように見えました。 しかし、土曜日の午前2時07分に僕のページャーが鳴った:

📟 あなたのゲームが炎上しています!🔥

ベッドから飛び起き、何が起こっているのかを理解しようとしました。 ログを検索しようと試みましたが、何もかもがクラッシュし続けていて困難でした。 最終的に、問題を見つけました。その子供たち! 彼らは私たちのゲームが大好きで、最大百万までプレイしていました! ひらめきの一瞬で、新たに2つのベンチマークを追加しました:

def test_game_100(benchmark):
def run_game():
play_game(100, False)
benchmark(run_game)
def test_game_1_000_000(benchmark):
def run_game():
play_game(1_000_000, False)
benchmark(run_game)
  • 数字の百(100)でゲームをするためのマイクロベンチマークtest_game_100
  • 数字の百万(1_000_000)でゲームをするためのマイクロベンチマークtest_game_1_000_000

実行してみたところ、次のような結果が得られました:

$ pytest game.py
======================================================= test session starts ========================================================
platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0
benchmark: 4.0.0 (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: /usr/bencher/examples/python/pytest_benchmark
plugins: benchmark-4.0.0
collected 3 items
game.py ... [100%]

しばらくお待ちください…

-------------------------------------------------------------------------------------------------- benchmark: 3 tests --------------------------------------------------------------------------------------------------
Name (time in us) Min Max Mean StdDev Median IQR Outliers OPS Rounds Iterations
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_game_100 15.4166 (1.0) 112.8749 (1.0) 15.8470 (1.0) 1.1725 (1.0) 15.6672 (1.0) 0.1672 (1.0) 1276;7201 63,103.3078 (1.0) 58970 1
test_game 727.0002 (47.16) 1,074.3327 (9.52) 754.3231 (47.60) 33.2047 (28.32) 748.9999 (47.81) 33.7283 (201.76) 134;54 1,325.6918 (0.02) 1319 1
test_game_1_000_000 565,232.3328 (>1000.0) 579,829.1252 (>1000.0) 571,684.6334 (>1000.0) 6,365.1577 (>1000.0) 568,294.3747 (>1000.0) 10,454.0113 (>1000.0) 2;0 1.7492 (0.00) 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
======================================================== 3 passed in 7.01s =========================================================

何ですと! 15.8470 us x 1,00015,847.0 us になるべきところが、 571,684.6334 us ではないか 🤯 Fibonacciシーケンスのコードが機能的には正しいのに、どこかにパフォーマンス上のバグがあるに違いない。

PythonでのFizzBuzzFibonacciの修正

is_fibonacci_number 関数をもう一度見てみましょう:

def is_fibonacci_number(n):
for i in range(n + 1):
previous, current = 0, 1
while current < i:
next_value = previous + current
previous = current
current = next_value
if current == n:
return True
return False

パフォーマンスを考慮するときに、不要で余分なループがあることに気付きました。 for i in range(n + 1): ループを完全になくし、 current の値を与えられた数 (n) と比較するだけでよいのです 🤦

def is_fibonacci_number(n):
previous, current = 0, 1
while current < n:
next_value = previous + current
previous = current
current = next_value
return current == n
  • is_fibonacci_number 関数を更新します。
  • フィボナッチ数列を 01 で始め、それぞれを previouscurrent の数字として初期化します。
  • current の数字が_与えられた数_ n より小さい間、繰り返します。
  • previouscurrent の数字を加えて next_value の数字を得ます。
  • previous の数字を current の数字に更新します。
  • current の数字を next_value の数字に更新します。
  • current が与えられた数 n 以上になったら、ループを終了します。
  • current の数字が与えられた数 n と等しいか確認し、その結果を返します。

さて、それらのベンチマークを再実行して、どうなったか見てみましょう:

$ pytest game.py
======================================================= test session starts ========================================================
platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0
benchmark: 4.0.0 (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: /usr/bencher/examples/python/pytest_benchmark
plugins: benchmark-4.0.0
collected 3 items
game.py ... [100%]
------------------------------------------------------------------------------------------------ benchmark: 3 tests ------------------------------------------------------------------------------------------------
Name (time in ns) Min Max Mean StdDev Median IQR Outliers OPS (Kops/s) Rounds Iterations
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
test_game_100 309.8685 (1.0) 40,197.8614 (2.38) 322.0815 (1.0) 101.7570 (1.0) 320.2877 (1.0) 5.1805 (1.0) 321;12616 3,104.8046 (1.0) 195120 16
test_game_1_000_000 724.9881 (2.34) 16,912.4920 (1.0) 753.1445 (2.34) 121.0458 (1.19) 741.7053 (2.32) 12.4797 (2.41) 656;13698 1,327.7664 (0.43) 123073 10
test_game 26,958.9946 (87.00) 129,667.1107 (7.67) 27,448.7719 (85.22) 1,555.0003 (15.28) 27,291.9424 (85.21) 165.7754 (32.00) 479;2372 36.4315 (0.01) 25918 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
======================================================== 3 passed in 3.99s =========================================================

おお、すごい! test_gameのベンチマークが元のFizzBuzzレベルに戻りました。 具体的にどのスコアだったのか正確には思い出せませんが、3週間も経っていて、ターミナルの履歴もそこまで遡れません。 そして、pytest-benchmarkは要求した時にのみ結果を保存しますが、おそらく近いと思います!

test_game_100のベンチマークはほぼ50倍に減少し、322.0815 nsになりました。 そしてtest_game_1_000_000のベンチマークはなんと500,000倍以上も減少しました! 571,684,633.4 nsから753.1445 nsに!

🐰 おっと、少なくともこのパフォーマンスバグがプロダクションに持ち込まれる前に発見できてよかった… いや、気にしないで…

CIでパフォーマンスの後退を捕捉する

私のちょっとしたパフォーマンスのバグが原因で我々のゲームが大量の否定的なレビューを受けたことに、エクゼクティブたちは不満を持っていました。 彼らは再びそれを起こさないようにと言い、どうすれば良いのか尋ねると、ただ再びやらないようにと言われるだけでした。 どうすればそれを管理することができるのでしょうか‽

幸運なことに、Bencherという素晴らしいオープンソースツールを見つけました。 超大盤振る舞いの無料枠があるので、私の個人的なプロジェクトではBencherクラウドをただ使うことができます。 そして、仕事では全てが私たちのプライベートクラウド内にある必要があるので、Bencher Self-Hostedを使い始めました。

Bencherには組み込みのアダプターがあり、 そのためCIに簡単に統合することができます。クイックスタートガイドをフォローした後、 私は私のベンチマークを実行し、それらをBencherで追跡することができます。

$ bencher run --adapter python_pytest --file results.json "pytest --benchmark-json results.json game.py"
======================================================= test session starts ========================================================
platform darwin -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0
benchmark: 4.0.0 (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: /usr/bencher/examples/python/pytest_benchmark
plugins: benchmark-4.0.0
collected 3 items
game.py ...
...
View results:
- test_game (Latency): https://bencher.dev/console/projects/game/perf?measures=52507e04-ffd9-4021-b141-7d4b9f1e9194&branches=3a27b3ce-225c-4076-af7c-75adbc34ef9a&testbeds=bc05ed88-74c1-430d-b96a-5394fdd18bb0&benchmarks=077449e5-5b45-4c00-bdfb-3a277413180d&start_time=1697224006000&end_time=1699816009000&upper_boundary=true
- test_game_100 (Latency): https://bencher.dev/console/projects/game/perf?measures=52507e04-ffd9-4021-b141-7d4b9f1e9194&branches=3a27b3ce-225c-4076-af7c-75adbc34ef9a&testbeds=bc05ed88-74c1-430d-b96a-5394fdd18bb0&benchmarks=96508869-4fa2-44ac-8e60-b635b83a17b7&start_time=1697224006000&end_time=1699816009000&upper_boundary=true
- test_game_1_000_000 (Latency): https://bencher.dev/console/projects/game/perf?measures=52507e04-ffd9-4021-b141-7d4b9f1e9194&branches=3a27b3ce-225c-4076-af7c-75adbc34ef9a&testbeds=bc05ed88-74c1-430d-b96a-5394fdd18bb0&benchmarks=ff014217-4570-42ea-8813-6ed0284500a4&start_time=1697224006000&end_time=1699816009000&upper_boundary=true

この素敵なウサギが私にくれた便利なタイムマシンを使って、私たちがずっとBencherを使っていたらどうなっていたかを時間を遡って再現しました。 最初にバギーなFizzBuzzFibonacciの実装をプッシュしたところを見ることができます。 私のプルリクエストに対するコメントとしてCIで直ちに失敗が出ました。 その同じ日に、私はその無駄な、余分なループを取り除くことでパフォーマンスのバグを修正しました。 火事はありません。ただ幸せなユーザーたちだけです。

Bencher: 連続ベンチマーキング

🐰 Bencher

Bencherは、連続ベンチマーキングツールのスイートです。 パフォーマンスの後退があなたのユーザーに影響を与えたことはありますか? Bencherなら、それが起こるのを防げた可能性があります。 Bencherは、パフォーマンスの低下を_productionに到達する_前に検出し、防止することを可能にします。

  • 実行: お気に入りのベンチマーキングツールを使用してベンチマークをローカルまたはCIで実行します。 bencher CLIは単にあなたの既存のベンチマークハーネスをラップし、その結果を保存します。
  • 追跡: ベンチマークの結果を時間と共に追跡します。ソースブランチ、テストベッド、測定基準に基づいてBencherのWebコンソールを使用して結果を監視、クエリ、グラフ化します。
  • キャッチ: CIでパフォーマンスの後退をキャッチします。Bencherは最先端のカスタマイズ可能な分析を使用して、パフォーマンスの後退がProductionに到達する前にそれを検出します。

機能の後退を防ぐためにユニットテストがCIで実行されるのと同じ理由で、Bencherを使用してCIでベンチマークを実行してパフォーマンスの後退を防ぐべきです。パフォーマンスのバグはバグです!

CIでパフォーマンスの回帰を捉えるのを開始してください - Bencher Cloudを無料で試す

🤖 このドキュメントは OpenAI GPT-4 によって自動的に生成されました。 正確ではない可能性があり、間違いが含まれている可能性があります。 エラーを見つけた場合は、GitHub で問題を開いてください。.