| Index: base/debug/trace_event_win.cc
|
| diff --git a/base/debug/trace_event_win.cc b/base/debug/trace_event_win.cc
|
| index 686ade344c889a25c4d52df1ae61dcf969b7bde3..5dd094cd0f09a82b993f03ef3568ec52298c85a4 100644
|
| --- a/base/debug/trace_event_win.cc
|
| +++ b/base/debug/trace_event_win.cc
|
| @@ -7,6 +7,136 @@
|
| #include "base/memory/singleton.h"
|
| #include <initguid.h> // NOLINT
|
|
|
| +namespace {
|
| +// Returns the ETW event type ("opcode") associated with an event. The ETW
|
| +// event type depends on:
|
| +// - |internal_type|: Internal type of the event.
|
| +// - |num_args|: Number of arguments included with the event.
|
| +// - |with_stack|: Presence of a stack trace with the event.
|
| +// The bits in the returned event type mean:
|
| +// - 0-3 LSB: Number of arguments associated with the event.
|
| +// - 4: Indicates whether a stack trace is included with the event.
|
| +// - 5-8 MSB: Code associated with an internal event type.
|
| +base::win::EtwEventType GetEtwEventType(char internal_type,
|
| + int num_args,
|
| + bool with_stack) {
|
| + const base::win::EtwEventType kEtwBeginType = 1;
|
| + const base::win::EtwEventType kEtwEndType = 2;
|
| + const base::win::EtwEventType kEtwCompleteType = 3;
|
| + const base::win::EtwEventType kEtwInstantType = 4;
|
| + const base::win::EtwEventType kEtwAsyncBeginType = 5;
|
| + const base::win::EtwEventType kEtwAsyncStepIntoType = 6;
|
| + const base::win::EtwEventType kEtwAsyncStepPastType = 7;
|
| + const base::win::EtwEventType kEtwAsyncEndType = 8;
|
| + const base::win::EtwEventType kEtwFlowBeginType = 9;
|
| + const base::win::EtwEventType kEtwFlowStepType = 10;
|
| + const base::win::EtwEventType kEtwFlowEndType = 11;
|
| + const base::win::EtwEventType kEtwMetadataType = 12;
|
| + const base::win::EtwEventType kEtwCounterType = 13;
|
| + const base::win::EtwEventType kEtwSampleType = 14;
|
| + const base::win::EtwEventType kEtwCreateObjectType = 15;
|
| + const base::win::EtwEventType kEtwSnapshotObjectType = 16;
|
| + const base::win::EtwEventType kEtwDeleteObjectType = 17;
|
| +
|
| + const base::win::EtwEventType kEtwInternalTypeShiftLeft = 3;
|
| + const base::win::EtwEventType kEtwStackMask = 0x04;
|
| + const base::win::EtwEventType kEtwNumArgsMask = 0x03;
|
| +
|
| + // This type is used by third party libraries. It's defined here so that
|
| + // events from these libraries can be handled correctly.
|
| + const char kTraceEventPhaseInstantOld = 'I';
|
| +
|
| + base::win::EtwEventType etw_type;
|
| + switch (internal_type) {
|
| + case TRACE_EVENT_PHASE_BEGIN:
|
| + etw_type = kEtwBeginType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_END:
|
| + etw_type = kEtwEndType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_COMPLETE:
|
| + etw_type = kEtwCompleteType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_INSTANT:
|
| + case kTraceEventPhaseInstantOld:
|
| + etw_type = kEtwInstantType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_ASYNC_BEGIN:
|
| + etw_type = kEtwAsyncBeginType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_ASYNC_STEP_INTO:
|
| + etw_type = kEtwAsyncStepIntoType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_ASYNC_STEP_PAST:
|
| + etw_type = kEtwAsyncStepPastType;
|
| + break;
|
| + case TRACE_EVENT_PHASE_ASYNC_END:
|
| + etw_type = kEtwAsyncEndType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_FLOW_BEGIN:
|
| + etw_type = kEtwFlowBeginType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_FLOW_STEP:
|
| + etw_type = kEtwFlowStepType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_FLOW_END:
|
| + etw_type = kEtwFlowEndType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_METADATA:
|
| + etw_type = kEtwMetadataType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_COUNTER:
|
| + etw_type = kEtwCounterType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_SAMPLE:
|
| + etw_type = kEtwSampleType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_CREATE_OBJECT:
|
| + etw_type = kEtwCreateObjectType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT:
|
| + etw_type = kEtwSnapshotObjectType;
|
| + break;
|
| +
|
| + case TRACE_EVENT_PHASE_DELETE_OBJECT:
|
| + etw_type = kEtwAsyncEndType;
|
| + break;
|
| +
|
| + default:
|
| + NOTREACHED() << "Unknown event type";
|
| + etw_type = kEtwInstantType;
|
| + break;
|
| + }
|
| +
|
| + etw_type = etw_type << kEtwInternalTypeShiftLeft;
|
| + DCHECK(num_args <= kEtwNumArgsMask);
|
| + etw_type += static_cast<base::win::EtwEventType>(num_args) & kEtwNumArgsMask;
|
| + if (with_stack)
|
| + etw_type |= kEtwStackMask;
|
| +
|
| + return etw_type;
|
| +}
|
| +
|
| +// Maximum number of MOF fields for traced events.
|
| +// See the comment above the declaration of
|
| +// TraceEventETWProvider::TraceEventWithArgs() for the list of fields.
|
| +const int kTraceNumFields = 5 + 2 * base::debug::kTraceMaxNumArgs;
|
| +} // namespace
|
| +
|
| namespace base {
|
| namespace debug {
|
|
|
| @@ -21,10 +151,9 @@ const GUID kChromeTraceProviderName = {
|
| const GUID kTraceEventClass32 = {
|
| 0xb967ae67, 0xbb22, 0x49d7, 0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60 };
|
|
|
| -// {97BE602D-2930-4ac3-8046-B6763B631DFE}
|
| -const GUID kTraceEventClass64 = {
|
| - 0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe};
|
| -
|
| +// {d2d578d9-2936-45b6-a09f-30e32715f41d}
|
| +const GUID kTraceEventClass = {
|
| + 0xd2d578d9, 0x2936, 0x45b6, 0xa0, 0x9f, 0x30, 0xe3, 0x27, 0x15, 0xf4, 0x1d};
|
|
|
| TraceEventETWProvider::TraceEventETWProvider() :
|
| EtwTraceProvider(kChromeTraceProviderName) {
|
| @@ -97,6 +226,87 @@ void TraceEventETWProvider::TraceEvent(const char* name,
|
| Log(event.get());
|
| }
|
|
|
| +void TraceEventETWProvider::TraceEventWithArgs(
|
| + const char* category_group,
|
| + const char* name,
|
| + char type,
|
| + 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) {
|
| + // Make sure we don't touch NULL.
|
| + if (name == NULL)
|
| + name = "";
|
| + if (category_group == NULL)
|
| + category_group = "";
|
| +
|
| + EtwMofEvent<kTraceNumFields> event(kTraceEventClass,
|
| + TRACE_LEVEL_INFORMATION);
|
| +
|
| + int field_index = 0;
|
| + event.SetField(field_index++, strlen(name) + 1, name);
|
| + event.SetField(field_index++, sizeof(id), &id);
|
| + event.SetField(field_index++, strlen(category_group) + 1, category_group);
|
| +
|
| + // Real number of arguments for the event. Might end up being less than
|
| + // |num_args| when some arguments types are deactivated by flags.
|
| + unsigned int real_num_args = 0;
|
| +
|
| + // Traced arguments values converted to strings.
|
| + std::string arg_str_values[kTraceMaxNumArgs];
|
| +
|
| + if (enable_flags() & CAPTURE_SIMPLE_ARGUMENTS ||
|
| + enable_flags() & CAPTURE_ALL_ARGUMENTS) {
|
| + if (num_args > kTraceMaxNumArgs) {
|
| + NOTREACHED() << "Maximum number of custom fields exceeded in ETW event. "
|
| + "Extra custom fields will be ignored.";
|
| + num_args = kTraceMaxNumArgs;
|
| + }
|
| +
|
| + for (int i = 0; i < num_args; ++i) {
|
| + if (arg_types[i] != TRACE_VALUE_TYPE_CONVERTABLE) {
|
| + base::debug::TraceEvent::TraceValue value;
|
| + value.as_uint = arg_values[i];
|
| + base::debug::TraceEvent::AppendValueAsJSON(arg_types[i],
|
| + value,
|
| + &arg_str_values[i]);
|
| + } else if (enable_flags() & CAPTURE_ALL_ARGUMENTS) {
|
| + convertable_values[i]->AppendAsTraceFormat(&arg_str_values[i]);
|
| + } else {
|
| + continue;
|
| + }
|
| +
|
| + ++real_num_args;
|
| + event.SetField(field_index++, strlen(arg_names[i]) + 1, arg_names[i]);
|
| + event.SetField(field_index++,
|
| + arg_str_values[i].size() + 1,
|
| + arg_str_values[i].c_str());
|
| + }
|
| + }
|
| + bool capture_stack_trace = enable_flags() & CAPTURE_STACK_TRACE;
|
| + event.SetType(GetEtwEventType(type, real_num_args, capture_stack_trace));
|
| +
|
| + // See whether we're to capture a backtrace.
|
| + DWORD depth;
|
| + void* backtrace[32];
|
| + if (capture_stack_trace) {
|
| + DWORD hash = 0;
|
| + depth = CaptureStackBackTrace(0,
|
| + arraysize(backtrace),
|
| + backtrace,
|
| + NULL);
|
| + event.SetField(field_index++, sizeof(depth), &depth);
|
| + event.SetField(field_index++, sizeof(backtrace[0]) * depth, backtrace);
|
| + }
|
| + DCHECK(field_index <= kTraceNumFields)
|
| + << "Maxium number of fields exceeded in ETW event.";
|
| +
|
| + // Trace the event.
|
| + Log(event.get());
|
| +}
|
| +
|
| void TraceEventETWProvider::Trace(const char* name,
|
| size_t name_len,
|
| char type,
|
| @@ -115,6 +325,24 @@ void TraceEventETWProvider::Trace(const char* name,
|
| }
|
| }
|
|
|
| +void TraceEventETWProvider::TraceWithArgs(
|
| + const char* category_group,
|
| + const char* name,
|
| + char type,
|
| + 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) {
|
| + TraceEventETWProvider* provider = TraceEventETWProvider::GetInstance();
|
| + if (provider && provider->IsTracing()) {
|
| + provider->TraceEventWithArgs(category_group, name, type, id,
|
| + num_args, arg_names, arg_types, arg_values,
|
| + convertable_values);
|
| + }
|
| +}
|
| +
|
| void TraceEventETWProvider::Resurrect() {
|
| StaticMemorySingletonTraits<TraceEventETWProvider>::Resurrect();
|
| }
|
|
|