// 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 #include #include #include #include "../src/sfizz/Range.h" #include #include 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 distFloat { 0.1f, 1.0f }; std::uniform_int_distribution distInt { 1, maxCC }; floats = std::vector(state.range(0)); ccs = std::vector(state.range(0)); ranges = std::vector>(state.range(0)); absl::c_generate(floats, [&]() { return distFloat(gen); }); absl::c_generate(ccs, [&]() { return distInt(gen); }); absl::c_generate(ranges, [&]() { return sfz::Range(distInt(gen), distInt(gen)); }); } void TearDown(const ::benchmark::State& /* state */) { } std::vector ccs; std::vector> ranges; std::vector floats; }; template struct CCValuePair { int cc; ValueType value; }; template struct CCValuePairComparator { bool operator()(const CCValuePair& valuePair, const int& cc) { return (valuePair.cc < cc); } bool operator()(const int& cc, const CCValuePair& valuePair) { return (cc < valuePair.cc); } bool operator()(const CCValuePair& lhs, const CCValuePair& rhs) { return (lhs.cc < rhs.cc); } }; template struct CCValuePairComparator { bool operator()(const CCValuePair& valuePair, const ValueType& value) { return (valuePair.value < value); } bool operator()(const ValueType& value, const CCValuePair& valuePair) { return (value < valuePair.value); } bool operator()(const CCValuePair& lhs, const CCValuePair& rhs) { return (lhs.value < rhs.value); } }; template 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{}); 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{}); 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{}); } typename std::vector>::const_iterator begin() const { return container.cbegin(); } typename std::vector>::const_iterator end() const { return container.cend(); } private: // typename std::vector>::iterator begin() { return container.begin(); } // typename std::vector>::iterator end() { return container.end(); } const ValueType defaultValue; std::vector> container; }; BENCHMARK_DEFINE_F(MyFixture, FillVector_Float) (benchmark::State& state) { for (auto _ : state) { CCMap 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> map { sfz::Range(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 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> 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 output; output.resize(state.range(0)); std::vector 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> output; output.resize(state.range(0)); std::vector> 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 output; output.resize(state.range(0)); CCMap 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> output; output.resize(state.range(0)); CCMap> map { sfz::Range(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 output; output.resize(state.range(0)); absl::flat_hash_map 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> output; output.resize(state.range(0)); absl::flat_hash_map> 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 output; output.reserve(maxCC); CCMap 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 output; output.reserve(maxCC); absl::flat_hash_map 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();