-
Notifications
You must be signed in to change notification settings - Fork 5.3k
stats: Factor out creation of cluster-stats StatNames from creation of the stats, to save CPU during xDS updates #14028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
98d6a27
618834e
bd5c8a8
50976f1
56259be
f6b5fd5
6b0c333
d798bb0
d437b12
6d1e6c7
63d0d21
a34cb47
c046273
11e9bd7
c4bb1f8
9060912
0498546
02c56ae
e845693
5f6b47b
f702021
588d16e
a595f32
4554d16
5678a02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| #pragma once | ||
|
|
||
| #include "envoy/common/pure.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Router { | ||
|
|
||
| struct StatNames; | ||
|
|
||
| class Context { | ||
| public: | ||
| virtual ~Context() = default; | ||
|
|
||
| /** | ||
| * @return a struct containing StatNames for router stats. | ||
| */ | ||
| virtual const StatNames& statNames() const PURE; | ||
| }; | ||
|
|
||
| } // namespace Router | ||
| } // namespace Envoy |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,9 @@ | |
| #include "envoy/stats/histogram.h" | ||
| #include "envoy/stats/stats.h" | ||
|
|
||
| #include "common/stats/symbol_table_impl.h" | ||
| #include "common/stats/utility.h" | ||
|
|
||
| #include "absl/strings/match.h" | ||
| #include "absl/strings/str_cat.h" | ||
|
|
||
|
|
@@ -33,6 +36,36 @@ namespace Envoy { | |
| * Finally, when you want to actually instantiate the above struct using a Stats::Pool, you do: | ||
| * MyCoolStats stats{ | ||
| * MY_COOL_STATS(POOL_COUNTER(...), POOL_GAUGE(...), POOL_HISTOGRAM(...))}; | ||
| * | ||
| * | ||
| * The above constructs are the simplest way to declare counters, gauges, | ||
| * histograms, and text-readouts in your data structures. However they incur | ||
| * some overhead to symbolize the names every time they are instantiated. For | ||
| * data structures that are re-instantiated extensively during operation, | ||
| * e.g. in response to an xDS update, We can separately instantiate a | ||
| * StatNameStruct, containing symbolized names for each stat. That should be | ||
| * instantiated once at startup and held in some context or factory. Do that | ||
| * with: | ||
| * | ||
| * MAKE_STAT_NAMES_STRUCT(MyStatNames, MY_COOL_STATS); | ||
| * | ||
| * This generates a structure definition with a constructor that requires a | ||
| * SymbolTable. So you must, in a context instantiated once, initialize with: | ||
| * | ||
| * : my_cool_stat_names_(stat_store.symbolTable()) | ||
| * | ||
| * Once you have the StatNamesStruct instance declared, you can create a stats | ||
| * struct efficiently during operation (e.g. in an xDS handler) with | ||
| * | ||
| * MAKE_STATS_STRUCT(MyStats, MyStatNames, MY_COOL_STATS); | ||
| * | ||
| * This new structure is constructed with 2 or 3 args: | ||
| * 1. The stat_names struct created from MAKE_STAT_NAMES_STRUCT | ||
| * 2. The scope in which to instantiate the stats | ||
| * 3. An optional prefix, which will be prepended to each stat name. | ||
| * For example: | ||
| * | ||
| * : my_cool_stats_(context.my_cool_stat_names_, scope, opt_prefix) | ||
| */ | ||
|
|
||
| // Fully-qualified for use in external callsites. | ||
|
|
@@ -59,6 +92,7 @@ static inline std::string statPrefixJoin(absl::string_view prefix, absl::string_ | |
| #define POOL_GAUGE_PREFIX(POOL, PREFIX) (POOL).gaugeFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_MODE_ | ||
| #define POOL_HISTOGRAM_PREFIX(POOL, PREFIX) (POOL).histogramFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_UNIT_ | ||
| #define POOL_TEXT_READOUT_PREFIX(POOL, PREFIX) (POOL).textReadoutFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_ | ||
| #define POOL_STAT_NAME_PREFIX(POOL, PREFIX) (POOL).symbolTable().textReadoutFromString(Envoy::statPrefixJoin(PREFIX, FINISH_STAT_DECL_ | ||
|
|
||
| #define POOL_COUNTER(POOL) POOL_COUNTER_PREFIX(POOL, "") | ||
| #define POOL_GAUGE(POOL) POOL_GAUGE_PREFIX(POOL, "") | ||
|
|
@@ -69,4 +103,65 @@ static inline std::string statPrefixJoin(absl::string_view prefix, absl::string_ | |
| #define NULL_STAT_DECL_IGNORE_MODE_(X, MODE) std::string(#X)), | ||
|
|
||
| #define NULL_POOL_GAUGE(POOL) (POOL).nullGauge(NULL_STAT_DECL_IGNORE_MODE_ | ||
|
|
||
| // Used for declaring StatNames in a structure. | ||
| #define GENERATE_STAT_NAME_STRUCT(NAME, ...) Envoy::Stats::StatName NAME##_; | ||
| #define GENERATE_STAT_NAME_INIT(NAME, ...) , NAME##_(pool_.add(#NAME)) | ||
|
|
||
| // Macros for declaring stat-structures using StatNames, for those that must be | ||
| // instantiated during operation, and where speed and scale matters. These | ||
| // macros are not for direct use; they are only for use from | ||
| // MAKE_STAT_NAMES_STRUCT. and MAKE_STAT_STRUCT. | ||
| #define MAKE_STATS_STRUCT_COUNTER_HELPER_(NAME) \ | ||
| , NAME##_(Envoy::Stats::Utility::counterFromStatNames(scope, {prefix, stat_names.NAME##_})) | ||
| #define MAKE_STATS_STRUCT_GAUGE_HELPER_(NAME, MODE) \ | ||
| , NAME##_(Envoy::Stats::Utility::gaugeFromStatNames(scope, {prefix, stat_names.NAME##_}, \ | ||
| Envoy::Stats::Gauge::ImportMode::MODE)) | ||
| #define MAKE_STATS_STRUCT_HISTOGRAM_HELPER_(NAME, UNIT) \ | ||
| , NAME##_(Envoy::Stats::Utility::histogramFromStatNames(scope, {prefix, stat_names.NAME##_}, \ | ||
| Envoy::Stats::Histogram::Unit::UNIT)) | ||
| #define MAKE_STATS_STRUCT_TEXT_READOUT_HELPER_(NAME) \ | ||
| , NAME##_(Envoy::Stats::Utility::textReadoutFromStatNames(scope, {prefix, stat_names.NAME##_})) | ||
|
|
||
| #define MAKE_STATS_STRUCT_STATNAME_HELPER_(name) | ||
| #define GENERATE_STATNAME_STRUCT(name) | ||
|
|
||
| /** | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that MAKE_STAT_NAMES_STRUCT and MAKE_STATS_STRUCT do not follow the pattern of the existing macros as they require distinct initializers based on data constructed from the ctor params. There's also a bit of hackery where the HELPER_ functions above depend on formal-param names established in other macros. I couldn't figure out how to make something like your FINISH_DECL macros work for this. |
||
| * Generates a struct with StatNames for a subsystem, based on the stats macro | ||
| * with COUNTER, GAUGE, HISTOGRAM, TEXT_READOUT, and STATNAME calls. The | ||
| * ALL_STATS macro must have all 5 parameters. | ||
| */ | ||
| #define MAKE_STAT_NAMES_STRUCT(StatNamesStruct, ALL_STATS) \ | ||
| struct StatNamesStruct { \ | ||
| explicit StatNamesStruct(Envoy::Stats::SymbolTable& symbol_table) \ | ||
| : pool_(symbol_table) \ | ||
| ALL_STATS(GENERATE_STAT_NAME_INIT, GENERATE_STAT_NAME_INIT, GENERATE_STAT_NAME_INIT, \ | ||
| GENERATE_STAT_NAME_INIT, GENERATE_STAT_NAME_INIT) {} \ | ||
| Envoy::Stats::StatNamePool pool_; \ | ||
| ALL_STATS(GENERATE_STAT_NAME_STRUCT, GENERATE_STAT_NAME_STRUCT, GENERATE_STAT_NAME_STRUCT, \ | ||
| GENERATE_STAT_NAME_STRUCT, GENERATE_STAT_NAME_STRUCT) \ | ||
| } | ||
|
|
||
| /** | ||
| * Instantiates a structure of stats based on a new scope and optional prefix, | ||
| * using a predefined structure of stat names. A reference to the stat_names is | ||
| * also stored in the structure, for two reasons: (a) as a syntactic convenience | ||
| * for using macros to generate the comma separators for the initializer and (b) | ||
| * as a convenience at the call-site to access STATNAME-declared names from the | ||
| * stats structure. | ||
| */ | ||
| #define MAKE_STATS_STRUCT(StatsStruct, StatNamesStruct, ALL_STATS) \ | ||
| struct StatsStruct { \ | ||
| StatsStruct(const StatNamesStruct& stat_names, Envoy::Stats::Scope& scope, \ | ||
| Envoy::Stats::StatName prefix = Envoy::Stats::StatName()) \ | ||
| : stat_names_(stat_names) \ | ||
| ALL_STATS(MAKE_STATS_STRUCT_COUNTER_HELPER_, MAKE_STATS_STRUCT_GAUGE_HELPER_, \ | ||
| MAKE_STATS_STRUCT_HISTOGRAM_HELPER_, \ | ||
| MAKE_STATS_STRUCT_TEXT_READOUT_HELPER_, \ | ||
| MAKE_STATS_STRUCT_STATNAME_HELPER_) {} \ | ||
| const StatNamesStruct& stat_names_; \ | ||
| ALL_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT, GENERATE_HISTOGRAM_STRUCT, \ | ||
| GENERATE_TEXT_READOUT_STRUCT, GENERATE_STATNAME_STRUCT) \ | ||
| } | ||
|
|
||
| } // namespace Envoy | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| #include "common/router/context_impl.h" | ||
|
|
||
| namespace Envoy { | ||
| namespace Router { | ||
|
|
||
| ContextImpl::ContextImpl(Stats::SymbolTable& symbol_table) : stat_names_(symbol_table) {} | ||
|
|
||
| } // namespace Router | ||
| } // namespace Envoy |
Uh oh!
There was an error while loading. Please reload this page.