Skip to content

processSEG 0.3.1: relation runs, one interval test, 24-lane picking, fresh benchmarks - #5

Merged
xrfez merged 6 commits into
mainfrom
phase12-followups
Nov 13, 2026
Merged

xrfez merged 6 commits into
mainfrom
phase12-followups

Conversation

@xrfez

@xrfez xrfez commented Nov 13, 2026

Copy link
Copy Markdown
Owner

Follow-ups to 0.3.0, on parseSEG 0.10.0 (the lock is unchanged). No breaking change. Two new exported symbols: sameInterval and iirLanes.

  • Relation walk (survey/relwalk.nim, internal): preplotFold, describePatches, compareRelations and recordCompleteness walk parseSEG's relationRuns station by station. For records where the runs would not give exactly what relations gives (runs that overlap or are out of order, or a multi-component run that ends partway through a station), they fall back to relations. Results are identical: digests of every output match the previous build on Morgantown and on synthetic edge cases. Morgantown, min of 7: preplotFold 535 → 409 ms, compareRelations 2259 → 1900 ms, completeness of 5519 records 2770 → 2615 ms. describePatches is unchanged (its time goes elsewhere).
  • sameInterval(dtMs, planDtMs) in core/types replaces the relative 1e-9 interval test that was written out at 14 sites.
  • tests/tvectorized.nim now checks 11 more kernels from QC, statics, stack and vibroseis in release and danger builds. Each passes, and each fails when built scalar. stack.normalize doesn't vectorize, against what its comment said (GCC adds a branch). It runs once per stack, so only the comment changed.
  • First-break picking: the band-pass runs in batches of the IIR's 24 lanes (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.
  • Benchmarks: a full nim bench run 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 docs and the nimpretty check pass.

🤖 Generated with Claude Code

xrfez and others added 6 commits November 13, 2026 03:41
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>
@xrfez
xrfez merged commit 3eff93a into main Nov 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant