SPB Git

spb/wp40_uqo

Public MIT
4.1 KB · 17 lines latex
1\section{Metal execution and precision strategy}2\label{sec:metal}34\paragraph{The constraint.} Apple GPUs and the Metal Shading Language have no 64-bit floating-point type; a kernel declaring a \texttt{double} does not compile (``\texttt{'double' is not supported in Metal}''). Econometric accumulators---sums of $4\times10^5$ squared returns of magnitude $10^{-6}$, Gram matrices $X'X$ with regressors of very different scales, log-likelihoods summed over thousands of observations---lose several digits in naive FP32. The strategy has four parts.56\paragraph{1. Double-float accumulation.} Every accumulator on the GPU is a pair $(h, \ell)$ of \texttt{float}s representing $h+\ell$ with $|\ell|\le\frac12\,\mathrm{ulp}(h)$. Additions use the error-free transformation TwoSum \citep{Dekker1971,Neumaier1974}: $s = h + v$, $e = (h - (s - (s - h))) + (v - (s - h))$, followed by a renormalisation. The pair carries about 48 significant bits; the error analysis of \citet{Higham1993} gives a bound of order $n\,u^2$ rather than $n\,u$ for a sum of $n$ terms with unit roundoff $u$. The Metal compiler must not reassociate: the kernels are compiled with \texttt{-fno-fast-math} offline and with \texttt{fastMathEnabled = NO} at runtime. Per-element inputs are still rounded to FP32 on the way in; for a sum of squares of $M$ independent returns this input rounding contributes a relative error of order $2u\sqrt{3/M}$, i.e. about $10^{-8}$ for $M = 390$, which is what we observe (Section~\ref{sec:correct}).78\paragraph{2. Chunked partial sums combined in FP64.} A segment longer than the chunk length (4\,096 elements by default, a \texttt{PrecisionPolicy} parameter) is split into chunks; one threadgroup of 256 threads reduces each chunk with a fixed-order tree reduction of double-float values and writes a \texttt{float2}; the host adds the chunks in FP64 in a fixed order and adds the chunk-boundary cross terms ($|r_j||r_{j-1}|$ across a boundary) in FP64. The combination order is deterministic, so results are bitwise reproducible across runs for a given chunk length and threadgroup width (verified in Section~\ref{sec:correct}).910\paragraph{3. Mixed precision by design.} Quantities that are cheap and precision-critical stay in FP64 on the CPU: the finite-sample constants, the initial variance of a GARCH recursion, the Student-$t$ density constants (Metal has no \texttt{lgamma}), the regression solve from the GPU-accumulated sufficient statistics, and all inference. The batched GARCH kernel scales each series to unit variance on the host (FP64) and un-scales the likelihood by $n\log s$, which conditions the FP32 recursion for returns of magnitude $10^{-2}$.1112\paragraph{4. Kernel fusion.} The realized kernel computes the five accumulators of \eqref{eq:rv}--\eqref{eq:rq} in a single pass over the data; the four-kernel variant exists only for the ablation. Regression statistics accumulate the upper triangle of $X'X$, $X'y$ and $y'y$ ($k\le 8$) in registers. The GARCH kernel runs one recursion per thread for one (series, parameter vector) pair---the parallelism comes from the number of parameter vectors, not from the recursion.1314\paragraph{Host side.} The backend owns one device, one command queue, one library and one pipeline cache per process; buffers come from a pool keyed by power-of-two size class in shared storage (unified memory). The shader library is loaded from a prebuilt \texttt{.metallib} when present and compiled from the embedded MSL source otherwise; both paths are measured. GPU time is read from the command buffer's \texttt{GPUStartTime}/\texttt{GPUEndTime}; wall-clock includes FP64$\to$FP32 conversion into the shared buffer, encoding, commit and completion. Metal does not expose the GPU core count; the manifest records it from \texttt{system\_profiler}.1516\paragraph{What the GPU does not do.} Optimisation drivers (BFGS line searches) run on the CPU; the GPU evaluates batches of likelihoods. Rolling sums use a direct $O(w)$-per-output kernel, which the experiments show to be slower than the CPU's $O(1)$ running sum---a limitation we report rather than hide. Nothing in the Metal path is a new estimator.17
Files · v0.1.0-wp40
Menu

Theme