Repository navigation
processSEG 0.3.1: relation runs, one interval test, 24-lane picking, fresh benchmarks - #5
Merged
Merged
Conversation
preplotFold, describePatches, compareRelations and recordCompleteness now share one internal walk, survey/relwalk.nim: `stationChannels` goes along parseSEG 0.10.0's `relationRuns`, one station key per station instead of one per channel, and yields each station with its channel count (the components of a multi-component station). It falls back to `relations` channel by channel for any record where the runs would not give what `relations` gives: runs out of order or sharing a channel (`relationsDisjoint`), or a multi-component run whose last channel is not a station's last component (`relations` then also yields the channels after it, on a station past the run's last point; the channel count of the runs differs from `expectedChannels`). recordCompleteness keeps its per-channel loop through `channelRelations`, built on it. Identical results: digests of every fold tensor and count, the patch description, compareRelations and the completeness of every record match the previous build on Morgantown (5519 X records, 11.2 M pairs) and on synthetic geometries with multi-component, misaligned multi-component, overlapping and out-of-order, descending and gapped runs, and O records. Tests unchanged. Morgantown, -d:danger --opt:speed -march=x86-64-v3, min of 7, same build for both: preplotFold 535 -> 409 ms (all options 831 -> 763), compareRelations (self) 2259 -> 1900 ms, recordCompleteness of all 5519 records 2770 -> 2615 ms, describePatches 1706 -> 1717 ms (unchanged: its time is elsewhere). The plan's 2.5-4x came from a prototype that computed neither offsets nor bearings; with them, the pair work (station lookups, binAt, hypot, addToBin) is now about two thirds of preplotFold's instructions (callgrind), the station keys of the runs a fifth. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`sameInterval(dtMs, planDtMs)`, equal within a relative 1e-9, replaces the expression `abs(a - b) > 1e-9 * b` written out at fourteen sites: the pipeline, spectra, FFT and IIR filters, gain and gain curves, first-break picking, slicing, correlation (block and pilot), pilots and record stacks (addRecord, merge). Same test at every site (the operands are all validated finite and positive, so the negated form agrees for every value that reaches them). Listed in docs/api.md. StackAccumulator.merge still compares dtMs and startMs exactly: not a copy of this test, and left as it is. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eleven more kernels must hold packed instructions in the release and the danger build: the accumulator merge (mergeInto), the statics shift's interior (lerpInto, cubicInto), amplitude QC (sumAndSquares, extremes, countBeyond, spikeCount), the vertical and diversity record stacks (addVertical, addWeighted), correlation's per-bin multiply (mulKernel) and the pilot resampler's dot product (dot). Each passes, and each fails when the kernels are built with -fno-tree-vectorize -fno-tree-slp-vectorize. The correlation calls live in tests/utils/veccorrelate.nim: a correlation plan transforms its pilot with the one-trace FFT, which is scalar by design, and its instance would otherwise be checked with the lanes FFT instances of veckernels. Left out, scalar: clipRuns and the diversity window powers (serial by design), and stack.normalize, whose comment said it vectorizes. GCC branches on a fold of 0 or 1 there (dividing by 1 leaves the sample alone), with max(fold, 1) written either in int32 or in float64: the report says "control flow in loop". It runs once per stack, after the stacking, so the comment now says so and the loop is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FirstBreakPlan.pickInto filtered its copies `fftLanes` (8) rows per
IIR call, while the IIR runs 24 lanes at a time: two thirds of every
batch were zeros. It now batches `iirLanes` rows (exported from
filter/iir, next to `fftLanes`), and the pool hands pickInto runs of
whole multiples of 24 rows (RowQueue.reset takes the batch size;
the other jobs keep runs of whole FFT batches). A plan's workspace
holds 24 copies instead of 8 (`plan.workspaceSize`).
Same picks bit for bit (digest of time, column, SNR and confidence of
every pick, block and pool forms). 2400 x 2000 f32 at 2 ms, 5-60 Hz
band-pass, guided window, every 13th row dead, every 17th shorter;
-d:danger --opt:speed -march=x86-64-v3, min of 15, ms, before -> after:
STA/LTA energy ratio Coppens
block, 1 thread 6.26 -> 3.59 5.60 -> 3.18 29.77 -> 17.69
pool, 1 worker 6.55 -> 3.75 5.92 -> 3.27 30.93 -> 18.09
pool, 4 1.70 -> 0.99 1.57 -> 0.88 7.98 -> 4.65
pool, 8 0.93 -> 0.54 0.81 -> 0.46 4.23 -> 2.48
pool, 16 0.61 -> 0.30 0.47 -> 0.31 2.86 -> 1.51
The pool's runs alone: with 24-row batches but runs of 8-multiples
(32 rows here), the pool was 15-20 % slower than with runs of 24
(e.g. STA/LTA, 8 workers: 0.67 against 0.51 ms).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`nim bench` on 2026-11-13 (Ryzen 9 3950X, Nim 2.4.0, gcc 12.2.0,
-d:danger --opt:speed --debuginfo:on --linedir:on -march=x86-64-v3, after
the load average fell below 1, nothing else running). bench/README.md:
current tables replaced (memory, FFT, long records, filters, gain, AGC,
pool) and a column added where a section records how a kernel got faster
(pre-stack, guided picking, QC and vibroseis); a new brute-stack section.
docs/integration.md, docs/guide/{gain,pipelines}.md and README.md quote
the new costs.
Main changes against the recorded tables: FFT 2048 x 2000 fwd+inv 11.4 ->
4.61 ms (12.1); 65536 points now cost what 60000 do (56.5 against 54.2 us
per transform; 233 against 74 before); band-pass panel 23.6 -> 11.9 ms on
one thread, 6.2 -> 3.15 ms on 4 workers; IIR 25.0 -> 10.8 ms; AGC
6.3/6.7/6.7 -> 4.5/5.1/6.8 ms; viewer flow (demean + band-pass + AGC)
32.2 -> 18.7 ms on one thread, 8.6 -> 5.1 ms on 4, 4.3 -> 2.9 ms on 8;
NMO linear 17.5 -> 7.6 ms; guided picks with a band-pass
5.84/5.21/28.1 -> 3.29/2.89/16.0 ms.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-ups to 0.3.0, on parseSEG 0.10.0 (the lock is unchanged). No breaking change. Two new exported symbols:
sameIntervalandiirLanes.survey/relwalk.nim, internal):preplotFold,describePatches,compareRelationsandrecordCompletenesswalk parseSEG'srelationRunsstation by station. For records where the runs would not give exactly whatrelationsgives (runs that overlap or are out of order, or a multi-component run that ends partway through a station), they fall back torelations. Results are identical: digests of every output match the previous build on Morgantown and on synthetic edge cases. Morgantown, min of 7:preplotFold535 → 409 ms,compareRelations2259 → 1900 ms, completeness of 5519 records 2770 → 2615 ms.describePatchesis unchanged (its time goes elsewhere).sameInterval(dtMs, planDtMs)incore/typesreplaces the relative 1e-9 interval test that was written out at 14 sites.tests/tvectorized.nimnow checks 11 more kernels from QC, statics, stack and vibroseis in release and danger builds. Each passes, and each fails when built scalar.stack.normalizedoesn't vectorize, against what its comment said (GCC adds a branch). It runs once per stack, so only the comment changed.iirLanes), up from 8, and the pool hands out runs of whole batches. The picks are the same bit for bit. 2400 × 2000 f32, one thread: 6.26 / 5.60 / 29.77 → 3.59 / 3.18 / 17.69 ms (STA/LTA, energy ratio, Coppens). The pool gains the same at 1 to 16 workers.nim benchrun on a quiet machine.bench/README.md,docs/integration.md, the guides and README now quote it.Local:
nim test,nim testRelease,nim asan,nim docsand the nimpretty check pass.🤖 Generated with Claude Code