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}
diff --git a/base/base.gyp b/base/base.gyp
index e99b0d6..1d6ba344 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -190,6 +190,9 @@
               ],
             },
           ],
+          'dependencies': [
+           'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
+          ],
         }],
         ['OS == "mac" or (OS == "ios" and _toolset == "host")', {
           'link_settings': {
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index d32bd28..ed8761f 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -26,6 +26,8 @@
     "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 @@
     "//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",
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
new file mode 100644
index 0000000..07cf80e
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -0,0 +1,37 @@
+# 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),
+  ]
+}
diff --git a/base/trace_event/etw_manifest/BUILD/message_compiler.py b/base/trace_event/etw_manifest/BUILD/message_compiler.py
new file mode 100644
index 0000000..be5927d
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD/message_compiler.py
@@ -0,0 +1,16 @@
+# 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)
diff --git a/base/trace_event/etw_manifest/chrome_events_win.man b/base/trace_event/etw_manifest/chrome_events_win.man
new file mode 100644
index 0000000..10a8ddf
--- /dev/null
+++ b/base/trace_event/etw_manifest/chrome_events_win.man
@@ -0,0 +1,84 @@
+<?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>
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 0000000..b0a8712
--- /dev/null
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -0,0 +1,39 @@
+# 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)',
+          }],
+        }],
+      ],
+    }
+  ]
+}
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
index 9be9149..392f0632 100644
--- a/base/trace_event/trace_event.gypi
+++ b/base/trace_event/trace_event.gypi
@@ -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',
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 1bf9429..7c4d3ab 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -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) \
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
new file mode 100644
index 0000000..f7f9ecca
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -0,0 +1,239 @@
+// 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
diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h
new file mode 100644
index 0000000..0a551c3
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -0,0 +1,73 @@
+// 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_
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index f312c71..12f9598 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -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 @@
   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 @@
     }
   }
 
+#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)) {
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 1d00a711..33a85c9 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -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 @@
     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();
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 71e3ff4..0ab9496 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -165,6 +165,7 @@
     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 @@
       # 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",
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi
index 29d91f67..b9a9973 100644
--- a/chrome/chrome_dll.gypi
+++ b/chrome/chrome_dll.gypi
@@ -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.
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 42f1865..0db941a 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -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 @@
           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
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index c308e7e5..67670c0f 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1382,6 +1382,7 @@
     switches::kDisableDirectWrite,
     switches::kEnableWin32kRendererLockDown,
     switches::kDisableWin32kRendererLockDown,
+    switches::kTraceExportEventsToETW,
 #endif
 #if defined(OS_CHROMEOS)
     switches::kDisableVaapiAcceleratedVideoEncode,
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index fe20d99..f9b5801 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -991,6 +991,10 @@
 // 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.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index bcb3de1b..c72322a 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -298,6 +298,7 @@
 // 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[];