-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Emit telemetry when create-instance steps exceed 10s #40269
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
Open
shuaiyuanxx
wants to merge
11
commits into
master
Choose a base branch
from
user/shawn/slow-operation-warning
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
76192d4
Emit telemetry when create-instance steps exceed 10s
shuaiyuanxx 11e8775
Use TraceLoggingValue for SlowOperation name field
shuaiyuanxx 218e088
Include <exception> explicitly for std::uncaught_exceptions()
shuaiyuanxx 56cb403
update
shuaiyuanxx 577833c
resolve comments
shuaiyuanxx a94d220
resolve comments
shuaiyuanxx 77d6636
Merge remote-tracking branch 'origin/master' into user/shawn/slow-ope…
shuaiyuanxx b62b81d
update
shuaiyuanxx 8fd0c0c
format src files
shuaiyuanxx d83bd7e
resolve comments
shuaiyuanxx 9e65c78
resolve comments
shuaiyuanxx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /*++ | ||
|
|
||
| Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| Module Name: | ||
|
|
||
| SlowOperationWatcher.cpp | ||
|
|
||
| Abstract: | ||
|
|
||
| See header for contract. A single-shot threadpool timer is armed for SlowThreshold | ||
| in the constructor. If it fires, the callback emits one `SlowOperation` telemetry | ||
| event with the phase name and captured std::source_location. The timer is owned by | ||
| wil::unique_threadpool_timer, whose destroyer cancels pending callbacks and blocks | ||
| for any in-flight callback before closing, so OnTimerFired cannot dereference | ||
| `*this` after destruction. | ||
|
|
||
| --*/ | ||
|
|
||
| #include "precomp.h" | ||
| #include "SlowOperationWatcher.h" | ||
|
|
||
| namespace { | ||
| FILETIME RelativeFileTime(std::chrono::milliseconds Relative) noexcept | ||
| { | ||
| // Negative FILETIME means "relative to now", in 100ns units. Matches the pattern used | ||
| // elsewhere in the service (see Lifetime.cpp). | ||
| return wil::filetime::from_int64(-wil::filetime_duration::one_millisecond * Relative.count()); | ||
| } | ||
|
|
||
| // std::source_location::file_name() returns the path as the compiler saw it, which on | ||
| // MSVC is an absolute build-agent path. Strip to the basename so telemetry groups the | ||
| // same file across different build environments without leaking machine-specific paths. | ||
| // The substring is taken from the same null-terminated char array, so the returned view's | ||
| // data() is safe to pass to C APIs that expect a null-terminated string. | ||
| constexpr std::string_view Basename(std::string_view Path) noexcept | ||
| { | ||
| const auto pos = Path.find_last_of("\\/"); | ||
| return pos == std::string_view::npos ? Path : Path.substr(pos + 1); | ||
| } | ||
|
|
||
| static_assert(Basename("/foo/bar/test.cpp") == "test.cpp"); | ||
| static_assert(Basename("C:\\src\\test.cpp") == "test.cpp"); | ||
| static_assert(Basename("no_separator.cpp") == "no_separator.cpp"); | ||
| } // namespace | ||
|
|
||
| SlowOperationWatcher::SlowOperationWatcher(_In_z_ const char* Name, std::chrono::milliseconds SlowThreshold, std::source_location Location) : | ||
| m_name(Name), m_slowThreshold(SlowThreshold), m_location(Location) | ||
| { | ||
| m_timer.reset(CreateThreadpoolTimer(OnTimerFired, this, nullptr)); | ||
| THROW_IF_NULL_ALLOC(m_timer.get()); | ||
|
|
||
| FILETIME due = RelativeFileTime(m_slowThreshold); | ||
| SetThreadpoolTimer(m_timer.get(), &due, 0, 0); | ||
| } | ||
|
|
||
| void SlowOperationWatcher::Reset() noexcept | ||
| { | ||
| m_timer.reset(); | ||
| } | ||
|
|
||
| void CALLBACK SlowOperationWatcher::OnTimerFired(PTP_CALLBACK_INSTANCE, PVOID Context, PTP_TIMER) noexcept | ||
| try | ||
| { | ||
| auto* self = static_cast<SlowOperationWatcher*>(Context); | ||
|
|
||
| WSL_LOG_TELEMETRY( | ||
| "SlowOperation", | ||
| PDT_ProductAndServicePerformance, | ||
| TraceLoggingValue(self->m_name, "name"), | ||
| TraceLoggingInt64(self->m_slowThreshold.count(), "thresholdMs"), | ||
| TraceLoggingValue(Basename(self->m_location.file_name()).data(), "file"), | ||
| TraceLoggingValue(self->m_location.function_name(), "function"), | ||
| TraceLoggingUInt32(self->m_location.line(), "line")); | ||
| } | ||
| CATCH_LOG() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| /*++ | ||
|
|
||
| Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| Module Name: | ||
|
|
||
| SlowOperationWatcher.h | ||
|
|
||
| Abstract: | ||
|
|
||
| RAII guard that watches a scoped operation. A threadpool timer is armed in the | ||
| constructor for `SlowThreshold` (10 s default). On the fast path (scope exits | ||
| before the threshold) the watcher's destructor cancels and drains the timer and | ||
| nothing is emitted. If the threshold is reached first -- including while the | ||
| scope is still running or hung indefinitely -- the timer callback fires once, | ||
| emitting a single `SlowOperation` telemetry event carrying the phase name and | ||
| the call site captured via std::source_location, so the backend can attribute | ||
|
shuaiyuanxx marked this conversation as resolved.
|
||
| where time is spent. | ||
|
|
||
| Usage: | ||
|
|
||
| SlowOperationWatcher slow{"WaitForMiniInitConnect"}; | ||
| m_miniInitChannel = wsl::shared::SocketChannel{AcceptConnection(timeout), ...}; | ||
|
|
||
| If the scope needs to outlive the watched operation (for example to keep a | ||
| pointer into an internal receive buffer alive without a nested block), call | ||
| Reset() to disarm the watcher early: | ||
|
|
||
| SlowOperationWatcher slow{"WaitForCreateInstanceResult"}; | ||
| const auto& result = channel.ReceiveMessage<...>(...); | ||
| slow.Reset(); | ||
| // result remains valid and usable here | ||
|
|
||
| --*/ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <windows.h> | ||
| #include <wil/resource.h> | ||
| #include <chrono> | ||
| #include <source_location> | ||
|
|
||
| class SlowOperationWatcher | ||
| { | ||
| public: | ||
| // Name is restricted to a string-literal reference (const char (&)[N]) to guarantee | ||
| // static storage duration: the raw pointer is dereferenced later from a threadpool | ||
| // callback, so accepting a `const char*` would make UAF via a temporary (e.g. | ||
| // std::string::c_str()) easy. Keep Name a short CamelCase phase identifier that the | ||
| // backend query can switch on (e.g. "WaitForMiniInitConnect"). | ||
| template <size_t N> | ||
| explicit SlowOperationWatcher( | ||
| const char (&Name)[N], | ||
| std::chrono::milliseconds SlowThreshold = std::chrono::seconds{10}, | ||
| std::source_location Location = std::source_location::current()) : | ||
| SlowOperationWatcher(static_cast<const char*>(Name), SlowThreshold, Location) | ||
| { | ||
| } | ||
|
|
||
| ~SlowOperationWatcher() noexcept = default; | ||
|
|
||
| // Disarm the watcher early. After Reset() returns, the threshold callback is | ||
| // guaranteed not to fire. Relies on wil::unique_threadpool_timer's destroyer to | ||
| // cancel pending callbacks and drain any in-flight one. | ||
| void Reset() noexcept; | ||
|
|
||
| SlowOperationWatcher(const SlowOperationWatcher&) = delete; | ||
| SlowOperationWatcher& operator=(const SlowOperationWatcher&) = delete; | ||
| SlowOperationWatcher(SlowOperationWatcher&&) = delete; | ||
| SlowOperationWatcher& operator=(SlowOperationWatcher&&) = delete; | ||
|
|
||
| private: | ||
| explicit SlowOperationWatcher(_In_z_ const char* Name, std::chrono::milliseconds SlowThreshold, std::source_location Location); | ||
|
|
||
| static void CALLBACK OnTimerFired(PTP_CALLBACK_INSTANCE, PVOID Context, PTP_TIMER) noexcept; | ||
|
|
||
| const char* const m_name; | ||
| const std::chrono::milliseconds m_slowThreshold; | ||
| const std::source_location m_location; | ||
| wil::unique_threadpool_timer m_timer; | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.