OLD | NEW |
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/string_tokenizer.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/threading/platform_thread.h" |
12 #include "base/trace_event/trace_event.h" | 13 #include "base/trace_event/trace_event.h" |
13 #include "base/trace_event/trace_event_impl.h" | 14 #include "base/trace_event/trace_event_impl.h" |
14 | 15 |
15 // The GetProcAddress technique is borrowed from | 16 // The GetProcAddress technique is borrowed from |
16 // https://github.com/google/UIforETW/tree/master/ETWProviders | 17 // https://github.com/google/UIforETW/tree/master/ETWProviders |
17 // | 18 // |
18 // EVNTAPI is used in evntprov.h which is included by chrome_events_win.h. | 19 // EVNTAPI is used in evntprov.h which is included by chrome_events_win.h. |
19 // We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can | 20 // We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can |
20 // implement these functions locally instead of using the import library, and | 21 // implement these functions locally instead of using the import library, and |
21 // can therefore still run on Windows XP. | 22 // can therefore still run on Windows XP. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 "toplevel", // 0x200 | 84 "toplevel", // 0x200 |
84 "v8", // 0x400 | 85 "v8", // 0x400 |
85 "disabled-by-default-cc.debug", // 0x800 | 86 "disabled-by-default-cc.debug", // 0x800 |
86 "disabled-by-default-cc.debug.picture", // 0x1000 | 87 "disabled-by-default-cc.debug.picture", // 0x1000 |
87 "disabled-by-default-toplevel.flow"}; // 0x2000 | 88 "disabled-by-default-toplevel.flow"}; // 0x2000 |
88 const char* other_events_group_name = "__OTHER_EVENTS"; // 0x2000000000000000 | 89 const char* other_events_group_name = "__OTHER_EVENTS"; // 0x2000000000000000 |
89 const char* disabled_other_events_group_name = | 90 const char* disabled_other_events_group_name = |
90 "__DISABLED_OTHER_EVENTS"; // 0x4000000000000000 | 91 "__DISABLED_OTHER_EVENTS"; // 0x4000000000000000 |
91 uint64 other_events_keyword_bit = 1ULL << 61; | 92 uint64 other_events_keyword_bit = 1ULL << 61; |
92 uint64 disabled_other_events_keyword_bit = 1ULL << 62; | 93 uint64 disabled_other_events_keyword_bit = 1ULL << 62; |
| 94 |
| 95 // This object will be created by each process. It's a background (low-priority) |
| 96 // thread that will monitor the ETW keyword for any changes. |
| 97 class ETWKeywordUpdateThread : public base::PlatformThread::Delegate { |
| 98 public: |
| 99 ETWKeywordUpdateThread() {} |
| 100 ~ETWKeywordUpdateThread() override {} |
| 101 |
| 102 // Implementation of PlatformThread::Delegate: |
| 103 void ThreadMain() override { |
| 104 base::PlatformThread::SetName("ETW Keyword Update Thread"); |
| 105 base::TimeDelta sleep_time = |
| 106 base::TimeDelta::FromMilliseconds(kUpdateTimerDelayMs); |
| 107 while (1) { |
| 108 base::PlatformThread::Sleep(sleep_time); |
| 109 base::trace_event::TraceEventETWExport::UpdateETWKeyword(); |
| 110 } |
| 111 } |
| 112 |
| 113 private: |
| 114 // Time between checks for ETW keyword changes (in milliseconds). |
| 115 unsigned int kUpdateTimerDelayMs = 1000; |
| 116 }; |
| 117 |
93 } // namespace | 118 } // namespace |
94 | 119 |
95 // Redirector function for EventRegister. Called by macros in | 120 // Redirector function for EventRegister. Called by macros in |
96 // chrome_events_win.h | 121 // chrome_events_win.h |
97 ULONG EVNTAPI EventRegister(LPCGUID ProviderId, | 122 ULONG EVNTAPI EventRegister(LPCGUID ProviderId, |
98 PENABLECALLBACK EnableCallback, | 123 PENABLECALLBACK EnableCallback, |
99 PVOID CallbackContext, | 124 PVOID CallbackContext, |
100 PREGHANDLE RegHandle) { | 125 PREGHANDLE RegHandle) { |
101 if (EventRegisterProc) | 126 if (EventRegisterProc) |
102 return EventRegisterProc(ProviderId, EnableCallback, CallbackContext, | 127 return EventRegisterProc(ProviderId, EnableCallback, CallbackContext, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 EventRegisterProc = reinterpret_cast<tEventRegister>( | 161 EventRegisterProc = reinterpret_cast<tEventRegister>( |
137 ::GetProcAddress(AdvapiDLL, "EventRegister")); | 162 ::GetProcAddress(AdvapiDLL, "EventRegister")); |
138 EventWriteProc = reinterpret_cast<tEventWrite>( | 163 EventWriteProc = reinterpret_cast<tEventWrite>( |
139 ::GetProcAddress(AdvapiDLL, "EventWrite")); | 164 ::GetProcAddress(AdvapiDLL, "EventWrite")); |
140 EventUnregisterProc = reinterpret_cast<tEventUnregister>( | 165 EventUnregisterProc = reinterpret_cast<tEventUnregister>( |
141 ::GetProcAddress(AdvapiDLL, "EventUnregister")); | 166 ::GetProcAddress(AdvapiDLL, "EventUnregister")); |
142 | 167 |
143 // Register the ETW provider. If registration fails then the event logging | 168 // Register the ETW provider. If registration fails then the event logging |
144 // calls will fail (on XP this call will do nothing). | 169 // calls will fail (on XP this call will do nothing). |
145 EventRegisterChrome(); | 170 EventRegisterChrome(); |
146 | |
147 UpdateEnabledCategories(); | |
148 } | 171 } |
149 } | 172 } |
150 | 173 |
151 TraceEventETWExport::~TraceEventETWExport() { | 174 TraceEventETWExport::~TraceEventETWExport() { |
152 EventUnregisterChrome(); | 175 EventUnregisterChrome(); |
153 } | 176 } |
154 | 177 |
155 // static | 178 // static |
156 TraceEventETWExport* TraceEventETWExport::GetInstance() { | 179 TraceEventETWExport* TraceEventETWExport::GetInstance() { |
157 return Singleton<TraceEventETWExport, | 180 return Singleton<TraceEventETWExport, |
158 StaticMemorySingletonTraits<TraceEventETWExport>>::get(); | 181 StaticMemorySingletonTraits<TraceEventETWExport>>::get(); |
159 } | 182 } |
160 | 183 |
161 // static | 184 // static |
162 void TraceEventETWExport::EnableETWExport() { | 185 void TraceEventETWExport::EnableETWExport() { |
163 if (GetInstance()) | 186 auto* instance = GetInstance(); |
164 GetInstance()->etw_export_enabled_ = true; | 187 if (instance && !instance->etw_export_enabled_) { |
| 188 instance->etw_export_enabled_ = true; |
| 189 // Sync the enabled categories with ETW by calling UpdateEnabledCategories() |
| 190 // that checks the keyword. Then create a thread that will call that same |
| 191 // function periodically, to make sure we stay in sync. |
| 192 instance->UpdateEnabledCategories(); |
| 193 if (instance->keyword_update_thread_handle_.is_null()) { |
| 194 instance->keyword_update_thread_.reset(new ETWKeywordUpdateThread); |
| 195 PlatformThread::CreateWithPriority( |
| 196 0, instance->keyword_update_thread_.get(), |
| 197 &instance->keyword_update_thread_handle_, ThreadPriority::BACKGROUND); |
| 198 } |
| 199 } |
165 } | 200 } |
166 | 201 |
167 // static | 202 // static |
168 void TraceEventETWExport::DisableETWExport() { | 203 void TraceEventETWExport::DisableETWExport() { |
169 if (GetInstance()) | 204 auto* instance = GetInstance(); |
170 GetInstance()->etw_export_enabled_ = false; | 205 if (instance && instance->etw_export_enabled_) |
| 206 instance->etw_export_enabled_ = false; |
171 } | 207 } |
172 | 208 |
173 // static | 209 // static |
174 bool TraceEventETWExport::IsETWExportEnabled() { | 210 bool TraceEventETWExport::IsETWExportEnabled() { |
175 return (GetInstance() && GetInstance()->etw_export_enabled_); | 211 auto* instance = GetInstance(); |
| 212 return (instance && instance->etw_export_enabled_); |
176 } | 213 } |
177 | 214 |
178 // static | 215 // static |
179 void TraceEventETWExport::AddEvent( | 216 void TraceEventETWExport::AddEvent( |
180 char phase, | 217 char phase, |
181 const unsigned char* category_group_enabled, | 218 const unsigned char* category_group_enabled, |
182 const char* name, | 219 const char* name, |
183 unsigned long long id, | 220 unsigned long long id, |
184 int num_args, | 221 int num_args, |
185 const char** arg_names, | 222 const char** arg_names, |
186 const unsigned char* arg_types, | 223 const unsigned char* arg_types, |
187 const unsigned long long* arg_values, | 224 const unsigned long long* arg_values, |
188 const scoped_refptr<ConvertableToTraceFormat>* convertable_values) { | 225 const scoped_refptr<ConvertableToTraceFormat>* convertable_values) { |
189 // We bail early in case exporting is disabled or no consumer is listening. | 226 // We bail early in case exporting is disabled or no consumer is listening. |
190 if (!GetInstance() || !GetInstance()->etw_export_enabled_ || | 227 auto* instance = GetInstance(); |
191 !EventEnabledChromeEvent()) | 228 if (!instance || !instance->etw_export_enabled_ || !EventEnabledChromeEvent()) |
192 return; | 229 return; |
193 | 230 |
194 const char* phase_string = nullptr; | 231 const char* phase_string = nullptr; |
195 // Space to store the phase identifier and null-terminator, when needed. | 232 // Space to store the phase identifier and null-terminator, when needed. |
196 char phase_buffer[2]; | 233 char phase_buffer[2]; |
197 switch (phase) { | 234 switch (phase) { |
198 case TRACE_EVENT_PHASE_BEGIN: | 235 case TRACE_EVENT_PHASE_BEGIN: |
199 phase_string = "Begin"; | 236 phase_string = "Begin"; |
200 break; | 237 break; |
201 case TRACE_EVENT_PHASE_END: | 238 case TRACE_EVENT_PHASE_END: |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 | 324 |
288 // static | 325 // static |
289 void TraceEventETWExport::AddCustomEvent(const char* name, | 326 void TraceEventETWExport::AddCustomEvent(const char* name, |
290 char const* phase, | 327 char const* phase, |
291 const char* arg_name_1, | 328 const char* arg_name_1, |
292 const char* arg_value_1, | 329 const char* arg_value_1, |
293 const char* arg_name_2, | 330 const char* arg_name_2, |
294 const char* arg_value_2, | 331 const char* arg_value_2, |
295 const char* arg_name_3, | 332 const char* arg_name_3, |
296 const char* arg_value_3) { | 333 const char* arg_value_3) { |
297 if (!GetInstance() || !GetInstance()->etw_export_enabled_ || | 334 auto* instance = GetInstance(); |
298 !EventEnabledChromeEvent()) | 335 if (!instance || !instance->etw_export_enabled_ || !EventEnabledChromeEvent()) |
299 return; | 336 return; |
300 | 337 |
301 EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2, | 338 EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2, |
302 arg_value_2, arg_name_3, arg_value_3); | 339 arg_value_2, arg_name_3, arg_value_3); |
303 } | 340 } |
304 | 341 |
305 // static | 342 // static |
306 bool TraceEventETWExport::IsCategoryGroupEnabled( | 343 bool TraceEventETWExport::IsCategoryGroupEnabled( |
307 const char* category_group_name) { | 344 const char* category_group_name) { |
308 DCHECK(category_group_name); | 345 DCHECK(category_group_name); |
309 auto instance = GetInstance(); | 346 auto* instance = GetInstance(); |
310 if (instance == nullptr) | 347 if (instance == nullptr) |
311 return false; | 348 return false; |
312 | 349 |
313 if (!instance->IsETWExportEnabled()) | 350 if (!instance->IsETWExportEnabled()) |
314 return false; | 351 return false; |
315 | 352 |
316 CStringTokenizer category_group_tokens( | 353 CStringTokenizer category_group_tokens( |
317 category_group_name, category_group_name + strlen(category_group_name), | 354 category_group_name, category_group_name + strlen(category_group_name), |
318 ","); | 355 ","); |
319 while (category_group_tokens.GetNext()) { | 356 while (category_group_tokens.GetNext()) { |
(...skipping 27 matching lines...) Expand all Loading... |
347 categories_status_[other_events_group_name] = true; | 384 categories_status_[other_events_group_name] = true; |
348 } else { | 385 } else { |
349 categories_status_[other_events_group_name] = false; | 386 categories_status_[other_events_group_name] = false; |
350 } | 387 } |
351 if (etw_match_any_keyword_ & disabled_other_events_keyword_bit) { | 388 if (etw_match_any_keyword_ & disabled_other_events_keyword_bit) { |
352 categories_status_[disabled_other_events_group_name] = true; | 389 categories_status_[disabled_other_events_group_name] = true; |
353 } else { | 390 } else { |
354 categories_status_[disabled_other_events_group_name] = false; | 391 categories_status_[disabled_other_events_group_name] = false; |
355 } | 392 } |
356 | 393 |
| 394 // Update the categories in TraceLog. |
| 395 TraceLog::GetInstance()->UpdateETWCategoryGroupEnabledFlags(); |
| 396 |
357 return true; | 397 return true; |
358 } | 398 } |
359 | 399 |
360 bool TraceEventETWExport::IsCategoryEnabled(const char* category_name) const { | 400 bool TraceEventETWExport::IsCategoryEnabled(const char* category_name) const { |
361 // Try to find the category and return its status if found | 401 // Try to find the category and return its status if found |
362 auto it = categories_status_.find(category_name); | 402 auto it = categories_status_.find(category_name); |
363 if (it != categories_status_.end()) | 403 if (it != categories_status_.end()) |
364 return it->second; | 404 return it->second; |
365 | 405 |
366 // Otherwise return the corresponding default status by first checking if the | 406 // Otherwise return the corresponding default status by first checking if the |
367 // category is disabled by default. | 407 // category is disabled by default. |
368 if (StringPiece(category_name).starts_with("disabled-by-default")) { | 408 if (StringPiece(category_name).starts_with("disabled-by-default")) { |
369 DCHECK(categories_status_.find(disabled_other_events_group_name) != | 409 DCHECK(categories_status_.find(disabled_other_events_group_name) != |
370 categories_status_.end()); | 410 categories_status_.end()); |
371 return categories_status_.find(disabled_other_events_group_name)->second; | 411 return categories_status_.find(disabled_other_events_group_name)->second; |
372 } else { | 412 } else { |
373 DCHECK(categories_status_.find(other_events_group_name) != | 413 DCHECK(categories_status_.find(other_events_group_name) != |
374 categories_status_.end()); | 414 categories_status_.end()); |
375 return categories_status_.find(other_events_group_name)->second; | 415 return categories_status_.find(other_events_group_name)->second; |
376 } | 416 } |
377 } | 417 } |
378 | 418 |
| 419 // static |
| 420 void TraceEventETWExport::UpdateETWKeyword() { |
| 421 if (!IsETWExportEnabled()) |
| 422 return; |
| 423 auto* instance = GetInstance(); |
| 424 DCHECK(instance); |
| 425 instance->UpdateEnabledCategories(); |
| 426 } |
379 } // namespace trace_event | 427 } // namespace trace_event |
380 } // namespace base | 428 } // namespace base |
OLD | NEW |