summaryrefslogtreecommitdiff
path: root/chromium/base/trace_event
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/base/trace_event')
-rw-r--r--chromium/base/trace_event/base_tracing.h28
-rw-r--r--chromium/base/trace_event/builtin_categories.h9
-rw-r--r--chromium/base/trace_event/category_registry.cc1
-rw-r--r--chromium/base/trace_event/category_registry.h2
-rw-r--r--chromium/base/trace_event/etw_manifest/BUILD.gn27
-rw-r--r--chromium/base/trace_event/etw_manifest/chrome_events_win.man95
-rw-r--r--chromium/base/trace_event/features.gni12
-rw-r--r--chromium/base/trace_event/memory_allocator_dump.h1
-rw-r--r--chromium/base/trace_event/memory_dump_manager.cc1
-rw-r--r--chromium/base/trace_event/memory_infra_background_allowlist.cc3
-rw-r--r--chromium/base/trace_event/process_memory_dump.cc1
-rw-r--r--chromium/base/trace_event/trace_config.cc1
-rw-r--r--chromium/base/trace_event/trace_event_etw_export_win.cc315
-rw-r--r--chromium/base/trace_event/trace_event_etw_export_win.h20
-rw-r--r--chromium/base/trace_event/trace_event_impl.cc2
-rw-r--r--chromium/base/trace_event/trace_event_stub.cc21
-rw-r--r--chromium/base/trace_event/trace_event_stub.h176
-rw-r--r--chromium/base/trace_event/trace_event_unittest.cc5
-rw-r--r--chromium/base/trace_event/trace_log.cc7
-rw-r--r--chromium/base/trace_event/trace_logging_minimal_win.cc351
-rw-r--r--chromium/base/trace_event/trace_logging_minimal_win.h393
-rw-r--r--chromium/base/trace_event/typed_macros.h74
-rw-r--r--chromium/base/trace_event/typed_macros_embedder_support.h65
-rw-r--r--chromium/base/trace_event/typed_macros_internal.cc95
-rw-r--r--chromium/base/trace_event/typed_macros_internal.h176
-rw-r--r--chromium/base/trace_event/typed_macros_unittest.cc111
26 files changed, 1751 insertions, 241 deletions
diff --git a/chromium/base/trace_event/base_tracing.h b/chromium/base/trace_event/base_tracing.h
new file mode 100644
index 00000000000..c5831f237d2
--- /dev/null
+++ b/chromium/base/trace_event/base_tracing.h
@@ -0,0 +1,28 @@
+// Copyright 2020 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.
+
+#ifndef BASE_TRACE_EVENT_BASE_TRACING_H_
+#define BASE_TRACE_EVENT_BASE_TRACING_H_
+
+// Proxy header that provides tracing instrumentation for //base code. When
+// tracing support is disabled via the gn flag enable_base_tracing, this header
+// provides a mock implementation of the relevant trace macros instead, which
+// causes the instrumentation in //base to be compiled into no-ops.
+
+#include "base/tracing_buildflags.h"
+
+#if BUILDFLAG(ENABLE_BASE_TRACING)
+// Update the check in //base/PRESUBMIT.py when adding new headers here.
+// TODO(crbug/1006541): Switch to perfetto for trace event implementation.
+#include "base/trace_event/blame_context.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/traced_value.h"
+#include "base/trace_event/typed_macros.h"
+#else // BUILDFLAG(ENABLE_BASE_TRACING)
+#include "base/trace_event/trace_event_stub.h"
+#endif // BUILDFLAG(ENABLE_BASE_TRACING)
+
+#endif // BASE_TRACE_EVENT_BASE_TRACING_H_
diff --git a/chromium/base/trace_event/builtin_categories.h b/chromium/base/trace_event/builtin_categories.h
index 7ce21d4711b..31f563dd4d5 100644
--- a/chromium/base/trace_event/builtin_categories.h
+++ b/chromium/base/trace_event/builtin_categories.h
@@ -83,6 +83,7 @@
X("GAMEPAD") \
X("gpu") \
X("gpu.capture") \
+ X("gpu.memory") \
X("headless") \
X("hwoverlays") \
X("identity") \
@@ -148,9 +149,11 @@
X("test_gpu") \
X("test_tracing") \
X("toplevel") \
+ X("toplevel.flow") \
X("ui") \
X("v8") \
X("v8.execute") \
+ X("v8.wasm") \
X("ValueStoreFrontend::Backend") \
X("views") \
X("views.frame") \
@@ -214,6 +217,7 @@
X(TRACE_DISABLED_BY_DEFAULT("power")) \
X(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler")) \
X(TRACE_DISABLED_BY_DEFAULT("renderer.scheduler.debug")) \
+ X(TRACE_DISABLED_BY_DEFAULT("sandbox")) \
X(TRACE_DISABLED_BY_DEFAULT("sequence_manager")) \
X(TRACE_DISABLED_BY_DEFAULT("sequence_manager.debug")) \
X(TRACE_DISABLED_BY_DEFAULT("sequence_manager.verbose_snapshots")) \
@@ -223,12 +227,10 @@
X(TRACE_DISABLED_BY_DEFAULT("SyncFileSystem")) \
X(TRACE_DISABLED_BY_DEFAULT("system_stats")) \
X(TRACE_DISABLED_BY_DEFAULT("thread_pool_diagnostics")) \
- X(TRACE_DISABLED_BY_DEFAULT("toplevel.flow")) \
X(TRACE_DISABLED_BY_DEFAULT("toplevel.ipc")) \
X(TRACE_DISABLED_BY_DEFAULT("user_action_samples")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.compile")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler")) \
- X(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler.hires")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.gc")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.gc_stats")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.ic_stats")) \
@@ -236,7 +238,7 @@
X(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.runtime_stats_sampling")) \
X(TRACE_DISABLED_BY_DEFAULT("v8.turbofan")) \
- X(TRACE_DISABLED_BY_DEFAULT("v8.wasm")) \
+ X(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed")) \
X(TRACE_DISABLED_BY_DEFAULT("video_and_image_capture")) \
X(TRACE_DISABLED_BY_DEFAULT("viz.debug.overlay_planes")) \
X(TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow")) \
@@ -246,6 +248,7 @@
X(TRACE_DISABLED_BY_DEFAULT("viz.surface_lifetime")) \
X(TRACE_DISABLED_BY_DEFAULT("viz.triangles")) \
X(TRACE_DISABLED_BY_DEFAULT("webaudio.audionode")) \
+ X(TRACE_DISABLED_BY_DEFAULT("webrtc")) \
X(TRACE_DISABLED_BY_DEFAULT("worker.scheduler"))
#define INTERNAL_TRACE_INIT_CATEGORY_NAME(name) name,
diff --git a/chromium/base/trace_event/category_registry.cc b/chromium/base/trace_event/category_registry.cc
index 691336f8707..27c77740358 100644
--- a/chromium/base/trace_event/category_registry.cc
+++ b/chromium/base/trace_event/category_registry.cc
@@ -6,6 +6,7 @@
#include <string.h>
+#include <ostream>
#include <type_traits>
#include "base/check.h"
diff --git a/chromium/base/trace_event/category_registry.h b/chromium/base/trace_event/category_registry.h
index a6439d94595..cd95ba8f547 100644
--- a/chromium/base/trace_event/category_registry.h
+++ b/chromium/base/trace_event/category_registry.h
@@ -10,7 +10,7 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/stl_util.h"
#include "base/trace_event/builtin_categories.h"
#include "base/trace_event/common/trace_event_common.h"
diff --git a/chromium/base/trace_event/etw_manifest/BUILD.gn b/chromium/base/trace_event/etw_manifest/BUILD.gn
deleted file mode 100644
index a66fef9e3c8..00000000000
--- a/chromium/base/trace_event/etw_manifest/BUILD.gn
+++ /dev/null
@@ -1,27 +0,0 @@
-# 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.
-
-import("//build/win/message_compiler.gni")
-
-assert(is_win, "This only runs on Windows.")
-
-message_compiler("chrome_events_win") {
- visibility = [
- "//base/*",
- "//chrome:chrome_dll",
- ]
-
- sources = [ "chrome_events_win.man" ]
-
- user_mode_logging = true
-
- # The only code generated from chrome_events_win.man is a header file that
- # is included by trace_event_etw_export_win.cc, so there is no need to
- # compile any generated code. The other thing which compile_generated_code
- # controls in this context is linking in the .res file generated from the
- # manifest. However this is only needed for ETW provider registration which
- # is done by UIforETW (https://github.com/google/UIforETW) and therefore the
- # manifest resource can be skipped in Chrome.
- compile_generated_code = false
-}
diff --git a/chromium/base/trace_event/etw_manifest/chrome_events_win.man b/chromium/base/trace_event/etw_manifest/chrome_events_win.man
deleted file mode 100644
index 489d16720aa..00000000000
--- a/chromium/base/trace_event/etw_manifest/chrome_events_win.man
+++ /dev/null
@@ -1,95 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes'?>
-<assembly
- xmlns="urn:schemas-microsoft-com:asm.v3"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- manifestVersion="1.0"
- >
- <assemblyIdentity
- buildType="$(build.buildType)"
- language="neutral"
- name="Chrome.ETW"
- processorArchitecture="$(build.arch)"
- publicKeyToken="$(Build.WindowsPublicKeyToken)"
- version="$(build.version)"
- versionScope="nonSxS"
- />
- <instrumentation
- xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
- buildFilter="not build.isWow"
- >
- <events xmlns="http://schemas.microsoft.com/win/2004/08/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>
- <resources culture="en-US">
- <stringTable>
- <string
- id="ChromeEvent.EventMessage"
- value="Chrome Event: %1 (%2)"
- />
- </stringTable>
- </resources>
- </localization>
-</assembly>
diff --git a/chromium/base/trace_event/features.gni b/chromium/base/trace_event/features.gni
deleted file mode 100644
index 7d6bb2a8509..00000000000
--- a/chromium/base/trace_event/features.gni
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright 2020 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.
-
-# Features used by //base/trace_event and //services/tracing.
-declare_args() {
- # Switches the TRACE_EVENT instrumentation from base's TraceLog implementation
- # to //third_party/perfetto's client library. Not implemented yet, currently a
- # no-op to set up trybot infrastructure.
- # TODO(eseckler): Implement.
- use_perfetto_client_library = false
-}
diff --git a/chromium/base/trace_event/memory_allocator_dump.h b/chromium/base/trace_event/memory_allocator_dump.h
index 4999e85f560..b11e239b2a1 100644
--- a/chromium/base/trace_event/memory_allocator_dump.h
+++ b/chromium/base/trace_event/memory_allocator_dump.h
@@ -13,7 +13,6 @@
#include "base/base_export.h"
#include "base/gtest_prod_util.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
diff --git a/chromium/base/trace_event/memory_dump_manager.cc b/chromium/base/trace_event/memory_dump_manager.cc
index 0490e364a46..240b7af3bb0 100644
--- a/chromium/base/trace_event/memory_dump_manager.cc
+++ b/chromium/base/trace_event/memory_dump_manager.cc
@@ -16,6 +16,7 @@
#include "base/command_line.h"
#include "base/debug/alias.h"
#include "base/debug/stack_trace.h"
+#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/trace_event/memory_infra_background_allowlist.cc b/chromium/base/trace_event/memory_infra_background_allowlist.cc
index 7d1e5744c15..dfaf6271f1f 100644
--- a/chromium/base/trace_event/memory_infra_background_allowlist.cc
+++ b/chromium/base/trace_event/memory_infra_background_allowlist.cc
@@ -26,6 +26,7 @@ const char* const kDumpProviderAllowlist[] = {
"BlinkGC",
"BlinkObjectCounters",
"BlobStorageContext",
+ "Canvas",
"ClientDiscardableSharedMemoryManager",
"DevTools",
"DiscardableSharedMemoryManager",
@@ -95,6 +96,8 @@ const char* const kAllocatorDumpNameAllowlist[] = {
"blink_objects/WorkerGlobalScope",
"blink_objects/UACSSResource",
"blink_objects/ResourceFetcher",
+ "canvas/ResourceProvider/SkSurface",
+ "canvas/ResourceProvider/SkSurface/0x?",
"components/download/controller_0x?",
"devtools/file_watcher_0x?",
"discardable",
diff --git a/chromium/base/trace_event/process_memory_dump.cc b/chromium/base/trace_event/process_memory_dump.cc
index 021e9862e21..2b095661230 100644
--- a/chromium/base/trace_event/process_memory_dump.cc
+++ b/chromium/base/trace_event/process_memory_dump.cc
@@ -8,6 +8,7 @@
#include <vector>
+#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/memory/shared_memory_tracker.h"
#include "base/process/process_metrics.h"
diff --git a/chromium/base/trace_event/trace_config.cc b/chromium/base/trace_event/trace_config.cc
index 5b4493f1bd6..14a670647fa 100644
--- a/chromium/base/trace_event/trace_config.cc
+++ b/chromium/base/trace_event/trace_config.cc
@@ -11,6 +11,7 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
+#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_split.h"
#include "base/trace_event/memory_dump_manager.h"
diff --git a/chromium/base/trace_event/trace_event_etw_export_win.cc b/chromium/base/trace_event/trace_event_etw_export_win.cc
index 680cdbdc027..cf4383fe031 100644
--- a/chromium/base/trace_event/trace_event_etw_export_win.cc
+++ b/chromium/base/trace_event/trace_event_etw_export_win.cc
@@ -4,44 +4,23 @@
#include "base/trace_event/trace_event_etw_export_win.h"
+#include <evntrace.h>
+#include <guiddef.h>
#include <stddef.h>
+#include <stdlib.h>
+#include <windows.h>
#include "base/at_exit.h"
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/platform_thread.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_impl.h"
-
-#include <windows.h>
-
-// The GetProcAddress technique is borrowed from
-// https://github.com/google/UIforETW/tree/master/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.
-
-// Headers generated by mc.exe have a ';' at the end of extern "C" {} blocks.
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra-semi"
-#endif
-
-#include "base/trace_event/etw_manifest/chrome_events_win.h" // NOLINT
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
+#include "base/trace_event/trace_logging_minimal_win.h"
namespace {
@@ -51,28 +30,62 @@ namespace {
// one bit per category. We can therefore enable a particular category by
// setting its corresponding bit in the keyword. For events that are not present
// in |kFilteredEventGroupNames|, we have two bits that control their
-// behaviour. When bit 61 is enabled, any event that is not disabled by default
+// behaviour. When bit 46 is enabled, any event that is not disabled by default
// (ie. doesn't start with disabled-by-default-) will be exported. Likewise,
-// when bit 62 is enabled, any event that is disabled by default will be
+// when bit 47 is enabled, any event that is disabled by default will be
// exported.
//
-// Note that bit 63 (MSB) must always be set, otherwise tracing will be disabled
-// by ETW. Therefore, the keyword will always be greater than
-// 0x8000000000000000.
-//
// Examples of passing keywords to the provider using xperf:
// # This exports "benchmark" and "cc" events
-// xperf -start chrome -on Chrome:0x8000000000000009
+// xperf -start chrome -on Chrome:0x9
//
// # This exports "gpu", "netlog" and all other events that are not disabled by
// # default
-// xperf -start chrome -on Chrome:0xA0000000000000A0
+// xperf -start chrome -on Chrome:0x4000000000A0
//
// More info about starting a trace and keyword can be obtained by using the
// help section of xperf (xperf -help start). Note that xperf documentation
// refers to keywords as flags and there are two ways to enable them, using
// group names or the hex representation. We only support the latter. Also, we
// ignore the level.
+//
+// To avoid continually having to bump MSEdge values to next higher bits, we
+// are putting MSEdge values at the high end of the bit range and will grow
+// 'down' to lower bits for future MSEdge entries.
+//
+// As the writing of this comment, we have 4 values:
+// "navigation", // 0x40000000000
+// "ServiceWorker", // 0x80000000000
+// "edge_webview", // 0x100000000000
+// "diagnostic_event", // 0x200000000000
+//
+// This means the next value added should be:
+// "the_next_value", // 0x20000000000
+// "navigation", // 0x40000000000
+// "ServiceWorker", // 0x80000000000
+// "edge_webview", // 0x100000000000
+// "diagnostic_event", // 0x200000000000
+//
+// The addition of the "unused_bit_nn" entries keeps the existing code execution
+// routines working (ex. TraceEventETWExport::UpdateEnabledCategories()) and
+// enables others to see which bits are available.
+//
+// Example: For some new category group...
+// "latency", // 0x8000
+// "blink.user_timing", // 0x10000
+// "unused_bit_18", // 0x20000
+// "unused_bit_19", // 0x40000
+// "unused_bit_20", // 0x80000
+// ...
+// becomes:
+// "latency", // 0x8000
+// "blink.user_timing", // 0x10000
+// "new_upstream_value", // 0x20000
+// "unused_bit_19", // 0x40000
+// "unused_bit_20", // 0x80000
+//
+// The high 16 bits of the keyword have special semantics and should not be
+// set for enabling individual categories as they are reserved by winmeta.xml.
const char* const kFilteredEventGroupNames[] = {
"benchmark", // 0x1
"blink", // 0x2
@@ -93,13 +106,44 @@ const char* const kFilteredEventGroupNames[] = {
"blink.user_timing", // 0x10000
"media", // 0x20000
"loading", // 0x40000
+ "unused_bit_19", // 0x80000
+ "unused_bit_20", // 0x100000
+ "unused_bit_21", // 0x200000
+ "unused_bit_22", // 0x400000
+ "unused_bit_23", // 0x800000
+ "unused_bit_24", // 0x1000000
+ "unused_bit_25", // 0x2000000
+ "unused_bit_26", // 0x4000000
+ "unused_bit_27", // 0x8000000
+ "unused_bit_28", // 0x10000000
+ "unused_bit_29", // 0x20000000
+ "unused_bit_30", // 0x40000000
+ "unused_bit_31", // 0x80000000
+ "unused_bit_32", // 0x100000000
+ "unused_bit_33", // 0x200000000
+ "unused_bit_34", // 0x400000000
+ "unused_bit_35", // 0x800000000
+ "unused_bit_36", // 0x1000000000
+ "unused_bit_37", // 0x2000000000
+ "unused_bit_38", // 0x4000000000
+ "unused_bit_39", // 0x8000000000
+ "unused_bit_40", // 0x10000000000
+ "unused_bit_41", // 0x20000000000
+ "navigation", // 0x40000000000
+ "ServiceWorker", // 0x80000000000
+ "edge_webview", // 0x100000000000
+ "diagnostic_event", // 0x200000000000
+ "__OTHER_EVENTS", // 0x400000000000 See below
+ "__DISABLED_OTHER_EVENTS", // 0x800000000000 See below
};
-const char kOtherEventsGroupName[] = "__OTHER_EVENTS"; // 0x2000000000000000
-const char kDisabledOtherEventsGroupName[] =
- "__DISABLED_OTHER_EVENTS"; // 0x4000000000000000
-const uint64_t kOtherEventsKeywordBit = 1ULL << 61;
-const uint64_t kDisabledOtherEventsKeywordBit = 1ULL << 62;
-const size_t kNumberOfCategories = ARRAYSIZE(kFilteredEventGroupNames) + 2U;
+
+// These must be kept as the last two entries in the above array.
+constexpr uint8_t kOtherEventsGroupNameIndex = 46;
+constexpr uint8_t kDisabledOtherEventsGroupNameIndex = 47;
+
+// Max number of available keyword bits.
+constexpr size_t kMaxNumberOfGroupNames = 48;
+uint64_t g_callback_match_any_keyword = 0;
static void __stdcall EtwEnableCallback(LPCGUID SourceId,
ULONG ControlCode,
@@ -108,10 +152,19 @@ static void __stdcall EtwEnableCallback(LPCGUID SourceId,
ULONGLONG MatchAllKeyword,
PEVENT_FILTER_DESCRIPTOR FilterData,
PVOID CallbackContext) {
- // Invoke the default callback, which updates the information inside
- // CHROME_Context.
- McGenControlCallbackV2(SourceId, ControlCode, Level, MatchAnyKeyword,
- MatchAllKeyword, FilterData, CallbackContext);
+ // This callback is called in the context of an ETW OS thread to
+ // inform the process of the global state of the level and keyword
+ // across all sessions for this provider. We need to update the
+ // local keywords so we log the corresponding events. Protect the
+ // upper 16 bits reserved by winmeta.xml as they should not be used
+ // but older logging code and tools incorrectly used them.
+ g_callback_match_any_keyword = MatchAnyKeyword;
+ g_callback_match_any_keyword &= ~0xFFFF000000000000;
+
+ DVLOG(1) << "ETW Keyword"
+ << " Bits enabled in global context: " << std::hex << MatchAnyKeyword
+ << " Bits enabled in our code: " << std::hex
+ << g_callback_match_any_keyword;
base::trace_event::TraceEventETWExport::OnETWEnableUpdate();
}
@@ -123,31 +176,41 @@ namespace trace_event {
bool TraceEventETWExport::is_registration_complete_ = false;
-TraceEventETWExport::TraceEventETWExport() : etw_match_any_keyword_(0ULL) {
- // Register the ETW provider. If registration fails then the event logging
- // calls will fail. We're essentially doing the same operation as
- // EventRegisterChrome (which was auto generated for our provider by the
- // ETW manifest compiler), but instead we're passing our own callback.
+TraceEventETWExport::TraceEventETWExport() {
+ // Construct the ETW provider. If construction fails then the event logging
+ // calls will fail. We're passing a callback function as part of registration.
// This allows us to detect changes to enable/disable/keyword changes.
- // ChromeHandle and the other parameters to EventRegister are all generated
- // globals from chrome_events_win.h
- DCHECK(!ChromeHandle);
- EventRegister(&CHROME, &EtwEnableCallback, &CHROME_Context, &ChromeHandle);
+
+ // This GUID is the used to identify the Chrome provider and is used whenever
+ // ETW is enabled via tracing tools and cannot change without updating tools
+ // that collect Chrome ETW data.
+ static const GUID Chrome_GUID = {
+ 0xD2D578D9,
+ 0x2936,
+ 0x45B6,
+ {0xA0, 0x9F, 0x30, 0xE3, 0x27, 0x15, 0xF4, 0x2D}};
+
+ etw_provider_ = std::make_unique<TlmProvider>("Google.Chrome", Chrome_GUID,
+ &EtwEnableCallback);
TraceEventETWExport::is_registration_complete_ = true;
// Make sure to initialize the map with all the group names. Subsequent
// modifications will be made by the background thread and only affect the
// values of the keys (no key addition/deletion). Therefore, the map does not
// require a lock for access.
- for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++)
+ // Also set up the map from category name to keyword.
+ for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
+ uint64_t keyword = 1ULL << i;
categories_status_[kFilteredEventGroupNames[i]] = false;
- categories_status_[kOtherEventsGroupName] = false;
- categories_status_[kDisabledOtherEventsGroupName] = false;
- DCHECK_EQ(kNumberOfCategories, categories_status_.size());
+ categories_keyword_[kFilteredEventGroupNames[i]] = keyword;
+ }
+ // Make sure we stay at 48 entries, the maximum number of bits available
+ // for keyword use.
+ static_assert(ARRAYSIZE(kFilteredEventGroupNames) <= kMaxNumberOfGroupNames,
+ "Exceeded max ETW keyword bits");
}
TraceEventETWExport::~TraceEventETWExport() {
- EventUnregisterChrome();
is_registration_complete_ = false;
}
@@ -163,6 +226,52 @@ void TraceEventETWExport::EnableETWExport() {
}
// static
+uint64_t TraceEventETWExport::CategoryGroupToKeyword(
+ const uint8_t* category_state) {
+ uint64_t keyword = 0;
+
+ // To enable multiple sessions with this provider enabled we need to log the
+ // level and keyword with the event so that if the sessions differ in the
+ // level or keywords enabled we log the right events and allow ETW to
+ // route the data to the appropriate session.
+ // TODO(joel@microsoft.com) Explore better methods in future integration
+ // with perfetto.
+
+ auto* instance = GetInstance();
+ if (!instance)
+ return keyword;
+
+ // Add in the keyword for the special bits if they are set.
+ if (instance->categories_status_
+ [kFilteredEventGroupNames[kOtherEventsGroupNameIndex]]) {
+ keyword |= instance->categories_keyword_
+ [kFilteredEventGroupNames[kOtherEventsGroupNameIndex]];
+ }
+ if (instance->categories_status_
+ [kFilteredEventGroupNames[kDisabledOtherEventsGroupNameIndex]]) {
+ keyword |=
+ instance->categories_keyword_
+ [kFilteredEventGroupNames[kDisabledOtherEventsGroupNameIndex]];
+ }
+ // Add in the keyword for the categories specified at the logging site.
+ const TraceCategory* category = TraceCategory::FromStatePtr(category_state);
+ StringPiece category_group_name = category->name();
+
+ CStringTokenizer category_group_tokens(category_group_name.begin(),
+ category_group_name.end(), ",");
+ while (category_group_tokens.GetNext()) {
+ StringPiece category_group_token = category_group_tokens.token_piece();
+
+ // Lookup the keyword for this part of the category_group_name
+ // and or in the keyword.
+ auto it = instance->categories_keyword_.find(category_group_token);
+ if (it != instance->categories_keyword_.end())
+ keyword |= it->second;
+ }
+ return keyword;
+}
+
+// static
void TraceEventETWExport::AddEvent(char phase,
const unsigned char* category_group_enabled,
const char* name,
@@ -170,10 +279,14 @@ void TraceEventETWExport::AddEvent(char phase,
const TraceArguments* args) {
// We bail early in case exporting is disabled or no consumer is listening.
auto* instance = GetInstance();
- if (!instance || !EventEnabledChromeEvent())
+ uint64_t keyword = CategoryGroupToKeyword(category_group_enabled);
+ if (!instance ||
+ !instance->etw_provider_->IsEnabled(TRACE_LEVEL_NONE, keyword)) {
return;
+ }
const char* phase_string = nullptr;
+
// Space to store the phase identifier and null-terminator, when needed.
char phase_buffer[2];
switch (phase) {
@@ -257,30 +370,54 @@ void TraceEventETWExport::AddEvent(char phase,
}
}
- EventWriteChromeEvent(
- name, phase_string, num_args > 0 ? args->names()[0] : "",
- arg_values_string[0].c_str(), num_args > 1 ? args->names()[1] : "",
- arg_values_string[1].c_str(), "", "");
+ // Log the event and include the info needed to decode it via TraceLogging
+ if (num_args == 0) {
+ instance->etw_provider_->WriteEvent(
+ name, TlmEventDescriptor(0, keyword),
+ TlmMbcsStringField("Phase", phase_string));
+ } else if (num_args == 1) {
+ instance->etw_provider_->WriteEvent(
+ name, TlmEventDescriptor(0, keyword),
+ TlmMbcsStringField("Phase", phase_string),
+ TlmMbcsStringField((args->names()[0]), (arg_values_string[0].c_str())));
+ } else if (num_args == 2) {
+ instance->etw_provider_->WriteEvent(
+ name, TlmEventDescriptor(0, keyword),
+ TlmMbcsStringField("Phase", phase_string),
+ TlmMbcsStringField((args->names()[0]), (arg_values_string[0].c_str())),
+ TlmMbcsStringField((args->names()[1]), (arg_values_string[1].c_str())));
+ } else {
+ NOTREACHED();
+ }
}
// static
-void TraceEventETWExport::AddCompleteEndEvent(const char* name) {
+void TraceEventETWExport::AddCompleteEndEvent(
+ const unsigned char* category_group_enabled,
+ const char* name) {
auto* instance = GetInstance();
- if (!instance || !EventEnabledChromeEvent())
+ uint64_t keyword = CategoryGroupToKeyword(category_group_enabled);
+ if (!instance ||
+ !instance->etw_provider_->IsEnabled(TRACE_LEVEL_NONE, keyword)) {
return;
+ }
- EventWriteChromeEvent(name, "Complete End", "", "", "", "", "", "");
+ // Log the event and include the info needed to decode it via TraceLogging
+ instance->etw_provider_->WriteEvent(
+ name, TlmEventDescriptor(0, keyword),
+ TlmMbcsStringField("Phase", "Complete End"));
}
// static
bool TraceEventETWExport::IsCategoryGroupEnabled(
StringPiece category_group_name) {
DCHECK(!category_group_name.empty());
+
auto* instance = GetInstanceIfExists();
if (instance == nullptr)
return false;
- if (!EventEnabledChromeEvent())
+ if (!instance->etw_provider_->IsEnabled())
return false;
CStringTokenizer category_group_tokens(category_group_name.begin(),
@@ -295,14 +432,15 @@ bool TraceEventETWExport::IsCategoryGroupEnabled(
}
bool TraceEventETWExport::UpdateEnabledCategories() {
- if (etw_match_any_keyword_ == CHROME_Context.MatchAnyKeyword)
+ if (etw_match_any_keyword_ == g_callback_match_any_keyword)
return false;
- // If the keyword has changed, update each category.
- // Chrome_Context.MatchAnyKeyword is set by UIforETW (or other ETW trace
- // recording tools) using the ETW infrastructure. This value will be set in
- // all Chrome processes that have registered their ETW provider.
- etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
+ // If the global keyword has changed, update each category. The global
+ // context is set by UIforETW (or other ETW trace recording tools)
+ // using the ETW infrastructure. When the global context changes the
+ // callback will be called to set the updated keyword bits in each
+ // browser process that has registered their ETW provider.
+ etw_match_any_keyword_ = g_callback_match_any_keyword;
for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
if (etw_match_any_keyword_ & (1ULL << i)) {
categories_status_[kFilteredEventGroupNames[i]] = true;
@@ -311,20 +449,6 @@ bool TraceEventETWExport::UpdateEnabledCategories() {
}
}
- // Also update the two default categories.
- if (etw_match_any_keyword_ & kOtherEventsKeywordBit) {
- categories_status_[kOtherEventsGroupName] = true;
- } else {
- categories_status_[kOtherEventsGroupName] = false;
- }
- if (etw_match_any_keyword_ & kDisabledOtherEventsKeywordBit) {
- categories_status_[kDisabledOtherEventsGroupName] = true;
- } else {
- categories_status_[kDisabledOtherEventsGroupName] = false;
- }
-
- DCHECK_EQ(kNumberOfCategories, categories_status_.size());
-
// Update the categories in TraceLog.
TraceLog::GetInstance()->UpdateETWCategoryGroupEnabledFlags();
@@ -332,7 +456,6 @@ bool TraceEventETWExport::UpdateEnabledCategories() {
}
bool TraceEventETWExport::IsCategoryEnabled(StringPiece category_name) const {
- DCHECK_EQ(kNumberOfCategories, categories_status_.size());
// Try to find the category and return its status if found
auto it = categories_status_.find(category_name);
if (it != categories_status_.end())
@@ -341,13 +464,19 @@ bool TraceEventETWExport::IsCategoryEnabled(StringPiece category_name) const {
// Otherwise return the corresponding default status by first checking if the
// category is disabled by default.
if (category_name.starts_with("disabled-by-default")) {
- DCHECK(categories_status_.find(kDisabledOtherEventsGroupName) !=
+ DCHECK(categories_status_.find(
+ kFilteredEventGroupNames[kDisabledOtherEventsGroupNameIndex]) !=
categories_status_.end());
- return categories_status_.find(kDisabledOtherEventsGroupName)->second;
+ return categories_status_
+ .find(kFilteredEventGroupNames[kDisabledOtherEventsGroupNameIndex])
+ ->second;
} else {
- DCHECK(categories_status_.find(kOtherEventsGroupName) !=
+ DCHECK(categories_status_.find(
+ kFilteredEventGroupNames[kOtherEventsGroupNameIndex]) !=
categories_status_.end());
- return categories_status_.find(kOtherEventsGroupName)->second;
+ return categories_status_
+ .find(kFilteredEventGroupNames[kOtherEventsGroupNameIndex])
+ ->second;
}
}
diff --git a/chromium/base/trace_event/trace_event_etw_export_win.h b/chromium/base/trace_event/trace_event_etw_export_win.h
index 0f853533d3a..8f5c8849860 100644
--- a/chromium/base/trace_event/trace_event_etw_export_win.h
+++ b/chromium/base/trace_event/trace_event_etw_export_win.h
@@ -7,13 +7,16 @@
#define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
#include <stdint.h>
+#include <windows.h>
#include <map>
+#include <memory>
#include "base/base_export.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_logging_minimal_win.h"
namespace base {
@@ -49,7 +52,8 @@ class BASE_EXPORT TraceEventETWExport {
const TraceArguments* args);
// Exports an ETW event that marks the end of a complete event.
- static void AddCompleteEndEvent(const char* name);
+ static void AddCompleteEndEvent(const unsigned char* category_group_enabled,
+ const char* name);
// Returns true if any category in the group is enabled.
static bool IsCategoryGroupEnabled(StringPiece category_group_name);
@@ -61,23 +65,31 @@ class BASE_EXPORT TraceEventETWExport {
private:
// Ensure only the provider can construct us.
friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
-
TraceEventETWExport();
// Updates the list of enabled categories by consulting the ETW keyword.
// Returns true if there was a change, false otherwise.
bool UpdateEnabledCategories();
+ static uint64_t CategoryGroupToKeyword(const uint8_t* category_state);
+
// Returns true if the category is enabled.
bool IsCategoryEnabled(StringPiece category_name) const;
static bool is_registration_complete_;
+ // The keywords that were enabled last time the callback was made.
+ uint64_t etw_match_any_keyword_ = 0;
+
+ // The provider is set based on channel for MSEdge, in other Chromium
+ // based browsers all channels use the same GUID/provider.
+ std::unique_ptr<TlmProvider> etw_provider_;
+
// Maps category names to their status (enabled/disabled).
std::map<StringPiece, bool> categories_status_;
- // Local copy of the ETW keyword.
- uint64_t etw_match_any_keyword_;
+ // Maps category names to their keyword.
+ std::map<StringPiece, uint64_t> categories_keyword_;
DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
};
diff --git a/chromium/base/trace_event/trace_event_impl.cc b/chromium/base/trace_event/trace_event_impl.cc
index c74d71c5dd1..dd902bd85d3 100644
--- a/chromium/base/trace_event/trace_event_impl.cc
+++ b/chromium/base/trace_event/trace_event_impl.cc
@@ -6,6 +6,8 @@
#include <stddef.h>
+#include <sstream>
+
#include "base/format_macros.h"
#include "base/json/string_escape.h"
#include "base/memory/ptr_util.h"
diff --git a/chromium/base/trace_event/trace_event_stub.cc b/chromium/base/trace_event/trace_event_stub.cc
new file mode 100644
index 00000000000..2b49d9c3ac4
--- /dev/null
+++ b/chromium/base/trace_event/trace_event_stub.cc
@@ -0,0 +1,21 @@
+// Copyright 2020 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 <stddef.h>
+
+#include <string>
+
+#include "base/trace_event/trace_event_stub.h"
+
+namespace base {
+namespace trace_event {
+
+ConvertableToTraceFormat::~ConvertableToTraceFormat() = default;
+
+void TracedValue::AppendAsTraceFormat(std::string* out) const {}
+
+MemoryDumpProvider::~MemoryDumpProvider() = default;
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/trace_event_stub.h b/chromium/base/trace_event/trace_event_stub.h
new file mode 100644
index 00000000000..b10e9498e61
--- /dev/null
+++ b/chromium/base/trace_event/trace_event_stub.h
@@ -0,0 +1,176 @@
+// Copyright 2020 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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_STUB_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_STUB_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/values.h"
+
+#define TRACE_STR_COPY(str) str
+#define TRACE_ID_WITH_SCOPE(scope, ...) 0
+#define TRACE_ID_GLOBAL(id) 0
+#define TRACE_ID_LOCAL(id) 0
+
+namespace trace_event_internal {
+
+const unsigned long long kNoId = 0;
+
+template <typename... Args>
+void Ignore(Args&&... args) {}
+
+struct IgnoredValue {
+ template <typename... Args>
+ IgnoredValue(Args&&... args) {}
+};
+
+} // namespace trace_event_internal
+
+#define INTERNAL_TRACE_IGNORE(...) \
+ (false ? trace_event_internal::Ignore(__VA_ARGS__) : (void)0)
+
+#define INTERNAL_TRACE_EVENT_ADD(...) INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(...) INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_TASK_EXECUTION(...) INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_LOG_MESSAGE(...) INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
+ INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(...) \
+ INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMPS(...) \
+ INTERNAL_TRACE_IGNORE(__VA_ARGS__)
+
+#define TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
+ trace_event_internal::IgnoredValue
+
+#define TRACE_ID_MANGLE(val) (val)
+
+#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(cat) INTERNAL_TRACE_IGNORE(cat);
+#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() false
+
+#define TRACE_EVENT_API_CURRENT_THREAD_ID 0
+
+// Typed macros. For these, we have to erase the extra args entirely, as they
+// may include a lambda that refers to protozero message types (which aren't
+// available in the stub). This may trigger "unused variable" errors at the
+// callsite, which have to be addressed at the callsite (e.g. via
+// ignore_result()).
+#define TRACE_EVENT_BEGIN(category, name, ...) \
+ INTERNAL_TRACE_IGNORE(category, name)
+#define TRACE_EVENT_END(category, ...) INTERNAL_TRACE_IGNORE(category)
+#define TRACE_EVENT(category, name, ...) INTERNAL_TRACE_IGNORE(category, name)
+#define TRACE_EVENT_INSTANT(category, name, scope, ...) \
+ INTERNAL_TRACE_IGNORE(category, name, scope)
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT ConvertableToTraceFormat {
+ public:
+ ConvertableToTraceFormat() = default;
+ virtual ~ConvertableToTraceFormat();
+
+ // Append the class info to the provided |out| string. The appended
+ // data must be a valid JSON object. Strings must be properly quoted, and
+ // escaped. There is no processing applied to the content after it is
+ // appended.
+ virtual void AppendAsTraceFormat(std::string* out) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
+};
+
+class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
+ public:
+ explicit TracedValue(size_t capacity = 0) {}
+
+ void EndDictionary() {}
+ void EndArray() {}
+
+ void SetInteger(const char* name, int value) {}
+ void SetDouble(const char* name, double value) {}
+ void SetBoolean(const char* name, bool value) {}
+ void SetString(const char* name, base::StringPiece value) {}
+ void SetValue(const char* name, TracedValue* value) {}
+ void BeginDictionary(const char* name) {}
+ void BeginArray(const char* name) {}
+
+ void SetIntegerWithCopiedName(base::StringPiece name, int value) {}
+ void SetDoubleWithCopiedName(base::StringPiece name, double value) {}
+ void SetBooleanWithCopiedName(base::StringPiece name, bool value) {}
+ void SetStringWithCopiedName(base::StringPiece name,
+ base::StringPiece value) {}
+ void SetValueWithCopiedName(base::StringPiece name, TracedValue* value) {}
+ void BeginDictionaryWithCopiedName(base::StringPiece name) {}
+ void BeginArrayWithCopiedName(base::StringPiece name) {}
+
+ void AppendInteger(int) {}
+ void AppendDouble(double) {}
+ void AppendBoolean(bool) {}
+ void AppendString(base::StringPiece) {}
+ void BeginArray() {}
+ void BeginDictionary() {}
+
+ void AppendAsTraceFormat(std::string* out) const override;
+};
+
+class BASE_EXPORT TracedValueJSON : public TracedValue {
+ public:
+ explicit TracedValueJSON(size_t capacity = 0) : TracedValue(capacity) {}
+
+ std::unique_ptr<base::Value> ToBaseValue() const { return nullptr; }
+ std::string ToJSON() const { return ""; }
+ std::string ToFormattedJSON() const { return ""; }
+};
+
+class BASE_EXPORT BlameContext {
+ public:
+ BlameContext(const char* category,
+ const char* name,
+ const char* type,
+ const char* scope,
+ int64_t id,
+ const BlameContext* parent_context) {}
+
+ void Initialize() {}
+ void Enter() {}
+ void Leave() {}
+ void TakeSnapshot() {}
+
+ const char* category() const { return nullptr; }
+ const char* name() const { return nullptr; }
+ const char* type() const { return nullptr; }
+ const char* scope() const { return nullptr; }
+ int64_t id() const { return 0; }
+};
+
+struct MemoryDumpArgs;
+class ProcessMemoryDump;
+
+class BASE_EXPORT MemoryDumpProvider {
+ public:
+ virtual ~MemoryDumpProvider();
+
+ virtual bool OnMemoryDump(const MemoryDumpArgs& args,
+ ProcessMemoryDump* pmd) = 0;
+
+ protected:
+ MemoryDumpProvider() = default;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACE_EVENT_STUB_H_
diff --git a/chromium/base/trace_event/trace_event_unittest.cc b/chromium/base/trace_event/trace_event_unittest.cc
index 7cdfe504b8c..70f1e1fa260 100644
--- a/chromium/base/trace_event/trace_event_unittest.cc
+++ b/chromium/base/trace_event/trace_event_unittest.cc
@@ -17,6 +17,7 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
@@ -2317,7 +2318,7 @@ bool IsArgNameWhitelisted(const char* arg_name) {
return base::MatchPattern(arg_name, "granular_arg_whitelisted");
}
-bool IsTraceEventArgsWhitelisted(const char* category_group_name,
+bool IsTraceEventArgsAllowlisted(const char* category_group_name,
const char* event_name,
ArgumentNameFilterPredicate* arg_filter) {
if (base::MatchPattern(category_group_name, "toplevel") &&
@@ -2338,7 +2339,7 @@ bool IsTraceEventArgsWhitelisted(const char* category_group_name,
TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
TraceLog::GetInstance()->SetArgumentFilterPredicate(
- base::BindRepeating(&IsTraceEventArgsWhitelisted));
+ base::BindRepeating(&IsTraceEventArgsAllowlisted));
TraceLog::GetInstance()->SetEnabled(
TraceConfig(kRecordAllCategoryFilter, "enable-argument-filter"),
diff --git a/chromium/base/trace_event/trace_log.cc b/chromium/base/trace_event/trace_log.cc
index c0d85ea90f1..ac2bc911840 100644
--- a/chromium/base/trace_event/trace_log.cc
+++ b/chromium/base/trace_event/trace_log.cc
@@ -16,6 +16,7 @@
#include "base/command_line.h"
#include "base/debug/leak_annotations.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted_memory.h"
@@ -172,7 +173,7 @@ void ForEachCategoryFilter(const unsigned char* category_group_enabled,
}
// The fallback arguments filtering function will filter away every argument.
-bool DefaultIsTraceEventArgsWhitelisted(
+bool DefaultIsTraceEventArgsAllowlisted(
const char* category_group_name,
const char* event_name,
base::trace_event::ArgumentNameFilterPredicate* arg_name_filter) {
@@ -993,7 +994,7 @@ void TraceLog::FinishFlush(int generation, bool discard_events) {
// use the safe default filtering predicate.
if (argument_filter_predicate_.is_null()) {
argument_filter_predicate =
- base::BindRepeating(&DefaultIsTraceEventArgsWhitelisted);
+ base::BindRepeating(&DefaultIsTraceEventArgsAllowlisted);
} else {
argument_filter_predicate = argument_filter_predicate_;
}
@@ -1488,7 +1489,7 @@ void TraceLog::UpdateTraceEventDurationExplicit(
#if defined(OS_WIN)
// Generate an ETW event that marks the end of a complete event.
if (category_group_enabled_local & TraceCategory::ENABLED_FOR_ETW_EXPORT)
- TraceEventETWExport::AddCompleteEndEvent(name);
+ TraceEventETWExport::AddCompleteEndEvent(category_group_enabled, name);
#endif // OS_WIN
if (category_group_enabled_local & TraceCategory::ENABLED_FOR_RECORDING) {
diff --git a/chromium/base/trace_event/trace_logging_minimal_win.cc b/chromium/base/trace_event/trace_logging_minimal_win.cc
new file mode 100644
index 00000000000..6a346a0e281
--- /dev/null
+++ b/chromium/base/trace_event/trace_logging_minimal_win.cc
@@ -0,0 +1,351 @@
+// Copyright 2020 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_logging_minimal_win.h"
+
+#include <evntrace.h>
+
+#include "base/check_op.h"
+
+/*
+EventSetInformation configuration macros:
+
+TraceLogging works best if the EventSetInformation API can be used to notify
+ETW that the provider uses TraceLogging event encoding.
+
+The EventSetInformation API is available on Windows 8 and later. (It is also
+available on fully-patched Windows 7, but not on Windows 7 RTM).
+
+The TLM_HAVE_EVENT_SET_INFORMATION and TLM_EVENT_SET_INFORMATION macros can
+be set before compiling this file to control how the TlmProvider class deals
+with the EventSetInformation API.
+
+If these macros are not set, the default behavior is to check the WINVER
+macro at compile time:
+
+- If WINVER is set to Windows 7 or before, TlmProvider will use GetProcAddress
+ to locate EventSetInformation, and then invoke it if present. This is less
+ efficient, but works on older versions of Windows.
+- If WINVER is set to Windows 8 or later, TlmProvider will directly invoke
+ EventSetInformation. This is more efficient, but the resulting application
+ will only work correctly on newer versions of Windows.
+
+If you need to run on Windows 7 RTM, but for some reason need to set WINVER to
+Windows 8 or higher, you can override the default behavior by defining
+TLM_HAVE_EVENT_SET_INFORMATION=2 when compiling this file.
+
+Details:
+- The TLM_EVENT_SET_INFORMATION macro can be set the name of a replacement
+ function that TlmProvider should use instead of EventSetInformation.
+- The TLM_HAVE_EVENT_SET_INFORMATION macro can be set to 0 (disable the use of
+ EventSetInformation), 1 (directly invoke EventSetInformation), or 2 (try to
+ locate EventSetInformation via GetProcAddress, and invoke if found).
+*/
+
+// This code needs to run on Windows 7 and this is magic which
+// removes static linking to EventSetInformation
+#define TLM_HAVE_EVENT_SET_INFORMATION 2
+
+#ifndef TLM_EVENT_SET_INFORMATION
+#define TLM_EVENT_SET_INFORMATION EventSetInformation
+#ifndef TLM_HAVE_EVENT_SET_INFORMATION
+#if WINVER < 0x0602 || !defined(EVENT_FILTER_TYPE_SCHEMATIZED)
+// Find "EventSetInformation" via GetModuleHandleExW+GetProcAddress
+#define TLM_HAVE_EVENT_SET_INFORMATION 2
+#else
+// Directly invoke TLM_EVENT_SET_INFORMATION(...)
+#define TLM_HAVE_EVENT_SET_INFORMATION 1
+#endif
+#endif
+#elif !defined(TLM_HAVE_EVENT_SET_INFORMATION)
+// Directly invoke TLM_EVENT_SET_INFORMATION(...)
+#define TLM_HAVE_EVENT_SET_INFORMATION 1
+#endif
+
+TlmProvider::~TlmProvider() {
+ Unregister();
+}
+
+TlmProvider::TlmProvider(const char* provider_name,
+ const GUID& provider_guid,
+ PENABLECALLBACK enable_callback,
+ void* enable_callback_context) noexcept {
+ int32_t status = Register(provider_name, provider_guid, enable_callback,
+ enable_callback_context);
+ DCHECK_EQ(status, ERROR_SUCCESS);
+}
+
+// Appends a nul-terminated string to a metadata block.
+// Returns new meta_data_index value, or -1 for overflow.
+uint16_t TlmProvider::AppendNameToMetadata(char* metadata,
+ uint16_t metadata_size,
+ uint16_t metadata_index,
+ const char* name) const noexcept {
+ uint16_t index = metadata_index;
+ DCHECK_LE(index, metadata_size);
+
+ const size_t cch = strlen(name) + 1;
+ if (cch > static_cast<unsigned>(metadata_size - index)) {
+ index = -1;
+ } else {
+ memcpy(metadata + index, name, cch);
+ index += static_cast<uint16_t>(cch);
+ }
+
+ return index;
+}
+
+void TlmProvider::Unregister() noexcept {
+ if (reg_handle_ == 0)
+ return;
+
+ int32_t status = EventUnregister(reg_handle_);
+ DCHECK_EQ(status, ERROR_SUCCESS);
+ reg_handle_ = 0;
+ level_plus1_ = 0;
+}
+
+int32_t TlmProvider::Register(const char* provider_name,
+ const GUID& provider_guid,
+ PENABLECALLBACK enable_callback,
+ void* enable_callback_context) noexcept {
+ // Calling Register when already registered is a fatal error.
+ CHECK_EQ(reg_handle_, 0ULL);
+
+ // provider_metadata_ for tracelogging has the following format:
+ // UINT16 metadata_size;
+ // char NullTerminatedUtf8ProviderName[];
+ // ( + optional extension data, not used here)
+
+ // Append the provider name starting at offset 2 (skip MetadataSize).
+ provider_metadata_size_ = AppendNameToMetadata(
+ provider_metadata_, kMaxProviderMetadataSize, 2, provider_name);
+ if (provider_metadata_size_ > kMaxProviderMetadataSize) {
+ DCHECK_GT(provider_metadata_size_, kMaxProviderMetadataSize);
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ // Fill in MetadataSize field at offset 0.
+ *reinterpret_cast<uint16_t*>(provider_metadata_) = provider_metadata_size_;
+
+ enable_callback_ = enable_callback;
+ enable_callback_context_ = enable_callback_context;
+ int32_t status =
+ EventRegister(&provider_guid, StaticEnableCallback, this, &reg_handle_);
+ if (status != ERROR_SUCCESS)
+ return status;
+
+#if TLM_HAVE_EVENT_SET_INFORMATION == 1
+
+ // Best-effort, ignore failure.
+ status =
+ TLM_EVENT_SET_INFORMATION(reg_handle_, EventProviderSetTraits,
+ provider_metadata_, provider_metadata_size_);
+
+#elif TLM_HAVE_EVENT_SET_INFORMATION == 2
+
+ HMODULE eventing_lib;
+ if (GetModuleHandleExW(0, L"api-ms-win-eventing-provider-l1-1-0.dll",
+ &eventing_lib) ||
+ GetModuleHandleExW(0, L"advapi32.dll", &eventing_lib)) {
+ typedef ULONG(WINAPI * PFEventSetInformation)(
+ REGHANDLE reg_handle, EVENT_INFO_CLASS information_class,
+ PVOID event_information, ULONG information_length);
+ PFEventSetInformation event_set_information_ptr =
+ reinterpret_cast<decltype(&::EventSetInformation)>(
+ GetProcAddress(eventing_lib, "EventSetInformation"));
+ if (event_set_information_ptr) {
+ // Best-effort, ignore failure.
+ status = event_set_information_ptr(reg_handle_, EventProviderSetTraits,
+ provider_metadata_,
+ provider_metadata_size_);
+ DCHECK_EQ(status, ERROR_SUCCESS);
+ }
+
+ FreeLibrary(eventing_lib);
+ }
+
+#else // TLM_HAVE_EVENT_SET_INFORMATION == 0
+
+ // Make no attempt to invoke EventSetInformation.
+
+#endif // TLM_HAVE_EVENT_SET_INFORMATION
+
+ return status;
+}
+
+bool TlmProvider::IsEnabled() const noexcept {
+ return 0 < level_plus1_;
+}
+
+bool TlmProvider::IsEnabled(uint8_t level) const noexcept {
+ return level < level_plus1_;
+}
+
+bool TlmProvider::IsEnabled(uint8_t level, uint64_t keyword) const noexcept {
+ return level < level_plus1_ && KeywordEnabled(keyword);
+}
+
+bool TlmProvider::IsEnabled(
+ const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
+ return event_descriptor.Level < level_plus1_ &&
+ KeywordEnabled(event_descriptor.Keyword);
+}
+
+void TlmProvider::StaticEnableCallback(const GUID* source_id,
+ ULONG is_enabled,
+ UCHAR level,
+ ULONGLONG match_any_keyword,
+ ULONGLONG match_all_keyword,
+ PEVENT_FILTER_DESCRIPTOR filter_data,
+ PVOID callback_context) {
+ if (!callback_context)
+ return;
+
+ TlmProvider* pProvider = static_cast<TlmProvider*>(callback_context);
+ switch (is_enabled) {
+ case EVENT_CONTROL_CODE_DISABLE_PROVIDER:
+ pProvider->level_plus1_ = 0;
+ break;
+ case EVENT_CONTROL_CODE_ENABLE_PROVIDER:
+ pProvider->level_plus1_ =
+ level != 0 ? static_cast<unsigned>(level) + 1u : 256u;
+ pProvider->keyword_any_ = match_any_keyword;
+ pProvider->keyword_all_ = match_all_keyword;
+ break;
+ }
+
+ if (pProvider->enable_callback_) {
+ pProvider->enable_callback_(source_id, is_enabled, level, match_any_keyword,
+ match_all_keyword, filter_data,
+ pProvider->enable_callback_context_);
+ }
+}
+
+uint16_t TlmProvider::EventBegin(char* metadata,
+ const char* event_name) const noexcept {
+ // EventMetadata for tracelogging has the following format
+ // UINT16 MetadataSize;
+ // BYTE SpecialFlags[]; // Not used, so always size 1.
+ // char NullTerminatedUtf8EventName[];
+ // ( + field definitions)
+
+ uint16_t index = 2; // Skip MetadataSize field.
+
+ metadata[index] = 0; // Set SpecialFlags[0] = 0.
+ index++; // sizeof(SpecialFlags) == 1.
+
+ index =
+ AppendNameToMetadata(metadata, kMaxEventMetadataSize, index, event_name);
+ return index;
+}
+
+char TlmProvider::EventAddField(char* metadata,
+ uint16_t* metadata_index,
+ uint8_t in_type,
+ uint8_t out_type,
+ const char* field_name) const noexcept {
+ DCHECK_LT(in_type, 0x80);
+ DCHECK_LT(out_type, 0x80);
+
+ // FieldDefinition =
+ // char NullTerminatedUtf8FieldName[];
+ // BYTE InType;
+ // BYTE OutType; // Only present if high bit set in InType.
+ // ( + optional extension data not used here)
+
+ if (*metadata_index >= kMaxEventMetadataSize)
+ return 0;
+
+ *metadata_index = AppendNameToMetadata(metadata, kMaxEventMetadataSize,
+ *metadata_index, field_name);
+ if (*metadata_index >= kMaxEventMetadataSize)
+ return 0;
+
+ if (out_type == 0) {
+ // 1-byte encoding: inType + TlgOutNULL.
+ if (1 > kMaxEventMetadataSize - *metadata_index) {
+ *metadata_index = -1;
+ return 0;
+ }
+
+ metadata[*metadata_index] = in_type;
+ *metadata_index += 1;
+ return 0;
+ }
+ // 2-byte encoding: in_type + out_type.
+ if (kMaxEventMetadataSize - *metadata_index < 2) {
+ *metadata_index = -1;
+ return 0;
+ }
+
+ // Set high bit to indicate presence of OutType.
+ metadata[*metadata_index] = in_type | 0x80;
+ *metadata_index += 1;
+ metadata[*metadata_index] = out_type;
+ *metadata_index += 1;
+ return 0;
+}
+
+int32_t TlmProvider::EventEnd(
+ char* metadata,
+ uint16_t meta_data_index,
+ EVENT_DATA_DESCRIPTOR* descriptors,
+ uint32_t descriptors_index,
+ const EVENT_DESCRIPTOR& event_descriptor) const noexcept {
+ if (meta_data_index > kMaxEventMetadataSize) {
+ return ERROR_BUFFER_OVERFLOW;
+ }
+
+ // Fill in EventMetadata's MetadataSize field.
+ *reinterpret_cast<uint16_t*>(metadata) = meta_data_index;
+
+ descriptors[0].Ptr = reinterpret_cast<ULONG_PTR>(provider_metadata_);
+ descriptors[0].Size = provider_metadata_size_;
+ descriptors[0].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_PROVIDER_METADATA;
+
+ descriptors[1].Ptr = reinterpret_cast<ULONG_PTR>(metadata);
+ descriptors[1].Size = meta_data_index;
+ descriptors[1].Reserved = EVENT_DATA_DESCRIPTOR_TYPE_EVENT_METADATA;
+
+ return EventWrite(reg_handle_, &event_descriptor, descriptors_index,
+ descriptors);
+}
+
+bool TlmProvider::KeywordEnabled(uint64_t keyword) const noexcept {
+ return keyword == 0 ||
+ ((keyword & keyword_any_) && (keyword & keyword_all_) == keyword_all_);
+}
+
+TlmMbcsStringField::TlmMbcsStringField(const char* name,
+ const char* value) noexcept
+ : TlmFieldBase(name), value_(value) {
+ DCHECK_NE(Name(), nullptr);
+ DCHECK_NE(value_, nullptr);
+}
+
+const char* TlmMbcsStringField::Value() const noexcept {
+ return value_;
+}
+
+void TlmMbcsStringField::FillEventDescriptor(
+ EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
+ EventDataDescCreate(&descriptors[0], value_, strlen(value_) + 1);
+}
+
+TlmUtf8StringField::TlmUtf8StringField(const char* name,
+ const char* value) noexcept
+ : TlmFieldBase(name), value_(value) {
+ DCHECK_NE(Name(), nullptr);
+ DCHECK_NE(value_, nullptr);
+}
+
+const char* TlmUtf8StringField::Value() const noexcept {
+ return value_;
+}
+
+void TlmUtf8StringField::FillEventDescriptor(
+ EVENT_DATA_DESCRIPTOR* descriptors) const noexcept {
+ EventDataDescCreate(&descriptors[0], value_, strlen(value_) + 1);
+}
diff --git a/chromium/base/trace_event/trace_logging_minimal_win.h b/chromium/base/trace_event/trace_logging_minimal_win.h
new file mode 100644
index 00000000000..e7b640e9f21
--- /dev/null
+++ b/chromium/base/trace_event/trace_logging_minimal_win.h
@@ -0,0 +1,393 @@
+// Copyright 2020 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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_LOGGING_MINIMAL_WIN_H_
+#define BASE_TRACE_EVENT_TRACE_LOGGING_MINIMAL_WIN_H_
+
+/*
+ * TraceLogging minimal dynamic provider
+ *
+ * TlmProvider is a simple class that implements an Event Tracing for Windows
+ * (ETW) provider that generates TraceLogging events with string fields. Unlike
+ * the Windows SDK's TraceLoggingProvider.h, this provider class supports
+ * runtime-variable settings for event name, level, keyword, and field name.
+ *
+ * Note that this approach is not recommended for general use. Support for
+ * runtime-variable settings is not normally needed, and it requires extra
+ * buffering as compared to the approach used by TraceLoggingProvider.h. It is
+ * needed in this case because we're trying to feed data from the existing call
+ * sites (which use a runtime-variable function-call syntax) into ETW. If this
+ * were new code, it would be better to update each call site to use a syntax
+ * compatible with compile-time event settings compatible with structured
+ * logging like TraceLoggingProvider.h.
+ */
+
+#include <stdint.h>
+#include <windows.h>
+// Evntprov.h must come after windows.h.
+#include <evntprov.h>
+// TODO(joel@microsoft.com) Update headers and use defined constants instead
+// of magic numbers after crbug.com/1089996 is resolved.
+
+/*
+ * An instance of TlmProvider represents a logger through which data can be
+ * sent to Event Tracing for Windows (ETW). This logger generates
+ * TraceLogging-encoded events (compatible with the events generated by the
+ * Windows SDK's TraceLoggingProvider.h header). In most cases, a developer
+ * would prefer using TraceLoggingProvider.h over TlmProvider
+ * (TraceLoggingProvider.h is more efficient and more full-featured), but
+ * TlmProvider allows for configuring the event parameters (event name,
+ * level, keyword, field names) at runtime (TraceLoggingProvider.h requires
+ * these to be set at compile time).
+ *
+ * Note that the Register/Unregister operations are relatively expensive, so
+ * the TlmProvider instance should be a long-lived variable (i.e. global
+ * variable, static variable, or field of a long-lived object), not a local
+ * variable andnot a field of a short-lived object.
+ *
+ * Note that provider name and provider GUID are a tightly-bound pair, i.e.
+ * they should each uniquely map to each other. Once a provider name and
+ * provider GUID have been used together, no other GUID should be used with
+ * that name and no other name should be used with that GUID. Normally this
+ * goal is achieved by using a hashing algorithm to generate the GUID from
+ * a hash of the name.
+ *
+ * Note that each event should use a non-zero level and a non-zero keyword.
+ * Predefined level constants are defined in <evntrace.h>: 0=Always,
+ * 1=Critical, 2=Error, 3=Warning, 4=Info, 5=Verbose (other level values can
+ * be used but are not well-defined and are not generally useful). A keyword
+ * is a bitmask of "category" bits, where each bit indicates whether or not
+ * the event belongs in a particular category of event. The low 48 bits are
+ * user-defined and the upper 16 bits are Microsoft-defined (in <winmeta.h>).
+ *
+ * General usage:
+ *
+ * // During component initialization (main or DllMain), call Register().
+ * // Note that there is an overload of the TlmProvider constructor that
+ * // calls Register(), but it's often convenient to do this manually
+ * // (i.e. to control the timing of the call to Register).
+ * my_provider.Register(
+ * "MyCompany.MyComponentName",
+ * MyComponentGuid);
+ *
+ * // To log an event with minimal code:
+ * my_provider.WriteEvent("MyEventName",
+ * TlmEventDescriptor(
+ * TRACE_LEVEL_VERBOSE, // Level defined in <evntrace.h>
+ * 0x20), // Keyword bits are user-defined.
+ * // Value must not be null for the string fields.
+ * TlmUtf8StringField("MyUtf8Field", GetValue1()),
+ * TlmMbcsStringField("MyAsciiField", GetValue2()));
+ *
+ * // Note that the minimal-code example has a bit of overhead, as it
+ * // will make the calls to GetValue1(), GetValue2(), and WriteEvent()
+ * // even if nobody is listening to the event. WriteEvent() will return
+ // immediately if nobody is listening, but there is still some
+ * // overhead. To minimize the overhead when nobody is listening,
+ * // add an extra IF condition:
+ * static const auto MyEventDescriptor = TlmEventDescriptor(
+ * TRACE_LEVEL_VERBOSE, // Level defined in <evntrace.h>
+ * 0x20); // Keyword bits are user-defined.
+ * if (my_provider.IsEnabled(MyEventDescriptor))
+ * {
+ * // The IF condition is primarily to prevent unnecessary
+ * // calls to GetValue1() and GetValue2().
+ * my_provider.WriteEvent("MyEventName",
+ * MyEventDescriptor,
+ * // Value must not be null for the string fields.
+ * TlmUtf8StringField("MyUtf8Field", GetValue1()),
+ * TlmMbcsStringField("MyAsciiField", GetValue2()));
+ * }
+ *
+ * // During component shutdown (main or DllMain), call Unregister().
+ * // Note that the TlmProvider destructor will also call
+ * // Unregister(), butit's often convenient to do this manually
+ * // (i.e. to control the timingof the call to Unregister).
+ * my_provider.Unregister();
+ */
+
+class TlmProvider {
+ public:
+ // Initialize a provider in the unregistered state.
+ // Note that WriteEvent and Unregister operations on an unregistered
+ // provider are safe no-ops.
+ constexpr TlmProvider() noexcept = default;
+
+ // Initializes a provider and attempts to register it.
+ // If there is an error, provider will be left unregistered.
+ // Note that WriteEvent and Unregister operations on an unregistered
+ // provider are safe no-ops.
+ TlmProvider(const char* provider_name,
+ const GUID& provider_guid,
+ PENABLECALLBACK enable_callback = nullptr,
+ void* enable_callback_context = nullptr) noexcept;
+
+ // If provider is registered, unregisters provider.
+ ~TlmProvider();
+
+ // Disable copy operations.
+ TlmProvider(const TlmProvider&) = delete;
+ TlmProvider& operator=(const TlmProvider&) = delete;
+
+ // Unregisters this provider.
+ // Calling Unregister on an unregistered provider is a safe no-op.
+ // Not thread safe - caller must ensure serialization between calls to
+ // Register() and calls to Unregister().
+ void Unregister() noexcept;
+
+ // Registers this provider. Returns Win32 error code or 0 for success.
+ // Error code is primarily for debugging and should generally be ignored
+ // in production (failure to register means Unregister and WriteEvent are
+ // safe no-ops.)
+ // Calling Register on an already-registered provider is a fatal error.
+ // Not thread safe - caller must ensure serialization between calls to
+ // Register() and calls to Unregister().
+ int32_t Register(const char* provider_name,
+ const GUID& provider_guid,
+ PENABLECALLBACK enable_callback = nullptr,
+ void* enable_callback_context = nullptr) noexcept;
+
+ // Returns true if any active trace listeners are interested in any events
+ // from this provider.
+ // Equivalent to IsEnabled(0, 0).
+ bool IsEnabled() const noexcept;
+
+ // Returns true if any active trace listeners are interested in events
+ // from this provider with the specified level.
+ // Equivalent to IsEnabled(level, 0).
+ bool IsEnabled(uint8_t level) const noexcept;
+
+ // Returns true if any active trace listeners are interested in events
+ // from this provider with the specified level and keyword.
+ bool IsEnabled(uint8_t level, uint64_t keyword) const noexcept;
+
+ // Returns true if any active trace listeners are interested in events
+ // from this provider with the specified level and keyword.
+ // Equivalent to IsEnabled(event_descriptor.level, event_descriptor.keyword).
+ bool IsEnabled(const EVENT_DESCRIPTOR& event_descriptor) const noexcept;
+
+ // If any active trace listeners are interested in events from this provider
+ // with the specified level and keyword, packs the data into an event and
+ // sends it to ETW. Returns Win32 error code or 0 for success.
+ template <class... FieldTys>
+ int32_t WriteEvent(const char* event_name,
+ const EVENT_DESCRIPTOR& event_descriptor,
+ const FieldTys&... event_fields) const noexcept {
+ if (!IsEnabled(event_descriptor)) {
+ // If nobody is listening, report success.
+ return 0;
+ }
+ // Pack the event metadata.
+ char metadata[kMaxEventMetadataSize];
+ uint16_t metadata_index;
+ metadata_index = EventBegin(metadata, event_name);
+ { // scope for dummy array (simulates a C++17 comma-fold expression)
+ bool dummy[sizeof...(FieldTys) == 0 ? 1 : sizeof...(FieldTys)] = {
+ EventAddField(metadata, &metadata_index, event_fields.in_type_,
+ event_fields.out_type_, event_fields.Name())...};
+ DCHECK(dummy);
+ }
+
+ // Pack the event data.
+ constexpr uint8_t kDescriptorsCount =
+ 2 + DataDescCountSum<FieldTys...>::value;
+ EVENT_DATA_DESCRIPTOR descriptors[kDescriptorsCount];
+ uint8_t descriptors_index = 2;
+ { // scope for dummy array (simulates a C++17 comma-fold expression)
+ bool dummy[sizeof...(FieldTys) == 0 ? 1 : sizeof...(FieldTys)] = {
+ EventDescriptorFill(descriptors, &descriptors_index,
+ event_fields)...};
+ DCHECK(dummy);
+ }
+
+ // Finalize event and call EventWrite.
+ return EventEnd(metadata, metadata_index, descriptors, descriptors_index,
+ event_descriptor);
+ }
+
+ private:
+ // Size of the buffer used for provider metadata (field within the
+ // TlmProvider object). Provider metadata consists of the nul-terminated
+ // provider name plus a few sizes and flags, so this buffer needs to be
+ // just a few bytes larger than the largest expected provider name.
+ static constexpr uint16_t kMaxProviderMetadataSize = 128;
+
+ // Size of the buffer used for event metadata (stack-allocated in the
+ // WriteEvent method). Event metadata consists of nul-terminated event
+ // name, nul-terminated field names, field types (1 or 2 bytes per field),
+ // and a few bytes for sizes and flags.
+ static constexpr uint16_t kMaxEventMetadataSize = 256;
+
+ template <class... FieldTys>
+ struct DataDescCountSum; // undefined
+
+ template <>
+ struct DataDescCountSum<> {
+ static constexpr uint8_t value = 0;
+ };
+
+ template <class FieldTy1, class... FieldTyRest>
+ struct DataDescCountSum<FieldTy1, FieldTyRest...> {
+ static constexpr uint8_t value =
+ FieldTy1::data_desc_count_ + DataDescCountSum<FieldTyRest...>::value;
+ };
+
+ template <class FieldTy>
+ static char EventDescriptorFill(EVENT_DATA_DESCRIPTOR* descriptors,
+ uint8_t* pdescriptors_index,
+ const FieldTy& event_field) noexcept {
+ event_field.FillEventDescriptor(&descriptors[*pdescriptors_index]);
+ *pdescriptors_index += FieldTy::data_desc_count_;
+ return 0;
+ }
+
+ // This is called from the OS, so use the required call type.
+ static void __stdcall StaticEnableCallback(
+ const GUID* source_id,
+ ULONG is_enabled,
+ UCHAR level,
+ ULONGLONG match_any_keyword,
+ ULONGLONG match_all_keyword,
+ PEVENT_FILTER_DESCRIPTOR FilterData,
+ PVOID callback_context);
+
+ // Returns initial value of metadata_index.
+ uint16_t EventBegin(char* metadata, const char* event_name) const noexcept;
+
+ char EventAddField(char* metadata,
+ uint16_t* metadata_index,
+ uint8_t in_type,
+ uint8_t out_type,
+ const char* field_name) const noexcept;
+
+ // Returns Win32 error code, or 0 for success.
+ int32_t EventEnd(char* metadata,
+ uint16_t metadata_index,
+ EVENT_DATA_DESCRIPTOR* descriptors,
+ uint32_t descriptors_index,
+ const EVENT_DESCRIPTOR& event_descriptor) const noexcept;
+
+ bool KeywordEnabled(uint64_t keyword) const noexcept;
+
+ uint16_t AppendNameToMetadata(char* metadata,
+ uint16_t metadata_size,
+ uint16_t metadata_index,
+ const char* name) const noexcept;
+
+ uint32_t level_plus1_ = 0;
+ uint32_t provider_metadata_size_ = 0;
+ uint64_t keyword_any_ = 0;
+ uint64_t keyword_all_ = 0;
+ uint64_t reg_handle_ = 0;
+ PENABLECALLBACK enable_callback_ = nullptr;
+ void* enable_callback_context_ = nullptr;
+ char provider_metadata_[kMaxProviderMetadataSize] = {};
+};
+
+// Base class for field types.
+template <uint8_t data_desc_count,
+ uint8_t in_type,
+ uint8_t out_type = 0> // Default out_type is TlgOutNULL
+class TlmFieldBase {
+ public:
+ constexpr const char* Name() const noexcept { return name_; }
+
+ protected:
+ explicit constexpr TlmFieldBase(const char* name) noexcept : name_(name) {}
+
+ private:
+ friend class TlmProvider;
+
+ static constexpr uint8_t data_desc_count_ = data_desc_count;
+ static constexpr uint8_t in_type_ = in_type;
+ static constexpr uint8_t out_type_ = out_type;
+
+ const char* name_;
+};
+
+// Class that represents an event field containing nul-terminated MBCS data.
+class TlmMbcsStringField
+ : public TlmFieldBase<1, 2> // 1 data descriptor, Type = TlgInANSISTRING
+{
+ public:
+ // name is a utf-8 nul-terminated string.
+ // value is MBCS nul-terminated string (assumed to be in system's default code
+ // page).
+ TlmMbcsStringField(const char* name, const char* value) noexcept;
+
+ const char* Value() const noexcept;
+
+ void FillEventDescriptor(EVENT_DATA_DESCRIPTOR* descriptors) const noexcept;
+
+ private:
+ const char* value_;
+};
+
+// Class that represents an event field containing nul-terminated UTF-8 data.
+class TlmUtf8StringField
+ : public TlmFieldBase<1, 2, 35> // 1 data descriptor, Type =
+ // TlgInANSISTRING + TlgOutUTF8
+{
+ public:
+ // name and value are utf-8 nul-terminated strings.
+ TlmUtf8StringField(const char* name, const char* value) noexcept;
+
+ const char* Value() const noexcept;
+
+ void FillEventDescriptor(EVENT_DATA_DESCRIPTOR* descriptors) const noexcept;
+
+ private:
+ const char* value_;
+};
+
+// Helper for creating event descriptors for use with WriteEvent.
+constexpr EVENT_DESCRIPTOR TlmEventDescriptor(uint8_t level,
+ uint64_t keyword) noexcept {
+ return {
+
+ // Id
+ // TraceLogging generally uses the event's Name instead of Id+Version,
+ // so Id is normally set to 0 for TraceLogging events.
+ 0,
+
+ // Version
+ // TraceLogging generally uses the event's Name instead of Id+Version,
+ // so Version is normally set to 0 for TraceLogging events.
+ 0,
+
+ // Channel (WINEVENT_CHANNEL_*)
+ // Setting Channel = 11 allows TraceLogging events to be decoded
+ // correctly even if they were collected on older operating systems.
+ // If a TraceLogging event sets channel to a value other than 11, the
+ // event will only decode correctly if it was collected on an
+ // operating system that has built-in TraceLogging support, i.e.
+ // Windows 7sp1 + patch, Windows 8.1 + patch, or Windows 10+.
+ 11, // = WINEVENT_CHANNEL_TRACELOGGING
+
+ // Level (WINEVENT_LEVEL_*)
+ // 0=always, 1=fatal, 2=error, 3=warning, 4=info, 5=verbose.
+ // Levels higher than 5 are for user-defined debug levels.
+ level,
+
+ // Opcode (WINEVENT_OPCODE_*)
+ // Set Opcode for special semantics such as starting/ending an
+ // activity.
+ 0, // = WINEVENT_OPCODE_INFO
+
+ // Task
+ // Set Task for user-defined semantics.
+ 0, // = WINEVENT_TASK_NONE
+
+ // Keyword
+ // A keyword is a 64-bit value used for filtering events. Each bit of
+ // the keyword indicates whether the event belongs to a particular
+ // category of events. The top 16 bits of keyword have
+ // Microsoft-defined semantics and should be set to 0. The low 48 bits
+ // of keyword have user-defined semantics. All events should use a
+ // nonzero keyword to support effective event filtering (events with
+ // keyword set to 0 always pass keyword filtering).
+ keyword};
+}
+
+#endif // BASE_TRACE_EVENT_TRACE_LOGGING_MINIMAL_WIN_H_ \ No newline at end of file
diff --git a/chromium/base/trace_event/typed_macros.h b/chromium/base/trace_event/typed_macros.h
new file mode 100644
index 00000000000..8b792c4d52b
--- /dev/null
+++ b/chromium/base/trace_event/typed_macros.h
@@ -0,0 +1,74 @@
+// Copyright 2019 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.
+
+#ifndef BASE_TRACE_EVENT_TYPED_MACROS_H_
+#define BASE_TRACE_EVENT_TYPED_MACROS_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/typed_macros_internal.h"
+#include "build/build_config.h"
+
+// Needed not for this file, but for every user of the TRACE_EVENT macros for
+// the lambda definition. So included here for convenience.
+#include "third_party/perfetto/include/perfetto/tracing/event_context.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+#if defined(TRACE_EVENT_BEGIN)
+#error "Another copy of perfetto tracing macros have been included"
+#endif
+
+// This file implements typed event macros [1] that will be provided by the
+// Perfetto client library in the future, as a stop-gap to support typed trace
+// events in Chrome until we are ready to switch to the client library's
+// implementation of trace macros.
+// [1] https://perfetto.dev/docs/instrumentation/track-events
+// TODO(crbug/1006541): Replace this file with the Perfetto client library.
+
+// Begin a thread-scoped slice under |category| with the title |name|. Both
+// strings must be static constants. The track event is only recorded if
+// |category| is enabled for a tracing session.
+//
+// Rest of parameters can contain: a perfetto::Track object for asynchronous
+// events and a lambda used to fill typed event. Should be passed in that exact
+// order when both are used.
+//
+// When lambda is passed as an argument, it is executed synchronously.
+//
+// TODO(nuskos): Give a simple example once we have a typed event that doesn't
+// need interning.
+// TRACE_EVENT_BEGIN("log", "LogMessage",
+// [](perfetto::EventContext ctx) {
+// auto* event = ctx.event();
+// // Fill in some field in track_event.
+// });
+#define TRACE_EVENT_BEGIN(category, name, ...) \
+ TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_BEGIN, category, name, \
+ TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__)
+
+// End a thread-scoped slice under |category|.
+#define TRACE_EVENT_END(category, ...) \
+ TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, category, \
+ trace_event_internal::kTraceEventEndName, \
+ TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__)
+
+// Begin a thread-scoped slice which gets automatically closed when going out
+// of scope.
+//
+// BEWARE: similarly to TRACE_EVENT_BEGIN, this macro does accept a track, but
+// it does not work properly and should not be used.
+// TODO(b/154583431): figure out how to fix or disallow that and update the
+// comment.
+//
+// Similarly to TRACE_EVENT_BEGIN, when lambda is passed as an argument, it is
+// executed synchronously.
+#define TRACE_EVENT(category, name, ...) \
+ TRACING_INTERNAL_SCOPED_ADD_TRACE_EVENT(category, name, ##__VA_ARGS__)
+
+// Emit a single event called "name" immediately, with zero duration.
+#define TRACE_EVENT_INSTANT(category, name, scope, ...) \
+ TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_INSTANT, category, name, \
+ scope, ##__VA_ARGS__)
+
+#endif // BASE_TRACE_EVENT_TYPED_MACROS_H_
diff --git a/chromium/base/trace_event/typed_macros_embedder_support.h b/chromium/base/trace_event/typed_macros_embedder_support.h
new file mode 100644
index 00000000000..d06c5b8a359
--- /dev/null
+++ b/chromium/base/trace_event/typed_macros_embedder_support.h
@@ -0,0 +1,65 @@
+// Copyright 2020 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.
+
+#ifndef BASE_TRACE_EVENT_TYPED_MACROS_EMBEDDER_SUPPORT_H_
+#define BASE_TRACE_EVENT_TYPED_MACROS_EMBEDDER_SUPPORT_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT TrackEventHandle {
+ public:
+ using TrackEvent = perfetto::protos::pbzero::TrackEvent;
+
+ class BASE_EXPORT CompletionListener {
+ public:
+ // Implemented in typed_macros_internal.h.
+ virtual ~CompletionListener();
+ virtual void OnTrackEventCompleted() = 0;
+ };
+
+ // Creates a handle to |event| which notifies |listener| on the handle's
+ // destruction, i.e. after the event lambda has emitted any typed arguments
+ // into the event. Note that |listener| must outlive the TRACE_EVENT call,
+ // i.e. cannot be destroyed until OnTrackEventCompleted() is called. Ownership
+ // of both TrackEvent and the listener remains with the caller.
+ TrackEventHandle(TrackEvent* event, CompletionListener* listener)
+ : event_(event), listener_(listener) {}
+
+ // Creates an invalid handle.
+ TrackEventHandle() : TrackEventHandle(nullptr, nullptr) {}
+
+ ~TrackEventHandle() {
+ if (listener_)
+ listener_->OnTrackEventCompleted();
+ }
+
+ explicit operator bool() const { return event_; }
+ TrackEvent& operator*() const { return *event_; }
+ TrackEvent* operator->() const { return event_; }
+ TrackEvent* get() const { return event_; }
+
+ private:
+ TrackEvent* event_;
+ CompletionListener* listener_;
+};
+
+using PrepareTrackEventFunction = TrackEventHandle (*)(TraceEvent*);
+
+// Embedder should call this (only once) to set the callback invoked when a
+// typed event should be emitted. The callback function may be executed on any
+// thread. Implemented in typed_macros_internal.h.
+BASE_EXPORT void EnableTypedTraceEvents(
+ PrepareTrackEventFunction typed_event_callback);
+
+BASE_EXPORT void ResetTypedTraceEventsForTesting();
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TYPED_MACROS_EMBEDDER_SUPPORT_H_
diff --git a/chromium/base/trace_event/typed_macros_internal.cc b/chromium/base/trace_event/typed_macros_internal.cc
new file mode 100644
index 00000000000..89825fde5cb
--- /dev/null
+++ b/chromium/base/trace_event/typed_macros_internal.cc
@@ -0,0 +1,95 @@
+// Copyright 2019 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/typed_macros_internal.h"
+
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "base/trace_event/thread_instruction_count.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/typed_macros.h"
+
+namespace {
+
+base::ThreadTicks ThreadNow() {
+ return base::ThreadTicks::IsSupported()
+ ? base::subtle::ThreadTicksNowIgnoringOverride()
+ : base::ThreadTicks();
+}
+
+base::trace_event::ThreadInstructionCount ThreadInstructionNow() {
+ return base::trace_event::ThreadInstructionCount::IsSupported()
+ ? base::trace_event::ThreadInstructionCount::Now()
+ : base::trace_event::ThreadInstructionCount();
+}
+
+base::trace_event::PrepareTrackEventFunction g_typed_event_callback = nullptr;
+
+} // namespace
+
+namespace base {
+namespace trace_event {
+
+void EnableTypedTraceEvents(PrepareTrackEventFunction typed_event_callback) {
+ g_typed_event_callback = typed_event_callback;
+}
+
+void ResetTypedTraceEventsForTesting() {
+ g_typed_event_callback = nullptr;
+}
+
+TrackEventHandle::CompletionListener::~CompletionListener() = default;
+
+} // namespace trace_event
+} // namespace base
+
+namespace trace_event_internal {
+
+base::trace_event::TrackEventHandle CreateTrackEvent(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ base::TimeTicks ts,
+ bool explicit_track) {
+ DCHECK(phase == TRACE_EVENT_PHASE_BEGIN || phase == TRACE_EVENT_PHASE_END ||
+ phase == TRACE_EVENT_PHASE_INSTANT);
+ DCHECK(category_group_enabled);
+
+ if (!g_typed_event_callback)
+ return base::trace_event::TrackEventHandle();
+
+ const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ auto* trace_log = base::trace_event::TraceLog::GetInstance();
+ DCHECK(trace_log);
+ if (!trace_log->ShouldAddAfterUpdatingState(phase, category_group_enabled,
+ name, trace_event_internal::kNoId,
+ thread_id, nullptr)) {
+ return base::trace_event::TrackEventHandle();
+ }
+
+ if (ts.is_null()) {
+ ts = TRACE_TIME_TICKS_NOW();
+ } else {
+ flags |= TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP;
+ }
+
+ // Only emit thread time / instruction count for events on the default track
+ // without explicit timestamp.
+ base::ThreadTicks thread_now;
+ base::trace_event::ThreadInstructionCount thread_instruction_now;
+ if ((flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP) == 0 && !explicit_track) {
+ thread_now = ThreadNow();
+ thread_instruction_now = ThreadInstructionNow();
+ }
+
+ base::trace_event::TraceEvent event(
+ thread_id, ts, thread_now, thread_instruction_now, phase,
+ category_group_enabled, name, trace_event_internal::kGlobalScope,
+ trace_event_internal::kNoId, trace_event_internal::kNoId, nullptr, flags);
+
+ return g_typed_event_callback(&event);
+}
+
+} // namespace trace_event_internal
diff --git a/chromium/base/trace_event/typed_macros_internal.h b/chromium/base/trace_event/typed_macros_internal.h
new file mode 100644
index 00000000000..51e91b7e56e
--- /dev/null
+++ b/chromium/base/trace_event/typed_macros_internal.h
@@ -0,0 +1,176 @@
+// Copyright 2019 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.
+
+#ifndef BASE_TRACE_EVENT_TYPED_MACROS_INTERNAL_H_
+#define BASE_TRACE_EVENT_TYPED_MACROS_INTERNAL_H_
+
+#include "base/base_export.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/typed_macros_embedder_support.h"
+#include "build/build_config.h"
+#include "third_party/perfetto/include/perfetto/protozero/message_handle.h"
+#include "third_party/perfetto/include/perfetto/tracing/event_context.h"
+#include "third_party/perfetto/include/perfetto/tracing/track.h"
+#include "third_party/perfetto/protos/perfetto/trace/track_event/track_event.pbzero.h"
+
+// These macros should not be called directly. They are intended to be used by
+// macros in //base/trace_event/typed_macros.h only.
+
+#define TRACING_INTERNAL_CONCAT2(a, b) a##b
+#define TRACING_INTERNAL_CONCAT(a, b) TRACING_INTERNAL_CONCAT2(a, b)
+#define TRACING_INTERNAL_UID(prefix) TRACING_INTERNAL_CONCAT(prefix, __LINE__)
+
+#define TRACING_INTERNAL_ADD_TRACE_EVENT(phase, category, name, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED()) { \
+ trace_event_internal::AddTraceEvent( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ flags, ##__VA_ARGS__); \
+ } \
+ } while (false)
+
+#define TRACING_INTERNAL_SCOPED_ADD_TRACE_EVENT(category, name, ...) \
+ struct { \
+ struct ScopedTraceEvent { \
+ /* The parameter is an implementation detail. It allows the */ \
+ /* anonymous struct to use aggregate initialization to invoke the */ \
+ /* lambda to emit the begin event with the proper reference capture */ \
+ /* for any TrackEventArgumentFunction in |__VA_ARGS__|. This is */ \
+ /* required so that the scoped event is exactly ONE line and can't */ \
+ /* escape the scope if used in a single line if statement. */ \
+ ScopedTraceEvent(...) {} \
+ ~ScopedTraceEvent() { \
+ /* TODO(nuskos): Remove the empty string passed as the |name| */ \
+ /* field. As described in macros.h we shouldn't need it in our */ \
+ /* end state. */ \
+ TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_END, category, "", \
+ TRACE_EVENT_FLAG_NONE, \
+ [](perfetto::EventContext) {}); \
+ } \
+ } event; \
+ } TRACING_INTERNAL_UID(scoped_event){[&]() { \
+ TRACING_INTERNAL_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_BEGIN, category, name, \
+ TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
+ return 0; \
+ }()};
+
+namespace trace_event_internal {
+
+// Copy of function with the same name from Perfetto client library.
+template <typename T>
+static constexpr bool IsValidTraceLambdaImpl(
+ typename std::enable_if<static_cast<bool>(
+ sizeof(std::declval<T>()(std::declval<perfetto::EventContext>()),
+ 0))>::type* = nullptr) {
+ return true;
+}
+
+template <typename T>
+static constexpr bool IsValidTraceLambdaImpl(...) {
+ return false;
+}
+
+template <typename T>
+static constexpr bool IsValidTraceLambda() {
+ return IsValidTraceLambdaImpl<T>(nullptr);
+}
+
+// The perfetto client library does not use event names for
+// TRACE_EVENT_PHASE_END. However, TraceLog expects all TraceEvents to have
+// event names. So, until we move over to the client library, we will use this
+// empty name for all TRACE_EVENT_PHASE_END typed events.
+constexpr char kTraceEventEndName[] = "";
+
+base::trace_event::TrackEventHandle BASE_EXPORT
+CreateTrackEvent(char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ base::TimeTicks timestamp,
+ bool explicit_track);
+
+template <
+ typename TrackEventArgumentFunction = void (*)(perfetto::EventContext),
+ typename ArgumentFunctionCheck = typename std::enable_if<
+ IsValidTraceLambda<TrackEventArgumentFunction>()>::type>
+static inline void AddTraceEvent(char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ const perfetto::Track& track,
+ base::TimeTicks timestamp,
+ TrackEventArgumentFunction argument_func) {
+ base::trace_event::TrackEventHandle track_event =
+ CreateTrackEvent(phase, category_group_enabled, name, flags, timestamp,
+ track.uuid != perfetto::Track().uuid);
+ if (!track_event)
+ return;
+
+ if (track)
+ track_event->set_track_uuid(track.uuid);
+
+ argument_func(perfetto::EventContext(track_event.get()));
+}
+
+template <
+ typename TrackEventArgumentFunction = void (*)(perfetto::EventContext),
+ typename ArgumentFunctionCheck = typename std::enable_if<
+ IsValidTraceLambda<TrackEventArgumentFunction>()>::type,
+ typename TrackType,
+ typename TrackTypeCheck = typename std::enable_if<
+ std::is_convertible<TrackType, perfetto::Track>::value>::type>
+static inline void AddTraceEvent(char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ const TrackType& track,
+ TrackEventArgumentFunction argument_func) {
+ AddTraceEvent(phase, category_group_enabled, name, flags, track,
+ base::TimeTicks(), argument_func);
+}
+
+template <
+ typename TrackEventArgumentFunction = void (*)(perfetto::EventContext),
+ typename ArgumentFunctionCheck = typename std::enable_if<
+ IsValidTraceLambda<TrackEventArgumentFunction>()>::type>
+static inline void AddTraceEvent(char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ TrackEventArgumentFunction argument_func) {
+ AddTraceEvent(phase, category_group_enabled, name, flags, perfetto::Track(),
+ base::TimeTicks(), argument_func);
+}
+
+template <typename TrackType,
+ typename TrackTypeCheck = typename std::enable_if<
+ std::is_convertible<TrackType, perfetto::Track>::value>::type>
+inline void AddTraceEvent(char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ const TrackType& track) {
+ AddTraceEvent(phase, category_group_enabled, name, flags, track,
+ base::TimeTicks(), [](perfetto::EventContext ctx) {});
+}
+
+template <typename TrackType,
+ typename TrackTypeCheck = typename std::enable_if<
+ std::is_convertible<TrackType, perfetto::Track>::value>::type>
+inline void AddTraceEvent(char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned int flags,
+ const TrackType& track,
+ base::TimeTicks timestamp) {
+ AddTraceEvent(phase, category_group_enabled, name, flags, track, timestamp,
+ [](perfetto::EventContext ctx) {});
+}
+
+} // namespace trace_event_internal
+
+#endif // BASE_TRACE_EVENT_TYPED_MACROS_INTERNAL_H_
diff --git a/chromium/base/trace_event/typed_macros_unittest.cc b/chromium/base/trace_event/typed_macros_unittest.cc
new file mode 100644
index 00000000000..741b43fba3f
--- /dev/null
+++ b/chromium/base/trace_event/typed_macros_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2020 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/typed_macros.h"
+
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_log.h"
+#include "base/trace_event/typed_macros_embedder_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/perfetto/include/perfetto/protozero/scattered_heap_buffer.h"
+
+#include "third_party/perfetto/protos/perfetto/trace/track_event/log_message.pbzero.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+constexpr const char kRecordAllCategoryFilter[] = "*";
+
+void CancelTraceAsync(WaitableEvent* flush_complete_event) {
+ TraceLog::GetInstance()->CancelTracing(base::BindRepeating(
+ [](WaitableEvent* complete_event,
+ const scoped_refptr<base::RefCountedString>&, bool has_more_events) {
+ if (!has_more_events)
+ complete_event->Signal();
+ },
+ base::Unretained(flush_complete_event)));
+}
+
+void CancelTrace() {
+ WaitableEvent flush_complete_event(WaitableEvent::ResetPolicy::AUTOMATIC,
+ WaitableEvent::InitialState::NOT_SIGNALED);
+ CancelTraceAsync(&flush_complete_event);
+ flush_complete_event.Wait();
+}
+
+struct TestTrackEvent;
+TestTrackEvent* g_test_track_event;
+
+struct TestTrackEvent : public TrackEventHandle::CompletionListener {
+ public:
+ TestTrackEvent() {
+ CHECK_EQ(g_test_track_event, nullptr)
+ << "Another instance of TestTrackEvent is already active";
+ g_test_track_event = this;
+ }
+
+ ~TestTrackEvent() override { g_test_track_event = nullptr; }
+
+ void OnTrackEventCompleted() override {
+ EXPECT_FALSE(event_completed);
+ event_completed = true;
+ }
+
+ protozero::HeapBuffered<perfetto::protos::pbzero::TrackEvent> event;
+ bool prepare_called = false;
+ bool event_completed = false;
+};
+
+TrackEventHandle PrepareTrackEvent(TraceEvent*) {
+ CHECK_NE(g_test_track_event, nullptr) << "TestTrackEvent not set yet";
+ g_test_track_event->prepare_called = true;
+ return TrackEventHandle(g_test_track_event->event.get(), g_test_track_event);
+}
+
+class TypedTraceEventTest : public testing::Test {
+ public:
+ TypedTraceEventTest() { EnableTypedTraceEvents(&PrepareTrackEvent); }
+
+ ~TypedTraceEventTest() override { ResetTypedTraceEventsForTesting(); }
+
+ protected:
+ TestTrackEvent event_;
+};
+
+} // namespace
+
+TEST_F(TypedTraceEventTest, CallbackExecutedWhenTracingEnabled) {
+ TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+ TraceLog::RECORDING_MODE);
+
+ TRACE_EVENT("cat", "Name", [this](perfetto::EventContext ctx) {
+ EXPECT_EQ(ctx.event(), event_.event.get());
+ perfetto::protos::pbzero::LogMessage* log = ctx.event()->set_log_message();
+ log->set_body_iid(1);
+ });
+
+ EXPECT_TRUE(event_.prepare_called);
+ EXPECT_FALSE(event_.event.empty());
+ EXPECT_TRUE(event_.event_completed);
+
+ CancelTrace();
+}
+
+TEST_F(TypedTraceEventTest, CallbackNotExecutedWhenTracingDisabled) {
+ TRACE_EVENT("cat", "Name", [this](perfetto::EventContext ctx) {
+ EXPECT_EQ(ctx.event(), event_.event.get());
+ perfetto::protos::pbzero::LogMessage* log = ctx.event()->set_log_message();
+ log->set_body_iid(1);
+ });
+
+ EXPECT_FALSE(event_.prepare_called);
+ EXPECT_TRUE(event_.event.empty());
+ EXPECT_FALSE(event_.event_completed);
+}
+
+} // namespace trace_event
+} // namespace base