[vm] Reduce duplication in timeline.cc

Place serialization code shared between fixed
buffer and endless recorders into an abstract
superclass.

TEST=ci

Change-Id: I643e606ec144b06406375b796f4f2b369b657d3c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417200
Reviewed-by: Derek Xu <derekx@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
This commit is contained in:
Vyacheslav Egorov
2025-03-25 08:13:56 -07:00
committed by Commit Queue
parent 0dd150bd27
commit 6659976329
2 changed files with 81 additions and 151 deletions
+44 -105
View File
@@ -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<void(const TimelineEvent&)>&& print_impl) {
void TimelineEventFixedBufferRecorder::ForEachNonEmptyBlock(
std::function<void(const TimelineEventBlock&)>&& 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<void(const TimelineEvent&)>&& 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<void(const TimelineEvent&)>&& print_impl) {
void TimelineEventEndlessRecorder::ForEachNonEmptyBlock(
std::function<void(const TimelineEventBlock&)>&& 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<perfetto::protos::pbzero::TracePacket>*
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() {
+37 -46
View File
@@ -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<void(const TimelineEventBlock&)>&& 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<void(const TimelineEvent&)>&& 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<void(const TimelineEvent&)>&& print_impl);
#ifndef PRODUCT
void ForEachNonEmptyBlock(
std::function<void(const TimelineEventBlock&)>&& 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<void(const TimelineEvent&)>&& print_impl);
#ifndef PRODUCT
void ForEachNonEmptyBlock(
std::function<void(const TimelineEventBlock&)>&& handle_block) final;
#endif // !defined(PRODUCT)
friend class TimelineTestHelper;