mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 10:49:00 +00:00
fe43431184
TEST=Retrieved a trace using GetPerfettoVMTimeline and checked that the timestamps of events were correct in the Perfetto trace viewer. Change-Id: Ie06e9e883a5d740022fa162bf7162dca6babcf58 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/302961 Reviewed-by: Ben Konyi <bkonyi@google.com>
129 lines
4.7 KiB
C++
129 lines
4.7 KiB
C++
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef RUNTIME_VM_PERFETTO_UTILS_H_
|
|
#define RUNTIME_VM_PERFETTO_UTILS_H_
|
|
|
|
#if defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
|
|
|
#include <memory>
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
#include "perfetto/ext/tracing/core/trace_packet.h"
|
|
#include "perfetto/protozero/scattered_heap_buffer.h"
|
|
#include "vm/json_stream.h"
|
|
#include "vm/os.h"
|
|
#include "vm/protos/perfetto/common/builtin_clock.pbzero.h"
|
|
#include "vm/protos/perfetto/trace/clock_snapshot.pbzero.h"
|
|
#include "vm/protos/perfetto/trace/trace_packet.pbzero.h"
|
|
#include "vm/protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
|
|
#include "vm/protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
|
|
|
|
namespace dart {
|
|
|
|
namespace perfetto_utils {
|
|
|
|
inline void SetTrustedPacketSequenceId(
|
|
perfetto::protos::pbzero::TracePacket* packet) {
|
|
// trusted_packet_sequence_id uniquely identifies a trace producer + writer
|
|
// pair. We set the trusted_packet_sequence_id of all packets that we write to
|
|
// the arbitrary value of 1.
|
|
packet->set_trusted_packet_sequence_id(1);
|
|
}
|
|
|
|
inline void SetTimestampAndMonotonicClockId(
|
|
perfetto::protos::pbzero::TracePacket* packet,
|
|
intptr_t timestamp_micros) {
|
|
ASSERT(packet != nullptr);
|
|
// TODO(derekx): We should be able to set the unit_multiplier_ns field in a
|
|
// ClockSnapshot to avoid manually converting from microseconds to
|
|
// nanoseconds, but I haven't been able to get it to work.
|
|
packet->set_timestamp(timestamp_micros * 1000);
|
|
packet->set_timestamp_clock_id(
|
|
perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
|
|
}
|
|
|
|
inline void PopulateClockSnapshotPacket(
|
|
perfetto::protos::pbzero::TracePacket* packet) {
|
|
SetTrustedPacketSequenceId(packet);
|
|
|
|
perfetto::protos::pbzero::ClockSnapshot& clock_snapshot =
|
|
*packet->set_clock_snapshot();
|
|
clock_snapshot.set_primary_trace_clock(
|
|
perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
|
|
|
|
perfetto::protos::pbzero::ClockSnapshot_Clock& clock =
|
|
*clock_snapshot.add_clocks();
|
|
clock.set_clock_id(
|
|
perfetto::protos::pbzero::BuiltinClock::BUILTIN_CLOCK_MONOTONIC);
|
|
clock.set_timestamp(OS::GetCurrentMonotonicMicrosForTimeline() * 1000);
|
|
}
|
|
|
|
inline void PopulateProcessDescriptorPacket(
|
|
perfetto::protos::pbzero::TracePacket* packet) {
|
|
perfetto_utils::SetTrustedPacketSequenceId(packet);
|
|
|
|
perfetto::protos::pbzero::TrackDescriptor& track_descriptor =
|
|
*packet->set_track_descriptor();
|
|
const int64_t pid = OS::ProcessId();
|
|
track_descriptor.set_uuid(pid);
|
|
|
|
perfetto::protos::pbzero::ProcessDescriptor& process_descriptor =
|
|
*track_descriptor.set_process();
|
|
process_descriptor.set_pid(pid);
|
|
// TODO(derekx): Add the process name.
|
|
}
|
|
|
|
inline const std::tuple<std::unique_ptr<const uint8_t[]>, intptr_t>
|
|
GetProtoPreamble(
|
|
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet) {
|
|
ASSERT(packet != nullptr);
|
|
|
|
intptr_t size = 0;
|
|
for (const protozero::ScatteredHeapBuffer::Slice& slice :
|
|
packet->GetSlices()) {
|
|
size += slice.size() - slice.unused_bytes();
|
|
}
|
|
|
|
std::unique_ptr<uint8_t[]> preamble =
|
|
std::make_unique<uint8_t[]>(perfetto::TracePacket::kMaxPreambleBytes);
|
|
uint8_t* ptr = &preamble[0];
|
|
|
|
const uint8_t tag = protozero::proto_utils::MakeTagLengthDelimited(
|
|
perfetto::TracePacket::kPacketFieldNumber);
|
|
static_assert(tag < 0x80, "TracePacket tag should fit in one byte");
|
|
*(ptr++) = tag;
|
|
|
|
ptr = protozero::proto_utils::WriteVarInt(size, ptr);
|
|
intptr_t preamble_size = reinterpret_cast<intptr_t>(ptr) -
|
|
reinterpret_cast<intptr_t>(&preamble[0]);
|
|
return std::make_tuple(std::move(preamble), preamble_size);
|
|
}
|
|
|
|
inline void AppendPacketToJSONBase64String(
|
|
JSONBase64String* jsonBase64String,
|
|
protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet) {
|
|
ASSERT(jsonBase64String != nullptr);
|
|
ASSERT(packet != nullptr);
|
|
|
|
const std::tuple<std::unique_ptr<const uint8_t[]>, intptr_t>& response =
|
|
perfetto_utils::GetProtoPreamble(packet);
|
|
const uint8_t* preamble = std::get<0>(response).get();
|
|
const intptr_t preamble_length = std::get<1>(response);
|
|
jsonBase64String->AppendBytes(preamble, preamble_length);
|
|
for (const protozero::ScatteredHeapBuffer::Slice& slice :
|
|
packet->GetSlices()) {
|
|
jsonBase64String->AppendBytes(slice.start(),
|
|
slice.size() - slice.unused_bytes());
|
|
}
|
|
}
|
|
|
|
} // namespace perfetto_utils
|
|
|
|
} // namespace dart
|
|
|
|
#endif // defined(SUPPORT_PERFETTO) && !defined(PRODUCT)
|
|
|
|
#endif // RUNTIME_VM_PERFETTO_UTILS_H_
|