-
Notifications
You must be signed in to change notification settings - Fork 844
Refactor new metrics with Counter vs Gauge types #10694
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
Conversation
ae5feaa to
a502f4c
Compare
|
Maybe you can fix the Clang Analyzer defect by inserting |
I could, but the thing is, this is not my fault :). I asked @masaori335 to look at this, I'm suspecting that something in my PR makes clang-analyzer either confused, or brilliant, in detecting this old issue. |
a502f4c to
eaa3ff6
Compare
|
Clang Analyzer punishes for unconfessed sins and those from previous lifetimes. |
True dat. |
8fc2b43 to
7688644
Compare
|
|
||
| class AtomicType : public Metrics::AtomicType | ||
| { | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just using AtomicType = Metrics::AtomicType; ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because then the compiler won't give errors or warnings about wrong types. Initially I did this all with "using", and then it became too easy to do the wrong things with the wrong types of metrics. Meaning, if you do
using Foo == Bar;
Foo and Bar are identical types, and can be used interchangeable. They truly are aliases. And I wanted to avoid people trying to do dangerous stuff such as sucking out a Counter out of the metrics storage, and then treat it as a Gauge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you give it the constructor explicit AtomicType(Metrics::AtomicType a) : Metrics::AtomicType(a) {} so you won't need the reinterpret_cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let me look tomorrow morning.
include/api/Metrics.h
Outdated
|
|
||
| public: | ||
| AtomicType() = default; | ||
| virtual ~AtomicType() = default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making this virtual doubles the size of instances of this type. Why is it necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above :/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
above what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It had to be virtual, otherwise I couldn't subclass it later as I did. And I had to sub class it, rather than aliases, to make the compiler detect bad usage. It's not considered polymorphic otherwise, e.g.
/Users/leif/apache/trafficserver/src/proxy/http/PreWarmManager.cc:1181:18: error: 'ts::Metrics::AtomicType' is not polymorphic
metric = dynamic_cast<Metrics::Counter::AtomicType *>(metrics.lookup(stats_id));
Maybe we can fix the usage that's causing trouble here, I didn't write this code in the PreWarmManager.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the right solution here is to have
Metrics::Counter::lookup(stats_id);
Metrics::Gauge::lookup(stats_id);
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ywkaras I added those static's, which allows us to eliminate the virtual. Let me know what you think, it's in the last commit that I lovingly made just for you.
| { | ||
| auto &instance = Metrics::instance(); | ||
|
|
||
| return reinterpret_cast<AtomicType *>(instance.lookup(instance._create(name))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like the overload of lookup() that returns IdType/uint32_t. How can that work, to cast it to a64-bit pointer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a different lookup no? I'd have to look again, but remember there are two lookups, one to that returns the IdType, and one that returns a pointer directly to the atomic types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I see but it shouldn't need the case then.
include/api/Metrics.h
Outdated
| } | ||
|
|
||
| static int64_t | ||
| load(AtomicType *metric) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can't be const?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe? I can try.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, fixed, and uploaded with a new commit for your review suggestions (will add more as if we identify more things that needs fixing).
| return metric->_value.load(); | ||
| } | ||
|
|
||
| }; // class Counter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have expected Counter to have load, increment and clear, and Gauge to have load, increment and decrement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clear? Why clear? All counters starts at zero, and can always go up. You should not set it back to 0 IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes there are pros and cons to having clear(). I was thinking we had set() to do a clear, so just have clear().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I'll probably argue that if you need to do clear(), you are using this wrong, and it should be a gauge. Counters are supposed to always increase, randomly setting it to 0 (or any value) is wrong, and why I even bothered adding this difference of Counters vs Gauges.
include/api/Metrics.h
Outdated
| return lookup(id); | ||
| } | ||
| return std::nullopt; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is not currently used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used in the tests :). But it could be used, maybe even should be used. Certainly in plugins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
| increment_current_active_connections_stat() override | ||
| { | ||
| Metrics::increment(http2_rsb.current_active_server_connection_count); | ||
| Metrics::Gauge::increment(http2_rsb.current_active_server_connection_count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you had to change all of these anyway, why didn't you make increment and decrement non-static member functions:
http2_rsb.current_active_server_connection_count->increment(). It's shorter, and you would get a compiler error if you tried to decrement a counter rather than a gauge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought of that, and even asked @cmcfarlen , we both preferred the static. I can change it if we think it's better. It just reads better with the static IMO.
| { | ||
| auto &instance = Metrics::instance(); | ||
|
|
||
| return reinterpret_cast<AtomicType *>(instance.lookup(instance._create(name))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another superfluous cast.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I don't think it's superfluous, it won't compile otherwise I'm fairly certain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/Users/leif/apache/trafficserver/include/api/Metrics.h:312:14: error: cannot initialize return object of type 'AtomicType *' (aka 'ts::Metrics::Gauge::AtomicType *') with an rvalue of type 'AtomicType *' (aka 'ts::Metrics::AtomicType *')
return instance.lookup(instance._create(name));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/iocore/aio/test_AIO.cc
Outdated
| Metrics::IntType *completed = m.lookup(m.lookup("proxy.process.io_uring.completed")); | ||
| Metrics::IntType *submitted = m.lookup(m.lookup("proxy.process.io_uring.submitted")); | ||
| Metrics::Counter::AtomicType *completed = m.lookup(m.lookup("proxy.process.io_uring.completed")); | ||
| Metrics::Counter::AtomicType *submitted = m.lookup(m.lookup("proxy.process.io_uring.submitted")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could have had two more useless casts here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You implying we should have another lookup function, that avoids both lookups here/ This is an unusual use case honestly, the the IdType lookups are kept mostly because of the old APIs and use of "ids" instead of pointers.
We can probably eliminate some of this in v11 once we clean out more old stuff completely. Or, if we could convince Strostrup to allow overloading to take the return type into the resolution.
|
|
||
| printf("submissions: %lu\n", Metrics::read(submitted)); | ||
| printf("completions: %lu\n", Metrics::read(completed)); | ||
| printf("submissions: %lu\n", Metrics::Gauge::load(submitted)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really %lu quit slacking https://en.cppreference.com/w/cpp/types/integer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeh, not my code. I'm fairly certain we've agreed that you don't have to rewrite everyones code to make something "better".
| } | ||
|
|
||
| static AtomicType * | ||
| createPtr(const std::string_view name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::string_view is overkill, all the member functions are const I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it hurt? Other than your eyes ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alan will sentence you to hard labor on his pumpkin farm for this.
| this->rsb.refcountcache_last_sync_time = intm.newMetricPtr((metrics_prefix + "last_sync.time").c_str()); | ||
| this->rsb.refcountcache_last_total_items = intm.newMetricPtr((metrics_prefix + "last_sync.total_items").c_str()); | ||
| this->rsb.refcountcache_last_total_size = intm.newMetricPtr((metrics_prefix + "last_sync.total_size").c_str()); | ||
| this->rsb.refcountcache_current_items = Metrics::Gauge::createPtr((metrics_prefix + "current_items").c_str()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you doing string -> c string -> string_view instead of just string -> string_view directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably a remnant from the code as it was prior to changing to new metrics.
afa6c52 to
acdb96c
Compare
|
How about: https://godbolt.org/z/7Wv444EfE |
774727b to
e287f76
Compare
|
[approve ci] |
1 similar comment
|
[approve ci] |
e56c764 to
10ea86c
Compare
| std::string_view alpn_name = alpn_name_for_stat(dst->alpn_index); | ||
| _makeName(dst, COUNTER_STAT_ENTRIES[j], name, sizeof(name)); | ||
|
|
||
| auto metric = Metrics::Counter::createPtr(name); // This will do a lookup if it already exists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks much convenient 👍
masaori335
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes metrics type explicit. Looks good to me.
10ea86c to
8e6333d
Compare
This adds some more tooling around
CountervsGaugetype of metrics, assuring that Counters for example can only increment. There's no change in functionality here, other than the naming and creation details. But it will assure that the underlying APIs are used correctly.Performance wise this should make no difference, at least in a release build. The compiler will optimize this down to just the
fetch_add()just as before.