在 Ubuntu 20.04 中,有许多适用于 OpenBLAS 的软件包。
~$ apt search openblas
p libopenblas-base - Optimized BLAS (linear algebra) library (transitional)
p libopenblas-dev - Optimized BLAS (linear algebra) library (dev, meta)
p libopenblas-openmp-dev - Optimized BLAS (linear algebra) library (dev, openmp)
p libopenblas-pthread-dev - Optimized BLAS (linear algebra) library (dev, pthread)
p libopenblas-serial-dev - Optimized BLAS (linear algebra) library (dev, serial)
i A libopenblas0 - Optimized BLAS (linear algebra) library (meta)
p libopenblas0-openmp - Optimized BLAS (linear algebra) library (shared lib, openmp)
i A libopenblas0-pthread - Optimized BLAS (linear algebra) library (shared lib, pthread)
p libopenblas0-serial - Optimized BLAS (linear algebra) library (shared lib, serial)
p libopenblas64-0 - Optimized BLAS (linear algebra) library (shared lib, 64bit, meta)
p libopenblas64-0-openmp - Optimized BLAS (linear algebra) library (shared lib, 64bit, openmp)
p libopenblas64-0-pthread - Optimized BLAS (linear algebra) library (shared lib, 64bit, pthread)
p libopenblas64-0-serial - Optimized BLAS (linear algebra) library (shared lib, 64bit, serial)
p libopenblas64-dev - Optimized BLAS (linear algebra) library (dev, 64bit, meta)
p libopenblas64-openmp-dev - Optimized BLAS (linear algebra) library (dev, 64bit, openmp)
p libopenblas64-pthread-dev - Optimized BLAS (linear algebra) library (dev, 64bit, pthread)
p libopenblas64-serial-dev - Optimized BLAS (linear algebra) library (dev, 64bit, serial)
哪一个包可以产生最快的结果?
我打算在 GNU Octave 中进行数值计算(主要是对角化矩阵)。我的电脑有 Intel Core i3-5005U 处理器(如果优化包取决于处理器类型,请说明在其他类型的处理器上应该优先使用哪个包)。
我注意到,当使用 OpenBLAS 而不是默认 BLAS 时,速度至少提高了 10 倍。
答案1
为什么有这么多?
- -dev 库包括用于链接的头文件和库
- libopenblas0* 库具有 32 位(即 uint32_t)参数
- libopenblas64-0* 库有 64 位(即 uint64_t)参数。
- 例如,在 中
zgetrf()
,如果您的数组是uint32_t *ip
,则它不适合使用 64 版本,因为您的内存对齐是元素之间的 4 字节(uint32_t
)而不是 8 字节。您必须重构代码以支持数组元素之间的 8 字节对齐(uint64_t
)。 - 如果您使用 64 但设置为 32,它将会超出界限。
- 如果您使用 32 并设置为 64,它可能不会超出界限,但您将无法获得正确的结果。
- 例如,在 中
基准
我正在将 LAPACK、ATLAS 和 OpenBLAS 支持集成到xnec2c EM 模拟器并有以下基准测试,特别是针对用于替代现有 NEC2 高斯消元算法的 zgetrf() 和 zgetrs()。请务必为您的应用程序运行自己的基准测试,结果会有所不同。
在 Ubuntu 20.04 中我们选择的库如下:
~# update-alternatives --config libblas.so.3-x86_64-linux-gnu
~# update-alternatives --config liblapack.so.3-x86_64-linux-gnu
在 CentOS/RHEL 中,您拥有以下库,可以直接访问它们而无需使用alternatives
:
- libopenblas.so: 串行
- 自由开放布拉斯o.so: OpenMP
- 自由开放布拉斯页.so: pthreads
以下是我在测试 Ubuntu 20.04 时从记事本中复制粘贴的数字。每个部分的前两行定义了测试所选择的内容。这些测试是在 KVM 下的 CentOS 7 VM 上运行的,该 VM 有 24 个 vCPU,运行在双插槽 Xeon E5-2450 v2 服务器上,该服务器有 32 个逻辑处理器:16 个内核,32 个线程。虚拟机管理程序负载很轻,不会对数字造成太大影响,但肯定会有一些抖动。
默认 LAPACK+BLAS:
/usr/lib/x86_64-linux-gnu/blas/libblas.so.3
/usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3
Serial:
Frequency_Loop elapsed time: 17.540371 seconds
Frequency_Loop elapsed time: 16.697984 seconds
Frequency_Loop elapsed time: 15.621345 seconds
Frequency_Loop elapsed time: 15.515307 seconds
使用 ATLAS
/usr/lib/x86_64-linux-gnu/atlas/libblas.so.3
/usr/lib/x86_64-linux-gnu/atlas/liblapack.so.3
Serial:
Frequency_Loop elapsed time: 12.882587 seconds
Frequency_Loop elapsed time: 12.233791 seconds
Frequency_Loop elapsed time: 12.828287 seconds
Frequency_Loop elapsed time: 12.607457 seconds
将 ATLAS 的 BLAS 与 OpenBLAS 串行混合
/usr/lib/x86_64-linux-gnu/atlas/libblas.so.3
/usr/lib/x86_64-linux-gnu/openblas-serial/liblapack.so.3
Serial:
Frequency_Loop elapsed time: 11.757070 seconds
Frequency_Loop elapsed time: 11.566754 seconds
OpenBLAS 串行
/usr/lib/x86_64-linux-gnu/openblas-serial/libblas.so.3
/usr/lib/x86_64-linux-gnu/openblas-serial/liblapack.so.3
Serial:
Frequency_Loop elapsed time: 11.345475 seconds
Frequency_Loop elapsed time: 12.047305 seconds
Frequency_Loop elapsed time: 11.693541 seconds
OpenBLAS 串行 LAPACK 和 OpenMP BLAS
/usr/lib/x86_64-linux-gnu/openblas-openmp/libblas.so.3
/usr/lib/x86_64-linux-gnu/openblas-serial/liblapack.so.3
Serial (or barely threaded, 101%)
Frequency_Loop elapsed time: 11.049351 seconds
Frequency_Loop elapsed time: 11.756581 seconds
OpenBLAS OpenMP
/usr/lib/x86_64-linux-gnu/openblas-openmp/libblas.so.3
/usr/lib/x86_64-linux-gnu/openblas-openmp/liblapack.so.3
Threaded (~400% cpu)
Frequency_Loop elapsed time: 8.079269 seconds
Frequency_Loop elapsed time: 8.119229 seconds
Frequency_Loop elapsed time: 8.329753 seconds
OpenBLAS OpenMP LAPACK 带有默认 BLAS
/usr/lib/x86_64-linux-gnu/blas/libblas.so.3
/usr/lib/x86_64-linux-gnu/openblas-openmp/liblapack.so.3
Frequency_Loop elapsed time: 8.161807 seconds
Frequency_Loop elapsed time: 8.009399 seconds
具有不同线程限制的 OpenBLAS pthreads。
请注意,限制线程可以减少线程争用并在某些情况下提高性能:
/usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
/usr/lib/x86_64-linux-gnu/openblas-pthread/liblapack.so.3
Threaded 1400% cpu
Frequency_Loop elapsed time: 13.181950 seconds
Frequency_Loop elapsed time: 12.866588 seconds
OPENBLAS_NUM_THREADS=4
Frequency_Loop elapsed time: 9.567861 seconds
OPENBLAS_NUM_THREADS=8
Frequency_Loop elapsed time: 8.767348 seconds
OPENBLAS_NUM_THREADS=16
Frequency_Loop elapsed time: 9.818271 seconds
结果
OpenBLAS 的 OpenMP 似乎在本例中表现最佳。但是,如果您的代码分区良好,您可能会受益于 fork() 或使用 pthreads 完全并行运行。对于单作业并行,分叉作业和 _NUM_THREADS 之间的某种平衡可能会很好——但将分叉与 OpenBLAS 或 ATLAS 的线程相结合会引起争用。
例如,xnec2c 支持 -jNN 选项,用于指定要运行的频率作业数。对于许多频率,以完全 fork() 并行方式(每个频率一个作业)运行串行 LAPACK 版本通常是最快的,而不是使用更多 OpenBLAS/ATLAS 线程运行较少的并行分叉作业,因为矩阵运算通常具有无法并行化的大多数串行缩减阶段。(参见阿姆达尔定律。
附注:如果您为主机重新编译 ATLAS,它将自动调整您的 CPU。OpenBLAS 可能也会执行一些这样的操作,但不确定。
答案2
“为什么?”这个问题的答案可能是——为了获得适用于多种 CPU 和平台的通用解决方案。
从技术上讲,所有这些二进制包来自同一个openblas
源码包。
如果我们谈论提供的库变体更新替代方案,然后sudo apt-get install "*openblas*"
我们可以算出 4 组,有 4 个选择:
$ sudo update-alternatives --config libopenblas<Tab> libopenblas64.so.0-x86_64-linux-gnu libopenblas64.so-x86_64-linux-gnu libopenblas.so.0-x86_64-linux-gnu libopenblas.so-x86_64-linux-gnu
安装后线程设置为默认(0 个选择)版本。
对于基本的基准测试,我们可以利用我们的旧mkl-test.sh
脚本针对openblas
使用 的库的不同替代方案update-alternatives
。
以下是我的 i7-3537U 第三次运行的结果(速度越低表示速度越快,所有结果均以秒为单位):
Alt 库 | 科学实验室 | 朱莉娅 | Python 3 与 NumPy | R | 八度 |
---|---|---|---|---|---|
pthread |
0.31 | 0.76 | 0.31 | 0.39 | 0.31 |
openmp |
0.24 | 0.75 | 0.22 | 0.31 | 0.22 |
serial |
0.17 | 0.79 | 0.17 | 0.27 | 0.17 |
atlas/liblapack | 0.31 | 0.75 | 0.32 | 0.52 | 0.32 |
lapack/liblapack | 0.26 | 0.76 | 0.30 | 0.47 | 0.28 |
libmkl_rt (MKL) | 0.16 | 0.76 | 0.16 | 0.22 | 0.16 |
更好的方法是运行官方基准,但我目前不明白如何运行它们。