我想編寫一個廣泛使用 BLAS 和 LAPACK 線性代數功能的程序。由於性能是一個問題,我做了一些基準測試,想知道我採用的方法是否合法。
可以這麼說,我有三個參賽者,想用一個簡單的矩陣矩陣來測試他們的表現乘法。參賽者是:
- Numpy,僅使用
dot
的功能。 - Python,通過共享對象調用BLAS功能。
- C++,通過共享對象調用BLAS功能。
場景
我實現了不同維度的矩陣-矩陣乘法我。
i
從 5 運行到 500,增量為 5,矩陣 m1
和 m2
設置如下:
m1 = numpy.random.rand(i,i).astype(numpy.float32) m2 = numpy.random.rand(i,i).astype(numpy.float32)
1。 Numpy
使用的代碼如下所示:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1 , m2") rNumpy.append((i, tNumpy.repeat(20, 1)))
2. Python,通過共享對象調用BLAS
使用函數
_blaslib = ctypes.cdll.LoadLibrary("libblas.so") def Mul(m1, m2, i , r): no_trans = c_char("n") n = c_int(i) 一 = c_float(1.0) 零 = c_float(0.0) _blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref (n), byref(n), byref(one), 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.zeros ((i,i), numpy.float32) tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul") rBlas。追加((我,tBlas.repeat(20, 1)))
3。 c++,通過共享對象調用 BLAS
現在 c++ 代碼自然要長一些,所以我將信息減少到最少。
我用
void* 句柄 = dlopen("libblas.so", RTLD_LAZY); void* Func = dlsym(handle, "sgemm_");
我用 gettimeofday
像這樣測量時間:
gettimeofday(&start, NULL); f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim); gettimeofday(&end, NULL); dTimes[j] = 計算時間(開始,結束);
其中 j
是一個循環運行 20 次。我用
double CalcTime(timeval start, timeval end) { double factor = 1000000;返回(((雙)end.tv_sec)*因子+((雙)end.tv_usec)-(((雙)start.tv_sec)*因子+((雙)start.tv_usec)))/因子; }
結果
結果如下圖所示:
問題
- 你認為我的做法是否公平,或者我可以做一些不必要的開銷避免?
- 您是否期望結果會顯示 c++ 和 python 方法之間存在如此巨大的差異?兩者都使用共享對象進行計算。
- 由於我更願意在我的程序中使用 python,所以在調用 BLAS 或 LAPACK 例程時我可以做些什麼來提高性能?
下載
完整的基準測試可以在這裡下載。 (JF Sebastian 使該鏈接成為可能^^)