25#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
26#include "perfetto/ext/tracing/core/trace_packet.h"
27#include "perfetto/protozero/scattered_heap_buffer.h"
46 : token_pos_(token_pos), exclusive_ticks_(0), inclusive_ticks_(0) {}
59 const intptr_t table_index)
63 table_index_(table_index),
65 source_position_ticks_(0),
68 inclusive_serial_(-1) {
75 if (name_ !=
nullptr) {
104 return FLAG_show_invisible_frames || function_.
is_visible();
108 intptr_t inclusive_serial,
115 if (inclusive_serial_ == inclusive_serial) {
119 inclusive_serial_ = inclusive_serial;
127 for (;
i < source_position_ticks_.length();
i++) {
134 }
else if (cmp == 0) {
135 if (FLAG_trace_profiler_verbose) {
137 exclusive ?
"exclusive" :
"inclusive",
141 position.
Tick(exclusive);
148 if (FLAG_trace_profiler_verbose) {
150 exclusive ?
"exclusive" :
"inclusive",
153 pfsp.
Tick(exclusive);
155 if (
i < source_position_ticks_.length()) {
156 source_position_ticks_.InsertAt(
i, pfsp);
158 source_position_ticks_.Add(pfsp);
180void ProfileFunction::PrintToJSONObject(
JSONObject* func) {
187 bool print_only_ids) {
188 if (print_only_ids) {
195 PrintToJSONObject(&obj);
210 PrintToJSONObject(&func);
214 for (intptr_t
i = 0;
i < profile_codes_.
length();
i++) {
215 intptr_t code_index = profile_codes_[
i];
221void ProfileFunction::AddProfileCode(intptr_t code_table_index) {
222 for (intptr_t
i = 0;
i < profile_codes_.
length();
i++) {
223 if (profile_codes_[
i] == code_table_index) {
227 profile_codes_.
Add(code_table_index);
231 if (pfsp ==
nullptr) {
234 if (source_position_ticks_.length() != 1) {
237 *pfsp = source_position_ticks_[0];
242 : pc_(pc), exclusive_ticks_(0), inclusive_ticks_(0) {}
262 inclusive_serial_(-1),
265 compile_timestamp_(0),
267 code_table_index_(-1),
273 if (
start > start_) {
287 if (
start < start_) {
311 if (
name ==
nullptr) {
314 intptr_t
len = strlen(
name) + 1;
320 const intptr_t kBuffSize = 512;
321 char buff[kBuffSize];
327void ProfileCode::Tick(
uword pc,
bool exclusive, intptr_t
serial) {
331 TickAddress(pc,
true);
334 if (inclusive_serial_ ==
serial) {
338 inclusive_serial_ =
serial;
340 TickAddress(pc,
false);
343void ProfileCode::TickAddress(
uword pc,
bool exclusive) {
344 const intptr_t
length = address_ticks_.length();
348 ProfileCodeAddress& entry = address_ticks_[
i];
349 if (entry.pc() == pc) {
351 entry.Tick(exclusive);
354 if (entry.pc() > pc) {
360 ProfileCodeAddress entry(pc);
362 entry.Tick(exclusive);
366 address_ticks_.InsertAt(
i, entry);
369 address_ticks_.Add(entry);
373void ProfileCode::PrintNativeCode(JSONObject* profile_code_obj) {
375 JSONObject obj(profile_code_obj,
"code");
376 obj.AddProperty(
"type",
"@Code");
377 obj.AddProperty(
"kind",
"Native");
378 obj.AddProperty(
"name",
name());
379 obj.AddProperty(
"_optimized",
false);
380 obj.AddPropertyF(
"start",
"%" Px "",
start());
381 obj.AddPropertyF(
"end",
"%" Px "",
end());
384 JSONObject func(&obj,
"function");
385 ASSERT(function_ !=
nullptr);
386 function_->PrintToJSONObject(&func);
390void ProfileCode::PrintCollectedCode(JSONObject* profile_code_obj) {
392 JSONObject obj(profile_code_obj,
"code");
393 obj.AddProperty(
"type",
"@Code");
394 obj.AddProperty(
"kind",
"Collected");
395 obj.AddProperty(
"name",
name());
396 obj.AddProperty(
"_optimized",
false);
397 obj.AddPropertyF(
"start",
"%" Px "",
start());
398 obj.AddPropertyF(
"end",
"%" Px "",
end());
401 JSONObject func(&obj,
"function");
402 ASSERT(function_ !=
nullptr);
403 function_->PrintToJSONObject(&func);
407void ProfileCode::PrintOverwrittenCode(JSONObject* profile_code_obj) {
409 JSONObject obj(profile_code_obj,
"code");
410 obj.AddProperty(
"type",
"@Code");
411 obj.AddProperty(
"kind",
"Collected");
412 obj.AddProperty(
"name",
name());
413 obj.AddProperty(
"_optimized",
false);
414 obj.AddPropertyF(
"start",
"%" Px "",
start());
415 obj.AddPropertyF(
"end",
"%" Px "",
end());
418 JSONObject func(&obj,
"function");
419 ASSERT(function_ !=
nullptr);
420 function_->PrintToJSONObject(&func);
424void ProfileCode::PrintTagCode(JSONObject* profile_code_obj) {
426 JSONObject obj(profile_code_obj,
"code");
427 obj.AddProperty(
"type",
"@Code");
428 obj.AddProperty(
"kind",
"Tag");
429 obj.AddProperty(
"name",
name());
430 obj.AddPropertyF(
"start",
"%" Px "",
start());
431 obj.AddPropertyF(
"end",
"%" Px "",
end());
432 obj.AddProperty(
"_optimized",
false);
435 JSONObject func(&obj,
"function");
436 ASSERT(function_ !=
nullptr);
437 function_->PrintToJSONObject(&func);
450 return "Overwritten";
467 PrintCollectedCode(&obj);
469 PrintOverwrittenCode(&obj);
474 PrintNativeCode(&obj);
478 for (intptr_t
i = 0;
i < address_ticks_.length();
i++) {
490 : null_function_(
Function::ZoneHandle()),
491 unknown_function_(nullptr),
500 if (profile_function !=
nullptr) {
501 return profile_function;
512 ASSERT(unknown_function_ !=
nullptr);
513 return unknown_function_;
534 intptr_t
length()
const {
return table_.length(); }
548 table_.Add(profile_function);
549 return profile_function;
552 ProfileFunction* Add(
const Function&
function) {
554 ProfileFunction* profile_function =
new ProfileFunction(
556 table_.Add(profile_function);
557 function_hash_.
Insert(profile_function);
558 return profile_function;
562 struct ProfileFunctionTableTrait {
563 typedef ProfileFunction*
Value;
564 typedef const Function*
Key;
565 typedef ProfileFunction*
Pair;
567 static Key KeyOf(
Pair kv) {
return kv->function(); }
569 static Value ValueOf(
Pair kv) {
return kv; }
573 static inline bool IsKeyEqual(
Pair kv,
Key key) {
574 return kv->function()->ptr() ==
key->ptr();
578 const Function& null_function_;
579 ProfileFunction* unknown_function_;
580 ZoneGrowableArray<ProfileFunction*> table_;
581 DirectChainedHashMap<ProfileFunctionTableTrait> function_hash_;
584ProfileFunction* ProfileCode::SetFunctionAndName(ProfileFunctionTable*
table) {
585 ASSERT(function_ ==
nullptr);
587 ProfileFunction*
function =
nullptr;
589 if (
name() ==
nullptr) {
599 if (obj.IsFunction()) {
607 if (
name() ==
nullptr) {
609 const intptr_t kBuffSize = 512;
610 char buff[kBuffSize];
612 const char* dso_name;
626 if (
name() ==
nullptr) {
629 ASSERT(tag_name !=
nullptr);
634 ASSERT(tag_name !=
nullptr);
681 intptr_t
length = table_.length();
688 intptr_t mid = (hi - lo + 1) / 2 + lo;
692 if (
code->Contains(pc)) {
694 }
else if (pc < code->
start()) {
704 const intptr_t
length = table_.length();
706 table_.Add(new_code);
715 const uword pc = new_code->
end() - 1;
716 FindNeighbors(pc, &lo, &hi, &lo_code, &hi_code);
717 ASSERT((lo_code !=
nullptr) || (hi_code !=
nullptr));
732 (lo_code->
end() == new_code->
start())) {
742 (new_code->
end() == hi_code->
start())) {
753 }
else if (hi == -1) {
758 table_.InsertAt(insert, new_code);
762void ProfileCodeTable::FindNeighbors(
uword pc,
767 ASSERT(table_.length() >= 1);
769 intptr_t
length = table_.length();
794 while ((*hi - *lo) > 1) {
795 intptr_t mid = (*hi - *lo + 1) / 2 + *lo;
798 ProfileCode*
code =
At(mid);
799 if (
code->end() <= pc) {
803 if (pc < code->
end()) {
810void ProfileCodeTable::VerifyOrder() {
811 const intptr_t
length = table_.length();
815 uword last = table_[0]->end();
817 ProfileCode*
a = table_[
i];
823void ProfileCodeTable::VerifyOverlap() {
824 const intptr_t
length = table_.length();
826 ProfileCode*
a = table_[
i];
827 for (intptr_t j =
i + 1; j <
length; j++) {
828 ProfileCode*
b = table_[j];
829 ASSERT(!
a->Contains(
b->start()) && !
a->Contains(
b->end() - 1) &&
830 !
b->Contains(
a->start()) && !
b->Contains(
a->end() - 1));
839 intptr_t frame_index,
844 const intptr_t
offset = OffsetForPC(pc,
code, sample, frame_index);
845 if (FindInCache(pc,
offset, inlined_functions, inlined_token_positions,
850 Add(pc,
code, sample, frame_index, inlined_functions, inlined_token_positions,
854bool ProfileCodeInlinedFunctionsCache::FindInCache(
861 for (intptr_t
i = 0;
i < kCacheSize;
i++) {
862 intptr_t index = (last_hit_ +
i) % kCacheSize;
863 if ((cache_[index].pc == pc) && (cache_[index].offset ==
offset)) {
865 if (cache_[index].inlined_functions.
length() == 0) {
866 *inlined_functions =
nullptr;
867 *inlined_token_positions =
nullptr;
869 *inlined_functions = &cache_[index].inlined_functions;
870 *inlined_token_positions = &cache_[index].inlined_token_positions;
872 *token_position = cache_[index].token_position;
883void ProfileCodeInlinedFunctionsCache::Add(
886 ProcessedSample* sample,
887 intptr_t frame_index,
889 GrowableArray<const Function*>** inlined_functions,
890 GrowableArray<TokenPosition>** inlined_token_positions,
891 TokenPosition* token_position) {
892 const intptr_t
offset = OffsetForPC(pc,
code, sample, frame_index);
893 CacheEntry* cache_entry = &cache_[NextFreeIndex()];
894 cache_entry->Reset();
895 cache_entry->pc = pc;
896 cache_entry->offset =
offset;
897 code.GetInlinedFunctionsAtInstruction(
898 offset, &(cache_entry->inlined_functions),
899 &(cache_entry->inlined_token_positions));
900 if (cache_entry->inlined_functions.length() == 0) {
901 *inlined_functions =
nullptr;
902 *inlined_token_positions =
nullptr;
903 *token_position = cache_entry->token_position = TokenPosition::kNoSource;
908 *inlined_functions = &(cache_entry->inlined_functions);
909 *inlined_token_positions = &(cache_entry->inlined_token_positions);
910 *token_position = cache_entry->token_position =
911 cache_entry->inlined_token_positions[0];
914intptr_t ProfileCodeInlinedFunctionsCache::OffsetForPC(
uword pc,
916 ProcessedSample* sample,
917 intptr_t frame_index) {
919 if (frame_index != 0) {
923 }
else if (sample->IsAllocationSample()) {
927 }
else if (!sample->first_frame_executing()) {
955 vm_isolate_(
Dart::vm_isolate()),
957 sample_buffer_(sample_buffer),
959 null_code_(
Code::null()),
960 null_function_(
Function::ZoneHandle()),
961 inclusive_tree_(
false),
965 ASSERT(profile_ !=
nullptr);
969 ScopeTimer sw(
"ProfileBuilder::Build", FLAG_trace_profiler);
970 if (!FilterSamples()) {
975 FinalizeCodeIndexes();
976 BuildFunctionTable();
977 PopulateFunctionTicks();
978 SanitizeMinMaxTimes();
983 static bool IsExecutingFrame(
ProcessedSample* sample, intptr_t frame_index) {
984 return (frame_index == 0) &&
989 profile_->live_code_ =
new ProfileCodeTable();
990 profile_->dead_code_ =
new ProfileCodeTable();
991 profile_->tag_code_ =
new ProfileCodeTable();
992 profile_->functions_ =
new ProfileFunctionTable();
1004 bool FilterSamples() {
1005 ScopeTimer sw(
"ProfileBuilder::FilterSamples", FLAG_trace_profiler);
1006 if (sample_buffer_ ==
nullptr) {
1010 profile_->samples_ = samples_;
1011 profile_->sample_count_ = samples_->
length();
1015 void UpdateMinMaxTimes(int64_t timestamp) {
1016 profile_->min_time_ =
1017 timestamp < profile_->min_time_ ? timestamp : profile_->min_time_;
1018 profile_->max_time_ =
1019 timestamp > profile_->max_time_ ? timestamp : profile_->max_time_;
1022 void SanitizeMinMaxTimes() {
1023 if ((profile_->min_time_ ==
kMaxInt64) && (profile_->max_time_ == 0)) {
1024 profile_->min_time_ = 0;
1025 profile_->max_time_ = 0;
1029 void BuildCodeTable() {
1030 ScopeTimer sw(
"ProfileBuilder::BuildCodeTable", FLAG_trace_profiler);
1035 for (intptr_t
i = 0;
i < code_lookup_table.length();
i++) {
1036 const CodeDescriptor* descriptor = code_lookup_table.
At(
i);
1037 ASSERT(descriptor !=
nullptr);
1038 const AbstractCode
code = descriptor->code();
1039 RegisterLiveProfileCode(
new ProfileCode(
1046 for (intptr_t sample_index = 0; sample_index < samples_->
length();
1048 ProcessedSample* sample = samples_->
At(sample_index);
1049 const int64_t timestamp = sample->
timestamp();
1053 UpdateMinMaxTimes(timestamp);
1057 RegisterProfileCodeTag(VMTag::kNativeTagId);
1059 RegisterProfileCodeTag(VMTag::kRuntimeTagId);
1061 RegisterProfileCodeTag(sample->vm_tag());
1063 RegisterProfileCodeTag(sample->user_tag());
1067 for (intptr_t frame_index = 0; frame_index < sample->length();
1069 const uword pc = sample->At(frame_index);
1071 ProfileCode*
code = FindOrRegisterProfileCode(pc, timestamp);
1073 code->Tick(pc, IsExecutingFrame(sample, frame_index), sample_index);
1076 TickExitFrame(sample->vm_tag(), sample_index, sample);
1081 void FinalizeCodeIndexes() {
1082 ScopeTimer sw(
"ProfileBuilder::FinalizeCodeIndexes", FLAG_trace_profiler);
1083 ProfileCodeTable* live_table = profile_->live_code_;
1084 ProfileCodeTable* dead_table = profile_->dead_code_;
1085 ProfileCodeTable* tag_table = profile_->tag_code_;
1086 const intptr_t dead_code_index_offset = live_table->
length();
1087 const intptr_t tag_code_index_offset =
1088 dead_table->length() + dead_code_index_offset;
1090 profile_->dead_code_index_offset_ = dead_code_index_offset;
1091 profile_->tag_code_index_offset_ = tag_code_index_offset;
1093 for (intptr_t
i = 0;
i < live_table->length();
i++) {
1094 const intptr_t index =
i;
1095 ProfileCode*
code = live_table->At(
i);
1097 code->set_code_table_index(index);
1100 for (intptr_t
i = 0;
i < dead_table->length();
i++) {
1101 const intptr_t index = dead_code_index_offset +
i;
1102 ProfileCode*
code = dead_table->At(
i);
1104 code->set_code_table_index(index);
1107 for (intptr_t
i = 0;
i < tag_table->length();
i++) {
1108 const intptr_t index = tag_code_index_offset +
i;
1109 ProfileCode*
code = tag_table->At(
i);
1111 code->set_code_table_index(index);
1115 void BuildFunctionTable() {
1116 ScopeTimer sw(
"ProfileBuilder::BuildFunctionTable", FLAG_trace_profiler);
1117 ProfileCodeTable* live_table = profile_->live_code_;
1118 ProfileCodeTable* dead_table = profile_->dead_code_;
1119 ProfileCodeTable* tag_table = profile_->tag_code_;
1120 ProfileFunctionTable* function_table = profile_->functions_;
1121 for (intptr_t
i = 0;
i < live_table->length();
i++) {
1122 ProfileCode*
code = live_table->At(
i);
1124 code->SetFunctionAndName(function_table);
1128 for (intptr_t
i = 0;
i < dead_table->length();
i++) {
1129 ProfileCode*
code = dead_table->At(
i);
1131 code->SetFunctionAndName(function_table);
1135 for (intptr_t
i = 0;
i < tag_table->length();
i++) {
1136 ProfileCode*
code = tag_table->At(
i);
1138 code->SetFunctionAndName(function_table);
1143 void PopulateFunctionTicks() {
1144 ScopeTimer sw(
"ProfileBuilder::PopulateFunctionTicks", FLAG_trace_profiler);
1145 for (intptr_t sample_index = 0; sample_index < samples_->
length();
1147 ProcessedSample* sample = samples_->
At(sample_index);
1150 for (intptr_t frame_index = 0; frame_index < sample->length();
1152 ASSERT(sample->At(frame_index) != 0);
1153 ProcessFrame(sample_index, sample, frame_index);
1155 if (sample->truncated()) {
1156 InclusiveTickTruncatedTag(sample);
1161 void ProcessFrame(intptr_t sample_index,
1162 ProcessedSample* sample,
1163 intptr_t frame_index) {
1164 const uword pc = sample->At(frame_index);
1165 ProfileCode* profile_code = GetProfileCode(pc, sample->timestamp());
1166 ProfileFunction*
function = profile_code->function();
1168 const intptr_t code_index = profile_code->code_table_index();
1169 ASSERT(profile_code !=
nullptr);
1171 GrowableArray<const Function*>* inlined_functions =
nullptr;
1172 GrowableArray<TokenPosition>* inlined_token_positions =
nullptr;
1173 TokenPosition token_position = TokenPosition::kNoSource;
1175 if (profile_code->code().IsCode()) {
1176 code ^= profile_code->code().ptr();
1177 inlined_functions_cache_->
Get(pc,
code, sample, frame_index,
1179 &inlined_token_positions, &token_position);
1180 if (FLAG_trace_profiler_verbose && (inlined_functions !=
nullptr)) {
1181 for (intptr_t
i = 0;
i < inlined_functions->length();
i++) {
1182 const String&
name =
1186 (*inlined_token_positions)[
i].ToCString());
1191 if (
code.IsNull() || (inlined_functions ==
nullptr) ||
1192 (inlined_functions->length() <= 1)) {
1193 ProcessFunction(sample_index, sample, frame_index,
function,
1194 token_position, code_index);
1198 if (!
code.is_optimized()) {
1199 OS::PrintErr(
"Code that should be optimized is not. Please file a bug\n");
1202 inlined_functions->length());
1203 for (intptr_t
i = 0;
i < inlined_functions->length();
i++) {
1205 (*inlined_functions)[
i]->ToFullyQualifiedCString());
1212 for (intptr_t
i = inlined_functions->length() - 1;
i >= 0;
i--) {
1213 const Function* inlined_function = (*inlined_functions)[
i];
1214 ASSERT(inlined_function !=
nullptr);
1215 ASSERT(!inlined_function->IsNull());
1216 TokenPosition inlined_token_position = (*inlined_token_positions)[
i];
1217 ProcessInlinedFunction(sample_index, sample, frame_index +
i,
1218 inlined_function, inlined_token_position,
1223 void ProcessInlinedFunction(intptr_t sample_index,
1224 ProcessedSample* sample,
1225 intptr_t frame_index,
1226 const Function* inlined_function,
1227 TokenPosition inlined_token_position,
1228 intptr_t code_index) {
1229 ProfileFunctionTable* function_table = profile_->functions_;
1230 ProfileFunction*
function = function_table->LookupOrAdd(*inlined_function);
1232 ProcessFunction(sample_index, sample, frame_index,
function,
1233 inlined_token_position, code_index);
1236 bool ShouldTickNode(ProcessedSample* sample, intptr_t frame_index) {
1237 if (frame_index != 0) {
1241 return IsExecutingFrame(sample, frame_index) || !FLAG_profile_vm;
1244 void ProcessFunction(intptr_t sample_index,
1245 ProcessedSample* sample,
1246 intptr_t frame_index,
1248 TokenPosition token_position,
1249 intptr_t code_index) {
1253 if (FLAG_trace_profiler_verbose) {
1255 frame_index,
function->Name(), token_position.ToCString(),
1256 sample->At(frame_index));
1258 function->Tick(IsExecutingFrame(sample, frame_index), sample_index,
1260 function->AddProfileCode(code_index);
1264 void InclusiveTickTruncatedTag(ProcessedSample* sample) {
1265 ProfileCodeTable* tag_table = profile_->tag_code_;
1268 ProfileCode*
code = tag_table->At(index);
1269 code->IncInclusiveTicks();
1295 void TickExitFrame(
uword vm_tag, intptr_t
serial, ProcessedSample* sample) {
1296 if (FLAG_profile_vm) {
1302 ProfileCodeTable* tag_table = profile_->tag_code_;
1303 ProfileCode*
code = tag_table->FindCodeForPC(vm_tag);
1308 void TickExitFrameFunction(
uword vm_tag, intptr_t
serial) {
1309 if (FLAG_profile_vm) {
1315 ProfileCodeTable* tag_table = profile_->tag_code_;
1316 ProfileCode*
code = tag_table->FindCodeForPC(vm_tag);
1323 intptr_t GetProfileCodeTagIndex(
uword tag) {
1324 ProfileCodeTable* tag_table = profile_->tag_code_;
1327 ProfileCode*
code = tag_table->At(index);
1329 return code->code_table_index();
1332 intptr_t GetProfileFunctionTagIndex(
uword tag) {
1333 ProfileCodeTable* tag_table = profile_->tag_code_;
1336 ProfileCode*
code = tag_table->At(index);
1343 intptr_t GetProfileCodeIndex(
uword pc, int64_t timestamp) {
1347 ProfileCode* GetProfileCode(
uword pc, int64_t timestamp) {
1351 void RegisterProfileCodeTag(
uword tag) {
1356 ProfileCodeTable* tag_table = profile_->tag_code_;
1364 index = tag_table->InsertCode(
code);
1368 ProfileCode* CreateProfileCodeReused(
uword pc) {
1374 bool IsPCInDartHeap(
uword pc) {
1379 ProfileCode* FindOrRegisterNativeProfileCode(
uword pc) {
1381 ProfileCodeTable* live_table = profile_->live_code_;
1383 if (profile_code !=
nullptr) {
1384 return profile_code;
1390 uword native_start = 0;
1391 const char* native_name =
1393 if (native_name ==
nullptr) {
1398#if defined(HOST_ARCH_ARM)
1404 if (native_start > pc) {
1406 if (native_name !=
nullptr) {
1408 native_name =
nullptr;
1412 if ((pc - native_start) > (32 *
KB)) {
1415 if (native_name !=
nullptr) {
1417 native_name =
nullptr;
1422 ASSERT(pc >= native_start);
1425 pc + 1, 0, null_code_);
1426 if (native_name !=
nullptr) {
1427 profile_code->SetName(native_name);
1431 RegisterLiveProfileCode(profile_code);
1432 return profile_code;
1435 void RegisterLiveProfileCode(ProfileCode*
code) {
1436 ProfileCodeTable* live_table = profile_->live_code_;
1441 ProfileCode* FindOrRegisterDeadProfileCode(
uword pc) {
1442 ProfileCodeTable* dead_table = profile_->dead_code_;
1444 ProfileCode*
code = dead_table->FindCodeForPC(pc);
1445 if (
code !=
nullptr) {
1450 intptr_t index = dead_table->InsertCode(CreateProfileCodeReused(pc));
1452 return dead_table->At(index);
1455 ProfileCode* FindOrRegisterProfileCode(
uword pc, int64_t timestamp) {
1456 ProfileCodeTable* live_table = profile_->live_code_;
1457 ProfileCode*
code = live_table->FindCodeForPC(pc);
1458 if ((
code !=
nullptr) && (
code->compile_timestamp() <= timestamp)) {
1462 if ((
code ==
nullptr) && !IsPCInDartHeap(pc)) {
1464 return FindOrRegisterNativeProfileCode(pc);
1467 return FindOrRegisterDeadProfileCode(pc);
1472 Isolate* vm_isolate_;
1473 SampleFilter* filter_;
1474 SampleBlockBuffer* sample_buffer_;
1476 const AbstractCode null_code_;
1477 const Function& null_function_;
1478 bool inclusive_tree_;
1479 ProfileCodeInlinedFunctionsCache* inlined_functions_cache_;
1480 ProcessedSampleBuffer* samples_;
1485 : zone_(
Thread::Current()->zone()),
1487 live_code_(nullptr),
1488 dead_code_(nullptr),
1490 functions_(nullptr),
1491 dead_code_index_offset_(-1),
1492 tag_code_index_offset_(-1),
1501 ASSERT(isolate !=
nullptr);
1511 ASSERT(index < sample_count_);
1512 return samples_->
At(index);
1516 return functions_->
length();
1520 ASSERT(functions_ !=
nullptr);
1521 return functions_->
At(index);
1525 ASSERT(live_code_ !=
nullptr);
1526 ASSERT(dead_code_ !=
nullptr);
1527 ASSERT(tag_code_ !=
nullptr);
1528 ASSERT(dead_code_index_offset_ >= 0);
1529 ASSERT(tag_code_index_offset_ >= 0);
1536 if (index < dead_code_index_offset_) {
1537 return live_code_->
At(index);
1540 if (index < tag_code_index_offset_) {
1541 index -= dead_code_index_offset_;
1542 return dead_code_->
At(index);
1545 index -= tag_code_index_offset_;
1546 return tag_code_->
At(index);
1555 code = dead_code_->
At(index);
1557 code = live_code_->
At(index);
1559 if (
code->compile_timestamp() > timestamp) {
1563 code = dead_code_->
At(index);
1569 ASSERT(
code->compile_timestamp() <= timestamp);
1573void Profile::PrintHeaderJSON(
JSONObject* obj) {
1576 obj->
AddProperty(
"samplePeriod",
static_cast<intptr_t
>(FLAG_profile_period));
1578 static_cast<intptr_t
>(FLAG_max_profile_depth));
1586 counts.AddProperty64(
"bail_out_unknown_task",
1587 counters.bail_out_unknown_task);
1588 counts.AddProperty64(
"bail_out_jump_to_exception_handler",
1589 counters.bail_out_jump_to_exception_handler);
1590 counts.AddProperty64(
"bail_out_check_isolate",
1591 counters.bail_out_check_isolate);
1592 counts.AddProperty64(
"single_frame_sample_deoptimizing",
1593 counters.single_frame_sample_deoptimizing);
1595 "single_frame_sample_get_and_validate_stack_bounds",
1596 counters.single_frame_sample_get_and_validate_stack_bounds);
1597 counts.AddProperty64(
"stack_walker_native", counters.stack_walker_native);
1598 counts.AddProperty64(
"stack_walker_dart_exit",
1599 counters.stack_walker_dart_exit);
1600 counts.AddProperty64(
"stack_walker_dart", counters.stack_walker_dart);
1601 counts.AddProperty64(
"stack_walker_none", counters.stack_walker_none);
1605void Profile::ProcessSampleFrameJSON(JSONArray* stack,
1606 ProfileCodeInlinedFunctionsCache*
cache,
1607 ProcessedSample* sample,
1608 intptr_t frame_index) {
1609 const uword pc = sample->At(frame_index);
1610 ProfileCode* profile_code =
GetCodeFromPC(pc, sample->timestamp());
1611 ASSERT(profile_code !=
nullptr);
1612 ProfileFunction*
function = profile_code->function();
1621 GrowableArray<const Function*>* inlined_functions =
nullptr;
1622 GrowableArray<TokenPosition>* inlined_token_positions =
nullptr;
1623 TokenPosition token_position = TokenPosition::kNoSource;
1626 if (profile_code->code().IsCode()) {
1627 code ^= profile_code->code().ptr();
1628 cache->Get(pc,
code, sample, frame_index, &inlined_functions,
1629 &inlined_token_positions, &token_position);
1630 if (FLAG_trace_profiler_verbose && (inlined_functions !=
nullptr)) {
1631 for (intptr_t
i = 0;
i < inlined_functions->length();
i++) {
1632 const String&
name =
1635 (*inlined_token_positions)[
i].ToCString());
1640 if (
code.IsNull() || (inlined_functions ==
nullptr) ||
1641 (inlined_functions->length() <= 1)) {
1642 PrintFunctionFrameIndexJSON(stack,
function);
1646 if (!
code.is_optimized()) {
1647 OS::PrintErr(
"Code that should be optimized is not. Please file a bug\n");
1650 inlined_functions->length());
1651 for (intptr_t
i = 0;
i < inlined_functions->length();
i++) {
1653 (*inlined_functions)[
i]->ToFullyQualifiedCString());
1659 for (intptr_t
i = inlined_functions->length() - 1;
i >= 0;
i--) {
1660 const Function* inlined_function = (*inlined_functions)[
i];
1661 ASSERT(inlined_function !=
nullptr);
1662 ASSERT(!inlined_function->IsNull());
1663 ProcessInlinedFunctionFrameJSON(stack, inlined_function);
1667#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1668void Profile::ProcessSampleFramePerfetto(
1670 ProfileCodeInlinedFunctionsCache*
cache,
1671 ProcessedSample* sample,
1672 intptr_t frame_index) {
1673 const uword pc = sample->At(frame_index);
1674 ProfileCode* profile_code =
GetCodeFromPC(pc, sample->timestamp());
1675 ASSERT(profile_code !=
nullptr);
1676 ProfileFunction*
function = profile_code->function();
1685 GrowableArray<const Function*>* inlined_functions =
nullptr;
1686 GrowableArray<TokenPosition>* inlined_token_positions =
nullptr;
1687 TokenPosition token_position = TokenPosition::kNoSource;
1690 if (profile_code->code().IsCode()) {
1691 code ^= profile_code->code().ptr();
1692 cache->Get(pc,
code, sample, frame_index, &inlined_functions,
1693 &inlined_token_positions, &token_position);
1694 if (FLAG_trace_profiler_verbose && (inlined_functions != NULL)) {
1695 for (intptr_t
i = 0;
i < inlined_functions->length();
i++) {
1696 const String&
name =
1699 (*inlined_token_positions)[
i].ToCString());
1704 if (
code.IsNull() || (inlined_functions ==
nullptr) ||
1705 (inlined_functions->length() <= 1)) {
1713 if (!
code.is_optimized()) {
1714 OS::PrintErr(
"Code that should be optimized is not. Please file a bug\n");
1717 inlined_functions->length());
1718 for (intptr_t
i = 0;
i < inlined_functions->length();
i++) {
1720 (*inlined_functions)[
i]->ToFullyQualifiedCString());
1726 for (intptr_t
i = 0;
i < inlined_functions->length(); ++
i) {
1727 const Function* inlined_function = (*inlined_functions)[
i];
1728 ASSERT(inlined_function != NULL);
1729 ASSERT(!inlined_function->IsNull());
1730 ProfileFunction* profile_function =
1732 ASSERT(profile_function != NULL);
1736 callstack->
add_frame_ids(profile_function->table_index() + 1);
1741void Profile::ProcessInlinedFunctionFrameJSON(
1743 const Function* inlined_function) {
1746 PrintFunctionFrameIndexJSON(stack,
function);
1749void Profile::PrintFunctionFrameIndexJSON(JSONArray* stack,
1751 stack->AddValue64(
function->table_index());
1754void Profile::PrintCodeFrameIndexJSON(JSONArray* stack,
1755 ProcessedSample* sample,
1756 intptr_t frame_index) {
1758 GetCodeFromPC(sample->At(frame_index), sample->timestamp());
1759 const AbstractCode codeObj =
code->code();
1762 if (codeObj.IsStubCode() || codeObj.IsAllocationStubCode() ||
1763 codeObj.IsTypeTestStubCode()) {
1766 stack->AddValue64(
code->code_table_index());
1769void Profile::PrintSamplesJSON(JSONObject* obj,
bool code_samples) {
1770 JSONArray samples(obj,
"samples");
1773 auto*
cache =
new ProfileCodeInlinedFunctionsCache();
1774 for (intptr_t sample_index = 0; sample_index < samples_->
length();
1776 JSONObject sample_obj(&samples);
1777 ProcessedSample* sample = samples_->
At(sample_index);
1779 sample_obj.AddPropertyTimeMicros(
"timestamp", sample->timestamp());
1780 sample_obj.AddProperty(
"vmTag",
VMTag::TagName(sample->vm_tag()));
1782 sample_obj.AddProperty(
"nativeEntryTag",
true);
1785 sample_obj.AddProperty(
"runtimeEntryTag",
true);
1790 if (sample->truncated()) {
1791 sample_obj.AddProperty(
"truncated",
true);
1794 JSONArray stack(&sample_obj,
"stack");
1796 for (intptr_t frame_index = 0; frame_index < sample->length();
1798 ASSERT(sample->At(frame_index) != 0);
1799 ProcessSampleFrameJSON(&stack,
cache, sample, frame_index);
1803 JSONArray stack(&sample_obj,
"_codeStack");
1804 for (intptr_t frame_index = 0; frame_index < sample->length();
1806 ASSERT(sample->At(frame_index) != 0);
1807 PrintCodeFrameIndexJSON(&stack, sample, frame_index);
1810 if (sample->IsAllocationSample()) {
1811 sample_obj.AddProperty64(
"classId", sample->allocation_cid());
1812 sample_obj.AddProperty64(
"identityHashCode",
1813 sample->allocation_identity_hash());
1818#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1819void Profile::PrintSamplesPerfetto(
1820 JSONBase64String* jsonBase64String,
1821 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>*
1823 ASSERT(jsonBase64String !=
nullptr);
1824 ASSERT(packet_ptr !=
nullptr);
1825 auto& packet = *packet_ptr;
1829 auto*
cache =
new ProfileCodeInlinedFunctionsCache();
1830 for (intptr_t sample_index = 0; sample_index < samples_->
length();
1832 ProcessedSample* sample = samples_->
At(sample_index);
1834 perfetto_utils::SetTrustedPacketSequenceId(packet.get());
1837 packet->set_sequence_flags(
1840 perfetto_utils::SetTimestampAndMonotonicClockId(packet.get(),
1841 sample->timestamp());
1843 const intptr_t callstack_iid = sample_index + 1;
1847 packet->set_interned_data()->add_callstacks();
1848 callstack->
set_iid(callstack_iid);
1850 for (intptr_t frame_index = sample->length() - 1; frame_index >= 0;
1852 ASSERT(sample->At(frame_index) != 0);
1853 ProcessSampleFramePerfetto(callstack,
cache, sample, frame_index);
1859 *packet->set_perf_sample();
1864 perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, &packet);
1871 return (functions_ !=
nullptr) ? functions_->
Lookup(
function) :
nullptr;
1880 bool include_code_samples,
1882 ScopeTimer sw(
"Profile::PrintProfileJSON", FLAG_trace_profiler);
1889 PrintHeaderJSON(obj);
1890 if (include_code_samples) {
1892 for (intptr_t
i = 0;
i < live_code_->
length();
i++) {
1895 code->PrintToJSONArray(&codes);
1898 for (intptr_t
i = 0;
i < dead_code_->
length();
i++) {
1901 code->PrintToJSONArray(&codes);
1904 for (intptr_t
i = 0;
i < tag_code_->
length();
i++) {
1907 code->PrintToJSONArray(&codes);
1914 for (intptr_t
i = 0;
i < functions_->
length();
i++) {
1917 function->PrintToJSONArray(&functions, is_event);
1921 PrintSamplesJSON(obj, include_code_samples);
1925#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1927 ScopeTimer sw(
"Profile::PrintProfilePerfetto", FLAG_trace_profiler);
1931 jsobj_topLevel.AddProperty(
"type",
"PerfettoCpuSamples");
1932 PrintHeaderJSON(&jsobj_topLevel);
1934 js->AppendSerializedObject(
"\"samples\":");
1939 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket> packet;
1941 perfetto_utils::PopulateClockSnapshotPacket(packet.get());
1942 perfetto_utils::AppendPacketToJSONBase64String(&jsonBase64String, &packet);
1945 perfetto_utils::SetTrustedPacketSequenceId(packet.get());
1953 packet->set_sequence_flags(
1958 *packet->set_interned_data();
1965 for (intptr_t
i = 0;
i < functions_->
length(); ++
i) {
1968 const intptr_t common_iid =
function->table_index() + 1;
1975 const char* resolved_script_url =
function->ResolvedScriptUrl();
1976 if (resolved_script_url !=
nullptr) {
1979 mapping_path.
set_iid(common_iid);
1980 const Script& script_handle =
1985 intptr_t column = -1;
1987 intptr_t path_with_location_buffer_size =
1991 std::unique_ptr<char[]> path_with_location =
1992 std::make_unique<char[]>(path_with_location_buffer_size);
1993 Utils::SNPrint(path_with_location.get(), path_with_location_buffer_size,
1994 "%s:%" Pd ":%" Pd, resolved_script_url,
line, column);
1995 mapping_path.
set_str(path_with_location.get());
1997 mapping_path.
set_str(resolved_script_url);
2013 frame.set_iid(common_iid);
2014 frame.set_function_name_id(common_iid);
2015 frame.set_mapping_id(resolved_script_url ==
nullptr ? 0 : common_iid);
2019 perfetto_utils::AppendPacketToJSONBase64String(&jsonBase64String, &packet);
2022 PrintSamplesPerfetto(&jsonBase64String, &packet);
2027void ProfilerService::PrintCommonImpl(PrintFormat
format,
2030 SampleFilter* filter,
2031 SampleBlockBuffer*
buffer,
2032 bool include_code_samples) {
2036 StackZone zone(thread);
2041 profile.PrintProfileJSON(
js, include_code_samples);
2043#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
2058 intptr_t thread_task_mask,
2059 int64_t time_origin_micros,
2060 int64_t time_extent_micros)
2064 time_extent_micros) {}
2069void ProfilerService::PrintCommon(PrintFormat
format,
2071 int64_t time_origin_micros,
2072 int64_t time_extent_micros,
2073 bool include_code_samples) {
2075 const Isolate* isolate = thread->isolate();
2077 time_origin_micros, time_extent_micros);
2080 include_code_samples);
2084 int64_t time_origin_micros,
2085 int64_t time_extent_micros,
2086 bool include_code_samples) {
2088 include_code_samples);
2091#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
2093 int64_t time_origin_micros,
2094 int64_t time_extent_micros) {
2096 time_extent_micros);
2103 intptr_t thread_task_mask,
2104 int64_t time_origin_micros,
2105 int64_t time_extent_micros)
2109 time_extent_micros) {}
2115 int64_t time_origin_micros,
2116 int64_t time_extent_micros) {
2120 time_origin_micros, time_extent_micros);
2129 intptr_t thread_task_mask,
2130 int64_t time_origin_micros,
2131 int64_t time_extent_micros)
2135 time_extent_micros),
2136 cls_(
Class::Handle(cls.ptr())) {
2151 int64_t time_origin_micros,
2152 int64_t time_extent_micros) {
2157 time_extent_micros);
2164 if (sample_block_buffer ==
nullptr) {
const char * QualifiedName() const
const Object * handle() const
bool is_optimized() const
AllocationSampleFilter(Dart_Port port, intptr_t thread_task_mask, int64_t time_origin_micros, int64_t time_extent_micros)
bool FilterSample(Sample *sample)
KeyValueTrait::Value LookupValue(typename KeyValueTrait::Key key) const
void Insert(typename KeyValueTrait::Pair kv)
bool FilterSample(Sample *sample)
ClassAllocationSampleFilter(Dart_Port port, const Class &cls, intptr_t thread_task_mask, int64_t time_origin_micros, int64_t time_extent_micros)
const CodeDescriptor * At(intptr_t index) const
static bool is_visible(FunctionPtr f)
void AddFunctionServiceId(const JSONObject &obj) const
StringPtr QualifiedUserVisibleName() const
bool CodeContains(uword addr) const
IsolateGroup * group() const
Dart_Port main_port() const
void AddValue(bool b) const
void AddValueF(const char *format,...) const PRINTF_ATTRIBUTE(2
void AddProperty64(const char *name, int64_t i) const
void AddProperty(const char *name, bool b) const
void AddPropertyTimeMicros(const char *name, int64_t micros) const
static bool LookupSharedObject(uword pc, uword *dso_base=nullptr, const char **dso_name=nullptr)
static const char * LookupSymbolName(uword pc, uword *start)
static void FreeSymbolName(const char *name)
NoAllocationSampleFilter(Dart_Port port, intptr_t thread_task_mask, int64_t time_origin_micros, int64_t time_extent_micros)
bool FilterSample(Sample *sample)
static intptr_t ThreadIdToIntPtr(ThreadId id)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static intptr_t ProcessId()
static Object & ZoneHandle()
ProcessedSample * At(intptr_t index)
const CodeLookupTable & code_lookup_table() const
bool first_frame_executing() const
int64_t timestamp() const
bool IsAllocationSample() const
ProfileBuilder(Thread *thread, Isolate *isolate, SampleFilter *filter, SampleBlockBuffer *sample_buffer, Profile *profile)
void Tick(bool exclusive)
ProfileCodeAddress(uword pc)
intptr_t exclusive_ticks() const
intptr_t inclusive_ticks() const
void Get(uword pc, const Code &code, ProcessedSample *sample, intptr_t frame_index, GrowableArray< const Function * > **inlined_functions, GrowableArray< TokenPosition > **inlined_token_positions, TokenPosition *token_position)
ProfileCode * At(intptr_t index) const
intptr_t InsertCode(ProfileCode *new_code)
ProfileCode * FindCodeForPC(uword pc) const
intptr_t FindCodeIndexForPC(uword pc) const
void ExpandUpper(uword end)
void TruncateLower(uword start)
intptr_t inclusive_ticks() const
static const char * KindToCString(Kind kind)
ProfileFunction * function() const
void TruncateUpper(uword end)
void SetName(const char *name)
intptr_t exclusive_ticks() const
bool IsOptimizedDart() const
bool Contains(uword pc) const
void ExpandLower(uword start)
void PrintToJSONArray(JSONArray *codes)
bool Overlaps(const ProfileCode *other) const
void GenerateAndSetSymbolName(const char *prefix)
ProfileCode(Kind kind, uword start, uword end, int64_t timestamp, const AbstractCode code)
const char * name() const
intptr_t code_table_index() const
TokenPosition token_pos() const
ProfileFunctionSourcePosition(TokenPosition token_pos)
void Tick(bool exclusive)
ProfileFunction * GetUnknown()
ProfileFunction * Lookup(const Function &function)
ProfileFunction * AddTag(uword tag_id, const char *name)
ProfileFunction * LookupOrAdd(const Function &function)
ProfileFunction * AddNative(uword start_address, const char *name)
ProfileFunction * At(intptr_t i) const
ProfileFunction * AddStub(uword start_address, const char *name)
ProfileFunction(Kind kind, const char *name, const Function &function, const intptr_t table_index)
void Tick(bool exclusive, intptr_t inclusive_serial, TokenPosition token_position)
const char * name() const
void TickSourcePosition(TokenPosition token_position, bool exclusive)
intptr_t inclusive_ticks() const
const char * ResolvedScriptUrl() const
void PrintToJSONArray(JSONArray *functions, bool print_only_ids=false)
bool GetSinglePosition(ProfileFunctionSourcePosition *pfsp)
intptr_t exclusive_ticks() const
const char * Name() const
static const char * KindToCString(Kind kind)
intptr_t sample_count() const
ProcessedSample * SampleAt(intptr_t index)
ProfileCode * GetCodeFromPC(uword pc, int64_t timestamp)
intptr_t NumFunctions() const
void Build(Thread *thread, Isolate *isolate, SampleFilter *filter, SampleBlockBuffer *sample_block_buffer)
ProfileCode * GetCode(intptr_t index)
void PrintProfileJSON(JSONStream *stream, bool include_code_samples)
ProfileFunction * FindFunction(const Function &function)
ProfileFunction * GetFunction(intptr_t index)
int64_t GetTimeSpan() const
static void PrintAllocationJSON(JSONStream *stream, const Class &cls, int64_t time_origin_micros, int64_t time_extent_micros)
static void ClearSamples()
static void PrintJSON(JSONStream *stream, int64_t time_origin_micros, int64_t time_extent_micros, bool include_code_samples)
static ProfilerCounters counters()
static SampleBlockBuffer * sample_block_buffer()
ProcessedSampleBuffer * BuildProcessedSampleBuffer(Isolate *isolate, SampleFilter *filter, ProcessedSampleBuffer *buffer=nullptr)
void VisitSamples(SampleVisitor *visitor)
bool is_allocation_sample() const
intptr_t allocation_cid() const
bool GetTokenLocation(const TokenPosition &token_pos, intptr_t *line, intptr_t *column=nullptr) const
static const char * ToCString(Thread *thread, StringPtr ptr)
static Thread * Current()
Isolate * isolate() const
static intptr_t CompareForSorting(const TokenPosition &a, const TokenPosition &b)
const char * ToCString() const
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
static bool IsExitFrameTag(uword id)
static bool IsVMTag(uword id)
static bool IsNativeEntryTag(uword id)
static bool IsRuntimeEntryTag(uword id)
static const char * TagName(uword id)
ElementType * Alloc(intptr_t length)
void add_frame_ids(uint64_t value)
void set_iid(uint64_t value)
void set_str(const uint8_t *data, size_t size)
void set_iid(uint64_t value)
void add_path_string_ids(uint64_t value)
void set_iid(uint64_t value)
void set_pid(uint32_t value)
void set_callstack_iid(uint64_t value)
void set_tid(uint32_t value)
#define THR_Print(format,...)
uint32_t uint32_t * format
Dart_NativeFunction function
constexpr int64_t kMaxInt64
static uint32_t Hash(uint32_t key)
const char *const function_name
DECLARE_FLAG(bool, show_invisible_frames)
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 Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
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 counts
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
@ SEQ_NEEDS_INCREMENTAL_STATE
@ SEQ_INCREMENTAL_STATE_CLEARED