我想对这个简单的C代码进行基准测试:
float f(float x[], float y[]) {
float p = 0;
for (int i = 0; i <64; i++)
p += x[i] * y[i];
return p;
}
我的动机是尝试不同的编译器标志以及gcc和clang,看看它有什么不同。
我发现了这个test framework并且一直试图让它发挥作用。虽然我是C ++的新手,但这是我的最大努力:
#include <benchmark.h>
#include <benchmark_api.h>
#include <cstdio>
#include <random>
std::random_device seed;
std::mt19937 gen(seed());
float f(float* x, float* y) {
float p = 0;
for (int i = 0; i <64; i++) {
p += x[i] * y[i];
}
return p;
}
void f_benchmark(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(f((float*) state.range(0), (float*) state.range(1)));
}
}
void args(benchmark::internal::Benchmark* b) {
std::uniform_real_distribution<float> rand(0, 100);
for (int i = 0; i < 10; i++) {
float* x = new float[64];
float* y = new float[64];
for (int i = 0; i < 64; i++) {
x[i] = rand(gen);
y[i] = rand(gen);
printf("%f %f\n", x[i], y[i]);
}
b->Args({(int) x, (int) y});
}
}
BENCHMARK(f_benchmark)->Apply(args);
BENCHMARK_MAIN();
为了编译它我做:
g ++ -Ofast -Wall -std = c ++ 11 test.cpp -Ibenchmark / include / benchmark / -Lbenchmark / src / -o test -lbenchmark -lpthread
这给了我:
test.cpp: In function ‘void f_benchmark(benchmark::State&)’:
test.cpp:20:54: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
benchmark::DoNotOptimize(f((float*) state.range(0), (float*) state.range(1)));
[...]
test.cpp: In function ‘void args(benchmark::internal::Benchmark*)’:
test.cpp:38:20: error: cast from ‘float*’ to ‘int’ loses precision [-fpermissive]
b->Args({(int) x, (int) y});
^
[...]
我如何摆脱这些警告,一般来说,我是这样做的 正确?
答案 0 :(得分:3)
您的代码会将float*
转换为int
并返回float*
- 这可能会导致问题,因为sizeof(int)
和sizeof(float*)
无法保证相同(即在x86-64 int
上是32位,而float*
是64位!)。
您遇到此问题的原因可能是因为Args()
仅支持int
个参数(它们应该被用作一系列基准的索引,而不是您的实际函数参数功能)。要使用不同类型的参数,您可以:
:一种。使用全局变量来存储预先计算的随机数组 即。
#include <benchmark.h>
#include <benchmark_api.h>
#include <cstdio>
#include <random>
std::random_device seed;
std::mt19937 gen(seed());
float x[64*10], y[64*10];
float f(float* x, float* y) {
float p = 0;
for (int i = 0; i <64; i++) {
p += x[i] * y[i];
}
return p;
}
void f_benchmark(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(f(&x[state.range(0)*64], &y[state.range(0)*64]));
}
}
void args(benchmark::internal::Benchmark* b) {
std::uniform_real_distribution<float> rand(0, 100);
for (int i = 0; i < 64*10; i++) {
x[i] = rand(gen);
y[i] = rand(gen);
}
for (int i = 0; i < 10; ++i)
b->Arg({ i });
}
BENCHMARK(f_benchmark)->Apply(args);
BENCHMARK_MAIN();
<强> B中。计算随机数作为基准函数的一部分(选择这种方法,如果你真的需要每次迭代的不同随机值 - 时间需要暂停/恢复相应不包括随机生成/内存的时间在基准中分配) 即。
#include <benchmark.h>
#include <benchmark_api.h>
#include <cstdio>
#include <random>
std::random_device seed;
std::mt19937 gen(seed());
float f(float* x, float* y) {
float p = 0;
for (int i = 0; i <64; i++) {
p += x[i] * y[i];
}
return p;
}
void f_benchmark(benchmark::State& state) {
state.PauseTiming();
std::uniform_real_distribution<float> rand(0, 100);
float* x = new float[64];
float* y = new float[64];
while (state.KeepRunning()) {
for (int i = 0; i < 64; i++) {
x[i] = rand(gen);
y[i] = rand(gen);
}
state.ResumeTiming();
benchmark::DoNotOptimize(f(x, y));
state.PauseTiming();
}
delete[] x;
delete[] y;
}
BENCHMARK(f_benchmark)->Apply([](benchmark::internal::Benchmark* b){
for (int i = 0; i < 10; ++i)
b->Arg({ i });
});
BENCHMARK_MAIN();
附注:同时注意for
循环中的泄漏内存 - 您应该为每个delete[]
运算符调用new[]
运算符一次。