如何使用 google 基准测试自定义界面
How to benchmark custom interface using google benchmark
因为除了 github 自述文件中的内容之外,我找不到真正好的资源或文档,所以我会在这里询问社区。
假设我有一个名为 Base
的接口和多个派生类型。
我想用相同的函数和传递给 Foo
.
的相同参数对所有派生类型的虚函数 Foo
进行基准测试
对于每个派生类型,我想在单个基准测试中多次调用 Foo
,并使用从 std::vector<std::size_t>
.
传递的不同参数
我的一些派生类型的构造函数也需要额外的参数,我应该如何处理?
在我看来,最简单的做法是使用模板化基准并传递给:
const std::vector<std::size_t> v {1, 2, 4, 8, 16};
BENCHMARK_TEMPLATE(func, Derived1, v);
BENCHMARK_TEMPLATE(func, Derived2, v);
BENCHMARK_TEMPLATE(func, Derived3, v);
...
我认为这不是正确的方法,因为对于具有不同构造函数签名的每个派生类型,我需要具有不同的基准函数,这几乎与前一个相同。
对此进行基准测试的正确方法是什么?
**更新*:
我的解决方法如下:
std::unique_ptr<Base> GetObj(const std::size_t index)
{
switch(index)
{
case 0:
return std::make_unique<Derived1>(...);
case 1:
return std::make_unique<Derived2>(...);
...
}
}
void func(benchmark::State& state)
{
auto r = state.range();
auto object = GetObj(r);
for (auto _ : state)
{
...
}
}
BENCHMARK(func)->DenseRange(0,5);
但我不喜欢的是基准测试的名称是 func/0-5
模式,我希望它是 func/Derived1
、func/Derived2
和等等..有什么想法可以实现吗?
您的方法非常正确。如果您想避免使用多个基准测试函数,请将基准测试的核心移动到一个单独的函数中,并从每个类型的函数中调用它。类似于:
static void Benchmark(Base* b, benchmark::State& st) {
for (auto _ : state) {
b->DoTheThing()
}
}
void BM_Foo(benchmark::State& st) {
Foo f;
Benchmark(&f, st);
}
BENCHMARK(BM_Foo);
如果你想更复杂一些,可以使用RegisterBenchmark
功能来更灵活地注册东西。类似于:
auto BM_base = [](benchmark::State& st, auto inputs, Base* b) { /* ... */ };
int main(int argc, char**argv) {
const std::vector<std::size_t> v = {1, 2, 4, 8, 16};
benchmark::RegisterBenchmark("foo", BM_base, v, new Foo());
benchmark::Initialize(&argc, argv);
return benchmark::RunSpecifiedBenchmarks();
}
顺便说一句,注册基准时v应该设置为Arg
s吗?
因为除了 github 自述文件中的内容之外,我找不到真正好的资源或文档,所以我会在这里询问社区。
假设我有一个名为 Base
的接口和多个派生类型。
我想用相同的函数和传递给 Foo
.
的相同参数对所有派生类型的虚函数 Foo
进行基准测试
对于每个派生类型,我想在单个基准测试中多次调用 Foo
,并使用从 std::vector<std::size_t>
.
我的一些派生类型的构造函数也需要额外的参数,我应该如何处理?
在我看来,最简单的做法是使用模板化基准并传递给:
const std::vector<std::size_t> v {1, 2, 4, 8, 16};
BENCHMARK_TEMPLATE(func, Derived1, v);
BENCHMARK_TEMPLATE(func, Derived2, v);
BENCHMARK_TEMPLATE(func, Derived3, v);
...
我认为这不是正确的方法,因为对于具有不同构造函数签名的每个派生类型,我需要具有不同的基准函数,这几乎与前一个相同。
对此进行基准测试的正确方法是什么?
**更新*: 我的解决方法如下:
std::unique_ptr<Base> GetObj(const std::size_t index)
{
switch(index)
{
case 0:
return std::make_unique<Derived1>(...);
case 1:
return std::make_unique<Derived2>(...);
...
}
}
void func(benchmark::State& state)
{
auto r = state.range();
auto object = GetObj(r);
for (auto _ : state)
{
...
}
}
BENCHMARK(func)->DenseRange(0,5);
但我不喜欢的是基准测试的名称是 func/0-5
模式,我希望它是 func/Derived1
、func/Derived2
和等等..有什么想法可以实现吗?
您的方法非常正确。如果您想避免使用多个基准测试函数,请将基准测试的核心移动到一个单独的函数中,并从每个类型的函数中调用它。类似于:
static void Benchmark(Base* b, benchmark::State& st) {
for (auto _ : state) {
b->DoTheThing()
}
}
void BM_Foo(benchmark::State& st) {
Foo f;
Benchmark(&f, st);
}
BENCHMARK(BM_Foo);
如果你想更复杂一些,可以使用RegisterBenchmark
功能来更灵活地注册东西。类似于:
auto BM_base = [](benchmark::State& st, auto inputs, Base* b) { /* ... */ };
int main(int argc, char**argv) {
const std::vector<std::size_t> v = {1, 2, 4, 8, 16};
benchmark::RegisterBenchmark("foo", BM_base, v, new Foo());
benchmark::Initialize(&argc, argv);
return benchmark::RunSpecifiedBenchmarks();
}
顺便说一句,注册基准时v应该设置为Arg
s吗?