summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
Diffstat (limited to 'base')
-rw-r--r--base/debug/trace_event.h130
-rw-r--r--base/debug/trace_event_impl.cc138
-rw-r--r--base/debug/trace_event_impl.h19
-rw-r--r--base/debug/trace_event_unittest.cc40
4 files changed, 284 insertions, 43 deletions
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
index 9f9ec1c..838b2a6d 100644
--- a/base/debug/trace_event.h
+++ b/base/debug/trace_event.h
@@ -123,6 +123,36 @@
// "arg1", std::string("string will be copied"));
//
//
+// Convertable notes:
+// Converting a large data type to a string can be costly. To help with this,
+// the trace framework provides an interface ConvertableToTraceFormat. If you
+// inherit from it and implement the AppendAsTraceFormat method the trace
+// framework will call back to your object to convert a trace output time. This
+// means, if the category for the event is disabled, the conversion will not
+// happen.
+//
+// class MyData : public base::debug::ConvertableToTraceFormat {
+// public:
+// MyData() {}
+// virtual ~MyData() {}
+// virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
+// out->append("{\"foo\":1}");
+// }
+// private:
+// DISALLOW_COPY_AND_ASSIGN(MyData);
+// };
+//
+// scoped_ptr<MyData> data(new MyData());
+// TRACE_EVENT1("foo", "bar", "data",
+// data.PassAs<base::debug::ConvertableToTraceFormat>());
+//
+// The trace framework will take ownership if the passed pointer and it will
+// be free'd when the trace buffer is flushed.
+//
+// Note, we only do the conversion when the buffer is flushed, so the provided
+// data object should not be modified after it's passed to the trace framework.
+//
+//
// Thread Safety:
// A thread safe singleton and mutex are used for thread safety. Category
// enabled flags are used to limit the performance impact when the system
@@ -799,6 +829,7 @@ TRACE_EVENT_API_CLASS_EXPORT extern TRACE_EVENT_API_ATOMIC_WORD g_trace_state2;
#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
+#define TRACE_VALUE_TYPE_CONVERTABLE (static_cast<unsigned char>(8))
// Enum reflecting the scope of an INSTANT event. Must fit within
// TRACE_EVENT_FLAG_SCOPE_MASK.
@@ -906,9 +937,10 @@ class TraceStringWithCopy {
#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
union_member, \
value_type_id) \
- static inline void SetTraceValue(actual_type arg, \
- unsigned char* type, \
- unsigned long long* value) { \
+ static inline void SetTraceValue( \
+ actual_type arg, \
+ unsigned char* type, \
+ unsigned long long* value) { \
TraceValueUnion type_value; \
type_value.union_member = arg; \
*type = value_type_id; \
@@ -917,9 +949,10 @@ class TraceStringWithCopy {
// Simpler form for int types that can be safely casted.
#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
value_type_id) \
- static inline void SetTraceValue(actual_type arg, \
- unsigned char* type, \
- unsigned long long* value) { \
+ static inline void SetTraceValue( \
+ actual_type arg, \
+ unsigned char* type, \
+ unsigned long long* value) { \
*type = value_type_id; \
*value = static_cast<unsigned long long>(arg); \
}
@@ -969,10 +1002,87 @@ static inline void AddTraceEventWithThreadIdAndTimestamp(
unsigned long long id,
int thread_id,
const base::TimeTicks& timestamp,
+ unsigned char flags,
+ const char* arg1_name,
+ scoped_ptr<base::debug::ConvertableToTraceFormat> arg1_val) {
+ const int num_args = 1;
+ unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
+ scoped_ptr<base::debug::ConvertableToTraceFormat> convertable_values[1];
+ convertable_values[0].reset(arg1_val.release());
+
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+ phase, category_enabled, name, id, thread_id, timestamp,
+ num_args, &arg1_name, arg_types, NULL, convertable_values, flags);
+}
+
+static inline void AddTraceEvent(
+ char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags,
+ const char* arg1_name,
+ scoped_ptr<base::debug::ConvertableToTraceFormat> arg1_val) {
+ int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+ AddTraceEventWithThreadIdAndTimestamp(phase, category_enabled, name, id,
+ thread_id, now, flags, arg1_name,
+ arg1_val.Pass());
+}
+
+static inline void AddTraceEventWithThreadIdAndTimestamp(
+ char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int thread_id,
+ const base::TimeTicks& timestamp,
+ unsigned char flags,
+ const char* arg1_name,
+ scoped_ptr<base::debug::ConvertableToTraceFormat> arg1_val,
+ const char* arg2_name,
+ scoped_ptr<base::debug::ConvertableToTraceFormat> arg2_val) {
+ const int num_args = 2;
+ unsigned char arg_types[2] =
+ { TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE };
+ scoped_ptr<base::debug::ConvertableToTraceFormat> convertable_values[2];
+ convertable_values[0].reset(arg1_val.release());
+ convertable_values[1].reset(arg2_val.release());
+
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+ phase, category_enabled, name, id, thread_id, timestamp,
+ num_args, &arg1_name, arg_types, NULL, convertable_values, flags);
+}
+
+static inline void AddTraceEvent(
+ char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned char flags,
+ const char* arg1_name,
+ scoped_ptr<base::debug::ConvertableToTraceFormat> arg1_val,
+ const char* arg2_name,
+ scoped_ptr<base::debug::ConvertableToTraceFormat> arg2_val) {
+ int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+ base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
+ AddTraceEventWithThreadIdAndTimestamp(phase, category_enabled, name, id,
+ thread_id, now, flags,
+ arg1_name, arg1_val.Pass(),
+ arg2_name, arg2_val.Pass());
+}
+
+static inline void AddTraceEventWithThreadIdAndTimestamp(
+ char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int thread_id,
+ const base::TimeTicks& timestamp,
unsigned char flags) {
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
phase, category_enabled, name, id, thread_id, timestamp,
- kZeroNumArgs, NULL, NULL, NULL, flags);
+ kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
}
static inline void AddTraceEvent(char phase,
@@ -1003,7 +1113,7 @@ static inline void AddTraceEventWithThreadIdAndTimestamp(
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
phase, category_enabled, name, id, thread_id, timestamp,
- num_args, &arg1_name, arg_types, arg_values, flags);
+ num_args, &arg1_name, arg_types, arg_values, NULL, flags);
}
template<class ARG1_TYPE>
@@ -1042,7 +1152,7 @@ static inline void AddTraceEventWithThreadIdAndTimestamp(
SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
phase, category_enabled, name, id, thread_id, timestamp,
- num_args, arg_names, arg_types, arg_values, flags);
+ num_args, arg_names, arg_types, arg_values, NULL, flags);
}
template<class ARG1_TYPE, class ARG2_TYPE>
@@ -1088,7 +1198,7 @@ class TRACE_EVENT_API_CLASS_EXPORT TraceEndOnScopeClose {
TRACE_EVENT_PHASE_END,
p_data_->category_enabled,
p_data_->name, kNoEventId,
- kZeroNumArgs, NULL, NULL, NULL,
+ kZeroNumArgs, NULL, NULL, NULL, NULL,
TRACE_EVENT_FLAG_NONE);
}
}
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index 871ac9c..f525d7c 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -264,17 +264,19 @@ TraceEvent::TraceEvent()
memset(arg_values_, 0, sizeof(arg_values_));
}
-TraceEvent::TraceEvent(int thread_id,
- TimeTicks timestamp,
- char phase,
- const unsigned char* category_enabled,
- const char* name,
- unsigned long long id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- unsigned char flags)
+TraceEvent::TraceEvent(
+ int thread_id,
+ TimeTicks timestamp,
+ char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ scoped_ptr<ConvertableToTraceFormat> convertable_values[],
+ unsigned char flags)
: timestamp_(timestamp),
id_(id),
category_enabled_(category_enabled),
@@ -287,12 +289,17 @@ TraceEvent::TraceEvent(int thread_id,
int i = 0;
for (; i < num_args; ++i) {
arg_names_[i] = arg_names[i];
- arg_values_[i].as_uint = arg_values[i];
arg_types_[i] = arg_types[i];
+
+ if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ convertable_values_[i].reset(convertable_values[i].release());
+ else
+ arg_values_[i].as_uint = arg_values[i];
}
for (; i < kTraceMaxNumArgs; ++i) {
arg_names_[i] = NULL;
arg_values_[i].as_uint = 0u;
+ convertable_values_[i].reset();
arg_types_[i] = TRACE_VALUE_TYPE_UINT;
}
@@ -309,6 +316,10 @@ TraceEvent::TraceEvent(int thread_id,
bool arg_is_copy[kTraceMaxNumArgs];
for (i = 0; i < num_args; ++i) {
+ // No copying of convertable types, we retain ownership.
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ continue;
+
// We only take a copy of arg_vals if they are of type COPY_STRING.
arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
if (arg_is_copy[i])
@@ -322,10 +333,15 @@ TraceEvent::TraceEvent(int thread_id,
const char* end = ptr + alloc_size;
if (copy) {
CopyTraceEventParameter(&ptr, &name_, end);
- for (i = 0; i < num_args; ++i)
+ for (i = 0; i < num_args; ++i) {
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ continue;
CopyTraceEventParameter(&ptr, &arg_names_[i], end);
+ }
}
for (i = 0; i < num_args; ++i) {
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ continue;
if (arg_is_copy[i])
CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end);
}
@@ -333,6 +349,58 @@ TraceEvent::TraceEvent(int thread_id,
}
}
+TraceEvent::TraceEvent(const TraceEvent& other)
+ : timestamp_(other.timestamp_),
+ id_(other.id_),
+ category_enabled_(other.category_enabled_),
+ name_(other.name_),
+ thread_id_(other.thread_id_),
+ phase_(other.phase_),
+ flags_(other.flags_) {
+ parameter_copy_storage_ = other.parameter_copy_storage_;
+
+ for (int i = 0; i < kTraceMaxNumArgs; ++i) {
+ arg_values_[i] = other.arg_values_[i];
+ arg_names_[i] = other.arg_names_[i];
+ arg_types_[i] = other.arg_types_[i];
+
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+ convertable_values_[i].reset(
+ const_cast<TraceEvent*>(&other)->convertable_values_[i].release());
+ } else {
+ convertable_values_[i].reset();
+ }
+ }
+}
+
+TraceEvent& TraceEvent::operator=(const TraceEvent& other) {
+ if (this == &other)
+ return *this;
+
+ timestamp_ = other.timestamp_;
+ id_ = other.id_;
+ category_enabled_ = other.category_enabled_;
+ name_ = other.name_;
+ parameter_copy_storage_ = other.parameter_copy_storage_;
+ thread_id_ = other.thread_id_;
+ phase_ = other.phase_;
+ flags_ = other.flags_;
+
+ for (int i = 0; i < kTraceMaxNumArgs; ++i) {
+ arg_values_[i] = other.arg_values_[i];
+ arg_names_[i] = other.arg_names_[i];
+ arg_types_[i] = other.arg_types_[i];
+
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+ convertable_values_[i].reset(
+ const_cast<TraceEvent*>(&other)->convertable_values_[i].release());
+ } else {
+ convertable_values_[i].reset();
+ }
+ }
+ return *this;
+}
+
TraceEvent::~TraceEvent() {
}
@@ -403,7 +471,11 @@ void TraceEvent::AppendAsJSON(std::string* out) const {
*out += "\"";
*out += arg_names_[i];
*out += "\":";
- AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ convertable_values_[i]->AppendAsTraceFormat(out);
+ else
+ AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
}
*out += "}";
@@ -565,13 +637,7 @@ void TraceSamplingThread::DefaultSampleCallback(TraceBucketData* bucket_data) {
ExtractCategoryAndName(combined, &category, &name);
TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_SAMPLE,
TraceLog::GetCategoryEnabled(category),
- name,
- 0,
- 0,
- NULL,
- NULL,
- NULL,
- 0);
+ name, 0, 0, NULL, NULL, NULL, NULL, 0);
}
void TraceSamplingThread::GetSamples() {
@@ -1014,20 +1080,23 @@ void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
}
}
-void TraceLog::AddTraceEvent(char phase,
- const unsigned char* category_enabled,
- const char* name,
- unsigned long long id,
- int num_args,
- const char** arg_names,
- const unsigned char* arg_types,
- const unsigned long long* arg_values,
- unsigned char flags) {
+void TraceLog::AddTraceEvent(
+ char phase,
+ const unsigned char* category_enabled,
+ const char* name,
+ unsigned long long id,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ scoped_ptr<ConvertableToTraceFormat> convertable_values[],
+ unsigned char flags) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
base::TimeTicks now = base::TimeTicks::NowFromSystemTraceTime();
AddTraceEventWithThreadIdAndTimestamp(phase, category_enabled, name, id,
thread_id, now, num_args, arg_names,
- arg_types, arg_values, flags);
+ arg_types, arg_values,
+ convertable_values, flags);
}
void TraceLog::AddTraceEventWithThreadIdAndTimestamp(
@@ -1041,6 +1110,7 @@ void TraceLog::AddTraceEventWithThreadIdAndTimestamp(
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
+ scoped_ptr<ConvertableToTraceFormat> convertable_values[],
unsigned char flags) {
DCHECK(name);
@@ -1097,7 +1167,7 @@ void TraceLog::AddTraceEventWithThreadIdAndTimestamp(
logged_events_->AddEvent(TraceEvent(thread_id,
now, phase, category_enabled, name, id,
num_args, arg_names, arg_types, arg_values,
- flags));
+ convertable_values, flags));
if (logged_events_->IsFull())
notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL);
@@ -1184,7 +1254,7 @@ void TraceLog::AddThreadNameMetadataEvents() {
TimeTicks(), TRACE_EVENT_PHASE_METADATA,
&g_category_enabled[g_category_metadata],
"thread_name", trace_event_internal::kNoEventId,
- num_args, &arg_name, &arg_type, &arg_value,
+ num_args, &arg_name, &arg_type, &arg_value, NULL,
TRACE_EVENT_FLAG_NONE));
}
}
@@ -1244,6 +1314,7 @@ ScopedTrace::ScopedTrace(
NULL, // arg_names
NULL, // arg_types
NULL, // arg_values
+ NULL, // convertable_values
TRACE_EVENT_FLAG_NONE); // flags
} else {
category_enabled_ = NULL;
@@ -1261,6 +1332,7 @@ ScopedTrace::~ScopedTrace() {
NULL, // arg_names
NULL, // arg_types
NULL, // arg_values
+ NULL, // convertable values
TRACE_EVENT_FLAG_NONE); // flags
}
}
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index 7652419..d9f8f1c 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -46,6 +46,19 @@ class WaitableEvent;
namespace debug {
+// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
+// class must implement this interface.
+class ConvertableToTraceFormat {
+ public:
+ virtual ~ConvertableToTraceFormat() {}
+
+ // Append the class info to the provided |out| string. The appended
+ // data must be a valid JSON object. Strings must be propertly quoted, and
+ // escaped. There is no processing applied to the content after it is
+ // appended.
+ virtual void AppendAsTraceFormat(std::string* out) const = 0;
+};
+
const int kTraceMaxNumArgs = 2;
// Output records are "Events" and can be obtained via the
@@ -74,7 +87,10 @@ class BASE_EXPORT TraceEvent {
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
+ scoped_ptr<ConvertableToTraceFormat> convertable_values[],
unsigned char flags);
+ TraceEvent(const TraceEvent& other);
+ TraceEvent& operator=(const TraceEvent& other);
~TraceEvent();
// Serialize event data to JSON
@@ -106,6 +122,7 @@ class BASE_EXPORT TraceEvent {
unsigned long long id_;
TraceValue arg_values_[kTraceMaxNumArgs];
const char* arg_names_[kTraceMaxNumArgs];
+ scoped_ptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
const unsigned char* category_enabled_;
const char* name_;
scoped_refptr<base::RefCountedString> parameter_copy_storage_;
@@ -318,6 +335,7 @@ class BASE_EXPORT TraceLog {
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
+ scoped_ptr<ConvertableToTraceFormat> convertable_values[],
unsigned char flags);
void AddTraceEventWithThreadIdAndTimestamp(
char phase,
@@ -330,6 +348,7 @@ class BASE_EXPORT TraceLog {
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
+ scoped_ptr<ConvertableToTraceFormat> convertable_values[],
unsigned char flags);
static void AddTraceEventEtw(char phase,
const char* name,
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 782f07b..c682216 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -1591,6 +1591,46 @@ TEST_F(TraceEventTestFixture, TraceSampling) {
EXPECT_TRUE(FindNamePhase("Things", "P"));
}
+class MyData : public base::debug::ConvertableToTraceFormat {
+ public:
+ MyData() {}
+ virtual ~MyData() {}
+
+ virtual void AppendAsTraceFormat(std::string* out) const OVERRIDE {
+ out->append("{\"foo\":1}");
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MyData);
+};
+
+TEST_F(TraceEventTestFixture, ConvertableTypes) {
+ ManualTestSetUp();
+ TraceLog::GetInstance()->SetEnabled(true, TraceLog::RECORD_UNTIL_FULL);
+
+ scoped_ptr<MyData> data(new MyData());
+ TRACE_EVENT1("foo", "bar", "data",
+ data.PassAs<base::debug::ConvertableToTraceFormat>());
+ EndTraceAndFlush();
+
+ DictionaryValue* dict = FindNamePhase("bar", "B");
+ ASSERT_TRUE(dict);
+
+ const DictionaryValue* args_dict = NULL;
+ dict->GetDictionary("args", &args_dict);
+ ASSERT_TRUE(args_dict);
+
+ const Value* value = NULL;
+ const DictionaryValue* convertable_dict = NULL;
+ EXPECT_TRUE(args_dict->Get("data", &value));
+ ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+ int foo_val;
+ EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+ EXPECT_EQ(1, foo_val);
+}
+
+
class TraceEventCallbackTest : public TraceEventTestFixture {
public:
virtual void SetUp() OVERRIDE {