Skip to content

GPU Metal: also run the border-range sorts on the host - #16071

Open
ktf wants to merge 4 commits into
AliceO2Group:devfrom
ktf:pr16071
Open

ktf wants to merge 4 commits into
AliceO2Group:devfrom
ktf:pr16071

Conversation

@ktf

@ktf ktf commented Nov 7, 2026

Copy link
Copy Markdown
Member

The border-range sorts of the track merging between sectors, 360 per
time frame, took 312 ms per event on a 30-collision Pb-Pb time frame on
a single GPU thread. On the host they take about 6 ms, plus 52 ms of
waiting for the streams.

ktf added 4 commits November 7, 2026 07:27
Move the comparators of the TPC merger's sorts, and MergeLooperParam they
sort, from GPUTPCGMMerger.cxx and GPUTPCGMO2Output.cxx into
GPUTPCGMMergerSortComp.h, unchanged. The CUDA and HIP backends see them
because they compile the kernel sources into one unit; a backend that
runs these sorts in host code needs them from a header.
Needs review. On a 30-collision Pb-Pb time frame, 7 of 4,416,506 clusters
differed between the CPU and the Metal backend, each by one step of a
packed width, sigmaTime or sigmaPad. Those widths were all within one
float ulp below a quantisation step: sigma * 32 was 11.4999994,
14.4999992, 29.4999996 or 31.4999988, where the packing rounds at n + 0.5,
so any difference in the last bit decides between n and n + 1.

The CPU build compiles this with -ffast-math. Its arm64 code for
finalize() computes 1 / Q once, the means as products with it, the
variance as one fused multiply-add, fma(SS, 1 / Q, -mean * mean), and an
IEEE sqrt. Metal's fast-math division and sqrt are not correctly rounded.
Do the same operations on Metal explicitly, with precise::divide, fma and
precise::sqrt: the pbpb clusters then match the CPU bit for bit, with no
measurable cost; the rest of the Metal code keeps fast math.

This matches the CPU build that the compiler produces on arm64 with
clang. An x86 build, or another compiler, may choose a different sequence
under -ffast-math. Writing the sequence explicitly for all backends would
make the widths independent of those choices, but can change the CPU
results on some platforms.
The sorts of the merged tracks by quality and by q/pT, of the looper
candidates and of the O2 output tracks, which CUDA and HIP run with
thrust, ran on a single GPU thread otherwise: about 730 ms per event on
a 30-collision Pb-Pb time frame, at up to 140 times the CPU's time. The
GPU memory is shared with the host, so sort there once the stream is
drained, with the std::sort of the CPU backend, which also orders the
elements that compare equal as on the CPU. The number of elements is
read from the device copy of the counters, as the host copy of the O2
output count is still being transferred when the sort is launched.
The border-range sorts of the track merging between sectors, 360 per
time frame, took 312 ms per event on a 30-collision Pb-Pb time frame on
a single GPU thread. On the host they take about 6 ms, plus 52 ms of
waiting for the streams.
@ktf
ktf requested a review from davidrohr as a code owner November 7, 2026 06:42
@davidrohr

Copy link
Copy Markdown
Collaborator

Could you check if this rebases onto #15318? If this will cause merge conflicts, I'd wait with this until the new tracking version is deployed.

@ktf

ktf commented Nov 7, 2026

Copy link
Copy Markdown
Member Author

I can wait. It's only a speedup. The part I care more is #16065 which makes results equal between CPU and GPU (on Apple devices).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants