Added a benchmark for maps
This commit is contained in:
parent
3046c2393f
commit
2e020cb213
2 changed files with 352 additions and 0 deletions
350
benchmarks/BM_maps.cpp
Normal file
350
benchmarks/BM_maps.cpp
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include "../src/sfizz/Range.h"
|
||||
#include <absl/container/flat_hash_map.h>
|
||||
#include <absl/algorithm/container.h>
|
||||
|
||||
constexpr int maxCC { 256 };
|
||||
|
||||
class MyFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state)
|
||||
{
|
||||
std::random_device rd {};
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> distFloat { 0.1f, 1.0f };
|
||||
std::uniform_int_distribution<int> distInt { 1, maxCC };
|
||||
floats = std::vector<float>(state.range(0));
|
||||
ccs = std::vector<int>(state.range(0));
|
||||
ranges = std::vector<sfz::Range<int>>(state.range(0));
|
||||
absl::c_generate(floats, [&]() {
|
||||
return distFloat(gen);
|
||||
});
|
||||
absl::c_generate(ccs, [&]() {
|
||||
return distInt(gen);
|
||||
});
|
||||
absl::c_generate(ranges, [&]() {
|
||||
return sfz::Range<int>(distInt(gen), distInt(gen));
|
||||
});
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state [[maybe_unused]])
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<int> ccs;
|
||||
std::vector<sfz::Range<int>> ranges;
|
||||
std::vector<float> floats;
|
||||
};
|
||||
|
||||
template<class ValueType>
|
||||
struct CCValuePair {
|
||||
int cc;
|
||||
ValueType value;
|
||||
};
|
||||
|
||||
template<class ValueType, bool CompareValue = false>
|
||||
struct CCValuePairComparator {
|
||||
bool operator()(const CCValuePair<ValueType>& valuePair, const int& cc)
|
||||
{
|
||||
return (valuePair.cc < cc);
|
||||
}
|
||||
|
||||
bool operator()(const int& cc, const CCValuePair<ValueType>& valuePair)
|
||||
{
|
||||
return (cc < valuePair.cc);
|
||||
}
|
||||
|
||||
bool operator()(const CCValuePair<ValueType>& lhs, const CCValuePair<ValueType>& rhs)
|
||||
{
|
||||
return (lhs.cc < rhs.cc);
|
||||
}
|
||||
};
|
||||
|
||||
template<class ValueType>
|
||||
struct CCValuePairComparator<ValueType, true> {
|
||||
bool operator()(const CCValuePair<ValueType>& valuePair, const ValueType& value)
|
||||
{
|
||||
return (valuePair.value < value);
|
||||
}
|
||||
|
||||
bool operator()(const ValueType& value, const CCValuePair<ValueType>& valuePair)
|
||||
{
|
||||
return (value < valuePair.value);
|
||||
}
|
||||
|
||||
bool operator()(const CCValuePair<ValueType>& lhs, const CCValuePair<ValueType>& rhs)
|
||||
{
|
||||
return (lhs.value < rhs.value);
|
||||
}
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
class CCMap {
|
||||
public:
|
||||
CCMap() = delete;
|
||||
/**
|
||||
* @brief Construct a new CCMap object with the specified default value.
|
||||
*
|
||||
* @param defaultValue
|
||||
*/
|
||||
CCMap(const ValueType& defaultValue)
|
||||
: defaultValue(defaultValue)
|
||||
{
|
||||
}
|
||||
CCMap(CCMap&&) = default;
|
||||
CCMap(const CCMap&) = default;
|
||||
~CCMap() = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the held object at the index, or a default value if not present
|
||||
*
|
||||
* @param index
|
||||
* @return const ValueType&
|
||||
*/
|
||||
const ValueType& getWithDefault(int index) const noexcept
|
||||
{
|
||||
auto it = absl::c_lower_bound(container, index, CCValuePairComparator<ValueType>{});
|
||||
if (it == container.end() || it->cc != index) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return it->value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the value at index or emplace a new one if not present
|
||||
*
|
||||
* @param index the index of the element
|
||||
* @return ValueType&
|
||||
*/
|
||||
ValueType& operator[](const int& index) noexcept
|
||||
{
|
||||
auto it = absl::c_lower_bound(container, index, CCValuePairComparator<ValueType>{});
|
||||
if (it == container.end() || it->cc != index) {
|
||||
auto inserted = container.insert(it, { index, defaultValue });
|
||||
return inserted->value;
|
||||
} else {
|
||||
return it->value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Is the container empty
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
inline bool empty() const { return container.empty(); }
|
||||
/**
|
||||
* @brief Returns true if the container containers an element at index
|
||||
*
|
||||
* @param index
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool contains(int index) const noexcept
|
||||
{
|
||||
return absl::c_binary_search(container, index, CCValuePairComparator<ValueType>{});
|
||||
}
|
||||
typename std::vector<CCValuePair<ValueType>>::const_iterator begin() const { return container.cbegin(); }
|
||||
typename std::vector<CCValuePair<ValueType>>::const_iterator end() const { return container.cend(); }
|
||||
private:
|
||||
// typename std::vector<std::pair<int, ValueType>>::iterator begin() { return container.begin(); }
|
||||
// typename std::vector<std::pair<int, ValueType>>::iterator end() { return container.end(); }
|
||||
|
||||
const ValueType defaultValue;
|
||||
std::vector<CCValuePair<ValueType>> container;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, FillVector_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
CCMap<float> map { 0 };
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = floats[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, FillVector_Range)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
CCMap<sfz::Range<int>> map { sfz::Range<int>(0, 127) };
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = ranges[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, FillAbseilFlatHM_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
absl::flat_hash_map<int, float> map;
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = floats[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, FillAbseilFlatHM_Range)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
absl::flat_hash_map<int, sfz::Range<int>> map;
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = ranges[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, LookupBaseline_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<float> output;
|
||||
output.resize(state.range(0));
|
||||
|
||||
std::vector<float> map;
|
||||
output.reserve(state.range(0));
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map.push_back(floats[i]);
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = map[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, LookupBaseline_Range)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<sfz::Range<int>> output;
|
||||
output.resize(state.range(0));
|
||||
|
||||
std::vector<sfz::Range<int>> map;
|
||||
output.reserve(state.range(0));
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map.push_back(ranges[i]);
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = map[i];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, LookupVector_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<float> output;
|
||||
output.resize(state.range(0));
|
||||
|
||||
CCMap<float> map { 0 };
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = floats[i];
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = map[ccs[i]];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, LookupVector_Range)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<sfz::Range<int>> output;
|
||||
output.resize(state.range(0));
|
||||
|
||||
CCMap<sfz::Range<int>> map { sfz::Range<int>(0, 127) };
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = ranges[i];
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = map[ccs[i]];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, LookupAbseilFlatHM_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<float> output;
|
||||
output.resize(state.range(0));
|
||||
|
||||
absl::flat_hash_map<int, float> map;
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = floats[i];
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = map[ccs[i]];
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, LookupAbseilFlatHM_Range)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<sfz::Range<int>> output;
|
||||
output.resize(state.range(0));
|
||||
|
||||
absl::flat_hash_map<int, sfz::Range<int>> map;
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = ranges[i];
|
||||
|
||||
for (auto _ : state) {
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
output[i] = map[ccs[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, IterateVector_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<float> output;
|
||||
output.reserve(maxCC);
|
||||
|
||||
CCMap<float> map { 0 };
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = floats[i];
|
||||
|
||||
for (auto _ : state) {
|
||||
for (auto& pair: map)
|
||||
output.push_back(pair.value);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(MyFixture, IterateAbseilFlatHM_Float)
|
||||
(benchmark::State& state)
|
||||
{
|
||||
std::vector<float> output;
|
||||
output.reserve(maxCC);
|
||||
|
||||
absl::flat_hash_map<int, float> map;
|
||||
for (int i = 0; i < state.range(0); ++i)
|
||||
map[ccs[i]] = floats[i];
|
||||
for (auto _ : state) {
|
||||
for (auto& pair: map)
|
||||
output.push_back(pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK_REGISTER_F(MyFixture, FillVector_Float)->RangeMultiplier(2)->Range(16, 512);
|
||||
// BENCHMARK_REGISTER_F(MyFixture, FillVector_Range)->RangeMultiplier(2)->Range(16, 512);
|
||||
BENCHMARK_REGISTER_F(MyFixture, FillAbseilFlatHM_Float)->RangeMultiplier(2)->Range(16, 512);
|
||||
// BENCHMARK_REGISTER_F(MyFixture, FillAbseilFlatHM_Range)->RangeMultiplier(2)->Range(16, 512);
|
||||
BENCHMARK_REGISTER_F(MyFixture, LookupBaseline_Float)->RangeMultiplier(2)->Range(16, 512);
|
||||
// BENCHMARK_REGISTER_F(MyFixture, LookupBaseline_Range)->RangeMultiplier(2)->Range(16, 512);
|
||||
BENCHMARK_REGISTER_F(MyFixture, LookupVector_Float)->RangeMultiplier(2)->Range(16, 512);
|
||||
// BENCHMARK_REGISTER_F(MyFixture, LookupVector_Range)->RangeMultiplier(2)->Range(16, 512);
|
||||
BENCHMARK_REGISTER_F(MyFixture, LookupAbseilFlatHM_Float)->RangeMultiplier(2)->Range(16, 512);
|
||||
// BENCHMARK_REGISTER_F(MyFixture, LookupAbseilFlatHM_Range)->RangeMultiplier(2)->Range(16, 512);
|
||||
BENCHMARK_REGISTER_F(MyFixture, IterateVector_Float)->Range(maxCC, maxCC);
|
||||
BENCHMARK_REGISTER_F(MyFixture, IterateAbseilFlatHM_Float)->Range(maxCC, maxCC);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -58,6 +58,8 @@ sfizz_add_benchmark(bm_diff BM_diff.cpp)
|
|||
sfizz_add_benchmark(bm_widthPos BM_widthPos.cpp)
|
||||
sfizz_add_benchmark(bm_interpolationCast BM_interpolationCast.cpp)
|
||||
sfizz_add_benchmark(bm_pointerIterationOrOffsets BM_pointerIterationOrOffsets.cpp)
|
||||
sfizz_add_benchmark(bm_maps BM_maps.cpp)
|
||||
target_link_libraries(bm_maps PRIVATE absl::flat_hash_map)
|
||||
|
||||
sfizz_add_benchmark(bm_logger BM_logger.cpp)
|
||||
target_link_libraries(bm_logger PRIVATE sfizz::sfizz)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue