diff options
-rw-r--r-- | base/trace_event/trace_event_etw_export_win.cc | 135 | ||||
-rw-r--r-- | base/trace_event/trace_event_etw_export_win.h | 28 | ||||
-rw-r--r-- | base/trace_event/trace_event_impl.cc | 4 |
3 files changed, 156 insertions, 11 deletions
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc index d199bf5..47e6353 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,13 @@ 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 @@ -129,7 +182,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 +264,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 +289,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; @@ -248,5 +301,75 @@ 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; +} + +void TraceEventETWExport::UpdateEnabledCategories() { + // 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. + if (etw_match_any_keyword_ != CHROME_Context.MatchAnyKeyword) { + 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; + } +} + +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 } // namespace base diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h index eefe820..a9b580c 100644 --- a/base/trace_event/trace_event_etw_export_win.h +++ b/base/trace_event/trace_event_etw_export_win.h @@ -6,7 +6,10 @@ #ifndef BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_ #define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_ +#include <map> + #include "base/base_export.h" +#include "base/strings/string_piece.h" #include "base/trace_event/trace_event_impl.h" // Fwd. @@ -29,8 +32,8 @@ class BASE_EXPORT TraceEventETWExport { static void EnableETWExport(); static void DisableETWExport(); - static bool isETWExportEnabled() { - return (GetInstance() && GetInstance()->ETWExportEnabled_); + static bool IsETWExportEnabled() { + return (GetInstance() && GetInstance()->etw_match_any_keyword_); } // Exports an event to ETW. This is mainly used in @@ -50,7 +53,7 @@ class BASE_EXPORT TraceEventETWExport { // to ETW. Supports three arguments to be passed to ETW. // TODO(georgesak): Allow different providers. static void AddCustomEvent(const char* name, - char const* phase, + const char* phase, const char* arg_name_1, const char* arg_value_1, const char* arg_name_2, @@ -58,14 +61,31 @@ class BASE_EXPORT TraceEventETWExport { const char* arg_name_3, const char* arg_value_3); + // Returns true if any category in the group is enabled. + static bool IsCategoryGroupEnabled(const char* category_group_name); + void Resurrect(); private: - bool ETWExportEnabled_; // Ensure only the provider can construct us. friend struct StaticMemorySingletonTraits<TraceEventETWExport>; TraceEventETWExport(); + // Updates the list of enabled categories by consulting the ETW keyword. + void UpdateEnabledCategories(); + + // Returns true if the category is enabled. + bool IsCategoryEnabled(const char* category_name) const; + + // True if ETW is enabled. Allows hiding the exporting behind a flag. + bool etw_export_enabled_; + + // Maps category names to their status (enabled/disabled). + std::map<base::StringPiece, bool> categories_status_; + + // Local copy of the ETW keyword. + uint64 etw_match_any_keyword_; + DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport); }; diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc index 3925710..1fc2256 100644 --- a/base/trace_event/trace_event_impl.cc +++ b/base/trace_event/trace_event_impl.cc @@ -1381,8 +1381,10 @@ void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) { event_callback_trace_config_.IsCategoryGroupEnabled(category_group)) enabled_flag |= ENABLED_FOR_EVENT_CALLBACK; #if defined(OS_WIN) - if (base::trace_event::TraceEventETWExport::isETWExportEnabled()) + if (base::trace_event::TraceEventETWExport::IsCategoryGroupEnabled( + category_group)) { enabled_flag |= ENABLED_FOR_ETW_EXPORT; + } #endif g_category_group_enabled[category_index] = enabled_flag; |