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
3 // found in the LICENSE file.
5 #include "base/trace_event/trace_event_etw_export_win.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/memory/singleton.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/trace_event/trace_event.h"
12 #include "base/trace_event/trace_event_impl.h"
14 // The GetProcAddress technique is borrowed from
15 // https://github.com/google/UIforETW/tree/master/ETWProviders
17 // 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 // implement these functions locally instead of using the import library, and
20 // can therefore still run on Windows XP.
21 #define EVNTAPI __stdcall
22 // Include the event register/write/unregister macros compiled from the manifest
23 // file. Note that this includes evntprov.h which requires a Vista+ Windows SDK.
25 // In SHARED_INTERMEDIATE_DIR.
26 #include "base/trace_event/etw_manifest/chrome_events_win.h" // NOLINT
29 // Typedefs for use with GetProcAddress
30 typedef ULONG(__stdcall
* tEventRegister
)(LPCGUID ProviderId
,
31 PENABLECALLBACK EnableCallback
,
32 PVOID CallbackContext
,
33 PREGHANDLE RegHandle
);
34 typedef ULONG(__stdcall
* tEventWrite
)(REGHANDLE RegHandle
,
35 PCEVENT_DESCRIPTOR EventDescriptor
,
37 PEVENT_DATA_DESCRIPTOR UserData
);
38 typedef ULONG(__stdcall
* tEventUnregister
)(REGHANDLE RegHandle
);
40 tEventRegister EventRegisterProc
= nullptr;
41 tEventWrite EventWriteProc
= nullptr;
42 tEventUnregister EventUnregisterProc
= nullptr;
45 // Redirector function for EventRegister. Called by macros in
46 // chrome_events_win.h
47 ULONG EVNTAPI
EventRegister(LPCGUID ProviderId
,
48 PENABLECALLBACK EnableCallback
,
49 PVOID CallbackContext
,
50 PREGHANDLE RegHandle
) {
51 if (EventRegisterProc
)
52 return EventRegisterProc(ProviderId
, EnableCallback
, CallbackContext
,
58 // Redirector function for EventWrite. Called by macros in
59 // chrome_events_win.h
60 ULONG EVNTAPI
EventWrite(REGHANDLE RegHandle
,
61 PCEVENT_DESCRIPTOR EventDescriptor
,
63 PEVENT_DATA_DESCRIPTOR UserData
) {
65 return EventWriteProc(RegHandle
, EventDescriptor
, UserDataCount
, UserData
);
69 // Redirector function for EventUnregister. Called by macros in
70 // chrome_events_win.h
71 ULONG EVNTAPI
EventUnregister(REGHANDLE RegHandle
) {
72 if (EventUnregisterProc
)
73 return EventUnregisterProc(RegHandle
);
78 namespace trace_event
{
80 TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
81 // Find Advapi32.dll. This should always succeed.
82 HMODULE AdvapiDLL
= ::LoadLibraryW(L
"Advapi32.dll");
84 // Try to find the ETW functions. This will fail on XP.
85 EventRegisterProc
= reinterpret_cast<tEventRegister
>(
86 ::GetProcAddress(AdvapiDLL
, "EventRegister"));
87 EventWriteProc
= reinterpret_cast<tEventWrite
>(
88 ::GetProcAddress(AdvapiDLL
, "EventWrite"));
89 EventUnregisterProc
= reinterpret_cast<tEventUnregister
>(
90 ::GetProcAddress(AdvapiDLL
, "EventUnregister"));
92 // Register the ETW provider. If registration fails then the event logging
93 // calls will fail (on XP this call will do nothing).
94 EventRegisterChrome();
98 TraceEventETWExport::~TraceEventETWExport() {
99 EventUnregisterChrome();
103 TraceEventETWExport
* TraceEventETWExport::GetInstance() {
104 return Singleton
<TraceEventETWExport
,
105 StaticMemorySingletonTraits
<TraceEventETWExport
>>::get();
109 void TraceEventETWExport::EnableETWExport() {
111 GetInstance()->ETWExportEnabled_
= true;
115 void TraceEventETWExport::DisableETWExport() {
117 GetInstance()->ETWExportEnabled_
= false;
121 void TraceEventETWExport::AddEvent(
123 const unsigned char* category_group_enabled
,
125 unsigned long long id
,
127 const char** arg_names
,
128 const unsigned char* arg_types
,
129 const unsigned long long* arg_values
,
130 const scoped_refptr
<ConvertableToTraceFormat
>* convertable_values
) {
131 // We bail early in case exporting is disabled or no consumer is listening.
132 if (!GetInstance() || !GetInstance()->ETWExportEnabled_
||
133 !EventEnabledChromeEvent())
136 const char* phase_string
= nullptr;
137 // Space to store the phase identifier and null-terminator, when needed.
138 char phase_buffer
[2];
140 case TRACE_EVENT_PHASE_BEGIN
:
141 phase_string
= "Begin";
143 case TRACE_EVENT_PHASE_END
:
144 phase_string
= "End";
146 case TRACE_EVENT_PHASE_COMPLETE
:
147 phase_string
= "Complete";
149 case TRACE_EVENT_PHASE_INSTANT
:
150 phase_string
= "Instant";
152 case TRACE_EVENT_PHASE_ASYNC_BEGIN
:
153 phase_string
= "Async Begin";
155 case TRACE_EVENT_PHASE_ASYNC_STEP_INTO
:
156 phase_string
= "Async Step Into";
158 case TRACE_EVENT_PHASE_ASYNC_STEP_PAST
:
159 phase_string
= "Async Step Past";
161 case TRACE_EVENT_PHASE_ASYNC_END
:
162 phase_string
= "Async End";
164 case TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
:
165 phase_string
= "Nestable Async Begin";
167 case TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
:
168 phase_string
= "Nestable Async End";
170 case TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT
:
171 phase_string
= "Nestable Async Instant";
173 case TRACE_EVENT_PHASE_FLOW_BEGIN
:
174 phase_string
= "Phase Flow Begin";
176 case TRACE_EVENT_PHASE_FLOW_STEP
:
177 phase_string
= "Phase Flow Step";
179 case TRACE_EVENT_PHASE_FLOW_END
:
180 phase_string
= "Phase Flow End";
182 case TRACE_EVENT_PHASE_METADATA
:
183 phase_string
= "Phase Metadata";
185 case TRACE_EVENT_PHASE_COUNTER
:
186 phase_string
= "Phase Counter";
188 case TRACE_EVENT_PHASE_SAMPLE
:
189 phase_string
= "Phase Sample";
191 case TRACE_EVENT_PHASE_CREATE_OBJECT
:
192 phase_string
= "Phase Create Object";
194 case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT
:
195 phase_string
= "Phase Snapshot Object";
197 case TRACE_EVENT_PHASE_DELETE_OBJECT
:
198 phase_string
= "Phase Delete Object";
201 phase_buffer
[0] = phase
;
203 phase_string
= phase_buffer
;
207 std::string arg_values_string
[3];
208 for (int i
= 0; i
< num_args
; i
++) {
209 if (arg_types
[i
] == TRACE_VALUE_TYPE_CONVERTABLE
) {
210 // 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
212 // created exceed WPA's 4094 byte limit and are shown as:
213 // "Unable to parse data". See crbug.com/488257
214 //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
216 TraceEvent::TraceValue trace_event
;
217 trace_event
.as_uint
= arg_values
[i
];
218 TraceEvent::AppendValueAsJSON(arg_types
[i
], trace_event
,
219 arg_values_string
+ i
);
223 EventWriteChromeEvent(
224 name
, phase_string
, num_args
> 0 ? arg_names
[0] : "",
225 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] : "",
227 arg_values_string
[2].c_str());
231 void TraceEventETWExport::AddCustomEvent(const char* name
,
233 const char* arg_name_1
,
234 const char* arg_value_1
,
235 const char* arg_name_2
,
236 const char* arg_value_2
,
237 const char* arg_name_3
,
238 const char* arg_value_3
) {
239 if (!GetInstance() || !GetInstance()->ETWExportEnabled_
||
240 !EventEnabledChromeEvent())
243 EventWriteChromeEvent(name
, phase
, arg_name_1
, arg_value_1
, arg_name_2
,
244 arg_value_2
, arg_name_3
, arg_value_3
);
247 void TraceEventETWExport::Resurrect() {
248 StaticMemorySingletonTraits
<TraceEventETWExport
>::Resurrect();
251 } // namespace trace_event