libtest benchを使用してRustコードのベンチマークを取る方法


ベンチマークとは?

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

RustでFizzBuzzを書く

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

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

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

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

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

fn main() {
for i in 1..=100 {
match (i % 3, i % 5) {
(0, 0) => println!("FizzBuzz"),
(0, _) => println!("Fizz"),
(_, 0) => println!("Buzz"),
(_, _) => println!("{i}"),
}
}
}
  • main関数を作成する
  • 1 から 100 までを含む範囲で繰り返します。
  • 各数値に対して、35 の両方で余り(除算後の余り)を計算します。
  • 2つの余りにパターンマッチを行います。 余りが 0 の場合、その数は指定された因数の倍数です。
  • 35 の両方で余りが 0 の場合は FizzBuzz を出力します。
  • 3 のみで余りが 0 の場合は Fizz を出力します。
  • 5 のみで余りが 0 の場合は Buzz を出力します。
  • それ以外の場合は、単に数字を出力します。

ステップバイステップで進める

このステップバイステップのチュートリアルを進めるには、まずRustをインストールする必要があります。

🐰 このポストのソースコードはGitHub上で利用可能です。

Rustがインストールされたら、ターミナルウィンドウを開き、次のコマンドを入力します:cargo init game

その後、新たに作成されたgameディレクトリに移動します。

game
├── Cargo.toml
└── src
└── main.rs

srcという名前のディレクトリがあり、その中にmain.rsというファイルが存在しているはずです:

fn main() {
println!("Hello, world!");
}

先ほどのFizzBuzzの実装をその内容と置き換えてから、cargo runを実行します。 出力結果は次のようになるはずです:

$ cargo run
Compiling playground v0.0.1 (/home/bencher)
Finished dev [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/game`
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
...
97
98
Fizz
Buzz

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

新たなCargo.lockファイルが生成されているはずです:

game
├── Cargo.lock
├── Cargo.toml
└── src
└── main.rs

これ以上進む前に、マイクロベンチマークとマクロベンチマークの違いについて話すことが重要です。

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

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

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

Rustにおけるベンチマーク

Rustでのベンチマークにおいて人気のあるオプションは、libtest benchCriterion、そしてIaiです。

libtestはRustの組み込みユニットテストとベンチマークフレームワークです。 Rust標準ライブラリの一部であるにもかかわらず、libtest benchはまだ不安定とされており、nightlyコンパイラリリースでのみ利用可能です。 安定バージョンのRustコンパイラで動作させるためには、別のベンチマークハーネスを使用する必要があります。 しかし、どちらも積極的に開発されているわけではありません。

Rustエコシステム内で最も人気のあるベンチマークハーネスはCriterionです。 これは安定版とnightly版の両方のRustコンパイラリリースで動作し、Rustコミュニティ内で事実上の標準として定着しています。 Criterionはlibtest benchと比べてはるかに多機能です。

Criterionの実験的な代替としてIaiがありますが、これはCriterionの作成者によって開発されたものです。 しかし、壁時計時間の代わりに命令カウントを使用します:CPU命令、L1アクセス、L2アクセス、RAMアクセスです。 これにより、これらのメトリクスはラン間でほぼ同一であるべきなので、シングルショットベンチマークが可能になります。

すべてが Bencherによってサポートされています。では、なぜlibtest benchを選ぶのでしょうか? プロジェクトの外部依存関係を制限しようとしている、またはプロジェクトがすでにnightlyツールチェインを使用している場合、 それを使用すると良いかもしれません。その他の場合、CriterionまたはIaiを使用することをお勧めします。

Rust nightly のインストール

以上を踏まえて、libtest benchを使用することにしたので、Rustツールチェーンを nightly に設定しましょう。 gameプロジェクトのルートにrust-toolchain.tomlファイルを作成し、Cargo.tomlの隣に配置します。

[toolchain]
channel = "nightly"

あなたのディレクトリ構造は次のようになる必要があります。

game
├── Cargo.lock
├── Cargo.toml
├── rust-toolchain.toml
└── src
└── main.rs

それが完了したら、cargo runを再実行します。 新しい, nightlyツールチェインのインストールに少々時間がかかるかもしれません。 その後、再実行し、以前と同じ出力を得られるはずです。

FizzBuzzのリファクタリング

FizzBuzzアプリケーションをテストするためには、ロジックをプログラムのmain関数から分離する必要があります。 ベンチマークハーネスはmain関数をベンチマークできません。

あなたのコードを下記のように更新してください:

fn main() {
for i in 1..=100 {
play_game(i);
}
}
pub fn play_game(n: u32) {
println!("{}", fizz_buzz(n));
}
pub fn fizz_buzz(n: u32) -> String {
match (n % 3, n % 5) {
(0, 0) => "FizzBuzz".to_string(),
(0, _) => "Fizz".to_string(),
(_, 0) => "Buzz".to_string(),
(_, _) => n.to_string(),
}
}

これで、コードを以下の3つの異なる関数に分割しました:

  • main: プログラムへの主なエントリーポイントで、数値の 1 から 100 まで(両方を含む)を通過し、各数値について play_game を呼び出します。
  • play_game: 符号なし整数 n を引き取り、その数値を使って fizz_buzz を呼び出し、結果を出力します。
  • fizz_buzz: 符号なし整数 n を引き取り、実際の FizzBuzzFizzBuzz、または数値のロジックを行い、結果を文字列として返します。

FizzBuzzのベンチマーク取得

安定していないlibtestクレートを使用するには、 test 機能をコードに有効にし、testクレートをインポートする必要があります。 main.rs一番上に 次の行を追加します。

#![feature(test)]
extern crate test;

これで最初のベンチマークを追加する準備が整いました! main.rs一番下に 次の行を追加します。

#[cfg(test)]
mod benchmarks {
use test::Bencher;
use super::play_game;
#[bench]
fn bench_play_game(b: &mut Bencher) {
b.iter(|| {
std::hint::black_box(for i in 1..=100 {
play_game(i)
});
});
}
}
  • benchmarksという名前のモジュールを作成し、 コンパイラ設定test modeにします。
  • ベンチマークランナーBencherをインポートします。(🐰クールな名前ですね!)
  • 私たちのplay_game関数をインポートします。
  • Bencherへの可変参照を取る、bench_play_gameという名前のベンチマークを作成します。
  • bench_play_gameがベンチマークであることを示すために、#[bench]属性を設定します。
  • Bencherのインスタンス(b)を使って、私たちのマクロベンチマークを何度も実行します。
  • コンパイラがコードを最適化しないように、私たちのマクロベンチマークを”ブラックボックス”内で実行します。
  • 1から100までを含めてイテレートします。
  • それぞれの数字で、play_gameを呼び出します。

これでコードのベンチマークを取る準備が整いました、cargo benchを実行します:

$ cargo bench
Compiling playground v0.0.1 (/home/bencher)
Finished bench [optimized] target(s) in 0.02s
Running unittests src/main.rs (target/release/deps/game-68f58c96f4025bd4)
running 1 test
test benchmarks::bench_play_game ... bench: 4,879 ns/iter (+/- 170)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in 0.68s

🐰 レティスとターニップのビート!私たちが最初のベンチマークメトリックをゲットしたよ!

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

RustでFizzBuzzFibonacciを書く

私たちの主要業績指標(KPI)が下降しているため、製品マネージャー(PM)は新機能の追加を希望しています。多くのブレインストーミングとユーザーインタビューの結果、単なるFizzBuzzだけでは足りないと判断されました。今日の子供たちは新しいゲーム、FizzBuzzFibonacciを求めています。

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

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

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

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

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

fn is_fibonacci_number(n: u32) -> bool {
for i in 0..=n {
let (mut previous, mut current) = (0, 1);
while current < i {
let next = previous + current;
previous = current;
current = next;
}
if current == n {
return true;
}
}
false
}
  • is_fibonacci_numberという名前の関数を作成し、符号なし整数を引数に取り、ブールを返します。
  • 0から我々の与えられた数nの間で全ての数値に対して反復します。
  • フィボナッチ数列を0および1から開始し、それぞれをpreviouscurrentの両方の数値とし初期化します。
  • current の数値が現在の i の反復より少ない間反復します。
  • previouscurrent の数値を加えて next の数値を取得します。
  • previous の数値を current の数値にアップデートします。
  • current の数値を next の数値にアップデートします。
  • 一度 current が与えられた数値 n と等しいかそれ以上になったら、ループを終了します。
  • current の数値が与えられた数値 n と等しいかどうか確認し、そうであれば true を返します。
  • それ以外の場合は、 false を返します。

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

pub fn fizz_buzz_fibonacci(n: u32) -> String {
if is_fibonacci_number(n) {
"Fibonacci".to_string()
} else {
match (n % 3, n % 5) {
(0, 0) => "FizzBuzz".to_string(),
(0, _) => "Fizz".to_string(),
(_, 0) => "Buzz".to_string(),
(_, _) => n.to_string(),
}
}
}
  • fizz_buzz 関数の名前を fizz_buzz_fibonacci に変更して、より説明的にします。
  • 弊社の is_fibonacci_number ヘルパー関数を呼び出します。
  • is_fibonacci_number から得た結果が true の場合は Fibonacci を返します。
  • is_fibonacci_number の結果が false の場合は、同じ FizzBuzzFizzBuzz 、または数値のロジックを実行し、結果を返します。

fizz_buzzfizz_buzz_fibonacci に変更するため、 play_game 関数も更新する必要があります:

pub fn play_game(n: u32) {
println!("{}", fizz_buzz_fibonacci(n));
}

私たちの mainbench_play_game の両関数は全く同じままで構いません。

FizzBuzzFibonacciのベンチマーク取得

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

$ cargo bench
Compiling playground v0.0.1 (/home/bencher)
Finished bench [optimized] target(s) in 0.00s
Running unittests src/main.rs (target/release/deps/game-68f58c96f4025bd4)
running 1 test
test benchmarks::bench_play_game ... bench: 22,167 ns/iter (+/- 502)
test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 0 filtered out; finished in 0.62s

私たちのターミナル履歴を戻してみると、FizzBuzzとFizzBuzzFibonacciのゲーム性能を眼球で比較できます:4,879 ns vs 22,167 ns。 あなたの数字は私のものと少し異なるかもしれません。 しかし、2つのゲーム間の差はおそらく5倍の範囲にあります。 それは私にとって良いように思えます!特に、私たちのゲームに_Fibonacci_というファンシーそうな機能を追加しているので。 子供たちはそれを愛するでしょう!

RustにてFizzBuzzFibonacciを展開

我々のゲームは大ヒットです!子供たちは確かにFizzBuzzFibonacciを遊ぶのが大好きです。 それほどに、経営陣から続編を求める声が聞こえてきました。 しかし、これは現代の世界、我々は一度きりの購入ではなく、年間定期収入(ARR)が必要です! 我々のゲームの新たなビジョンは、それがオープンエンドであり、1から100(包含)の間に生息するのではなく、新たなフロンティアへと向かうことです。

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

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

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

我々のゲームが任意の数値で動作できるようにするため、コマンドライン引数を受け取る必要があります。 main関数を以下のように更新してください:

fn main() {
let args: Vec<String> = std::env::args().collect();
let i = args
.get(1)
.map(|s| s.parse::<u32>())
.unwrap_or(Ok(15))
.unwrap_or(15);
play_game(i);
}
  • コマンドラインから我々のゲームに渡されたすべての引数(args)を収集します。
  • 我々のゲームに渡された最初の引数を取得し、それを符号なし整数iとして解析します。
  • 解析に失敗した場合、または引数が渡されない場合は、入力として15を用いて我々のゲームをデフォルトで遊びます。
  • 最後に、新たに解析した符号なし整数iで我々のゲームを遊びます。

これで我々のゲームは何の数でも遊べます! 我々のゲームに引数を渡すためにcargo runの後に--を使用してください:

$ cargo run -- 9
Compiling playground v0.0.1 (/home/bencher)
Finished dev [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/game 9`
Fizz
$ cargo run -- 10
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/game 10`
Buzz
$ cargo run -- 13
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/game 13`
Fibonacci

そして、もし我々が数字を省略したり、無効な数字が提供されたりすると:

$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target/debug/game`
FizzBuzz
$ cargo run -- bad
Finished dev [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/game bad`
FizzBuzz

うわー、それは手厚いテストだった!CIがパスします。我々の上司たちは大喜びです。 それでは、出荷しましょう! 🚀

終わり


SpongeBob SquarePants Three Weeks Later
This is Fine meme

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


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

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

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

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

#[bench]
fn bench_play_game_100(b: &mut Bencher) {
b.iter(|| std::hint::black_box(play_game(100)));
}
#[bench]
fn bench_play_game_1_000_000(b: &mut Bencher) {
b.iter(|| std::hint::black_box(play_game(1_000_000)));
}
  • ゲームを数字一百(100)で遊ぶためのマイクロベンチマークbench_play_game_100
  • ゲームを数字一百万(1_000_000)で遊ぶためのマイクロベンチマークbench_play_game_1_000_000

私がこれを実行した時、私はこれを得ました:

$ cargo bench
Compiling game v0.1.0 (/home/bencher)
Finished bench [optimized] target(s) in 0.75s
Running unittests src/main.rs (target/release/deps/game-6e1cb3355509b761)
running 3 tests
test benchmarks::bench_play_game ... bench: 22,458 ns/iter (+/- 1,508)
test benchmarks::bench_play_game_100 ... bench: 439 ns/iter (+/- 21)

待って、待って…

test benchmarks::bench_play_game_1_000_000 ... bench: 9,586,977 ns/iter (+/- 15,923)

何! 439 ns x 1,000439,000 nsであるべきで、9,586,977 nsではありません 🤯 私が私のフィボナッチ順列コードを機能的に正しく得たにもかかわらず、どこかにパフォーマンスバグがあるはずです。

RustでFizzBuzzFibonacciを修正する

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

fn is_fibonacci_number(n: u32) -> bool {
for i in 0..=n {
let (mut previous, mut current) = (0, 1);
while current < i {
let next = previous + current;
previous = current;
current = next;
}
if current == n {
return true;
}
}
false
}

パフォーマンスを考えると、不要な余分なループがあることに気づきます。 for i in 0..=n {} ループを完全に取り除き、 与えられた数値(n)と current の値を単に比較するだけで良いのです🤦

fn is_fibonacci_number(n: u32) -> bool {
let (mut previous, mut current) = (0, 1);
while current < n {
let next = previous + current;
previous = current;
current = next;
}
current == n
}
  • あなたの is_fibonacci_number関数を更新します。
  • フィボナッチ数列を 01から始める previouscurrent の数で初期化します。
  • 与えられた数 n よりも current 数が小さい間、繰り返します。
  • previouscurrentの数を足して nextの数を得ます。
  • previousの数を currentの数に更新します。
  • currentの数を nextの数に更新します。
  • currentが与えられた数 nよりも大きくなれば、ループを退出します。
  • currentの数が与えられた数 nと等しいかどうかを確認し、その結果を返します。

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

$ cargo bench
Compiling game v0.1.0 (/home/bencher)
Finished bench [optimized] target(s) in 0.75s
Running unittests src/main.rs (target/release/deps/game-6e1cb3355509b761)
running 3 tests
test benchmarks::bench_play_game ... bench: 5,570 ns/iter (+/- 390)
test benchmarks::bench_play_game_100 ... bench: 46 ns/iter (+/- 3)
test benchmarks::bench_play_game_1_000_000 ... bench: 53 ns/iter (+/- 4)
test result: ok. 0 passed; 0 failed; 0 ignored; 3 measured; 0 filtered out; finished in 9.24s

おお、素晴らしい!私たちのbench_play_gameベンチマークは、オリジナルのFizzBuzzの頃のレベルに戻っています。 そのスコアが正確に何だったか覚えていればいいのですが。それは3週間前ですからね。 私のターミナル履歴はそこまで遡っていません。 しかし、それは近いと思います!

bench_play_game_100 ベンチマークは、ほぼ10x下がりました、 439 ns から 46 nsに。 そして、bench_play_game_1_000_000 ベンチマークは10,000x以上下がりました! 9,586,977 ns から 53 nsに!

🐰 さて、少なくともこのパフォーマンスバグをプロダクションに送り出す前に見つけることができた… え? そうですね、うーん…

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

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

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

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

$ bencher run --project game "cargo bench"
Finished bench [optimized] target(s) in 0.03s
Running unittests src/main.rs (target/release/deps/game-6e1cb3355509b761)
running 3 tests
test benchmarks::bench_play_game ... bench: 5,690 ns/iter (+/- 1,091)
test benchmarks::bench_play_game_100 ... bench: 48 ns/iter (+/- 7)
test benchmarks::bench_play_game_1_000_000 ... bench: 51 ns/iter (+/- 3)
test result: ok. 0 passed; 0 failed; 0 ignored; 3 measured; 0 filtered out; finished in 2.81s
Bencher New Report:
...
View results:
- benchmarks::bench_play_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
- benchmarks::bench_play_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
- benchmarks::bench_play_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 で問題を開いてください。.