Skip to main content

GPUTraceAggregation

Overview​

GPUTraceAggregation computes dense counts and duration statistics over canonical trace columns. GPUTraceTimeBuckets computes interval occupancy and clipped active duration over trace time. Both are exported from @luma.gl/experimental/gpu-trace; the underlying generic aggregations remain GPUGroupAggregation and GPUHistogram.

GitHub
Loading examplePreparing GPU resources…

The live viewer uses a separate analysis command graph. It can profile the entire trace, the visible viewport, or a measured time interval; viewport updates are deferred until navigation settles. The graph keeps group counts, duration histograms, and clipped time buckets on the GPU and reads back only the small fixed-size chart result. Unchanged scope generations reuse cached output.

At a glance

QuestionAnswer
ProblemCompute trace-domain counts, duration statistics, and trace-time occupancy.
Reads / writesReads canonical trace columns, scope masks, and time intervals; writes dense groups, buckets, and summaries.
OwnershipPublic inputs and outputs are caller-owned; scratch storage is graph-owned transient memory.
Output contractBounded group rows and time buckets with counts, clipped durations, and validation status.
Expected workLinear selected-row aggregation plus bounded group or bucket finalization.
ChunksPreserves canonical source partitions and aggregates into explicit result domains.
Conditions / budgetsCaches by scope generation and supports budgeted full-trace analysis.
Neighborhoodviewport/measurement/full-trace mask → GPUTraceAggregation → charts and cross-filtering.

Reusable chart-output layout​

GPUTraceAnalyticsOutputLayout packs named uint32 and float32 series into one compact result buffer. It calculates aligned offsets, creates typed graph views for contributors, and decodes the same named series after a small asynchronous readback. Applications therefore do not need to duplicate byte-offset arithmetic between their GPU graph and chart UI.

import {GPUTraceAnalyticsOutputLayout} from '@luma.gl/experimental/gpu-trace';

const outputLayout = new GPUTraceAnalyticsOutputLayout([
{id: 'service-counts', format: 'uint32', length: serviceCount},
{id: 'service-duration', format: 'float32', length: serviceCount},
{id: 'time-bucket-counts', format: 'uint32', length: 64}
]);

const resultBuffer = device.createBuffer({
byteLength: outputLayout.byteLength,
usage: Buffer.STORAGE | Buffer.COPY_SRC
});

const resultHandle = graph.importBuffer({id: 'analytics-results'}, resultBuffer);
const serviceCounts = outputLayout.createUint32View(graph, resultHandle, 'service-counts');

// After an explicitly requested compact readback:
const counts = outputLayout.decodeUint32(bytes, 'service-counts');

The layout owns no buffers, submission policy, or charts. The same views can remain GPU-resident for a renderer; decoding is only for applications that choose to draw small DOM or canvas charts.

Usage​

import {GPUTraceAggregation} from '@luma.gl/experimental/gpu-trace';

new GPUTraceAggregation({
trace: traceView,
dimension: 'process',
metric: 'duration-mean',
selection: interaction.visibleMask,
output: meanDurationByProcess
}).addToGraph(graph);

Built-in dimensions are lane, group, process, thread, and classification. Applications may instead supply a dense unsigned key column, such as an operation dictionary ID. Inputs may be packed or interleaved and may preserve multiple source chunks.

The supported metrics are count, duration-sum, duration-min, duration-max, and duration-mean. Count outputs use uint32; duration outputs use float32. Output length defines the accepted dense key range, and keys outside that range are ignored.

Trace-time buckets​

import {GPUTraceTimeBuckets} from '@luma.gl/experimental/gpu-trace';

new GPUTraceTimeBuckets({
trace: traceView,
domain: [traceStart, traceEnd],
selection: interaction.visibleMask,
countOutput: intersectingSpanCounts,
durationOutput: clippedDurationSums
}).addToGraph(graph);

The output length defines an equal-width trace-time partition. A span contributes once to every bucket it intersects, and its duration contribution is clipped at the bucket boundaries. For traces that guarantee non-overlapping spans within each lane, dividing a bucket's duration sum by bucketDuration * laneCount yields utilization. Overlapping spans intentionally produce summed occupancy rather than an interval union.

Execution contract​

  • The contributor declares graph work only; it never compiles, submits, or maps buffers.
  • The optional selection must contain one zero/nonzero row per canonical span and preserve input chunk boundaries when the trace uses multiple chunks.
  • Outputs are cleared on every graph encoding and remain GPU-resident.
  • Dataset-wide aggregations should be cached or encoded only when their input generation changes; do not attach a full-trace aggregation to every viewport-only frame.