Paced shared-memory convolution probe¶
This source-build diagnostic drives the public GpuAudioTransport and
GpuConvolver with a stereo, 257-tap convolution. The transport's worker owns
GPU submission and completion service. A separate thread supplies paced audio
blocks and never calls pump(). The probe checks the delivered stream against
independent direct-double convolution after the timed interval, including
latency-aligned CPU fallback.
Configure a Release Apple Silicon build with the pinned provider and these options:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_ARCHITECTURES=arm64 \
-DPULP_BUILD_TESTS=ON -DPULP_ENABLE_GPU=ON \
-DPULP_GPU_AUDIO_EXACT_PROVIDER_PROOF=ON \
-DPULP_GPU_AUDIO_ENABLE_EXPERIMENTAL_SHARED_IO_CONVOLVER=ON
tools/ci/governed-build.sh cmake --build build \
--target pulp-gpu-shared-io-paced-convolution-probe
ctest --test-dir build -R '^pulp-gpu-shared-io-paced-convolution-probe$' \
--output-on-failure
SDK-only builds can use the same provider options with PULP_BUILD_TESTS=OFF.
Production pulp-gpu-audio initializes the expected Dawn revision independently
of test registration. Exact proof validates the manifest, retained provider
archive, extracted headers/libraries, and generation receipt at configure time
and again before building the library. A mismatch fails the build. Configure
and library prelink receipts are under build/gpu-audio-provider-identity/;
probe executable binding receipts remain separate evidence when tests are built.
The experimental convolver option is still required to enable its shared path.
With exact proof off, the expected revision remains empty: providers may check
header/procedure-table agreement, but no manifest authentication is claimed.
These build checks establish provider identity, not successful GPU delivery or
a realtime performance claim.
Run a bounded diagnostic, choosing a new output directory:
build/test/pulp-gpu-shared-io-paced-convolution-probe \
--frames=32 --lead=2 --blocks=4096 --warmup=64 \
--output-dir=/absolute/path/to/new-capture
Supported frames are 32, 64, and 128; lead is 1, 2, 4, or 8 blocks. The sample
rate is 48 kHz and physical provider slots remain two. --wake-on-write enables
the transport's existing semaphore notification instead of its default polling
worker. Completion service remains the provider's default ProcessEvents
policy. The lower-level provider probe can compare this with
--completion-policy=wait-any or --completion-policy=timed-wait-any; those
policies retain each submission's Dawn Future handles and wait on the
serialized non-realtime dispatcher. timed-wait-any requests Dawn's
TimedWaitAny instance feature and accepts --completion-wait-ns=N as a
dispatcher wait bound. Pop-error-scope and device-lost callbacks still use
AllowProcessEvents and are explicitly pumped before terminal completion is
published. These policies keep Dawn calls off the audio callback and do not
promise hard realtime behavior or GPU scheduling priority.
The maximum is 100,000 measured blocks per invocation. The probe keeps the
stereo input, output, and per-callback records in memory so that it can emit a
complete CSV; the bound supports an approximately 67-second run at 48 kHz and
32 frames without turning the diagnostic into a multi-hundred-megabyte or
unbounded allocation. A million blocks would be about 11 minutes at that
period, but longer campaigns should use a streaming harness rather than
increasing this in-memory limit.
receipt.json contains configuration, numerical failures, callback overruns,
late callback starts, and the transport's miss-counter delta. blocks.csv
preserves every callback position, source position, scheduled time, observed
callback begin/end, miss-counter delta, and maximum numerical error. Warmup and
initial pipeline priming are retained but excluded from measured-block counts.
No file output or numerical-oracle work occurs during the paced interval.
Exit 0 means the stream passed the numerical oracle and the worker made GPU
progress. It does not mean that every deadline was met. Exit 1 is a completed
failed check; exit 2 is invalid configuration, unavailable shared provider, or
an execution/artifact error. --negative-control corrupts one measured output
sample after processing; the verifier requires exactly one failed block and
exit 1. Unavailability cannot satisfy that negative control.
This is a simulated callback driven by a non-realtime thread, not an audio device or host acceptance test. Callback begin/end are external CPU clock observations, not GPU timestamps. Miss-counter deltas are not a substitute for the full per-block terminal/disposition trace. Retain source revision, binary and provider hashes, build flags, machine/load/thermal context alongside these artifacts before making comparisons. The receipt deliberately leaves the performance verdict unassigned; matched staged/shared trials and host tests remain separate requirements.