From e8895fee11d09c570e5be54a6f0e2d6902b74241 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Wed, 28 Nov 2018 19:54:29 -0800 Subject: [PATCH] Add a binary search benchmark this one basically shows that the stl is is a good as our "branch less" versions. this is because clang generate branchless code in the end. --- libs/utils/CMakeLists.txt | 1 + .../benchmark/benchmark_binary_search.cpp | 164 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 libs/utils/benchmark/benchmark_binary_search.cpp diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index f1c0873954..d3f886c7cf 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -128,6 +128,7 @@ add_library(benchmark_${TARGET}_callee SHARED benchmark/benchmark_callee.cpp) set(BENCHMARK_SRCS benchmark/benchmark_allocators.cpp + benchmark/benchmark_binary_search.cpp benchmark/benchmark_calls.cpp benchmark/benchmark_mutex.cpp benchmark/benchmark_memcpy.cpp) diff --git a/libs/utils/benchmark/benchmark_binary_search.cpp b/libs/utils/benchmark/benchmark_binary_search.cpp new file mode 100644 index 0000000000..110a9c4088 --- /dev/null +++ b/libs/utils/benchmark/benchmark_binary_search.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PerformanceCounters.h" + +#include +#include + +#include + +#include +#include +#include + +using namespace utils; + + +class BinarySearch : public benchmark::Fixture { +public: + BinarySearch(); + ~BinarySearch() override; + +protected: + using value_type = uint64_t; + std::vector data; + std::default_random_engine gen{123}; + std::uniform_int_distribution nd; + + std::vector prepareItems(size_t size); +}; + +BinarySearch::BinarySearch() { + data.resize(2<<20); + std::generate(data.begin(), data.end(), [&](){ return nd(gen); }); + std::sort(data.begin(), data.end()); +} + +BinarySearch::~BinarySearch() = default; + +UTILS_NOINLINE +std::vector BinarySearch::prepareItems(size_t size) { + auto first = data.begin(); + auto last = data.begin() + size; + std::vector indices(last - first); + std::copy(first, last, indices.begin()); + std::default_random_engine gen{123}; + std::shuffle(indices.begin(), indices.end(), gen); + return indices; +} + +BENCHMARK_DEFINE_F(BinarySearch, linearSearch)(benchmark::State& state) { + auto first = data.begin(); + auto last = data.begin() + state.range(0); + std::vector indices = prepareItems(state.range(0)); + value_type const* ip = indices.data(); + size_t i = 0; + + { + PerformanceCounters pc(state); + for (auto _ : state) { + auto item = ip[i++ % state.range(0)]; + auto const& pos = std::find(first, last, item); + benchmark::DoNotOptimize(pos); + } + } +} + +BENCHMARK_DEFINE_F(BinarySearch, stdLowerBound)(benchmark::State& state) { + auto first = data.begin(); + auto last = data.begin() + state.range(0); + std::vector indices = prepareItems(state.range(0)); + value_type const* ip = indices.data(); + size_t i = 0; + + { + PerformanceCounters pc(state); + for (auto _ : state) { + auto item = ip[i++ % state.range(0)]; + auto const& pos = std::lower_bound(first, last, item); + benchmark::DoNotOptimize(pos); + } + } +} + +BENCHMARK_DEFINE_F(BinarySearch, utilsLowerBound)(benchmark::State& state) { + auto first = data.begin(); + auto last = data.begin() + state.range(0); + std::vector indices = prepareItems(state.range(0)); + value_type const* ip = indices.data(); + size_t i = 0; + + { + PerformanceCounters pc(state); + for (auto _ : state) { + auto item = ip[i++ % state.range(0)]; + auto const& pos = utils::lower_bound(first, last, item); + benchmark::DoNotOptimize(pos); + } + } +} + +BENCHMARK_DEFINE_F(BinarySearch, utilsLowerBoundPOT)(benchmark::State& state) { + auto first = data.begin(); + auto last = data.begin() + state.range(0); + std::vector indices = prepareItems(state.range(0)); + value_type const* ip = indices.data(); + size_t i = 0; + + { + PerformanceCounters pc(state); + for (auto _ : state) { + auto item = ip[i++ % state.range(0)]; + auto const& pos = utils::lower_bound(first, last, item, {}, true); + benchmark::DoNotOptimize(pos); + } + } +} + +BENCHMARK_DEFINE_F(BinarySearch, utilsLowerBound4096)(benchmark::State& state) { + auto first = data.begin(); + auto last = data.begin() + 4096; + std::vector indices = prepareItems(4096); + value_type const* ip = indices.data(); + size_t i = 0; + + { + PerformanceCounters pc(state); + for (auto _ : state) { + auto item = ip[i++ % 4096]; + auto const& pos = utils::lower_bound(first, last, item, {}, true); + benchmark::DoNotOptimize(pos); + } + } +} + +BENCHMARK_REGISTER_F(BinarySearch, linearSearch)->Range(2, 1<<20); +BENCHMARK_REGISTER_F(BinarySearch, stdLowerBound)->Range(2, 1<<20); +BENCHMARK_REGISTER_F(BinarySearch, utilsLowerBound)->Range(2, 1<<20); +BENCHMARK_REGISTER_F(BinarySearch, utilsLowerBoundPOT) + ->Arg(2) + ->Arg(4) + ->Arg(16) + ->Arg(32) + ->Arg(64) + ->Arg(256) + ->Arg(4096) + ->Arg(32768) + ->Arg(262144) + ->Arg(1048576); + +BENCHMARK_REGISTER_F(BinarySearch, utilsLowerBound4096);