有时候除了测量算法的具体性能指数,咱们也会但愿测试出算法的时间复杂度,以便咱们对待测试的算法的性能有一个更加直观的了解。算法
google benchmark已经为咱们提供了相似的功能,并且使用至关简单。函数
具体的解释在后面,咱们先来看几个例子,咱们人为制造几个时间复杂度分别为O(n)
, O(logn)
, O(n^n)
的测试用例:性能
// 这里都是为了演示而写成的代码,没有什么实际意义 static void bench_N(benchmark::State& state) { int n = 0; for ([[maybe_unused]] auto _ : state) { for (int i = 0; i < state.range(0); ++i) { benchmark::DoNotOptimize(n += 2); // 这个函数防止编译器将表达式优化,会略微下降一些性能 } } state.SetComplexityN(state.range(0)); } BENCHMARK(bench_N)->RangeMultiplier(10)->Range(10, 1000000)->Complexity(); static void bench_LogN(benchmark::State& state) { int n = 0; for ([[maybe_unused]] auto _ : state) { for (int i = 1; i < state.range(0); i *= 2) { benchmark::DoNotOptimize(n += 2); } } state.SetComplexityN(state.range(0)); } BENCHMARK(bench_LogN)->RangeMultiplier(10)->Range(10, 1000000)->Complexity(); static void bench_Square(benchmark::State& state) { int n = 0; auto len = state.range(0); for ([[maybe_unused]] auto _ : state) { for (int64_t i = 1; i < len*len; ++i) { benchmark::DoNotOptimize(n += 2); } } state.SetComplexityN(len); } BENCHMARK(bench_Square)->RangeMultiplier(10)->Range(10, 100000)->Complexity();
如何传递参数和生成批量测试咱们在上一篇已经介绍过了,这里再也不重复。测试
须要关注的是新出现的state.SetComplexityN
和Complexity
。优化
首先是state.SetComplexityN
,参数是一个64位整数,用来表示算法整体须要处理的数据总量。benchmark会根据这个数值,再加上运行耗时以及state
的迭代次数计算出一个用于后面预估平均时间复杂度的值。google
Complexity
会根据同一组的多个测试用例计算出一个较接近的平均时间复杂度和一个均方根值,须要和state.SetComplexityN
配合使用。code
Complexity
还有一个参数,能够接受一个函数或是benchmark::BigO
枚举,它的做用是提示benchmark该测试用例的时间复杂度,默认值为benchmark::oAuto
,测试中会自动帮咱们计算出时间复杂度。对于较为复杂的算法,而咱们又有预期的时间按复杂度,这时咱们就能够将其传给这个方法,好比对于第二个测试用例,咱们还能够这样写:blog
static void bench_LogN(benchmark::State& state) { // 中间部分与前面同样,略过 } BENCHMARK(bench_LogN)->RangeMultiplier(10)->Range(10, 1000000)->Complexity(benchmark::oLogN);
在选择正确的提示后对测试结果几乎没有影响,除了误差值能够降得更低,使结果更准确。ip
Complexity
在计算时间复杂度时会保留复杂度的系数,所以,若是咱们发现给出的提示的时间复杂度前的系数过大的话,就意味着咱们的预估发生了较大的误差,同时它还会计算出RMS值,一样反应了时间复杂度的误差状况。编译器
运行咱们的测试:
能够看到,自动的时间复杂度计算基本是准确的,能够在咱们对算法进行测试时提供一个有效的参考。