Commit 28ad5e6b authored by georgesak's avatar georgesak Committed by Commit bot

Add option to export tracing events to ETW.

- Exporting of ETW events can be turned on using --trace-export-events-to-etw.

BUG=

Committed: https://crrev.com/1cc86c4f686869f32dfede093a07828c73563892
Cr-Commit-Position: refs/heads/master@{#324982}

Review URL: https://codereview.chromium.org/1038453002

Cr-Commit-Position: refs/heads/master@{#325408}
parent c1379a6a
......@@ -190,6 +190,9 @@
],
},
],
'dependencies': [
'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
],
}],
['OS == "mac" or (OS == "ios" and _toolset == "host")', {
'link_settings': {
......
......@@ -26,6 +26,8 @@ source_set("trace_event") {
"trace_event_android.cc",
"trace_event_argument.cc",
"trace_event_argument.h",
"trace_event_etw_export_win.cc",
"trace_event_etw_export_win.h",
"trace_event_impl.cc",
"trace_event_impl.h",
"trace_event_impl_constants.cc",
......@@ -63,6 +65,10 @@ source_set("trace_event") {
"//base/third_party/dynamic_annotations",
]
if (is_win) {
deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
}
allow_circular_includes_from = [
"//base/debug",
"//base/memory",
......
# 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.
assert(is_win, "This only runs on Windows.")
# Makes the .h/.rc files from the .man file.
action("chrome_events_win") {
visibility = [
"//base/trace_event/*",
"//chrome:main_dll",
]
script = "build/message_compiler.py"
sources = [
"chrome_events_win.man",
]
outputs = [
"$target_gen_dir/chrome_events_win.h",
"$target_gen_dir/chrome_events_win.rc",
]
args = [
# Where to put the header.
"-h",
rebase_path("$target_gen_dir", root_build_dir),
# Where to put the .rc file.
"-r",
rebase_path("$target_gen_dir", root_build_dir),
# Generate the user-mode code.
"-um",
rebase_path("chrome_events_win.man", root_build_dir),
]
}
# 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.
# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
# GN build, which can only run Python and not native binaries.
import subprocess
import sys
# mc writes to stderr, so this explicily redirects to stdout and eats it.
try:
subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
print e.output
sys.exit(e.returncode)
<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<instrumentationManifest
xmlns="http://schemas.microsoft.com/win/2004/08/events"
xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
>
<instrumentation>
<events>
<provider
guid="{D2D578D9-2936-45B6-A09f-30E32715F42D}"
messageFileName="chrome.dll"
name="Chrome"
resourceFileName="chrome.dll"
symbol="CHROME"
>
<channels>
<importChannel
chid="SYSTEM"
name="System"
/>
</channels>
<templates>
<template tid="tid_chrome_event">
<data
inType="win:AnsiString"
name="Name"
/>
<data
inType="win:AnsiString"
name="Phase"
/>
<data
inType="win:AnsiString"
name="Arg Name 1"
/>
<data
inType="win:AnsiString"
name="Arg Value 1"
/>
<data
inType="win:AnsiString"
name="Arg Name 2"
/>
<data
inType="win:AnsiString"
name="Arg Value 2"
/>
<data
inType="win:AnsiString"
name="Arg Name 3"
/>
<data
inType="win:AnsiString"
name="Arg Value 3"
/>
</template>
</templates>
<events>
<event
channel="SYSTEM"
level="win:Informational"
message="$(string.ChromeEvent.EventMessage)"
opcode="win:Info"
symbol="ChromeEvent"
template="tid_chrome_event"
value="1"
/>
</events>
</provider>
</events>
</instrumentation>
<localization xmlns="http://schemas.microsoft.com/win/2004/08/events">
<resources culture="en-US">
<stringTable>
<string
id="ChromeEvent.EventMessage"
value="Chrome Event: %1 (%2)"
/>
</stringTable>
</resources>
</localization>
</instrumentationManifest>
# 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.
{
'targets': [
{
# GN version: //base/trace_event/etw_manifest/BUILD.gn
'target_name': 'etw_manifest',
'type': 'static_library',
'conditions': [
['OS=="win"', {
'sources': [
'chrome_events_win.man',
],
'variables': {
'man_output_dir': '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest',
},
'rules': [{
# Rule to run the message compiler.
'rule_name': 'message_compiler',
'extension': 'man',
'outputs': [
'<(man_output_dir)/chrome_events_win.h',
'<(man_output_dir)/chrome_events_win.rc',
],
'action': [
'mc.exe',
'-h', '<(man_output_dir)',
'-r', '<(man_output_dir)/.',
'-um',
'<(RULE_INPUT_PATH)',
],
'message': 'Running message compiler on <(RULE_INPUT_PATH)',
}],
}],
],
}
]
}
......@@ -26,6 +26,8 @@
'trace_event/trace_event_android.cc',
'trace_event/trace_event_argument.cc',
'trace_event/trace_event_argument.h',
'trace_event/trace_event_etw_export_win.cc',
'trace_event/trace_event_etw_export_win.h',
'trace_event/trace_event_impl.cc',
'trace_event/trace_event_impl.h',
'trace_event/trace_event_impl_constants.cc',
......
......@@ -828,9 +828,10 @@
category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
(base::trace_event::TraceLog::ENABLED_FOR_RECORDING | \
base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK))
UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) & \
(base::trace_event::TraceLog::ENABLED_FOR_RECORDING | \
base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK | \
base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
// Macro to efficiently determine if a given category group is enabled.
#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
......
// 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() {
GetInstance()->ETWExportEnabled_ = true;
}
// static
void TraceEventETWExport::DisableETWExport() {
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()->ETWExportEnabled_ || !EventEnabledChromeEvent())
return;
std::string phase_string;
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_string.push_back(phase);
break;
}
std::string arg_values_string[3];
for (int i = 0; i < num_args; i++) {
if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
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.c_str(), 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()->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
// 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.
// This file contains the Windows-specific exporting to ETW.
#ifndef BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
#define BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
#include "base/base_export.h"
#include "base/trace_event/trace_event_impl.h"
// Fwd.
template <typename Type>
struct StaticMemorySingletonTraits;
namespace base {
namespace trace_event {
class BASE_EXPORT TraceEventETWExport {
public:
~TraceEventETWExport();
// Retrieves the singleton.
// Note that this may return NULL post-AtExit processing.
static TraceEventETWExport* GetInstance();
// Enables/disables exporting of events to ETW. If disabled,
// AddEvent and AddCustomEvent will simply return when called.
static void EnableETWExport();
static void DisableETWExport();
static bool isETWExportEnabled() { return GetInstance()->ETWExportEnabled_; }
// Exports an event to ETW. This is mainly used in
// TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
static void 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);
// Exports an event to ETW. This should be used when exporting an event only
// to ETW. Supports three arguments to be passed to ETW.
// TODO(georgesak): Allow different providers.
static void 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);
void Resurrect();
private:
bool ETWExportEnabled_;
// Ensure only the provider can construct us.
friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
TraceEventETWExport();
DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
};
} // namespace trace_event
} // namespace base
#endif // BASE_TRACE_EVENT_TRACE_ETW_EXPORT_H_
......@@ -36,6 +36,7 @@
#include "base/trace_event/trace_event_synthetic_delay.h"
#if defined(OS_WIN)
#include "base/trace_event/trace_event_etw_export_win.h"
#include "base/trace_event/trace_event_win.h"
#endif
......@@ -1292,6 +1293,11 @@ void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
if (event_callback_ &&
event_callback_category_filter_.IsCategoryGroupEnabled(category_group))
enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
#if defined(OS_WIN)
if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
enabled_flag |= ENABLED_FOR_ETW_EXPORT;
#endif
g_category_group_enabled[category_index] = enabled_flag;
}
......@@ -1984,6 +1990,15 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
}
}
#if defined(OS_WIN)
// This is done sooner rather than later, to avoid creating the event and
// acquiring the lock, which is not needed for ETW as it's already threadsafe.
if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
num_args, arg_names, arg_types, arg_values,
convertable_values);
#endif // OS_WIN
std::string console_message;
if (*category_group_enabled &
(ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
......
......@@ -26,6 +26,7 @@
// Older style trace macros with explicit id and extra data
// Only these macros result in publishing data to ETW as currently implemented.
// TODO(georgesak): Update/replace these with new ETW macros.
#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
base::trace_event::TraceLog::AddTraceEventEtw( \
TRACE_EVENT_PHASE_BEGIN, \
......@@ -446,6 +447,8 @@ class BASE_EXPORT TraceLog {
ENABLED_FOR_MONITORING = 1 << 1,
// Category group enabled by SetEventCallbackEnabled().
ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
// Category group enabled to export events to ETW.
ENABLED_FOR_ETW_EXPORT = 1 << 3
};
static TraceLog* GetInstance();
......
......@@ -165,6 +165,7 @@ shared_library("main_dll") {
output_name = "chrome"
sources = [
"$root_gen_dir/base/trace_event/etw_manifest/chrome_events_win.rc",
"//base/win/dllmain.cc",
"app/chrome_command_ids.h",
"app/chrome_dll.rc",
......@@ -182,6 +183,7 @@ shared_library("main_dll") {
# On Windows, link the dependencies (libraries) that make up actual
# Chromium functionality into this .dll.
":chrome_version_resources",
"//base/trace_event/etw_manifest:chrome_events_win",
"//chrome/app/theme:chrome_unscaled_resources",
"//chrome_elf",
"//content/app/resources",
......
......@@ -124,6 +124,7 @@
# On Windows, link the dependencies (libraries) that make
# up actual Chromium functionality into this .dll.
'chrome_version_resources',
'../base/trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
'../chrome/chrome_resources.gyp:chrome_unscaled_resources',
'../content/app/resources/content_resources.gyp:content_resources',
'../crypto/crypto.gyp:crypto',
......@@ -133,6 +134,9 @@
'sources': [
'app/chrome_dll.rc',
# ETW Manifest.
'<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest/chrome_events_win.rc',
'<(SHARED_INTERMEDIATE_DIR)/chrome_version/chrome_dll_version.rc',
# Cursors.
......
......@@ -77,6 +77,7 @@
#include <cstring>
#include "base/strings/string_number_conversions.h"
#include "base/trace_event/trace_event_etw_export_win.h"
#include "ui/base/win/atl_module.h"
#include "ui/gfx/win/dpi.h"
#elif defined(OS_MACOSX)
......@@ -632,6 +633,12 @@ class ContentMainRunnerImpl : public ContentMainRunner {
base::trace_event::TraceOptions(
base::trace_event::RECORD_UNTIL_FULL));
}
#if defined(OS_WIN)
// Enable exporting of events to ETW if requested on the command line.
if (command_line.HasSwitch(switches::kTraceExportEventsToETW))
base::trace_event::TraceEventETWExport::EnableETWExport();
#endif // OS_WIN
#if !defined(OS_ANDROID)
// Android tracing started at the beginning of the method.
// Other OSes have to wait till we get here in order for all the memory
......
......@@ -1382,6 +1382,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
switches::kDisableDirectWrite,
switches::kEnableWin32kRendererLockDown,
switches::kDisableWin32kRendererLockDown,
switches::kTraceExportEventsToETW,
#endif
#if defined(OS_CHROMEOS)
switches::kDisableVaapiAcceleratedVideoEncode,
......
......@@ -991,6 +991,10 @@ const char kEnableWin32kRendererLockDown[] =
// This switch allows specifying suffix to shared memory section name to avoid
// clashes between different instances of Chrome.
const char kFontCacheSharedMemSuffix[] = "font-cache-shared-mem-suffix";
// Enables the exporting of the tracing events to ETW. This is only supported on
// Windows Vista and later.
const char kTraceExportEventsToETW[] = "trace-export-events-to-etw";
#endif
// Enables the use of NPAPI plugins.
......
......@@ -298,6 +298,7 @@ CONTENT_EXPORT extern const char kEnableWin32kRendererLockDown[];
// Switch to uniquely identify names shared memory section for font cache
// across chromium flavors.
CONTENT_EXPORT extern const char kFontCacheSharedMemSuffix[];
CONTENT_EXPORT extern const char kTraceExportEventsToETW[];
#endif
CONTENT_EXPORT extern const char kEnableNpapi[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment