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 |