1// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_TIMELINE_H_
6#define RUNTIME_VM_TIMELINE_H_
7
8#include <functional>
9#include <memory>
10
11#include "include/dart_tools_api.h"
12
13#include "platform/assert.h"
14#include "platform/atomic.h"
15#include "platform/hashmap.h"
16#include "vm/allocation.h"
17#include "vm/bitfield.h"
18#include "vm/globals.h"
19#include "vm/growable_array.h"
20#include "vm/os.h"
21#include "vm/os_thread.h"
22
23#if defined(SUPPORT_TIMELINE) && defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
24#include "perfetto/protozero/scattered_heap_buffer.h"
25#include "vm/protos/perfetto/trace/trace_packet.pbzero.h"
26#endif // defined(SUPPORT_TIMELINE) && defined(SUPPORT_PERFETTO) && \
27 // !defined(PRODUCT)
28
29#if defined(FUCHSIA_SDK) || defined(DART_HOST_OS_FUCHSIA)
30#include <lib/trace-engine/context.h>
31#include <lib/trace-engine/instrumentation.h>
32#elif defined(DART_HOST_OS_MACOS)
33#include <os/availability.h>
34#if defined(__MAC_10_14) || defined (__IPHONE_12_0)
35#define DART_HOST_OS_SUPPORTS_SIGNPOST 1
36#endif
37// signpost.h exists in macOS 10.14, iOS 12 or above
38#if defined(DART_HOST_OS_SUPPORTS_SIGNPOST)
39#include <os/signpost.h>
40#else
41#include <os/log.h>
42#endif
43#endif
44
45namespace dart {
46
47#if !defined(SUPPORT_TIMELINE)
48#define TIMELINE_DURATION(thread, stream, name)
49#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function)
50#define TIMELINE_FUNCTION_GC_DURATION(thread, name)
51#endif // !defined(SUPPORT_TIMELINE)
52
53class JSONArray;
54class JSONBase64String;
55class JSONObject;
56class JSONStream;
57class JSONWriter;
58class Object;
59class ObjectPointerVisitor;
60class Isolate;
61class Thread;
62class TimelineEvent;
63class TimelineEventBlock;
64class TimelineEventRecorder;
65class TimelineStream;
66class VirtualMemory;
67class Zone;
68
69#if defined(SUPPORT_TIMELINE)
70#define CALLBACK_RECORDER_NAME "Callback"
71#define ENDLESS_RECORDER_NAME "Endless"
72#define FILE_RECORDER_NAME "File"
73#define FUCHSIA_RECORDER_NAME "Fuchsia"
74#define MACOS_RECORDER_NAME "Macos"
75#define PERFETTO_FILE_RECORDER_NAME "Perfettofile"
76#define RING_RECORDER_NAME "Ring"
77#define STARTUP_RECORDER_NAME "Startup"
78#define SYSTRACE_RECORDER_NAME "Systrace"
79
80// (name, fuchsia_name, has_static_labels).
81#define TIMELINE_STREAM_LIST(V) \
82 V(API, "dart:api", true) \
83 V(Compiler, "dart:compiler", true) \
84 V(CompilerVerbose, "dart:compiler.verbose", true) \
85 V(Dart, "dart:dart", false) \
86 V(Debugger, "dart:debugger", true) \
87 V(Embedder, "dart:embedder", true) \
88 V(GC, "dart:gc", true) \
89 V(Isolate, "dart:isolate", true) \
90 V(VM, "dart:vm", true)
91#endif // defined(SUPPORT_TIMELINE)
92
93// A stream of timeline events. A stream has a name and can be enabled or
94// disabled (globally and per isolate).
95class TimelineStream {
96 public:
97 TimelineStream(const char* name,
98 const char* fuchsia_name,
99 bool static_labels,
100 bool enabled);
101
102 const char* name() const { return name_; }
103 const char* fuchsia_name() const { return fuchsia_name_; }
104
105 bool enabled() {
106#if defined(DART_HOST_OS_FUCHSIA)
107#ifdef PRODUCT
108 return trace_is_category_enabled(fuchsia_name_);
109#else
110 return trace_is_category_enabled(fuchsia_name_) || enabled_ != 0;
111#endif // PRODUCT
112#else
113 return enabled_ != 0;
114#endif // defined(DART_HOST_OS_FUCHSIA)
115 }
116
117 void set_enabled(bool enabled) { enabled_ = enabled ? 1 : 0; }
118
119 // Records an event. Will return |nullptr| if not enabled. The returned
120 // |TimelineEvent| is in an undefined state and must be initialized.
121 TimelineEvent* StartEvent();
122
123 static intptr_t enabled_offset() {
124 return OFFSET_OF(TimelineStream, enabled_);
125 }
126
127#if defined(DART_HOST_OS_FUCHSIA)
128 trace_site_t* trace_site() { return &trace_site_; }
129#elif defined(DART_HOST_OS_MACOS)
130 os_log_t macos_log() const { return macos_log_; }
131 bool has_static_labels() const { return has_static_labels_; }
132#endif
133
134 private:
135 const char* const name_;
136 const char* const fuchsia_name_;
137
138 // This field is accessed by generated code (intrinsic) and expects to see
139 // 0 or 1. If this becomes a BitField, the generated code must be updated.
140 uintptr_t enabled_;
141
142#if defined(DART_HOST_OS_FUCHSIA)
143 trace_site_t trace_site_ = {};
144#elif defined(DART_HOST_OS_MACOS)
145 os_log_t macos_log_ = {};
146 bool has_static_labels_ = false;
147#endif
148};
149
150#if defined(SUPPORT_TIMELINE)
151class RecorderSynchronizationLock : public AllStatic {
152 public:
153 static void Init() {
154 recorder_state_.store(d: kActive, m: std::memory_order_release);
155 outstanding_event_writes_.store(d: 0);
156 }
157
158 static void EnterLock() {
159 outstanding_event_writes_.fetch_add(op: 1, m: std::memory_order_acquire);
160 }
161
162 static void ExitLock() {
163 intptr_t count =
164 outstanding_event_writes_.fetch_sub(op: 1, m: std::memory_order_release);
165 ASSERT(count >= 0);
166 }
167
168 static bool IsUninitialized() {
169 return (recorder_state_.load(m: std::memory_order_acquire) == kUninitialized);
170 }
171
172 static bool IsActive() {
173 return (recorder_state_.load(m: std::memory_order_acquire) == kActive);
174 }
175
176 static void WaitForShutdown() {
177 recorder_state_.store(d: kShuttingDown, m: std::memory_order_release);
178 // Spin waiting for outstanding events to be completed.
179 while (outstanding_event_writes_.load(m: std::memory_order_relaxed) > 0) {
180 }
181 }
182
183 private:
184 typedef enum { kUninitialized = 0, kActive, kShuttingDown } RecorderState;
185 static std::atomic<RecorderState> recorder_state_;
186 static std::atomic<intptr_t> outstanding_event_writes_;
187
188 DISALLOW_COPY_AND_ASSIGN(RecorderSynchronizationLock);
189};
190
191// Any modifications to the timeline must be guarded by a
192// |RecorderSynchronizationLockScope| to prevent the timeline from being
193// cleaned up in the middle of the modifications.
194class RecorderSynchronizationLockScope {
195 public:
196 RecorderSynchronizationLockScope() {
197 RecorderSynchronizationLock::EnterLock();
198 }
199
200 ~RecorderSynchronizationLockScope() {
201 RecorderSynchronizationLock::ExitLock();
202 }
203
204 bool IsUninitialized() const {
205 return RecorderSynchronizationLock::IsUninitialized();
206 }
207
208 bool IsActive() const { return RecorderSynchronizationLock::IsActive(); }
209
210 private:
211 DISALLOW_COPY_AND_ASSIGN(RecorderSynchronizationLockScope);
212};
213
214class Timeline : public AllStatic {
215 public:
216 // Initialize timeline system. Not thread safe.
217 static void Init();
218
219 // Cleanup timeline system. Not thread safe.
220 static void Cleanup();
221
222 // Access the global recorder. Not thread safe.
223 static TimelineEventRecorder* recorder() { return recorder_; }
224
225 static bool recorder_discards_clock_values() {
226 return recorder_discards_clock_values_;
227 }
228 static void set_recorder_discards_clock_values(bool value) {
229 recorder_discards_clock_values_ = value;
230 }
231
232 static Dart_TimelineRecorderCallback callback() { return callback_; }
233 static void set_callback(Dart_TimelineRecorderCallback callback) {
234 callback_ = callback;
235 }
236
237 // Reclaim all |TimelineEventBlocks|s that are cached by threads.
238 static void ReclaimCachedBlocksFromThreads();
239
240 static void Clear();
241
242#ifndef PRODUCT
243 // Print information about streams to JSON.
244 static void PrintFlagsToJSON(JSONStream* json);
245
246 // Output the recorded streams to a JSONS array.
247 static void PrintFlagsToJSONArray(JSONArray* arr);
248#endif
249
250#define TIMELINE_STREAM_ACCESSOR(name, ...) \
251 static TimelineStream* Get##name##Stream() { return &stream_##name##_; }
252 TIMELINE_STREAM_LIST(TIMELINE_STREAM_ACCESSOR)
253#undef TIMELINE_STREAM_ACCESSOR
254
255#define TIMELINE_STREAM_FLAGS(name, ...) \
256 static void SetStream##name##Enabled(bool enabled) { \
257 stream_##name##_.set_enabled(enabled); \
258 }
259 TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAGS)
260#undef TIMELINE_STREAM_FLAGS
261
262 private:
263 static TimelineEventRecorder* recorder_;
264 static Dart_TimelineRecorderCallback callback_;
265 static MallocGrowableArray<char*>* enabled_streams_;
266 static bool recorder_discards_clock_values_;
267
268#define TIMELINE_STREAM_DECLARE(name, ...) \
269 static TimelineStream stream_##name##_;
270 TIMELINE_STREAM_LIST(TIMELINE_STREAM_DECLARE)
271#undef TIMELINE_STREAM_DECLARE
272
273 template <class>
274 friend class TimelineRecorderOverride;
275 friend class ReclaimBlocksIsolateVisitor;
276};
277
278struct TimelineEventArgument {
279 const char* name;
280 char* value;
281};
282
283class TimelineEventArguments {
284 public:
285 TimelineEventArguments() : buffer_(nullptr), length_(0) {}
286 ~TimelineEventArguments() { Free(); }
287 // Get/Set the number of arguments in the event.
288 void SetNumArguments(intptr_t length);
289 // |name| must be a compile time constant. Takes ownership of |argument|.
290 void SetArgument(intptr_t i, const char* name, char* argument);
291 // |name| must be a compile time constant. Copies |argument|.
292 void CopyArgument(intptr_t i, const char* name, const char* argument);
293 // |name| must be a compile time constant. Takes ownership of |args|
294 void FormatArgument(intptr_t i,
295 const char* name,
296 const char* fmt,
297 va_list args);
298
299 void StealArguments(TimelineEventArguments* arguments);
300
301 TimelineEventArgument* buffer() const { return buffer_; }
302
303 intptr_t length() const { return length_; }
304
305 void Free();
306
307 TimelineEventArgument& operator[](intptr_t index) const {
308 return buffer_[index];
309 }
310
311 bool IsEmpty() { return length_ == 0; }
312
313 bool IsNotEmpty() { return length_ != 0; }
314
315 private:
316 TimelineEventArgument* buffer_;
317 intptr_t length_;
318 DISALLOW_COPY_AND_ASSIGN(TimelineEventArguments);
319};
320
321// You should get a |TimelineEvent| from a |TimelineStream|.
322class TimelineEvent {
323 public:
324 // Keep in sync with StateBits below.
325 // Keep in sync with constants in sdk/lib/developer/timeline.dart.
326 enum EventType {
327 kNone = 0,
328 kBegin = 1,
329 kEnd = 2,
330 kDuration = 3,
331 kInstant = 4,
332 kAsyncBegin = 5,
333 kAsyncInstant = 6,
334 kAsyncEnd = 7,
335 kCounter = 8,
336 kFlowBegin = 9,
337 kFlowStep = 10,
338 kFlowEnd = 11,
339 kMetadata = 12,
340 kNumEventTypes,
341 };
342
343 // This value must be kept in sync with the value of _noFlowId in
344 // sdk/lib/developer/timeline.dart.
345 static const int64_t kNoFlowId = -1;
346
347 TimelineEvent();
348 ~TimelineEvent();
349
350 void Reset();
351
352 bool IsValid() const {
353 return (event_type() > kNone) && (event_type() < kNumEventTypes);
354 }
355
356 // Marks the beginning of an asynchronous operation with |async_id|.
357 void AsyncBegin(const char* label,
358 int64_t async_id,
359 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
360 // Marks an instantaneous event associated with |async_id|.
361 void AsyncInstant(
362 const char* label,
363 int64_t async_id,
364 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
365 // Marks the end of an asynchronous operation associated with |async_id|.
366 void AsyncEnd(const char* label,
367 int64_t async_id,
368 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
369
370 void DurationBegin(
371 const char* label,
372 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
373
374 void Instant(const char* label,
375 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
376
377 void Duration(const char* label, int64_t start_micros, int64_t end_micros);
378
379 void Begin(const char* label,
380 int64_t id,
381 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
382
383 void End(const char* label,
384 int64_t id,
385 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
386
387 void Counter(const char* label,
388 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
389
390 void FlowBegin(const char* label,
391 int64_t id,
392 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
393 void FlowStep(const char* label,
394 int64_t id,
395 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
396 void FlowEnd(const char* label,
397 int64_t id,
398 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
399
400 void Metadata(const char* label,
401 int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline());
402
403 void CompleteWithPreSerializedArgs(char* args_json);
404
405 // Get/Set the number of arguments in the event.
406 intptr_t GetNumArguments() const { return arguments_.length(); }
407 void SetNumArguments(intptr_t length) { arguments_.SetNumArguments(length); }
408 // |name| must be a compile time constant. Takes ownership of |argument|.
409 void SetArgument(intptr_t i, const char* name, char* argument) {
410 arguments_.SetArgument(i, name, argument);
411 }
412 // |name| must be a compile time constant. Copies |argument|.
413 void CopyArgument(intptr_t i, const char* name, const char* argument) {
414 arguments_.CopyArgument(i, name, argument);
415 }
416 // |name| must be a compile time constant.
417 void FormatArgument(intptr_t i, const char* name, const char* fmt, ...)
418 PRINTF_ATTRIBUTE(4, 5);
419
420 void StealArguments(TimelineEventArguments* arguments) {
421 arguments_.StealArguments(arguments);
422 }
423 // Mandatory to call when this event is completely filled out.
424 void Complete();
425
426 EventType event_type() const { return EventTypeField::decode(value: state_); }
427
428 TimelineStream* stream() const { return stream_; }
429
430 int64_t TimeOrigin() const { return timestamp0_; }
431 int64_t Id() const {
432 ASSERT(event_type() != kDuration && event_type() != kInstant &&
433 event_type() != kCounter);
434 return timestamp1_or_id_;
435 }
436 int64_t TimeDuration() const;
437 void SetTimeEnd(int64_t micros = OS::GetCurrentMonotonicMicrosForTimeline()) {
438 ASSERT(event_type() == kDuration);
439 ASSERT(timestamp1_or_id_ == 0);
440 set_timestamp1_or_id(micros);
441 }
442 int64_t TimeEnd() const {
443 ASSERT(IsFinishedDuration());
444 return timestamp1_or_id_;
445 }
446
447 int64_t timestamp0() const { return timestamp0_; }
448 int64_t timestamp1_or_id() const { return timestamp1_or_id_; }
449
450 void SetFlowIds(intptr_t flow_id_count,
451 std::unique_ptr<const int64_t[]>& flow_ids) {
452 flow_id_count_ = flow_id_count;
453 flow_ids_.swap(u&: flow_ids);
454 }
455 intptr_t flow_id_count() const { return flow_id_count_; }
456 const int64_t* FlowIds() const { return flow_ids_.get(); }
457
458 bool HasIsolateId() const;
459 bool HasIsolateGroupId() const;
460 std::unique_ptr<const char[]> GetFormattedIsolateId() const;
461 std::unique_ptr<const char[]> GetFormattedIsolateGroupId() const;
462
463 // The lowest time value stored in this event.
464 int64_t LowTime() const;
465 // The highest time value stored in this event.
466 int64_t HighTime() const;
467
468#ifndef PRODUCT
469 void PrintJSON(JSONStream* stream) const;
470#endif
471 void PrintJSON(JSONWriter* writer) const;
472#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
473 bool CanBeRepresentedByPerfettoTracePacket() const;
474 /*
475 * Populates the fields of |packet| with this event's data.
476 */
477 void PopulateTracePacket(perfetto::protos::pbzero::TracePacket* packet) const;
478#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
479
480 ThreadId thread() const { return thread_; }
481
482 void set_thread(ThreadId tid) { thread_ = tid; }
483
484 Dart_Port isolate_id() const { return isolate_id_; }
485
486 uint64_t isolate_group_id() const { return isolate_group_id_; }
487
488 void* isolate_data() const { return isolate_data_; }
489
490 void* isolate_group_data() const { return isolate_group_data_; }
491
492 const char* label() const { return label_; }
493
494 // Does this duration end before |micros| ?
495 bool DurationFinishedBefore(int64_t micros) const {
496 return TimeEnd() <= micros;
497 }
498
499 bool IsDuration() const { return (event_type() == kDuration); }
500
501 bool IsBegin() const { return (event_type() == kBegin); }
502
503 bool IsEnd() const { return (event_type() == kEnd); }
504
505 // Is this event a synchronous begin or end event?
506 bool IsBeginOrEnd() const { return IsBegin() || IsEnd(); }
507
508 // Does this duration fully contain |other| ?
509 bool DurationContains(TimelineEvent* other) const {
510 ASSERT(IsFinishedDuration());
511 if (other->IsBegin()) {
512 if (other->TimeOrigin() < TimeOrigin()) {
513 return false;
514 }
515 if (other->TimeOrigin() > TimeEnd()) {
516 return false;
517 }
518 return true;
519 } else {
520 ASSERT(other->IsFinishedDuration());
521 if (other->TimeOrigin() < TimeOrigin()) {
522 return false;
523 }
524 if (other->TimeEnd() < TimeOrigin()) {
525 return false;
526 }
527 if (other->TimeOrigin() > TimeEnd()) {
528 return false;
529 }
530 if (other->TimeEnd() > TimeEnd()) {
531 return false;
532 }
533 return true;
534 }
535 }
536
537 bool Within(int64_t time_origin_micros, int64_t time_extent_micros);
538
539 void set_owns_label(bool owns_label) {
540 state_ = OwnsLabelBit::update(value: owns_label, original: state_);
541 }
542
543 TimelineEventArgument* arguments() const { return arguments_.buffer(); }
544
545 intptr_t arguments_length() const { return arguments_.length(); }
546
547 bool ArgsArePreSerialized() const {
548 return PreSerializedArgsBit::decode(value: state_);
549 }
550
551 TimelineEvent* next() const {
552 return next_;
553 }
554 void set_next(TimelineEvent* next) {
555 next_ = next;
556 }
557
558 private:
559 void StreamInit(TimelineStream* stream) { stream_ = stream; }
560 void Init(EventType event_type, const char* label);
561
562 void set_event_type(EventType event_type) {
563 // We only reserve 4 bits to hold the event type.
564 COMPILE_ASSERT(kNumEventTypes < 16);
565 state_ = EventTypeField::update(value: event_type, original: state_);
566 }
567
568 void set_timestamp0(int64_t value) {
569 ASSERT(timestamp0_ == 0);
570 timestamp0_ = value;
571 }
572 void set_timestamp1_or_id(int64_t value) {
573 ASSERT(timestamp1_or_id_ == 0);
574 timestamp1_or_id_ = value;
575 }
576
577 bool IsFinishedDuration() const {
578 return (event_type() == kDuration) && (timestamp1_or_id_ > timestamp0_);
579 }
580
581 void set_pre_serialized_args(bool pre_serialized_args) {
582 state_ = PreSerializedArgsBit::update(value: pre_serialized_args, original: state_);
583 }
584
585 bool owns_label() const { return OwnsLabelBit::decode(value: state_); }
586
587 enum StateBits {
588 kEventTypeBit = 0, // reserve 4 bits for type.
589 kPreSerializedArgsBit = 4,
590 kOwnsLabelBit = 5,
591 kNextBit = 6,
592 };
593
594 class EventTypeField : public BitField<uword, EventType, kEventTypeBit, 4> {};
595 class PreSerializedArgsBit
596 : public BitField<uword, bool, kPreSerializedArgsBit, 1> {};
597 class OwnsLabelBit : public BitField<uword, bool, kOwnsLabelBit, 1> {};
598
599 int64_t timestamp0_;
600 // For an event of type |kDuration|, this is the end time. For an event of
601 // type |kFlowBegin|, |kFlowStep|, or |kFlowEnd| this is the flow ID. For an
602 // event of type |kBegin| or |kEnd|, this is the event ID (which is only
603 // referenced by the MacOS recorder). For an async event, this is the async
604 // ID.
605 int64_t timestamp1_or_id_;
606 intptr_t flow_id_count_;
607 // This field is needed to support trace serialization in Perfetto's proto
608 // format. Flow IDs must be associated with |TimelineEvent::kBegin|,
609 // |TimelineEvent::kDuration|, |TimelineEvent::kInstant|,
610 // |TimelineEvent::kAsyncBegin|, and |TimelineEvent::kAsyncInstant| events to
611 // serialize traces in Perfetto's format. Flow event information is serialized
612 // in Chrome's JSON trace format through events of type
613 // |TimelineEvent::kFlowBegin|, |TimelineEvent::kFlowStep|, and
614 // |TimelineEvent::kFlowEnd|.
615 std::unique_ptr<const int64_t[]> flow_ids_;
616 TimelineEventArguments arguments_;
617 uword state_;
618 const char* label_;
619 TimelineStream* stream_;
620 ThreadId thread_;
621 Dart_Port isolate_id_;
622 uint64_t isolate_group_id_;
623 void* isolate_data_;
624 void* isolate_group_data_;
625 TimelineEvent* next_;
626
627 friend class TimelineEventRecorder;
628 friend class TimelineEventEndlessRecorder;
629 friend class TimelineEventRingRecorder;
630 friend class TimelineEventStartupRecorder;
631 friend class TimelineEventPlatformRecorder;
632 friend class TimelineEventFuchsiaRecorder;
633 friend class TimelineEventMacosRecorder;
634#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
635 friend class TimelineEventPerfettoFileRecorder;
636#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
637 friend class TimelineStream;
638 friend class TimelineTestHelper;
639 DISALLOW_COPY_AND_ASSIGN(TimelineEvent);
640};
641
642class TimelineTrackMetadata {
643 public:
644 TimelineTrackMetadata(intptr_t pid,
645 intptr_t tid,
646 Utils::CStringUniquePtr&& track_name);
647 intptr_t pid() const { return pid_; }
648 intptr_t tid() const { return tid_; }
649 const char* track_name() const { return track_name_.get(); }
650 inline void set_track_name(Utils::CStringUniquePtr&& track_name);
651#if !defined(PRODUCT)
652 /*
653 * Prints a Chrome-format event representing the metadata stored by this
654 * object into |jsarr_events|.
655 */
656 void PrintJSON(const JSONArray& jsarr_events) const;
657#if defined(SUPPORT_PERFETTO)
658 /*
659 * Populates the fields of |track_descriptor_packet| with the metadata stored
660 * by this object.
661 */
662 void PopulateTracePacket(
663 perfetto::protos::pbzero::TracePacket* track_descriptor_packet) const;
664#endif // defined(SUPPORT_PERFETTO)
665#endif // !defined(PRODUCT)
666
667 private:
668 // The ID of the process that this track is associated with.
669 intptr_t pid_;
670 // The trace ID of the thread that this track is associated with.
671 intptr_t tid_;
672 // The name of this track.
673 Utils::CStringUniquePtr track_name_;
674};
675
676class AsyncTimelineTrackMetadata {
677 public:
678 AsyncTimelineTrackMetadata(intptr_t pid, intptr_t async_id);
679 intptr_t pid() const { return pid_; }
680 intptr_t async_id() const { return async_id_; }
681#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
682 /*
683 * Populates the fields of |track_descriptor_packet| with the metadata stored
684 * by this object.
685 */
686 void PopulateTracePacket(
687 perfetto::protos::pbzero::TracePacket* track_descriptor_packet) const;
688#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
689
690 private:
691 // The ID of the process that this track is associated with.
692 intptr_t pid_;
693 // The async ID that this track is associated with.
694 intptr_t async_id_;
695};
696
697#define TIMELINE_DURATION(thread, stream, name) \
698 TimelineBeginEndScope tbes(thread, Timeline::Get##stream##Stream(), name);
699#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function) \
700 TimelineBeginEndScope tbes(thread, Timeline::GetCompilerStream(), name); \
701 if (tbes.enabled()) { \
702 tbes.SetNumArguments(1); \
703 tbes.CopyArgument(0, "function", function.ToQualifiedCString()); \
704 }
705
706#define TIMELINE_FUNCTION_GC_DURATION(thread, name) \
707 TimelineBeginEndScope tbes(thread, Timeline::GetGCStream(), name);
708
709// See |TimelineBeginEndScope|.
710class TimelineEventScope : public StackResource {
711 public:
712 bool enabled() const { return enabled_; }
713
714 intptr_t GetNumArguments() { return arguments_.length(); }
715 void SetNumArguments(intptr_t length);
716
717 void SetArgument(intptr_t i, const char* name, char* argument);
718
719 void CopyArgument(intptr_t i, const char* name, const char* argument);
720
721 void FormatArgument(intptr_t i, const char* name, const char* fmt, ...)
722 PRINTF_ATTRIBUTE(4, 5);
723
724 protected:
725 TimelineEventScope(TimelineStream* stream, const char* label);
726
727 TimelineEventScope(Thread* thread, TimelineStream* stream, const char* label);
728
729 bool ShouldEmitEvent() const { return enabled_; }
730
731 void set_enabled(bool enabled) { enabled_ = enabled; }
732
733 const char* label() const { return label_; }
734
735 int64_t id() const { return id_; }
736
737 TimelineEventArgument* arguments() const { return arguments_.buffer(); }
738
739 intptr_t arguments_length() const { return arguments_.length(); }
740
741 TimelineStream* stream() const { return stream_; }
742
743 virtual ~TimelineEventScope();
744
745 void StealArguments(TimelineEvent* event);
746
747 private:
748 void Init();
749
750 TimelineStream* stream_;
751 const char* label_;
752 int64_t id_;
753 TimelineEventArguments arguments_;
754 bool enabled_;
755
756 DISALLOW_COPY_AND_ASSIGN(TimelineEventScope);
757};
758
759class TimelineBeginEndScope : public TimelineEventScope {
760 public:
761 TimelineBeginEndScope(TimelineStream* stream, const char* label);
762
763 TimelineBeginEndScope(Thread* thread,
764 TimelineStream* stream,
765 const char* label);
766
767 virtual ~TimelineBeginEndScope();
768
769 private:
770 void EmitBegin();
771 void EmitEnd();
772
773 DISALLOW_COPY_AND_ASSIGN(TimelineBeginEndScope);
774};
775
776// A block of |TimelineEvent|s. Not thread safe.
777class TimelineEventBlock : public MallocAllocated {
778 public:
779 static constexpr intptr_t kBlockSize = 64;
780
781 explicit TimelineEventBlock(intptr_t index);
782 ~TimelineEventBlock();
783
784 TimelineEventBlock* next() const { return next_; }
785 void set_next(TimelineEventBlock* next) { next_ = next; }
786
787 intptr_t length() const { return length_; }
788
789 intptr_t block_index() const { return block_index_; }
790
791 bool IsEmpty() const { return length_ == 0; }
792
793 bool IsFull() const { return length_ == kBlockSize; }
794
795 TimelineEvent* At(intptr_t index) {
796 ASSERT(index >= 0);
797 ASSERT(index < kBlockSize);
798 return &events_[index];
799 }
800
801 const TimelineEvent* At(intptr_t index) const {
802 ASSERT(index >= 0);
803 ASSERT(index < kBlockSize);
804 return &events_[index];
805 }
806
807 // Attempt to sniff the timestamp from the first event.
808 int64_t LowerTimeBound() const;
809
810 // Call Reset on all events and set length to 0.
811 void Reset();
812
813 // Only safe to access under the recorder's lock.
814 inline bool InUseLocked() const;
815
816 // Only safe to access under the recorder's lock.
817 inline bool ContainsEventsThatCanBeSerializedLocked() const;
818
819 protected:
820#ifndef PRODUCT
821 void PrintJSON(JSONStream* stream) const;
822#endif
823
824 // Only safe to call from the thread that owns this block, while the thread is
825 // holding its block lock.
826 TimelineEvent* StartEventLocked();
827
828 TimelineEvent events_[kBlockSize];
829 TimelineEventBlock* next_;
830 intptr_t length_;
831 intptr_t block_index_;
832
833 // Only safe to access under the recorder's lock.
834 OSThread* current_owner_;
835 bool in_use_;
836
837 void Open();
838
839 friend class Thread;
840 friend class TimelineEventRecorder;
841 friend class TimelineEventEndlessRecorder;
842 friend class TimelineEventRingRecorder;
843 friend class TimelineEventStartupRecorder;
844 friend class TimelineEventPlatformRecorder;
845 friend class TimelineTestHelper;
846 friend class JSONStream;
847
848 private:
849 void Finish();
850
851 DISALLOW_COPY_AND_ASSIGN(TimelineEventBlock);
852};
853
854class TimelineEventFilter : public ValueObject {
855 public:
856 TimelineEventFilter(int64_t time_origin_micros = -1,
857 int64_t time_extent_micros = -1);
858
859 virtual ~TimelineEventFilter();
860
861 virtual bool IncludeEvent(TimelineEvent* event) const {
862 if (event == nullptr) {
863 return false;
864 }
865 return event->IsValid();
866 }
867
868 int64_t time_origin_micros() const { return time_origin_micros_; }
869
870 int64_t time_extent_micros() const { return time_extent_micros_; }
871
872 private:
873 int64_t time_origin_micros_;
874 int64_t time_extent_micros_;
875};
876
877class IsolateTimelineEventFilter : public TimelineEventFilter {
878 public:
879 explicit IsolateTimelineEventFilter(Dart_Port isolate_id,
880 int64_t time_origin_micros = -1,
881 int64_t time_extent_micros = -1);
882
883 bool IncludeEvent(TimelineEvent* event) const final {
884 return event->IsValid() && (event->isolate_id() == isolate_id_);
885 }
886
887 private:
888 Dart_Port isolate_id_;
889};
890
891// Recorder of |TimelineEvent|s.
892class TimelineEventRecorder : public MallocAllocated {
893 public:
894 TimelineEventRecorder();
895 virtual ~TimelineEventRecorder();
896
897 // Interface method(s) which must be implemented.
898#ifndef PRODUCT
899 virtual void PrintJSON(JSONStream* js, TimelineEventFilter* filter) = 0;
900#if defined(SUPPORT_PERFETTO)
901 /*
902 * Prints a PerfettoTimeline service response into |js|.
903 */
904 virtual void PrintPerfettoTimeline(JSONStream* js,
905 const TimelineEventFilter& filter) = 0;
906#endif // defined(SUPPORT_PERFETTO)
907 virtual void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) = 0;
908#endif // !defined(PRODUCT)
909 virtual const char* name() const = 0;
910 virtual intptr_t Size() = 0;
911 // Only safe to call when holding |lock_|.
912 virtual TimelineEventBlock* GetNewBlockLocked() = 0;
913 void FinishBlock(TimelineEventBlock* block);
914 // This function must be called at least once for each thread that corresponds
915 // to a track in the trace.
916 void AddTrackMetadataBasedOnThread(const intptr_t process_id,
917 const intptr_t trace_id,
918 const char* thread_name);
919 void AddAsyncTrackMetadataBasedOnEvent(const TimelineEvent& event);
920
921 protected:
922 SimpleHashMap& track_uuid_to_track_metadata() {
923 return track_uuid_to_track_metadata_;
924 }
925 SimpleHashMap& async_track_uuid_to_track_metadata() {
926 return async_track_uuid_to_track_metadata_;
927 }
928#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
929 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet() {
930 return packet_;
931 }
932#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
933
934#ifndef PRODUCT
935 void WriteTo(const char* directory);
936#endif
937
938 // Interface method(s) which must be implemented.
939 virtual TimelineEvent* StartEvent() = 0;
940 virtual void CompleteEvent(TimelineEvent* event) = 0;
941 // Only safe to call when holding |lock_|.
942 virtual TimelineEventBlock* GetHeadBlockLocked() = 0;
943 // Only safe to call when holding |lock_|.
944 virtual void ClearLocked() = 0;
945
946 // Utility method(s).
947#ifndef PRODUCT
948 void PrintJSONMeta(const JSONArray& jsarr_events);
949#if defined(SUPPORT_PERFETTO)
950 /*
951 * Appends metadata about the timeline in Perfetto's proto format to
952 * |jsonBase64String|.
953 */
954 void PrintPerfettoMeta(JSONBase64String* jsonBase64String);
955#endif // defined(SUPPORT_PERFETTO)
956#endif // !defined(PRODUCT)
957 TimelineEvent* ThreadBlockStartEvent();
958 void ThreadBlockCompleteEvent(TimelineEvent* event);
959
960 void ResetTimeTracking();
961 void ReportTime(int64_t micros);
962 int64_t TimeOriginMicros() const;
963 int64_t TimeExtentMicros() const;
964
965 Mutex lock_;
966 int64_t time_low_micros_;
967 int64_t time_high_micros_;
968
969 friend class TimelineEvent;
970 friend class TimelineEventBlock;
971 friend class TimelineStream;
972 friend class TimelineTestHelper;
973 friend class Timeline;
974 friend class OSThread;
975
976 private:
977 static constexpr intptr_t kTrackUuidToTrackMetadataInitialCapacity = 1 << 4;
978 Mutex track_uuid_to_track_metadata_lock_;
979 SimpleHashMap track_uuid_to_track_metadata_;
980 Mutex async_track_uuid_to_track_metadata_lock_;
981 SimpleHashMap async_track_uuid_to_track_metadata_;
982#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
983 // We allocate one heap-buffered packet as a class member, because it lets us
984 // continuously follow a cycle of resetting the buffer and writing its
985 // contents.
986 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket> packet_;
987#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
988
989 DISALLOW_COPY_AND_ASSIGN(TimelineEventRecorder);
990};
991
992// An abstract recorder that stores events in a buffer of fixed capacity.
993class TimelineEventFixedBufferRecorder : public TimelineEventRecorder {
994 public:
995 static constexpr intptr_t kDefaultCapacity = 32 * KB; // Number of events.
996
997 explicit TimelineEventFixedBufferRecorder(intptr_t capacity);
998 virtual ~TimelineEventFixedBufferRecorder();
999
1000#ifndef PRODUCT
1001 void PrintJSON(JSONStream* js, TimelineEventFilter* filter) final;
1002#if defined(SUPPORT_PERFETTO)
1003 void PrintPerfettoTimeline(JSONStream* js,
1004 const TimelineEventFilter& filter) final;
1005#endif // defined(SUPPORT_PERFETTO)
1006 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) final;
1007#endif // !defined(PRODUCT)
1008
1009 intptr_t Size();
1010
1011 protected:
1012 TimelineEvent* StartEvent();
1013 void CompleteEvent(TimelineEvent* event);
1014 TimelineEventBlock* GetHeadBlockLocked();
1015 // Only safe to call when holding |lock_|.
1016 intptr_t FindOldestBlockIndexLocked() const;
1017 void ClearLocked();
1018
1019#ifndef PRODUCT
1020 void PrintJSONEvents(const JSONArray& array,
1021 const TimelineEventFilter& filter);
1022#if defined(SUPPORT_PERFETTO)
1023 void PrintPerfettoEvents(JSONBase64String* jsonBase64String,
1024 const TimelineEventFilter& filter);
1025#endif // defined(SUPPORT_PERFETTO)
1026#endif // !defined(PRODUCT)
1027
1028 VirtualMemory* memory_;
1029 TimelineEventBlock* blocks_;
1030 intptr_t capacity_;
1031 intptr_t num_blocks_;
1032 intptr_t block_cursor_;
1033
1034 private:
1035#if !defined(PRODUCT)
1036 inline void PrintEventsCommon(
1037 const TimelineEventFilter& filter,
1038 std::function<void(const TimelineEvent&)>&& print_impl);
1039#endif // !defined(PRODUCT)
1040};
1041
1042// A recorder that stores events in a buffer of fixed capacity. When the buffer
1043// is full, new events overwrite old events.
1044class TimelineEventRingRecorder : public TimelineEventFixedBufferRecorder {
1045 public:
1046 explicit TimelineEventRingRecorder(intptr_t capacity = kDefaultCapacity)
1047 : TimelineEventFixedBufferRecorder(capacity) {}
1048 virtual ~TimelineEventRingRecorder() {}
1049
1050 const char* name() const { return RING_RECORDER_NAME; }
1051
1052 protected:
1053 TimelineEventBlock* GetNewBlockLocked();
1054};
1055
1056// A recorder that stores events in a buffer of fixed capacity. When the buffer
1057// is full, new events are dropped.
1058class TimelineEventStartupRecorder : public TimelineEventFixedBufferRecorder {
1059 public:
1060 explicit TimelineEventStartupRecorder(intptr_t capacity = kDefaultCapacity)
1061 : TimelineEventFixedBufferRecorder(capacity) {}
1062 virtual ~TimelineEventStartupRecorder() {}
1063
1064 const char* name() const { return STARTUP_RECORDER_NAME; }
1065
1066 protected:
1067 TimelineEventBlock* GetNewBlockLocked();
1068};
1069
1070// An abstract recorder that calls |OnEvent| whenever an event is complete.
1071// This should only be used for testing.
1072class TimelineEventCallbackRecorder : public TimelineEventRecorder {
1073 public:
1074 TimelineEventCallbackRecorder();
1075 virtual ~TimelineEventCallbackRecorder();
1076
1077#ifndef PRODUCT
1078 void PrintJSON(JSONStream* js, TimelineEventFilter* filter) final;
1079#if defined(SUPPORT_PERFETTO)
1080 void PrintPerfettoTimeline(JSONStream* js,
1081 const TimelineEventFilter& filter) final;
1082#endif // defined(SUPPORT_PERFETTO)
1083 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) final;
1084#endif // !defined(PRODUCT)
1085
1086 // Called when |event| is completed. It is unsafe to keep a reference to
1087 // |event| as it may be freed as soon as this function returns.
1088 virtual void OnEvent(TimelineEvent* event) = 0;
1089
1090 const char* name() const { return CALLBACK_RECORDER_NAME; }
1091 intptr_t Size() {
1092 return 0;
1093 }
1094
1095 protected:
1096 TimelineEventBlock* GetNewBlockLocked() { UNREACHABLE(); }
1097 TimelineEventBlock* GetHeadBlockLocked() { UNREACHABLE(); }
1098 void ClearLocked() { ASSERT(lock_.IsOwnedByCurrentThread()); }
1099 TimelineEvent* StartEvent();
1100 void CompleteEvent(TimelineEvent* event);
1101};
1102
1103// A recorder that forwards completed events to the callback provided by
1104// Dart_SetTimelineRecorderCallback.
1105class TimelineEventEmbedderCallbackRecorder
1106 : public TimelineEventCallbackRecorder {
1107 public:
1108 TimelineEventEmbedderCallbackRecorder() {}
1109 virtual ~TimelineEventEmbedderCallbackRecorder() {}
1110
1111 virtual void OnEvent(TimelineEvent* event);
1112};
1113
1114// A recorder that does nothing.
1115class TimelineEventNopRecorder : public TimelineEventCallbackRecorder {
1116 public:
1117 TimelineEventNopRecorder() {}
1118 virtual ~TimelineEventNopRecorder() {}
1119
1120 virtual void OnEvent(TimelineEvent* event);
1121};
1122
1123// A recorder that stores events in chains of blocks of events.
1124// NOTE: This recorder will continue to allocate blocks until it exhausts
1125// memory.
1126class TimelineEventEndlessRecorder : public TimelineEventRecorder {
1127 public:
1128 TimelineEventEndlessRecorder();
1129 virtual ~TimelineEventEndlessRecorder();
1130
1131#ifndef PRODUCT
1132 void PrintJSON(JSONStream* js, TimelineEventFilter* filter) final;
1133#if defined(SUPPORT_PERFETTO)
1134 void PrintPerfettoTimeline(JSONStream* js,
1135 const TimelineEventFilter& filter) final;
1136#endif // defined(SUPPORT_PERFETTO)
1137 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) final;
1138#endif // !defined(PRODUCT)
1139
1140 const char* name() const { return ENDLESS_RECORDER_NAME; }
1141 intptr_t Size() { return block_index_ * sizeof(TimelineEventBlock); }
1142
1143 protected:
1144 TimelineEvent* StartEvent();
1145 void CompleteEvent(TimelineEvent* event);
1146 TimelineEventBlock* GetNewBlockLocked();
1147 TimelineEventBlock* GetHeadBlockLocked();
1148 void ClearLocked();
1149
1150#ifndef PRODUCT
1151 void PrintJSONEvents(const JSONArray& array,
1152 const TimelineEventFilter& filter);
1153#if defined(SUPPORT_PERFETTO)
1154 void PrintPerfettoEvents(JSONBase64String* jsonBase64String,
1155 const TimelineEventFilter& filter);
1156#endif // defined(SUPPORT_PERFETTO)
1157#endif // !defined(PRODUCT)
1158
1159 TimelineEventBlock* head_;
1160 TimelineEventBlock* tail_;
1161 intptr_t block_index_;
1162
1163 private:
1164#if !defined(PRODUCT)
1165 inline void PrintEventsCommon(
1166 const TimelineEventFilter& filter,
1167 std::function<void(const TimelineEvent&)>&& print_impl);
1168#endif // !defined(PRODUCT)
1169
1170 friend class TimelineTestHelper;
1171};
1172
1173// The TimelineEventPlatformRecorder records timeline events to a platform
1174// specific destination. It's implementation is in the timeline_{linux,...}.cc
1175// files.
1176class TimelineEventPlatformRecorder : public TimelineEventRecorder {
1177 public:
1178 TimelineEventPlatformRecorder();
1179 virtual ~TimelineEventPlatformRecorder();
1180
1181#ifndef PRODUCT
1182 void PrintJSON(JSONStream* js, TimelineEventFilter* filter) final;
1183#if defined(SUPPORT_PERFETTO)
1184 void PrintPerfettoTimeline(JSONStream* js,
1185 const TimelineEventFilter& filter) final;
1186#endif // defined(SUPPORT_PERFETTO)
1187 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) final;
1188#endif // !defined(PRODUCT)
1189
1190 // Called when |event| is completed. It is unsafe to keep a reference to
1191 // |event| as it may be freed as soon as this function returns.
1192 virtual void OnEvent(TimelineEvent* event) = 0;
1193
1194 virtual const char* name() const = 0;
1195
1196 protected:
1197 TimelineEventBlock* GetNewBlockLocked() { UNREACHABLE(); }
1198 TimelineEventBlock* GetHeadBlockLocked() { UNREACHABLE(); }
1199 void ClearLocked() { ASSERT(lock_.IsOwnedByCurrentThread()); }
1200 TimelineEvent* StartEvent();
1201 void CompleteEvent(TimelineEvent* event);
1202};
1203
1204#if defined(DART_HOST_OS_FUCHSIA)
1205// A recorder that sends events to Fuchsia's tracing app.
1206class TimelineEventFuchsiaRecorder : public TimelineEventPlatformRecorder {
1207 public:
1208 TimelineEventFuchsiaRecorder() {}
1209 virtual ~TimelineEventFuchsiaRecorder() {}
1210
1211 const char* name() const { return FUCHSIA_RECORDER_NAME; }
1212 intptr_t Size() { return 0; }
1213
1214 private:
1215 void OnEvent(TimelineEvent* event);
1216};
1217#endif // defined(DART_HOST_OS_FUCHSIA)
1218
1219#if defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
1220// A recorder that writes events to Android Systrace. This class is exposed in
1221// this header file only so that PrintSystrace can be visible to
1222// timeline_test.cc.
1223class TimelineEventSystraceRecorder : public TimelineEventPlatformRecorder {
1224 public:
1225 TimelineEventSystraceRecorder();
1226 virtual ~TimelineEventSystraceRecorder();
1227
1228 static intptr_t PrintSystrace(TimelineEvent* event,
1229 char* buffer,
1230 intptr_t buffer_size);
1231
1232 const char* name() const { return SYSTRACE_RECORDER_NAME; }
1233 intptr_t Size() { return 0; }
1234
1235 private:
1236 void OnEvent(TimelineEvent* event);
1237
1238 int systrace_fd_;
1239};
1240#endif // defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_LINUX)
1241
1242#if defined(DART_HOST_OS_MACOS)
1243// A recorder that sends events to Macos's tracing app. See:
1244// https://developer.apple.com/documentation/os/logging?language=objc
1245class TimelineEventMacosRecorder : public TimelineEventPlatformRecorder {
1246 public:
1247 TimelineEventMacosRecorder() API_AVAILABLE(ios(12.0), macos(10.14));
1248 virtual ~TimelineEventMacosRecorder() API_AVAILABLE(ios(12.0), macos(10.14));
1249
1250 const char* name() const { return MACOS_RECORDER_NAME; }
1251 intptr_t Size() { return 0; }
1252
1253 private:
1254 void OnEvent(TimelineEvent* event) API_AVAILABLE(ios(12.0), macos(10.14));
1255};
1256#endif // defined(DART_HOST_OS_MACOS)
1257
1258class TimelineEventFileRecorderBase : public TimelineEventPlatformRecorder {
1259 public:
1260 explicit TimelineEventFileRecorderBase(const char* path);
1261 virtual ~TimelineEventFileRecorderBase();
1262
1263 intptr_t Size() final { return 0; }
1264 void OnEvent(TimelineEvent* event) final { UNREACHABLE(); }
1265 void Drain();
1266
1267 protected:
1268 void Write(const char* buffer, intptr_t len) const;
1269 void Write(const char* buffer) const { Write(buffer, len: strlen(s: buffer)); }
1270 void CompleteEvent(TimelineEvent* event) final;
1271 void ShutDown();
1272
1273 private:
1274 virtual void DrainImpl(const TimelineEvent& event) = 0;
1275
1276 Monitor monitor_;
1277 TimelineEvent* head_;
1278 TimelineEvent* tail_;
1279 void* file_;
1280 bool shutting_down_;
1281 bool drained_;
1282 ThreadJoinId thread_id_;
1283};
1284
1285class TimelineEventFileRecorder : public TimelineEventFileRecorderBase {
1286 public:
1287 explicit TimelineEventFileRecorder(const char* path);
1288 virtual ~TimelineEventFileRecorder();
1289
1290 const char* name() const final { return FILE_RECORDER_NAME; }
1291
1292 private:
1293 void DrainImpl(const TimelineEvent& event) final;
1294
1295 bool first_;
1296};
1297
1298#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1299class TimelineEventPerfettoFileRecorder : public TimelineEventFileRecorderBase {
1300 public:
1301 explicit TimelineEventPerfettoFileRecorder(const char* path);
1302 virtual ~TimelineEventPerfettoFileRecorder();
1303
1304 const char* name() const final { return PERFETTO_FILE_RECORDER_NAME; }
1305
1306 private:
1307 void WritePacket(
1308 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
1309 const;
1310 void DrainImpl(const TimelineEvent& event) final;
1311};
1312#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
1313
1314class DartTimelineEventHelpers : public AllStatic {
1315 public:
1316 // When reporting an event of type |kAsyncBegin|, |kAsyncEnd|, or
1317 // |kAsyncInstant|, the async ID associated with the event should be passed
1318 // through |id|. When reporting an event of type |kFlowBegin|, |kFlowStep|,
1319 // or |kFlowEnd|, the flow ID associated with the event should be passed
1320 // through |id|. When reporting an event of type |kBegin| or |kEnd|, the event
1321 // ID associated with the event should be passed through |id|. Note that this
1322 // event ID will only be used by the MacOS recorder.
1323 static void ReportTaskEvent(TimelineEvent* event,
1324 int64_t id,
1325 intptr_t flow_id_count,
1326 std::unique_ptr<const int64_t[]>& flow_ids,
1327 intptr_t type,
1328 char* name,
1329 char* args);
1330};
1331#endif // defined(SUPPORT_TIMELINE)
1332
1333} // namespace dart
1334
1335#endif // RUNTIME_VM_TIMELINE_H_
1336

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/third_party/dart/runtime/vm/timeline.h