processor: Import and export legacy flow event args for all TrackEvents
(Legacy) flow events can be attached to events of any phase, including
those that we import into native (non-raw events) tables in TP.
To preserve them for proto2json conversion, also import the flow-event
related args for slices into their args set and convert them back into
the legacy json event attributes during export_json().
Bug: 130786981, 130786269
Change-Id: I89d5b846009b5ecff350e6b26361576187eee1cd
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 64f6644..e3c5950 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -38,6 +38,26 @@
using IndexMap = perfetto::trace_processor::TraceStorage::Stats::IndexMap;
+const char kLegacyEventArgsKey[] = "legacy_event";
+const char kLegacyEventCategoryKey[] = "category";
+const char kLegacyEventNameKey[] = "name";
+const char kLegacyEventPhaseKey[] = "phase";
+const char kLegacyEventDurationNsKey[] = "duration_ns";
+const char kLegacyEventThreadTimestampNsKey[] = "thread_timestamp_ns";
+const char kLegacyEventThreadDurationNsKey[] = "thread_duration_ns";
+const char kLegacyEventThreadInstructionCountKey[] = "thread_instruction_count";
+const char kLegacyEventThreadInstructionDeltaKey[] = "thread_instruction_delta";
+const char kLegacyEventUseAsyncTtsKey[] = "use_async_tts";
+const char kLegacyEventGlobalIdKey[] = "global_id";
+const char kLegacyEventLocalIdKey[] = "local_id";
+const char kLegacyEventIdScopeKey[] = "id_scope";
+const char kLegacyEventBindIdKey[] = "bind_id";
+const char kLegacyEventBindToEnclosingKey[] = "bind_to_enclosing";
+const char kLegacyEventFlowDirectionKey[] = "flow_direction";
+const char kFlowDirectionValueIn[] = "in";
+const char kFlowDirectionValueOut[] = "out";
+const char kFlowDirectionValueInout[] = "inout";
+
const char* GetNonNullString(const TraceStorage* storage, StringId id) {
return id == kNullStringId ? "" : storage->GetString(id).c_str();
}
@@ -267,6 +287,33 @@
std::vector<Json::Value> args_sets_;
};
+void ConvertLegacyFlowEventArgs(const Json::Value& legacy_args,
+ Json::Value* event) {
+ if (legacy_args.isMember(kLegacyEventIdScopeKey))
+ (*event)["scope"] = legacy_args[kLegacyEventIdScopeKey];
+
+ if (legacy_args.isMember(kLegacyEventBindIdKey)) {
+ (*event)["bind_id"] =
+ PrintUint64(legacy_args[kLegacyEventBindIdKey].asUInt64());
+ }
+
+ if (legacy_args.isMember(kLegacyEventBindToEnclosingKey))
+ (*event)["bp"] = "e";
+
+ if (legacy_args.isMember(kLegacyEventFlowDirectionKey)) {
+ const char* val = legacy_args[kLegacyEventFlowDirectionKey].asCString();
+ if (strcmp(val, kFlowDirectionValueIn) == 0) {
+ (*event)["flow_in"] = true;
+ } else if (strcmp(val, kFlowDirectionValueOut) == 0) {
+ (*event)["flow_out"] = true;
+ } else {
+ PERFETTO_DCHECK(strcmp(val, kFlowDirectionValueInout) == 0);
+ (*event)["flow_in"] = true;
+ (*event)["flow_out"] = true;
+ }
+ }
+}
+
ResultCode ExportThreadNames(const TraceStorage* storage,
TraceFormatWriter* writer) {
for (UniqueTid i = 1; i < storage->thread_count(); ++i) {
@@ -304,7 +351,14 @@
event["pid"] = 0;
const Json::Value& args = args_builder.GetArgs(slices.arg_set_ids()[i]);
if (!args.empty()) {
- event["args"] = args;
+ event["args"] = args; // Makes a copy of |args|.
+
+ if (event["args"].isMember(kLegacyEventArgsKey)) {
+ ConvertLegacyFlowEventArgs(event["args"][kLegacyEventArgsKey], &event);
+
+ if (event["args"].empty())
+ event.removeMember("args");
+ }
}
if (slices.types()[i] == RefType::kRefTrack) { // Async event.
@@ -460,28 +514,6 @@
Json::Value ConvertLegacyRawEventToJson(const TraceStorage* storage,
const ArgsBuilder& args_builder,
uint32_t index) {
- const char kLegacyEventArgsKey[] = "legacy_event";
- const char kLegacyEventCategoryKey[] = "category";
- const char kLegacyEventNameKey[] = "name";
- const char kLegacyEventPhaseKey[] = "phase";
- const char kLegacyEventDurationNsKey[] = "duration_ns";
- const char kLegacyEventThreadTimestampNsKey[] = "thread_timestamp_ns";
- const char kLegacyEventThreadDurationNsKey[] = "thread_duration_ns";
- const char kLegacyEventThreadInstructionCountKey[] =
- "thread_instruction_count";
- const char kLegacyEventThreadInstructionDeltaKey[] =
- "thread_instruction_delta";
- const char kLegacyEventUseAsyncTtsKey[] = "use_async_tts";
- const char kLegacyEventGlobalIdKey[] = "global_id";
- const char kLegacyEventLocalIdKey[] = "local_id";
- const char kLegacyEventIdScopeKey[] = "id_scope";
- const char kLegacyEventBindIdKey[] = "bind_id";
- const char kLegacyEventBindToEnclosingKey[] = "bind_to_enclosing";
- const char kLegacyEventFlowDirectionKey[] = "flow_direction";
- const char kFlowDirectionValueIn[] = "in";
- const char kFlowDirectionValueOut[] = "out";
- const char kFlowDirectionValueInout[] = "inout";
-
const auto& events = storage->raw_events();
Json::Value event;
@@ -495,10 +527,9 @@
}
// Raw legacy events store all other params in the arg set. Make a copy of
- // the converted args here and remove these params.
- Json::Value args = args_builder.GetArgs(events.arg_set_ids()[index]);
- Json::Value legacy_args = args[kLegacyEventArgsKey];
- args.removeMember(kLegacyEventArgsKey);
+ // the converted args here, parse, and then remove the legacy params.
+ event["args"] = args_builder.GetArgs(events.arg_set_ids()[index]);
+ const Json::Value& legacy_args = event["args"][kLegacyEventArgsKey];
PERFETTO_DCHECK(legacy_args.isMember(kLegacyEventCategoryKey));
event["cat"] = legacy_args[kLegacyEventCategoryKey];
@@ -509,9 +540,8 @@
PERFETTO_DCHECK(legacy_args.isMember(kLegacyEventPhaseKey));
event["ph"] = legacy_args[kLegacyEventPhaseKey];
- if (legacy_args.isMember(kLegacyEventDurationNsKey)) {
+ if (legacy_args.isMember(kLegacyEventDurationNsKey))
event["dur"] = legacy_args[kLegacyEventDurationNsKey].asInt64() / 1000;
- }
if (legacy_args.isMember(kLegacyEventThreadTimestampNsKey)) {
event["tts"] =
@@ -523,17 +553,14 @@
legacy_args[kLegacyEventThreadDurationNsKey].asInt64() / 1000;
}
- if (legacy_args.isMember(kLegacyEventThreadInstructionCountKey)) {
+ if (legacy_args.isMember(kLegacyEventThreadInstructionCountKey))
event["ticount"] = legacy_args[kLegacyEventThreadInstructionCountKey];
- }
- if (legacy_args.isMember(kLegacyEventThreadInstructionDeltaKey)) {
+ if (legacy_args.isMember(kLegacyEventThreadInstructionDeltaKey))
event["tidelta"] = legacy_args[kLegacyEventThreadInstructionDeltaKey];
- }
- if (legacy_args.isMember(kLegacyEventUseAsyncTtsKey)) {
+ if (legacy_args.isMember(kLegacyEventUseAsyncTtsKey))
event["use_async_tts"] = legacy_args[kLegacyEventUseAsyncTtsKey];
- }
if (legacy_args.isMember(kLegacyEventGlobalIdKey)) {
event["id2"]["global"] =
@@ -545,35 +572,11 @@
PrintUint64(legacy_args[kLegacyEventLocalIdKey].asUInt64());
}
- if (legacy_args.isMember(kLegacyEventIdScopeKey)) {
- event["scope"] = legacy_args[kLegacyEventIdScopeKey];
- }
+ ConvertLegacyFlowEventArgs(legacy_args, &event);
- if (legacy_args.isMember(kLegacyEventBindIdKey)) {
- event["bind_id"] =
- PrintUint64(legacy_args[kLegacyEventBindIdKey].asUInt64());
- }
-
- if (legacy_args.isMember(kLegacyEventBindToEnclosingKey)) {
- event["bp"] = "e";
- }
-
- if (legacy_args.isMember(kLegacyEventFlowDirectionKey)) {
- const char* val = legacy_args[kLegacyEventFlowDirectionKey].asCString();
- if (strcmp(val, kFlowDirectionValueIn) == 0) {
- event["flow_in"] = true;
- } else if (strcmp(val, kFlowDirectionValueOut) == 0) {
- event["flow_out"] = true;
- } else {
- PERFETTO_DCHECK(strcmp(val, kFlowDirectionValueInout) == 0);
- event["flow_in"] = true;
- event["flow_out"] = true;
- }
- }
-
- if (!args.empty()) {
- event["args"] = args;
- }
+ event["args"].removeMember(kLegacyEventArgsKey);
+ if (event["args"].empty())
+ event.removeMember("args");
return event;
}
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 511f677..d57e856 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -104,6 +104,7 @@
EXPECT_EQ(event["name"].asString(), kName);
EXPECT_FALSE(event.isMember("args"));
}
+
TEST(ExportJsonTest, StorageWithOneUnfinishedSlice) {
const int64_t kTimestamp = 10000000;
const int64_t kDuration = -1;
@@ -381,6 +382,63 @@
EXPECT_EQ(event["args"]["src"].asString(), kSrc);
}
+TEST(ExportJsonTest, StorageWithSliceAndFlowEventArgs) {
+ const char* kCategory = "cat";
+ const char* kName = "name";
+ constexpr TrackId track = 22;
+ const uint64_t kBindId = 0xaa00aa00aa00aa00;
+ const char* kFlowDirection = "inout";
+ const char* kArgName = "arg_name";
+ const int kArgValue = 123;
+
+ TraceProcessorContext context;
+ context.storage.reset(new TraceStorage());
+ TraceStorage* storage = context.storage.get();
+
+ UniqueTid utid = storage->AddEmptyThread(0);
+ StringId cat_id = storage->InternString(base::StringView(kCategory));
+ StringId name_id = storage->InternString(base::StringView(kName));
+ RowId row_id = TraceStorage::CreateRowId(
+ kNestableSlices,
+ storage->mutable_nestable_slices()->AddSlice(
+ 0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0));
+
+ ArgsTracker args(&context);
+ auto add_arg = [&](const char* key, Variadic value) {
+ StringId key_id = storage->InternString(key);
+ args.AddArg(row_id, key_id, key_id, value);
+ };
+
+ add_arg("legacy_event.bind_id", Variadic::UnsignedInteger(kBindId));
+ add_arg("legacy_event.bind_to_enclosing", Variadic::Boolean(true));
+ StringId flow_direction_id = storage->InternString(kFlowDirection);
+ add_arg("legacy_event.flow_direction", Variadic::String(flow_direction_id));
+
+ add_arg(kArgName, Variadic::Integer(kArgValue));
+
+ args.Flush();
+
+ base::TempFile temp_file = base::TempFile::Create();
+ FILE* output = fopen(temp_file.path().c_str(), "w+");
+ int code = ExportJson(storage, output);
+
+ EXPECT_EQ(code, kResultOk);
+
+ Json::Reader reader;
+ Json::Value result;
+ EXPECT_TRUE(reader.parse(ReadFile(output), result));
+ EXPECT_EQ(result["traceEvents"].size(), 1u);
+
+ Json::Value event = result["traceEvents"][0];
+ EXPECT_EQ(event["cat"].asString(), kCategory);
+ EXPECT_EQ(event["name"].asString(), kName);
+ EXPECT_EQ(event["bind_id"].asString(), "0xaa00aa00aa00aa00");
+ EXPECT_EQ(event["bp"].asString(), "e");
+ EXPECT_EQ(event["flow_in"].asBool(), true);
+ EXPECT_EQ(event["flow_out"].asBool(), true);
+ EXPECT_EQ(event["args"][kArgName].asInt(), kArgValue);
+}
+
TEST(ExportJsonTest, StorageWithListArgs) {
const char* kCategory = "cat";
const char* kName = "name";
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index 3ce4ef1..423c798 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -1849,7 +1849,7 @@
}
}
- auto args_callback = [this, &event, &sequence_state,
+ auto args_callback = [this, &event, &legacy_event, &sequence_state,
sequence_state_generation, ts,
utid](ArgsTracker* args_tracker, RowId row_id) {
for (auto it = event.debug_annotations(); it; ++it) {
@@ -1867,6 +1867,42 @@
sequence_state_generation, ts, utid, args_tracker,
row_id);
}
+
+ // TODO(eseckler): Parse legacy flow events into flow events table once we
+ // have a design for it.
+ if (legacy_event.has_bind_id()) {
+ args_tracker->AddArg(row_id, legacy_event_bind_id_key_id_,
+ legacy_event_bind_id_key_id_,
+ Variadic::UnsignedInteger(legacy_event.bind_id()));
+ }
+
+ if (legacy_event.bind_to_enclosing()) {
+ args_tracker->AddArg(row_id, legacy_event_bind_to_enclosing_key_id_,
+ legacy_event_bind_to_enclosing_key_id_,
+ Variadic::Boolean(true));
+ }
+
+ if (legacy_event.flow_direction()) {
+ StringId value;
+ switch (legacy_event.flow_direction()) {
+ case protos::pbzero::TrackEvent::LegacyEvent::FLOW_IN:
+ value = flow_direction_value_in_id_;
+ break;
+ case protos::pbzero::TrackEvent::LegacyEvent::FLOW_OUT:
+ value = flow_direction_value_out_id_;
+ break;
+ case protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT:
+ value = flow_direction_value_inout_id_;
+ break;
+ default:
+ PERFETTO_FATAL("Unknown flow direction: %d",
+ legacy_event.flow_direction());
+ break;
+ }
+ args_tracker->AddArg(row_id, legacy_event_flow_direction_key_id_,
+ legacy_event_flow_direction_key_id_,
+ Variadic::String(value));
+ }
};
switch (static_cast<char>(phase)) {
@@ -2088,8 +2124,6 @@
StringId name_id,
const protos::pbzero::TrackEvent::LegacyEvent::Decoder& legacy_event,
SliceTracker::SetArgsCallback args_callback) {
- using LegacyEvent = protos::pbzero::TrackEvent::LegacyEvent;
-
if (!utid) {
context_->storage->IncrementStats(stats::track_event_parser_errors);
PERFETTO_DLOG("raw legacy event without thread association");
@@ -2167,41 +2201,6 @@
context_->storage->InternString(legacy_event.id_scope())));
}
- // TODO(eseckler): Parse legacy flow events into flow events table once we
- // have a design for it.
- if (legacy_event.has_bind_id()) {
- args.AddArg(row_id, legacy_event_bind_id_key_id_,
- legacy_event_bind_id_key_id_,
- Variadic::UnsignedInteger(legacy_event.bind_id()));
- }
-
- if (legacy_event.bind_to_enclosing()) {
- args.AddArg(row_id, legacy_event_bind_to_enclosing_key_id_,
- legacy_event_bind_to_enclosing_key_id_,
- Variadic::Boolean(true));
- }
-
- if (legacy_event.flow_direction()) {
- StringId value;
- switch (legacy_event.flow_direction()) {
- case LegacyEvent::FLOW_IN:
- value = flow_direction_value_in_id_;
- break;
- case LegacyEvent::FLOW_OUT:
- value = flow_direction_value_out_id_;
- break;
- case LegacyEvent::FLOW_INOUT:
- value = flow_direction_value_inout_id_;
- break;
- default:
- PERFETTO_FATAL("Unknown flow direction: %d",
- legacy_event.flow_direction());
- break;
- }
- args.AddArg(row_id, legacy_event_flow_direction_key_id_,
- legacy_event_flow_direction_key_id_, Variadic::String(value));
- }
-
// No need to parse legacy_event.instant_event_scope() because we import
// instant events into the slice table.
diff --git a/src/trace_processor/proto_trace_parser_unittest.cc b/src/trace_processor/proto_trace_parser_unittest.cc
index f751b8d..9b6c7d5 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -950,6 +950,10 @@
legacy_event->set_duration_us(23); // absolute end: 1028.
legacy_event->set_thread_duration_us(12); // absolute end: 2015.
legacy_event->set_thread_instruction_delta(50); // absolute end: 3060.
+ legacy_event->set_bind_id(9999);
+ legacy_event->set_bind_to_enclosing(true);
+ legacy_event->set_flow_direction(
+ protos::pbzero::TrackEvent::LegacyEvent::FLOW_INOUT);
auto* interned_data = packet->set_interned_data();
auto cat2 = interned_data->add_event_categories();
@@ -991,12 +995,17 @@
InSequence in_sequence; // Below slices should be sorted by timestamp.
+ RowId first_slice_row_id =
+ TraceStorage::CreateRowId(TableId::kNestableSlices, 3u);
EXPECT_CALL(*slice_, Scoped(1005000, thread_1_track, 1, RefType::kRefUtid,
StringId(1), StringId(2), 23000, _))
- .WillOnce(DoAll(
- InvokeArgument<7>(
- &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
- Return(0u)));
+ .WillOnce(
+ DoAll(InvokeArgument<7>(&args, first_slice_row_id), Return(0u)));
+
+ EXPECT_CALL(
+ args, AddArg(first_slice_row_id, _, _, Variadic::UnsignedInteger(9999u)));
+ EXPECT_CALL(args, AddArg(first_slice_row_id, _, _, Variadic::Boolean(true)));
+ EXPECT_CALL(args, AddArg(first_slice_row_id, _, _, _));
EXPECT_CALL(*slice_, Begin(1010000, thread_1_track, 1, RefType::kRefUtid,
StringId(3), StringId(4), _))