Skip to content

Eliminate repeated invariant work during ITS metrics collection and export #4453

Open

Description

@jmacd

Pre-filing checklist

  • I searched existing issues and didn't find a duplicate

Component(s)

Rust OTAP dataflow (rust/otap-dataflow/)

Objective

Eliminate repeated work on invariant metadata during ITS metrics SDK collection
and export. This concerns the native ITS metrics implementation, not the removed
Rust OpenTelemetry metrics SDK.

Treat this as a category of avoidable collection/export overhead, starting with
two confirmed examples: repeated view resolution and repeated scope-attribute
encoding. Share immutable metadata and precomputed results where appropriate,
rather than rediscovering them on every reporting interval.

Rationale

1. View selection is recomputed for every export.

MetricsOtlpEncoder::encode() prepares each export batch. When views are
configured, prepare_metric_set_with_views() matches scope selectors once per
metric set in that batch, then resolves instrument selectors for each metric
field. These results are not retained across exports, even though the registered
entity attributes, metric descriptors, and the encoder's view configuration are
unchanged.

This is not measurement-recording overhead, and the no-views path skips it.
However, the same selection work repeats on every collection/export interval and
scales with metric sets, fields, and views.

2. Metrics repeatedly serialize immutable scope attributes.

Registered entities snapshot their typed attributes into EntityAttributeSet.
Metric exports retain those attributes through an Arc, but
metrics::otlp::encode_scope() iterates and protobuf-encodes them again for
every emitted scope.

The logging path already has a separate ScopeToBytesMap for encoded
scope-attribute fragments. Both signals use OTLP
InstrumentationScope.attributes; immutable attribute fragments are candidates
for shared pre-encoding, rather than separate serialization lifecycles.

Scope

  • Resolve view selections and invariant output metadata once per metric-set
    identity and active view configuration. Registration is one possible boundary;
    an encoder-owned first-use plan is another where view configuration is not
    available at registration. Keep genuinely batch-dependent work separate.
  • Pre-encode complete, validated entity scope-attribute fragments on a cold path
    and reuse them for both metrics and logs. Retain typed attributes for
    selection, equality, and deduplication. Scope names and outer envelopes remain
    signal-specific.
  • Account for entity registration, deduplication, unregistration, pending
    exports, and replacement of view configuration. Reuse must not introduce stale
    identity matches, unbounded cache growth, or new shared locks in measurement
    recording.
  • Review adjacent recurring metadata validation, projection, and collision-index
    construction for invariant portions that can be moved into the same plan. Do
    not assume all batch-dependent validation can be removed.
  • Resolve semantic differences before sharing an encoder or fragment. For
    example, metrics currently clamp UInt to i64::MAX, while self-tracing
    casts it to i64. Choose and test the intended behavior explicitly.
  • Keep invalid scope metadata explicit: cold-path validation/encoding must not
    silently accept truncation or overflow. Avoid carrying newly introduced
    truncation bookkeeping through every export merely to enable implementation
    reuse.

Acceptance Criteria

  • Repeated exports with unchanged metadata do not repeat scope/instrument
    view matching.
  • Repeated exports do not re-encode unchanged entity scope attributes, and
    metrics/logs can reuse the same validated attribute fragment.
  • Tests preserve typed selector semantics, view fan-out and naming,
    collision detection, and OTLP output; cover entity and view-configuration
    lifecycle changes.
  • Tests demonstrate bounded metadata retention and correct behavior for
    invalid attributes and identity reuse.
  • Extend internal_metrics_bridge measurements to distinguish cold
    initialization/first export from steady-state repeated exports, with and
    without views at representative entity counts.
  • Report before/after time, allocations, and retained memory, and verify
    that sharing scope encoding does not regress existing self-tracing benchmarks.

Dependencies or Blockers

Additional Context

Source references at upstream revision f3215c1c0:

Historical measurements in #3714 reported 98.03 us
without views versus 179.59 us with six views for 100 entities. This includes
all view processing, not just matching; it motivates measuring the invariant
work separately, not attributing the entire difference to these two issues.

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions