blob: 28c154c1647c37751c1e8ca79f6eb1d4b6cb5b4d [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/trace_event/trace_event_etw_export_win.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_impl.h"
// The GetProcAddress technique is borrowed from
// https://github.com/randomascii/main/tree/master/xperf/ETWProviders
//
// EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
// We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
// implement these functions locally instead of using the import library, and
// can therefore still run on Windows XP.
#define EVNTAPI __stdcall
// Include the event register/write/unregister macros compiled from the manifest
// file. Note that this includes evntprov.h which requires a Vista+ Windows SDK.
//
// In SHARED_INTERMEDIATE_DIR.
#include "base/trace_event/etw_manifest/chrome_events_win.h" // NOLINT
namespace {
// Typedefs for use with GetProcAddress
typedef ULONG(__stdcall* tEventRegister)(LPCGUID ProviderId,
PENABLECALLBACK EnableCallback,
PVOID CallbackContext,
PREGHANDLE RegHandle);
typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle,
PCEVENT_DESCRIPTOR EventDescriptor,
ULONG UserDataCount,
PEVENT_DATA_DESCRIPTOR UserData);
typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
tEventRegister EventRegisterProc = nullptr;
tEventWrite EventWriteProc = nullptr;
tEventUnregister EventUnregisterProc = nullptr;
} // namespace
// Redirector function for EventRegister. Called by macros in
// chrome_events_win.h
ULONG EVNTAPI EventRegister(LPCGUID ProviderId,
PENABLECALLBACK EnableCallback,
PVOID CallbackContext,
PREGHANDLE RegHandle) {
if (EventRegisterProc)
return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
RegHandle);
return 0;
}
// Redirector function for EventWrite. Called by macros in
// chrome_events_win.h
ULONG EVNTAPI EventWrite(REGHANDLE RegHandle,
PCEVENT_DESCRIPTOR EventDescriptor,
ULONG UserDataCount,
PEVENT_DATA_DESCRIPTOR UserData) {
if (EventWriteProc)
return EventWriteProc(RegHandle, EventDescriptor, UserDataCount, UserData);
return 0;
}
// Redirector function for EventUnregister. Called by macros in
// chrome_events_win.h
ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
if (EventUnregisterProc)
return EventUnregisterProc(RegHandle);
return 0;
}
namespace base {
namespace trace_event {
TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
// Find Advapi32.dll. This should always succeed.
HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
if (AdvapiDLL) {
// Try to find the ETW functions. This will fail on XP.
EventRegisterProc = reinterpret_cast<tEventRegister>(
::GetProcAddress(AdvapiDLL, "EventRegister"));
EventWriteProc = reinterpret_cast<tEventWrite>(
::GetProcAddress(AdvapiDLL, "EventWrite"));
EventUnregisterProc = reinterpret_cast<tEventUnregister>(
::GetProcAddress(AdvapiDLL, "EventUnregister"));
// Register the ETW provider. If registration fails then the event logging
// calls will fail (on XP this call will do nothing).
EventRegisterChrome();
}
}
TraceEventETWExport::~TraceEventETWExport() {
EventUnregisterChrome();
}
// static
TraceEventETWExport* TraceEventETWExport::GetInstance() {
return Singleton<TraceEventETWExport,
StaticMemorySingletonTraits<TraceEventETWExport>>::get();
}
// static
void TraceEventETWExport::EnableETWExport() {
if (GetInstance())
GetInstance()->ETWExportEnabled_ = true;
}
// static
void TraceEventETWExport::DisableETWExport() {
if (GetInstance())
GetInstance()->ETWExportEnabled_ = false;
}
// static
void TraceEventETWExport::AddEvent(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
// We bail early in case exporting is disabled or no consumer is listening.
if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
!EventEnabledChromeEvent())
return;
const char* phase_string = nullptr;
// Space to store the phase identifier and null-terminator, when needed.
char phase_buffer[2];
switch (phase) {
case TRACE_EVENT_PHASE_BEGIN:
phase_string = "Begin";
break;
case TRACE_EVENT_PHASE_END:
phase_string = "End";
break;
case TRACE_EVENT_PHASE_COMPLETE:
phase_string = "Complete";
break;
case TRACE_EVENT_PHASE_INSTANT:
phase_string = "Instant";
break;
case TRACE_EVENT_PHASE_ASYNC_BEGIN:
phase_string = "Async Begin";
break;
case TRACE_EVENT_PHASE_ASYNC_STEP_INTO:
phase_string = "Async Step Into";
break;
case TRACE_EVENT_PHASE_ASYNC_STEP_PAST:
phase_string = "Async Step Past";
break;
case TRACE_EVENT_PHASE_ASYNC_END:
phase_string = "Async End";
break;
case TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN:
phase_string = "Nestable Async Begin";
break;
case TRACE_EVENT_PHASE_NESTABLE_ASYNC_END:
phase_string = "Nestable Async End";
break;
case TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT:
phase_string = "Nestable Async Instant";
break;
case TRACE_EVENT_PHASE_FLOW_BEGIN:
phase_string = "Phase Flow Begin";
break;
case TRACE_EVENT_PHASE_FLOW_STEP:
phase_string = "Phase Flow Step";
break;
case TRACE_EVENT_PHASE_FLOW_END:
phase_string = "Phase Flow End";
break;
case TRACE_EVENT_PHASE_METADATA:
phase_string = "Phase Metadata";
break;
case TRACE_EVENT_PHASE_COUNTER:
phase_string = "Phase Counter";
break;
case TRACE_EVENT_PHASE_SAMPLE:
phase_string = "Phase Sample";
break;
case TRACE_EVENT_PHASE_CREATE_OBJECT:
phase_string = "Phase Create Object";
break;
case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT:
phase_string = "Phase Snapshot Object";
break;
case TRACE_EVENT_PHASE_DELETE_OBJECT:
phase_string = "Phase Delete Object";
break;
default:
phase_buffer[0] = phase;
phase_buffer[1] = 0;
phase_string = phase_buffer;
break;
}
std::string arg_values_string[3];
for (int i = 0; i < num_args; i++) {
if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
// Temporarily do nothing here. This function consumes 1/3 to 1/2 of
// *total* process CPU time when ETW tracing, and many of the strings
// created exceed WPA's 4094 byte limit and are shown as:
// "Unable to parse data". See crbug.com/488257
//convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
} else {
TraceEvent::TraceValue trace_event;
trace_event.as_uint = arg_values[i];
TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
arg_values_string + i);
}
}
EventWriteChromeEvent(
name, phase_string, num_args > 0 ? arg_names[0] : "",
arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
arg_values_string[2].c_str());
}
// static
void TraceEventETWExport::AddCustomEvent(const char* name,
char const* phase,
const char* arg_name_1,
const char* arg_value_1,
const char* arg_name_2,
const char* arg_value_2,
const char* arg_name_3,
const char* arg_value_3) {
if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
!EventEnabledChromeEvent())
return;
EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
arg_value_2, arg_name_3, arg_value_3);
}
void TraceEventETWExport::Resurrect() {
StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
}
} // namespace trace_event
} // namespace base