Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: base/trace_event/trace_event_etw_export_win.cc

Issue 1641513004: Update //base to chromium 9659b08ea5a34f889dc4166217f438095ddc10d2 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/trace_event/trace_event_etw_export_win.h" 5 #include "base/trace_event/trace_event_etw_export_win.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/singleton.h" 9 #include "base/memory/singleton.h"
10 #include "base/strings/string_tokenizer.h"
10 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
11 #include "base/trace_event/trace_event.h" 12 #include "base/trace_event/trace_event.h"
12 #include "base/trace_event/trace_event_impl.h" 13 #include "base/trace_event/trace_event_impl.h"
13 14
14 // The GetProcAddress technique is borrowed from 15 // The GetProcAddress technique is borrowed from
15 // https://github.com/google/UIforETW/tree/master/ETWProviders 16 // https://github.com/google/UIforETW/tree/master/ETWProviders
16 // 17 //
17 // EVNTAPI is used in evntprov.h which is included by chrome_events_win.h. 18 // EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
18 // We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can 19 // We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
19 // implement these functions locally instead of using the import library, and 20 // implement these functions locally instead of using the import library, and
(...skipping 13 matching lines...) Expand all
33 PREGHANDLE RegHandle); 34 PREGHANDLE RegHandle);
34 typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle, 35 typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle,
35 PCEVENT_DESCRIPTOR EventDescriptor, 36 PCEVENT_DESCRIPTOR EventDescriptor,
36 ULONG UserDataCount, 37 ULONG UserDataCount,
37 PEVENT_DATA_DESCRIPTOR UserData); 38 PEVENT_DATA_DESCRIPTOR UserData);
38 typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle); 39 typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
39 40
40 tEventRegister EventRegisterProc = nullptr; 41 tEventRegister EventRegisterProc = nullptr;
41 tEventWrite EventWriteProc = nullptr; 42 tEventWrite EventWriteProc = nullptr;
42 tEventUnregister EventUnregisterProc = nullptr; 43 tEventUnregister EventUnregisterProc = nullptr;
44
45 // |filtered_event_group_names| contains the event categories that can be
46 // exported individually. These categories can be enabled by passing the correct
47 // keyword when starting the trace. A keyword is a 64-bit flag and we attribute
48 // one bit per category. We can therefore enable a particular category by
49 // setting its corresponding bit in the keyword. For events that are not present
50 // in |filtered_event_group_names|, we have two bits that control their
51 // behaviour. When bit 61 is enabled, any event that is not disabled by default
52 // (ie. doesn't start with disabled-by-default-) will be exported. Likewise,
53 // when bit 62 is enabled, any event that is disabled by default will be
54 // exported.
55 //
56 // Note that bit 63 (MSB) must always be set, otherwise tracing will be disabled
57 // by ETW. Therefore, the keyword will always be greater than
58 // 0x8000000000000000.
59 //
60 // Examples of passing keywords to the provider using xperf:
61 // # This exports "benchmark" and "cc" events
62 // xperf -start chrome -on Chrome:0x8000000000000009
63 //
64 // # This exports "gpu", "netlog" and all other events that are not disabled by
65 // # default
66 // xperf -start chrome -on Chrome:0xA0000000000000A0
67 //
68 // More info about starting a trace and keyword can be obtained by using the
69 // help section of xperf (xperf -help start). Note that xperf documentation
70 // refers to keywords as flags and there are two ways to enable them, using
71 // group names or the hex representation. We only support the latter. Also, we
72 // ignore the level.
73 const char* const filtered_event_group_names[] = {
74 "benchmark", // 0x1
75 "blink", // 0x2
76 "browser", // 0x4
77 "cc", // 0x8
78 "evdev", // 0x10
79 "gpu", // 0x20
80 "input", // 0x40
81 "netlog", // 0x80
82 "renderer.scheduler", // 0x100
83 "toplevel", // 0x200
84 "v8", // 0x400
85 "disabled-by-default-cc.debug", // 0x800
86 "disabled-by-default-cc.debug.picture", // 0x1000
87 "disabled-by-default-toplevel.flow"}; // 0x2000
88 const char* other_events_group_name = "__OTHER_EVENTS"; // 0x2000000000000000
89 const char* disabled_other_events_group_name =
90 "__DISABLED_OTHER_EVENTS"; // 0x4000000000000000
91 uint64 other_events_keyword_bit = 1ULL << 61;
92 uint64 disabled_other_events_keyword_bit = 1ULL << 62;
43 } // namespace 93 } // namespace
44 94
45 // Redirector function for EventRegister. Called by macros in 95 // Redirector function for EventRegister. Called by macros in
46 // chrome_events_win.h 96 // chrome_events_win.h
47 ULONG EVNTAPI EventRegister(LPCGUID ProviderId, 97 ULONG EVNTAPI EventRegister(LPCGUID ProviderId,
48 PENABLECALLBACK EnableCallback, 98 PENABLECALLBACK EnableCallback,
49 PVOID CallbackContext, 99 PVOID CallbackContext,
50 PREGHANDLE RegHandle) { 100 PREGHANDLE RegHandle) {
51 if (EventRegisterProc) 101 if (EventRegisterProc)
52 return EventRegisterProc(ProviderId, EnableCallback, CallbackContext, 102 return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
(...skipping 17 matching lines...) Expand all
70 // chrome_events_win.h 120 // chrome_events_win.h
71 ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) { 121 ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
72 if (EventUnregisterProc) 122 if (EventUnregisterProc)
73 return EventUnregisterProc(RegHandle); 123 return EventUnregisterProc(RegHandle);
74 return 0; 124 return 0;
75 } 125 }
76 126
77 namespace base { 127 namespace base {
78 namespace trace_event { 128 namespace trace_event {
79 129
80 TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) { 130 TraceEventETWExport::TraceEventETWExport()
131 : etw_export_enabled_(false), etw_match_any_keyword_(0ULL) {
81 // Find Advapi32.dll. This should always succeed. 132 // Find Advapi32.dll. This should always succeed.
82 HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll"); 133 HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
83 if (AdvapiDLL) { 134 if (AdvapiDLL) {
84 // Try to find the ETW functions. This will fail on XP. 135 // Try to find the ETW functions. This will fail on XP.
85 EventRegisterProc = reinterpret_cast<tEventRegister>( 136 EventRegisterProc = reinterpret_cast<tEventRegister>(
86 ::GetProcAddress(AdvapiDLL, "EventRegister")); 137 ::GetProcAddress(AdvapiDLL, "EventRegister"));
87 EventWriteProc = reinterpret_cast<tEventWrite>( 138 EventWriteProc = reinterpret_cast<tEventWrite>(
88 ::GetProcAddress(AdvapiDLL, "EventWrite")); 139 ::GetProcAddress(AdvapiDLL, "EventWrite"));
89 EventUnregisterProc = reinterpret_cast<tEventUnregister>( 140 EventUnregisterProc = reinterpret_cast<tEventUnregister>(
90 ::GetProcAddress(AdvapiDLL, "EventUnregister")); 141 ::GetProcAddress(AdvapiDLL, "EventUnregister"));
91 142
92 // Register the ETW provider. If registration fails then the event logging 143 // Register the ETW provider. If registration fails then the event logging
93 // calls will fail (on XP this call will do nothing). 144 // calls will fail (on XP this call will do nothing).
94 EventRegisterChrome(); 145 EventRegisterChrome();
146
147 UpdateEnabledCategories();
95 } 148 }
96 } 149 }
97 150
98 TraceEventETWExport::~TraceEventETWExport() { 151 TraceEventETWExport::~TraceEventETWExport() {
99 EventUnregisterChrome(); 152 EventUnregisterChrome();
100 } 153 }
101 154
102 // static 155 // static
103 TraceEventETWExport* TraceEventETWExport::GetInstance() { 156 TraceEventETWExport* TraceEventETWExport::GetInstance() {
104 return Singleton<TraceEventETWExport, 157 return Singleton<TraceEventETWExport,
105 StaticMemorySingletonTraits<TraceEventETWExport>>::get(); 158 StaticMemorySingletonTraits<TraceEventETWExport>>::get();
106 } 159 }
107 160
108 // static 161 // static
109 void TraceEventETWExport::EnableETWExport() { 162 void TraceEventETWExport::EnableETWExport() {
110 if (GetInstance()) 163 if (GetInstance())
111 GetInstance()->ETWExportEnabled_ = true; 164 GetInstance()->etw_export_enabled_ = true;
112 } 165 }
113 166
114 // static 167 // static
115 void TraceEventETWExport::DisableETWExport() { 168 void TraceEventETWExport::DisableETWExport() {
116 if (GetInstance()) 169 if (GetInstance())
117 GetInstance()->ETWExportEnabled_ = false; 170 GetInstance()->etw_export_enabled_ = false;
118 } 171 }
119 172
120 // static 173 // static
174 bool TraceEventETWExport::IsETWExportEnabled() {
175 return (GetInstance() && GetInstance()->etw_export_enabled_);
176 }
177
178 // static
121 void TraceEventETWExport::AddEvent( 179 void TraceEventETWExport::AddEvent(
122 char phase, 180 char phase,
123 const unsigned char* category_group_enabled, 181 const unsigned char* category_group_enabled,
124 const char* name, 182 const char* name,
125 unsigned long long id, 183 unsigned long long id,
126 int num_args, 184 int num_args,
127 const char** arg_names, 185 const char** arg_names,
128 const unsigned char* arg_types, 186 const unsigned char* arg_types,
129 const unsigned long long* arg_values, 187 const unsigned long long* arg_values,
130 const scoped_refptr<ConvertableToTraceFormat>* convertable_values) { 188 const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
131 // We bail early in case exporting is disabled or no consumer is listening. 189 // We bail early in case exporting is disabled or no consumer is listening.
132 if (!GetInstance() || !GetInstance()->ETWExportEnabled_ || 190 if (!GetInstance() || !GetInstance()->etw_export_enabled_ ||
133 !EventEnabledChromeEvent()) 191 !EventEnabledChromeEvent())
134 return; 192 return;
135 193
136 const char* phase_string = nullptr; 194 const char* phase_string = nullptr;
137 // Space to store the phase identifier and null-terminator, when needed. 195 // Space to store the phase identifier and null-terminator, when needed.
138 char phase_buffer[2]; 196 char phase_buffer[2];
139 switch (phase) { 197 switch (phase) {
140 case TRACE_EVENT_PHASE_BEGIN: 198 case TRACE_EVENT_PHASE_BEGIN:
141 phase_string = "Begin"; 199 phase_string = "Begin";
142 break; 200 break;
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 break; 262 break;
205 } 263 }
206 264
207 std::string arg_values_string[3]; 265 std::string arg_values_string[3];
208 for (int i = 0; i < num_args; i++) { 266 for (int i = 0; i < num_args; i++) {
209 if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) { 267 if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
210 // Temporarily do nothing here. This function consumes 1/3 to 1/2 of 268 // Temporarily do nothing here. This function consumes 1/3 to 1/2 of
211 // *total* process CPU time when ETW tracing, and many of the strings 269 // *total* process CPU time when ETW tracing, and many of the strings
212 // created exceed WPA's 4094 byte limit and are shown as: 270 // created exceed WPA's 4094 byte limit and are shown as:
213 // "Unable to parse data". See crbug.com/488257 271 // "Unable to parse data". See crbug.com/488257
214 //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i); 272 // convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
215 } else { 273 } else {
216 TraceEvent::TraceValue trace_event; 274 TraceEvent::TraceValue trace_event;
217 trace_event.as_uint = arg_values[i]; 275 trace_event.as_uint = arg_values[i];
218 TraceEvent::AppendValueAsJSON(arg_types[i], trace_event, 276 TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
219 arg_values_string + i); 277 arg_values_string + i);
220 } 278 }
221 } 279 }
222 280
223 EventWriteChromeEvent( 281 EventWriteChromeEvent(
224 name, phase_string, num_args > 0 ? arg_names[0] : "", 282 name, phase_string, num_args > 0 ? arg_names[0] : "",
225 arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "", 283 arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
226 arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "", 284 arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
227 arg_values_string[2].c_str()); 285 arg_values_string[2].c_str());
228 } 286 }
229 287
230 // static 288 // static
231 void TraceEventETWExport::AddCustomEvent(const char* name, 289 void TraceEventETWExport::AddCustomEvent(const char* name,
232 char const* phase, 290 char const* phase,
233 const char* arg_name_1, 291 const char* arg_name_1,
234 const char* arg_value_1, 292 const char* arg_value_1,
235 const char* arg_name_2, 293 const char* arg_name_2,
236 const char* arg_value_2, 294 const char* arg_value_2,
237 const char* arg_name_3, 295 const char* arg_name_3,
238 const char* arg_value_3) { 296 const char* arg_value_3) {
239 if (!GetInstance() || !GetInstance()->ETWExportEnabled_ || 297 if (!GetInstance() || !GetInstance()->etw_export_enabled_ ||
240 !EventEnabledChromeEvent()) 298 !EventEnabledChromeEvent())
241 return; 299 return;
242 300
243 EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2, 301 EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
244 arg_value_2, arg_name_3, arg_value_3); 302 arg_value_2, arg_name_3, arg_value_3);
245 } 303 }
246 304
247 void TraceEventETWExport::Resurrect() { 305 // static
248 StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect(); 306 bool TraceEventETWExport::IsCategoryGroupEnabled(
307 const char* category_group_name) {
308 DCHECK(category_group_name);
309 auto instance = GetInstance();
310 if (instance == nullptr)
311 return false;
312
313 if (!instance->IsETWExportEnabled())
314 return false;
315
316 CStringTokenizer category_group_tokens(
317 category_group_name, category_group_name + strlen(category_group_name),
318 ",");
319 while (category_group_tokens.GetNext()) {
320 std::string category_group_token = category_group_tokens.token();
321 if (instance->IsCategoryEnabled(category_group_token.c_str())) {
322 return true;
323 }
324 }
325 return false;
326 }
327
328 bool TraceEventETWExport::UpdateEnabledCategories() {
329 if (etw_match_any_keyword_ == CHROME_Context.MatchAnyKeyword)
330 return false;
331
332 // If the keyword has changed, update each category.
333 // Chrome_Context.MatchAnyKeyword is set by UIforETW (or other ETW trace
334 // recording tools) using the ETW infrastructure. This value will be set in
335 // all Chrome processes that have registered their ETW provider.
336 etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
337 for (int i = 0; i < ARRAYSIZE(filtered_event_group_names); i++) {
338 if (etw_match_any_keyword_ & (1ULL << i)) {
339 categories_status_[filtered_event_group_names[i]] = true;
340 } else {
341 categories_status_[filtered_event_group_names[i]] = false;
342 }
343 }
344
345 // Also update the two default categories.
346 if (etw_match_any_keyword_ & other_events_keyword_bit) {
347 categories_status_[other_events_group_name] = true;
348 } else {
349 categories_status_[other_events_group_name] = false;
350 }
351 if (etw_match_any_keyword_ & disabled_other_events_keyword_bit) {
352 categories_status_[disabled_other_events_group_name] = true;
353 } else {
354 categories_status_[disabled_other_events_group_name] = false;
355 }
356
357 return true;
358 }
359
360 bool TraceEventETWExport::IsCategoryEnabled(const char* category_name) const {
361 // Try to find the category and return its status if found
362 auto it = categories_status_.find(category_name);
363 if (it != categories_status_.end())
364 return it->second;
365
366 // Otherwise return the corresponding default status by first checking if the
367 // category is disabled by default.
368 if (StringPiece(category_name).starts_with("disabled-by-default")) {
369 DCHECK(categories_status_.find(disabled_other_events_group_name) !=
370 categories_status_.end());
371 return categories_status_.find(disabled_other_events_group_name)->second;
372 } else {
373 DCHECK(categories_status_.find(other_events_group_name) !=
374 categories_status_.end());
375 return categories_status_.find(other_events_group_name)->second;
376 }
249 } 377 }
250 378
251 } // namespace trace_event 379 } // namespace trace_event
252 } // namespace base 380 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698