有時候除了測量算法的具體性能指數,咱們也會但願測試出算法的時間複雜度,以便咱們對待測試的算法的性能有一個更加直觀的瞭解。算法
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值,一樣反應了時間複雜度的誤差狀況。編譯器
運行咱們的測試:
能夠看到,自動的時間複雜度計算基本是準確的,能夠在咱們對算法進行測試時提供一個有效的參考。