| Index: base/trace_event/trace_event_etw_export_win.cc
|
| diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
|
| index d199bf5c8b2e4f6f359335b55e045d393adcb0b5..98e45539c84e1bcd595ea3248a50d9116716d61f 100644
|
| --- a/base/trace_event/trace_event_etw_export_win.cc
|
| +++ b/base/trace_event/trace_event_etw_export_win.cc
|
| @@ -7,6 +7,7 @@
|
| #include "base/command_line.h"
|
| #include "base/logging.h"
|
| #include "base/memory/singleton.h"
|
| +#include "base/strings/string_tokenizer.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "base/trace_event/trace_event_impl.h"
|
| @@ -40,6 +41,55 @@ typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
|
| tEventRegister EventRegisterProc = nullptr;
|
| tEventWrite EventWriteProc = nullptr;
|
| tEventUnregister EventUnregisterProc = nullptr;
|
| +
|
| +// |filtered_event_group_names| contains the event categories that can be
|
| +// exported individually. These categories can be enabled by passing the correct
|
| +// keyword when starting the trace. A keyword is a 64-bit flag and we attribute
|
| +// one bit per category. We can therefore enable a particular category by
|
| +// setting its corresponding bit in the keyword. For events that are not present
|
| +// in |filtered_event_group_names|, we have two bits that control their
|
| +// behaviour. When bit 61 is enabled, any event that is not disabled by default
|
| +// (ie. doesn't start with disabled-by-default-) will be exported. Likewise,
|
| +// when bit 62 is enabled, any event that is disabled by default will be
|
| +// exported.
|
| +//
|
| +// Note that bit 63 (MSB) must always be set, otherwise tracing will be disabled
|
| +// by ETW. Therefore, the keyword will always be greater than
|
| +// 0x8000000000000000.
|
| +//
|
| +// Examples of passing keywords to the provider using xperf:
|
| +// # This exports "benchmark" and "cc" events
|
| +// xperf -start chrome -on Chrome:0x8000000000000009
|
| +//
|
| +// # This exports "gpu", "netlog" and all other events that are not disabled by
|
| +// # default
|
| +// xperf -start chrome -on Chrome:0xA0000000000000A0
|
| +//
|
| +// More info about starting a trace and keyword can be obtained by using the
|
| +// help section of xperf (xperf -help start). Note that xperf documentation
|
| +// refers to keywords as flags and there are two ways to enable them, using
|
| +// group names or the hex representation. We only support the latter. Also, we
|
| +// ignore the level.
|
| +const char* const filtered_event_group_names[] = {
|
| + "benchmark", // 0x1
|
| + "blink", // 0x2
|
| + "browser", // 0x4
|
| + "cc", // 0x8
|
| + "evdev", // 0x10
|
| + "gpu", // 0x20
|
| + "input", // 0x40
|
| + "netlog", // 0x80
|
| + "renderer.scheduler", // 0x100
|
| + "toplevel", // 0x200
|
| + "v8", // 0x400
|
| + "disabled-by-default-cc.debug", // 0x800
|
| + "disabled-by-default-cc.debug.picture", // 0x1000
|
| + "disabled-by-default-toplevel.flow"}; // 0x2000
|
| +const char* other_events_group_name = "__OTHER_EVENTS"; // 0x2000000000000000
|
| +const char* disabled_other_events_group_name =
|
| + "__DISABLED_OTHER_EVENTS"; // 0x4000000000000000
|
| +uint64 other_events_keyword_bit = 1ULL << 61;
|
| +uint64 disabled_other_events_keyword_bit = 1ULL << 62;
|
| } // namespace
|
|
|
| // Redirector function for EventRegister. Called by macros in
|
| @@ -77,7 +127,8 @@ ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
|
| namespace base {
|
| namespace trace_event {
|
|
|
| -TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
|
| +TraceEventETWExport::TraceEventETWExport()
|
| + : etw_export_enabled_(false), etw_match_any_keyword_(0ULL) {
|
| // Find Advapi32.dll. This should always succeed.
|
| HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
|
| if (AdvapiDLL) {
|
| @@ -92,6 +143,8 @@ TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
|
| // Register the ETW provider. If registration fails then the event logging
|
| // calls will fail (on XP this call will do nothing).
|
| EventRegisterChrome();
|
| +
|
| + UpdateEnabledCategories();
|
| }
|
| }
|
|
|
| @@ -108,13 +161,18 @@ TraceEventETWExport* TraceEventETWExport::GetInstance() {
|
| // static
|
| void TraceEventETWExport::EnableETWExport() {
|
| if (GetInstance())
|
| - GetInstance()->ETWExportEnabled_ = true;
|
| + GetInstance()->etw_export_enabled_ = true;
|
| }
|
|
|
| // static
|
| void TraceEventETWExport::DisableETWExport() {
|
| if (GetInstance())
|
| - GetInstance()->ETWExportEnabled_ = false;
|
| + GetInstance()->etw_export_enabled_ = false;
|
| +}
|
| +
|
| +// static
|
| +bool TraceEventETWExport::IsETWExportEnabled() {
|
| + return (GetInstance() && GetInstance()->etw_export_enabled_);
|
| }
|
|
|
| // static
|
| @@ -129,7 +187,7 @@ void TraceEventETWExport::AddEvent(
|
| const unsigned long long* arg_values,
|
| const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
|
| // We bail early in case exporting is disabled or no consumer is listening.
|
| - if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
|
| + if (!GetInstance() || !GetInstance()->etw_export_enabled_ ||
|
| !EventEnabledChromeEvent())
|
| return;
|
|
|
| @@ -211,7 +269,7 @@ void TraceEventETWExport::AddEvent(
|
| // *total* process CPU time when ETW tracing, and many of the strings
|
| // created exceed WPA's 4094 byte limit and are shown as:
|
| // "Unable to parse data". See crbug.com/488257
|
| - //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
|
| + // convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
|
| } else {
|
| TraceEvent::TraceValue trace_event;
|
| trace_event.as_uint = arg_values[i];
|
| @@ -236,7 +294,7 @@ void TraceEventETWExport::AddCustomEvent(const char* name,
|
| const char* arg_value_2,
|
| const char* arg_name_3,
|
| const char* arg_value_3) {
|
| - if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
|
| + if (!GetInstance() || !GetInstance()->etw_export_enabled_ ||
|
| !EventEnabledChromeEvent())
|
| return;
|
|
|
| @@ -244,8 +302,78 @@ void TraceEventETWExport::AddCustomEvent(const char* name,
|
| arg_value_2, arg_name_3, arg_value_3);
|
| }
|
|
|
| -void TraceEventETWExport::Resurrect() {
|
| - StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
|
| +// static
|
| +bool TraceEventETWExport::IsCategoryGroupEnabled(
|
| + const char* category_group_name) {
|
| + DCHECK(category_group_name);
|
| + auto instance = GetInstance();
|
| + if (instance == nullptr)
|
| + return false;
|
| +
|
| + if (!instance->IsETWExportEnabled())
|
| + return false;
|
| +
|
| + CStringTokenizer category_group_tokens(
|
| + category_group_name, category_group_name + strlen(category_group_name),
|
| + ",");
|
| + while (category_group_tokens.GetNext()) {
|
| + std::string category_group_token = category_group_tokens.token();
|
| + if (instance->IsCategoryEnabled(category_group_token.c_str())) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool TraceEventETWExport::UpdateEnabledCategories() {
|
| + if (etw_match_any_keyword_ == CHROME_Context.MatchAnyKeyword)
|
| + return false;
|
| +
|
| + // If the keyword has changed, update each category.
|
| + // Chrome_Context.MatchAnyKeyword is set by UIforETW (or other ETW trace
|
| + // recording tools) using the ETW infrastructure. This value will be set in
|
| + // all Chrome processes that have registered their ETW provider.
|
| + etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
|
| + for (int i = 0; i < ARRAYSIZE(filtered_event_group_names); i++) {
|
| + if (etw_match_any_keyword_ & (1ULL << i)) {
|
| + categories_status_[filtered_event_group_names[i]] = true;
|
| + } else {
|
| + categories_status_[filtered_event_group_names[i]] = false;
|
| + }
|
| + }
|
| +
|
| + // Also update the two default categories.
|
| + if (etw_match_any_keyword_ & other_events_keyword_bit) {
|
| + categories_status_[other_events_group_name] = true;
|
| + } else {
|
| + categories_status_[other_events_group_name] = false;
|
| + }
|
| + if (etw_match_any_keyword_ & disabled_other_events_keyword_bit) {
|
| + categories_status_[disabled_other_events_group_name] = true;
|
| + } else {
|
| + categories_status_[disabled_other_events_group_name] = false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool TraceEventETWExport::IsCategoryEnabled(const char* category_name) const {
|
| + // Try to find the category and return its status if found
|
| + auto it = categories_status_.find(category_name);
|
| + if (it != categories_status_.end())
|
| + return it->second;
|
| +
|
| + // Otherwise return the corresponding default status by first checking if the
|
| + // category is disabled by default.
|
| + if (StringPiece(category_name).starts_with("disabled-by-default")) {
|
| + DCHECK(categories_status_.find(disabled_other_events_group_name) !=
|
| + categories_status_.end());
|
| + return categories_status_.find(disabled_other_events_group_name)->second;
|
| + } else {
|
| + DCHECK(categories_status_.find(other_events_group_name) !=
|
| + categories_status_.end());
|
| + return categories_status_.find(other_events_group_name)->second;
|
| + }
|
| }
|
|
|
| } // namespace trace_event
|
|
|