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)) {
281void Timeline::Init() {
282 ASSERT(recorder_ ==
nullptr);
283 recorder_ = CreateTimelineRecorder();
285 RecorderSynchronizationLock::Init();
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
308void Timeline::Cleanup() {
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) {
417 free(buffer_[i].value);
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);
455 char*
buffer =
reinterpret_cast<char*
>(
malloc(len + 1));
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;
472void TimelineEventArguments::Free() {
473 if (buffer_ ==
nullptr) {
476 for (intptr_t i = 0; i < length_; i++) {
477 free(buffer_[i].value);
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() {
511void TimelineEvent::Reset() {
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();
645void TimelineEvent::Init(EventType
event_type,
const char* label) {
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);
828 perfetto::protos::pbzero::TrackEvent::Type::TYPE_SLICE_BEGIN);
831inline void AddInstantEventFields(
833 const TimelineEvent&
event) {
834 AddBeginAndInstantEventCommonFields(track_event,
event);
836 perfetto::protos::pbzero::TrackEvent::Type::TYPE_INSTANT);
839inline void AddEndEventFields(
842 perfetto::protos::pbzero::TrackEvent::Type::TYPE_SLICE_END);
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(
1006 Utils::CStringUniquePtr&& track_name)
1007 : pid_(pid), tid_(tid), track_name_(
std::move(track_name)) {}
1009void TimelineTrackMetadata::set_track_name(
1010 Utils::CStringUniquePtr&& track_name) {
1011 track_name_ = std::move(track_name);
1014#if !defined(PRODUCT)
1015void TimelineTrackMetadata::PrintJSON(
const JSONArray& jsarr_events)
const {
1016 JSONObject jsobj(&jsarr_events);
1017 jsobj.AddProperty(
"name",
"thread_name");
1018 jsobj.AddProperty(
"ph",
"M");
1019 jsobj.AddProperty(
"pid", pid());
1020 jsobj.AddProperty(
"tid", tid());
1022 JSONObject jsobj_args(&jsobj,
"args");
1023 jsobj_args.AddPropertyF(
"name",
"%s (%" Pd ")", track_name(), tid());
1024 jsobj_args.AddProperty(
"mode",
"basic");
1028#if defined(SUPPORT_PERFETTO)
1029void TimelineTrackMetadata::PopulateTracePacket(
1031 perfetto_utils::SetTrustedPacketSequenceId(track_descriptor_packet);
1040 thread_descriptor.
set_pid(pid());
1041 thread_descriptor.
set_tid(tid());
1047AsyncTimelineTrackMetadata::AsyncTimelineTrackMetadata(intptr_t pid,
1049 : pid_(pid), async_id_(async_id) {}
1051#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1052void AsyncTimelineTrackMetadata::PopulateTracePacket(
1054 perfetto_utils::SetTrustedPacketSequenceId(track_descriptor_packet);
1058 track_descriptor.
set_uuid(async_id());
1062TimelineStream::TimelineStream(
const char*
name,
1063 const char* fuchsia_name,
1064 bool has_static_labels,
1067 fuchsia_name_(fuchsia_name),
1068#
if defined(DART_HOST_OS_FUCHSIA)
1069 enabled_(static_cast<uintptr_t>(
true))
1071 enabled_(static_cast<uintptr_t>(enabled))
1074#if defined(DART_HOST_OS_MACOS)
1075 macos_log_ = os_log_create(
"Dart",
name);
1076 has_static_labels_ = has_static_labels;
1080TimelineEvent* TimelineStream::StartEvent() {
1087 RecorderSynchronizationLock::EnterLock();
1088 TimelineEventRecorder* recorder = Timeline::recorder();
1089 if (!enabled() || (recorder ==
nullptr) ||
1090 !RecorderSynchronizationLock::IsActive()) {
1091 RecorderSynchronizationLock::ExitLock();
1094 ASSERT(name_ !=
nullptr);
1095 TimelineEvent*
event = recorder->StartEvent();
1096 if (
event ==
nullptr) {
1097 RecorderSynchronizationLock::ExitLock();
1100 event->StreamInit(
this);
1104TimelineEventScope::TimelineEventScope(TimelineStream* stream,
1106 : StackResource(static_cast<Thread*>(nullptr)),
1113TimelineEventScope::TimelineEventScope(Thread* thread,
1114 TimelineStream* stream,
1116 : StackResource(thread), stream_(
stream), label_(label), enabled_(
false) {
1120TimelineEventScope::~TimelineEventScope() {}
1122void TimelineEventScope::Init() {
1123 ASSERT(enabled_ ==
false);
1124 ASSERT(label_ !=
nullptr);
1125 ASSERT(stream_ !=
nullptr);
1126 if (!stream_->enabled()) {
1131 Thread* thread =
static_cast<Thread*
>(this->thread());
1132 if (thread !=
nullptr) {
1133 id_ = thread->GetNextTaskId();
1135 static RelaxedAtomic<int64_t> next_bootstrap_task_id = {0};
1136 id_ = next_bootstrap_task_id.fetch_add(1);
1140void TimelineEventScope::SetNumArguments(intptr_t
length) {
1144 arguments_.SetNumArguments(
length);
1148void TimelineEventScope::SetArgument(intptr_t i,
1154 arguments_.SetArgument(i,
name, argument);
1158void TimelineEventScope::CopyArgument(intptr_t i,
1160 const char* argument) {
1164 arguments_.CopyArgument(i,
name, argument);
1167void TimelineEventScope::FormatArgument(intptr_t i,
1180void TimelineEventScope::StealArguments(TimelineEvent*
event) {
1181 if (
event ==
nullptr) {
1184 event->StealArguments(&arguments_);
1187TimelineBeginEndScope::TimelineBeginEndScope(TimelineStream* stream,
1189 : TimelineEventScope(
stream, label) {
1193TimelineBeginEndScope::TimelineBeginEndScope(Thread* thread,
1194 TimelineStream* stream,
1196 : TimelineEventScope(thread,
stream, label) {
1200TimelineBeginEndScope::~TimelineBeginEndScope() {
1204void TimelineBeginEndScope::EmitBegin() {
1205 if (!ShouldEmitEvent()) {
1208 TimelineEvent*
event =
stream()->StartEvent();
1209 if (
event ==
nullptr) {
1216 event->Begin(label(),
id());
1220void TimelineBeginEndScope::EmitEnd() {
1221 if (!ShouldEmitEvent()) {
1224 TimelineEvent*
event =
stream()->StartEvent();
1225 if (
event ==
nullptr) {
1232 event->End(label(),
id());
1233 StealArguments(
event);
1237bool TimelineEventBlock::InUseLocked()
const {
1238 ASSERT(Timeline::recorder()->lock_.IsOwnedByCurrentThread());
1242bool TimelineEventBlock::ContainsEventsThatCanBeSerializedLocked()
const {
1243 ASSERT(Timeline::recorder()->lock_.IsOwnedByCurrentThread());
1248 return !InUseLocked() && !IsEmpty();
1251TimelineEventFilter::TimelineEventFilter(int64_t time_origin_micros,
1252 int64_t time_extent_micros)
1253 : time_origin_micros_(time_origin_micros),
1254 time_extent_micros_(time_extent_micros) {
1255 ASSERT(time_origin_micros_ >= -1);
1256 ASSERT(time_extent_micros_ >= -1);
1259TimelineEventFilter::~TimelineEventFilter() {}
1261IsolateTimelineEventFilter::IsolateTimelineEventFilter(
1263 int64_t time_origin_micros,
1264 int64_t time_extent_micros)
1265 : TimelineEventFilter(time_origin_micros, time_extent_micros),
1266 isolate_id_(isolate_id) {}
1268TimelineEventRecorder::TimelineEventRecorder()
1269 : time_low_micros_(0),
1270 time_high_micros_(0),
1271 track_uuid_to_track_metadata_lock_(),
1272 track_uuid_to_track_metadata_(
1273 &SimpleHashMap::SamePointerValue,
1274 TimelineEventRecorder::kTrackUuidToTrackMetadataInitialCapacity),
1275 async_track_uuid_to_track_metadata_lock_(),
1276 async_track_uuid_to_track_metadata_(
1277 &SimpleHashMap::SamePointerValue,
1278 TimelineEventRecorder::kTrackUuidToTrackMetadataInitialCapacity) {}
1280TimelineEventRecorder::~TimelineEventRecorder() {
1284 for (SimpleHashMap::Entry* entry = track_uuid_to_track_metadata_.Start();
1285 entry !=
nullptr; entry = track_uuid_to_track_metadata_.Next(entry)) {
1286 TimelineTrackMetadata*
value =
1287 static_cast<TimelineTrackMetadata*
>(entry->value);
1290 for (SimpleHashMap::Entry* entry =
1291 async_track_uuid_to_track_metadata_.Start();
1293 entry = async_track_uuid_to_track_metadata_.Next(entry)) {
1294 AsyncTimelineTrackMetadata*
value =
1295 static_cast<AsyncTimelineTrackMetadata*
>(entry->value);
1301void TimelineEventRecorder::PrintJSONMeta(
const JSONArray& jsarr_events) {
1302 MutexLocker ml(&track_uuid_to_track_metadata_lock_);
1303 for (SimpleHashMap::Entry* entry = track_uuid_to_track_metadata_.Start();
1304 entry !=
nullptr; entry = track_uuid_to_track_metadata_.Next(entry)) {
1305 TimelineTrackMetadata*
value =
1306 static_cast<TimelineTrackMetadata*
>(entry->value);
1307 value->PrintJSON(jsarr_events);
1311#if defined(SUPPORT_PERFETTO)
1312void TimelineEventRecorder::PrintPerfettoMeta(
1313 JSONBase64String* jsonBase64String) {
1314 ASSERT(jsonBase64String !=
nullptr);
1316 perfetto_utils::PopulateClockSnapshotPacket(packet_.get());
1317 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, &packet_);
1319 perfetto_utils::PopulateProcessDescriptorPacket(packet_.get());
1320 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, &packet_);
1324 MutexLocker ml(&async_track_uuid_to_track_metadata_lock_);
1325 for (SimpleHashMap::Entry* entry =
1326 async_track_uuid_to_track_metadata_.Start();
1328 entry = async_track_uuid_to_track_metadata_.Next(entry)) {
1329 AsyncTimelineTrackMetadata*
value =
1330 static_cast<AsyncTimelineTrackMetadata*
>(entry->value);
1331 value->PopulateTracePacket(packet_.get());
1332 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
1339 MutexLocker ml(&track_uuid_to_track_metadata_lock_);
1340 for (SimpleHashMap::Entry* entry = track_uuid_to_track_metadata_.Start();
1341 entry !=
nullptr; entry = track_uuid_to_track_metadata_.Next(entry)) {
1342 TimelineTrackMetadata*
value =
1343 static_cast<TimelineTrackMetadata*
>(entry->value);
1344 value->PopulateTracePacket(packet_.get());
1345 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
1354TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
1356 OSThread* thread = OSThread::Current();
1357 ASSERT(thread !=
nullptr);
1361 Mutex& recorder_lock = lock_;
1362 recorder_lock.Lock();
1363 Mutex* thread_block_lock = thread->timeline_block_lock();
1364 ASSERT(thread_block_lock !=
nullptr);
1367 thread_block_lock->Lock();
1369 Thread*
T = Thread::Current();
1371 T->IncrementNoSafepointScopeDepth();
1375 TimelineEventBlock* thread_block = thread->TimelineBlockLocked();
1377 if ((thread_block !=
nullptr) && thread_block->IsFull()) {
1380 thread->SetTimelineBlockLocked(
nullptr);
1381 FinishBlock(thread_block);
1385 thread_block_lock->Unlock();
1386 thread_block = GetNewBlockLocked();
1387 thread_block_lock->Lock();
1388 thread->SetTimelineBlockLocked(thread_block);
1389 }
else if (thread_block ==
nullptr) {
1393 thread_block_lock->Unlock();
1394 thread_block = GetNewBlockLocked();
1395 thread_block_lock->Lock();
1396 thread->SetTimelineBlockLocked(thread_block);
1398 recorder_lock.Unlock();
1399 if (thread_block !=
nullptr) {
1401 ASSERT(!thread_block->IsFull());
1402 TimelineEvent*
event = thread_block->StartEventLocked();
1408 T->DecrementNoSafepointScopeDepth();
1411 thread_block_lock->Unlock();
1415void TimelineEventRecorder::ResetTimeTracking() {
1416 time_high_micros_ = 0;
1420void TimelineEventRecorder::ReportTime(int64_t micros) {
1421 if (time_high_micros_ < micros) {
1422 time_high_micros_ = micros;
1424 if (time_low_micros_ > micros) {
1425 time_low_micros_ = micros;
1429int64_t TimelineEventRecorder::TimeOriginMicros()
const {
1430 if (time_high_micros_ == 0) {
1433 return time_low_micros_;
1436int64_t TimelineEventRecorder::TimeExtentMicros()
const {
1437 if (time_high_micros_ == 0) {
1440 return time_high_micros_ - time_low_micros_;
1443void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent*
event) {
1444 if (
event ==
nullptr) {
1447#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1451 if (
event->event_type() == TimelineEvent::kAsyncBegin ||
1452 event->event_type() == TimelineEvent::kAsyncInstant) {
1453 AddAsyncTrackMetadataBasedOnEvent(*
event);
1457 OSThread* thread = OSThread::Current();
1458 ASSERT(thread !=
nullptr);
1460 Mutex* thread_block_lock = thread->timeline_block_lock();
1461 ASSERT(thread_block_lock !=
nullptr);
1463 Thread*
T = Thread::Current();
1465 T->DecrementNoSafepointScopeDepth();
1468 thread_block_lock->Unlock();
1472void TimelineEventRecorder::WriteTo(
const char* directory) {
1476 if ((file_open ==
nullptr) || (file_write ==
nullptr) ||
1477 (file_close ==
nullptr)) {
1478 OS::PrintErr(
"warning: Could not access file callbacks.");
1484 MutexLocker ml(&lock_);
1485 Timeline::ReclaimCachedBlocksFromThreads();
1487 intptr_t pid = OS::ProcessId();
1489 OS::SCreate(
nullptr,
"%s/dart-timeline-%" Pd ".json", directory, pid);
1490 void*
file = (*file_open)(filename,
true);
1491 if (file ==
nullptr) {
1492 OS::PrintErr(
"warning: Failed to write timeline file: %s\n", filename);
1499 TimelineEventFilter filter;
1500 PrintTraceEvent(&js, &filter);
1503 intptr_t output_length = 0;
1504 js.Steal(&output, &output_length);
1508 (*file_close)(
file);
1514void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) {
1515 if (block !=
nullptr) {
1520void TimelineEventRecorder::AddTrackMetadataBasedOnThread(
1521 const intptr_t process_id,
1522 const intptr_t trace_id,
1523 const char* thread_name) {
1524 ASSERT(FLAG_timeline_recorder !=
nullptr);
1525 if (strcmp(
"none", FLAG_timeline_recorder) == 0 ||
1526 strcmp(
"callback", FLAG_timeline_recorder) == 0 ||
1527 strcmp(
"systrace", FLAG_timeline_recorder) == 0 ||
1528 FLAG_systrace_timeline) {
1534 MutexLocker ml(&track_uuid_to_track_metadata_lock_);
1536 void*
key =
reinterpret_cast<void*
>(trace_id);
1537 const intptr_t
hash = Utils::WordHash(trace_id);
1538 SimpleHashMap::Entry* entry =
1539 track_uuid_to_track_metadata_.Lookup(
key,
hash,
true);
1540 if (entry->value ==
nullptr) {
1541 entry->value =
new TimelineTrackMetadata(
1542 process_id, trace_id,
1543 Utils::CreateCStringUniquePtr(
1544 Utils::StrDup(thread_name ==
nullptr ?
"" : thread_name)));
1546 TimelineTrackMetadata*
value =
1547 static_cast<TimelineTrackMetadata*
>(entry->value);
1549 value->set_track_name(Utils::CreateCStringUniquePtr(
1550 Utils::StrDup(thread_name ==
nullptr ?
"" : thread_name)));
1554#if !defined(PRODUCT)
1555void TimelineEventRecorder::AddAsyncTrackMetadataBasedOnEvent(
1556 const TimelineEvent&
event) {
1557 ASSERT(FLAG_timeline_recorder !=
nullptr);
1558 if (strcmp(
"none", FLAG_timeline_recorder) == 0 ||
1559 strcmp(
"callback", FLAG_timeline_recorder) == 0 ||
1560 strcmp(
"systrace", FLAG_timeline_recorder) == 0 ||
1561 FLAG_systrace_timeline) {
1567 MutexLocker ml(&async_track_uuid_to_track_metadata_lock_);
1569 void*
key =
reinterpret_cast<void*
>(
event.Id());
1570 const intptr_t
hash = Utils::WordHash(
event.Id());
1571 SimpleHashMap::Entry* entry =
1572 async_track_uuid_to_track_metadata_.Lookup(
key,
hash,
true);
1573 if (entry->value ==
nullptr) {
1574 entry->value =
new AsyncTimelineTrackMetadata(OS::ProcessId(),
event.Id());
1579TimelineEventFixedBufferRecorder::TimelineEventFixedBufferRecorder(
1583 capacity_(capacity),
1587 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0);
1589 num_blocks_ = capacity / TimelineEventBlock::kBlockSize;
1591 intptr_t
size = Utils::RoundUp(num_blocks_ *
sizeof(TimelineEventBlock),
1592 VirtualMemory::PageSize());
1593 const bool executable =
false;
1594 const bool compressed =
false;
1596 VirtualMemory::Allocate(size, executable, compressed,
"dart-timeline");
1597 if (memory_ ==
nullptr) {
1600 blocks_ =
reinterpret_cast<TimelineEventBlock*
>(memory_->address());
1603TimelineEventFixedBufferRecorder::~TimelineEventFixedBufferRecorder() {
1610intptr_t TimelineEventFixedBufferRecorder::Size() {
1611 return memory_->size();
1615void TimelineEventFixedBufferRecorder::PrintEventsCommon(
1616 const TimelineEventFilter& filter,
1617 std::function<
void(
const TimelineEvent&)>&& print_impl) {
1620 MutexLocker ml(&lock_);
1621 Timeline::ReclaimCachedBlocksFromThreads();
1622 ResetTimeTracking();
1623 intptr_t block_offset = FindOldestBlockIndexLocked();
1624 if (block_offset == -1) {
1628 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) {
1629 TimelineEventBlock* block =
1630 &blocks_[(block_idx + block_offset) % num_blocks_];
1631 if (!block->ContainsEventsThatCanBeSerializedLocked()) {
1634 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) {
1635 TimelineEvent*
event = block->At(event_idx);
1636 if (filter.IncludeEvent(
event) &&
1637 event->Within(filter.time_origin_micros(),
1638 filter.time_extent_micros())) {
1639 ReportTime(
event->LowTime());
1640 ReportTime(
event->HighTime());
1647void TimelineEventFixedBufferRecorder::PrintJSONEvents(
1648 const JSONArray& events,
1649 const TimelineEventFilter& filter) {
1650 PrintEventsCommon(filter, [&events](
const TimelineEvent&
event) {
1651 events.AddValue(&
event);
1655#if defined(SUPPORT_PERFETTO)
1660inline void PrintPerfettoEventCallbackBody(
1661 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
1662 heap_buffered_packet,
1663 const TimelineEvent&
event,
1664 const std::function<
1665 void(protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*)>&&
1667 ASSERT(heap_buffered_packet !=
nullptr);
1668 if (!
event.CanBeRepresentedByPerfettoTracePacket()) {
1671 if (
event.IsDuration()) {
1675 *heap_buffered_packet->get();
1677 perfetto_utils::SetTrustedPacketSequenceId(&packet);
1678 perfetto_utils::SetTimestampAndMonotonicClockId(&packet,
1679 event.TimeOrigin());
1684 AddSyncEventFields(track_event,
event);
1685 AddBeginEventFields(track_event,
event);
1686 AddDebugAnnotations(track_event,
event);
1688 print_callback(heap_buffered_packet);
1689 heap_buffered_packet->Reset();
1692 perfetto_utils::SetTrustedPacketSequenceId(&packet);
1693 perfetto_utils::SetTimestampAndMonotonicClockId(&packet,
event.TimeEnd());
1698 AddSyncEventFields(track_event,
event);
1699 AddEndEventFields(track_event);
1700 AddDebugAnnotations(track_event,
event);
1703 event.PopulateTracePacket(heap_buffered_packet->get());
1705 print_callback(heap_buffered_packet);
1706 heap_buffered_packet->Reset();
1709void TimelineEventFixedBufferRecorder::PrintPerfettoEvents(
1710 JSONBase64String* jsonBase64String,
1711 const TimelineEventFilter& filter) {
1713 filter, [
this, &jsonBase64String](
const TimelineEvent&
event) {
1714 PrintPerfettoEventCallbackBody(
1716 [&jsonBase64String](
1717 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
1719 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
1726void TimelineEventFixedBufferRecorder::PrintJSON(JSONStream* js,
1727 TimelineEventFilter* filter) {
1728 JSONObject topLevel(js);
1729 topLevel.AddProperty(
"type",
"Timeline");
1731 JSONArray events(&topLevel,
"traceEvents");
1732 PrintJSONMeta(events);
1733 PrintJSONEvents(events, *filter);
1735 topLevel.AddPropertyTimeMicros(
"timeOriginMicros", TimeOriginMicros());
1736 topLevel.AddPropertyTimeMicros(
"timeExtentMicros", TimeExtentMicros());
1739#define PRINT_PERFETTO_TIMELINE_BODY \
1740 JSONObject jsobj_topLevel(js); \
1741 jsobj_topLevel.AddProperty("type", "PerfettoTimeline"); \
1743 js->AppendSerializedObject("\"trace\":"); \
1745 JSONBase64String jsonBase64String(js); \
1746 PrintPerfettoMeta(&jsonBase64String); \
1747 PrintPerfettoEvents(&jsonBase64String, filter); \
1750 jsobj_topLevel.AddPropertyTimeMicros("timeOriginMicros", \
1751 TimeOriginMicros()); \
1752 jsobj_topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros());
1754#if defined(SUPPORT_PERFETTO)
1755void TimelineEventFixedBufferRecorder::PrintPerfettoTimeline(
1757 const TimelineEventFilter& filter) {
1758 PRINT_PERFETTO_TIMELINE_BODY
1762void TimelineEventFixedBufferRecorder::PrintTraceEvent(
1764 TimelineEventFilter* filter) {
1765 JSONArray events(js);
1766 PrintJSONMeta(events);
1767 PrintJSONEvents(events, *filter);
1771TimelineEventBlock* TimelineEventFixedBufferRecorder::GetHeadBlockLocked() {
1772 ASSERT(lock_.IsOwnedByCurrentThread());
1776void TimelineEventFixedBufferRecorder::ClearLocked() {
1777 ASSERT(lock_.IsOwnedByCurrentThread());
1778 for (intptr_t i = 0; i < num_blocks_; i++) {
1779 TimelineEventBlock* block = &blocks_[i];
1784intptr_t TimelineEventFixedBufferRecorder::FindOldestBlockIndexLocked()
const {
1785 ASSERT(lock_.IsOwnedByCurrentThread());
1787 intptr_t earliest_index = -1;
1788 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) {
1789 TimelineEventBlock* block = &blocks_[block_idx];
1790 if (!block->ContainsEventsThatCanBeSerializedLocked()) {
1794 if (block->LowerTimeBound() < earliest_time) {
1795 earliest_time = block->LowerTimeBound();
1796 earliest_index = block_idx;
1799 return earliest_index;
1802TimelineEvent* TimelineEventFixedBufferRecorder::StartEvent() {
1803 return ThreadBlockStartEvent();
1806void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent*
event) {
1807 if (
event ==
nullptr) {
1810 ThreadBlockCompleteEvent(
event);
1813TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() {
1814 ASSERT(lock_.IsOwnedByCurrentThread());
1815 if (block_cursor_ == num_blocks_) {
1818 TimelineEventBlock* block = &blocks_[block_cursor_++];
1819 if (block->current_owner_ !=
nullptr) {
1820 MutexLocker ml(block->current_owner_->timeline_block_lock());
1821 block->current_owner_->SetTimelineBlockLocked(
nullptr);
1831TimelineEventBlock* TimelineEventStartupRecorder::GetNewBlockLocked() {
1832 ASSERT(lock_.IsOwnedByCurrentThread());
1833 if (block_cursor_ == num_blocks_) {
1836 TimelineEventBlock* block = &blocks_[block_cursor_++];
1842TimelineEventCallbackRecorder::TimelineEventCallbackRecorder() {}
1844TimelineEventCallbackRecorder::~TimelineEventCallbackRecorder() {}
1847void TimelineEventCallbackRecorder::PrintJSON(JSONStream* js,
1848 TimelineEventFilter* filter) {
1852#if defined(SUPPORT_PERFETTO)
1853void TimelineEventCallbackRecorder::PrintPerfettoTimeline(
1855 const TimelineEventFilter& filter) {
1860void TimelineEventCallbackRecorder::PrintTraceEvent(
1862 TimelineEventFilter* filter) {
1863 JSONArray events(js);
1867TimelineEvent* TimelineEventCallbackRecorder::StartEvent() {
1868 TimelineEvent*
event =
new TimelineEvent();
1872void TimelineEventCallbackRecorder::CompleteEvent(TimelineEvent*
event) {
1877void TimelineEventEmbedderCallbackRecorder::OnEvent(TimelineEvent*
event) {
1885 switch (
event->event_type()) {
1886 case TimelineEvent::kBegin:
1889 case TimelineEvent::kEnd:
1892 case TimelineEvent::kInstant:
1895 case TimelineEvent::kDuration:
1898 case TimelineEvent::kAsyncBegin:
1901 case TimelineEvent::kAsyncEnd:
1904 case TimelineEvent::kAsyncInstant:
1907 case TimelineEvent::kCounter:
1910 case TimelineEvent::kFlowBegin:
1913 case TimelineEvent::kFlowStep:
1916 case TimelineEvent::kFlowEnd:
1923 recorder_event.
timestamp0 =
event->timestamp0();
1925 recorder_event.
isolate =
event->isolate_id();
1929 recorder_event.
label =
event->label();
1930 recorder_event.
stream =
event->stream()->name();
1934 event->arguments());
1936 NoActiveIsolateScope no_active_isolate_scope;
1940void TimelineEventNopRecorder::OnEvent(TimelineEvent*
event) {
1944TimelineEventPlatformRecorder::TimelineEventPlatformRecorder() {}
1946TimelineEventPlatformRecorder::~TimelineEventPlatformRecorder() {}
1949void TimelineEventPlatformRecorder::PrintJSON(JSONStream* js,
1950 TimelineEventFilter* filter) {
1954#if defined(SUPPORT_PERFETTO)
1955void TimelineEventPlatformRecorder::PrintPerfettoTimeline(
1957 const TimelineEventFilter& filter) {
1962void TimelineEventPlatformRecorder::PrintTraceEvent(
1964 TimelineEventFilter* filter) {
1965 JSONArray events(js);
1969TimelineEvent* TimelineEventPlatformRecorder::StartEvent() {
1970 TimelineEvent*
event =
new TimelineEvent();
1974void TimelineEventPlatformRecorder::CompleteEvent(TimelineEvent*
event) {
1979static void TimelineEventFileRecorderBaseStart(uword parameter) {
1980 reinterpret_cast<TimelineEventFileRecorderBase*
>(parameter)->Drain();
1983TimelineEventFileRecorderBase::TimelineEventFileRecorderBase(
const char* path)
1984 : TimelineEventPlatformRecorder(),
1989 shutting_down_(
false),
1991 thread_id_(OSThread::kInvalidThreadJoinId) {
1995 if ((file_open ==
nullptr) || (file_write ==
nullptr) ||
1996 (file_close ==
nullptr)) {
1997 OS::PrintErr(
"warning: Could not access file callbacks.");
2000 void*
file = (*file_open)(
path,
true);
2001 if (file ==
nullptr) {
2002 OS::PrintErr(
"warning: Failed to open timeline file: %s\n", path);
2009TimelineEventFileRecorderBase::~TimelineEventFileRecorderBase() {
2016 if (file_ ==
nullptr)
return;
2018 ASSERT(thread_id_ != OSThread::kInvalidThreadJoinId);
2019 OSThread::Join(thread_id_);
2020 thread_id_ = OSThread::kInvalidThreadJoinId;
2022 TimelineEvent*
event = head_;
2023 while (
event !=
nullptr) {
2024 TimelineEvent*
next =
event->next();
2028 head_ = tail_ =
nullptr;
2031 (*file_close)(file_);
2035void TimelineEventFileRecorderBase::Drain() {
2036 MonitorLocker ml(&monitor_);
2037 thread_id_ = OSThread::GetCurrentThreadJoinId(OSThread::Current());
2038 while (!shutting_down_) {
2039 if (head_ ==
nullptr) {
2043 TimelineEvent*
event = head_;
2044 TimelineEvent*
next =
event->next();
2046 if (
next ==
nullptr) {
2060void TimelineEventFileRecorderBase::Write(
const char*
buffer,
2061 intptr_t len)
const {
2066void TimelineEventFileRecorderBase::CompleteEvent(TimelineEvent*
event) {
2067 if (
event ==
nullptr) {
2070 if (file_ ==
nullptr) {
2075 MonitorLocker ml(&monitor_);
2077 event->set_next(
nullptr);
2078 if (tail_ ==
nullptr) {
2079 head_ = tail_ =
event;
2081 tail_->set_next(
event);
2089void TimelineEventFileRecorderBase::ShutDown() {
2090 MonitorLocker ml(&monitor_);
2091 shutting_down_ =
true;
2098TimelineEventFileRecorder::TimelineEventFileRecorder(
const char* path)
2099 : TimelineEventFileRecorderBase(
path), first_(
true) {
2107 OSThread::Start(
"TimelineEventFileRecorder",
2108 TimelineEventFileRecorderBaseStart,
2109 reinterpret_cast<uword>(
this));
2112TimelineEventFileRecorder::~TimelineEventFileRecorder() {
2117void TimelineEventFileRecorder::DrainImpl(
const TimelineEvent&
event) {
2122 writer.buffer()->AddChar(
',');
2124 event.PrintJSON(&writer);
2126 intptr_t output_length = 0;
2127 writer.Steal(&output, &output_length);
2128 Write(output, output_length);
2132#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
2133TimelineEventPerfettoFileRecorder::TimelineEventPerfettoFileRecorder(
2135 : TimelineEventFileRecorderBase(
path) {
2136 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet =
2139 perfetto_utils::PopulateClockSnapshotPacket(packet.get());
2140 WritePacket(&packet);
2143 perfetto_utils::PopulateProcessDescriptorPacket(packet.get());
2144 WritePacket(&packet);
2147 OSThread::Start(
"TimelineEventPerfettoFileRecorder",
2148 TimelineEventFileRecorderBaseStart,
2149 reinterpret_cast<uword>(
this));
2152TimelineEventPerfettoFileRecorder::~TimelineEventPerfettoFileRecorder() {
2153 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet =
2159 for (SimpleHashMap::Entry* entry = track_uuid_to_track_metadata().Start();
2160 entry !=
nullptr; entry = track_uuid_to_track_metadata().Next(entry)) {
2161 TimelineTrackMetadata*
value =
2162 static_cast<TimelineTrackMetadata*
>(entry->value);
2163 value->PopulateTracePacket(packet.get());
2164 WritePacket(&packet);
2167 for (SimpleHashMap::Entry* entry =
2168 async_track_uuid_to_track_metadata().Start();
2170 entry = async_track_uuid_to_track_metadata().Next(entry)) {
2171 AsyncTimelineTrackMetadata*
value =
2172 static_cast<AsyncTimelineTrackMetadata*
>(entry->value);
2173 value->PopulateTracePacket(packet.get());
2174 WritePacket(&packet);
2179void TimelineEventPerfettoFileRecorder::WritePacket(
2180 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
2182 const std::tuple<std::unique_ptr<const uint8_t[]>, intptr_t>& response =
2183 perfetto_utils::GetProtoPreamble(packet);
2184 Write(
reinterpret_cast<const char*
>(std::get<0>(response).
get()),
2185 std::get<1>(response));
2186 for (
const protozero::ScatteredHeapBuffer::Slice& slice :
2187 packet->GetSlices()) {
2188 Write(
reinterpret_cast<char*
>(slice.start()),
2189 slice.size() - slice.unused_bytes());
2193void TimelineEventPerfettoFileRecorder::DrainImpl(
const TimelineEvent&
event) {
2194 PrintPerfettoEventCallbackBody(
2196 [
this](protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
2197 packet) { WritePacket(packet); });
2199 if (
event.event_type() == TimelineEvent::kAsyncBegin ||
2200 event.event_type() == TimelineEvent::kAsyncInstant) {
2201 AddAsyncTrackMetadataBasedOnEvent(
event);
2206TimelineEventEndlessRecorder::TimelineEventEndlessRecorder()
2207 : head_(nullptr), tail_(nullptr), block_index_(0) {}
2209TimelineEventEndlessRecorder::~TimelineEventEndlessRecorder() {
2210 ASSERT(head_ ==
nullptr);
2214void TimelineEventEndlessRecorder::PrintEventsCommon(
2215 const TimelineEventFilter& filter,
2216 std::function<
void(
const TimelineEvent&)>&& print_impl) {
2219 MutexLocker ml(&lock_);
2220 Timeline::ReclaimCachedBlocksFromThreads();
2221 ResetTimeTracking();
2222 for (TimelineEventBlock* current = head_; current !=
nullptr;
2223 current = current->next()) {
2224 if (!current->ContainsEventsThatCanBeSerializedLocked()) {
2227 intptr_t
length = current->length();
2228 for (intptr_t i = 0; i <
length; i++) {
2229 TimelineEvent*
event = current->At(i);
2230 if (filter.IncludeEvent(
event) &&
2231 event->Within(filter.time_origin_micros(),
2232 filter.time_extent_micros())) {
2233 ReportTime(
event->LowTime());
2234 ReportTime(
event->HighTime());
2241void TimelineEventEndlessRecorder::PrintJSONEvents(
2242 const JSONArray& events,
2243 const TimelineEventFilter& filter) {
2244 PrintEventsCommon(filter, [&events](
const TimelineEvent&
event) {
2245 events.AddValue(&
event);
2249#if defined(SUPPORT_PERFETTO)
2250void TimelineEventEndlessRecorder::PrintPerfettoEvents(
2251 JSONBase64String* jsonBase64String,
2252 const TimelineEventFilter& filter) {
2254 filter, [
this, &jsonBase64String](
const TimelineEvent&
event) {
2255 PrintPerfettoEventCallbackBody(
2257 [&jsonBase64String](
2258 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
2260 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String,
2267void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js,
2268 TimelineEventFilter* filter) {
2269 JSONObject topLevel(js);
2270 topLevel.AddProperty(
"type",
"Timeline");
2272 JSONArray events(&topLevel,
"traceEvents");
2273 PrintJSONMeta(events);
2274 PrintJSONEvents(events, *filter);
2276 topLevel.AddPropertyTimeMicros(
"timeOriginMicros", TimeOriginMicros());
2277 topLevel.AddPropertyTimeMicros(
"timeExtentMicros", TimeExtentMicros());
2280#if defined(SUPPORT_PERFETTO)
2281void TimelineEventEndlessRecorder::PrintPerfettoTimeline(
2283 const TimelineEventFilter& filter) {
2284 PRINT_PERFETTO_TIMELINE_BODY
2288void TimelineEventEndlessRecorder::PrintTraceEvent(
2290 TimelineEventFilter* filter) {
2291 JSONArray events(js);
2292 PrintJSONMeta(events);
2293 PrintJSONEvents(events, *filter);
2297TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() {
2298 ASSERT(lock_.IsOwnedByCurrentThread());
2302TimelineEvent* TimelineEventEndlessRecorder::StartEvent() {
2303 return ThreadBlockStartEvent();
2306void TimelineEventEndlessRecorder::CompleteEvent(TimelineEvent*
event) {
2307 if (
event ==
nullptr) {
2310 ThreadBlockCompleteEvent(
event);
2313TimelineEventBlock* TimelineEventEndlessRecorder::GetNewBlockLocked() {
2314 ASSERT(lock_.IsOwnedByCurrentThread());
2315 TimelineEventBlock* block =
new TimelineEventBlock(block_index_++);
2317 if (head_ ==
nullptr) {
2318 head_ = tail_ = block;
2320 tail_->set_next(block);
2323 if (FLAG_trace_timeline) {
2324 OS::PrintErr(
"Created new block %p\n", block);
2329void TimelineEventEndlessRecorder::ClearLocked() {
2330 ASSERT(lock_.IsOwnedByCurrentThread());
2331 TimelineEventBlock* current = head_;
2332 while (current !=
nullptr) {
2333 TimelineEventBlock*
next = current->next();
2342TimelineEventBlock::TimelineEventBlock(intptr_t block_index)
2345 block_index_(block_index),
2346 current_owner_(nullptr),
2349TimelineEventBlock::~TimelineEventBlock() {
2354void TimelineEventBlock::PrintJSON(JSONStream* js)
const {
2356 JSONArray events(js);
2357 for (intptr_t i = 0; i <
length(); i++) {
2358 const TimelineEvent*
event = At(i);
2359 if (
event->IsValid()) {
2360 events.AddValue(
event);
2366TimelineEvent* TimelineEventBlock::StartEventLocked() {
2367 OSThread* os_thread = OSThread::Current();
2368 ASSERT(os_thread !=
nullptr);
2369 ASSERT(os_thread == current_owner_);
2370 ASSERT(os_thread->timeline_block_lock()->IsOwnedByCurrentThread());
2372 if (FLAG_trace_timeline) {
2373 intptr_t tid = OSThread::ThreadIdToIntPtr(os_thread->id());
2374 OS::PrintErr(
"StartEvent in block %p for thread %" Pd "\n",
this, tid);
2376 return &events_[length_++];
2379int64_t TimelineEventBlock::LowerTimeBound()
const {
2384 return events_[0].TimeOrigin();
2387void TimelineEventBlock::Reset() {
2388 for (intptr_t i = 0; i < kBlockSize; i++) {
2393 current_owner_ =
nullptr;
2397void TimelineEventBlock::Open() {
2398 OSThread* os_thread = OSThread::Current();
2399 ASSERT(os_thread !=
nullptr);
2400 current_owner_ = os_thread;
2404void TimelineEventBlock::Finish() {
2405 if (FLAG_trace_timeline) {
2406 OS::PrintErr(
"Finish block %p\n",
this);
2408 current_owner_ =
nullptr;
2411 if (Service::timeline_stream.enabled()) {
2412 ServiceEvent service_event(ServiceEvent::kTimelineEvents);
2413 service_event.set_timeline_event_block(
this);
2414 Service::HandleEvent(&service_event,
false);
2419void DartTimelineEventHelpers::ReportTaskEvent(
2420 TimelineEvent*
event,
2422 intptr_t flow_id_count,
2423 std::unique_ptr<
const int64_t[]>& flow_ids,
2427 const int64_t
start = OS::GetCurrentMonotonicMicrosForTimeline();
2428 switch (
static_cast<TimelineEvent::EventType
>(
type)) {
2429 case TimelineEvent::kAsyncInstant:
2432 case TimelineEvent::kAsyncBegin:
2435 case TimelineEvent::kAsyncEnd:
2438 case TimelineEvent::kBegin:
2441 case TimelineEvent::kEnd:
2444 case TimelineEvent::kFlowBegin:
2447 case TimelineEvent::kFlowStep:
2450 case TimelineEvent::kFlowEnd:
2453 case TimelineEvent::kInstant:
2459 if (flow_id_count > 0) {
2460 ASSERT(
type == TimelineEvent::kBegin ||
type == TimelineEvent::kInstant ||
2461 type == TimelineEvent::kAsyncBegin ||
2462 type == TimelineEvent::kAsyncInstant);
2464 event->SetFlowIds(flow_id_count, flow_ids);
2466 event->set_owns_label(
true);
2467 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
static const uint8_t buffer[]
#define DEFINE_FLAG(type, name, default_value, comment)
constexpr int64_t kMaxInt64
void * malloc(size_t size)
static void Free(FreeList *free_list, uword address, intptr_t size, bool is_protected)
void * calloc(size_t n, size_t size)
void * realloc(void *ptr, size_t size)
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
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(const myers::Segment &)
static SkString fmt(SkColor4f c)
#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