diff --git a/.travis.yml b/.travis.yml index 0d272803..4964babd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,4 @@ install: script: - bazel test --test_output=all //tests:prometheus_test - bazel test --test_output=all //tests/integration:scrape_test + - bazel run -c opt //tests/benchmark:benchmarks diff --git a/README.md b/README.md index 8a050ea3..b179c3bb 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,50 @@ sample server. With telegraf installed, it can be run using bazel test //tests/integration:scrape_test ``` +## Benchmarks + +There's a benchmark suite you can run: + +``` +bazel run -c opt tests/benchmark/benchmarks + +INFO: Found 1 target... +Target //tests/benchmark:benchmarks up-to-date: + bazel-bin/tests/benchmark/benchmarks +INFO: Elapsed time: 1.682s, Critical Path: 1.56s + +INFO: Running command line: bazel-bin/tests/benchmark/benchmarks +Run on (8 X 2300 MHz CPU s) +2016-10-17 15:56:49 +Benchmark Time CPU Iterations +-------------------------------------------------------------------- +BM_Counter_Increment 11 ns 11 ns 62947942 +BM_Counter_Collect 84 ns 84 ns 8221752 +BM_Gauge_Increment 11 ns 11 ns 61384663 +BM_Gauge_Decrement 11 ns 11 ns 62148197 +BM_Gauge_SetToCurrentTime 199 ns 198 ns 3589670 +BM_Gauge_Collect 86 ns 85 ns 7469136 +BM_Histogram_Observe/0 122 ns 122 ns 5839855 +BM_Histogram_Observe/1 116 ns 115 ns 5806623 +BM_Histogram_Observe/8 126 ns 126 ns 5781588 +BM_Histogram_Observe/64 138 ns 138 ns 4895550 +BM_Histogram_Observe/512 228 ns 228 ns 2992898 +BM_Histogram_Observe/4k 959 ns 958 ns 642231 +BM_Histogram_Collect/0 328 ns 327 ns 2002792 +BM_Histogram_Collect/1 356 ns 354 ns 1819032 +BM_Histogram_Collect/8 1553 ns 1544 ns 454921 +BM_Histogram_Collect/64 10389 ns 10287 ns 66759 +BM_Histogram_Collect/512 75795 ns 75093 ns 9075 +BM_Histogram_Collect/4k 615853 ns 610277 ns 1222 +BM_Registry_CreateFamily 195 ns 182 ns 3843894 +BM_Registry_CreateCounter/0 319 ns 317 ns 1914132 +BM_Registry_CreateCounter/1 2146 ns 2131 ns 408432 +BM_Registry_CreateCounter/8 8936 ns 8837 ns 82439 +BM_Registry_CreateCounter/64 72589 ns 72010 ns 9248 +BM_Registry_CreateCounter/512 694323 ns 686655 ns 1056 +BM_Registry_CreateCounter/4k 18246638 ns 18150525 ns 40 +``` + ## Project Status Alpha diff --git a/WORKSPACE b/WORKSPACE index 6bc78a20..9ff345b4 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -95,3 +95,25 @@ cc_library( ) """ ) + +new_git_repository( + name = "googlebenchmark", + remote = "https://github.com/google/benchmark.git", + commit = "57a22c69b382b3f010ec4042c9574ea3fd8dcbb4", + build_file_content = """ +cc_library( + name = "googlebenchmark", + srcs = glob(["src/*.cc"], + exclude = ["src/re_posix.cc", "src/gnuregex.cc"]), + hdrs = glob(["src/*.h", "include/benchmark/*.h"], + exclude = ["src/re_posix.h", "src/gnuregex.h"]), + includes = [ + "include", + ], + visibility = ["//visibility:public"], + copts = [ + "-DHAVE_STD_REGEX" + ], +) +""" +) diff --git a/tests/benchmark/BUILD b/tests/benchmark/BUILD new file mode 100644 index 00000000..7ac89785 --- /dev/null +++ b/tests/benchmark/BUILD @@ -0,0 +1,17 @@ +cc_binary( + name = "benchmarks", + srcs = [ + "main.cc", + "benchmark_helpers.cc", + "benchmark_helpers.h", + "counter_bench.cc", + "gauge_bench.cc", + "histogram_bench.cc", + "registry_bench.cc", + ], + deps = [ + "@googlebenchmark//:googlebenchmark", + "//lib:prometheus-cpp", + ], + linkstatic = 1, +) diff --git a/tests/benchmark/benchmark_helpers.cc b/tests/benchmark/benchmark_helpers.cc new file mode 100644 index 00000000..ad968dc1 --- /dev/null +++ b/tests/benchmark/benchmark_helpers.cc @@ -0,0 +1,29 @@ +#include +#include + +#include "benchmark_helpers.h" + +std::string generateRandomString(size_t length) { + auto randchar = []() -> char { + const char charset[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + const size_t max_index = (sizeof(charset) - 1); + return charset[rand() % max_index]; + }; + std::string str(length, 0); + std::generate_n(str.begin(), length, randchar); + return str; +} + +std::map generateRandomLabels( + std::size_t numberOfPairs) { + const auto labelCharacterCount = 10; + auto labelPairs = std::map{}; + for (int i = 0; i < numberOfPairs; i++) { + labelPairs.insert({generateRandomString(labelCharacterCount), + generateRandomString(labelCharacterCount)}); + } + return labelPairs; +} diff --git a/tests/benchmark/benchmark_helpers.h b/tests/benchmark/benchmark_helpers.h new file mode 100644 index 00000000..426dfc1d --- /dev/null +++ b/tests/benchmark/benchmark_helpers.h @@ -0,0 +1,7 @@ +#pragma once + +#include +#include + +std::string generateRandomString(size_t length); +std::map generateRandomLabels(std::size_t numberOfLabels); diff --git a/tests/benchmark/counter_bench.cc b/tests/benchmark/counter_bench.cc new file mode 100644 index 00000000..65d97d14 --- /dev/null +++ b/tests/benchmark/counter_bench.cc @@ -0,0 +1,26 @@ +#include +#include "lib/registry.h" + +static void BM_Counter_Increment(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Counter; + auto registry = Registry{{}}; + auto counterFamily = registry.add_counter("benchmark counter", "", {}); + auto counter = counterFamily->add({}); + + while (state.KeepRunning()) counter->inc(); +} +BENCHMARK(BM_Counter_Increment); + +static void BM_Counter_Collect(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Counter; + auto registry = Registry{{}}; + auto counterFamily = registry.add_counter("benchmark counter", "", {}); + auto counter = counterFamily->add({}); + + while (state.KeepRunning()) { + benchmark::DoNotOptimize(counter->collect()); + }; +} +BENCHMARK(BM_Counter_Collect); diff --git a/tests/benchmark/gauge_bench.cc b/tests/benchmark/gauge_bench.cc new file mode 100644 index 00000000..9107e07c --- /dev/null +++ b/tests/benchmark/gauge_bench.cc @@ -0,0 +1,48 @@ +#include +#include "lib/registry.h" + +static void BM_Gauge_Increment(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Gauge; + auto registry = Registry{{}}; + auto gaugeFamily = registry.add_gauge("benchmark gauge", "", {}); + auto gauge = gaugeFamily->add({}); + + while (state.KeepRunning()) gauge->inc(2); +} +BENCHMARK(BM_Gauge_Increment); + +static void BM_Gauge_Decrement(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Gauge; + auto registry = Registry{{}}; + auto gaugeFamily = registry.add_gauge("benchmark gauge", "", {}); + auto gauge = gaugeFamily->add({}); + + while (state.KeepRunning()) gauge->dec(2); +} +BENCHMARK(BM_Gauge_Decrement); + +static void BM_Gauge_SetToCurrentTime(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Gauge; + auto registry = Registry{{}}; + auto gaugeFamily = registry.add_gauge("benchmark gauge", "", {}); + auto gauge = gaugeFamily->add({}); + + while (state.KeepRunning()) gauge->set_to_current_time(); +} +BENCHMARK(BM_Gauge_SetToCurrentTime); + +static void BM_Gauge_Collect(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Gauge; + auto registry = Registry{{}}; + auto gaugeFamily = registry.add_gauge("benchmark gauge", "", {}); + auto gauge = gaugeFamily->add({}); + + while (state.KeepRunning()) { + benchmark::DoNotOptimize(gauge->collect()); + }; +} +BENCHMARK(BM_Gauge_Collect); diff --git a/tests/benchmark/histogram_bench.cc b/tests/benchmark/histogram_bench.cc new file mode 100644 index 00000000..35387512 --- /dev/null +++ b/tests/benchmark/histogram_bench.cc @@ -0,0 +1,60 @@ +#include +#include + +#include +#include "lib/registry.h" + +using prometheus::Histogram; + +static Histogram::BucketBoundaries createLinearBuckets(double start, double end, + double step) { + auto bucketBoundaries = Histogram::BucketBoundaries{}; + for (auto i = start; i < end; i += step) { + bucketBoundaries.push_back(i); + } + return bucketBoundaries; +} + +static void BM_Histogram_Observe(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Histogram; + + const auto numberOfBuckets = state.range(0); + + auto registry = Registry{{}}; + auto counterFamily = registry.add_histogram("benchmark histogram", "", {}); + auto bucketBoundaries = createLinearBuckets(0, numberOfBuckets - 1, 1); + auto histogram = counterFamily->add({}, bucketBoundaries); + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution<> d(0, numberOfBuckets); + + while (state.KeepRunning()) { + auto observation = d(gen); + auto start = std::chrono::high_resolution_clock::now(); + histogram->observe(observation); + auto end = std::chrono::high_resolution_clock::now(); + + auto elapsed_seconds = + std::chrono::duration_cast>(end - start); + state.SetIterationTime(elapsed_seconds.count()); + } +} +BENCHMARK(BM_Histogram_Observe)->Range(0, 4096); + +static void BM_Histogram_Collect(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Histogram; + + const auto numberOfBuckets = state.range(0); + + auto registry = Registry{{}}; + auto counterFamily = registry.add_histogram("benchmark histogram", "", {}); + auto bucketBoundaries = createLinearBuckets(0, numberOfBuckets - 1, 1); + auto histogram = counterFamily->add({}, bucketBoundaries); + + while (state.KeepRunning()) { + benchmark::DoNotOptimize(histogram->collect()); + } +} +BENCHMARK(BM_Histogram_Collect)->Range(0, 4096); diff --git a/tests/benchmark/main.cc b/tests/benchmark/main.cc new file mode 100644 index 00000000..71fefa04 --- /dev/null +++ b/tests/benchmark/main.cc @@ -0,0 +1,3 @@ +#include + +BENCHMARK_MAIN(); diff --git a/tests/benchmark/registry_bench.cc b/tests/benchmark/registry_bench.cc new file mode 100644 index 00000000..63303d7f --- /dev/null +++ b/tests/benchmark/registry_bench.cc @@ -0,0 +1,36 @@ +#include + +#include +#include "lib/registry.h" + +#include "benchmark_helpers.h" + +static void BM_Registry_CreateFamily(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Counter; + auto registry = Registry{{}}; + + while (state.KeepRunning()) registry.add_counter("benchmark counter", "", {}); +} +BENCHMARK(BM_Registry_CreateFamily); + +static void BM_Registry_CreateCounter(benchmark::State& state) { + using prometheus::Registry; + using prometheus::Counter; + auto registry = Registry{generateRandomLabels(10)}; + auto counterFamily = + registry.add_counter("benchmark counter", "", generateRandomLabels(10)); + + while (state.KeepRunning()) { + auto labels = generateRandomLabels(state.range(0)); + + auto start = std::chrono::high_resolution_clock::now(); + counterFamily->add(labels); + auto end = std::chrono::high_resolution_clock::now(); + + auto elapsed_seconds = + std::chrono::duration_cast>(end - start); + state.SetIterationTime(elapsed_seconds.count()); + } +} +BENCHMARK(BM_Registry_CreateCounter)->Range(0, 4096);