d91fc7ca3d8d0205cea18e57e2e75bbf49968481
1610
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d91fc7ca3d |
Merge mr-gpumem (51706641f) into rc175: RESULT-CHANGING (owner approved, float rounding): molecular replacement's transform FFT on the GPU wherever it fits the search's budget
4nwv molecular replacement 31.7 -> 20.1 s; outputs identical on myob, cytochrome C and 4nwv on the RTX 5080. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
323df1561e |
Merge mr-gpumem (011b98838) into rc175: molecular replacement plans its GPU parts once per merge on model validation's budget (one rigid-body pool for every fit, the transform cropped to the indices it is read at, the pool trimmed at each stage), output unchanged
4nwv MR peak 13.77 -> 8.74 GB on the RTX 5080; myob, cytc and 4nwv outputs identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
51706641fa |
RESULT-CHANGING: molecular replacement's transform FFT on the GPU wherever it fits the search's budget
The molecular transform's FFT went to the GPU only where its buffers took at most a quarter of the card (MapToFPhiGPUFits), the last quarter rule left in molecular replacement. On a large cell that is never: 4nwv's 768^3 box needs 5.45 GB, so on a 16 GB card it ran on the CPU in FFTW, single-threaded - 12.5 s of the search's 31 s. Now it is judged, as every other part of the search, against the search's budget (80% of the card less what is resident; the search holds nothing else yet when it runs), and the device writes only the cropped transform the search keeps (CropHalfL, moved to ModelFFT), so it needs 4.46 GB instead of 5.45. cuFFT and FFTW agree to float rounding, not bit for bit, so wherever the transform moves to the GPU the search's functions can differ in their last bits: on 4nwv on 16 GB and 8.55 GB cards it moves (it now does on any card above about 5.6 GB, before above 21.8 GB); the small boxes were on the GPU before and give the same values (the same kernel, cropped). Measured on the RTX 5080, timing benchmark: 4nwv's transform 14.1 -> 2.2 s, MR 31.6 -> 20.1 s, run 93.0 -> 89.2 s; MR's peak device memory unchanged at 8.7 GB (the FFT's own 5.2 GB comes before anything else is held). On this card the reflection files, maps, placed models, reports and the MR candidate lines of myob, cytc and 4nwv still came out byte-identical to rc175-metal-merge. [MolecularReplacement] passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
011b98838e |
Molecular replacement: one GPU plan per merge on model validation's budget, the transform cropped, output unchanged
What molecular replacement put on its GPU was decided part by part on a quarter of the card each: every group's rigid-body pool (up to three engines), every null's (up to nine), the score engines' cache, the --mr hand check's structure factors. The groups and the nulls run side by side, so the quarters added up: on 4nwv on a 16 GB card the search held 4 rigid-body engines of 1.88 GB, two score engines of 1.64 GB, the 1.82 GB molecular transform, two translation functions' 1.2 GB and the 2.4 GB the allocation pool kept from the validation before - 13.8 GB at its peak, 83% of the card. On an 8.55 GB card that pages. Now each merge's search is planned once, before it starts, on the budget model validation uses (ModelGPUBudget: 80% of the card's total, less what a merge engine still at work holds): the transform, one rigid-body engine and the largest score engine take their place in that order where they still fit, more rigid-body engines only within half of the budget, and what is left is a room the score engines (least recently used given up first, as before) and the rotation and translation functions' working buffers share, each waiting for the other to finish rather than spilling past it (PlanMolecularReplacementGPU). A part that does not fit runs on the CPU, decided on its size alone. - One rigid-body pool per merge serves every fit of the merge - the groups' first and further copies, the nulls, the tNCS shifts, the carried copies - sized for the largest (the most copies Matthews allows, in any group) and reserved once, instead of a pool made and freed for each. RigidBodyGPUPool::Cover widens a planned pool to another model or group; its zones are kept by group, atom count and resolution. RigidBodyGPUPool::Create (the quarter rule) is gone. - The sizes are worked out on the CPU while the transform is computed. - The molecular transform keeps only the indices it is read at (|k|, l <= box / d_min + 1): 0.84 GB instead of 1.82 on 4nwv, host and device. Its rows keep their full length: cut short too, the rotation function read them 15% slower. - The translation function's prepared setup is kept on the host and uploaded by each call, so the device holds it only while a function runs; the cross-term offsets are uploaded only where there are cross terms. - The allocation pool is trimmed before the search, after the transform's GPU FFT, before a score engine is made and before the hand check, whose structure factors are now judged against the budget. - rugnux passes the merge engine's bytes, where the finalist ledger keeps it, to the search, the hand check and the validation of the placed model. Measured on the RTX 5080 (16.6 GB), timing benchmark: peak device memory during MR 13.8 -> 8.7 GB on 4nwv (start 3.0 -> 0.66 GB after the trim), 1.67 -> 1.14 GB on cytc, 6.3 -> 0.76 GB on myob. On 4nwv the plan holds the transform 0.84 GB, one rigid-body engine of 2.10 GB and leaves 10.35 GB of a 13.29 GB budget to the score engines and the functions; a second engine would pass half of the budget (one engine against two: +1.2 s on the rescoring and the null). MR 31.7 -> 31.6 s on 4nwv. Reflection files, maps, placed models, reports and the MR candidate lines byte-identical to rc175-metal-merge on myob, cytc and 4nwv; [MolecularReplacement], [ModelValidation], RigidBody*, ModelScale*, [CUDAMemHelpers] pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d24d328e7b |
Merge gpumem-run into rc175: FFT indexers released (and the allocation pools trimmed) right after the last indexing of a pass; probe passes give their memory back when they end; on a card below 12 GB the speculative probe takes turns with the merge, output unchanged
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2091c0524a |
GPU memory: a probe pass hands its memory to the card when it ends
The speculative geometry probe and the rotation-scale walk's indexing probes gave their indexers' and image workers' buffers back to the allocation pool only, which kept them reserved under the main line's merge and analyses: 5.5 GB on 8qaw and 5.3 GB on 4nwv on the RTX 5080, until the end of the run. The pool is trimmed (every card: cuda_trim_allocation_pools) when such a probe ends, as IndexerThreadPool::ReleaseIndexers now does through the same helper. Measured (RTX 5080): device memory held at the end of the final merge 8.7 -> 3.4 GB (4nwv), 14.5 -> 7.7 GB (8qaw). Output unchanged: p.hkl byte-identical on cytc_x10sa, myob_x10sa, 4nwv and 8qaw, on this card and with its total read as 8.55 GB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
eb4c1d373d |
Merge scale-footprint round 3 into rc175: each partial's frame derived from the frame CSR, on_ice and clipped in one flags byte, estimate re-fitted to 51 B per observation + 98 B per distinct hkl, output unchanged
8qaw's scaling engine peak 8.16 -> 7.54 GB (12.5 GB before round 1); p.hkl byte-identical on 15 battery sets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fd1fb3e25e |
Rotation scaling on the GPU: a partial's frame from the frame CSR, its two flag bytes in one, output unchanged
- The partials lie in frame order, so a partial's frame is the last frame starting at or before it in the frame CSR (FrameOf, a binary search) and is no longer stored: UpdateCorr, SmoothCorr (which takes the fulls' stored frames through the same FrameOf), FilterFrame, the combine, and the ingest's flux, delta_phi and partiality kernels. 4 B less per observation. - on_ice and clipped/overloaded share one flags byte (on ice at bit 0, the host's OBS_CLIPPED / OBS_OVERLOADED one bit up); a full's on_ice byte is 0/1, so the kernels shared by the two read either alike. 1 B less. Measured on an RTX 5080, largest engine of each set, round 2 -> round 3, MB: set obs/hkl ingest peak (B/refl) post-decision peak 4nwv 32.7 M/15.4 M 2336 (72) -> 2172 (67) 3625 -> 3461 8qaw 122.7 M/ 8.6 M 7421 (61) -> 6808 (56) 8156 -> 7543 9v16 54.7 M/ 5.7 M 3419 (63) -> 3146 (58) 3774 -> 3500 7qij 78.1 M/ 2.2 M 4707 (60) -> 4317 (55) 4707 -> 4317 8sa8 50.0 M/ 5.0 M 3134 (63) -> 2884 (58) 3603 -> 3353 Kernel time on 8qaw (nsys, all calls): UpdateCorr 364 -> 365 ms, SmoothCorr 143 -> 112 ms, combine 477 -> 476 ms, ingest partiality/delta_phi/flux 113 -> 109 ms - the search costs nothing measurable, the saved reads pay for it. GPUScalingPeakBytes refitted: 56 + 99 -> 51 B/obs + 98 B/hkl, within 10%. DeviceBytes: 58 -> 53 B per observation, ingest 60 -> 55 B per reflection. p.hkl byte-identical to the rc175 baseline on 15 battery sets (4nwv, 8qaw, 9v16, 7qij, 8sa8, 11if, 5reo, 6oel, 9jzo, 9min, metformin, lyso_x06da_ref, thau_bl1a_3p8keV, insu_I_x06da_5keV_2, myob_x06da); compare shows no change. [RotationScale] and ErrorModel_DeviceFitIsTheHostFit pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1ebb28e3ab |
Merge cytc-mr into rc175: molecular replacement decides an R-free tie between groups with as many copies on every reflection (paired, 3 standard errors), else UNDECIDED as before
Cytochrome C from its sequence-exact AlphaFold model now places in P 32 2 1; MR replay survey of 193 sets: UNDECIDED 7 -> 4, all three newly decided correctly, no wrong decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
6cdc063b4c |
Molecular replacement: an R-free tie between groups with as many copies decided on every reflection
Two space groups of a merge whose placements are within R_FREE_MARGIN (0.03) of each other in R-free left the choice UNDECIDED. Where both placed the same number of copies they have the same parameters, so the working reflections compare them as fairly as the free ones, and there are about twenty times as many: the other group is now ruled out where the chosen placement's |F_obs - F_calc| is lower by 3 standard errors of the paired per-reflection difference over all reflections to the scoring limit. Groups with different copy counts, and the tNCS carry rule, are unchanged. Found on the timing benchmark's cytochrome C set started from the bovine AlphaFold model (the sequence-exact one): three copies placed in both P 32 2 1 (R-free 0.427) and P 31 2 1 (0.437), so MR_DECISION was UNDECIDED. Not a regression: the 2026-10-11 tNCS work ran this set with the horse model, whose first copy did not place in P 31 2 1 at all, so P 32 2 1 was chosen with no tie (still so at rc175 HEAD). With the 380 free reflections at 3 A the two hands differ by 0.010 +- 0.012 in R-free; over all 7285 reflections by 0.029 at 11 standard errors. Now ENANTIOMORPH P 32 2 1, 3 copies, placement CC 0.744. MR replay survey of 193 sets (AlphaFold models): multi-copy UNDECIDED 7 -> 4, all three now correct (7q6j P 21 21 21; both cytochrome C x06da sets P 32 2 1); one PAE-domain case (8tha) breaks its whole- model hand tie towards the deposited group but stays UNDECIDED by the domain rule; no other set changes, no wrong decision. Every tie the rule decided did so at 8.5-12.4 standard errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8f722227e8 |
Merge rc175 (bd7464d70) into gpumem-run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1c3a2e202c |
GPU memory over the run: FFT indexers given back after the last indexing; speculative probe takes turns with the merge on a small card
- IndexerThreadPool::ReleaseIndexers(): each worker drops the indexers it has built (once its current frame is done) and the allocation pool is trimmed, so their memory goes back to the card, not only to the pool. A later frame builds them again, as on first use. A rotation pass calls it once its first pass is done and again when the leftover-lattice census - the last of its indexing - ends. Measured on the RTX 5080: the 1.24 GB (pre-pass) / 0.62 GB (later passes) the pass's pool held through the image pass and the scaling is gone; 4nwv's pre-pass image pass peaks 5.97 instead of 7.18 GB of device memory. - GPUMerge: the main line holds one through ScaleMergeAndSymmetry. The speculative geometry probe (GPUWorkBeside(after_merges=true)) waits for it on a card below the take-turns size (12 GB), where the probe's FFT indexers and image workers beside the merge's arrays would overfill the card - on a Windows (WDDM) card that does not fail an allocation but pages it and crawls. The merge waits for nothing, so nothing the merge waits on (the rotation-scale walk's probes) can wait in a circle with it. No change on a 16 GB card. Output unchanged: p.hkl byte-identical on cytc_x10sa, myob_x10sa, 4nwv and 8qaw on this card; also identical with the card's total read as 8.55 GB (10 / 9 image workers instead of 16) and with 4 image workers, so the worker count does not change the result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
bd7464d705 |
Merge scale-footprint round 2 into rc175: two-pass scaling ingest with the GPU/CPU decision before the card is touched, px/py and h,k,l kept on the host, estimate re-fitted to 56 B per observation + 99 B per distinct hkl, output unchanged
8qaw's scaling engine peak 10.76 -> 8.16 GB; p.hkl byte-identical on 15 battery sets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f46dc303a3 |
Rotation scaling on the GPU: two-pass ingest, decided before the card is touched, output unchanged
- The resident ingest reads the reflections twice: first only what the sort
and the cut need (frame position, resolution, background, raw-hkl key),
then - once the GPU/CPU decision has been made on the exact counts - the
observations the cut kept, written straight to their place. The
observation arrays and the sort buffers are never on the card together,
and no observation field is cut (held twice) any more.
- A set too large even for that sort scales on the CPU before anything is
allocated on the card (ScaleOnCPUWhereSortTooLarge, same 80%-of-total rule).
- The predicted detector position never goes to the card: it is taken on the
host, and the combine emits the index of each full's peak partial instead
of its px/py (8 B less per observation and 4 per full).
- A full carries its raw-hkl run index instead of h, k, l (8 B less per
full); the constant-1 partiality array of the fulls is gone.
- The fulls' CSR sorts and the error-model rank sort run on cub::DoubleBuffer.
Measured with per-array device accounting on an RTX 5080, largest engine of
each set, before (
|
||
|
|
d7d138fd25 | Merge rc175 into scale-footprint | ||
|
|
9d8b06525f |
Merge rc175-metal-integration (bd27d802b) into rc175: CPU fulls scaling loop on a working copy, combine prefetches, output unchanged
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # image_analysis/scale_merge/RotationScaleMerge.cpp |
||
|
|
36062a55f1 |
Merge mv-gpu-budget into rc175: model validation plans its GPU parts against one budget, 80% of the card's total, after trimming the allocation pool and releasing the FFT indexers; extra engines only within half of it
On the RTX 5080 nothing moves between GPU and CPU and the output is byte-identical; on cards below about 9-10 GB parts that used to fall back to the CPU now stay on the GPU. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
640b2e464a |
Merge scale-footprint into rc175: rotation scaling's GPU peak cut (allocation pool trimmed before scaling, arrays freed at last use, ingest sorts without cub's extra copies), estimate re-fitted to 63 B per observation + 115 B per distinct hkl, output unchanged
p.hkl byte-identical on the RTX 5080 for 4nwv, lysozyme, cytochrome C, myoglobin, 8qaw and 9v16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3373106ae1 |
Model validation: budget counts only what is really held; fewer extra engines
On an 8.55 GB card (WDDM) the validation planned 6.81 GB of a 6.84 GB budget, but the card already
held more than the 20% headroom allowed, and the driver paged GPU memory to system RAM: every
rigid-body fit ran ~5x slower. Measured on 4nwv on a 16 GB card, at the start of model validation
the device held 1.1 GB beyond a fresh context, and on 6oel 2.7 GB:
- the stream-ordered allocation pool's free-but-reserved memory, left by the image passes and the
scaling's pooled buffers (1.07 GB on 4nwv, 2.1 GB on 6oel); the validation's engines are allocated
outside the pool and cannot reuse it;
- the image pass's FFT indexers (IndexerThreadPool), alive for the whole run (0.8 GB on 4nwv,
0.5 GB on 6oel), although nothing indexes after the merge.
Both are now released: the validation trims the pool (cuda_trim_allocation_pool) before it plans,
and rugnux drops the indexer pool once the leftover-lattice census, its last user, has ended, before
the model is validated or searched for. What is left beside the validation is 0.06 GB over a fresh
context on both sets (streams, idle cuFFT plans).
Extra engines are now added only within half of the budget. They change no number and bought little
where measured (4nwv, 16 GB card: 13.6 s with one rigid-body engine, 13.1 s with two, 12.6 s with
five), so the card keeps headroom instead. On 16 GB 4nwv now plans 2 rigid-body and 2 scale-fit
engines, 6.56 GB (measured peak 7.3 GB with the context); on an 8.55 GB card one of each, 4.42 GB.
Reflection files, maps and models byte-identical to rc175 HEAD on 4nwv, 8tyy, 6oel and 3inp.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
1ae834e39c | Merge rc175 into scale-footprint | ||
|
|
c130c79236 |
Rotation scaling on the GPU: smaller device footprint, output unchanged
The scaling engine held far more on the card than any step needed, and the image passes' pooled memory was still reserved when it started. - The image passes' allocation pool is trimmed before the scaling's arrays are allocated (they are not pooled): 4.3-8.8 GB of the 16 GB card was held by others when the scaling started, now 1.5-2.3 GB (context, cuFFT and the run's FFT indexers, which live for the whole run). - A new grouping or combine frees the previous one's fulls, CSRs and merge results before allocating its own; the final merge of a large cell used to hold the P1 search's per-group arrays beside its own. - The partials' group CSR goes at the combine; the arrays only the fulls' scaling and download read (records, zeta, frame CSR, group means, image number, px/py, clipped) go once the fulls are on the host. - Merge buffers live only in the call that needs them: the error-model sums and sample places, the outlier medians, half-sets and CC factors, the R_meas sums; MergeAccum's per-group results go once downloaded (MergeAccumRelease). - The combine's per-run scratch is local to the combine. - Ingest: both radix sorts run on cub::DoubleBuffer (no cub copies of keys and values), the sort outputs are allocated after the raw-hkl key is gathered and freed, the uncut runs and old order go before the observations are cut, and the delta_phi re-solve takes the hkl from its run, so the per-observation 64-bit key no longer outlives the sort. Measured with per-array device accounting on an RTX 5080, engine peak after the GPU/CPU decision (MB, before -> after; largest engine of each set): 4nwv 32.7 M obs, 15.4 M hkl: 7536 -> 4265 8qaw 122.7 M obs, 8.6 M hkl: 11716 -> 9327 (ingest 12533 -> 10756) 9v16 54.7 M obs, 5.7 M hkl: 5831 -> 4283 7qij 78.1 M obs, 2.2 M hkl: 6108 -> 5242 (ingest 7978 -> 6768) 8sa8 50.0 M obs, 5.0 M hkl: 5490 -> 4205 The ingest's own peak went from ~104 to 82-100 bytes per reflection. GPUScalingPeakBytes refitted on fourteen engines of these five sets to the peak after the decision it makes (the ingest has passed by then): 81 B/obs + 291 B/hkl -> 63 + 115, within 12%. DeviceBytes refitted as an upper bound: 67/260/200 -> 66/94/52 per obs/event/hkl (up to 18% over), ingest 103/58 -> 89/56 per reflection/run. With it the all-observation arm now runs beside the first merge on a 16 GB card for 4nwv, 9v16 and 8sa8. p.hkl byte-identical to the rc175 baseline on 15 battery sets (the five above, 11if, 5reo, 6oel, 9jzo, 9min, metformin, lyso_x06da_ref, thau_bl1a_3p8keV, insu_I_x06da_5keV_2, myob_x06da), p.mtz identical apart from the history; battery compare shows no change. [RotationScale] and ErrorModel_DeviceFitIsTheHostFit pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
bd27d802b7 |
RotationScaleMerge: CPU fulls scaling loop on a working copy, combine prefetches, output unchanged
Build Packages / Create release (push) Successful in 18s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 4m53s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 7m37s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 12m1s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 14m35s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 22m23s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m33s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 15m13s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 11m10s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m58s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 15m55s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 15m21s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m20s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m14s
Build Packages / Generate python client (push) Successful in 28s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 20m30s
Build Packages / Build documentation (push) Successful in 51s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 14m3s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 20m46s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 14m33s
Build Packages / Unit tests (push) Successful in 1h26m4s
Build Packages / Validation Battery (push) Failing after 36m1s
The fulls' scaling loop now works as the partials' loop does since
|
||
|
|
b9fd1c8d75 |
Merge timing-bench into rc175: battery.py timing, a three-set benchmark (myoglobin and cytochrome C from AlphaFold DB models, 4nwv from a moved deposited model) placed by molecular replacement, checked and timed per step
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
c28f7683c8 |
Merge rc175-metal-integration into rc175: Metal Bragg integration engine on macOS; CPU profile fit in single precision with a shared exp (result-changing at ulp level on the CPU path only); CPU partial scaling loop reads its working copy in order
The CUDA engine is untouched: on the RTX 5080 p.hkl is byte-identical to rc175 on 4nwv, lysozyme and cytochrome C. Under --no-gpu (lysozyme, cytochrome C, myoglobin) intensities move at the ulp level from the single-precision fit and nothing changes beyond noise in battery compare; wall 44/117/71 s -> 41/105/65 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f99ed0b5ac |
battery.py timing: a three-set benchmark placed by molecular replacement, checked and timed per step
`battery.py timing --rugnux BIN` runs myob_x10sa and cytc_x10sa from their AlphaFold DB predictions (AF-P68082-F1 and AF-P62894-F1, v6, committed verbatim with their predicted aligned error under tools/battery/models/, CC BY 4.0) and 4nwv from its deposited model with strict NCS expanded and moved by a fixed rigid-body transform (30 deg about (0.36, 0.48, 0.80) through the centroid, shift (12, -18, 25) A), made at run time from the site's pdb_cache. Each set runs the battery's own command for its arm, in an ordinary run directory, so the site config, results.json, report, table and compare all apply. A set passes when the battery's own verdict passes, MODEL_PLACEMENT is MR, MR_SPACE_GROUP is the expected group with its hand, R_FREE is under its limit, CC_MODEL_CONFIRMED_TO_D_MIN is not NONE, and the placed model's intensities correlate with the reference model's (|F|^2, shell-normalised, 10-4 A, best over the lattices' changes of basis) at 0.30 or more. That last check is independent of rugnux's scores: correct placements give 0.55 / 0.90 / 0.96; the myoglobin placement turned by 30 deg with rugnux's report unchanged gives 0.035, the unplaced 4nwv start model 0.011, a placement relabelled to the other hand 0.18. Rows carry the checks and the per-step times from the TIMING step lines; the report gets a Timing benchmark section; the run exits 1 on any failure. On the workstation (RTX 5080, rc175 8eacce): myoglobin passes in 10 s (R-free 0.44), 4nwv in 106 s (MR 34 s, R-free 0.315 against 0.297 for the deposited placement). Cytochrome c fails: MR places three copies of the monomer in both P 32 2 1 and P 31 2 1 within 0.03 in R-free and so places neither (MR_DECISION UNDECIDED), where the three-copy reference model decides the hand at once. battery.py now imports fcntl only for the full-run lock, falls back to Popen.kill where there are no process groups, and keeps the binary's extension in the run directory, so a timing run can work on Windows (untried there). Licence and credit: licenses/alphafold-db.txt (from models/LICENSE.txt via COLLECT.sh), a new "Data files in the repository" table in THIRD_PARTY_NOTICES.md, and the AlphaFold DB with Jumper et al. 2021 and Varadi et al. 2022 and 2024 in docs/ACKNOWLEDGEMENT.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
229a432a66 |
RESULT-CHANGING (owner approved, ulp level): Metal profile fit, CPU Gaussian from a shared exp
Build Packages / Create release (push) Successful in 8s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m54s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m49s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 13m58s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 18m10s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m35s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m13s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 24m25s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 25m6s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m48s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 26m15s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m34s
Build Packages / Generate python client (push) Successful in 26s
Build Packages / Build documentation (push) Successful in 1m1s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 21m5s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 23m36s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 24m54s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 22m7s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 25m53s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 28m8s
Build Packages / Unit tests (push) Failing after 3h11m38s
Build Packages / Validation Battery (push) Successful in 33m42s
Pass B of BraggIntegrationEngineCPU is split where a device can take over: per reflection, what the
fit needs is worked out in double (BraggFitSetup), the profile, its readable mass and the reweighted
fit run in single precision (FitProfile -> BraggFitOut), and the error, the summation guard and the
result are finished in double. BraggIntegrationEngineMetal runs the middle as a Metal kernel, one
thread per reflection, summing in the CPU's order (FitOnDevice); the CUDA engine is untouched.
The Gaussian's exp is now BraggExp (BraggExp.h), on the CPU and on the GPU: no GPU exp reproduces the
host's expf, and BraggExp uses only +, -, * and exact power-of-two scaling, so both compile it to the
same bits. Checked on the Apple M6 over every float in [-110, 89] (2.2e9 arguments), with subnormal
products and sums matching too. It is closer to correctly rounded than macOS expf (max 0.53 ulp;
0.2% of arguments below -1 not correctly rounded vs 0.62%). This is the one result change: per
observation |dI|/sigma p99.9 <= 1.7e-6, max 1e-4, 10-30x below what
|
||
|
|
0d25d765cf |
Model validation: one GPU budget for all its parts, 80% of the card's total
Build Packages / Create release (push) Successful in 22s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Failing after 1m31s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 9m12s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 11m39s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 12m39s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 23m36s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m15s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 15m15s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 14m8s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m36s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 17m13s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 17m33s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 22m58s
Build Packages / Generate python client (push) Successful in 28s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 24m10s
Build Packages / Build documentation (push) Successful in 1m9s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 22m10s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 18m23s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 22m59s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 21m53s
Build Packages / Unit tests (push) Successful in 2h5m52s
Build Packages / Validation Battery (push) Successful in 36m32s
What a validation puts on its GPU was decided part by part on fixed fractions of the card: the structure factors to d_min on a quarter, the null's structure factors on whatever of that quarter the first left, the rigid-body engines on another quarter, the scale fits on an eighth. On an 8 GB card that sent the null's structure factors of a 4.4 GB validation to the CPU (and held the rigid body to one engine) although everything the validation holds fits the card with room to spare. Now PlanModelValidationGPU decides all of it at once, before anything is reserved, from the card's total memory: every engine is reserved up front and kept to the end, so their sum is held against one budget, 80% of the card less what a merge engine still at work holds there (the finalist ledger's P1 merge, RotationScaleMerge::DeviceBytes). Each part takes one engine where it still fits, in the order structure factors to d_min, rigid body, the null's structure factors, scale fits; a part that does not fit runs on the CPU. What is left goes to more rigid-body engines (up to one per null replicate plus the real fit) and then more scale-fit engines, which only change how many fits run at once. A second validation may run beside where twice this one's whole GPU plan fits the cards' budgets; it gets this one's bytes as gpu_beside_bytes, which limit its engine counts and never its placement, so its numbers are those of the validation it stands in for. One log line states the placement, the bytes held and the budget. - RigidBodyGPUPool::Plan sizes the pool without engines (EngineBytes), Reserve(n) makes them; Create (Plan + engines on a quarter of the card) stays for molecular replacement, whose own rules, and the --mr hand check's structure factors (ReadModelAnomalousMap, a quarter), are unchanged. - The null's resolution is worked out before the plan, so its engine is decided and reserved with the others instead of after the indexing probe. Placement changes only on smaller cards: with the logged footprints of the open-arm sets, 4nwv's null structure factors move to the GPU below ~9 GB (and its rigid body at 6 GB), 8tyy's structure factors to d_min below ~8.7 GB; on 16 GB and larger nothing moves. On the RTX 5080 (16 GB), 4nwv, 8tyy, 6oel and 3inp give byte-identical reflection files, maps and models to rc175 HEAD, with more rigid-body engines where they fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
4e177bdb21 |
RotationScaleMerge: CPU partial scaling loop reads its working copy in order, output unchanged
The loop's corr now lives in the group CSR's order next to the references (the partials in no group after them), so the group means read both sequentially instead of gathering corr through the permutation, and the corr update walks the same arrays. FitPerFrameG's filters, which do not change over the loop, are applied once into a per-frame ScalingFit list with the reference-independent factors precomputed (FitScalingFrames). ReferenceWeight is inline, and the group means are no longer pre-filled with NaN serially. Same values, same operations in the same order: p.hkl and the merged and unmerged MTZ data are byte-identical on lysozyme, cytochrome C, myoglobin, a small-molecule set and 4nwv. On 4nwv (Apple M6, 12 threads) the partial scaling iterations take 3-4x less time, ~18 s -> ~6 s over 168 iterations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f05e67b2b4 |
Metal Bragg integration engine on macOS, output unchanged (bit-identical to the CPU engine)
Build Packages / Create release (push) Successful in 7s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m16s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 7m41s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 11m24s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 14m56s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 22m55s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m7s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 13m56s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 19m6s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 19m0s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m33s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 17m43s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 20m21s
Build Packages / Generate python client (push) Successful in 31s
Build Packages / Build documentation (push) Successful in 1m25s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 19m20s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 24m18s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 23m34s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 24m21s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 20m7s
Build Packages / Unit tests (push) Successful in 1h22m15s
Build Packages / Validation Battery (push) Successful in 35m52s
BraggIntegrationEngineMetal is BraggIntegrationEngineCPU with its integer pixel work run as Metal kernels, one thread per reflection: the neighbour mask, the owner map, pass A's walk over every box and the background clip. Everything in double, the profile learning and pass B stay on the CPU, in the CPU engine's own code - Apple GPUs have no double, and no GPU exp matches macOS expf bit for bit. The sums are integers, so the GPU's order does not matter; the stencil arithmetic is the same BraggStencil.h, compiled at run time (MSL 3.0, no offline Metal toolchain needed) with fast math off (sqrt and division correctly rounded, measured) and fp contraction off, as the host already builds (-ffp-contract=off, now extended to Objective-C++). The image is read in place (unified memory). The CPU engine is split so both engines share the finishing code: pass A counts into BraggBoxSums (integer; the double ring sums were exact integers already), the clip threshold is its integer floor, FinishPassA and ProfilePasses are shared. Verified byte-identical p.hkl and MTZ data before/after the split and with the Metal engine on lysozyme, cytochrome C, myoglobin, 4nwv and a small-molecule set. Measured on an Apple M6 (wall, CPU engine -> Metal): 4nwv 180.5 -> 151.2 s, cytochrome C 72.7 -> 59.8 s, lysozyme 29.2 -> 22.5 s, myoglobin 43.3 -> 41.2 s; the sparse small-molecule set +1.5 s (few reflections per frame leave the GPU idle). CI: a macOS step runs tests/BraggIntegrationEngineMetalTest.cpp, which requires every float of every reflection and every count to match the CPU engine over 19 setting combinations on random crowded frames (negative pixels, exact-pixel ties, hot, masked and overloaded pixels), three frames per engine; it fails without a Metal device and if the GPU path fell back to the CPU. Ten planted kernel bugs were each caught. rugnux --no-gpu hides the Metal device too (gpus_are_hidden). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
228f0fc00f |
SpotTiles_MatchWholeFrame_GPU: wait for the upload before the squares are cut
Build Packages / Create release (push) Successful in 7s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Failing after 1m18s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 8m39s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 12m27s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 17m23s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 15m5s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 20m8s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m41s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 20m52s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 23m35s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m45s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 16m28s
Build Packages / Generate python client (push) Successful in 28s
Build Packages / Build documentation (push) Successful in 1m6s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 22m46s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 21m12s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 24m56s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 25m25s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 24m47s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 27m16s
Build Packages / Unit tests (push) Successful in 1h52m27s
Build Packages / Validation Battery (push) Failing after 36m29s
cudaMemcpy from pageable memory may return before the copy lands on the card, and ImagePreprocessorBufferGPU gathers its squares on a non-blocking stream that does not wait for the NULL stream, so on a loaded GPU the squares could be cut from the previous frame. Test-only race; the pre-scan's engines synchronise their own streams before the buffer is read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
8eacce02f7 |
Merge unified-nvtx into rc175: NVTX range per timed section and console step; kernels read host buffers in place on unified-memory GPUs (discrete cards unchanged)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # common/CUDAWrapper.cu |
||
|
|
c17002379c |
Merge cufft-cache into rc175: cuFFT plans reused within a rugnux run and destroyed when it ends, output unchanged
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # image_analysis/geom_refinement/BeamCenterFFTGPU.cu |
||
|
|
7f57cfb8d4 |
Merge gpucpu-decide into rc175: GPU or CPU decided up front from the card's total memory, never from what is free
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
3917bb9c79 |
cuFFT plans kept only within a processing run's scope, destroyed when it ends, output unchanged
The plan cache of |
||
|
|
3102221568 |
cuFFT plans kept for the process and lent to one user at a time, output unchanged
Every cuModuleLoadData/Unload in a run is cuFFT making or destroying a plan, and each plan loads
its own kernel modules under a process-wide lock: over a second a plan on a busy GB10, and a PTX
compile per load on Windows. The FFT indexers, rigid-body engines, structure-factor engines,
molecular replacement and beam-centre FFT each made their plans afresh and destroyed them again,
and the sizing functions (rigid-body and structure-factor FFTWorkBytes, beam-centre
DeviceMemoryNeeded via cufftEstimate*) made throwaway plans only to read a work size.
CudaFFTPlan now borrows a plan from a per-process cache keyed by device and full plan shape
(CudaFFTShape: n, embeds, strides, distances, type, batch). A plan is lent to one user at a time
(cuFFT is thread safe only across distinct plans), goes back when its owner is done - after a wait
for the owner's stream - and is never destroyed. Kept plans hold no work area: the user passes its
own, or CudaFFTPlan allocates one from the pool while it is borrowed. The sizing functions read the
work size from the kept plan (CudaFFTPlan::WorkBytes), which the engines then reuse. Plan creation
keeps the NULL-stream wait of
|
||
|
|
e3b33591ca |
GPU: kernels read host buffers in place on unified-memory systems
gpu_direct_host_read() (CUDAWrapper) is true where the device accesses pageable memory through the host's page tables (cudaDevAttrPageableMemoryAccess and ...UsesHostPageTables: GB10, GH200, GB200), asked once per device; JFJOCH_FORCE_DIRECT_HOST_READ forces it on for testing with page-locked inputs. Where it holds: - BSLZ4DecoderGPU: the LZ4/fused kernels and the tail copy read the reader's compressed chunk directly, no pinned staging memcpy and no H2D copy; - ImagePreprocessorGPU: Analyze and the UINT16_WIDENED path hand the host buffer to preprocess_kernel (if aligned to the pixel type), and nothing is page-locked; - RotationScaleMergeGPU::IngestUpload: IngestExtractKernel reads the pinned stage in place, without device staging buffers; the stage is reused only after the kernel has run. Discrete cards take the unchanged path. Every caller synchronises its stream before the host buffer goes away. DirectHostReadGPUTest checks the three sites against the CPU on page-locked inputs, in either mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
fe4db26716 |
rugnux: an NVTX range per timed section and per console step
Every TimingMark ("TIMING <section>") and every rugnux step ("TIMING step ...") now
opens an NVTX v3 range of the same name, so Nsight Systems traces from different
machines can be lined up by pipeline step. Start/end ranges, not push/pop, so a
range may end on another thread and parallel arms may overlap. Header-only NVTX
(CUDA::nvtx3), a no-op without a profiler attached and compiled out without CUDA.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
||
|
|
5de7189643 |
GPU or CPU decided up front from the card's total memory, never from what is free
- Scaling: the 80%-of-card check runs right after the device ingest's sort and cut, where the observation and distinct-hkl counts are first known, instead of after the geometry smoothing; same counts, same decision, but a run that goes to the CPU no longer does the device smoothing (6.9 s on an 8 GB card for a 33 M observation set) or holds its memory meanwhile. - Rigid body: engines budgeted on a quarter of the card's total (the validation's plan), not min(total/4, free - 1 GB). A busy card no longer sends the rigid body to the CPU (measured on an 8 GB card: ~80 s and a different fit); engine allocations wait for GPU work beside the run, and an engine that cannot be set up fails the validation (RigidBodyGPUFailure) instead of falling back to the CPU. - Beam-centre FFT: GPU when its footprint is at most half of the card's total, otherwise CPU, logged; no catch-and-rescore on the CPU after a GPU failure. - FitPerFrameG reserves its per-frame vector (CPU scaling waited on the heap lock on Windows). - get_gpu_free_memory(): cudaMemGetInfo, except on an integrated GPU under Linux, where free also counts MemAvailable less a tenth of the total. Used only where free memory is waited on (cuda_memory_available) or quoted in out-of-memory messages; it decides nothing. The two card-filling [CUDAMemHelpers] tests skip on integrated GPUs. - Out-of-memory messages point at rugnux --no-gpu instead of "the CPU build". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
f96ee13629 |
Merge rc175-mac exact commits into rc175: CPU spot-finder ring histogram value-first; CPU Bragg background clip reuses pass A's ring pixels; integrated reflections relabelled in parallel; tNCS modulation-null searches on several workers (all output unchanged)
|
||
|
|
ba3f754752 |
RESULT-CHANGING (owner approved, ulp level): CPU profile fit in the GPU engine's arithmetic
Build Packages / Create release (push) Successful in 8s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 4m55s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m12s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 12m20s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 22m9s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 7m11s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 10m37s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 13m30s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 15m22s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 14m5s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 18m9s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m7s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 21m10s
Build Packages / Generate python client (push) Successful in 21s
Build Packages / Build documentation (push) Successful in 1m2s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 23m31s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 22m6s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 17m42s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 22m34s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 19m24s
Build Packages / Unit tests (push) Failing after 1h54m39s
Build Packages / Validation Battery (push) Failing after 41m38s
Pass B of BraggIntegrationEngineCPU now does what BraggIntegrationEngineGPU's fit does: profiles in float, the Gaussian from expf with the widths' reciprocals taken once and normalised by a reciprocal, and the reweighted fit in float with one reciprocal of the variance for its three sums (the GPU's __frcp_rn). Per-reflection geometry and the final sigma stay in double. The logic was already the same on both; the CPU now differs from the GPU only in summation order. Measured (CPU-only, Apple M6): Pass B loops 1.2x faster on P cores; cytochrome C 1.9%, myoglobin 1.5% faster end to end, 4nwv integration steps 3%. Intensities move by ~1e-6 relative; merged statistics in the fourth digit (error model b 1.3259e-3 -> 1.3258e-3, R_work 0.2440 -> 0.2439). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
d1f4c86298 |
tNCS: the modulation null's searches on several workers, output unchanged
The 20 shuffled copies are drawn in order from the one generator as before, then each greedy search runs on a worker of its own and reads only its copy, so the nulls are the serial loop's bit for bit. Measured on 4nwv (CPU-only): the analysis was ~3.9 s on the main thread, most of it these searches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ec02b181db |
rugnux: relabel the integrated reflections in parallel, output unchanged
reseat_integrated changed the basis of every integrated reflection on the main thread. One image per task now; each touches only its own outcome. Measured on 4nwv (CPU-only): 2.1 s of serial time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1c748ba41e |
BraggIntegrationEngineCPU: background clip reads the ring pixels pass A gathered, output unchanged
The one-pass sigma clip of the background ring walked the reflection's whole box a second time, recomputing every pixel's stencil distances and neighbour mask. Pass A now keeps the ring pixels the clip reads (readable, not a neighbour's flux), with their radial offset, in pixel order, and the clip sums those - the same values in the same order. Measured on cytochrome C (CPU-only, Apple M6): the clip loop was 8.4% of CPU; the run is 4-5% faster with this and the ring-histogram change together. Merged reflections and maps byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
93958cfdc7 |
AdaptiveSpotFinderCPU: ring histogram indexed [value][ring], output unchanged
The per-ring value histogram of the plain ring pass was laid out [ring][value], so the counters of neighbouring pixels - neighbouring rings, low values - lay 4 KB apart and fell in the same few L1 sets, evicting each other on every pixel. Indexed [value][ring] they share a few cache lines. The sigma-clip passes read it value-major; integer sums, so the same totals. Measured on a 16M-pixel frame (microbenchmark of AccumulateRingsBlock, Apple M6): 0.97 -> 0.80 ns/pixel on a P core, 5.3 -> 3.7 on an E core. The function was 9-38% of CPU on the battery sets run CPU-only; one small-molecule set ran 4% faster end to end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
212fa457d6 |
CI macOS: hardened-runtime checks read codesign's output from a file
Build Packages / Create release (push) Successful in 6s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 5m21s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 9m16s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 14m0s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 17m35s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m32s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 24m40s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 16m39s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 27m12s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m33s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 13m50s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 17m0s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 22m28s
Build Packages / Generate python client (push) Successful in 20s
Build Packages / Build documentation (push) Successful in 1m2s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 23m57s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 23m9s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 18m19s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 24m24s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 20m59s
Build Packages / Unit tests (push) Failing after 2h0m28s
Build Packages / Validation Battery (push) Successful in 52m44s
The viewer-bundle and rugnux-tarball checks piped `codesign -d` into `grep -q`. grep exits at the first match, codesign then dies of SIGPIPE (141), and under `set -o pipefail` that is the pipeline's status, so a correctly signed bundle was reported as "no hardened runtime". Both checks now write to a file and grep it, as the other checks in this workflow do, and print the signature when they fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
76adf3f0fa |
Merge origin/rc175 (macOS signing and notarization) into rc175
Build Packages / Create release (push) Successful in 8s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m53s
Build Packages / build:portable:macos-arm64:nocuda (push) Failing after 10m37s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 14m38s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 19m15s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 19m49s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m41s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 23m5s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 23m47s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m48s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m39s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 28m52s
Build Packages / Generate python client (push) Successful in 26s
Build Packages / Build documentation (push) Successful in 1m0s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 20m25s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 17m44s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 21m46s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 23m32s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 22m48s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m46s
Build Packages / Unit tests (push) Successful in 1h37m57s
Build Packages / Validation Battery (push) Successful in 37m52s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
082781490a |
Merge stillsint into rc175: the stills pre-scan masks pixels holding the error value and dead pixels (no false overloads; +4% observations at high resolution)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
3f25bbf003 |
Merge fftpeak exact commits into rc175: GPU peak search four threads per direction; CudaFFTPlan waits for cuFFT's NULL-stream plan setup (latent race)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
90ba15871f |
CudaFFTPlan: wait for the plan's NULL-stream setup before it is used, output unchanged
A transform launched on a non-blocking stream straight after cufftPlanMany could read the plan before its setup, still queued on the NULL stream, had finished: Xid 31, a read at a fixed near-null address, "an illegal memory access" in the indexer threads. It showed at transform length 3072, in 3 of 4 runs of one rotation set where a pool built its FFT indexers at the start of integration (6 of 28 ci-tier sets, 9 of 25 null-model runs). It went away under CUDA_LAUNCH_BLOCKING=1 and with a cudaStreamSynchronize(NULL) after the plan (0 of 11 runs). The 3142 length the indexer used so far never hit it, but nothing ordered it either. Plans are built once per indexer, so the wait costs nothing measurable. The other cuFFT users (beam-centre FFT, model structure factors, rigid body) create raw plans and are not covered by this wrapper. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
eb53b11b88 |
Merge stillsmerge into rc175: stills crystals indexed in a lattice containing the run's are relabelled onto its cell; unmerged MTZ only for crystals on the run's cell; French-Wilson on the merge's workers
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |