mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Reland "[vm] Generate event ids for synchronous begin and end events."
Fix transposed id and timestamp. TEST=Instruments, ci Bug: https://github.com/dart-lang/sdk/issues/49178 Change-Id: I2c2650f28050b179d26e1269729727f58201a8a8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/251581 Commit-Queue: Ryan Macnak <rmacnak@google.com> Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
parent
a13ef8a5d5
commit
2d13b205d7
|
@ -24,15 +24,11 @@ DEFINE_NATIVE_ENTRY(Timeline_isDartStreamEnabled, 0, 0) {
|
|||
return Bool::False().ptr();
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Timeline_getNextAsyncId, 0, 0) {
|
||||
DEFINE_NATIVE_ENTRY(Timeline_getNextTaskId, 0, 0) {
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
return Integer::New(0);
|
||||
#else
|
||||
TimelineEventRecorder* recorder = Timeline::recorder();
|
||||
if (recorder == NULL) {
|
||||
return Integer::New(0);
|
||||
}
|
||||
return Integer::New(recorder->GetNextAsyncId());
|
||||
return Integer::New(thread->GetNextTaskId());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ namespace dart {
|
|||
V(TypeError_throwNew, 4) \
|
||||
V(Stopwatch_now, 0) \
|
||||
V(Stopwatch_frequency, 0) \
|
||||
V(Timeline_getNextAsyncId, 0) \
|
||||
V(Timeline_getNextTaskId, 0) \
|
||||
V(Timeline_getTraceClock, 0) \
|
||||
V(Timeline_isDartStreamEnabled, 0) \
|
||||
V(Timeline_reportFlowEvent, 5) \
|
||||
|
|
|
@ -1900,6 +1900,23 @@ void AsmIntrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler,
|
|||
#endif
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Timeline_getNextTaskId(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
__ LoadImmediate(R0, target::ToRawSmi(0));
|
||||
__ Ret();
|
||||
#else
|
||||
__ ldr(R1, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ ldr(R2, Address(THR, target::Thread::next_task_id_offset() + 4));
|
||||
__ SmiTag(R0, R1); // Ignore loss of precision.
|
||||
__ adds(R1, R1, Operand(1));
|
||||
__ adcs(R2, R2, Operand(0));
|
||||
__ str(R1, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ str(R2, Address(THR, target::Thread::next_task_id_offset() + 4));
|
||||
__ Ret();
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace compiler
|
||||
|
|
|
@ -2146,6 +2146,20 @@ void AsmIntrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler,
|
|||
#endif
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Timeline_getNextTaskId(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
__ LoadImmediate(R0, target::ToRawSmi(0));
|
||||
__ ret();
|
||||
#else
|
||||
__ ldr(R0, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ add(R1, R0, Operand(1));
|
||||
__ str(R1, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ SmiTag(R0); // Ignore loss of precision.
|
||||
__ ret();
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace compiler
|
||||
|
|
|
@ -1937,6 +1937,24 @@ void AsmIntrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler,
|
|||
#endif
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Timeline_getNextTaskId(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
__ LoadImmediate(EAX, target::ToRawSmi(0));
|
||||
__ ret();
|
||||
#else
|
||||
__ movl(EBX, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ movl(ECX, Address(THR, target::Thread::next_task_id_offset() + 4));
|
||||
__ movl(EAX, EBX);
|
||||
__ SmiTag(EAX); // Ignore loss of precision.
|
||||
__ addl(EBX, Immediate(1));
|
||||
__ adcl(ECX, Immediate(0));
|
||||
__ movl(Address(THR, target::Thread::next_task_id_offset()), EBX);
|
||||
__ movl(Address(THR, target::Thread::next_task_id_offset() + 4), ECX);
|
||||
__ ret();
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace compiler
|
||||
|
|
|
@ -2160,6 +2160,30 @@ void AsmIntrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler,
|
|||
#endif
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Timeline_getNextTaskId(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
__ LoadImmediate(A0, target::ToRawSmi(0));
|
||||
__ ret();
|
||||
#elif XLEN == 64
|
||||
__ ld(A0, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ addi(A1, A0, 1);
|
||||
__ sd(A1, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ SmiTag(A0); // Ignore loss of precision.
|
||||
__ ret();
|
||||
#else
|
||||
__ lw(T0, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ lw(T1, Address(THR, target::Thread::next_task_id_offset() + 4));
|
||||
__ SmiTag(A0, T0); // Ignore loss of precision.
|
||||
__ addi(T2, T0, 1);
|
||||
__ sltu(T3, T2, T0); // Carry.
|
||||
__ add(T1, T1, T3);
|
||||
__ sw(T2, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ sw(T1, Address(THR, target::Thread::next_task_id_offset() + 4));
|
||||
__ ret();
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace compiler
|
||||
|
|
|
@ -2034,6 +2034,21 @@ void AsmIntrinsifier::Timeline_isDartStreamEnabled(Assembler* assembler,
|
|||
#endif
|
||||
}
|
||||
|
||||
void AsmIntrinsifier::Timeline_getNextTaskId(Assembler* assembler,
|
||||
Label* normal_ir_body) {
|
||||
#if !defined(SUPPORT_TIMELINE)
|
||||
__ xorq(RAX, RAX); // Return Smi 0.
|
||||
__ ret();
|
||||
#else
|
||||
__ movq(RAX, Address(THR, target::Thread::next_task_id_offset()));
|
||||
__ movq(RBX, RAX);
|
||||
__ incq(RBX);
|
||||
__ movq(Address(THR, target::Thread::next_task_id_offset()), RBX);
|
||||
__ SmiTag(RAX); // Ignore loss of precision.
|
||||
__ ret();
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace compiler
|
||||
|
|
|
@ -437,6 +437,7 @@ namespace dart {
|
|||
V(::, _getDefaultTag, UserTag_defaultTag, 0x6c19c8a5) \
|
||||
V(::, _getCurrentTag, Profiler_getCurrentTag, 0x70ead08e) \
|
||||
V(::, _isDartStreamEnabled, Timeline_isDartStreamEnabled, 0xc97aafb3) \
|
||||
V(::, _getNextTaskId, Timeline_getNextTaskId, 0x5b2b0b0b) \
|
||||
|
||||
#define INTERNAL_LIB_INTRINSIC_LIST(V) \
|
||||
V(::, allocateOneByteString, AllocateOneByteString, 0x9e7745d5) \
|
||||
|
|
|
@ -1249,6 +1249,7 @@ class Thread : public AllStatic {
|
|||
THREAD_XMM_CONSTANT_LIST(DECLARE_CONSTANT_OFFSET_GETTER)
|
||||
#undef DECLARE_CONSTANT_OFFSET_GETTER
|
||||
|
||||
static word next_task_id_offset();
|
||||
static word random_offset();
|
||||
|
||||
static word suspend_state_init_async_entry_point_offset();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -318,6 +318,7 @@
|
|||
FIELD(Thread, heap_base_offset) \
|
||||
FIELD(Thread, callback_code_offset) \
|
||||
FIELD(Thread, callback_stack_return_offset) \
|
||||
FIELD(Thread, next_task_id_offset) \
|
||||
FIELD(Thread, random_offset) \
|
||||
FIELD(Thread, jump_to_frame_entry_point_offset) \
|
||||
FIELD(Thread, tsan_utils_offset) \
|
||||
|
|
|
@ -307,6 +307,7 @@ char* Dart::DartInit(const Dart_InitializeParams* params) {
|
|||
#endif
|
||||
|
||||
OSThread::Init();
|
||||
Random::Init();
|
||||
Zone::Init();
|
||||
#if defined(SUPPORT_TIMELINE)
|
||||
Timeline::Init();
|
||||
|
@ -779,6 +780,7 @@ char* Dart::Cleanup() {
|
|||
Timeline::Cleanup();
|
||||
#endif
|
||||
Zone::Cleanup();
|
||||
Random::Cleanup();
|
||||
// Delete the current thread's TLS and set it's TLS to null.
|
||||
// If it is the last thread then the destructor would call
|
||||
// OSThread::Cleanup.
|
||||
|
|
|
@ -6361,10 +6361,10 @@ DART_EXPORT void Dart_TimelineEvent(const char* label,
|
|||
if (event != NULL) {
|
||||
switch (type) {
|
||||
case Dart_Timeline_Event_Begin:
|
||||
event->Begin(label, timestamp0);
|
||||
event->Begin(label, timestamp1_or_async_id, timestamp0);
|
||||
break;
|
||||
case Dart_Timeline_Event_End:
|
||||
event->End(label, timestamp0);
|
||||
event->End(label, timestamp1_or_async_id, timestamp0);
|
||||
break;
|
||||
case Dart_Timeline_Event_Instant:
|
||||
event->Instant(label, timestamp0);
|
||||
|
|
|
@ -9413,7 +9413,29 @@ TEST_CASE(DartAPI_TimelineDuration) {
|
|||
// Make sure it is enabled.
|
||||
stream->set_enabled(true);
|
||||
// Add a duration event.
|
||||
Dart_TimelineEvent("testDurationEvent", 0, 1, Dart_Timeline_Event_Duration, 0,
|
||||
Dart_TimelineEvent("testDurationEvent", 500, 1500,
|
||||
Dart_Timeline_Event_Duration, 0, NULL, NULL);
|
||||
// Check that it is in the output.
|
||||
TimelineEventRecorder* recorder = Timeline::recorder();
|
||||
Timeline::ReclaimCachedBlocksFromThreads();
|
||||
JSONStream js;
|
||||
IsolateTimelineEventFilter filter(isolate->main_port());
|
||||
recorder->PrintJSON(&js, &filter);
|
||||
const char* json = js.ToCString();
|
||||
EXPECT_SUBSTRING("\"name\":\"testDurationEvent\"", json);
|
||||
EXPECT_SUBSTRING("\"ph\":\"X\"", json);
|
||||
EXPECT_SUBSTRING("\"ts\":500", json);
|
||||
EXPECT_SUBSTRING("\"dur\":1000", json);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_TimelineBegin) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
// Grab embedder stream.
|
||||
TimelineStream* stream = Timeline::GetEmbedderStream();
|
||||
// Make sure it is enabled.
|
||||
stream->set_enabled(true);
|
||||
// Add a begin event.
|
||||
Dart_TimelineEvent("testBeginEvent", 1000, 1, Dart_Timeline_Event_Begin, 0,
|
||||
NULL, NULL);
|
||||
// Check that it is in the output.
|
||||
TimelineEventRecorder* recorder = Timeline::recorder();
|
||||
|
@ -9421,7 +9443,31 @@ TEST_CASE(DartAPI_TimelineDuration) {
|
|||
JSONStream js;
|
||||
IsolateTimelineEventFilter filter(isolate->main_port());
|
||||
recorder->PrintJSON(&js, &filter);
|
||||
EXPECT_SUBSTRING("testDurationEvent", js.ToCString());
|
||||
const char* json = js.ToCString();
|
||||
EXPECT_SUBSTRING("\"name\":\"testBeginEvent\"", json);
|
||||
EXPECT_SUBSTRING("\"ph\":\"B\"", json);
|
||||
EXPECT_SUBSTRING("\"ts\":1000", json);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_TimelineEnd) {
|
||||
Isolate* isolate = Isolate::Current();
|
||||
// Grab embedder stream.
|
||||
TimelineStream* stream = Timeline::GetEmbedderStream();
|
||||
// Make sure it is enabled.
|
||||
stream->set_enabled(true);
|
||||
// Add a begin event.
|
||||
Dart_TimelineEvent("testEndEvent", 1000, 1, Dart_Timeline_Event_End, 0, NULL,
|
||||
NULL);
|
||||
// Check that it is in the output.
|
||||
TimelineEventRecorder* recorder = Timeline::recorder();
|
||||
Timeline::ReclaimCachedBlocksFromThreads();
|
||||
JSONStream js;
|
||||
IsolateTimelineEventFilter filter(isolate->main_port());
|
||||
recorder->PrintJSON(&js, &filter);
|
||||
const char* json = js.ToCString();
|
||||
EXPECT_SUBSTRING("\"name\":\"testEndEvent\"", json);
|
||||
EXPECT_SUBSTRING("\"ph\":\"E\"", json);
|
||||
EXPECT_SUBSTRING("\"ts\":1000", json);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_TimelineInstant) {
|
||||
|
@ -9430,15 +9476,18 @@ TEST_CASE(DartAPI_TimelineInstant) {
|
|||
TimelineStream* stream = Timeline::GetEmbedderStream();
|
||||
// Make sure it is enabled.
|
||||
stream->set_enabled(true);
|
||||
Dart_TimelineEvent("testInstantEvent", 0, 1, Dart_Timeline_Event_Instant, 0,
|
||||
NULL, NULL);
|
||||
Dart_TimelineEvent("testInstantEvent", 1000, 1, Dart_Timeline_Event_Instant,
|
||||
0, NULL, NULL);
|
||||
// Check that it is in the output.
|
||||
TimelineEventRecorder* recorder = Timeline::recorder();
|
||||
Timeline::ReclaimCachedBlocksFromThreads();
|
||||
JSONStream js;
|
||||
IsolateTimelineEventFilter filter(isolate->main_port());
|
||||
recorder->PrintJSON(&js, &filter);
|
||||
EXPECT_SUBSTRING("testInstantEvent", js.ToCString());
|
||||
const char* json = js.ToCString();
|
||||
EXPECT_SUBSTRING("\"name\":\"testInstantEvent\"", json);
|
||||
EXPECT_SUBSTRING("\"ph\":\"i\"", json);
|
||||
EXPECT_SUBSTRING("\"ts\":1000", json);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_TimelineAsyncDisabled) {
|
||||
|
@ -9465,7 +9514,7 @@ TEST_CASE(DartAPI_TimelineAsync) {
|
|||
// Make sure it is enabled.
|
||||
stream->set_enabled(true);
|
||||
int64_t async_id = 99;
|
||||
Dart_TimelineEvent("testAsyncEvent", 0, async_id,
|
||||
Dart_TimelineEvent("testAsyncEvent", 1000, async_id,
|
||||
Dart_Timeline_Event_Async_Begin, 0, NULL, NULL);
|
||||
|
||||
// Check that it is in the output.
|
||||
|
@ -9474,7 +9523,11 @@ TEST_CASE(DartAPI_TimelineAsync) {
|
|||
JSONStream js;
|
||||
IsolateTimelineEventFilter filter(isolate->main_port());
|
||||
recorder->PrintJSON(&js, &filter);
|
||||
EXPECT_SUBSTRING("testAsyncEvent", js.ToCString());
|
||||
const char* json = js.ToCString();
|
||||
EXPECT_SUBSTRING("\"name\":\"testAsyncEvent\"", json);
|
||||
EXPECT_SUBSTRING("\"ph\":\"b\"", json);
|
||||
EXPECT_SUBSTRING("\"ts\":1000", json);
|
||||
EXPECT_SUBSTRING("\"id\":\"63\"", json); // Hex for some reason.
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_TimelineClock) {
|
||||
|
|
|
@ -75,4 +75,26 @@ uint32_t Random::NextUInt32() {
|
|||
return static_cast<uint32_t>(NextState() & MASK_32);
|
||||
}
|
||||
|
||||
static Random* global_random = nullptr;
|
||||
static Mutex* global_random_mutex = nullptr;
|
||||
|
||||
void Random::Init() {
|
||||
ASSERT(global_random_mutex == nullptr);
|
||||
global_random_mutex = new Mutex(NOT_IN_PRODUCT("global_random_mutex"));
|
||||
ASSERT(global_random == nullptr);
|
||||
global_random = new Random();
|
||||
}
|
||||
|
||||
void Random::Cleanup() {
|
||||
delete global_random_mutex;
|
||||
global_random_mutex = nullptr;
|
||||
delete global_random;
|
||||
global_random = nullptr;
|
||||
}
|
||||
|
||||
uint64_t Random::GlobalNextUInt64() {
|
||||
MutexLocker locker(global_random_mutex);
|
||||
return global_random->NextUInt64();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
|
|
@ -28,6 +28,10 @@ class Random {
|
|||
static_cast<uint64_t>(NextUInt32());
|
||||
}
|
||||
|
||||
static uint64_t GlobalNextUInt64();
|
||||
static void Init();
|
||||
static void Cleanup();
|
||||
|
||||
private:
|
||||
uint64_t NextState();
|
||||
void Initialize(uint64_t seed);
|
||||
|
|
|
@ -143,6 +143,12 @@ Thread::Thread(bool is_vm_isolate)
|
|||
if (!is_vm_isolate) {
|
||||
InitVMConstants();
|
||||
}
|
||||
|
||||
#if defined(DART_HOST_OS_FUCHSIA)
|
||||
next_task_id_ = trace_generate_nonce();
|
||||
#else
|
||||
next_task_id_ = Random::GlobalNextUInt64();
|
||||
#endif
|
||||
}
|
||||
|
||||
static const double double_nan_constant = NAN;
|
||||
|
|
|
@ -1094,6 +1094,10 @@ class Thread : public ThreadState {
|
|||
|
||||
void InitVMConstants();
|
||||
|
||||
int64_t GetNextTaskId() { return next_task_id_++; }
|
||||
static intptr_t next_task_id_offset() {
|
||||
return OFFSET_OF(Thread, next_task_id_);
|
||||
}
|
||||
Random* random() { return &thread_random_; }
|
||||
static intptr_t random_offset() { return OFFSET_OF(Thread, thread_random_); }
|
||||
|
||||
|
@ -1207,6 +1211,7 @@ class Thread : public ThreadState {
|
|||
uword exit_through_ffi_ = 0;
|
||||
ApiLocalScope* api_top_scope_;
|
||||
uint8_t double_truncate_round_supported_;
|
||||
ALIGN8 int64_t next_task_id_;
|
||||
ALIGN8 Random thread_random_;
|
||||
|
||||
TsanUtils* tsan_utils_ = nullptr;
|
||||
|
|
|
@ -498,19 +498,25 @@ void TimelineEvent::Duration(const char* label,
|
|||
}
|
||||
|
||||
void TimelineEvent::Begin(const char* label,
|
||||
int64_t id,
|
||||
int64_t micros,
|
||||
int64_t thread_micros) {
|
||||
Init(kBegin, label);
|
||||
set_timestamp0(micros);
|
||||
set_thread_timestamp0(thread_micros);
|
||||
// Overload timestamp1_ with the async_id.
|
||||
set_timestamp1(id);
|
||||
}
|
||||
|
||||
void TimelineEvent::End(const char* label,
|
||||
int64_t id,
|
||||
int64_t micros,
|
||||
int64_t thread_micros) {
|
||||
Init(kEnd, label);
|
||||
set_timestamp0(micros);
|
||||
set_thread_timestamp0(thread_micros);
|
||||
// Overload timestamp1_ with the async_id.
|
||||
set_timestamp1(id);
|
||||
}
|
||||
|
||||
void TimelineEvent::Counter(const char* label, int64_t micros) {
|
||||
|
@ -655,31 +661,31 @@ void TimelineEvent::PrintJSON(JSONWriter* writer) const {
|
|||
} break;
|
||||
case kAsyncBegin: {
|
||||
writer->PrintProperty("ph", "b");
|
||||
writer->PrintfProperty("id", "%" Px64 "", AsyncId());
|
||||
writer->PrintfProperty("id", "%" Px64 "", Id());
|
||||
} break;
|
||||
case kAsyncInstant: {
|
||||
writer->PrintProperty("ph", "n");
|
||||
writer->PrintfProperty("id", "%" Px64 "", AsyncId());
|
||||
writer->PrintfProperty("id", "%" Px64 "", Id());
|
||||
} break;
|
||||
case kAsyncEnd: {
|
||||
writer->PrintProperty("ph", "e");
|
||||
writer->PrintfProperty("id", "%" Px64 "", AsyncId());
|
||||
writer->PrintfProperty("id", "%" Px64 "", Id());
|
||||
} break;
|
||||
case kCounter: {
|
||||
writer->PrintProperty("ph", "C");
|
||||
} break;
|
||||
case kFlowBegin: {
|
||||
writer->PrintProperty("ph", "s");
|
||||
writer->PrintfProperty("id", "%" Px64 "", AsyncId());
|
||||
writer->PrintfProperty("id", "%" Px64 "", Id());
|
||||
} break;
|
||||
case kFlowStep: {
|
||||
writer->PrintProperty("ph", "t");
|
||||
writer->PrintfProperty("id", "%" Px64 "", AsyncId());
|
||||
writer->PrintfProperty("id", "%" Px64 "", Id());
|
||||
} break;
|
||||
case kFlowEnd: {
|
||||
writer->PrintProperty("ph", "f");
|
||||
writer->PrintProperty("bp", "e");
|
||||
writer->PrintfProperty("id", "%" Px64 "", AsyncId());
|
||||
writer->PrintfProperty("id", "%" Px64 "", Id());
|
||||
} break;
|
||||
case kMetadata: {
|
||||
writer->PrintProperty("ph", "M");
|
||||
|
@ -728,14 +734,6 @@ void TimelineEvent::PrintJSON(JSONWriter* writer) const {
|
|||
writer->CloseObject();
|
||||
}
|
||||
|
||||
int64_t TimelineEvent::TimeOrigin() const {
|
||||
return timestamp0_;
|
||||
}
|
||||
|
||||
int64_t TimelineEvent::AsyncId() const {
|
||||
return timestamp1_;
|
||||
}
|
||||
|
||||
int64_t TimelineEvent::LowTime() const {
|
||||
return timestamp0_;
|
||||
}
|
||||
|
@ -841,6 +839,13 @@ void TimelineEventScope::Init() {
|
|||
return;
|
||||
}
|
||||
enabled_ = true;
|
||||
Thread* thread = static_cast<Thread*>(this->thread());
|
||||
if (thread != NULL) {
|
||||
id_ = thread->GetNextTaskId();
|
||||
} else {
|
||||
static RelaxedAtomic<int64_t> next_bootstrap_task_id = {0};
|
||||
id_ = next_bootstrap_task_id.fetch_add(1);
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineEventScope::SetNumArguments(intptr_t length) {
|
||||
|
@ -919,7 +924,7 @@ void TimelineBeginEndScope::EmitBegin() {
|
|||
}
|
||||
ASSERT(event != NULL);
|
||||
// Emit a begin event.
|
||||
event->Begin(label());
|
||||
event->Begin(label(), id());
|
||||
event->Complete();
|
||||
}
|
||||
|
||||
|
@ -935,7 +940,7 @@ void TimelineBeginEndScope::EmitEnd() {
|
|||
}
|
||||
ASSERT(event != NULL);
|
||||
// Emit an end event.
|
||||
event->End(label());
|
||||
event->End(label(), id());
|
||||
StealArguments(event);
|
||||
event->Complete();
|
||||
}
|
||||
|
@ -958,7 +963,7 @@ IsolateTimelineEventFilter::IsolateTimelineEventFilter(
|
|||
isolate_id_(isolate_id) {}
|
||||
|
||||
TimelineEventRecorder::TimelineEventRecorder()
|
||||
: async_id_(0), time_low_micros_(0), time_high_micros_(0) {}
|
||||
: time_low_micros_(0), time_high_micros_(0) {}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
|
||||
|
@ -1120,16 +1125,6 @@ void TimelineEventRecorder::WriteTo(const char* directory) {
|
|||
}
|
||||
#endif
|
||||
|
||||
int64_t TimelineEventRecorder::GetNextAsyncId() {
|
||||
// TODO(johnmccutchan): Gracefully handle wrap around.
|
||||
#if defined(DART_HOST_OS_FUCHSIA)
|
||||
return trace_generate_nonce();
|
||||
#else
|
||||
uint32_t next = static_cast<uint32_t>(async_id_.fetch_add(1u));
|
||||
return static_cast<int64_t>(next);
|
||||
#endif
|
||||
}
|
||||
|
||||
void TimelineEventRecorder::FinishBlock(TimelineEventBlock* block) {
|
||||
if (block == NULL) {
|
||||
return;
|
||||
|
@ -1706,10 +1701,10 @@ void DartTimelineEventHelpers::ReportTaskEvent(Thread* thread,
|
|||
event->AsyncEnd(name, id, start);
|
||||
break;
|
||||
case 'B':
|
||||
event->Begin(name, start, start_cpu);
|
||||
event->Begin(name, id, start, start_cpu);
|
||||
break;
|
||||
case 'E':
|
||||
event->End(name, start, start_cpu);
|
||||
event->End(name, id, start, start_cpu);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
|
|
@ -334,10 +334,12 @@ class TimelineEvent {
|
|||
|
||||
void Begin(
|
||||
const char* label,
|
||||
int64_t id,
|
||||
int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline(),
|
||||
int64_t thread_micros = OS::GetCurrentThreadCPUMicrosForTimeline());
|
||||
|
||||
void End(const char* label,
|
||||
int64_t id,
|
||||
int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline(),
|
||||
int64_t thread_micros = OS::GetCurrentThreadCPUMicrosForTimeline());
|
||||
|
||||
|
@ -390,8 +392,11 @@ class TimelineEvent {
|
|||
int64_t ThreadCPUTimeDuration() const;
|
||||
int64_t ThreadCPUTimeOrigin() const;
|
||||
|
||||
int64_t TimeOrigin() const;
|
||||
int64_t AsyncId() const;
|
||||
int64_t TimeOrigin() const { return timestamp0_; }
|
||||
int64_t Id() const {
|
||||
ASSERT(event_type() != kDuration);
|
||||
return timestamp1_;
|
||||
}
|
||||
int64_t TimeDuration() const;
|
||||
int64_t TimeEnd() const {
|
||||
ASSERT(IsFinishedDuration());
|
||||
|
@ -598,6 +603,8 @@ class TimelineEventScope : public StackResource {
|
|||
|
||||
const char* label() const { return label_; }
|
||||
|
||||
int64_t id() const { return id_; }
|
||||
|
||||
TimelineEventArgument* arguments() const { return arguments_.buffer(); }
|
||||
|
||||
intptr_t arguments_length() const { return arguments_.length(); }
|
||||
|
@ -613,6 +620,7 @@ class TimelineEventScope : public StackResource {
|
|||
|
||||
TimelineStream* stream_;
|
||||
const char* label_;
|
||||
int64_t id_;
|
||||
TimelineEventArguments arguments_;
|
||||
bool enabled_;
|
||||
|
||||
|
@ -783,7 +791,6 @@ class TimelineEventRecorder : public MallocAllocated {
|
|||
virtual void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) = 0;
|
||||
#endif
|
||||
virtual const char* name() const = 0;
|
||||
int64_t GetNextAsyncId();
|
||||
|
||||
void FinishBlock(TimelineEventBlock* block);
|
||||
|
||||
|
@ -814,7 +821,6 @@ class TimelineEventRecorder : public MallocAllocated {
|
|||
int64_t TimeExtentMicros() const;
|
||||
|
||||
Mutex lock_;
|
||||
RelaxedAtomic<uintptr_t> async_id_;
|
||||
int64_t time_low_micros_;
|
||||
int64_t time_high_micros_;
|
||||
|
||||
|
|
|
@ -79,12 +79,12 @@ intptr_t TimelineEventSystraceRecorder::PrintSystrace(TimelineEvent* event,
|
|||
}
|
||||
case TimelineEvent::kAsyncBegin: {
|
||||
length = Utils::SNPrint(buffer, buffer_size, "S|%" Pd64 "|%s|%" Pd64 "",
|
||||
pid, event->label(), event->AsyncId());
|
||||
pid, event->label(), event->Id());
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kAsyncEnd: {
|
||||
length = Utils::SNPrint(buffer, buffer_size, "F|%" Pd64 "|%s|%" Pd64 "",
|
||||
pid, event->label(), event->AsyncId());
|
||||
pid, event->label(), event->Id());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -78,19 +78,19 @@ void TimelineEventFuchsiaRecorder::OnEvent(TimelineEvent* event) {
|
|||
args, num_args);
|
||||
break;
|
||||
case TimelineEvent::kAsyncBegin:
|
||||
trace_context_write_async_begin_event_record(
|
||||
context, start_time, &thread, &category, &name, event->AsyncId(),
|
||||
args, num_args);
|
||||
trace_context_write_async_begin_event_record(context, start_time, &thread,
|
||||
&category, &name,
|
||||
event->Id(), args, num_args);
|
||||
break;
|
||||
case TimelineEvent::kAsyncEnd:
|
||||
trace_context_write_async_end_event_record(
|
||||
context, end_time, &thread, &category, &name, event->AsyncId(), args,
|
||||
num_args);
|
||||
trace_context_write_async_end_event_record(context, end_time, &thread,
|
||||
&category, &name, event->Id(),
|
||||
args, num_args);
|
||||
break;
|
||||
case TimelineEvent::kAsyncInstant:
|
||||
trace_context_write_async_instant_event_record(
|
||||
context, start_time, &thread, &category, &name, event->AsyncId(),
|
||||
args, num_args);
|
||||
context, start_time, &thread, &category, &name, event->Id(), args,
|
||||
num_args);
|
||||
break;
|
||||
case TimelineEvent::kDuration:
|
||||
trace_context_write_duration_event_record(context, start_time, end_time,
|
||||
|
@ -98,19 +98,19 @@ void TimelineEventFuchsiaRecorder::OnEvent(TimelineEvent* event) {
|
|||
num_args);
|
||||
break;
|
||||
case TimelineEvent::kFlowBegin:
|
||||
trace_context_write_flow_begin_event_record(
|
||||
context, start_time, &thread, &category, &name, event->AsyncId(),
|
||||
args, num_args);
|
||||
trace_context_write_flow_begin_event_record(context, start_time, &thread,
|
||||
&category, &name, event->Id(),
|
||||
args, num_args);
|
||||
break;
|
||||
case TimelineEvent::kFlowStep:
|
||||
trace_context_write_flow_step_event_record(
|
||||
context, start_time, &thread, &category, &name, event->AsyncId(),
|
||||
args, num_args);
|
||||
trace_context_write_flow_step_event_record(context, start_time, &thread,
|
||||
&category, &name, event->Id(),
|
||||
args, num_args);
|
||||
break;
|
||||
case TimelineEvent::kFlowEnd:
|
||||
trace_context_write_flow_end_event_record(
|
||||
context, start_time, &thread, &category, &name, event->AsyncId(),
|
||||
args, num_args);
|
||||
trace_context_write_flow_end_event_record(context, start_time, &thread,
|
||||
&category, &name, event->Id(),
|
||||
args, num_args);
|
||||
break;
|
||||
default:
|
||||
// TODO(zra): Figure out what to do with kCounter and kMetadata.
|
||||
|
|
|
@ -79,12 +79,12 @@ intptr_t TimelineEventSystraceRecorder::PrintSystrace(TimelineEvent* event,
|
|||
}
|
||||
case TimelineEvent::kAsyncBegin: {
|
||||
length = Utils::SNPrint(buffer, buffer_size, "S|%" Pd64 "|%s|%" Pd64 "",
|
||||
pid, event->label(), event->AsyncId());
|
||||
pid, event->label(), event->Id());
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kAsyncEnd: {
|
||||
length = Utils::SNPrint(buffer, buffer_size, "F|%" Pd64 "|%s|%" Pd64 "",
|
||||
pid, event->label(), event->AsyncId());
|
||||
pid, event->label(), event->Id());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -40,28 +40,18 @@ void TimelineEventMacosRecorder::OnEvent(TimelineEvent* event) {
|
|||
buffer, sizeof(buffer));
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kBegin: {
|
||||
_os_signpost_emit_with_name_impl(
|
||||
&__dso_handle, log, OS_SIGNPOST_INTERVAL_BEGIN,
|
||||
OS_SIGNPOST_ID_EXCLUSIVE, label, "", buffer, sizeof(buffer));
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kEnd: {
|
||||
_os_signpost_emit_with_name_impl(
|
||||
&__dso_handle, log, OS_SIGNPOST_INTERVAL_END,
|
||||
OS_SIGNPOST_ID_EXCLUSIVE, label, "", buffer, sizeof(buffer));
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kBegin:
|
||||
case TimelineEvent::kAsyncBegin: {
|
||||
_os_signpost_emit_with_name_impl(
|
||||
&__dso_handle, log, OS_SIGNPOST_INTERVAL_BEGIN, event->AsyncId(),
|
||||
label, "", buffer, sizeof(buffer));
|
||||
_os_signpost_emit_with_name_impl(&__dso_handle, log,
|
||||
OS_SIGNPOST_INTERVAL_BEGIN, event->Id(),
|
||||
label, "", buffer, sizeof(buffer));
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kEnd:
|
||||
case TimelineEvent::kAsyncEnd: {
|
||||
_os_signpost_emit_with_name_impl(
|
||||
&__dso_handle, log, OS_SIGNPOST_INTERVAL_END, event->AsyncId(), label,
|
||||
"", buffer, sizeof(buffer));
|
||||
_os_signpost_emit_with_name_impl(&__dso_handle, log,
|
||||
OS_SIGNPOST_INTERVAL_END, event->Id(),
|
||||
label, "", buffer, sizeof(buffer));
|
||||
break;
|
||||
}
|
||||
case TimelineEvent::kCounter: {
|
||||
|
@ -69,8 +59,8 @@ void TimelineEventMacosRecorder::OnEvent(TimelineEvent* event) {
|
|||
Utils::SNPrint(reinterpret_cast<char*>(buffer), sizeof(buffer), fmt,
|
||||
event->arguments()[0].value);
|
||||
_os_signpost_emit_with_name_impl(&__dso_handle, log, OS_SIGNPOST_EVENT,
|
||||
event->AsyncId(), label, fmt, buffer,
|
||||
sizeof(buffer));
|
||||
OS_SIGNPOST_ID_EXCLUSIVE, label, fmt,
|
||||
buffer, sizeof(buffer));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -318,8 +318,8 @@ TEST_CASE(TimelineEventCallbackRecorderBasic) {
|
|||
|
||||
event = stream.StartEvent();
|
||||
EXPECT_EQ(0, override.recorder()->CountFor(TimelineEvent::kAsyncBegin));
|
||||
int64_t async_id = override.recorder()->GetNextAsyncId();
|
||||
EXPECT(async_id >= 0);
|
||||
int64_t async_id = thread->GetNextTaskId();
|
||||
EXPECT(async_id != 0);
|
||||
event->AsyncBegin("asyncBeginCabbage", async_id);
|
||||
EXPECT_EQ(0, override.recorder()->CountFor(TimelineEvent::kAsyncBegin));
|
||||
event->Complete();
|
||||
|
|
|
@ -157,7 +157,7 @@ void _reportInstantEvent(String category, String name, String argumentsAsJson) {
|
|||
}
|
||||
|
||||
@patch
|
||||
int _getNextAsyncId() {
|
||||
int _getNextTaskId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ void _reportInstantEvent(String category, String name, String argumentsAsJson) {
|
|||
}
|
||||
|
||||
@patch
|
||||
int _getNextAsyncId() {
|
||||
int _getNextTaskId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ external bool _isDartStreamEnabled();
|
|||
external int _getTraceClock();
|
||||
|
||||
@patch
|
||||
@pragma("vm:external-name", "Timeline_getNextAsyncId")
|
||||
external int _getNextAsyncId();
|
||||
@pragma("vm:external-name", "Timeline_getNextTaskId")
|
||||
external int _getNextTaskId();
|
||||
|
||||
@patch
|
||||
@pragma("vm:external-name", "Timeline_reportTaskEvent")
|
||||
|
|
|
@ -49,7 +49,7 @@ int _getTraceClock() => _traceClock++;
|
|||
int _traceClock = 0;
|
||||
|
||||
@patch
|
||||
int _getNextAsyncId() => 0;
|
||||
int _getNextTaskId() => 0;
|
||||
|
||||
@patch
|
||||
void _reportTaskEvent(int taskId, String phase, String category, String name,
|
||||
|
|
|
@ -60,7 +60,7 @@ class Flow {
|
|||
/// If [id] is not provided, an id that conflicts with no other Dart-generated
|
||||
/// flow id's will be generated.
|
||||
static Flow begin({int? id}) {
|
||||
return new Flow._(_begin, id ?? _getNextAsyncId());
|
||||
return new Flow._(_begin, id ?? _getNextTaskId());
|
||||
}
|
||||
|
||||
/// A "step" Flow event.
|
||||
|
@ -112,7 +112,8 @@ class Timeline {
|
|||
_stack.add(null);
|
||||
return;
|
||||
}
|
||||
var block = new _SyncBlock._(name, arguments: arguments, flow: flow);
|
||||
var block = new _SyncBlock._(name, _getNextTaskId(),
|
||||
arguments: arguments, flow: flow);
|
||||
_stack.add(block);
|
||||
block._startSync();
|
||||
}
|
||||
|
@ -190,7 +191,7 @@ class TimelineTask {
|
|||
TimelineTask({TimelineTask? parent, String? filterKey})
|
||||
: _parent = parent,
|
||||
_filterKey = filterKey,
|
||||
_taskId = _getNextAsyncId() {}
|
||||
_taskId = _getNextTaskId() {}
|
||||
|
||||
/// Create a task with an explicit [taskId]. This is useful if you are
|
||||
/// passing a task from one isolate to another.
|
||||
|
@ -335,6 +336,9 @@ class _SyncBlock {
|
|||
/// The name of this block.
|
||||
final String name;
|
||||
|
||||
/// Signpost needs help matching begin and end events.
|
||||
final int taskId;
|
||||
|
||||
/// An (optional) set of arguments which will be serialized to JSON and
|
||||
/// associated with this block.
|
||||
final Map? arguments;
|
||||
|
@ -344,18 +348,18 @@ class _SyncBlock {
|
|||
|
||||
late final String _jsonArguments = _argumentsAsJson(arguments);
|
||||
|
||||
_SyncBlock._(this.name, {this.arguments, this.flow});
|
||||
_SyncBlock._(this.name, this.taskId, {this.arguments, this.flow});
|
||||
|
||||
/// Start this block of time.
|
||||
void _startSync() {
|
||||
_reportTaskEvent(0, 'B', category, name, _jsonArguments);
|
||||
_reportTaskEvent(taskId, 'B', category, name, _jsonArguments);
|
||||
}
|
||||
|
||||
/// Finish this block of time. At this point, this block can no longer be
|
||||
/// used.
|
||||
void finish() {
|
||||
// Report event to runtime.
|
||||
_reportTaskEvent(0, 'E', category, name, _jsonArguments);
|
||||
_reportTaskEvent(taskId, 'E', category, name, _jsonArguments);
|
||||
final Flow? tempFlow = flow;
|
||||
if (tempFlow != null) {
|
||||
_reportFlowEvent(category, "${tempFlow.id}", tempFlow._type, tempFlow.id,
|
||||
|
@ -376,8 +380,9 @@ String _argumentsAsJson(Map? arguments) {
|
|||
@pragma("vm:recognized", "asm-intrinsic")
|
||||
external bool _isDartStreamEnabled();
|
||||
|
||||
/// Returns the next async task id.
|
||||
external int _getNextAsyncId();
|
||||
/// Returns the next task id.
|
||||
@pragma("vm:recognized", "asm-intrinsic")
|
||||
external int _getNextTaskId();
|
||||
|
||||
/// Returns the current value from the trace clock.
|
||||
external int _getTraceClock();
|
||||
|
|
Loading…
Reference in a new issue