This is an automated email from the ASF dual-hosted git repository. pnoltes pushed a commit to branch feature/674-use-properties-type-in-filter in repository https://gitbox.apache.org/repos/asf/celix.git
commit ad41008378fcbc920b8a2a0badae612c5aa573d5 Author: Pepijn Noltes <[email protected]> AuthorDate: Sun Nov 19 16:38:01 2023 +0100 Add Filter benchmark --- libs/utils/benchmark/CMakeLists.txt | 7 + libs/utils/benchmark/src/FilterBenchmark.cc | 209 ++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) diff --git a/libs/utils/benchmark/CMakeLists.txt b/libs/utils/benchmark/CMakeLists.txt index 81892af9..2f891e6c 100644 --- a/libs/utils/benchmark/CMakeLists.txt +++ b/libs/utils/benchmark/CMakeLists.txt @@ -40,4 +40,11 @@ if (UTILS_BENCHMARK) target_link_libraries(celix_long_hashmap_benchmark PRIVATE Celix::utils benchmark::benchmark) target_compile_options(celix_long_hashmap_benchmark PRIVATE -Wno-unused-function) celix_deprecated_utils_headers(celix_long_hashmap_benchmark) + + add_executable(celix_filter_benchmark + src/BenchmarkMain.cc + src/FilterBenchmark.cc + ) + target_link_libraries(celix_filter_benchmark PRIVATE Celix::utils benchmark::benchmark) + target_compile_options(celix_filter_benchmark PRIVATE -Wno-unused-function) endif () diff --git a/libs/utils/benchmark/src/FilterBenchmark.cc b/libs/utils/benchmark/src/FilterBenchmark.cc new file mode 100644 index 00000000..43b4cdef --- /dev/null +++ b/libs/utils/benchmark/src/FilterBenchmark.cc @@ -0,0 +1,209 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 <benchmark/benchmark.h> +#include <memory> +#include <iostream> +#include <random> +#include <climits> + +#include "celix/Filter.h" +#include "celix/Properties.h" +#include "celix_properties_internal.h" + +class FilterBenchmark { +public: + explicit FilterBenchmark(benchmark::State& state) : props{createTestProperties()} { + int64_t additionalPropertyEntries = state.range(0); + fillProperties(additionalPropertyEntries); + } + + static celix::Properties createTestProperties() { + celix::Properties props{}; + props.set("str_key1", "str_value1"); + props.set("long_key1", 1L); + props.set("double_key1", 1.0); + props.set("bool_key1", true); + props.set("version_key1", celix::Version{1,2,3}); + props.set("version_key2", celix::Version{1,2,3, "qualifier"}); + return props; + } + + void testFilter(benchmark::State& state, const celix::Filter& filter, bool expectedMatch) { + for (auto _ : state) { + // This code gets timed + auto match = filter.match(props); + if (match != expectedMatch) { + std::cerr << "ERROR: unexpected match result" << std::endl; + } + } + addStateCounters(state); + } + + void testCFilter(benchmark::State& state, const celix::Filter& filter, bool expectedMatch) { + auto* cFilter = filter.getCFilter(); + auto* cProps = props.getCProperties(); + for (auto _ : state) { + // This code gets timed + auto match = celix_filter_match(cFilter, cProps); + if (match != expectedMatch) { + std::cerr << "ERROR: unexpected match result" << std::endl; + } + + } + addStateCounters(state); + } + + void addStateCounters(benchmark::State& state) { + state.SetItemsProcessed(state.iterations()); + auto stats = celix_properties_getStatistics(props.getCProperties()); + //state.counters["nrOfProperties"] = (double)stats.mapStatistics.nrOfEntries; + //state.counters["nrOfBuckets"] = (double)stats.mapStatistics.nrOfBuckets; + //state.counters["resizeCount"] = (double)stats.mapStatistics.resizeCount; + //state.counters["averageNrOfEntriesPerBucket"] = stats.mapStatistics.averageNrOfEntriesPerBucket; + //state.counters["stdDeviationNrOfEntriesPerBucket"] = stats.mapStatistics.stdDeviationNrOfEntriesPerBucket; + //state.counters["averageSizeOfKeysAndStringValues"] = (double)stats.averageSizeOfKeysAndStringValues; + //state.counters["sizeOfKeysAndStringValues"] = (double)stats.sizeOfKeysAndStringValues; + state.counters["fillStringOptimizationBufferPercentage"] = stats.fillStringOptimizationBufferPercentage; + state.counters["fillEntriesOptimizationBufferPercentage"] = stats.fillEntriesOptimizationBufferPercentage; + } + + std::string randomString() { + std::string result{}; + int len = lenDistribution(generator); + result.reserve(len); + for (int i = 0; i < len-1; ++i) { + result[i] = (char)charDistribution(generator); + } + result[len-1] = '\0'; + return result; + } + + void fillProperties(int64_t additionalPropertyEntries) { + for (auto i = 0; i < additionalPropertyEntries; ++i) { + props.set(randomString(), randomString()); + } + } + + private: + celix::Properties props{}; + + const int MAX_LEN = 100; + std::default_random_engine generator{}; + std::uniform_int_distribution<int> lenDistribution{2,MAX_LEN}; + std::uniform_int_distribution<int> charDistribution{'a','z'}; +}; + +static void FilterBenchmark_testStringCFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(str_key1=str_value1)"}; + benchmark.testCFilter(state, filter, true); +} + +static void FilterBenchmark_testStringFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(str_key1=str_value1)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testStringGreaterEqualFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(str_key1>=str_value)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testLongFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(long_key1=1)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testLongGreaterEqualFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(long_key1>=1)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testDoubleGreaterEqualFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(double_key1>=0.9)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testBoolFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(bool_key1=true)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testVersionFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(version_key1=1.2.3)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_testVersionWithQualifierFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(version_key2=1.2.3.qualifier)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_versionGreaterEqualFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(version_key1>=1.0.0)"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_versionRangeFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(&(version_key1>=1.0.0)(version_key1<2.0.0))"}; + benchmark.testFilter(state, filter, true); +} + +static void FilterBenchmark_complexFilter(benchmark::State& state) { + FilterBenchmark benchmark{state}; + celix::Filter filter{"(&(version_key1>=1.0.0)(version_key1<2.0.0)(str_key1=str_value1)(long_key1=1)(double_key1>=0." + "9)(bool_key1=true))"}; + benchmark.testFilter(state, filter, true); +} + +#define CELIX_BENCHMARK(name) \ + BENCHMARK(name)->MeasureProcessCPUTime()->UseRealTime()->Unit(benchmark::kNanosecond) \ + ->RangeMultiplier(100)->Range(1, 10000) + +CELIX_BENCHMARK(FilterBenchmark_testStringCFilter); //done on C API, to check if C++ api does not have a big overhead + +//Operator = +CELIX_BENCHMARK(FilterBenchmark_testStringFilter); +CELIX_BENCHMARK(FilterBenchmark_testLongFilter); +//note no double = test +CELIX_BENCHMARK(FilterBenchmark_testBoolFilter); +CELIX_BENCHMARK(FilterBenchmark_testVersionFilter); +CELIX_BENCHMARK(FilterBenchmark_testVersionWithQualifierFilter); + +//Operator >= +CELIX_BENCHMARK(FilterBenchmark_testStringGreaterEqualFilter); +CELIX_BENCHMARK(FilterBenchmark_testLongGreaterEqualFilter); +CELIX_BENCHMARK(FilterBenchmark_testDoubleGreaterEqualFilter); +//note no bool >= test +CELIX_BENCHMARK(FilterBenchmark_versionGreaterEqualFilter); + +//Specials +CELIX_BENCHMARK(FilterBenchmark_versionRangeFilter); +CELIX_BENCHMARK(FilterBenchmark_complexFilter);
