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 "include/dart_tools_api.h"
9
10#include "platform/atomic.h"
11#include "vm/allocation.h"
12#include "vm/bitfield.h"
13#include "vm/globals.h"
14#include "vm/growable_array.h"
15#include "vm/os.h"
16#include "vm/os_thread.h"
17
18#if defined(FUCHSIA_SDK) || defined (HOST_OS_FUCHSIA)
19#include <lib/trace-engine/context.h>
20#include <lib/trace-engine/instrumentation.h>
21#elif defined(HOST_OS_MACOS)
22#include <os/availability.h>
23#if defined(__MAC_10_14) || defined (__IPHONE_12_0)
24#define HOST_OS_SUPPORTS_SIGNPOST 1
25#endif
26//signpost.h exists in macOS 10.14, iOS 12 or above
27#if defined(HOST_OS_SUPPORTS_SIGNPOST)
28#include <os/signpost.h>
29#else
30#include <os/log.h>
31#endif
32#endif
33
34namespace dart {
35
36class JSONArray;
37class JSONObject;
38class JSONStream;
39class Object;
40class ObjectPointerVisitor;
41class Isolate;
42class Thread;
43class TimelineEvent;
44class TimelineEventBlock;
45class TimelineEventRecorder;
46class TimelineStream;
47class VirtualMemory;
48class Zone;
49
50#define CALLBACK_RECORDER_NAME "Callback"
51#define ENDLESS_RECORDER_NAME "Endless"
52#define FUCHSIA_RECORDER_NAME "Fuchsia"
53#define MACOS_RECORDER_NAME "Macos"
54#define RING_RECORDER_NAME "Ring"
55#define STARTUP_RECORDER_NAME "Startup"
56#define SYSTRACE_RECORDER_NAME "Systrace"
57
58// (name, fuchsia_name).
59#define TIMELINE_STREAM_LIST(V) \
60 V(API, "dart:api") \
61 V(Compiler, "dart:compiler") \
62 V(CompilerVerbose, "dart:compiler.verbose") \
63 V(Dart, "dart:dart") \
64 V(Debugger, "dart:debugger") \
65 V(Embedder, "dart:embedder") \
66 V(GC, "dart:gc") \
67 V(Isolate, "dart:isolate") \
68 V(VM, "dart:vm")
69
70// A stream of timeline events. A stream has a name and can be enabled or
71// disabled (globally and per isolate).
72class TimelineStream {
73 public:
74 TimelineStream(const char* name, const char* fuchsia_name, bool enabled);
75
76 const char* name() const { return name_; }
77 const char* fuchsia_name() const { return fuchsia_name_; }
78
79 bool enabled() {
80#if defined(HOST_OS_FUCHSIA)
81#ifdef PRODUCT
82 return trace_is_category_enabled(fuchsia_name_);
83#else
84 return trace_is_category_enabled(fuchsia_name_) || enabled_ != 0;
85#endif // PRODUCT
86#else
87 return enabled_ != 0;
88#endif // defined(HOST_OS_FUCHSIA)
89 }
90
91 void set_enabled(bool enabled) { enabled_ = enabled ? 1 : 0; }
92
93 // Records an event. Will return |NULL| if not enabled. The returned
94 // |TimelineEvent| is in an undefined state and must be initialized.
95 // NOTE: It is not allowed to call StartEvent again without completing
96 // the first event.
97 TimelineEvent* StartEvent();
98
99 static intptr_t enabled_offset() {
100 return OFFSET_OF(TimelineStream, enabled_);
101 }
102
103#if defined(HOST_OS_FUCHSIA)
104 trace_site_t* trace_site() { return &trace_site_; }
105#elif defined(HOST_OS_MACOS)
106 os_log_t macos_log() { return macos_log_; }
107#endif
108
109 private:
110 const char* const name_;
111 const char* const fuchsia_name_;
112
113 // This field is accessed by generated code (intrinsic) and expects to see
114 // 0 or 1. If this becomes a BitField, the generated code must be updated.
115 uintptr_t enabled_;
116
117#if defined(HOST_OS_FUCHSIA)
118 trace_site_t trace_site_ = {};
119#elif defined(HOST_OS_MACOS)
120 os_log_t macos_log_ = {};
121#endif
122};
123
124class Timeline : public AllStatic {
125 public:
126 // Initialize timeline system. Not thread safe.
127 static void Init();
128
129 // Cleanup timeline system. Not thread safe.
130 static void Cleanup();
131
132 // Access the global recorder. Not thread safe.
133 static TimelineEventRecorder* recorder();
134
135 // Reclaim all |TimelineEventBlocks|s that are cached by threads.
136 static void ReclaimCachedBlocksFromThreads();
137
138 static void Clear();
139
140#ifndef PRODUCT
141 // Print information about streams to JSON.
142 static void PrintFlagsToJSON(JSONStream* json);
143
144 // Output the recorded streams to a JSONS array.
145 static void PrintFlagsToJSONArray(JSONArray* arr);
146#endif
147
148#define TIMELINE_STREAM_ACCESSOR(name, fuchsia_name) \
149 static TimelineStream* Get##name##Stream() { return &stream_##name##_; }
150 TIMELINE_STREAM_LIST(TIMELINE_STREAM_ACCESSOR)
151#undef TIMELINE_STREAM_ACCESSOR
152
153#define TIMELINE_STREAM_FLAGS(name, fuchsia_name) \
154 static void SetStream##name##Enabled(bool enabled) { \
155 stream_##name##_.set_enabled(enabled); \
156 }
157 TIMELINE_STREAM_LIST(TIMELINE_STREAM_FLAGS)
158#undef TIMELINE_STREAM_FLAGS
159
160 private:
161 static TimelineEventRecorder* recorder_;
162 static MallocGrowableArray<char*>* enabled_streams_;
163
164#define TIMELINE_STREAM_DECLARE(name, fuchsia_name) \
165 static TimelineStream stream_##name##_;
166 TIMELINE_STREAM_LIST(TIMELINE_STREAM_DECLARE)
167#undef TIMELINE_STREAM_DECLARE
168
169 friend class TimelineRecorderOverride;
170 friend class ReclaimBlocksIsolateVisitor;
171};
172
173struct TimelineEventArgument {
174 const char* name;
175 char* value;
176};
177
178class TimelineEventArguments {
179 public:
180 TimelineEventArguments() : buffer_(NULL), length_(0) {}
181 ~TimelineEventArguments() { Free(); }
182 // Get/Set the number of arguments in the event.
183 void SetNumArguments(intptr_t length);
184 // |name| must be a compile time constant. Takes ownership of |argument|.
185 void SetArgument(intptr_t i, const char* name, char* argument);
186 // |name| must be a compile time constant. Copies |argument|.
187 void CopyArgument(intptr_t i, const char* name, const char* argument);
188 // |name| must be a compile time constant. Takes ownership of |args|
189 void FormatArgument(intptr_t i,
190 const char* name,
191 const char* fmt,
192 va_list args);
193
194 void StealArguments(TimelineEventArguments* arguments);
195
196 TimelineEventArgument* buffer() const { return buffer_; }
197
198 intptr_t length() const { return length_; }
199
200 void Free();
201
202 TimelineEventArgument& operator[](intptr_t index) const {
203 return buffer_[index];
204 }
205
206 bool IsEmpty() { return length_ == 0; }
207
208 bool IsNotEmpty() { return length_ != 0; }
209
210 private:
211 TimelineEventArgument* buffer_;
212 intptr_t length_;
213 DISALLOW_COPY_AND_ASSIGN(TimelineEventArguments);
214};
215
216// You should get a |TimelineEvent| from a |TimelineStream|.
217class TimelineEvent {
218 public:
219 // Keep in sync with StateBits below.
220 enum EventType {
221 kNone,
222 kBegin,
223 kEnd,
224 kDuration,
225 kInstant,
226 kAsyncBegin,
227 kAsyncInstant,
228 kAsyncEnd,
229 kCounter,
230 kFlowBegin,
231 kFlowStep,
232 kFlowEnd,
233 kMetadata,
234 kNumEventTypes,
235 };
236
237 TimelineEvent();
238 ~TimelineEvent();
239
240 void Reset();
241
242 bool IsValid() const {
243 return (event_type() > kNone) && (event_type() < kNumEventTypes);
244 }
245
246 // Marks the beginning of an asynchronous operation with |async_id|.
247 void AsyncBegin(const char* label,
248 int64_t async_id,
249 int64_t micros = OS::GetCurrentMonotonicMicros());
250 // Marks an instantaneous event associated with |async_id|.
251 void AsyncInstant(const char* label,
252 int64_t async_id,
253 int64_t micros = OS::GetCurrentMonotonicMicros());
254 // Marks the end of an asynchronous operation associated with |async_id|.
255 void AsyncEnd(const char* label,
256 int64_t async_id,
257 int64_t micros = OS::GetCurrentMonotonicMicros());
258
259 void DurationBegin(
260 const char* label,
261 int64_t micros = OS::GetCurrentMonotonicMicros(),
262 int64_t thread_micros = OS::GetCurrentThreadCPUMicrosForTimeline());
263 void DurationEnd(
264 int64_t micros = OS::GetCurrentMonotonicMicros(),
265 int64_t thread_micros = OS::GetCurrentThreadCPUMicrosForTimeline());
266
267 void Instant(const char* label,
268 int64_t micros = OS::GetCurrentMonotonicMicros());
269
270 void Duration(const char* label,
271 int64_t start_micros,
272 int64_t end_micros,
273 int64_t thread_start_micros = -1,
274 int64_t thread_end_micros = -1);
275
276 void Begin(
277 const char* label,
278 int64_t micros = OS::GetCurrentMonotonicMicros(),
279 int64_t thread_micros = OS::GetCurrentThreadCPUMicrosForTimeline());
280
281 void End(const char* label,
282 int64_t micros = OS::GetCurrentMonotonicMicros(),
283 int64_t thread_micros = OS::GetCurrentThreadCPUMicrosForTimeline());
284
285 void Counter(const char* label,
286 int64_t micros = OS::GetCurrentMonotonicMicros());
287
288 void FlowBegin(const char* label,
289 int64_t async_id,
290 int64_t micros = OS::GetCurrentMonotonicMicros());
291 void FlowStep(const char* label,
292 int64_t async_id,
293 int64_t micros = OS::GetCurrentMonotonicMicros());
294 void FlowEnd(const char* label,
295 int64_t async_id,
296 int64_t micros = OS::GetCurrentMonotonicMicros());
297
298 void Metadata(const char* label,
299 int64_t micros = OS::GetCurrentMonotonicMicros());
300
301 void CompleteWithPreSerializedArgs(char* args_json);
302
303 // Get/Set the number of arguments in the event.
304 intptr_t GetNumArguments() { return arguments_.length(); }
305 void SetNumArguments(intptr_t length) { arguments_.SetNumArguments(length); }
306 // |name| must be a compile time constant. Takes ownership of |argument|.
307 void SetArgument(intptr_t i, const char* name, char* argument) {
308 arguments_.SetArgument(i, name, argument);
309 }
310 // |name| must be a compile time constant. Copies |argument|.
311 void CopyArgument(intptr_t i, const char* name, const char* argument) {
312 arguments_.CopyArgument(i, name, argument);
313 }
314 // |name| must be a compile time constant.
315 void FormatArgument(intptr_t i, const char* name, const char* fmt, ...)
316 PRINTF_ATTRIBUTE(4, 5);
317
318 void StealArguments(TimelineEventArguments* arguments) {
319 arguments_.StealArguments(arguments);
320 }
321 // Mandatory to call when this event is completely filled out.
322 void Complete();
323
324 EventType event_type() const { return EventTypeField::decode(state_); }
325
326 bool IsFinishedDuration() const {
327 return (event_type() == kDuration) && (timestamp1_ > timestamp0_);
328 }
329
330 bool HasThreadCPUTime() const;
331 int64_t ThreadCPUTimeDuration() const;
332 int64_t ThreadCPUTimeOrigin() const;
333
334 int64_t TimeOrigin() const;
335 int64_t AsyncId() const;
336 int64_t TimeDuration() const;
337 int64_t TimeEnd() const {
338 ASSERT(IsFinishedDuration());
339 return timestamp1_;
340 }
341
342 // The lowest time value stored in this event.
343 int64_t LowTime() const;
344 // The highest time value stored in this event.
345 int64_t HighTime() const;
346
347#ifndef PRODUCT
348 void PrintJSON(JSONStream* stream) const;
349#endif
350
351 ThreadId thread() const { return thread_; }
352
353 void set_thread(ThreadId tid) { thread_ = tid; }
354
355 Dart_Port isolate_id() const { return isolate_id_; }
356
357 uint64_t isolate_group_id() const { return isolate_group_id_; }
358
359 const char* label() const { return label_; }
360
361 // Does this duration end before |micros| ?
362 bool DurationFinishedBefore(int64_t micros) const {
363 return TimeEnd() <= micros;
364 }
365
366 bool IsDuration() const { return (event_type() == kDuration); }
367
368 bool IsBegin() const { return (event_type() == kBegin); }
369
370 bool IsEnd() const { return (event_type() == kEnd); }
371
372 // Is this event a synchronous begin or end event?
373 bool IsBeginOrEnd() const { return IsBegin() || IsEnd(); }
374
375 // Does this duration fully contain |other| ?
376 bool DurationContains(TimelineEvent* other) const {
377 ASSERT(IsFinishedDuration());
378 if (other->IsBegin()) {
379 if (other->TimeOrigin() < TimeOrigin()) {
380 return false;
381 }
382 if (other->TimeOrigin() > TimeEnd()) {
383 return false;
384 }
385 return true;
386 } else {
387 ASSERT(other->IsFinishedDuration());
388 if (other->TimeOrigin() < TimeOrigin()) {
389 return false;
390 }
391 if (other->TimeEnd() < TimeOrigin()) {
392 return false;
393 }
394 if (other->TimeOrigin() > TimeEnd()) {
395 return false;
396 }
397 if (other->TimeEnd() > TimeEnd()) {
398 return false;
399 }
400 return true;
401 }
402 }
403
404 bool Within(int64_t time_origin_micros, int64_t time_extent_micros);
405
406 void set_owns_label(bool owns_label) {
407 state_ = OwnsLabelBit::update(owns_label, state_);
408 }
409
410 TimelineEventArgument* arguments() const { return arguments_.buffer(); }
411
412 intptr_t arguments_length() const { return arguments_.length(); }
413
414 private:
415 void StreamInit(TimelineStream* stream) { stream_ = stream; }
416 void Init(EventType event_type, const char* label);
417
418 void set_event_type(EventType event_type) {
419 // We only reserve 4 bits to hold the event type.
420 COMPILE_ASSERT(kNumEventTypes < 16);
421 state_ = EventTypeField::update(event_type, state_);
422 }
423
424 void set_timestamp0(int64_t value) {
425 ASSERT(timestamp0_ == 0);
426 timestamp0_ = value;
427 }
428 void set_timestamp1(int64_t value) {
429 ASSERT(timestamp1_ == 0);
430 timestamp1_ = value;
431 }
432
433 void set_thread_timestamp0(int64_t value) {
434 ASSERT(thread_timestamp0_ == -1);
435 thread_timestamp0_ = value;
436 }
437
438 void set_thread_timestamp1(int64_t value) {
439 ASSERT(thread_timestamp1_ == -1);
440 thread_timestamp1_ = value;
441 }
442
443 bool pre_serialized_args() const {
444 return PreSerializedArgsBit::decode(state_);
445 }
446
447 void set_pre_serialized_args(bool pre_serialized_args) {
448 state_ = PreSerializedArgsBit::update(pre_serialized_args, state_);
449 }
450
451 bool owns_label() const { return OwnsLabelBit::decode(state_); }
452
453 enum StateBits {
454 kEventTypeBit = 0, // reserve 4 bits for type.
455 kPreSerializedArgsBit = 4,
456 kOwnsLabelBit = 5,
457 kNextBit = 6,
458 };
459
460 class EventTypeField : public BitField<uword, EventType, kEventTypeBit, 4> {};
461 class PreSerializedArgsBit
462 : public BitField<uword, bool, kPreSerializedArgsBit, 1> {};
463 class OwnsLabelBit : public BitField<uword, bool, kOwnsLabelBit, 1> {};
464
465 int64_t timestamp0_;
466 int64_t timestamp1_;
467 int64_t thread_timestamp0_;
468 int64_t thread_timestamp1_;
469 TimelineEventArguments arguments_;
470 uword state_;
471 const char* label_;
472 TimelineStream* stream_;
473 ThreadId thread_;
474 Dart_Port isolate_id_;
475 uint64_t isolate_group_id_;
476
477 friend class TimelineEventRecorder;
478 friend class TimelineEventEndlessRecorder;
479 friend class TimelineEventRingRecorder;
480 friend class TimelineEventStartupRecorder;
481 friend class TimelineEventPlatformRecorder;
482 friend class TimelineEventFuchsiaRecorder;
483 friend class TimelineEventMacosRecorder;
484 friend class TimelineStream;
485 friend class TimelineTestHelper;
486 DISALLOW_COPY_AND_ASSIGN(TimelineEvent);
487};
488
489#ifdef SUPPORT_TIMELINE
490#define TIMELINE_DURATION(thread, stream, name) \
491 TimelineBeginEndScope tbes(thread, Timeline::Get##stream##Stream(), name);
492#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function) \
493 TimelineBeginEndScope tbes(thread, Timeline::GetCompilerStream(), name); \
494 if (tbes.enabled()) { \
495 tbes.SetNumArguments(1); \
496 tbes.CopyArgument(0, "function", function.ToQualifiedCString()); \
497 }
498
499#define TIMELINE_FUNCTION_GC_DURATION(thread, name) \
500 TimelineBeginEndScope tbes(thread, Timeline::GetGCStream(), name);
501#define TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, name) \
502 TIMELINE_FUNCTION_GC_DURATION(thread, name) \
503 tbes.SetNumArguments(1); \
504 tbes.CopyArgument(0, "mode", "basic");
505#else
506#define TIMELINE_DURATION(thread, stream, name)
507#define TIMELINE_FUNCTION_COMPILATION_DURATION(thread, name, function)
508#define TIMELINE_FUNCTION_GC_DURATION(thread, name)
509#define TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, name)
510#endif // !PRODUCT
511
512// See |TimelineBeginEndScope|.
513class TimelineEventScope : public StackResource {
514 public:
515 bool enabled() const { return enabled_; }
516
517 intptr_t GetNumArguments() { return arguments_.length(); }
518 void SetNumArguments(intptr_t length);
519
520 void SetArgument(intptr_t i, const char* name, char* argument);
521
522 void CopyArgument(intptr_t i, const char* name, const char* argument);
523
524 void FormatArgument(intptr_t i, const char* name, const char* fmt, ...)
525 PRINTF_ATTRIBUTE(4, 5);
526
527 protected:
528 TimelineEventScope(TimelineStream* stream, const char* label);
529
530 TimelineEventScope(Thread* thread, TimelineStream* stream, const char* label);
531
532 bool ShouldEmitEvent() const { return enabled_; }
533
534 void set_enabled(bool enabled) { enabled_ = enabled; }
535
536 const char* label() const { return label_; }
537
538 TimelineEventArgument* arguments() const { return arguments_.buffer(); }
539
540 intptr_t arguments_length() const { return arguments_.length(); }
541
542 TimelineStream* stream() const { return stream_; }
543
544 virtual ~TimelineEventScope();
545
546 void StealArguments(TimelineEvent* event);
547
548 private:
549 void Init();
550
551 TimelineStream* stream_;
552 const char* label_;
553 TimelineEventArguments arguments_;
554 bool enabled_;
555
556 DISALLOW_COPY_AND_ASSIGN(TimelineEventScope);
557};
558
559class TimelineBeginEndScope : public TimelineEventScope {
560 public:
561 TimelineBeginEndScope(TimelineStream* stream, const char* label);
562
563 TimelineBeginEndScope(Thread* thread,
564 TimelineStream* stream,
565 const char* label);
566
567 virtual ~TimelineBeginEndScope();
568
569 private:
570 void EmitBegin();
571 void EmitEnd();
572
573 DISALLOW_COPY_AND_ASSIGN(TimelineBeginEndScope);
574};
575
576// A block of |TimelineEvent|s. Not thread safe.
577class TimelineEventBlock {
578 public:
579 static const intptr_t kBlockSize = 64;
580
581 explicit TimelineEventBlock(intptr_t index);
582 ~TimelineEventBlock();
583
584 TimelineEventBlock* next() const { return next_; }
585 void set_next(TimelineEventBlock* next) { next_ = next; }
586
587 intptr_t length() const { return length_; }
588
589 intptr_t block_index() const { return block_index_; }
590
591 bool IsEmpty() const { return length_ == 0; }
592
593 bool IsFull() const { return length_ == kBlockSize; }
594
595 TimelineEvent* At(intptr_t index) {
596 ASSERT(index >= 0);
597 ASSERT(index < kBlockSize);
598 return &events_[index];
599 }
600
601 const TimelineEvent* At(intptr_t index) const {
602 ASSERT(index >= 0);
603 ASSERT(index < kBlockSize);
604 return &events_[index];
605 }
606
607 // Attempt to sniff the timestamp from the first event.
608 int64_t LowerTimeBound() const;
609
610 // Returns false if |this| violates any of the following invariants:
611 // - events in the block come from one thread.
612 // - events have monotonically increasing timestamps.
613 bool CheckBlock();
614
615 // Call Reset on all events and set length to 0.
616 void Reset();
617
618 // Only safe to access under the recorder's lock.
619 bool in_use() const { return in_use_; }
620
621 // Only safe to access under the recorder's lock.
622 ThreadId thread_id() const { return thread_id_; }
623
624 protected:
625#ifndef PRODUCT
626 void PrintJSON(JSONStream* stream) const;
627#endif
628
629 TimelineEvent* StartEvent();
630
631 TimelineEvent events_[kBlockSize];
632 TimelineEventBlock* next_;
633 intptr_t length_;
634 intptr_t block_index_;
635
636 // Only accessed under the recorder's lock.
637 ThreadId thread_id_;
638 bool in_use_;
639
640 void Open();
641 void Finish();
642
643 friend class Thread;
644 friend class TimelineEventRecorder;
645 friend class TimelineEventEndlessRecorder;
646 friend class TimelineEventRingRecorder;
647 friend class TimelineEventStartupRecorder;
648 friend class TimelineEventPlatformRecorder;
649 friend class TimelineTestHelper;
650 friend class JSONStream;
651
652 private:
653 DISALLOW_COPY_AND_ASSIGN(TimelineEventBlock);
654};
655
656class TimelineEventFilter : public ValueObject {
657 public:
658 TimelineEventFilter(int64_t time_origin_micros = -1,
659 int64_t time_extent_micros = -1);
660
661 virtual ~TimelineEventFilter();
662
663 virtual bool IncludeBlock(TimelineEventBlock* block) {
664 if (block == NULL) {
665 return false;
666 }
667 // Not empty and not in use.
668 return !block->IsEmpty() && !block->in_use();
669 }
670
671 virtual bool IncludeEvent(TimelineEvent* event) {
672 if (event == NULL) {
673 return false;
674 }
675 return event->IsValid();
676 }
677
678 int64_t time_origin_micros() const { return time_origin_micros_; }
679
680 int64_t time_extent_micros() const { return time_extent_micros_; }
681
682 private:
683 int64_t time_origin_micros_;
684 int64_t time_extent_micros_;
685};
686
687class IsolateTimelineEventFilter : public TimelineEventFilter {
688 public:
689 explicit IsolateTimelineEventFilter(Dart_Port isolate_id,
690 int64_t time_origin_micros = -1,
691 int64_t time_extent_micros = -1);
692
693 bool IncludeBlock(TimelineEventBlock* block) {
694 if (block == NULL) {
695 return false;
696 }
697 // Not empty, not in use, and isolate match.
698 return !block->IsEmpty() && !block->in_use();
699 }
700
701 bool IncludeEvent(TimelineEvent* event) {
702 return event->IsValid() && (event->isolate_id() == isolate_id_);
703 }
704
705 private:
706 Dart_Port isolate_id_;
707};
708
709// Recorder of |TimelineEvent|s.
710class TimelineEventRecorder {
711 public:
712 TimelineEventRecorder();
713 virtual ~TimelineEventRecorder() {}
714
715 TimelineEventBlock* GetNewBlock();
716
717 // Interface method(s) which must be implemented.
718#ifndef PRODUCT
719 virtual void PrintJSON(JSONStream* js, TimelineEventFilter* filter) = 0;
720 virtual void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) = 0;
721#endif
722 virtual const char* name() const = 0;
723 int64_t GetNextAsyncId();
724
725 void FinishBlock(TimelineEventBlock* block);
726
727 virtual intptr_t Size() = 0;
728
729 protected:
730#ifndef PRODUCT
731 void WriteTo(const char* directory);
732#endif
733
734 // Interface method(s) which must be implemented.
735 virtual TimelineEvent* StartEvent() = 0;
736 virtual void CompleteEvent(TimelineEvent* event) = 0;
737 virtual TimelineEventBlock* GetHeadBlockLocked() = 0;
738 virtual TimelineEventBlock* GetNewBlockLocked() = 0;
739 virtual void Clear() = 0;
740
741 // Utility method(s).
742#ifndef PRODUCT
743 void PrintJSONMeta(JSONArray* array) const;
744#endif
745 TimelineEvent* ThreadBlockStartEvent();
746 void ThreadBlockCompleteEvent(TimelineEvent* event);
747
748 void ResetTimeTracking();
749 void ReportTime(int64_t micros);
750 int64_t TimeOriginMicros() const;
751 int64_t TimeExtentMicros() const;
752
753 Mutex lock_;
754 RelaxedAtomic<uintptr_t> async_id_;
755 int64_t time_low_micros_;
756 int64_t time_high_micros_;
757
758 friend class TimelineEvent;
759 friend class TimelineEventBlockIterator;
760 friend class TimelineStream;
761 friend class TimelineTestHelper;
762 friend class Timeline;
763
764 private:
765 DISALLOW_COPY_AND_ASSIGN(TimelineEventRecorder);
766};
767
768// An abstract recorder that stores events in a buffer of fixed capacity.
769class TimelineEventFixedBufferRecorder : public TimelineEventRecorder {
770 public:
771 static const intptr_t kDefaultCapacity = 32 * KB; // Number of events.
772
773 explicit TimelineEventFixedBufferRecorder(intptr_t capacity);
774 virtual ~TimelineEventFixedBufferRecorder();
775
776#ifndef PRODUCT
777 void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
778 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
779#endif
780
781 intptr_t Size();
782
783 protected:
784 TimelineEvent* StartEvent();
785 void CompleteEvent(TimelineEvent* event);
786 TimelineEventBlock* GetHeadBlockLocked();
787 intptr_t FindOldestBlockIndex() const;
788 void Clear();
789
790#ifndef PRODUCT
791 void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter);
792#endif
793
794 VirtualMemory* memory_;
795 TimelineEventBlock* blocks_;
796 intptr_t capacity_;
797 intptr_t num_blocks_;
798 intptr_t block_cursor_;
799};
800
801// A recorder that stores events in a buffer of fixed capacity. When the buffer
802// is full, new events overwrite old events.
803class TimelineEventRingRecorder : public TimelineEventFixedBufferRecorder {
804 public:
805 explicit TimelineEventRingRecorder(intptr_t capacity = kDefaultCapacity)
806 : TimelineEventFixedBufferRecorder(capacity) {}
807 virtual ~TimelineEventRingRecorder() {}
808
809 const char* name() const { return RING_RECORDER_NAME; }
810
811 protected:
812 TimelineEventBlock* GetNewBlockLocked();
813};
814
815// A recorder that stores events in a buffer of fixed capacity. When the buffer
816// is full, new events are dropped.
817class TimelineEventStartupRecorder : public TimelineEventFixedBufferRecorder {
818 public:
819 explicit TimelineEventStartupRecorder(intptr_t capacity = kDefaultCapacity)
820 : TimelineEventFixedBufferRecorder(capacity) {}
821 virtual ~TimelineEventStartupRecorder() {}
822
823 const char* name() const { return STARTUP_RECORDER_NAME; }
824
825 protected:
826 TimelineEventBlock* GetNewBlockLocked();
827};
828
829// An abstract recorder that calls |OnEvent| whenever an event is complete.
830// This should only be used for testing.
831class TimelineEventCallbackRecorder : public TimelineEventRecorder {
832 public:
833 TimelineEventCallbackRecorder();
834 virtual ~TimelineEventCallbackRecorder();
835
836#ifndef PRODUCT
837 void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
838 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
839#endif
840
841 // Called when |event| is completed. It is unsafe to keep a reference to
842 // |event| as it may be freed as soon as this function returns.
843 virtual void OnEvent(TimelineEvent* event) = 0;
844
845 const char* name() const { return CALLBACK_RECORDER_NAME; }
846
847 protected:
848 TimelineEventBlock* GetNewBlockLocked() { return NULL; }
849 TimelineEventBlock* GetHeadBlockLocked() { return NULL; }
850 void Clear() {}
851 TimelineEvent* StartEvent();
852 void CompleteEvent(TimelineEvent* event);
853};
854
855// A recorder that stores events in chains of blocks of events.
856// NOTE: This recorder will continue to allocate blocks until it exhausts
857// memory.
858class TimelineEventEndlessRecorder : public TimelineEventRecorder {
859 public:
860 TimelineEventEndlessRecorder();
861 virtual ~TimelineEventEndlessRecorder();
862
863#ifndef PRODUCT
864 void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
865 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
866#endif
867
868 const char* name() const { return ENDLESS_RECORDER_NAME; }
869 intptr_t Size() { return block_index_ * sizeof(TimelineEventBlock); }
870
871 protected:
872 TimelineEvent* StartEvent();
873 void CompleteEvent(TimelineEvent* event);
874 TimelineEventBlock* GetNewBlockLocked();
875 TimelineEventBlock* GetHeadBlockLocked();
876 void Clear();
877
878#ifndef PRODUCT
879 void PrintJSONEvents(JSONArray* array, TimelineEventFilter* filter);
880#endif
881
882 TimelineEventBlock* head_;
883 TimelineEventBlock* tail_;
884 intptr_t block_index_;
885
886 friend class TimelineTestHelper;
887};
888
889// An iterator for blocks.
890class TimelineEventBlockIterator {
891 public:
892 explicit TimelineEventBlockIterator(TimelineEventRecorder* recorder);
893 ~TimelineEventBlockIterator();
894
895 void Reset(TimelineEventRecorder* recorder);
896
897 // Returns false when there are no more blocks.
898 bool HasNext() const;
899
900 // Returns the next block and moves forward.
901 TimelineEventBlock* Next();
902
903 private:
904 TimelineEventBlock* current_;
905 TimelineEventRecorder* recorder_;
906};
907
908// The TimelineEventPlatformRecorder records timeline events to a platform
909// specific destination. It's implementation is in the timeline_{linux,...}.cc
910// files.
911class TimelineEventPlatformRecorder : public TimelineEventRecorder {
912 public:
913 TimelineEventPlatformRecorder();
914 virtual ~TimelineEventPlatformRecorder();
915
916#ifndef PRODUCT
917 void PrintJSON(JSONStream* js, TimelineEventFilter* filter);
918 void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter);
919#endif
920
921 // Called when |event| is completed. It is unsafe to keep a reference to
922 // |event| as it may be freed as soon as this function returns.
923 virtual void OnEvent(TimelineEvent* event) = 0;
924
925 virtual const char* name() const = 0;
926
927 protected:
928 TimelineEventBlock* GetNewBlockLocked() { return NULL; }
929 TimelineEventBlock* GetHeadBlockLocked() { return NULL; }
930 void Clear() {}
931 TimelineEvent* StartEvent();
932 void CompleteEvent(TimelineEvent* event);
933};
934
935#if defined(HOST_OS_FUCHSIA)
936// A recorder that sends events to Fuchsia's tracing app.
937class TimelineEventFuchsiaRecorder : public TimelineEventPlatformRecorder {
938 public:
939 TimelineEventFuchsiaRecorder() {}
940 virtual ~TimelineEventFuchsiaRecorder() {}
941
942 const char* name() const { return FUCHSIA_RECORDER_NAME; }
943 intptr_t Size() { return 0; }
944
945 private:
946 void OnEvent(TimelineEvent* event);
947};
948#endif // defined(HOST_OS_FUCHSIA)
949
950#if defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX)
951// A recorder that writes events to Android Systrace. This class is exposed in
952// this header file only so that PrintSystrace can be visible to
953// timeline_test.cc.
954class TimelineEventSystraceRecorder : public TimelineEventPlatformRecorder {
955 public:
956 TimelineEventSystraceRecorder();
957 virtual ~TimelineEventSystraceRecorder();
958
959 static intptr_t PrintSystrace(TimelineEvent* event,
960 char* buffer,
961 intptr_t buffer_size);
962
963 const char* name() const { return SYSTRACE_RECORDER_NAME; }
964 intptr_t Size() { return 0; }
965
966 private:
967 void OnEvent(TimelineEvent* event);
968
969 int systrace_fd_;
970};
971#endif // defined(HOST_OS_ANDROID) || defined(HOST_OS_LINUX)
972
973#if defined(HOST_OS_MACOS)
974// A recorder that sends events to Macos's tracing app. See:
975// https://developer.apple.com/documentation/os/logging?language=objc
976class TimelineEventMacosRecorder : public TimelineEventPlatformRecorder {
977 public:
978 TimelineEventMacosRecorder() API_AVAILABLE(ios(12.0), macos(10.14));
979 virtual ~TimelineEventMacosRecorder() API_AVAILABLE(ios(12.0), macos(10.14));
980
981 const char* name() const { return MACOS_RECORDER_NAME; }
982 intptr_t Size() { return 0; }
983
984 private:
985 void OnEvent(TimelineEvent* event) API_AVAILABLE(ios(12.0), macos(10.14));
986};
987#endif // defined(HOST_OS_MACOS)
988
989class DartTimelineEventHelpers : public AllStatic {
990 public:
991 static void ReportTaskEvent(Thread* thread,
992 TimelineEvent* event,
993 int64_t id,
994 const char* phase,
995 const char* category,
996 char* name,
997 char* args);
998
999 static void ReportFlowEvent(Thread* thread,
1000 TimelineEvent* event,
1001 const char* category,
1002 char* name,
1003 int64_t type,
1004 int64_t flow_id,
1005 char* args);
1006
1007 static void ReportInstantEvent(Thread* thread,
1008 TimelineEvent* event,
1009 const char* category,
1010 char* name,
1011 char* args);
1012};
1013
1014} // namespace dart
1015
1016#endif // RUNTIME_VM_TIMELINE_H_
1017