Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/reference/perfetto-manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,13 @@ Setting the same key twice overwrites: the last value wins.
Wherever a clock name is expected, one of:

`REALTIME`, `REALTIME_COARSE`, `MONOTONIC`, `MONOTONIC_COARSE`,
`MONOTONIC_RAW`, `BOOTTIME`
`MONOTONIC_RAW`, `BOOTTIME`, `TRACE_FILE`

These correspond to the builtin clocks in
[builtin_clock.proto](/protos/perfetto/common/builtin_clock.proto) and the
POSIX `clock_gettime` domains of the same names.
POSIX `clock_gettime` domains of the same names. `TRACE_FILE` is the file's
own per-file timeline (same as omitting `clock`); in `trace_time` it requires
`file`.

## {#sql} Effects on the SQL surface

Expand Down
22 changes: 18 additions & 4 deletions src/trace_processor/forwarding_trace_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -232,17 +232,31 @@ base::Status ForwardingTraceParser::Init(const TraceBlobView& blob) {
// clock of its own, so flag it: the file is now single-clock / single-machine
// and any ClockSnapshot or remote machine id on it is rejected. It still
// converts through the default clock set up below, like any clockless format.
if (manifest_entry && manifest_entry->clock_override &&
!manifest_entry->clock_override->source_clock) {
trace_context_->trace_state->has_clock_override = true;
//
// The override's edge is attached to a specific source clock (the manifest's
// `clock`, or for a pinned file its private TraceFile clock), so that clock
// must also be the file's default: otherwise events which don't name a clock
// (e.g. proto packets without timestamp_clock_id or ClockSnapshots) never
// reach the edge and the offset is silently ignored. Proto may still replace
// this later via primary_trace_clock.
bool force_default_clock = false;
if (manifest_entry && manifest_entry->clock_override) {
const auto& co = *manifest_entry->clock_override;
if (co.source_clock) {
trace_clock = ClockId::Machine(*co.source_clock);
} else {
trace_context_->trace_state->has_clock_override = true;
trace_clock = ClockId::TraceFile(trace_context_->trace_id().value);
}
force_default_clock = true;
}

// Set up the format's source clock. Proto manages its own default clock
// (primary_trace_clock / ClockSnapshot) so it does not set the default clock
// (sets_default_clock=false); every other format converts its events through
// the default clock via ClockTracker::ConvertDefaultClockToTraceTime.
if (trace_clock) {
if (desc->sets_default_clock) {
if (desc->sets_default_clock || force_default_clock) {
clock_tracker->SetTraceDefaultClock(*trace_clock);
}
if (desc->claims_global_clock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,13 @@ base::StatusOr<uint32_t> ParseClockName(const json::Dom& value) {
return BuiltinClock::BUILTIN_CLOCK_MONOTONIC_RAW;
if (name == "BOOTTIME")
return BuiltinClock::BUILTIN_CLOCK_BOOTTIME;
// The file's own private per-file timeline.
if (name == "TRACE_FILE")
return BuiltinClock::BUILTIN_CLOCK_TRACE_FILE;
return base::ErrStatus(
"perfetto_manifest: unknown clock name: %s. Use one of REALTIME, "
"REALTIME_COARSE, MONOTONIC, MONOTONIC_COARSE, MONOTONIC_RAW, BOOTTIME.",
"REALTIME_COARSE, MONOTONIC, MONOTONIC_COARSE, MONOTONIC_RAW, BOOTTIME, "
"TRACE_FILE.",
name.c_str());
}

Expand Down Expand Up @@ -102,7 +106,9 @@ base::StatusOr<ClockOverride> ParseClocks(const json::Dom& clocks) {
}
if (clocks.HasMember("clock")) {
ASSIGN_OR_RETURN(uint32_t source_clock, ParseClockName(clocks["clock"]));
result.source_clock = source_clock;
// TRACE_FILE is the same as omitting the clock (pin the private clock).
if (source_clock != protos::pbzero::BUILTIN_CLOCK_TRACE_FILE)
result.source_clock = source_clock;
}

if (!clocks.HasMember("sync_to")) {
Expand Down Expand Up @@ -133,9 +139,15 @@ base::StatusOr<ClockOverride> ParseClocks(const json::Dom& clocks) {
}
if (sync_to.HasMember("clock")) {
ASSIGN_OR_RETURN(uint32_t ref_clock, ParseClockName(sync_to["clock"]));
result.ref_clock = ref_clock;
if (ref_clock != protos::pbzero::BUILTIN_CLOCK_TRACE_FILE)
result.ref_clock = ref_clock;
}

if (sync_to.HasMember("offset_ns")) {
return base::ErrStatus(
"perfetto_manifest: clocks: offset_ns belongs in the clocks block, "
"not inside sync_to.");
}
if (clocks.HasMember("offset_ns")) {
if (!clocks["offset_ns"].IsIntegral()) {
return base::ErrStatus(
Expand Down Expand Up @@ -543,26 +555,6 @@ base::Status PerfettoManifestReader::ApplyManifest() {
return *name_to_id.Find(*ref_machine);
};

// Claim the global trace time clock directly: the manifest is the first file,
// so its claim wins over later traces. trace_time.file (+ .machine) pins it
// to that file's (pre-allocated) machine.
if (state->trace_time_clock) {
ClockId trace_time = ClockId::Machine(*state->trace_time_clock);
if (state->trace_time_file || state->trace_time_machine) {
ASSIGN_OR_RETURN(
int64_t raw,
resolve_ref("trace_time: file", "trace_time: machine",
state->trace_time_file, state->trace_time_machine,
/*fallback=*/0));
trace_time = ClockId::Machine(EnsureMachineRow(context_, raw),
*state->trace_time_clock);
}
context_->trace_time_state->TrySetClock(trace_time, file_id_);
context_->global_metadata_tracker->SetMetadata(
std::nullopt, std::nullopt, metadata::trace_time_clock_id,
Variadic::Integer(*state->trace_time_clock));
}

// Resolves which machine declared by |entry| owns its source clock: the named
// |source_machine| (which must be one this file itself declares), or - when
// unset - the file's sole machine. A multi-machine file is several machines,
Expand Down Expand Up @@ -615,6 +607,35 @@ base::Status PerfettoManifestReader::ApplyManifest() {
path.c_str());
};

// Claim the global trace time clock directly: the manifest is the first file,
// so its claim wins over later traces. trace_time.file (+ .machine) pins it
// to that file's (pre-allocated) machine.
if (state->trace_time_clock) {
ClockId trace_time = ClockId::Machine(*state->trace_time_clock);
if (state->trace_time_file || state->trace_time_machine) {
ASSIGN_OR_RETURN(
int64_t raw,
resolve_ref("trace_time: file", "trace_time: machine",
state->trace_time_file, state->trace_time_machine,
/*fallback=*/0));
trace_time = ClockId::Machine(EnsureMachineRow(context_, raw),
*state->trace_time_clock);
}
// TRACE_FILE: trace time is |file|'s private per-file clock.
if (*state->trace_time_clock == protos::pbzero::BUILTIN_CLOCK_TRACE_FILE) {
if (!state->trace_time_file) {
return base::ErrStatus(
"perfetto_manifest: trace_time: clock TRACE_FILE requires file");
}
ASSIGN_OR_RETURN(trace_time.trace_file_id,
find_trace_file_id(*state->trace_time_file));
}
context_->trace_time_state->TrySetClock(trace_time, file_id_);
context_->global_metadata_tracker->SetMetadata(
std::nullopt, std::nullopt, metadata::trace_time_clock_id,
Variadic::Integer(*state->trace_time_clock));
}

// Add every override's cross-machine edge to the global clock graph now,
// before any file is parsed (a file may reference another parsed later),
// recording it in the clock_snapshot table as ClockTracker would. The source
Expand Down
Loading
Loading