[VM/Timeline] Store an array of flow IDs in each dart::TimelineEvent
instead of just one ID
Sometimes the Flutter Engine is associating events with multiple flows,
this change is needed to allow events to be associated with multiple
flows in a Perfetto-format trace.
TEST=Checked the flow events reported through dart:developer still
looked correct when retrieved in Perfetto traces.
Change-Id: I2901ffde5e8b984abb1e924e014722bb0568f6d3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/305801
Reviewed-by: Ben Konyi <bkonyi@google.com>
Commit-Queue: Derek Xu <derekx@google.com>
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index 64e63d6..4592e50 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -55,8 +55,16 @@
return Object::null();
}
+ std::unique_ptr<const int64_t[]> flow_ids;
+ if (flow_id.AsInt64Value() != TimelineEvent::kNoFlowId) {
+ int64_t* flow_ids_internal = new int64_t[1];
+ flow_ids_internal[0] = flow_id.AsInt64Value();
+ flow_ids = std::unique_ptr<const int64_t[]>(flow_ids_internal);
+ }
+ intptr_t flow_id_count =
+ flow_id.AsInt64Value() == TimelineEvent::kNoFlowId ? 0 : 1;
DartTimelineEventHelpers::ReportTaskEvent(
- event, id.AsInt64Value(), flow_id.AsInt64Value(), type.Value(),
+ event, id.AsInt64Value(), flow_id_count, flow_ids, type.Value(),
name.ToMallocCString(), args.ToMallocCString());
#endif // SUPPORT_TIMELINE
return Object::null();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 55b98e9..7c42f26 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -6443,8 +6443,7 @@
// TODO(derekx): Dart_TimelineEvent() needs to be updated so that arrows
// corresponding to flow events reported by embedders get included in
// Perfetto traces.
- event->Begin(label, timestamp1_or_async_id,
- /*flow_id=*/TimelineEvent::kNoFlowId, timestamp0);
+ event->Begin(label, timestamp1_or_async_id, timestamp0);
break;
case Dart_Timeline_Event_End:
event->End(label, timestamp1_or_async_id, timestamp0);
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 94da8fc..1f63bef 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -505,7 +505,8 @@
TimelineEvent::TimelineEvent()
: timestamp0_(0),
timestamp1_(0),
- flow_id_(TimelineEvent::kNoFlowId),
+ flow_id_count_(0),
+ flow_ids_(),
state_(0),
label_(nullptr),
stream_(nullptr),
@@ -585,14 +586,12 @@
void TimelineEvent::Begin(const char* label,
int64_t id,
- int64_t flow_id,
int64_t micros) {
Init(kBegin, label);
set_timestamp0(micros);
// Overload timestamp1_ with the task id. This is required for the MacOS
// recorder to work.
set_timestamp1(id);
- set_flow_id(flow_id);
}
void TimelineEvent::End(const char* label, int64_t id, int64_t micros) {
@@ -670,7 +669,8 @@
state_ = 0;
timestamp0_ = 0;
timestamp1_ = 0;
- flow_id_ = TimelineEvent::kNoFlowId;
+ flow_id_count_ = 0;
+ flow_ids_.reset();
OSThread* os_thread = OSThread::Current();
ASSERT(os_thread != nullptr);
thread_ = os_thread->trace_id();
@@ -841,12 +841,12 @@
AddBeginAndInstantEventCommonFields(track_event, event);
track_event->set_type(
perfetto::protos::pbzero::TrackEvent::Type::TYPE_SLICE_BEGIN);
- if (event.HasFlowId()) {
+ for (intptr_t i = 0; i < event.flow_id_count(); ++i) {
// TODO(derekx): |TrackEvent|s have a |terminating_flow_ids| field that we
// aren't able to populate right now because we aren't keeping track of
// terminating flow IDs in |TimelineEvent|. I'm not even sure if using that
// field will provide any benefit though.
- track_event->add_flow_ids(event.flow_id());
+ track_event->add_flow_ids(event.FlowIds()[i]);
}
}
@@ -985,10 +985,6 @@
return timestamp1_ - timestamp0_;
}
-bool TimelineEvent::HasFlowId() const {
- return flow_id_ != TimelineEvent::kNoFlowId;
-}
-
bool TimelineEvent::HasIsolateId() const {
return isolate_id_ != ILLEGAL_ISOLATE_ID;
}
@@ -1240,7 +1236,7 @@
}
ASSERT(event != nullptr);
// Emit a begin event.
- event->Begin(label(), id(), /*flow_id=*/TimelineEvent::kNoFlowId);
+ event->Begin(label(), id());
event->Complete();
}
@@ -2416,12 +2412,14 @@
#endif
}
-void DartTimelineEventHelpers::ReportTaskEvent(TimelineEvent* event,
- int64_t id,
- int64_t flow_id,
- intptr_t type,
- char* name,
- char* args) {
+void DartTimelineEventHelpers::ReportTaskEvent(
+ TimelineEvent* event,
+ int64_t id,
+ intptr_t flow_id_count,
+ std::unique_ptr<const int64_t[]>& flow_ids,
+ intptr_t type,
+ char* name,
+ char* args) {
const int64_t start = OS::GetCurrentMonotonicMicrosForTimeline();
switch (static_cast<TimelineEvent::EventType>(type)) {
case TimelineEvent::kAsyncInstant:
@@ -2434,7 +2432,7 @@
event->AsyncEnd(name, id, start);
break;
case TimelineEvent::kBegin:
- event->Begin(name, id, flow_id, start);
+ event->Begin(name, id, start);
break;
case TimelineEvent::kEnd:
event->End(name, id, start);
@@ -2454,6 +2452,14 @@
default:
UNREACHABLE();
}
+ if (flow_id_count > 0) {
+ ASSERT(type == Dart_Timeline_Event_Begin ||
+ type == Dart_Timeline_Event_Instant ||
+ type == Dart_Timeline_Event_Async_Begin ||
+ type == Dart_Timeline_Event_Async_Instant);
+
+ event->SetFlowIds(flow_id_count, flow_ids);
+ }
event->set_owns_label(true);
event->CompleteWithPreSerializedArgs(args);
}
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 7bb39f5..6650599 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -373,7 +373,6 @@
void Begin(const char* label,
int64_t id,
- int64_t flow_id,
int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
void End(const char* label,
@@ -441,8 +440,13 @@
int64_t timestamp0() const { return timestamp0_; }
int64_t timestamp1() const { return timestamp1_; }
- bool HasFlowId() const;
- int64_t flow_id() const { return flow_id_; }
+ void SetFlowIds(intptr_t flow_id_count,
+ std::unique_ptr<const int64_t[]>& flow_ids) {
+ flow_id_count_ = flow_id_count;
+ flow_ids_.swap(flow_ids);
+ }
+ intptr_t flow_id_count() const { return flow_id_count_; }
+ const int64_t* FlowIds() const { return flow_ids_.get(); }
bool HasIsolateId() const;
bool HasIsolateGroupId() const;
@@ -563,11 +567,6 @@
timestamp1_ = value;
}
- void set_flow_id(int64_t flow_id) {
- ASSERT(flow_id_ == TimelineEvent::kNoFlowId);
- flow_id_ = flow_id;
- }
-
void set_pre_serialized_args(bool pre_serialized_args) {
state_ = PreSerializedArgsBit::update(pre_serialized_args, state_);
}
@@ -588,12 +587,13 @@
int64_t timestamp0_;
int64_t timestamp1_;
+ intptr_t flow_id_count_;
// This field is only used by the Perfetto recorders, because Perfetto's trace
// format handles flow events by processing flow IDs attached to
// |TimelineEvent::kBegin| events. Other recorders handle flow events by
// processing events of type TimelineEvent::kFlowBegin|,
// |TimelineEvent::kFlowStep|, and |TimelineEvent::kFlowEnd|.
- int64_t flow_id_;
+ std::unique_ptr<const int64_t[]> flow_ids_;
TimelineEventArguments arguments_;
uword state_;
const char* label_;
@@ -1293,7 +1293,8 @@
public:
static void ReportTaskEvent(TimelineEvent* event,
int64_t id,
- int64_t flow_id,
+ intptr_t flow_id_count,
+ std::unique_ptr<const int64_t[]>& flow_ids,
intptr_t type,
char* name,
char* args);
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 828775c..1050073 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -85,7 +85,7 @@
ASSERT(start >= 0);
TimelineEvent* event = recorder->StartEvent();
ASSERT(event != nullptr);
- event->Begin(label, /*id=*/-1, /*flow_id=*/TimelineEvent::kNoFlowId, start);
+ event->Begin(label, /*id=*/-1, start);
event->Complete();
}