Skip to content

Migrating V8 cpu profiler from legacy phase 'P' to modern TrackEvent #5673

@deepak1556

Description

@deepak1556

Context

V8 is migrating to modern events in https://issues.chromium.org/issues/498378089. The CPU profiler emits Profile and ProfileChunk events under the disabled-by-default-v8.cpu_profiler category, which currently use the legacy TRACE_EVENT_SAMPLE_WITH_ID1 macro (phase 'P').

The modern TrackEvent.Type has no TYPE_SAMPLE.

Current plan is to use TRACE_EVENT_INSTANT https://chromium-review.googlesource.com/c/v8/v8/+/7787230/5/src/profiler/profile-generator.cc since a sample event is structurally similar to instant event with a differentiating phase byte.

// Legacy (phase 'P'):
TrackEvent {
  legacy_event {
    phase: 'P'
    unscoped_id: 42
  }
  debug_annotation { ... } ← JSON payload
}

// Modern (TYPE_INSTANT):
TrackEvent {
  type: TYPE_INSTANT
  name: "Profile"
  debug_annotation {       ← JSON payload (same format)
    name: "data"
    string_value: "{...\"id\":42...}"  ← id is HERE (or in correlation_id)
  }
}

Current state in the Perfetto trace processor

Tokenizer

The tokenizer special-cases V8 CPU samples at

// Handle legacy sample events which might have timestamps embedded inside.
if (PERFETTO_UNLIKELY(event.has_legacy_event())) {
protos::pbzero::TrackEvent::LegacyEvent::Decoder leg(event.legacy_event());
if (PERFETTO_UNLIKELY(leg.phase() == 'P')) {
base::Status status = TokenizeLegacySampleEvent(
event, leg, *data.trace_packet_data.sequence_state);
if (!status.ok()) {
context_->storage->IncrementStats(
stats::legacy_v8_cpu_profile_invalid_sample);
}
}
}
based on the phase type. This extracts the embedded V8 CPU profile data and feeds it to V8Tracker, which populates the cpu_profile_stack_sample table.

Event importer

Phase 'P' has no dedicated case in the phase switch

// TODO(eseckler): Replace phase with type and remove handling of
// legacy_event_.phase() once it is no longer used by producers.
char phase = static_cast<char>(ParsePhaseOrType());
switch (phase) {
case 'B': // TRACE_EVENT_PHASE_BEGIN.
return ParseThreadBeginEvent();
case 'E': // TRACE_EVENT_PHASE_END.
return ParseThreadEndEvent();
case 'X': // TRACE_EVENT_PHASE_COMPLETE.
return ParseThreadCompleteEvent();
case 's': // TRACE_EVENT_PHASE_FLOW_BEGIN.
case 't': // TRACE_EVENT_PHASE_FLOW_STEP.
case 'f': // TRACE_EVENT_PHASE_FLOW_END.
return ParseFlowEventV1(phase);
case 'i':
case 'I': // TRACE_EVENT_PHASE_INSTANT.
case 'R': // TRACE_EVENT_PHASE_MARK.
return ParseThreadInstantEvent(phase);
case 'b': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
case 'S':
return ParseAsyncBeginEvent(phase);
case 'e': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
case 'F':
return ParseAsyncEndEvent();
case 'n': // TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT
return ParseAsyncInstantEvent();
case 'T':
case 'p':
return ParseAsyncStepEvent(phase);
case 'M': // TRACE_EVENT_PHASE_METADATA (process and thread names).
return ParseMetadataEvent();
default:
// Other events are proxied via the raw table for JSON export.
return ParseLegacyEventAsRawEvent();
}
— it defaults to storing the event in chrome_raw_table as an opaque blob.

The problem

Using TYPE_INSTANT there's no way to distinguish a "regular" instant event from a CPU profile sample event at the proto level. The tokenizer must now match by event name ("Profile", "ProfileChunk") rather than by type. Similarly, DevTools must explicitly exclude these events from generic instant event handling, https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/7800921.

  1. Should TYPE_INSTANT be the recommended modern replacement for phase 'P'?

The current approach works but requires name-based detection in the tokenizer and explicit exclusions in consumers. As part of this migration, I would need to special case tokenizer like

if (event.type() == TYPE_INSTANT) {
    if (name == "Profile" || name == "ProfileChunk") {
        TokenizeModernSampleEvent(...);
    }
}

Note: TokenizeModernSampleEvent will be using TrackEvent::Decoder instead of LegacyEvent::Decoder rest of the mechanics from the current tokenizer will remain the same.

  1. Would a dedicated TYPE_SAMPLE be considered?

    Adding TYPE_SAMPLE to the TrackEvent.Type enum would:

  • Allow the tokenizer to continue to detect CPU profile events by type alone
  • Eliminate the need for downstream consumers (DevTools) to special-case instant events by name

cc @camillobruni

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions