6#if defined(SUPPORT_TIMELINE)
30#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
31#include "perfetto/ext/tracing/core/trace_packet.h"
46#define DEFAULT_TIMELINE_RECORDER "none"
47#define SUPPORTED_TIMELINE_RECORDERS "systrace, file, callback"
49#define DEFAULT_TIMELINE_RECORDER "ring"
50#if defined(SUPPORT_PERFETTO)
51#define SUPPORTED_TIMELINE_RECORDERS \
52 "ring, endless, startup, systrace, file, callback, perfettofile"
54#define SUPPORTED_TIMELINE_RECORDERS \
55 "ring, endless, startup, systrace, file, callback"
59DEFINE_FLAG(
bool, complete_timeline,
false,
"Record the complete timeline");
60DEFINE_FLAG(
bool, startup_timeline,
false,
"Record the startup timeline");
66 "Record the timeline to the platform's tracing service if there is one");
67DEFINE_FLAG(
bool, trace_timeline,
false,
"Trace timeline backend");
71 "Enable all timeline trace streams and output VM global trace "
72 "into specified directory. This flag is ignored by the file and "
73 "perfetto recorders.");
77 "Comma separated list of timeline streams to record. "
78 "Valid values: all, API, Compiler, CompilerVerbose, Dart, "
79 "Debugger, Embedder, GC, Isolate, and VM.");
82 DEFAULT_TIMELINE_RECORDER,
83 "Select the timeline recorder used. "
84 "Valid values: none, " SUPPORTED_TIMELINE_RECORDERS)
130std::atomic<RecorderSynchronizationLock::RecorderState>
131 RecorderSynchronizationLock::recorder_state_ = {
132 RecorderSynchronizationLock::kUninitialized};
133std::atomic<intptr_t> RecorderSynchronizationLock::outstanding_event_writes_ = {
136static TimelineEventRecorder* CreateDefaultTimelineRecorder() {
138 return new TimelineEventNopRecorder();
140 return new TimelineEventRingRecorder();
144static TimelineEventRecorder* CreateTimelineRecorder() {
145 ASSERT(FLAG_timeline_recorder !=
nullptr);
146 const char*
flag = FLAG_timeline_recorder;
148 if (FLAG_systrace_timeline) {
150 "Warning: the --systrace-timeline flag is deprecated and will "
151 "be removed in Dart SDK v3.4. Please use --timeline-recorder=systrace "
154 }
else if (FLAG_timeline_dir !=
nullptr || FLAG_complete_timeline) {
157 }
else if (FLAG_startup_timeline) {
161 if (strcmp(
"none",
flag) == 0) {
162 return new TimelineEventNopRecorder();
166 if (strcmp(
"systrace",
flag) == 0) {
167#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
168 return new TimelineEventSystraceRecorder();
169#elif defined(DART_HOST_OS_MACOS)
170 return new TimelineEventMacosRecorder();
171#elif defined(DART_HOST_OS_FUCHSIA)
172 return new TimelineEventFuchsiaRecorder();
179 (
flag[4] ==
'\0' ||
flag[4] ==
':' ||
flag[4] ==
'=')) {
180 const char* filename =
flag[4] ==
'\0' ?
"dart-timeline.json" : &
flag[5];
181 free(
const_cast<char*
>(FLAG_timeline_dir));
182 FLAG_timeline_dir =
nullptr;
183 return new TimelineEventFileRecorder(filename);
186 if (strcmp(
"callback",
flag) == 0) {
187 return new TimelineEventEmbedderCallbackRecorder();
191#if defined(SUPPORT_PERFETTO)
195 const intptr_t kPrefixLength = 12;
197 (
flag[kPrefixLength] ==
'\0' ||
flag[kPrefixLength] ==
':' ||
198 flag[kPrefixLength] ==
'=')) {
199 const char* filename =
flag[kPrefixLength] ==
'\0'
200 ?
"dart.perfetto-trace"
201 : &
flag[kPrefixLength + 1];
202 free(
const_cast<char*
>(FLAG_timeline_dir));
203 FLAG_timeline_dir =
nullptr;
204 return new TimelineEventPerfettoFileRecorder(filename);
211 if (strcmp(
"endless",
flag) == 0) {
212 return new TimelineEventEndlessRecorder();
215 if (strcmp(
"startup",
flag) == 0) {
216 return new TimelineEventStartupRecorder();
219 if (strcmp(
"ring",
flag) == 0) {
220 return new TimelineEventRingRecorder();
224 if (strlen(
flag) > 0 && strcmp(
flag, DEFAULT_TIMELINE_RECORDER) != 0) {
226 "Warning: requested %s timeline recorder which is not supported, "
227 "defaulting to the " DEFAULT_TIMELINE_RECORDER
" recorder\n",
231 return CreateDefaultTimelineRecorder();
235static MallocGrowableArray<char*>* GetEnabledByDefaultTimelineStreams() {
236 MallocGrowableArray<char*>*
result =
new MallocGrowableArray<char*>();
237 if (FLAG_timeline_streams ==
nullptr) {
244 char* token = strtok_r(streams,
",", &save_ptr);
245 while (token !=
nullptr) {
247 token = strtok_r(
nullptr,
",", &save_ptr);
254static void FreeEnabledByDefaultTimelineStreams(
255 MallocGrowableArray<char*>* streams) {
256 if (streams ==
nullptr) {
259 for (intptr_t
i = 0;
i < streams->length();
i++) {
266static bool HasStream(MallocGrowableArray<char*>* streams,
const char*
stream) {
267 if ((FLAG_timeline_dir !=
nullptr) || FLAG_complete_timeline ||
268 FLAG_startup_timeline) {
271 for (intptr_t
i = 0;
i < streams->length();
i++) {
272 const char* checked_stream = (*streams)[
i];
273 if ((strstr(checked_stream,
"all") !=
nullptr) ||
274 (strstr(checked_stream,
stream) !=
nullptr)) {
282 ASSERT(recorder_ ==
nullptr);
283 recorder_ = CreateTimelineRecorder();
290 while (it.HasNext()) {
291 OSThread& thread = *it.Next();
292 recorder_->AddTrackMetadataBasedOnThread(
296 if (FLAG_trace_timeline) {
297 OS::PrintErr(
"Using the %s timeline recorder.\n", recorder_->name());
299 ASSERT(recorder_ !=
nullptr);
300 enabled_streams_ = GetEnabledByDefaultTimelineStreams();
302#define TIMELINE_STREAM_FLAG_DEFAULT(name, ...) \
303 stream_##name##_.set_enabled(HasStream(enabled_streams_, #name));
304 TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAG_DEFAULT)
305#undef TIMELINE_STREAM_FLAG_DEFAULT
309 ASSERT(recorder_ !=
nullptr);
312 if (FLAG_timeline_dir !=
nullptr) {
313 recorder_->WriteTo(FLAG_timeline_dir);
318#define TIMELINE_STREAM_DISABLE(name, ...) \
319 Timeline::stream_##name##_.set_enabled(false);
320 TIMELINE_STREAM_LIST(TIMELINE_STREAM_DISABLE)
321#undef TIMELINE_STREAM_DISABLE
322 RecorderSynchronizationLock::WaitForShutdown();
326 if (enabled_streams_ !=
nullptr) {
327 FreeEnabledByDefaultTimelineStreams(enabled_streams_);
328 enabled_streams_ =
nullptr;
332void Timeline::ReclaimCachedBlocksFromThreads() {
333 RecorderSynchronizationLockScope ls;
334 TimelineEventRecorder* recorder = Timeline::recorder();
335 if (recorder ==
nullptr || ls.IsUninitialized()) {
338 ASSERT(recorder !=
nullptr);
341 while (it.HasNext()) {
342 OSThread* thread = it.Next();
343 MutexLocker ml(thread->timeline_block_lock());
345 TimelineEventBlock* block = thread->TimelineBlockLocked();
346 thread->SetTimelineBlockLocked(
nullptr);
347 recorder->FinishBlock(block);
352void Timeline::PrintFlagsToJSONArray(JSONArray* arr) {
353#define ADD_RECORDED_STREAM_NAME(name, ...) \
354 if (stream_##name##_.enabled()) { \
355 arr->AddValue(#name); \
357 TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME);
358#undef ADD_RECORDED_STREAM_NAME
361void Timeline::PrintFlagsToJSON(JSONStream*
js) {
363 obj.AddProperty(
"type",
"TimelineFlags");
364 RecorderSynchronizationLockScope ls;
365 TimelineEventRecorder* recorder = Timeline::recorder();
366 if (recorder ==
nullptr || !ls.IsActive()) {
367 obj.AddProperty(
"recorderName",
"null");
369 obj.AddProperty(
"recorderName", recorder->name());
372 JSONArray availableStreams(&obj,
"availableStreams");
373#define ADD_STREAM_NAME(name, ...) availableStreams.AddValue(#name);
374 TIMELINE_STREAM_LIST(ADD_STREAM_NAME);
375#undef ADD_STREAM_NAME
378 JSONArray recordedStreams(&obj,
"recordedStreams");
379#define ADD_RECORDED_STREAM_NAME(name, ...) \
380 if (stream_##name##_.enabled()) { \
381 recordedStreams.AddValue(#name); \
383 TIMELINE_STREAM_LIST(ADD_RECORDED_STREAM_NAME);
384#undef ADD_RECORDED_STREAM_NAME
389void Timeline::Clear() {
390 RecorderSynchronizationLockScope ls;
391 TimelineEventRecorder* recorder = Timeline::recorder();
392 if (recorder ==
nullptr || ls.IsUninitialized()) {
395 ASSERT(recorder !=
nullptr);
398 MutexLocker ml(&recorder->lock_);
399 ReclaimCachedBlocksFromThreads();
400 recorder->ClearLocked();
403void TimelineEventArguments::SetNumArguments(intptr_t
length) {
411 if (buffer_ ==
nullptr) {
413 buffer_ =
reinterpret_cast<TimelineEventArgument*
>(
416 for (intptr_t
i =
length;
i < length_; ++
i) {
419 buffer_ =
reinterpret_cast<TimelineEventArgument*
>(
422 memset(buffer_ + length_, 0,
423 sizeof(TimelineEventArgument) * (
length - length_));
429void TimelineEventArguments::SetArgument(intptr_t
i,
434 buffer_[
i].name =
name;
435 buffer_[
i].value = argument;
438void TimelineEventArguments::CopyArgument(intptr_t
i,
440 const char* argument) {
444void TimelineEventArguments::FormatArgument(intptr_t
i,
450 va_list measure_args;
451 va_copy(measure_args,
args);
457 va_copy(print_args,
args);
464void TimelineEventArguments::StealArguments(TimelineEventArguments* arguments) {
466 length_ = arguments->length_;
467 buffer_ = arguments->buffer_;
468 arguments->length_ = 0;
469 arguments->buffer_ =
nullptr;
473 if (buffer_ ==
nullptr) {
476 for (intptr_t
i = 0;
i < length_;
i++) {
484TimelineEventRecorder* Timeline::recorder_ =
nullptr;
486MallocGrowableArray<char*>* Timeline::enabled_streams_ =
nullptr;
487bool Timeline::recorder_discards_clock_values_ =
false;
489#define TIMELINE_STREAM_DEFINE(name, fuchsia_name, static_labels) \
490 TimelineStream Timeline::stream_##name##_(#name, fuchsia_name, \
491 static_labels, false);
492TIMELINE_STREAM_LIST(TIMELINE_STREAM_DEFINE)
493#undef TIMELINE_STREAM_DEFINE
495TimelineEvent::TimelineEvent()
497 timestamp1_or_id_(0),
503 thread_(OSThread::kInvalidThreadId),
507TimelineEvent::~TimelineEvent() {
513 timestamp1_or_id_ = 0;
516 if (owns_label() && label_ !=
nullptr) {
517 free(
const_cast<char*
>(label_));
521 thread_ = OSThread::kInvalidThreadId;
528void TimelineEvent::AsyncBegin(
const char* label,
531 Init(kAsyncBegin, label);
532 set_timestamp0(micros);
534 set_timestamp1_or_id(async_id);
537void TimelineEvent::AsyncInstant(
const char* label,
540 Init(kAsyncInstant, label);
541 set_timestamp0(micros);
543 set_timestamp1_or_id(async_id);
546void TimelineEvent::AsyncEnd(
const char* label,
549 Init(kAsyncEnd, label);
550 set_timestamp0(micros);
552 set_timestamp1_or_id(async_id);
555void TimelineEvent::DurationBegin(
const char* label, int64_t micros) {
556 Init(kDuration, label);
557 set_timestamp0(micros);
560void TimelineEvent::Instant(
const char* label, int64_t micros) {
561 Init(kInstant, label);
562 set_timestamp0(micros);
565void TimelineEvent::Duration(
const char* label,
566 int64_t start_micros,
567 int64_t end_micros) {
568 Init(kDuration, label);
569 set_timestamp0(start_micros);
570 set_timestamp1_or_id(end_micros);
573void TimelineEvent::Begin(
const char* label, int64_t
id, int64_t micros) {
575 set_timestamp0(micros);
578 set_timestamp1_or_id(
id);
581void TimelineEvent::End(
const char* label, int64_t
id, int64_t micros) {
583 set_timestamp0(micros);
586 set_timestamp1_or_id(
id);
589void TimelineEvent::Counter(
const char* label, int64_t micros) {
590 Init(kCounter, label);
591 set_timestamp0(micros);
594void TimelineEvent::FlowBegin(
const char* label, int64_t
id, int64_t micros) {
595 Init(kFlowBegin, label);
596 set_timestamp0(micros);
598 set_timestamp1_or_id(
id);
601void TimelineEvent::FlowStep(
const char* label, int64_t
id, int64_t micros) {
602 Init(kFlowStep, label);
603 set_timestamp0(micros);
605 set_timestamp1_or_id(
id);
608void TimelineEvent::FlowEnd(
const char* label, int64_t
id, int64_t micros) {
609 Init(kFlowEnd, label);
610 set_timestamp0(micros);
612 set_timestamp1_or_id(
id);
615void TimelineEvent::Metadata(
const char* label, int64_t micros) {
616 Init(kMetadata, label);
617 set_timestamp0(micros);
620void TimelineEvent::CompleteWithPreSerializedArgs(
char* args_json) {
621 set_pre_serialized_args(
true);
623 SetArgument(0,
"Dart Arguments", args_json);
627void TimelineEvent::FormatArgument(intptr_t
i,
637void TimelineEvent::Complete() {
638 TimelineEventRecorder* recorder = Timeline::recorder();
639 recorder->CompleteEvent(
this);
642 RecorderSynchronizationLock::ExitLock();
649 timestamp1_or_id_ = 0;
652 OSThread* os_thread = OSThread::Current();
653 ASSERT(os_thread !=
nullptr);
654 thread_ = os_thread->trace_id();
655 auto thread = Thread::Current();
656 auto isolate = thread !=
nullptr ? thread->isolate() :
nullptr;
657 auto isolate_group = thread !=
nullptr ? thread->isolate_group() :
nullptr;
658 isolate_id_ = (isolate !=
nullptr) ? isolate->main_port() :
ILLEGAL_PORT;
659 isolate_group_id_ = (isolate_group !=
nullptr) ? isolate_group->id() : 0;
661 (isolate !=
nullptr) ? isolate->init_callback_data() :
nullptr;
662 isolate_group_data_ =
663 (isolate_group !=
nullptr) ? isolate_group->embedder_data() :
nullptr;
667 set_pre_serialized_args(
false);
668 set_owns_label(
false);
671bool TimelineEvent::Within(int64_t time_origin_micros,
672 int64_t time_extent_micros) {
673 if ((time_origin_micros == -1) || (time_extent_micros == -1)) {
677 if (IsFinishedDuration()) {
679 int64_t e_t0 = TimeOrigin();
680 int64_t e_t1 = TimeEnd();
683 int64_t r_t0 = time_origin_micros;
684 int64_t r_t1 = time_origin_micros + time_extent_micros;
686 return !((r_t1 < e_t0) || (e_t1 < r_t0));
688 int64_t
delta = TimeOrigin() - time_origin_micros;
689 return (
delta >= 0) && (
delta <= time_extent_micros);
693void TimelineEvent::PrintJSON(JSONStream*
stream)
const {
694 PrintJSON(
stream->writer());
698void TimelineEvent::PrintJSON(JSONWriter* writer)
const {
699 writer->OpenObject();
700 int64_t pid = OS::ProcessId();
701 int64_t tid = OSThread::ThreadIdToIntPtr(thread_);
702 writer->PrintProperty(
"name", label_);
703 writer->PrintProperty(
"cat", stream_ !=
nullptr ? stream_->name() :
nullptr);
704 writer->PrintProperty64(
"tid", tid);
705 writer->PrintProperty64(
"pid", pid);
706 writer->PrintProperty64(
"ts", TimeOrigin());
709 writer->PrintProperty(
"ph",
"B");
712 writer->PrintProperty(
"ph",
"E");
715 writer->PrintProperty(
"ph",
"X");
716 writer->PrintProperty64(
"dur", TimeDuration());
719 writer->PrintProperty(
"ph",
"i");
720 writer->PrintProperty(
"s",
"p");
723 writer->PrintProperty(
"ph",
"b");
724 writer->PrintfProperty(
"id",
"%" Px64 "", Id());
726 case kAsyncInstant: {
727 writer->PrintProperty(
"ph",
"n");
728 writer->PrintfProperty(
"id",
"%" Px64 "", Id());
731 writer->PrintProperty(
"ph",
"e");
732 writer->PrintfProperty(
"id",
"%" Px64 "", Id());
735 writer->PrintProperty(
"ph",
"C");
738 writer->PrintProperty(
"ph",
"s");
739 writer->PrintfProperty(
"id",
"%" Px64 "", Id());
742 writer->PrintProperty(
"ph",
"t");
743 writer->PrintfProperty(
"id",
"%" Px64 "", Id());
746 writer->PrintProperty(
"ph",
"f");
747 writer->PrintProperty(
"bp",
"e");
748 writer->PrintfProperty(
"id",
"%" Px64 "", Id());
751 writer->PrintProperty(
"ph",
"M");
757 if (ArgsArePreSerialized()) {
758 ASSERT(arguments_.length() == 1);
759 writer->AppendSerializedObject(
"args", arguments_[0].
value);
760 if (HasIsolateId()) {
761 writer->UncloseObject();
763 static_cast<int64_t
>(isolate_id_));
764 writer->CloseObject();
766 if (HasIsolateGroupId()) {
767 writer->UncloseObject();
768 writer->PrintfProperty(
"isolateGroupId",
771 writer->CloseObject();
776 writer->OpenObject(
"args");
777 for (intptr_t
i = 0;
i < arguments_.length();
i++) {
778 const TimelineEventArgument& arg = arguments_[
i];
779 writer->PrintProperty(arg.name, arg.value);
781 if (HasIsolateId()) {
783 static_cast<int64_t
>(isolate_id_));
785 if (HasIsolateGroupId()) {
786 writer->PrintfProperty(
"isolateGroupId",
792 writer->CloseObject();
794 writer->CloseObject();
797#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
798inline void AddSyncEventFields(
800 const TimelineEvent&
event) {
804inline void AddAsyncEventFields(
806 const TimelineEvent&
event) {
810inline void AddBeginAndInstantEventCommonFields(
812 const TimelineEvent&
event) {
814 for (intptr_t
i = 0;
i <
event.flow_id_count(); ++
i) {
823inline void AddBeginEventFields(
825 const TimelineEvent&
event) {
826 AddBeginAndInstantEventCommonFields(track_event,
event);
831inline void AddInstantEventFields(
833 const TimelineEvent&
event) {
834 AddBeginAndInstantEventCommonFields(track_event,
event);
839inline void AddEndEventFields(
845inline void AddDebugAnnotations(
847 const TimelineEvent&
event) {
848 if (
event.GetNumArguments() > 0) {
849 if (
event.ArgsArePreSerialized()) {
856 for (intptr_t
i = 0;
i <
event.GetNumArguments(); ++
i) {
864 if (
event.HasIsolateId()) {
867 debug_annotation.
set_name(
"isolateId");
868 std::unique_ptr<const char[]> formatted_isolate_id =
869 event.GetFormattedIsolateId();
872 if (
event.HasIsolateGroupId()) {
875 debug_annotation.
set_name(
"isolateGroupId");
876 std::unique_ptr<const char[]> formatted_isolate_group =
877 event.GetFormattedIsolateGroupId();
882bool TimelineEvent::CanBeRepresentedByPerfettoTracePacket()
const {
884 case TimelineEvent::kBegin:
885 case TimelineEvent::kEnd:
886 case TimelineEvent::kDuration:
887 case TimelineEvent::kInstant:
888 case TimelineEvent::kAsyncBegin:
889 case TimelineEvent::kAsyncEnd:
890 case TimelineEvent::kAsyncInstant:
897void TimelineEvent::PopulateTracePacket(
899 ASSERT(packet !=
nullptr);
900 ASSERT(CanBeRepresentedByPerfettoTracePacket());
902 perfetto_utils::SetTrustedPacketSequenceId(packet);
903 perfetto_utils::SetTimestampAndMonotonicClockId(packet, TimeOrigin());
907 const TimelineEvent&
event = *
this;
909 case TimelineEvent::kBegin: {
910 AddSyncEventFields(track_event,
event);
911 AddBeginEventFields(track_event,
event);
914 case TimelineEvent::kEnd: {
915 AddSyncEventFields(track_event,
event);
916 AddEndEventFields(track_event);
919 case TimelineEvent::kInstant: {
920 AddSyncEventFields(track_event,
event);
921 AddInstantEventFields(track_event,
event);
924 case TimelineEvent::kAsyncBegin: {
925 AddAsyncEventFields(track_event,
event);
926 AddBeginEventFields(track_event,
event);
929 case TimelineEvent::kAsyncEnd: {
930 AddAsyncEventFields(track_event,
event);
931 AddEndEventFields(track_event);
934 case TimelineEvent::kAsyncInstant: {
935 AddAsyncEventFields(track_event,
event);
936 AddInstantEventFields(track_event,
event);
942 AddDebugAnnotations(track_event,
event);
946int64_t TimelineEvent::LowTime()
const {
950int64_t TimelineEvent::HighTime()
const {
952 return timestamp1_or_id_;
958int64_t TimelineEvent::TimeDuration()
const {
960 if (timestamp1_or_id_ == 0) {
962 return OS::GetCurrentMonotonicMicrosForTimeline() - timestamp0_;
964 return timestamp1_or_id_ - timestamp0_;
967bool TimelineEvent::HasIsolateId()
const {
971bool TimelineEvent::HasIsolateGroupId()
const {
975std::unique_ptr<const char[]> TimelineEvent::GetFormattedIsolateId()
const {
977 intptr_t formatted_isolate_id_buffer_size =
981 auto formatted_isolate_id =
982 std::make_unique<char[]>(formatted_isolate_id_buffer_size);
983 Utils::SNPrint(formatted_isolate_id.get(), formatted_isolate_id_buffer_size,
985 return formatted_isolate_id;
988std::unique_ptr<const char[]> TimelineEvent::GetFormattedIsolateGroupId()
990 ASSERT(HasIsolateGroupId());
991 intptr_t formatted_isolate_group_id_buffer_size =
995 auto formatted_isolate_group_id =
996 std::make_unique<char[]>(formatted_isolate_group_id_buffer_size);
997 Utils::SNPrint(formatted_isolate_group_id.get(),
998 formatted_isolate_group_id_buffer_size,
1000 return formatted_isolate_group_id;
1003TimelineTrackMetadata::TimelineTrackMetadata(intptr_t pid,
1006 : pid_(pid), tid_(tid), track_name_(
std::move(track_name)) {}
1009 track_name_ = std::move(track_name);
1012#if !defined(PRODUCT)
1013void TimelineTrackMetadata::PrintJSON(
const JSONArray& jsarr_events)
const {
1014 JSONObject jsobj(&jsarr_events);
1015 jsobj.AddProperty(
"name",
"thread_name");
1016 jsobj.AddProperty(
"ph",
"M");
1017 jsobj.AddProperty(
"pid", pid());
1018 jsobj.AddProperty(
"tid", tid());
1020 JSONObject jsobj_args(&jsobj,
"args");
1021 jsobj_args.AddPropertyF(
"name",
"%s (%" Pd ")", track_name(), tid());
1022 jsobj_args.AddProperty(
"mode",
"basic");
1026#if defined(SUPPORT_PERFETTO)
1027void TimelineTrackMetadata::PopulateTracePacket(
1029 perfetto_utils::SetTrustedPacketSequenceId(track_descriptor_packet);
1038 thread_descriptor.
set_pid(pid());
1039 thread_descriptor.
set_tid(tid());
1045AsyncTimelineTrackMetadata::AsyncTimelineTrackMetadata(intptr_t pid,
1047 : pid_(pid), async_id_(async_id) {}
1049#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1050void AsyncTimelineTrackMetadata::PopulateTracePacket(
1052 perfetto_utils::SetTrustedPacketSequenceId(track_descriptor_packet);
1056 track_descriptor.
set_uuid(async_id());
1060TimelineStream::TimelineStream(
const char*
name,
1061 const char* fuchsia_name,
1062 bool has_static_labels,
1065 fuchsia_name_(fuchsia_name),
1066#
if defined(DART_HOST_OS_FUCHSIA)
1067 enabled_(static_cast<uintptr_t>(
true))
1069 enabled_(static_cast<uintptr_t>(enabled))
1072#if defined(DART_HOST_OS_MACOS)
1073 macos_log_ = os_log_create(
"Dart",
name);
1074 has_static_labels_ = has_static_labels;
1078TimelineEvent* TimelineStream::StartEvent() {
1085 RecorderSynchronizationLock::EnterLock();
1086 TimelineEventRecorder* recorder = Timeline::recorder();
1087 if (!enabled() || (recorder ==
nullptr) ||
1088 !RecorderSynchronizationLock::IsActive()) {
1089 RecorderSynchronizationLock::ExitLock();
1092 ASSERT(name_ !=
nullptr);
1093 TimelineEvent*
event = recorder->StartEvent();
1094 if (
event ==
nullptr) {
1095 RecorderSynchronizationLock::ExitLock();
1098 event->StreamInit(
this);
1102TimelineEventScope::TimelineEventScope(TimelineStream*
stream,
1104 : StackResource(static_cast<Thread*>(nullptr)),
1111TimelineEventScope::TimelineEventScope(Thread* thread,
1114 : StackResource(thread), stream_(
stream), label_(label), enabled_(
false) {
1118TimelineEventScope::~TimelineEventScope() {}
1121 ASSERT(enabled_ ==
false);
1122 ASSERT(label_ !=
nullptr);
1123 ASSERT(stream_ !=
nullptr);
1124 if (!stream_->enabled()) {
1129 Thread* thread =
static_cast<Thread*
>(this->thread());
1130 if (thread !=
nullptr) {
1131 id_ = thread->GetNextTaskId();
1133 static RelaxedAtomic<int64_t> next_bootstrap_task_id = {0};
1134 id_ = next_bootstrap_task_id.fetch_add(1);
1138void TimelineEventScope::SetNumArguments(intptr_t
length) {
1142 arguments_.SetNumArguments(
length);
1146void TimelineEventScope::SetArgument(intptr_t
i,
1152 arguments_.SetArgument(
i,
name, argument);
1156void TimelineEventScope::CopyArgument(intptr_t
i,
1158 const char* argument) {
1162 arguments_.CopyArgument(
i,
name, argument);
1165void TimelineEventScope::FormatArgument(intptr_t
i,
1178void TimelineEventScope::StealArguments(TimelineEvent*
event) {
1179 if (
event ==
nullptr) {
1182 event->StealArguments(&arguments_);
1185TimelineBeginEndScope::TimelineBeginEndScope(TimelineStream*
stream,
1187 : TimelineEventScope(
stream, label) {
1191TimelineBeginEndScope::TimelineBeginEndScope(Thread* thread,
1194 : TimelineEventScope(thread,
stream, label) {
1198TimelineBeginEndScope::~TimelineBeginEndScope() {
1202void TimelineBeginEndScope::EmitBegin() {
1203 if (!ShouldEmitEvent()) {
1206 TimelineEvent*
event =
stream()->StartEvent();
1207 if (
event ==
nullptr) {
1214 event->Begin(label(),
id());
1218void TimelineBeginEndScope::EmitEnd() {
1219 if (!ShouldEmitEvent()) {
1222 TimelineEvent*
event =
stream()->StartEvent();
1223 if (
event ==
nullptr) {
1230 event->End(label(),
id());
1231 StealArguments(
event);
1235bool TimelineEventBlock::InUseLocked()
const {
1236 ASSERT(Timeline::recorder()->lock_.IsOwnedByCurrentThread());
1240bool TimelineEventBlock::ContainsEventsThatCanBeSerializedLocked()
const {
1241 ASSERT(Timeline::recorder()->lock_.IsOwnedByCurrentThread());
1246 return !InUseLocked() && !
IsEmpty();
1249TimelineEventFilter::TimelineEventFilter(int64_t time_origin_micros,
1250 int64_t time_extent_micros)
1251 : time_origin_micros_(time_origin_micros),
1252 time_extent_micros_(time_extent_micros) {
1253 ASSERT(time_origin_micros_ >= -1);
1254 ASSERT(time_extent_micros_ >= -1);
1257TimelineEventFilter::~TimelineEventFilter() {}
1259IsolateTimelineEventFilter::IsolateTimelineEventFilter(
1261 int64_t time_origin_micros,
1262 int64_t time_extent_micros)
1263 : TimelineEventFilter(time_origin_micros, time_extent_micros),
1264 isolate_id_(isolate_id) {}
1266TimelineEventRecorder::TimelineEventRecorder()
1267 : time_low_micros_(0),
1268 time_high_micros_(0),
1269 track_uuid_to_track_metadata_lock_(),
1270 track_uuid_to_track_metadata_(
1271 &SimpleHashMap::SamePointerValue,
1272 TimelineEventRecorder::kTrackUuidToTrackMetadataInitialCapacity),
1273 async_track_uuid_to_track_metadata_lock_(),
1274 async_track_uuid_to_track_metadata_(
1275 &SimpleHashMap::SamePointerValue,
1276 TimelineEventRecorder::kTrackUuidToTrackMetadataInitialCapacity) {}
1278TimelineEventRecorder::~TimelineEventRecorder() {
1283 entry !=
nullptr; entry = track_uuid_to_track_metadata_.Next(entry)) {
1284 TimelineTrackMetadata*
value =
1285 static_cast<TimelineTrackMetadata*
>(entry->value);
1289 async_track_uuid_to_track_metadata_.Start();
1291 entry = async_track_uuid_to_track_metadata_.Next(entry)) {
1292 AsyncTimelineTrackMetadata*
value =
1293 static_cast<AsyncTimelineTrackMetadata*
>(entry->value);
1299void TimelineEventRecorder::PrintJSONMeta(
const JSONArray& jsarr_events) {
1300 MutexLocker ml(&track_uuid_to_track_metadata_lock_);
1302 entry !=
nullptr; entry = track_uuid_to_track_metadata_.Next(entry)) {
1303 TimelineTrackMetadata*
value =
1304 static_cast<TimelineTrackMetadata*
>(entry->value);
1305 value->PrintJSON(jsarr_events);
1309#if defined(SUPPORT_PERFETTO)
1310void TimelineEventRecorder::PrintPerfettoMeta(
1311 JSONBase64String* jsonBase64String) {
1312 ASSERT(jsonBase64String !=
nullptr);
1314 perfetto_utils::PopulateClockSnapshotPacket(packet_.get());
1315 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, &packet_);
1317 perfetto_utils::PopulateProcessDescriptorPacket(packet_.get());
1318 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, &packet_);
1322 MutexLocker ml(&async_track_uuid_to_track_metadata_lock_);
1324 async_track_uuid_to_track_metadata_.Start();
1326 entry = async_track_uuid_to_track_metadata_.Next(entry)) {
1327 AsyncTimelineTrackMetadata*
value =
1328 static_cast<AsyncTimelineTrackMetadata*
>(entry->value);
1329 value->PopulateTracePacket(packet_.get());
1330 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
1337 MutexLocker ml(&track_uuid_to_track_metadata_lock_);
1339 entry !=
nullptr; entry = track_uuid_to_track_metadata_.Next(entry)) {
1340 TimelineTrackMetadata*
value =
1341 static_cast<TimelineTrackMetadata*
>(entry->value);
1342 value->PopulateTracePacket(packet_.get());
1343 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
1352TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
1354 OSThread* thread = OSThread::Current();
1355 ASSERT(thread !=
nullptr);
1359 Mutex& recorder_lock = lock_;
1360 recorder_lock.Lock();
1361 Mutex* thread_block_lock = thread->timeline_block_lock();
1362 ASSERT(thread_block_lock !=
nullptr);
1365 thread_block_lock->Lock();
1367 Thread*
T = Thread::Current();
1369 T->IncrementNoSafepointScopeDepth();
1373 TimelineEventBlock* thread_block = thread->TimelineBlockLocked();
1375 if ((thread_block !=
nullptr) && thread_block->IsFull()) {
1378 thread->SetTimelineBlockLocked(
nullptr);
1379 FinishBlock(thread_block);
1383 thread_block_lock->Unlock();
1384 thread_block = GetNewBlockLocked();
1385 thread_block_lock->Lock();
1386 thread->SetTimelineBlockLocked(thread_block);
1387 }
else if (thread_block ==
nullptr) {
1391 thread_block_lock->Unlock();
1392 thread_block = GetNewBlockLocked();
1393 thread_block_lock->Lock();
1394 thread->SetTimelineBlockLocked(thread_block);
1396 recorder_lock.Unlock();
1397 if (thread_block !=
nullptr) {
1399 ASSERT(!thread_block->IsFull());
1400 TimelineEvent*
event = thread_block->StartEventLocked();
1406 T->DecrementNoSafepointScopeDepth();
1409 thread_block_lock->Unlock();
1413void TimelineEventRecorder::ResetTimeTracking() {
1414 time_high_micros_ = 0;
1418void TimelineEventRecorder::ReportTime(int64_t micros) {
1419 if (time_high_micros_ < micros) {
1420 time_high_micros_ = micros;
1422 if (time_low_micros_ > micros) {
1423 time_low_micros_ = micros;
1427int64_t TimelineEventRecorder::TimeOriginMicros()
const {
1428 if (time_high_micros_ == 0) {
1431 return time_low_micros_;
1434int64_t TimelineEventRecorder::TimeExtentMicros()
const {
1435 if (time_high_micros_ == 0) {
1438 return time_high_micros_ - time_low_micros_;
1441void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent*
event) {
1442 if (
event ==
nullptr) {
1445#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1449 if (
event->event_type() == TimelineEvent::kAsyncBegin ||
1450 event->event_type() == TimelineEvent::kAsyncInstant) {
1451 AddAsyncTrackMetadataBasedOnEvent(*
event);
1455 OSThread* thread = OSThread::Current();
1456 ASSERT(thread !=
nullptr);
1458 Mutex* thread_block_lock = thread->timeline_block_lock();
1459 ASSERT(thread_block_lock !=
nullptr);
1461 Thread*
T = Thread::Current();
1463 T->DecrementNoSafepointScopeDepth();
1466 thread_block_lock->Unlock();
1470void TimelineEventRecorder::WriteTo(
const char* directory) {
1474 if ((file_open ==
nullptr) || (file_write ==
nullptr) ||
1475 (file_close ==
nullptr)) {
1476 OS::PrintErr(
"warning: Could not access file callbacks.");
1482 MutexLocker ml(&lock_);
1483 Timeline::ReclaimCachedBlocksFromThreads();
1485 intptr_t pid = OS::ProcessId();
1487 OS::SCreate(
nullptr,
"%s/dart-timeline-%" Pd ".json", directory, pid);
1488 void*
file = (*file_open)(filename,
true);
1489 if (
file ==
nullptr) {
1490 OS::PrintErr(
"warning: Failed to write timeline file: %s\n", filename);
1497 TimelineEventFilter filter;
1498 PrintTraceEvent(&
js, &filter);
1501 intptr_t output_length = 0;
1506 (*file_close)(
file);
1512void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) {
1513 if (block !=
nullptr) {
1518void TimelineEventRecorder::AddTrackMetadataBasedOnThread(
1519 const intptr_t process_id,
1520 const intptr_t trace_id,
1521 const char* thread_name) {
1522 ASSERT(FLAG_timeline_recorder !=
nullptr);
1523 if (strcmp(
"none", FLAG_timeline_recorder) == 0 ||
1524 strcmp(
"callback", FLAG_timeline_recorder) == 0 ||
1525 strcmp(
"systrace", FLAG_timeline_recorder) == 0 ||
1526 FLAG_systrace_timeline) {
1532 MutexLocker ml(&track_uuid_to_track_metadata_lock_);
1534 void*
key =
reinterpret_cast<void*
>(trace_id);
1537 track_uuid_to_track_metadata_.Lookup(
key,
hash,
true);
1538 if (entry->value ==
nullptr) {
1539 entry->value =
new TimelineTrackMetadata(
1540 process_id, trace_id,
1542 Utils::StrDup(thread_name ==
nullptr ?
"" : thread_name)));
1544 TimelineTrackMetadata*
value =
1545 static_cast<TimelineTrackMetadata*
>(entry->value);
1548 Utils::StrDup(thread_name ==
nullptr ?
"" : thread_name)));
1552#if !defined(PRODUCT)
1553void TimelineEventRecorder::AddAsyncTrackMetadataBasedOnEvent(
1554 const TimelineEvent&
event) {
1555 ASSERT(FLAG_timeline_recorder !=
nullptr);
1556 if (strcmp(
"none", FLAG_timeline_recorder) == 0 ||
1557 strcmp(
"callback", FLAG_timeline_recorder) == 0 ||
1558 strcmp(
"systrace", FLAG_timeline_recorder) == 0 ||
1559 FLAG_systrace_timeline) {
1565 MutexLocker ml(&async_track_uuid_to_track_metadata_lock_);
1567 void*
key =
reinterpret_cast<void*
>(
event.Id());
1570 async_track_uuid_to_track_metadata_.Lookup(
key,
hash,
true);
1571 if (entry->value ==
nullptr) {
1572 entry->value =
new AsyncTimelineTrackMetadata(OS::ProcessId(),
event.Id());
1577TimelineEventFixedBufferRecorder::TimelineEventFixedBufferRecorder(
1581 capacity_(capacity),
1590 VirtualMemory::PageSize());
1591 const bool executable =
false;
1592 const bool compressed =
false;
1595 if (memory_ ==
nullptr) {
1598 blocks_ =
reinterpret_cast<TimelineEventBlock*
>(memory_->address());
1601TimelineEventFixedBufferRecorder::~TimelineEventFixedBufferRecorder() {
1609 return memory_->size();
1613void TimelineEventFixedBufferRecorder::PrintEventsCommon(
1614 const TimelineEventFilter& filter,
1618 MutexLocker ml(&lock_);
1619 Timeline::ReclaimCachedBlocksFromThreads();
1620 ResetTimeTracking();
1621 intptr_t block_offset = FindOldestBlockIndexLocked();
1622 if (block_offset == -1) {
1626 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) {
1627 TimelineEventBlock* block =
1628 &blocks_[(block_idx + block_offset) % num_blocks_];
1629 if (!block->ContainsEventsThatCanBeSerializedLocked()) {
1632 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) {
1633 TimelineEvent*
event = block->At(event_idx);
1634 if (filter.IncludeEvent(
event) &&
1635 event->Within(filter.time_origin_micros(),
1636 filter.time_extent_micros())) {
1637 ReportTime(
event->LowTime());
1638 ReportTime(
event->HighTime());
1645void TimelineEventFixedBufferRecorder::PrintJSONEvents(
1646 const JSONArray& events,
1647 const TimelineEventFilter& filter) {
1648 PrintEventsCommon(filter, [&events](
const TimelineEvent&
event) {
1649 events.AddValue(&
event);
1653#if defined(SUPPORT_PERFETTO)
1658inline void PrintPerfettoEventCallbackBody(
1659 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
1660 heap_buffered_packet,
1661 const TimelineEvent&
event,
1663 void(protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*)>&&
1665 ASSERT(heap_buffered_packet !=
nullptr);
1666 if (!
event.CanBeRepresentedByPerfettoTracePacket()) {
1669 if (
event.IsDuration()) {
1673 *heap_buffered_packet->get();
1675 perfetto_utils::SetTrustedPacketSequenceId(&packet);
1676 perfetto_utils::SetTimestampAndMonotonicClockId(&packet,
1677 event.TimeOrigin());
1682 AddSyncEventFields(track_event,
event);
1683 AddBeginEventFields(track_event,
event);
1684 AddDebugAnnotations(track_event,
event);
1686 print_callback(heap_buffered_packet);
1687 heap_buffered_packet->Reset();
1690 perfetto_utils::SetTrustedPacketSequenceId(&packet);
1691 perfetto_utils::SetTimestampAndMonotonicClockId(&packet,
event.TimeEnd());
1696 AddSyncEventFields(track_event,
event);
1697 AddEndEventFields(track_event);
1698 AddDebugAnnotations(track_event,
event);
1701 event.PopulateTracePacket(heap_buffered_packet->get());
1703 print_callback(heap_buffered_packet);
1704 heap_buffered_packet->Reset();
1707void TimelineEventFixedBufferRecorder::PrintPerfettoEvents(
1708 JSONBase64String* jsonBase64String,
1709 const TimelineEventFilter& filter) {
1711 filter, [
this, &jsonBase64String](
const TimelineEvent&
event) {
1712 PrintPerfettoEventCallbackBody(
1714 [&jsonBase64String](
1715 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
1717 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
1724void TimelineEventFixedBufferRecorder::PrintJSON(JSONStream*
js,
1725 TimelineEventFilter* filter) {
1726 JSONObject topLevel(
js);
1727 topLevel.AddProperty(
"type",
"Timeline");
1729 JSONArray events(&topLevel,
"traceEvents");
1730 PrintJSONMeta(events);
1731 PrintJSONEvents(events, *filter);
1733 topLevel.AddPropertyTimeMicros(
"timeOriginMicros", TimeOriginMicros());
1734 topLevel.AddPropertyTimeMicros(
"timeExtentMicros", TimeExtentMicros());
1737#define PRINT_PERFETTO_TIMELINE_BODY \
1738 JSONObject jsobj_topLevel(js); \
1739 jsobj_topLevel.AddProperty("type", "PerfettoTimeline"); \
1741 js->AppendSerializedObject("\"trace\":"); \
1743 JSONBase64String jsonBase64String(js); \
1744 PrintPerfettoMeta(&jsonBase64String); \
1745 PrintPerfettoEvents(&jsonBase64String, filter); \
1748 jsobj_topLevel.AddPropertyTimeMicros("timeOriginMicros", \
1749 TimeOriginMicros()); \
1750 jsobj_topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros());
1752#if defined(SUPPORT_PERFETTO)
1753void TimelineEventFixedBufferRecorder::PrintPerfettoTimeline(
1755 const TimelineEventFilter& filter) {
1756 PRINT_PERFETTO_TIMELINE_BODY
1760void TimelineEventFixedBufferRecorder::PrintTraceEvent(
1762 TimelineEventFilter* filter) {
1763 JSONArray events(
js);
1764 PrintJSONMeta(events);
1765 PrintJSONEvents(events, *filter);
1769TimelineEventBlock* TimelineEventFixedBufferRecorder::GetHeadBlockLocked() {
1770 ASSERT(lock_.IsOwnedByCurrentThread());
1774void TimelineEventFixedBufferRecorder::ClearLocked() {
1775 ASSERT(lock_.IsOwnedByCurrentThread());
1776 for (intptr_t
i = 0;
i < num_blocks_;
i++) {
1777 TimelineEventBlock* block = &blocks_[
i];
1782intptr_t TimelineEventFixedBufferRecorder::FindOldestBlockIndexLocked()
const {
1783 ASSERT(lock_.IsOwnedByCurrentThread());
1785 intptr_t earliest_index = -1;
1786 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) {
1787 TimelineEventBlock* block = &blocks_[block_idx];
1788 if (!block->ContainsEventsThatCanBeSerializedLocked()) {
1792 if (block->LowerTimeBound() < earliest_time) {
1793 earliest_time = block->LowerTimeBound();
1794 earliest_index = block_idx;
1797 return earliest_index;
1800TimelineEvent* TimelineEventFixedBufferRecorder::StartEvent() {
1801 return ThreadBlockStartEvent();
1804void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent*
event) {
1805 if (
event ==
nullptr) {
1808 ThreadBlockCompleteEvent(
event);
1811TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() {
1812 ASSERT(lock_.IsOwnedByCurrentThread());
1813 if (block_cursor_ == num_blocks_) {
1816 TimelineEventBlock* block = &blocks_[block_cursor_++];
1817 if (block->current_owner_ !=
nullptr) {
1818 MutexLocker ml(block->current_owner_->timeline_block_lock());
1819 block->current_owner_->SetTimelineBlockLocked(
nullptr);
1829TimelineEventBlock* TimelineEventStartupRecorder::GetNewBlockLocked() {
1830 ASSERT(lock_.IsOwnedByCurrentThread());
1831 if (block_cursor_ == num_blocks_) {
1834 TimelineEventBlock* block = &blocks_[block_cursor_++];
1840TimelineEventCallbackRecorder::TimelineEventCallbackRecorder() {}
1842TimelineEventCallbackRecorder::~TimelineEventCallbackRecorder() {}
1845void TimelineEventCallbackRecorder::PrintJSON(JSONStream*
js,
1846 TimelineEventFilter* filter) {
1850#if defined(SUPPORT_PERFETTO)
1851void TimelineEventCallbackRecorder::PrintPerfettoTimeline(
1853 const TimelineEventFilter& filter) {
1858void TimelineEventCallbackRecorder::PrintTraceEvent(
1860 TimelineEventFilter* filter) {
1861 JSONArray events(
js);
1865TimelineEvent* TimelineEventCallbackRecorder::StartEvent() {
1866 TimelineEvent*
event =
new TimelineEvent();
1870void TimelineEventCallbackRecorder::CompleteEvent(TimelineEvent*
event) {
1875void TimelineEventEmbedderCallbackRecorder::OnEvent(TimelineEvent*
event) {
1883 switch (
event->event_type()) {
1884 case TimelineEvent::kBegin:
1887 case TimelineEvent::kEnd:
1890 case TimelineEvent::kInstant:
1893 case TimelineEvent::kDuration:
1896 case TimelineEvent::kAsyncBegin:
1899 case TimelineEvent::kAsyncEnd:
1902 case TimelineEvent::kAsyncInstant:
1905 case TimelineEvent::kCounter:
1908 case TimelineEvent::kFlowBegin:
1911 case TimelineEvent::kFlowStep:
1914 case TimelineEvent::kFlowEnd:
1921 recorder_event.
timestamp0 =
event->timestamp0();
1923 recorder_event.
isolate =
event->isolate_id();
1927 recorder_event.
label =
event->label();
1928 recorder_event.
stream =
event->stream()->name();
1932 event->arguments());
1934 NoActiveIsolateScope no_active_isolate_scope;
1938void TimelineEventNopRecorder::OnEvent(TimelineEvent*
event) {
1942TimelineEventPlatformRecorder::TimelineEventPlatformRecorder() {}
1944TimelineEventPlatformRecorder::~TimelineEventPlatformRecorder() {}
1947void TimelineEventPlatformRecorder::PrintJSON(JSONStream*
js,
1948 TimelineEventFilter* filter) {
1952#if defined(SUPPORT_PERFETTO)
1953void TimelineEventPlatformRecorder::PrintPerfettoTimeline(
1955 const TimelineEventFilter& filter) {
1960void TimelineEventPlatformRecorder::PrintTraceEvent(
1962 TimelineEventFilter* filter) {
1963 JSONArray events(
js);
1967TimelineEvent* TimelineEventPlatformRecorder::StartEvent() {
1968 TimelineEvent*
event =
new TimelineEvent();
1972void TimelineEventPlatformRecorder::CompleteEvent(TimelineEvent*
event) {
1977static void TimelineEventFileRecorderBaseStart(
uword parameter) {
1978 reinterpret_cast<TimelineEventFileRecorderBase*
>(parameter)->Drain();
1981TimelineEventFileRecorderBase::TimelineEventFileRecorderBase(
const char*
path)
1982 : TimelineEventPlatformRecorder(),
1987 shutting_down_(
false),
1989 thread_id_(OSThread::kInvalidThreadJoinId) {
1993 if ((file_open ==
nullptr) || (file_write ==
nullptr) ||
1994 (file_close ==
nullptr)) {
1995 OS::PrintErr(
"warning: Could not access file callbacks.");
1998 void*
file = (*file_open)(
path,
true);
1999 if (
file ==
nullptr) {
2000 OS::PrintErr(
"warning: Failed to open timeline file: %s\n",
path);
2007TimelineEventFileRecorderBase::~TimelineEventFileRecorderBase() {
2014 if (file_ ==
nullptr)
return;
2016 ASSERT(thread_id_ != OSThread::kInvalidThreadJoinId);
2018 thread_id_ = OSThread::kInvalidThreadJoinId;
2020 TimelineEvent*
event = head_;
2021 while (
event !=
nullptr) {
2022 TimelineEvent*
next =
event->next();
2026 head_ = tail_ =
nullptr;
2029 (*file_close)(file_);
2033void TimelineEventFileRecorderBase::Drain() {
2034 MonitorLocker ml(&monitor_);
2035 thread_id_ = OSThread::GetCurrentThreadJoinId(OSThread::Current());
2036 while (!shutting_down_) {
2037 if (head_ ==
nullptr) {
2041 TimelineEvent*
event = head_;
2042 TimelineEvent*
next =
event->next();
2044 if (
next ==
nullptr) {
2058void TimelineEventFileRecorderBase::Write(
const char*
buffer,
2059 intptr_t
len)
const {
2064void TimelineEventFileRecorderBase::CompleteEvent(TimelineEvent*
event) {
2065 if (
event ==
nullptr) {
2068 if (file_ ==
nullptr) {
2073 MonitorLocker ml(&monitor_);
2075 event->set_next(
nullptr);
2076 if (tail_ ==
nullptr) {
2077 head_ = tail_ =
event;
2079 tail_->set_next(
event);
2087void TimelineEventFileRecorderBase::ShutDown() {
2088 MonitorLocker ml(&monitor_);
2089 shutting_down_ =
true;
2096TimelineEventFileRecorder::TimelineEventFileRecorder(
const char*
path)
2097 : TimelineEventFileRecorderBase(
path), first_(
true) {
2105 OSThread::Start(
"TimelineEventFileRecorder",
2106 TimelineEventFileRecorderBaseStart,
2107 reinterpret_cast<uword>(
this));
2110TimelineEventFileRecorder::~TimelineEventFileRecorder() {
2115void TimelineEventFileRecorder::DrainImpl(
const TimelineEvent&
event) {
2120 writer.buffer()->AddChar(
',');
2122 event.PrintJSON(&writer);
2124 intptr_t output_length = 0;
2125 writer.Steal(&
output, &output_length);
2126 Write(
output, output_length);
2130#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
2131TimelineEventPerfettoFileRecorder::TimelineEventPerfettoFileRecorder(
2133 : TimelineEventFileRecorderBase(
path) {
2134 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet =
2137 perfetto_utils::PopulateClockSnapshotPacket(packet.get());
2138 WritePacket(&packet);
2141 perfetto_utils::PopulateProcessDescriptorPacket(packet.get());
2142 WritePacket(&packet);
2145 OSThread::Start(
"TimelineEventPerfettoFileRecorder",
2146 TimelineEventFileRecorderBaseStart,
2147 reinterpret_cast<uword>(
this));
2150TimelineEventPerfettoFileRecorder::~TimelineEventPerfettoFileRecorder() {
2151 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet =
2158 entry !=
nullptr; entry = track_uuid_to_track_metadata().Next(entry)) {
2159 TimelineTrackMetadata*
value =
2160 static_cast<TimelineTrackMetadata*
>(entry->value);
2161 value->PopulateTracePacket(packet.get());
2162 WritePacket(&packet);
2166 async_track_uuid_to_track_metadata().Start();
2168 entry = async_track_uuid_to_track_metadata().Next(entry)) {
2169 AsyncTimelineTrackMetadata*
value =
2170 static_cast<AsyncTimelineTrackMetadata*
>(entry->value);
2171 value->PopulateTracePacket(packet.get());
2172 WritePacket(&packet);
2177void TimelineEventPerfettoFileRecorder::WritePacket(
2178 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
2180 const std::tuple<std::unique_ptr<const uint8_t[]>, intptr_t>& response =
2181 perfetto_utils::GetProtoPreamble(packet);
2182 Write(
reinterpret_cast<const char*
>(
std::get<0>(response).
get()),
2184 for (
const protozero::ScatteredHeapBuffer::Slice& slice :
2185 packet->GetSlices()) {
2186 Write(
reinterpret_cast<char*
>(slice.start()),
2187 slice.size() - slice.unused_bytes());
2191void TimelineEventPerfettoFileRecorder::DrainImpl(
const TimelineEvent&
event) {
2192 PrintPerfettoEventCallbackBody(
2194 [
this](protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
2195 packet) { WritePacket(packet); });
2197 if (
event.event_type() == TimelineEvent::kAsyncBegin ||
2198 event.event_type() == TimelineEvent::kAsyncInstant) {
2199 AddAsyncTrackMetadataBasedOnEvent(
event);
2204TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
2205 : head_(nullptr), tail_(nullptr), block_index_(0) {}
2207TimelineEventEndlessRecorder::~TimelineEventEndlessRecorder() {
2208 ASSERT(head_ ==
nullptr);
2212void TimelineEventEndlessRecorder::PrintEventsCommon(
2213 const TimelineEventFilter& filter,
2217 MutexLocker ml(&lock_);
2218 Timeline::ReclaimCachedBlocksFromThreads();
2219 ResetTimeTracking();
2220 for (TimelineEventBlock* current = head_; current !=
nullptr;
2221 current = current->next()) {
2222 if (!current->ContainsEventsThatCanBeSerializedLocked()) {
2225 intptr_t
length = current->length();
2227 TimelineEvent*
event = current->At(
i);
2228 if (filter.IncludeEvent(
event) &&
2229 event->Within(filter.time_origin_micros(),
2230 filter.time_extent_micros())) {
2231 ReportTime(
event->LowTime());
2232 ReportTime(
event->HighTime());
2239void TimelineEventEndlessRecorder::PrintJSONEvents(
2240 const JSONArray& events,
2241 const TimelineEventFilter& filter) {
2242 PrintEventsCommon(filter, [&events](
const TimelineEvent&
event) {
2243 events.AddValue(&
event);
2247#if defined(SUPPORT_PERFETTO)
2248void TimelineEventEndlessRecorder::PrintPerfettoEvents(
2249 JSONBase64String* jsonBase64String,
2250 const TimelineEventFilter& filter) {
2252 filter, [
this, &jsonBase64String](
const TimelineEvent&
event) {
2253 PrintPerfettoEventCallbackBody(
2255 [&jsonBase64String](
2256 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
2258 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
2265void TimelineEventEndlessRecorder::PrintJSON(JSONStream*
js,
2266 TimelineEventFilter* filter) {
2267 JSONObject topLevel(
js);
2268 topLevel.AddProperty(
"type",
"Timeline");
2270 JSONArray events(&topLevel,
"traceEvents");
2271 PrintJSONMeta(events);
2272 PrintJSONEvents(events, *filter);
2274 topLevel.AddPropertyTimeMicros(
"timeOriginMicros", TimeOriginMicros());
2275 topLevel.AddPropertyTimeMicros(
"timeExtentMicros", TimeExtentMicros());
2278#if defined(SUPPORT_PERFETTO)
2279void TimelineEventEndlessRecorder::PrintPerfettoTimeline(
2281 const TimelineEventFilter& filter) {
2282 PRINT_PERFETTO_TIMELINE_BODY
2286void TimelineEventEndlessRecorder::PrintTraceEvent(
2288 TimelineEventFilter* filter) {
2289 JSONArray events(
js);
2290 PrintJSONMeta(events);
2291 PrintJSONEvents(events, *filter);
2295TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() {
2296 ASSERT(lock_.IsOwnedByCurrentThread());
2300TimelineEvent* TimelineEventEndlessRecorder::StartEvent() {
2301 return ThreadBlockStartEvent();
2304void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent*
event) {
2305 if (
event ==
nullptr) {
2308 ThreadBlockCompleteEvent(
event);
2311TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() {
2312 ASSERT(lock_.IsOwnedByCurrentThread());
2313 TimelineEventBlock* block =
new TimelineEventBlock(block_index_++);
2315 if (head_ ==
nullptr) {
2316 head_ = tail_ = block;
2318 tail_->set_next(block);
2321 if (FLAG_trace_timeline) {
2322 OS::PrintErr(
"Created new block %p\n", block);
2327void TimelineEventEndlessRecorder::ClearLocked() {
2328 ASSERT(lock_.IsOwnedByCurrentThread());
2329 TimelineEventBlock* current = head_;
2330 while (current !=
nullptr) {
2331 TimelineEventBlock*
next = current->next();
2340TimelineEventBlock::TimelineEventBlock(intptr_t block_index)
2343 block_index_(block_index),
2344 current_owner_(nullptr),
2347TimelineEventBlock::~TimelineEventBlock() {
2352void TimelineEventBlock::PrintJSON(JSONStream*
js)
const {
2354 JSONArray events(
js);
2355 for (intptr_t
i = 0;
i <
length();
i++) {
2356 const TimelineEvent*
event = At(
i);
2357 if (
event->IsValid()) {
2358 events.AddValue(
event);
2364TimelineEvent* TimelineEventBlock::StartEventLocked() {
2365 OSThread* os_thread = OSThread::Current();
2366 ASSERT(os_thread !=
nullptr);
2367 ASSERT(os_thread == current_owner_);
2368 ASSERT(os_thread->timeline_block_lock()->IsOwnedByCurrentThread());
2370 if (FLAG_trace_timeline) {
2371 intptr_t tid = OSThread::ThreadIdToIntPtr(os_thread->id());
2372 OS::PrintErr(
"StartEvent in block %p for thread %" Pd "\n",
this, tid);
2374 return &events_[length_++];
2377int64_t TimelineEventBlock::LowerTimeBound()
const {
2382 return events_[0].TimeOrigin();
2391 current_owner_ =
nullptr;
2395void TimelineEventBlock::Open() {
2396 OSThread* os_thread = OSThread::Current();
2397 ASSERT(os_thread !=
nullptr);
2398 current_owner_ = os_thread;
2403 if (FLAG_trace_timeline) {
2404 OS::PrintErr(
"Finish block %p\n",
this);
2406 current_owner_ =
nullptr;
2409 if (Service::timeline_stream.enabled()) {
2410 ServiceEvent service_event(ServiceEvent::kTimelineEvents);
2411 service_event.set_timeline_event_block(
this);
2412 Service::HandleEvent(&service_event,
false);
2417void DartTimelineEventHelpers::ReportTaskEvent(
2418 TimelineEvent*
event,
2420 intptr_t flow_id_count,
2421 std::unique_ptr<
const int64_t[]>& flow_ids,
2425 const int64_t
start = OS::GetCurrentMonotonicMicrosForTimeline();
2427 case TimelineEvent::kAsyncInstant:
2430 case TimelineEvent::kAsyncBegin:
2433 case TimelineEvent::kAsyncEnd:
2436 case TimelineEvent::kBegin:
2439 case TimelineEvent::kEnd:
2442 case TimelineEvent::kFlowBegin:
2445 case TimelineEvent::kFlowStep:
2448 case TimelineEvent::kFlowEnd:
2451 case TimelineEvent::kInstant:
2457 if (flow_id_count > 0) {
2458 ASSERT(
type == TimelineEvent::kBegin ||
type == TimelineEvent::kInstant ||
2459 type == TimelineEvent::kAsyncBegin ||
2460 type == TimelineEvent::kAsyncInstant);
2462 event->SetFlowIds(flow_id_count, flow_ids);
2464 event->set_owns_label(
true);
2465 event->CompleteWithPreSerializedArgs(
args);
static float next(float f)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
ax::mojom::Event event_type
static intptr_t ThreadIdToIntPtr(ThreadId id)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static intptr_t ProcessId()
static char * StrDup(const char *s)
static bool StrStartsWith(const char *s, const char *prefix)
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
void set_name(const char *data, size_t size)
void set_legacy_json_value(const char *data, size_t size)
void set_string_value(const char *data, size_t size)
void set_pid(int32_t value)
void set_tid(int32_t value)
void set_thread_name(const char *data, size_t size)
T * set_track_descriptor()
void set_parent_uuid(uint64_t value)
void set_uuid(uint64_t value)
void add_categories(const char *data, size_t size)
void set_type(::perfetto::protos::pbzero::TrackEvent_Type value)
void set_track_uuid(uint64_t value)
void add_flow_ids(uint64_t value)
T * add_debug_annotations()
void set_name(const char *data, size_t size)
void(* Dart_FileWriteCallback)(const void *data, intptr_t length, void *stream)
void(* Dart_FileCloseCallback)(void *stream)
void *(* Dart_FileOpenCallback)(const char *name, bool write)
FlutterSemanticsFlag flag
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
Dart_NativeFunction function
std::variant< Lower, Cross, Upper > EventType
constexpr int64_t kMaxInt64
static void Finish(Thread *thread)
CAllocUniquePtr< char > CStringUniquePtr
void * malloc(size_t size)
static constexpr intptr_t kBlockSize
static void * Allocate(uword size, Zone *zone)
static uint32_t WordHash(uint32_t key)
static void Free(FreeList *free_list, uword address, intptr_t size, bool is_protected)
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
void * calloc(size_t n, size_t size)
void * realloc(void *ptr, size_t size)
static void RoundUp(Vector< char > buffer, int *length, int *decimal_point)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library name
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
const myers::Point & get< 1 >(const myers::Segment &s)
const myers::Point & get< 0 >(const myers::Segment &s)
const myers::Point & get(const myers::Segment &)
static SkString fmt(SkColor4f c)
bool EMSCRIPTEN_KEEPALIVE IsEmpty(const SkPath &path)
#define ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING
#define ISOLATE_SERVICE_ID_FORMAT_STRING
Dart_IsolateGroupId isolate_group
void * isolate_group_data
Dart_Timeline_Event_Type type
Dart_TimelineRecorderEvent_Argument * arguments