前の投稿 Googleのベンチマークを使用して我々の予備の経験では、この記事では、我々は一般的な方法のGoogleのベンチマークの理解を促進します。
引用
例をテストするためにパラメータを渡します
我々は例をテストする前にのみ受け入れbenchmark::State&
、我々はそれをテストするための追加のパラメータを渡す必要がある場合は、型のパラメータを?
私たちはキューを実装する必要がある場合たとえば、リストと2つの実装オプションリンクリングバッファが存在し、そして今、私たちは、さまざまな状況での二つのプログラムのパフォーマンスをテストします:
// 必要的数据结构
#include "ring.h"
#include "linked_ring.h"
// ring buffer的测试
static void bench_array_ring_insert_int_10(benchmark::State& state)
{
auto ring = ArrayRing<int>(10);
for (auto _: state) {
for (int i = 1; i <= 10; ++i) {
ring.insert(i);
}
state.PauseTiming(); // 暂停计时
ring.clear();
state.ResumeTiming(); // 恢复计时
}
}
BENCHMARK(bench_array_ring_insert_int_10);
// linked list的测试
static void bench_linked_queue_insert_int_10(benchmark::State &state)
{
auto ring = LinkedRing<int>{};
for (auto _:state) {
for (int i = 0; i < 10; ++i) {
ring.insert(i);
}
state.PauseTiming();
ring.clear();
state.ResumeTiming();
}
}
BENCHMARK(bench_linked_queue_insert_int_10);
// 还有针对删除的测试,以及针对string的测试,都是高度重复的代码,这里不再罗列
明らかに、任意の区別なしに挿入するデータの種類と量を試験するために、上記試験に加えて、多数のパラメータを渡すことによって制御することができればより少ない反復コードを書くことができます。
時間の無駄であり、多くの場合、あなたは愚かな何かをやっている意味が重複コードを記述し、Googleのエンジニアは確かにそれに気づいているだろう。テストは受け入れることができますが、benchmark::State&
型のパラメータを、私たちは状態オブジェクトに引数を渡し、そのテストケースに取得することができます:
static void bench_array_ring_insert_int(benchmark::State& state)
{
auto length = state.range(0);
auto ring = ArrayRing<int>(length);
for (auto _: state) {
for (int i = 1; i <= length; ++i) {
ring.insert(i);
}
state.PauseTiming();
ring.clear();
state.ResumeTiming();
}
}
BENCHMARK(bench_array_ring_insert_int)->Arg(10);
上記の例では、パラメータを転送して取得する方法を示しています。
- 使用渡すパラメータ
BENCHMARK
生成対象マクロブロックArg
法 - オブジェクトに渡されたパラメータは、内部状態にすることにより、記憶された
range
取得方法、パラメーター0に対応する第一パラメータ、必要なパラメータへの着信であります
Arg
方法は一つだけで複数のパラメータを渡すしたい場合は、パラメータを渡すことができますか?また、非常に簡単です:
static void bench_array_ring_insert_int(benchmark::State& state)
{
auto ring = ArrayRing<int>(state.range(0));
for (auto _: state) {
for (int i = 1; i <= state.range(1); ++i) {
ring.insert(i);
}
state.PauseTiming();
ring.clear();
state.ResumeTiming();
}
}
BENCHMARK(bench_array_ring_insert_int)->Args({10, 10});
ない実用的な意義上記の例では、単に複数のパラメータを渡す方法を示すために、Args
方法は、ベクトルオブジェクトを受け付けるので、我々は++ 11cを使用することができるブレースを提供する初期化コードのパラメータは依然としてを介して取得簡素化state.range
、メソッドに渡された1つの対応します二番目のパラメータ。
それはあなたが追加のパラメータの他のタイプを使用したい場合は、あなたが他のいくつかの方法を見つける必要がある、我々は唯一の整数パラメータが渡され受け入れることができ、注目に値します。
テストケース同様の単純化を複数生成します
あなたが書くかもしれないパラメータを渡す方法を知った後、重複したコードを書くことなく、より多くのテストケースを生成するために、例をテストするためにパラメータを渡すの究極の目標:
static void bench_array_ring_insert_int(benchmark::State& state)
{
auto length = state.range(0);
auto ring = ArrayRing<int>(length);
for (auto _: state) {
for (int i = 1; i <= length; ++i) {
ring.insert(i);
}
state.PauseTiming();
ring.clear();
state.ResumeTiming();
}
}
// 下面我们生成测试插入10,100,1000次的测试用例
BENCHMARK(bench_array_ring_insert_int)->Arg(10);
BENCHMARK(bench_array_ring_insert_int)->Arg(100);
BENCHMARK(bench_array_ring_insert_int)->Arg(1000);
ここでは、3つの例を生成し、次のような結果が生成されます。
それは、良い仕事をしていません見えますか?
はい、結果は正しいですが、我々はそれが前に言った覚えている- 重複したコードを記述しないでください!はい、私たちは手動でユースケースを生成する上で書かれた、重複を避けるように見えました。
幸い、Arg
およびArgs
テストケースのパラメータを、我々は生成するために登録するために使用する用例名/参数
新しいテストケースを、およびへのポインタを返すBENCHMARK
だけにして、私たちはさまざまなパラメータをテストするよりも多くを生成する場合は、他の言葉で、ポインタマクロオブジェクトを生成し、チェーンは、呼び出す必要があるArg
とArgs
次のことができます。
BENCHMARK(bench_array_ring_insert_int)->Arg(10)->Arg(100)->Arg(1000);
結果及び上記と同じ。
しかし、これが最適なソリューションではありません、我々はより多くのユースケースは、作業の重複をしなければならなかっただろう必要がある場合はargはまだ、メソッドを繰り返し呼ばれます。
この点では、Googleのベンチマークはまた、溶液があります。我々は、使用することができRange
、自動的にパラメータの範囲を生成する方法を。
プロトタイプの範囲を見てみましょう:
BENCHMAEK(func)->Range(int64_t start, int64_t limit);
スタートパラメータ範囲の開始値、範囲の終了を示す限界値を示し、範囲は閉区間_ _のために作られています。
私たちは、このコードを書き換える場合でも、偽のテスト結果を取得する予定です。
BENCHMARK(bench_array_ring_insert_int)->Range(10, 1000);
なぜこれがそうですか?デフォルトに加えて、一方の基板(ベース)、デフォルトでベース8の力になり、残りのパラメータの途中で、起動して、制限範囲からだので、我々は、正方形や立方体8ある64と512を、表示されます。
この動作は、使用している限り基板をリセットすることができるよう、また、非常にシンプルで変更するRangeMultiplier
方法を:
BENCHMARK(bench_array_ring_insert_int)->RangeMultiplier(10)->Range(10, 1000);
結果は今、これまでのように復元されます。
範囲は、複数のパラメータケースを用いて処理することができます。
BENCHMARK(func)->RangeMultiplier(10)->Ranges({{10, 1000}, {128, 256}});
第2のパラメータの可能な値の第2の所定範囲(この範囲ではないことに注意)を通過しながら、最初のパラメータの指定された範囲の第1の範囲は、テストに合格しました。
次のコードと同等です:
BENCHMARK(func)->Args({10, 128})
->Args({100, 128})
->Args({1000, 128})
->Args({10, 256})
->Args({100, 256})
->Args({1000, 256})
実際直積背後からなるパラメータで生成された最初の範囲パラメータの内容で指定されました。
パラメータジェネレータを使用します
私は、より複雑なパラメータをカスタマイズしたい場合は、それを否定しませんでしたか?その後、カスタムパラメータジェネレータaを実装する必要があります。
次のように署名パラメータジェネレータ
void CustomArguments(benchmark::internal::Benchmark* b);
当社は、発電機のパラメータを計算し、次に呼び出すbenchmark::internal::Benchmark
ArgまたはArgsのは2にパラメータとして渡さとして、オブジェクトのメソッドを。
その後、我々は、使用しApply
、発電機のテストケースに適用する方法を:
BENCHMARK(func)->Apply(CustomArguments);
実際には、このプロセスの原理は複雑ではありません、私は簡単な説明を行います。
BENCHMARK
これは、マクロ生成されbenchmark::internal::Benchmark
たオブジェクトと、それへのポインタを返します- するには
benchmark::internal::Benchmark
ArgのオブジェクトなどのArgs必要なパラメータを渡します Apply
この方法の適用は、パラメータ自体に機能します- 当社は、ジェネレータを使用
benchmark::internal::Benchmark
この時刻b実際には、我々のテストケースでは、ポインタオブジェクトArgsのB通過パラメータなどを
これまでのところBuilderは上記の結論に由来し、もちろん、それがどのように動作するか、すでに明らかである、我々はより多くのことを行うために適用させることができます。
具体的な使用下記をご覧適用します。
// 这次我们生成100,200,...,1000的测试用例,用range是无法生成这些参数的
static void custom_args(benchmark::internal::Benchmark* b)
{
for (int i = 100; i <= 1000; i += 100) {
b->Arg(i);
}
}
BENCHMARK(bench_array_ring_insert_int)->RangeMultiplier(10)->Apply(custom_args);
テスト結果のカスタムパラメータ:
以上導入されたすべてのケースをテストするためにパラメータを渡すのこれまでの方法。
次に、私は非常に私たちの不必要な作業を削減するテンプレートを使用して、唯一の方法と同様の方法でテストケースであることをテストのさまざまな種類のコードの重複の一部を解決することができるパラメータを渡し、テストケースのテンプレートを作成する方法を説明します。