diff options
author | georgesak <georgesak@chromium.org> | 2015-06-25 08:17:25 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-25 15:17:46 +0000 |
commit | 40ff770be17a5ffcea06b7475be554118612f4a9 (patch) | |
tree | 6bf6de58e4499d8fc1cd53c93e94ee28ee9a5418 | |
parent | dad2a66e603de9b0f1cdf7e99a010b2cd2ecb711 (diff) | |
download | chromium_src-40ff770be17a5ffcea06b7475be554118612f4a9.zip chromium_src-40ff770be17a5ffcea06b7475be554118612f4a9.tar.gz chromium_src-40ff770be17a5ffcea06b7475be554118612f4a9.tar.bz2 |
[ETW Export] Add event filtering.
This adds the possibility to filter which events get exported via ETW Keywords. 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 behavior. 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 "browser" and "cc" events
xperf -start chrome -on Chrome:0x8000000000000005
# 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.
Notes:
- For now, checking the keyword is only done once, at the start. Polling the value and updating the categories when it changes will be added by a subsequent CL.
- Native support for filtering will be added to UIForETW in a near future.
- Also fixed some outstanding nits from an earlier CL.
BUG=491909
Review URL: https://codereview.chromium.org/1176243016
Cr-Commit-Position: refs/heads/master@{#336156}
-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; |