diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc index 211f0e28741..d6c65462a8c 100644 --- a/runtime/vm/timeline.cc +++ b/runtime/vm/timeline.cc @@ -669,7 +669,7 @@ void TimelineEvent::Init(EventType event_type, const char* label) { } bool TimelineEvent::Within(int64_t time_origin_micros, - int64_t time_extent_micros) { + int64_t time_extent_micros) const { if ((time_origin_micros == -1) || (time_extent_micros == -1)) { // No time range specified. return true; @@ -1610,9 +1610,8 @@ intptr_t TimelineEventFixedBufferRecorder::Size() { } #ifndef PRODUCT -void TimelineEventFixedBufferRecorder::PrintEventsCommon( - const TimelineEventFilter& filter, - std::function&& print_impl) { +void TimelineEventFixedBufferRecorder::ForEachNonEmptyBlock( + std::function&& handle_block) { // Acquire the recorder's lock to prevent the reclaimed blocks from being // handed out again until the trace has been serialized. MutexLocker ml(&lock_); @@ -1629,20 +1628,30 @@ void TimelineEventFixedBufferRecorder::PrintEventsCommon( if (!block->ContainsEventsThatCanBeSerializedLocked()) { continue; } - for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { - TimelineEvent* event = block->At(event_idx); - if (filter.IncludeEvent(event) && - event->Within(filter.time_origin_micros(), - filter.time_extent_micros())) { - ReportTime(event->LowTime()); - ReportTime(event->HighTime()); - print_impl(*event); - } - } + handle_block(*block); } } -void TimelineEventFixedBufferRecorder::PrintJSONEvents( +void TimelineEventBufferedRecorder::PrintEventsCommon( + const TimelineEventFilter& filter, + std::function&& print_impl) { + ForEachNonEmptyBlock( + [this, &filter, print_impl = std::move(print_impl)](auto& block) { + for (intptr_t event_idx = 0, length = block.length(); + event_idx < length; event_idx++) { + auto event = block.At(event_idx); + if (filter.IncludeEvent(event) && + event->Within(filter.time_origin_micros(), + filter.time_extent_micros())) { + ReportTime(event->LowTime()); + ReportTime(event->HighTime()); + print_impl(*event); + } + } + }); +} + +void TimelineEventBufferedRecorder::PrintJSONEvents( const JSONArray& events, const TimelineEventFilter& filter) { PrintEventsCommon(filter, [&events](const TimelineEvent& event) { @@ -1704,7 +1713,7 @@ inline void PrintPerfettoEventCallbackBody( heap_buffered_packet->Reset(); } -void TimelineEventFixedBufferRecorder::PrintPerfettoEvents( +void TimelineEventBufferedRecorder::PrintPerfettoEvents( JSONBase64String* jsonBase64String, const TimelineEventFilter& filter) { PrintEventsCommon( @@ -1721,8 +1730,8 @@ void TimelineEventFixedBufferRecorder::PrintPerfettoEvents( } #endif // defined(SUPPORT_PERFETTO) -void TimelineEventFixedBufferRecorder::PrintJSON(JSONStream* js, - TimelineEventFilter* filter) { +void TimelineEventBufferedRecorder::PrintJSON(JSONStream* js, + TimelineEventFilter* filter) { JSONObject topLevel(js); topLevel.AddProperty("type", "Timeline"); { @@ -1734,30 +1743,26 @@ void TimelineEventFixedBufferRecorder::PrintJSON(JSONStream* js, topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros()); } -#define PRINT_PERFETTO_TIMELINE_BODY \ - JSONObject jsobj_topLevel(js); \ - jsobj_topLevel.AddProperty("type", "PerfettoTimeline"); \ - \ - js->AppendSerializedObject("\"trace\":"); \ - { \ - JSONBase64String jsonBase64String(js); \ - PrintPerfettoMeta(&jsonBase64String); \ - PrintPerfettoEvents(&jsonBase64String, filter); \ - } \ - \ - jsobj_topLevel.AddPropertyTimeMicros("timeOriginMicros", \ - TimeOriginMicros()); \ - jsobj_topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros()); - #if defined(SUPPORT_PERFETTO) -void TimelineEventFixedBufferRecorder::PrintPerfettoTimeline( +void TimelineEventBufferedRecorder::PrintPerfettoTimeline( JSONStream* js, const TimelineEventFilter& filter) { - PRINT_PERFETTO_TIMELINE_BODY + JSONObject jsobj_topLevel(js); + jsobj_topLevel.AddProperty("type", "PerfettoTimeline"); + + js->AppendSerializedObject("\"trace\":"); + { + JSONBase64String jsonBase64String(js); + PrintPerfettoMeta(&jsonBase64String); + PrintPerfettoEvents(&jsonBase64String, filter); + } + + jsobj_topLevel.AddPropertyTimeMicros("timeOriginMicros", TimeOriginMicros()); + jsobj_topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros()); } #endif // defined(SUPPORT_PERFETTO) -void TimelineEventFixedBufferRecorder::PrintTraceEvent( +void TimelineEventBufferedRecorder::PrintTraceEvent( JSONStream* js, TimelineEventFilter* filter) { JSONArray events(js); @@ -2225,9 +2230,8 @@ TimelineEventEndlessRecorder::~TimelineEventEndlessRecorder() { } #ifndef PRODUCT -void TimelineEventEndlessRecorder::PrintEventsCommon( - const TimelineEventFilter& filter, - std::function&& print_impl) { +void TimelineEventEndlessRecorder::ForEachNonEmptyBlock( + std::function&& handle_block) { // Acquire the recorder's lock to prevent the reclaimed blocks from being // handed out again until the trace has been serialized. MutexLocker ml(&lock_); @@ -2238,74 +2242,9 @@ void TimelineEventEndlessRecorder::PrintEventsCommon( if (!current->ContainsEventsThatCanBeSerializedLocked()) { continue; } - intptr_t length = current->length(); - for (intptr_t i = 0; i < length; i++) { - TimelineEvent* event = current->At(i); - if (filter.IncludeEvent(event) && - event->Within(filter.time_origin_micros(), - filter.time_extent_micros())) { - ReportTime(event->LowTime()); - ReportTime(event->HighTime()); - print_impl(*event); - } - } + handle_block(*current); } } - -void TimelineEventEndlessRecorder::PrintJSONEvents( - const JSONArray& events, - const TimelineEventFilter& filter) { - PrintEventsCommon(filter, [&events](const TimelineEvent& event) { - events.AddValue(&event); - }); -} - -#if defined(SUPPORT_PERFETTO) -void TimelineEventEndlessRecorder::PrintPerfettoEvents( - JSONBase64String* jsonBase64String, - const TimelineEventFilter& filter) { - PrintEventsCommon( - filter, [this, &jsonBase64String](const TimelineEvent& event) { - PrintPerfettoEventCallbackBody( - &packet(), event, - [&jsonBase64String]( - protozero::HeapBuffered* - packet) { - perfetto_utils::AppendPacketToJSONBase64String(jsonBase64String, - packet); - }); - }); -} -#endif // defined(SUPPORT_PERFETTO) - -void TimelineEventEndlessRecorder::PrintJSON(JSONStream* js, - TimelineEventFilter* filter) { - JSONObject topLevel(js); - topLevel.AddProperty("type", "Timeline"); - { - JSONArray events(&topLevel, "traceEvents"); - PrintJSONMeta(events); - PrintJSONEvents(events, *filter); - } - topLevel.AddPropertyTimeMicros("timeOriginMicros", TimeOriginMicros()); - topLevel.AddPropertyTimeMicros("timeExtentMicros", TimeExtentMicros()); -} - -#if defined(SUPPORT_PERFETTO) -void TimelineEventEndlessRecorder::PrintPerfettoTimeline( - JSONStream* js, - const TimelineEventFilter& filter) { - PRINT_PERFETTO_TIMELINE_BODY -} -#endif // defined(SUPPORT_PERFETTO) - -void TimelineEventEndlessRecorder::PrintTraceEvent( - JSONStream* js, - TimelineEventFilter* filter) { - JSONArray events(js); - PrintJSONMeta(events); - PrintJSONEvents(events, *filter); -} #endif // !defined(PRODUCT) TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked() { diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h index 0dc170a8d32..29bca99f721 100644 --- a/runtime/vm/timeline.h +++ b/runtime/vm/timeline.h @@ -533,7 +533,7 @@ class TimelineEvent { } } - bool Within(int64_t time_origin_micros, int64_t time_extent_micros); + bool Within(int64_t time_origin_micros, int64_t time_extent_micros) const; void set_owns_label(bool owns_label) { state_ = OwnsLabelBit::update(owns_label, state_); @@ -846,7 +846,7 @@ class TimelineEventFilter : public ValueObject { virtual ~TimelineEventFilter(); - virtual bool IncludeEvent(TimelineEvent* event) const { + virtual bool IncludeEvent(const TimelineEvent* event) const { if (event == nullptr) { return false; } @@ -868,7 +868,7 @@ class IsolateTimelineEventFilter : public TimelineEventFilter { int64_t time_origin_micros = -1, int64_t time_extent_micros = -1); - bool IncludeEvent(TimelineEvent* event) const final { + bool IncludeEvent(const TimelineEvent* event) const final { return event->IsValid() && (event->isolate_id() == isolate_id_); } @@ -977,14 +977,9 @@ class TimelineEventRecorder : public MallocAllocated { DISALLOW_COPY_AND_ASSIGN(TimelineEventRecorder); }; -// An abstract recorder that stores events in a buffer of fixed capacity. -class TimelineEventFixedBufferRecorder : public TimelineEventRecorder { +// An abstract recorder that buffers recorded events. +class TimelineEventBufferedRecorder : public TimelineEventRecorder { public: - static constexpr intptr_t kDefaultCapacity = 32 * KB; // Number of events. - - explicit TimelineEventFixedBufferRecorder(intptr_t capacity); - virtual ~TimelineEventFixedBufferRecorder(); - #ifndef PRODUCT void PrintJSON(JSONStream* js, TimelineEventFilter* filter) final; #if defined(SUPPORT_PERFETTO) @@ -992,7 +987,32 @@ class TimelineEventFixedBufferRecorder : public TimelineEventRecorder { const TimelineEventFilter& filter) final; #endif // defined(SUPPORT_PERFETTO) void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) final; + + private: + virtual void ForEachNonEmptyBlock( + std::function&& handle_block) = 0; + + void PrintJSONEvents(const JSONArray& array, + const TimelineEventFilter& filter); + +#if defined(SUPPORT_PERFETTO) + void PrintPerfettoEvents(JSONBase64String* jsonBase64String, + const TimelineEventFilter& filter); +#endif // defined(SUPPORT_PERFETTO) + + void PrintEventsCommon( + const TimelineEventFilter& filter, + std::function&& print_impl); #endif // !defined(PRODUCT) +}; + +// An abstract recorder that stores events in a buffer of fixed capacity. +class TimelineEventFixedBufferRecorder : public TimelineEventBufferedRecorder { + public: + static constexpr intptr_t kDefaultCapacity = 32 * KB; // Number of events. + + explicit TimelineEventFixedBufferRecorder(intptr_t capacity); + virtual ~TimelineEventFixedBufferRecorder(); intptr_t Size(); @@ -1004,15 +1024,6 @@ class TimelineEventFixedBufferRecorder : public TimelineEventRecorder { intptr_t FindOldestBlockIndexLocked() const; void ClearLocked(); -#ifndef PRODUCT - void PrintJSONEvents(const JSONArray& array, - const TimelineEventFilter& filter); -#if defined(SUPPORT_PERFETTO) - void PrintPerfettoEvents(JSONBase64String* jsonBase64String, - const TimelineEventFilter& filter); -#endif // defined(SUPPORT_PERFETTO) -#endif // !defined(PRODUCT) - VirtualMemory* memory_; TimelineEventBlock* blocks_; intptr_t capacity_; @@ -1020,10 +1031,9 @@ class TimelineEventFixedBufferRecorder : public TimelineEventRecorder { intptr_t block_cursor_; private: -#if !defined(PRODUCT) - inline void PrintEventsCommon( - const TimelineEventFilter& filter, - std::function&& print_impl); +#ifndef PRODUCT + void ForEachNonEmptyBlock( + std::function&& handle_block) final; #endif // !defined(PRODUCT) }; @@ -1109,20 +1119,11 @@ class TimelineEventNopRecorder : public TimelineEventCallbackRecorder { // A recorder that stores events in chains of blocks of events. // NOTE: This recorder will continue to allocate blocks until it exhausts // memory. -class TimelineEventEndlessRecorder : public TimelineEventRecorder { +class TimelineEventEndlessRecorder : public TimelineEventBufferedRecorder { public: TimelineEventEndlessRecorder(); virtual ~TimelineEventEndlessRecorder(); -#ifndef PRODUCT - void PrintJSON(JSONStream* js, TimelineEventFilter* filter) final; -#if defined(SUPPORT_PERFETTO) - void PrintPerfettoTimeline(JSONStream* js, - const TimelineEventFilter& filter) final; -#endif // defined(SUPPORT_PERFETTO) - void PrintTraceEvent(JSONStream* js, TimelineEventFilter* filter) final; -#endif // !defined(PRODUCT) - const char* name() const { return ENDLESS_RECORDER_NAME; } intptr_t Size() { return block_index_ * sizeof(TimelineEventBlock); } @@ -1133,24 +1134,14 @@ class TimelineEventEndlessRecorder : public TimelineEventRecorder { TimelineEventBlock* GetHeadBlockLocked(); void ClearLocked(); -#ifndef PRODUCT - void PrintJSONEvents(const JSONArray& array, - const TimelineEventFilter& filter); -#if defined(SUPPORT_PERFETTO) - void PrintPerfettoEvents(JSONBase64String* jsonBase64String, - const TimelineEventFilter& filter); -#endif // defined(SUPPORT_PERFETTO) -#endif // !defined(PRODUCT) - TimelineEventBlock* head_; TimelineEventBlock* tail_; intptr_t block_index_; private: -#if !defined(PRODUCT) - inline void PrintEventsCommon( - const TimelineEventFilter& filter, - std::function&& print_impl); +#ifndef PRODUCT + void ForEachNonEmptyBlock( + std::function&& handle_block) final; #endif // !defined(PRODUCT) friend class TimelineTestHelper;