Repository navigation
Expand file tree
/
Copy pathserver_stats_flush_benchmark_test.cc
More file actions
135 lines (115 loc) · 4.5 KB
/
Copy pathserver_stats_flush_benchmark_test.cc
File metadata and controls
135 lines (115 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <cstdint>
#include <memory>
#include "envoy/stats/sink.h"
#include "envoy/stats/stats.h"
#include "source/common/stats/thread_local_store.h"
#include "source/server/server.h"
#include "test/benchmark/main.h"
#include "test/mocks/stats/mocks.h"
#include "test/mocks/upstream/cluster_manager.h"
#include "test/test_common/simulated_time_system.h"
#include "test/test_common/utility.h"
#include "absl/strings/str_cat.h"
#include "benchmark/benchmark.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace Envoy {
// Override the one method used by this test so that using a mock doesn't affect performance.
class FastMockClusterManager : public testing::StrictMock<Upstream::MockClusterManager> {
public:
ClusterInfoMaps clusters() const override { return ClusterInfoMaps{}; }
void forEachActiveCluster(std::function<void(const Upstream::Cluster&)>) const override {}
};
class TestSinkPredicates : public Stats::SinkPredicates {
public:
bool includeCounter(const Stats::Counter&) override { return (++num_counters_) % 10 == 0; }
bool includeGauge(const Stats::Gauge&) override { return (++num_gauges_) % 10 == 0; }
bool includeTextReadout(const Stats::TextReadout&) override {
return (++num_text_readouts_) % 10 == 0;
}
bool includeHistogram(const Stats::Histogram&) override { return (++num_histograms_) % 10 == 0; }
private:
size_t num_counters_ = 0;
size_t num_gauges_ = 0;
size_t num_text_readouts_ = 0;
size_t num_histograms_ = 0;
};
class StatsSinkFlushSpeedTest {
public:
StatsSinkFlushSpeedTest(size_t const num_stats, bool set_sink_predicates = false)
: pool_(symbol_table_), stats_allocator_(symbol_table_), stats_store_(stats_allocator_) {
if (set_sink_predicates) {
stats_store_.setSinkPredicates(
std::unique_ptr<Stats::SinkPredicates>{std::make_unique<TestSinkPredicates>()});
}
// Create counters
for (uint64_t idx = 0; idx < num_stats; ++idx) {
auto stat_name = pool_.add(absl::StrCat("counter.", idx));
stats_store_.rootScope()->counterFromStatName(stat_name).inc();
}
// Create gauges
for (uint64_t idx = 0; idx < num_stats; ++idx) {
auto stat_name = pool_.add(absl::StrCat("gauge.", idx));
stats_store_.rootScope()
->gaugeFromStatName(stat_name, Stats::Gauge::ImportMode::NeverImport)
.set(idx);
}
// Create text readouts
for (uint64_t idx = 0; idx < num_stats; ++idx) {
auto stat_name = pool_.add(absl::StrCat("text_readout.", idx));
stats_store_.rootScope()->textReadoutFromStatName(stat_name).set(
absl::StrCat("text_readout.", idx));
}
// Create histograms
for (uint64_t idx = 0; idx < num_stats; ++idx) {
std::string stat_name(absl::StrCat("histogram.", idx));
stats_store_.histogramFromString(stat_name, Stats::Histogram::Unit::Unspecified);
}
}
void test(::benchmark::State& state) {
for (auto _ : state) {
UNREFERENCED_PARAMETER(_);
std::list<Stats::SinkPtr> sinks;
sinks.emplace_back(new testing::NiceMock<Stats::MockSink>());
Server::InstanceUtil::flushMetricsToSinks(sinks, stats_store_, cm_, time_system_);
}
}
private:
Stats::SymbolTableImpl symbol_table_;
Stats::StatNamePool pool_;
Stats::Allocator stats_allocator_;
Stats::ThreadLocalStoreImpl stats_store_;
Event::SimulatedTimeSystem time_system_;
FastMockClusterManager cm_;
};
static void bmFlushToSinks(::benchmark::State& state) {
// Skip expensive benchmarks for unit tests.
if (benchmark::skipExpensiveBenchmarks() && state.range(0) > 100) {
state.SkipWithError("Skipping expensive benchmark");
return;
}
StatsSinkFlushSpeedTest speed_test(state.range(0));
speed_test.test(state);
}
static void bmFlushToSinksWithPredicatesSet(::benchmark::State& state) {
// Skip expensive benchmarks for unit tests.
if (benchmark::skipExpensiveBenchmarks() && state.range(0) > 100) {
state.SkipWithError("Skipping expensive benchmark");
return;
}
StatsSinkFlushSpeedTest speed_test(state.range(0), true);
speed_test.test(state);
}
// The 2500000 case exercises 10M metric objects per snapshot (2.5M each of
// counters, gauges, histograms and text readouts), the regime where ref-count
// overhead during flush was reported in #43836.
BENCHMARK(bmFlushToSinks)
->Unit(::benchmark::kMillisecond)
->RangeMultiplier(10)
->Range(10, 1000000)
->Arg(2500000);
BENCHMARK(bmFlushToSinksWithPredicatesSet)
->Unit(::benchmark::kMillisecond)
->RangeMultiplier(10)
->Range(10, 1000000);
} // namespace Envoy