继《Linux下使用gtest对接口进行单元测试》一文之后,Google还有一个实用工具:benchmark;他是基于c++11的性能测试工具,写法方面跟gtest十分类似
实践这块正好使用bm这个工具,正好结合测试了一下leveldb的读写性能,课题背景是调研leveldb单条写入的测试,后续还继续对比redis、sqlite相关性能;
首先构造一个类bm_level,与gtest类似,实现setup、teardown方法。
#include
#include
#include
#include
#include
class bm_level:
public ::benchmark::Fixture
{
public:
leveldb::DB *_db;
leveldb::Options _opt;
void SetUp(const ::benchmark::State &st)
{
leveldb::Status res;
_opt.create_if_missing = true;
res = leveldb::DB::Open(_opt, "bm2.db", &_db);
if (!res.ok()) {
printf("DB::open, %s\n", res.ToString().c_str());
}
}
void TearDown(const ::benchmark::State &)
{
delete _db;
}
};
然后构造第一个测试方法,创造一个list,然后进行增删改操作:
注意for (auto _ : state)
的地方为计时的地方。然后测试规模times
由外部获取。
BENCHMARK_DEFINE_F(bm_level, easy)(benchmark::State &state)
{
leveldb::Status res;
const int times = static_cast<int>(state.range(0));
std::list<std::pair<std::string, std::string>> list;
for (int ix = 0; ix < times; ix++) {
list.push_back(std::pair<std::string, std::string>(std::to_string(ix), std::to_string(ix)));
}
for (auto _ : state) {
for (auto &pair : list) {
res = _db->Put(leveldb::WriteOptions(), pair.first, pair.second);
if (!res.ok()) {
break;
}
}
for (auto &pair : list) {
std::string val;
res = _db->Get(leveldb::ReadOptions(), pair.first, &val);
if (!res.ok()) {
break;
}
}
for (auto &pair : list) {
res = _db->Delete(leveldb::WriteOptions(), pair.first);
if (!res.ok()) {
break;
}
}
}
}
ok基本完成,最终构建入口测试,测试规模分别从1024到32768(2^15)
BENCHMARK_REGISTER_F(bm_level, easy)->Range(1 << 10, 1 << 15);
编译需要依赖libbenchmark、libbenchmark_main :
g++ -std=c++11 bm_level.cpp -lleveldb -lbenchmark -lbenchmark_main -o bm_level -Wall -O3 -Os
Running ./bm_level
Run on (1 X 2394.45 MHz CPU )
CPU Caches:
L1 Data 32K (x1)
L1 Instruction 32K (x1)
L2 Unified 4096K (x1)
------------------------------------------------------------
Benchmark Time CPU Iterations
------------------------------------------------------------
bm_level/easy/1024 6473115 ns 5874249 ns 142
bm_level/easy/4096 24995781 ns 21576585 ns 48
bm_level/easy/32768 141431213 ns 111995007 ns 8
可见benchmark在运行过程中,将自动选择合适的迭代次数(Iterations),然后得出开销时间。
Benchmark从编程风格上比较贴近与gtest,用过gtest对bm的编码上手将比较方便。同时,测试接口也可以不局限于c++,测试c的代码也是支持的。
注意的地方是在测试用例中,某些函数会出现被编译器优化,还得加入benchmark::DoNotOptimize
操作,其他的详细用法,可以参见Benchmark官方的项目说明。