Fallbacks for BLAS sgemm/dgemm and (parts of) machine_vectors - #2810
Conversation
|
Nice!! If this can help, here is the output of The comparison looks very good overall. There is still some gap for the thin cases, e.g. matrix-vector products, or It seems that some of the shortest measurements (small sizes with 1 thread, or smallish sizes with a few threads) should be taken with a grain of salt. |
|
Agreed, thin cases and matrix-vector products would need dedicated code. Your Icelake timings look fine for a first iteration of the code. Interestingly sgemm stays near 1.0 up to 2048x2048, only degrading slightly at 4096x4096, while dgemm is closer to 2/3 throughout. Hopefully this gap can be closed by just changing some of the parameters. |
|
Timings on Apple M4 (with code before the last commit). Nothing new for |
|
Thanks, that looks very good actually. We could open a followup issue about using the ARMv9 scalable matrix extensions. |
We (using Claude Fable 5 and Claude Opus 5) implement
flint_sgemmandflint_dgemmand make algorithms likenmod_mat_mul_blasavailable unconditionally, obsoleting non-BLAS tuning values.This should make
--with-blasunnecessary (actually, undesirable) for most users. On my Zen3 machine with AVX2,flint_sgemmandflint_dgemmmatch the speed of their OpenBLAS counterparts to within a few % both single-threaded and multi-threaded. Claude also claims that the speed matches OpenBLAS in its AVX512-enabled virtual machine, but someone should verify that, and also on NEON.For the AVX512 variant, this uses the
zextensions ofmachine_vectors.hproposed by @user202729 in #2715. This PR also adds a plain-C fallback formachine_vectors.h. The fallbacks don't cover enough ground to buildfft_smalljust yet, but they allowflint_sgemmandflint_dgemmto work in any environment. On my machine, forcing the plain-Cmachine_vectors.hfallback and letting GCC auto-vectorize results in just ~2x worse performance than the specialized version using AVX2 intrinsics.As noted above, linking to OpenBLAS is undesirable as it uses an OpenMP thread pool rather than FLINT's thread pool so that
flint_set_num_threadsdoes not have the intended effect (and parallel FLINT / BLAS work would compete for resources). At least on my machine, the OpenMP thread pool also adds a ridiculous ~1 second of startup CPU time to FLINT programs that link in OpenBLAS whether BLAS is actually used or not.If FLINT is compiled with
--with-blas, use of BLAS inflint_sgemm/flint_dgemmcan be toggled with a switchflint_gemm_use_blas.Some timings comparisons between
flint_sgemm/dgemm("sgemm/dgemm") and OpenBLAS ("blas_s/blas_d"), excerpted frombuild/machine_vectors/profile/p-gemm:Fortunately, it isn't that hard to match BLAS these days: this is a very standard design with a tiling microkernel.
The most complex part of gemm code is the multithreading. There is a complex version using synchronization, invented by Claude, and a simpler version that just splits the work into independent submatrices. The complex version seems to work and is slightly more efficient, but it's only enabled by default on x86-64 for now pending stress-testing in other environments.