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(); |
} |