Skip to content
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

perf: add annotations for non-concurrent cross-scoped duration measurements #13960

Merged
merged 7 commits into from
Nov 23, 2020

Conversation

rojkov
Copy link
Member

@rojkov rojkov commented Nov 10, 2020

Commit Message: perf: add annotations for non-concurrent cross-scoped duration measurements
Additional Description:
Risk Level: Low
Testing: updated unit tests
Docs Changes: N/A
Release Notes: N/A
Platform Specific Features: N/A
Fixes #13860

Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
@@ -32,6 +32,23 @@ void PerfOperation::record(absl::string_view category, absl::string_view descrip
// because the constructor is non-trivial due to the contained unordered_map.
PerfAnnotationContext::PerfAnnotationContext() = default;

void PerfAnnotationContext::begin(absl::string_view category, absl::string_view description) {
const CategoryDescription key = {std::string(category), std::string(description)};
RELEASE_ASSERT(!timestamps_map_.contains(key),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RELEASE_ASSERT use seems risky. Are these begin/end annotations meant to be used across event loop events or only within a single call stack?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within a single call stack only unfortunately. Would be nice to have uniquely identifiable events in the event loop though. Is it possible?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to use RELEASE_ASSERT as this code will only be activated when the binary is compiled with perf annotation enabled.

And it wouldn't do any good to use ASSERT because you generally would want opt-builds for measuring performance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a better way to do all of this: have an RAII object that is kept around for the duration of the perf operation and keeps the necessary state instead of keeping the state on a global as a string in a map.

It nicely solves the issue of concurrent performance measurements and works across call stacks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah for cases where RAII is OK, that works today with PERF_OPERATION which is just a wrapper that has all the code compile to nothing when perf annotations are not compiled in. I think that should be preferred when feasible to use.

I assume that PERF_BEGIN and PERF_END are where the plumbing needed to hold an object seems not worth it, and correlating by string seems worth it. It doesn't look to me like this adds any overhead when not used, so that's why I'm OK with this if it makes annotations easier to implement.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanest way though is just for begin() to return an object that you store in your filter undef ifdef

A-ha, now I see. In this case the owning object (e.g. filter) needs to be annotated too. And it has to be the same for a pair of begin() and end(). Right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah though I think the logical next step of what I suggested is that rather than calling begin() you just instantiate an RAII object yourself, throwing it in an ifdef'd member variable in (say) the filter; maybe via unique_ptr, and destructing it works like end().

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly, ^ is what I'm proposing. I think we can make it so it compiles to nothing if annotations are not enabled.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. Turned out it's enough to add a few new macros to achieve the same result.

@antoniovicente antoniovicente requested a review from asraa November 10, 2020 22:14
@antoniovicente antoniovicente assigned jmarantz and asraa and unassigned jmarantz Nov 10, 2020
Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice. Just some trivial comments.

@@ -32,6 +32,23 @@ void PerfOperation::record(absl::string_view category, absl::string_view descrip
// because the constructor is non-trivial due to the contained unordered_map.
PerfAnnotationContext::PerfAnnotationContext() = default;

void PerfAnnotationContext::begin(absl::string_view category, absl::string_view description) {
const CategoryDescription key = {std::string(category), std::string(description)};
RELEASE_ASSERT(!timestamps_map_.contains(key),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to use RELEASE_ASSERT as this code will only be activated when the binary is compiled with perf annotation enabled.

And it wouldn't do any good to use ASSERT because you generally would want opt-builds for measuring performance.

const CategoryDescription key = {std::string(category), std::string(description)};
const MonotonicTime end_time = currentTime();
const auto result = timestamps_map_.extract(key);
RELEASE_ASSERT(!result.empty(), "double perf measurement ending is disallowed!");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might as well include the category & description in this message and the RELEASE_ASSERT above.

@@ -42,6 +42,31 @@
perf.record(category, description); \
} while (false)

/**
* Initiates a duration measurement which can be finished in a different scope.
* Please note that this kind of measurements makes sense only in a strictly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/this/these/
s/makes/make/

* Initiates a duration measurement which can be finished in a different scope.
* Please note that this kind of measurements makes sense only in a strictly
* sequential flow, i.e. when a new stream isn't created until the current one
* is destroyed.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This in reference only to a particular combination of category and description, right?

{ PERF_BEGIN("gamma", "4"); }
{ PERF_BEGIN("sigma", "5"); }
{ PERF_END("gamma", "4"); }
{ PERF_END("sigma", "5"); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add begin/end checking with same-category different-description and vice versa?

* shown as separate columns in the generated output table. Before ending the
* measurement must be started first with a begin() call. The measurement can
* be started and ended in different scopes, but the flow of these start and
* stop points for the same category and description must be strictly sequential.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like you don't need to repeat all of this paragraph from above, but could just reference the doc in begin().

Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
jmarantz
jmarantz previously approved these changes Nov 12, 2020
Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@envoyproxy/senior-maintainers

This reverts commit c678883.

Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
…asurements"

This reverts commit 518b693.

Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
Copy link
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

@mattklein123
Copy link
Member

Can you check coverage?

/wait

@rojkov
Copy link
Member Author

rojkov commented Nov 23, 2020

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #13960 (comment) was created by @rojkov.

see: more, trace.

@rojkov
Copy link
Member Author

rojkov commented Nov 23, 2020

Can you check coverage?

@mattklein123 Looks it was a CI glitch. Everything is Ok now.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@mattklein123 mattklein123 merged commit ea10523 into envoyproxy:master Nov 23, 2020
qqustc pushed a commit to qqustc/envoy that referenced this pull request Nov 24, 2020
…ements (envoyproxy#13960)

Signed-off-by: Dmitry Rozhkov <dmitry.rozhkov@intel.com>
Signed-off-by: Qin Qin <qqin@google.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Extend PerfAnnotationContext with begin and end events.
5 participants