processor: Export thread instruction counts to JSON
Adds support for exporting thread instruction counts from imported
TrackEvent traces.
Bug: 130786269
Change-Id: I5367af57632e1efbb5951a5dccb59b340b5d4ad6
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 1cc5b27..ba505c3 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -284,6 +284,8 @@
const auto& virtual_track_slices = storage->virtual_track_slices();
int64_t thread_ts_ns = 0;
int64_t thread_duration_ns = 0;
+ int64_t thread_instruction_count = 0;
+ int64_t thread_instruction_delta = 0;
base::Optional<uint32_t> vtrack_slice_row =
virtual_track_slices.FindRowForSliceId(i);
if (vtrack_slice_row) {
@@ -291,12 +293,22 @@
virtual_track_slices.thread_timestamp_ns()[*vtrack_slice_row];
thread_duration_ns =
virtual_track_slices.thread_duration_ns()[*vtrack_slice_row];
+ thread_ts_ns =
+ virtual_track_slices.thread_timestamp_ns()[*vtrack_slice_row];
+ thread_instruction_count =
+ virtual_track_slices.thread_instruction_counts()[*vtrack_slice_row];
+ thread_instruction_delta =
+ virtual_track_slices.thread_instruction_deltas()[*vtrack_slice_row];
}
if (thread_ts_ns > 0) {
event["tts"] = Json::Int64(thread_ts_ns / 1000);
event["use_async_tts"] = Json::Int(1);
}
+ if (thread_instruction_count > 0) {
+ event["ticount"] = Json::Int64(thread_instruction_count);
+ event["use_async_tts"] = Json::Int(1);
+ }
int64_t duration_ns = slices.durations()[i];
if (duration_ns == 0) { // Instant async event.
@@ -315,6 +327,10 @@
event["tts"] =
Json::Int64((thread_ts_ns + thread_duration_ns) / 1000);
}
+ if (thread_instruction_count > 0) {
+ event["ticount"] = Json::Int64(
+ (thread_instruction_count + thread_instruction_delta));
+ }
event.removeMember("args");
writer->WriteCommonEvent(event);
}
@@ -323,12 +339,18 @@
const auto& thread_slices = storage->thread_slices();
int64_t thread_ts_ns = 0;
int64_t thread_duration_ns = 0;
+ int64_t thread_instruction_count = 0;
+ int64_t thread_instruction_delta = 0;
base::Optional<uint32_t> thread_slice_row =
thread_slices.FindRowForSliceId(i);
if (thread_slice_row) {
thread_ts_ns = thread_slices.thread_timestamp_ns()[*thread_slice_row];
thread_duration_ns =
thread_slices.thread_duration_ns()[*thread_slice_row];
+ thread_instruction_count =
+ thread_slices.thread_instruction_counts()[*thread_slice_row];
+ thread_instruction_delta =
+ thread_slices.thread_instruction_deltas()[*thread_slice_row];
}
int64_t duration_ns = slices.durations()[i];
if (duration_ns == 0) { // Instant event.
@@ -342,6 +364,9 @@
if (thread_ts_ns > 0) {
event["tts"] = Json::Int64(thread_ts_ns / 1000);
}
+ if (thread_instruction_count > 0) {
+ event["ticount"] = Json::Int64(thread_instruction_count);
+ }
event["tid"] = thread.tid;
event["s"] = "t";
} else if (slices.types()[i] == RefType::kRefUpid) {
@@ -374,10 +399,16 @@
}
if (thread_ts_ns > 0) {
event["tts"] = Json::Int64(thread_ts_ns / 1000);
- // Only write duration for complete events.
+ // Only write thread duration for completed events.
if (duration_ns > 0)
event["tdur"] = Json::Int64(thread_duration_ns / 1000);
}
+ if (thread_instruction_count > 0) {
+ event["ticount"] = Json::Int64(thread_instruction_count);
+ // Only write thread instruction delta for completed events.
+ if (duration_ns > 0)
+ event["tidelta"] = Json::Int64(thread_instruction_delta);
+ }
writer->WriteCommonEvent(event);
}
}
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index e79e722..fef2f3f 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -61,6 +61,8 @@
const int64_t kDuration = 10000;
const int64_t kThreadTimestamp = 20000000;
const int64_t kThreadDuration = 20000;
+ const int64_t kThreadInstructionCount = 30000000;
+ const int64_t kThreadInstructionDelta = 30000;
const int64_t kThreadID = 100;
const char* kCategory = "cat";
const char* kName = "name";
@@ -71,8 +73,9 @@
StringId name_id = storage.InternString(base::StringView(kName));
storage.mutable_nestable_slices()->AddSlice(
kTimestamp, kDuration, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
- storage.mutable_thread_slices()->AddThreadSlice(0, kThreadTimestamp,
- kThreadDuration, 0, 0);
+ storage.mutable_thread_slices()->AddThreadSlice(
+ 0, kThreadTimestamp, kThreadDuration, kThreadInstructionCount,
+ kThreadInstructionDelta);
base::TempFile temp_file = base::TempFile::Create();
FILE* output = fopen(temp_file.path().c_str(), "w+");
@@ -91,6 +94,8 @@
EXPECT_EQ(event["dur"].asInt64(), kDuration / 1000);
EXPECT_EQ(event["tts"].asInt64(), kThreadTimestamp / 1000);
EXPECT_EQ(event["tdur"].asInt64(), kThreadDuration / 1000);
+ EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
+ EXPECT_EQ(event["tidelta"].asInt64(), kThreadInstructionDelta);
EXPECT_EQ(event["tid"].asUInt(), kThreadID);
EXPECT_EQ(event["cat"].asString(), kCategory);
EXPECT_EQ(event["name"].asString(), kName);
@@ -101,6 +106,8 @@
const int64_t kDuration = -1;
const int64_t kThreadTimestamp = 20000000;
const int64_t kThreadDuration = -1;
+ const int64_t kThreadInstructionCount = 30000000;
+ const int64_t kThreadInstructionDelta = -1;
const int64_t kThreadID = 100;
const char* kCategory = "cat";
const char* kName = "name";
@@ -111,8 +118,9 @@
StringId name_id = storage.InternString(base::StringView(kName));
storage.mutable_nestable_slices()->AddSlice(
kTimestamp, kDuration, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
- storage.mutable_thread_slices()->AddThreadSlice(0, kThreadTimestamp,
- kThreadDuration, 0, 0);
+ storage.mutable_thread_slices()->AddThreadSlice(
+ 0, kThreadTimestamp, kThreadDuration, kThreadInstructionCount,
+ kThreadInstructionDelta);
base::TempFile temp_file = base::TempFile::Create();
FILE* output = fopen(temp_file.path().c_str(), "w+");
@@ -131,6 +139,8 @@
EXPECT_FALSE(event.isMember("dur"));
EXPECT_EQ(event["tts"].asInt64(), kThreadTimestamp / 1000);
EXPECT_FALSE(event.isMember("tdur"));
+ EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
+ EXPECT_FALSE(event.isMember("tidelta"));
EXPECT_EQ(event["tid"].asUInt(), kThreadID);
EXPECT_EQ(event["cat"].asString(), kCategory);
EXPECT_EQ(event["name"].asString(), kName);