我想写一个程序,广泛使用BLAS和LAPACK线性代数功能。由于性能是一个问题,我做了一些基准测试,想知道我采取的方法是否合法
可以说,我有三位参赛者,我想用一个简单的矩阵乘法来测试他们的表现。参赛者包括:
- Numpy,仅使用
dot
的功能 - Python,通过共享对象调用BLAS功能
- C++,通过共享对象调用BLAS功能
情景
我实现了不同维度的矩阵乘法I
i
从5运行到500,增量为5,矩阵m1
和m2
的设置如下:
m1=numpy.random.rand(i,i).astype(numpy.float32)
m2=numpy.random.rand(i,i).aType(numpy.float32)
一,。努比
使用的代码如下所示:
tNumpy=timeit.Timer(“numpy.dot(m1,m2)”,“导入numpy;从主导入m1,m2”)
rNumpy.append((i,tNumpy.repeat(20,1)))
二,。Python,通过共享对象调用BLAS
带函数
\u blaslib=ctypes.cdll.LoadLibrary(“libblas.so”)
def Mul(m1、m2、i、r):
无字符转换=c字符(“n”)
n=c_int(i)
一=c_浮动(1.0)
零=c_浮动(0.0)
_blaslib.sgemm_(byref(no_trans)、byref(no_trans)、byref(n)、byref(n)、byref(n),
byref(一),m1.ctypes.data_as(ctypes.c_void_p),byref(n),
m2.ctypes.data_as(ctypes.c_void_p),byref(n),byref(零),
r、 ctypes.data_as(ctypes.c_void_p),byref(n))
测试代码如下所示:
r=numpy.zero((i,i),numpy.float32)
tBlas=timeit.Timer(“Mul(m1,m2,i,r)”,“导入numpy;从主导入i,m1,m2,r,Mul”)
rBlas.append((i,tBlas.repeat(20,1)))
三,。C++,通过共享对象
调用BLAS现在C++代码自然会更长一点,所以我把信息减少到最小。
我用
void*handle=dlopen(“libblas.so”,RTLD\u LAZY);
void*Func=dlsym(手柄,“sgemm”);
我用gettimeofday
测量时间,如下所示:
gettimeofday(&;start,NULL);
f(&;no_trans,&;no_trans,&;dim,&;dim,&;one,A,&;dim,B,&;dim,&;zero,Return,&;dim);
gettimeofday(&;end,NULL);
dTimes[j]=计算时间(开始、结束);
其中j
是运行20次的循环。我计算着时间的流逝
双计算时间(timeval开始,timeval结束)
{
双因子=1000000;
返回(((双)端.tv_-sec)*因子+((双)端.tv_-usec)-((双)启动.tv_-sec)*因子+((双)启动.tv_-usec))/factor;
}
结果
结果如下图所示:
问题
- 你认为我的方法公平吗,或者我可以避免一些不必要的开销吗
- 既然我更愿意在程序中使用python,那么在调用BLAS或LAPACK例程时,我可以做些什么来提高性能呢
LI>你会期待结果会显示C++和Python方法之间的巨大差异吗?两者都使用共享对象进行计算
下载
完整的基准可以在这里下载。(J.F.塞巴斯蒂安使这种联系成为可能)
更新(30.07.2014):
我在新HPC上重新运行了基准测试。
硬件和软件堆栈都与原始答案中的设置不同
我把结果放在谷歌电子表格中(也包含原始答案的结果)
硬件
我们的HPC有两个不同的节点,一个使用Intel Sandy Bridge CPU,另一个使用较新的Ivy Bridge CPU:
桑迪(MKL、OpenBLAS、阿特拉斯):
- CPU:2 x 16英特尔(R)至强(R)E2560沙桥@2.00GHz(16核)
- RAM:64 GB
常春藤(MKL、OpenBLAS、ATLAS):
- CPU:2 x 20英特尔(R)至强(R)E2680 V2常春藤网桥@2.80GHz(20核,HT=40核)
- RAM:256 GB
软件
多线程的也被用于BLAS strong的多线程堆栈中
- 操作系统:Suse
- 英特尔编译器:ictce-5.3.0
- Numpy:1.8.0
- OpenBLAS:0.2.6
- 图集::3.8.4
Dot产品基准
基准代码如下所示。然而,对于新机器,我还运行了矩阵大小5000和8000的基准测试
下表包括原始答案的基准测试结果(重命名为:MKL–>Nehalem MKL、Netlib Blas–>Nehalem Netlib Blas等)
单线程性能:
多线程性能(8线程):
螺纹与基体尺寸(常春藤桥MKL):
基准测试套件
单线程性能:
多线程(8线程)性能:
结论
新的基准测试结果与原始答案中的结果相似OpenBLAS和MKL在同一水平上执行,但特征值测试除外。
特征值测试仅在单线程模式下的OpenBLAS上运行良好。
在多线程模式下,性能更差
“矩阵大小与线程图表”还显示,尽管MKL和OpenBLAS通常能很好地随内核/线程的数量扩展,但这取决于矩阵的大小。对于较小的矩阵,添加更多的内核并不会大大提高性能
从沙桥到常春藤桥的性能也有大约30%的提高,这可能是由于更高的时钟频率(+0.8 Ghz)和/或更好的体系结构
原始答复(2011年10月4日):
不久前,我不得不优化一些使用numpy和BLAS用python编写的线性代数计算/算法,因此我对不同的numpy/BLAS配置进行了基准测试/测试
我特别测试了:
- 带ATLAS的Numpy
- 带GotoBlas2的Numpy(1.13)
- 带MKL的Numpy(11.1/073)
- 带加速框架的Numpy(Mac OS X)
我确实运行了两个不同的基准:
- 不同尺寸矩阵的简单点积
- 可以在这里找到基准测试套件
以下是我的结果:
机器
Linux(MKL,ATLAS,无MKL,GotoBlas2):
- OS:Ubuntu Lucid 10.4 64位
- CPU:2 x 4英特尔(R)至强(R)[email protected](8核)
- 内存:24 GB
- 英特尔编译器:11.1/073
- Scipy:0.8
- Numpy:1.5
Mac Book Pro(加速框架):
- 操作系统:Mac操作系统X雪豹(10.6)
- CPU:1个Intel Core 2个Duo 2.93 Ghz(2个内核)
- 内存:4 GB
- Scipy:0.7
- Numpy:1.3
Mac服务器(加速框架):
- OS:Mac OS X雪豹服务器(10.6)
- CPU:4 X Intel(R)Xeon(R)[email protected] Ghz(8核)
- 内存:4 GB
- Scipy:0.8
- Numpy:1.5.1
Dot产品基准
代码:
将numpy导入为np
a=np.随机.随机样本((大小,大小))
b=np.随机.随机样本((大小,大小))
%timeit np.dot(a,b)
结果:
系统|尺寸=1000 |尺寸=2000 |尺寸=3000| netlib BLAS | 1350毫秒| 10900毫秒| 39200毫秒| ATLAS(1个CPU)| 314毫秒| 2560毫秒| 8700毫秒| MKL(1个CPU)| 268毫秒| 2110毫秒| 7120毫秒| MKL(2个CPU)|-|-| 3660毫秒| MKL(8个CPU)| 39毫秒| 319毫秒| 1000毫秒| GotoBlas2(1个CPU)| 266毫秒| 2100毫秒| 7280毫秒| GotoBlas2(2个CPU)| 139毫秒| 1009毫秒| 3690毫秒| GotoBlas2(8个CPU)| 54毫秒| 389毫秒| 1250毫秒| Mac OS X(1个CPU)| 143毫秒| 1060毫秒| 3605毫秒| Mac服务器(1个CPU)| 92毫秒| 714毫秒| 2130毫秒|
基准测试套件
代码:
有关基准测试套件的更多信息,请参见此处
结果:
系统|特征值| svd | det | inv | dot| netlib BLAS | 1688毫秒| 13102毫秒| 438毫秒| 2155毫秒| 3522毫秒| ATLAS(1个CPU)| 1210毫秒| 5897毫秒| 170毫秒| 560毫秒| 893毫秒| MKL(1个CPU)| 691毫秒| 4475毫秒| 141毫秒| 450毫秒| 736毫秒| MKL(2个CPU)| 552毫秒| 2718毫秒| 96毫秒| 267毫秒| 423毫秒| MKL(8个CPU)| 525毫秒| 1679毫秒| 60毫秒| 137毫秒| 197毫秒| GotoBlas2(1个CPU)| 2124毫秒| 4636毫秒| 147毫秒| 456毫秒| 743毫秒| GotoBlas2(2个CPU)| 1560毫秒| 3278毫秒| 116毫秒| 295毫秒| 460毫秒| GotoBlas2(8个CPU)| 741毫秒| 2914毫秒| 82毫秒| 262毫秒| 192毫秒| Mac OS X(1个CPU)| 948毫秒| 439毫秒| 151毫秒| 318毫秒| 566毫秒| Mac服务器(1个CPU)| 1033毫秒| 3645毫秒| 99毫秒| 232毫秒| 342毫秒|
装置
仪表