[Rd] R 4.5.3 macOS arm64: severe matrix-product performance regression vs R 4.5.2 due to libRblas.dylib selecting libRblas.0.dylib instead of libRblas.vecLib.dylib

Ben Bolker bbo|ker @end|ng |rom gm@||@com
Fri Mar 27 00:56:56 CET 2026


   Would the RhpcBLASctl 
<https://CRAN.R-project.org/package=RhpcBLASctl> package work on MacOS 
as a workaround/diagnostic tool?


On 2026-03-26 7:48 p.m., Jeffrey Racine wrote:
> Greetings,
> 
> I am reporting a substantial performance regression on macOS arm64 when
> moving from `R 4.5.2` to `R 4.5.3`.
> 
> This first appeared while benchmarking the `np` package, where a
> conditional-density least-squares cross-validation route (`npcdensbw(...,
> bwmethod="cv.ls")`) became roughly 5x slower under `R 4.5.3`. After
> investigation, the package itself appears not to be at fault: the
> regression can be reproduced directly with base matrix-product operations
> and seems to be caused by a change in which BLAS library `R 4.5.3` uses on
> macOS arm64.
> 
> ### System
> 
> - Hardware: Apple Silicon (`aarch64`)
> - OS: macOS Tahoe 26.4
> - `R 4.5.2`: `R version 4.5.2 (2025-10-31)`
> - `R 4.5.3`: `R version 4.5.3 (2026-03-11)`
> 
> ### Summary of findings
> 
> Using the official macOS arm64 installers:
> 
> - `R-4.5.2-arm64.pkg`
> - `R-4.5.3-arm64.pkg`
> 
> I unpacked both installers and compared their framework payloads.
> 
> Key visible result:
> 
> - In `R 4.5.2`, `Resources/lib/libRblas.dylib` points to
> `libRblas.vecLib.dylib`
> - In `R 4.5.3`, `Resources/lib/libRblas.dylib` points to `libRblas.0.dylib`
> 
> Both payloads still contain both files:
> 
> - `libRblas.0.dylib`
> - `libRblas.vecLib.dylib`
> 
> ### Payload evidence
> 
> `R 4.5.2` unpacked payload:
> 
> ```text
> lrwxr-xr-x ... libRblas.dylib -> libRblas.vecLib.dylib
> -rwxr-xr-x ... libRblas.0.dylib
> -rwxr-xr-x ... libRblas.vecLib.dylib
> ```
> 
> `R 4.5.3` unpacked payload:
> 
> ```text
> lrwxr-xr-x ... libRblas.dylib -> libRblas.0.dylib
> -rwxr-xr-x ... libRblas.0.dylib
> -rwxr-xr-x ... libRblas.vecLib.dylib
> ```
> 
> Additional payload comparison:
> 
> - `Makeconf`, `ldpaths`, `Renviron`, `bin/R`, and installer scripts were
> byte-identical between `4.5.2` and `4.5.3`
> - the executable `__text` sections of `libRblas.0.dylib` and
> `libRlapack.dylib` were identical
> - the executable `__text` section of `libR.dylib` differed
> 
> ### How the runtimes were tested
> 
> I ran both R versions directly from the unpacked installer payloads using
> `Resources/bin/exec/R`, with `R_HOME` and `DYLD_LIBRARY_PATH` pointed at
> each unpacked framework. This avoids relying on the live installed system
> framework.
> 
> Example invocation:
> 
> ```bash
> R_HOME=/tmp/R452_pkg/R-fw.pkg/Payload/R.framework/Versions/4.5-arm64/Resources
> \
> DYLD_LIBRARY_PATH=/tmp/R452_pkg/R-fw.pkg/Payload/R.framework/Versions/4.5-arm64/Resources/lib
> \
> /tmp/R452_pkg/R-fw.pkg/Payload/R.framework/Versions/4.5-arm64/Resources/bin/exec/R
> --vanilla -q -f /tmp/r_blas_probe2.R
> ```
> 
> and similarly for `R 4.5.3`.
> 
> ### Minimal reproducer
> 
> ```r
> set.seed(1)
> n <- 1000000L
> x <- rnorm(n)
> y <- rnorm(n)
> A <- matrix(rnorm(2000L*2000L), 2000L, 2000L)
> B <- matrix(rnorm(2000L*2000L), 2000L, 2000L)
> 
> cat(R.version.string, "\n")
> cat("crossprod vec\n")
> print(system.time(for(i in 1:40) z <- crossprod(x, y)))
> cat("matmult\n")
> print(system.time(C <- A %*% B))
> ```
> 
> ### Observed timings
> 
> `R 4.5.2`:
> 
> - `crossprod()` elapsed about `0.032s`
> - `%*%` elapsed about `0.034s`
> 
> Observed output:
> 
> ```text
> R version 4.5.2 (2025-10-31)
> crossprod vec
> user system elapsed
> 0.031 0.002 0.032
> matmult
> user system elapsed
> 0.058 0.003 0.034
> ```
> 
> `R 4.5.3`:
> 
> - `crossprod()` elapsed about `0.072s`
> - `%*%` elapsed about `2.443s`
> 
> Observed output:
> 
> ```text
> R version 4.5.3 (2026-03-11)
> crossprod vec
> user system elapsed
> 0.071 0.000 0.072
> matmult
> user system elapsed
> 2.381 0.057 2.443
> ```
> 
> This is a very large regression for `%*%` and a clear regression for
> `crossprod()`.
> 
> ### Loaded libraries during runtime
> 
> For the unpacked `R 4.5.2` process, `lsof` showed:
> 
> ```text
> ... /tmp/R452_pkg/.../Resources/lib/libRblas.vecLib.dylib
> ... /tmp/R452_pkg/.../Resources/lib/libR.dylib
> ... /tmp/R452_pkg/.../Resources/lib/libRlapack.dylib
> ```
> 
> `vmmap` also showed that Apple Accelerate / vecLib libraries were mapped.
> 
> For the unpacked `R 4.5.3` process, `lsof` showed:
> 
> ```text
> ... /tmp/R453_pkg/.../Resources/lib/libRblas.0.dylib
> ... /tmp/R453_pkg/.../Resources/lib/libR.dylib
> ... /tmp/R453_pkg/.../Resources/lib/libRlapack.dylib
> ```
> 
> ### Critical confirmation
> 
> In a temporary copy of the unpacked `R 4.5.3` framework, I changed only
> this symlink:
> 
> - from:
> 
> ```text
> libRblas.dylib -> libRblas.0.dylib
> ```
> 
> - to:
> 
> ```text
> libRblas.dylib -> libRblas.vecLib.dylib
> ```
> 
> After that single change, the `R 4.5.3` runtime regained the fast timings:
> 
> ```text
> R version 4.5.3 (2026-03-11)
> crossprod vec
> user system elapsed
> 0.032 0.002 0.033
> matmult
> user system elapsed
> 0.055 0.003 0.032
> ```
> 
> `lsof` then showed:
> 
> ```text
> ... /tmp/R453_test/.../Resources/lib/libRblas.vecLib.dylib
> ... /tmp/R453_test/.../Resources/lib/libR.dylib
> ... /tmp/R453_test/.../Resources/lib/libRlapack.dylib
> ```
> 
> So the regression appears to be directly tied to the BLAS target selected
> by `libRblas.dylib` in the macOS arm64 `R 4.5.3` distribution.
> 
> ### Why this matters
> 
> This caused a large apparent regression in package benchmarks, but the
> package code was not the source. The underlying issue is visible in base
> matrix-product operations.
> 
> For performance-sensitive code relying on repeated dot products or matrix
> multiplies, the effect is substantial.
> 
> One affected package-level example was `np::npcdensbw(..., bwmethod =
> "cv.ls")`,
> whose hot path repeatedly uses BLAS-backed dot products inside
> conditional-density CVLS block computations.
> 
> ### Expected behavior
> 
> I would expect `R 4.5.3` on macOS arm64 not to regress dramatically
> relative to `R 4.5.2` for basic matrix products on the same hardware.
> 
> At minimum, if the BLAS target changed intentionally, I would expect that
> change not to impose such a severe runtime penalty.
> 
> ### Request
> 
> Could you please confirm whether the `libRblas.dylib -> libRblas.0.dylib`
> change in the macOS arm64 `R 4.5.3` installer was intentional?
> 
> If intentional, is there a recommended way to restore the previous fast
> vecLib-backed behavior?
> 
> If not intentional, this appears to be a macOS arm64 packaging/runtime
> regression in `R 4.5.3`.
> 
> I can provide exact command transcripts and additional package-level
> evidence if helpful.
> 
> ## Local investigation notes
> 
> This report was motivated by a package-level timing cliff in `np`, but the
> package code appears exonerated:
> 
> - the relevant `np` hot path remains unchanged in current source
> - the same slowdown occurs across different `np` source snapshots when run
> under `R 4.5.3`
> - the same `np` source and same compiled package are fast again under `R
> 4.5.2`
> 
> The key practical interpretation is:
> 
> - not a package source regression
> - likely an R macOS BLAS-linkage/runtime regression in `4.5.3`
> 
> ## Relevant local files
> 
> - [R-4.5.2-arm64.pkg](/Users/jracine/Development/R-4.5.2-arm64.pkg)
> - [R-4.5.3-arm64.pkg](/Users/jracine/Development/R-4.5.3-arm64.pkg)
> 
> 	[[alternative HTML version deleted]]
> 
> ______________________________________________
> R-devel using r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list