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 | |
45 | namespace 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 | |
53 | class JSONArray; |
54 | class JSONBase64String; |
55 | class JSONObject; |
56 | class JSONStream; |
57 | class JSONWriter; |
58 | class Object; |
59 | class ObjectPointerVisitor; |
60 | class Isolate; |
61 | class Thread; |
62 | class TimelineEvent; |
63 | class TimelineEventBlock; |
64 | class TimelineEventRecorder; |
65 | class TimelineStream; |
66 | class VirtualMemory; |
67 | class 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). |
95 | class 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) |
151 | class 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. |
194 | class 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 | |
214 | class 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 | |
278 | struct TimelineEventArgument { |
279 | const char* name; |
280 | char* value; |
281 | }; |
282 | |
283 | class 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|. |
322 | class 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 | |
642 | class 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 | |
676 | class 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|. |
710 | class 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 | |
759 | class 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. |
777 | class 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 | |
854 | class 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 | |
877 | class 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. |
892 | class 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. |
993 | class 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. |
1044 | class 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. |
1058 | class 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. |
1072 | class 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. |
1105 | class 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. |
1115 | class 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. |
1126 | class 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. |
1176 | class 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. |
1206 | class 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. |
1223 | class 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 |
1245 | class 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 | |
1258 | class 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 | |
1285 | class 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) |
1299 | class 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 | |
1314 | class 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 |
Definitions
- TimelineStream
- name
- fuchsia_name
- enabled
- set_enabled
- enabled_offset
- RecorderSynchronizationLock
- Init
- EnterLock
- ExitLock
- IsUninitialized
- IsActive
- WaitForShutdown
- RecorderSynchronizationLock
- RecorderSynchronizationLockScope
- RecorderSynchronizationLockScope
- ~RecorderSynchronizationLockScope
- IsUninitialized
- IsActive
- RecorderSynchronizationLockScope
- Timeline
- recorder
- recorder_discards_clock_values
- set_recorder_discards_clock_values
- callback
- set_callback
- TimelineEventArgument
- TimelineEventArguments
- TimelineEventArguments
- ~TimelineEventArguments
- buffer
- length
- operator[]
- IsEmpty
- IsNotEmpty
- TimelineEventArguments
- TimelineEvent
- EventType
- IsValid
- GetNumArguments
- SetNumArguments
- SetArgument
- CopyArgument
- StealArguments
- event_type
- stream
- TimeOrigin
- Id
- SetTimeEnd
- TimeEnd
- timestamp0
- timestamp1_or_id
- SetFlowIds
- flow_id_count
- FlowIds
- thread
- set_thread
- isolate_id
- isolate_group_id
- isolate_data
- isolate_group_data
- label
- DurationFinishedBefore
- IsDuration
- IsBegin
- IsEnd
- IsBeginOrEnd
- DurationContains
- set_owns_label
- arguments
- arguments_length
- ArgsArePreSerialized
- next
- set_next
- StreamInit
- set_event_type
- set_timestamp0
- set_timestamp1_or_id
- IsFinishedDuration
- set_pre_serialized_args
- owns_label
- StateBits
- EventTypeField
- PreSerializedArgsBit
- OwnsLabelBit
- TimelineEvent
- TimelineTrackMetadata
- pid
- tid
- track_name
- AsyncTimelineTrackMetadata
- pid
- async_id
- TimelineEventScope
- enabled
- GetNumArguments
- ShouldEmitEvent
- set_enabled
- label
- id
- arguments
- arguments_length
- stream
- TimelineEventScope
- TimelineBeginEndScope
- TimelineBeginEndScope
- TimelineEventBlock
- kBlockSize
- next
- set_next
- length
- block_index
- IsEmpty
- IsFull
- At
- At
- TimelineEventBlock
- TimelineEventFilter
- IncludeEvent
- time_origin_micros
- time_extent_micros
- IsolateTimelineEventFilter
- IncludeEvent
- TimelineEventRecorder
- track_uuid_to_track_metadata
- async_track_uuid_to_track_metadata
- packet
- kTrackUuidToTrackMetadataInitialCapacity
- TimelineEventRecorder
- TimelineEventFixedBufferRecorder
- kDefaultCapacity
- TimelineEventRingRecorder
- TimelineEventRingRecorder
- ~TimelineEventRingRecorder
- name
- TimelineEventStartupRecorder
- TimelineEventStartupRecorder
- ~TimelineEventStartupRecorder
- name
- TimelineEventCallbackRecorder
- name
- Size
- GetNewBlockLocked
- GetHeadBlockLocked
- ClearLocked
- TimelineEventEmbedderCallbackRecorder
- TimelineEventEmbedderCallbackRecorder
- ~TimelineEventEmbedderCallbackRecorder
- TimelineEventNopRecorder
- TimelineEventNopRecorder
- ~TimelineEventNopRecorder
- TimelineEventEndlessRecorder
- name
- Size
- TimelineEventPlatformRecorder
- GetNewBlockLocked
- GetHeadBlockLocked
- ClearLocked
- TimelineEventSystraceRecorder
- name
- Size
- TimelineEventFileRecorderBase
- Size
- OnEvent
- Write
- TimelineEventFileRecorder
- name
- TimelineEventPerfettoFileRecorder
- name
Learn more about Flutter for embedded and desktop on industrialflutter.com