Chromium Code Reviews| 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.. | |
|
dsinclair
2015/08/11 19:33:14
nit: double .'s at end.
Georges Khalil
2015/08/12 17:24:25
Done.
| |
| 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 while (1) { | |
| 106 base::PlatformThread::Sleep( | |
| 107 base::TimeDelta::FromMilliseconds(kUpdateTimerDelayMs)); | |
|
dsinclair
2015/08/11 19:33:14
Why do the milliseconds conversion every iteration
Georges Khalil
2015/08/12 17:24:25
Done.
| |
| 108 base::trace_event::TraceEventETWExport::UpdateETWKeyword(); | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 private: | |
| 113 // Time between checks for ETW keyword changes (in milliseconds). | |
| 114 unsigned int kUpdateTimerDelayMs = 1000; | |
| 115 }; | |
| 116 | |
| 93 } // namespace | 117 } // namespace |
| 94 | 118 |
| 95 // Redirector function for EventRegister. Called by macros in | 119 // Redirector function for EventRegister. Called by macros in |
| 96 // chrome_events_win.h | 120 // chrome_events_win.h |
| 97 ULONG EVNTAPI EventRegister(LPCGUID ProviderId, | 121 ULONG EVNTAPI EventRegister(LPCGUID ProviderId, |
| 98 PENABLECALLBACK EnableCallback, | 122 PENABLECALLBACK EnableCallback, |
| 99 PVOID CallbackContext, | 123 PVOID CallbackContext, |
| 100 PREGHANDLE RegHandle) { | 124 PREGHANDLE RegHandle) { |
| 101 if (EventRegisterProc) | 125 if (EventRegisterProc) |
| 102 return EventRegisterProc(ProviderId, EnableCallback, CallbackContext, | 126 return EventRegisterProc(ProviderId, EnableCallback, CallbackContext, |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 ::GetProcAddress(AdvapiDLL, "EventRegister")); | 161 ::GetProcAddress(AdvapiDLL, "EventRegister")); |
| 138 EventWriteProc = reinterpret_cast<tEventWrite>( | 162 EventWriteProc = reinterpret_cast<tEventWrite>( |
| 139 ::GetProcAddress(AdvapiDLL, "EventWrite")); | 163 ::GetProcAddress(AdvapiDLL, "EventWrite")); |
| 140 EventUnregisterProc = reinterpret_cast<tEventUnregister>( | 164 EventUnregisterProc = reinterpret_cast<tEventUnregister>( |
| 141 ::GetProcAddress(AdvapiDLL, "EventUnregister")); | 165 ::GetProcAddress(AdvapiDLL, "EventUnregister")); |
| 142 | 166 |
| 143 // Register the ETW provider. If registration fails then the event logging | 167 // Register the ETW provider. If registration fails then the event logging |
| 144 // calls will fail (on XP this call will do nothing). | 168 // calls will fail (on XP this call will do nothing). |
| 145 EventRegisterChrome(); | 169 EventRegisterChrome(); |
| 146 | 170 |
| 147 UpdateEnabledCategories(); | 171 UpdateEnabledCategories(); |
|
Georges Khalil
2015/08/12 17:24:25
I removed this from here and moved it to EnableETW
| |
| 148 } | 172 } |
| 149 } | 173 } |
| 150 | 174 |
| 151 TraceEventETWExport::~TraceEventETWExport() { | 175 TraceEventETWExport::~TraceEventETWExport() { |
| 152 EventUnregisterChrome(); | 176 EventUnregisterChrome(); |
| 153 } | 177 } |
| 154 | 178 |
| 155 // static | 179 // static |
| 156 TraceEventETWExport* TraceEventETWExport::GetInstance() { | 180 TraceEventETWExport* TraceEventETWExport::GetInstance() { |
| 157 return Singleton<TraceEventETWExport, | 181 return Singleton<TraceEventETWExport, |
| 158 StaticMemorySingletonTraits<TraceEventETWExport>>::get(); | 182 StaticMemorySingletonTraits<TraceEventETWExport>>::get(); |
| 159 } | 183 } |
| 160 | 184 |
| 161 // static | 185 // static |
| 162 void TraceEventETWExport::EnableETWExport() { | 186 void TraceEventETWExport::EnableETWExport() { |
| 163 if (GetInstance()) | 187 auto* instance = GetInstance(); |
| 164 GetInstance()->etw_export_enabled_ = true; | 188 if (instance && !instance->etw_export_enabled_) { |
| 189 instance->etw_export_enabled_ = true; | |
| 190 // We only create the update thread once and it lives for as long as Chrome | |
| 191 // is running. | |
| 192 if (instance->keyword_update_thread_handle_.is_null()) { | |
| 193 instance->keyword_update_thread_.reset(new ETWKeywordUpdateThread); | |
| 194 PlatformThread::CreateWithPriority( | |
| 195 0, instance ->keyword_update_thread_.get(), | |
|
dsinclair
2015/08/11 19:33:14
nit: Remove space between instance and ->
Georges Khalil
2015/08/12 17:24:25
Done.
| |
| 196 &instance->keyword_update_thread_handle_, | |
| 197 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 } |
|
dsinclair
2015/08/11 19:33:14
Why don't we shut down the thread at the point we
brucedawson
2015/08/11 20:24:02
Currently this function is never called - there is
Georges Khalil
2015/08/12 17:24:25
Exactly. This might change down the road when we c
dsinclair
2015/08/13 19:03:17
If it's unused, we should probably use it as it's
| |
| 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(); |
| 228 if (!instance || !instance->etw_export_enabled_ || | |
| 191 !EventEnabledChromeEvent()) | 229 !EventEnabledChromeEvent()) |
| 192 return; | 230 return; |
| 193 | 231 |
| 194 const char* phase_string = nullptr; | 232 const char* phase_string = nullptr; |
| 195 // Space to store the phase identifier and null-terminator, when needed. | 233 // Space to store the phase identifier and null-terminator, when needed. |
| 196 char phase_buffer[2]; | 234 char phase_buffer[2]; |
| 197 switch (phase) { | 235 switch (phase) { |
| 198 case TRACE_EVENT_PHASE_BEGIN: | 236 case TRACE_EVENT_PHASE_BEGIN: |
| 199 phase_string = "Begin"; | 237 phase_string = "Begin"; |
| 200 break; | 238 break; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 287 | 325 |
| 288 // static | 326 // static |
| 289 void TraceEventETWExport::AddCustomEvent(const char* name, | 327 void TraceEventETWExport::AddCustomEvent(const char* name, |
| 290 char const* phase, | 328 char const* phase, |
| 291 const char* arg_name_1, | 329 const char* arg_name_1, |
| 292 const char* arg_value_1, | 330 const char* arg_value_1, |
| 293 const char* arg_name_2, | 331 const char* arg_name_2, |
| 294 const char* arg_value_2, | 332 const char* arg_value_2, |
| 295 const char* arg_name_3, | 333 const char* arg_name_3, |
| 296 const char* arg_value_3) { | 334 const char* arg_value_3) { |
| 297 if (!GetInstance() || !GetInstance()->etw_export_enabled_ || | 335 auto* instance = GetInstance(); |
| 336 if (!instance || !instance->etw_export_enabled_ || | |
| 298 !EventEnabledChromeEvent()) | 337 !EventEnabledChromeEvent()) |
| 299 return; | 338 return; |
| 300 | 339 |
| 301 EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2, | 340 EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2, |
| 302 arg_value_2, arg_name_3, arg_value_3); | 341 arg_value_2, arg_name_3, arg_value_3); |
| 303 } | 342 } |
| 304 | 343 |
| 305 // static | 344 // static |
| 306 bool TraceEventETWExport::IsCategoryGroupEnabled( | 345 bool TraceEventETWExport::IsCategoryGroupEnabled( |
| 307 const char* category_group_name) { | 346 const char* category_group_name) { |
| 308 DCHECK(category_group_name); | 347 DCHECK(category_group_name); |
| 309 auto instance = GetInstance(); | 348 auto* instance = GetInstance(); |
| 310 if (instance == nullptr) | 349 if (instance == nullptr) |
| 311 return false; | 350 return false; |
| 312 | 351 |
| 313 if (!instance->IsETWExportEnabled()) | 352 if (!instance->IsETWExportEnabled()) |
| 314 return false; | 353 return false; |
| 315 | 354 |
| 316 CStringTokenizer category_group_tokens( | 355 CStringTokenizer category_group_tokens( |
| 317 category_group_name, category_group_name + strlen(category_group_name), | 356 category_group_name, category_group_name + strlen(category_group_name), |
| 318 ","); | 357 ","); |
| 319 while (category_group_tokens.GetNext()) { | 358 while (category_group_tokens.GetNext()) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 DCHECK(categories_status_.find(disabled_other_events_group_name) != | 408 DCHECK(categories_status_.find(disabled_other_events_group_name) != |
| 370 categories_status_.end()); | 409 categories_status_.end()); |
| 371 return categories_status_.find(disabled_other_events_group_name)->second; | 410 return categories_status_.find(disabled_other_events_group_name)->second; |
| 372 } else { | 411 } else { |
| 373 DCHECK(categories_status_.find(other_events_group_name) != | 412 DCHECK(categories_status_.find(other_events_group_name) != |
| 374 categories_status_.end()); | 413 categories_status_.end()); |
| 375 return categories_status_.find(other_events_group_name)->second; | 414 return categories_status_.find(other_events_group_name)->second; |
| 376 } | 415 } |
| 377 } | 416 } |
| 378 | 417 |
| 418 // static | |
| 419 void TraceEventETWExport::UpdateETWKeyword() { | |
| 420 auto* instance = GetInstance(); | |
| 421 DCHECK(instance); | |
| 422 if (IsETWExportEnabled()) { | |
|
dsinclair
2015/08/11 19:33:14
if (!IsETWExportEnabled())
return;
if (!instance
Georges Khalil
2015/08/12 17:24:25
I changed this. Now UpdateEnabledCategories calls
| |
| 423 if (instance->UpdateEnabledCategories()) | |
| 424 TraceLog::GetInstance()->UpdateCategoryGroupEnabledFlags(); | |
| 425 } | |
| 426 } | |
| 379 } // namespace trace_event | 427 } // namespace trace_event |
| 380 } // namespace base | 428 } // namespace base |
| OLD | NEW |