const int m = 1000;
double *A = new double[m*m], *B = new double[m*m], *C = new double[m*m];
// 初始化為 1
for (int i = 0; i < m*m; ++i) { A[i] = 1; B[i] = 1; C[i] = 0; }
const int BF = 48; // 分塊因子,可調優化
for (int jj = 0; jj < m; jj += BF)
for (int kk = 0; kk < m; kk += BF)
for (int i = 0; i < m; ++i) {
int minj = min(jj + BF, m);
int im = i * m;
int mink = min(kk + BF, m);
for (int j = jj; j < minj; ++j) {
double r = 0;
for (int k = kk; k < mink; ++k)
r += A[im + k] * B[k*m + j];
C[im + j] += r;
}
}
delete[] A; delete[] B; delete[] C;
dgemm 比 MATLAB 慢 0.5 倍(1.5x 時間)。| 優化點 | 說明 | 預期收益 |
|---|---|---|
| 緩存友好訪問 | B 矩陣按列訪問導致缺失,需轉置或塊內連續訪問 | 高 |
| SIMD 向量化 | 編譯器自動向量化需簡單循環,或手寫 AVX/SSE 內聯匯編 | 高 |
| 寄存器分塊 | 內層循環展開,多累加器隱藏延遲(如 4×4 微內核) | 高 |
| 多線程並行 | OpenMP 外層循環並行,NUMA 感知內存分配 | 線性擴展 |
| 預取指令 | __builtin_prefetch 或硬件預取友好訪問模式 | 中 |
| 調用優化庫 | 直接鏈接 OpenBLAS/MKL/BLIS 的 cblas_dgemm | 最高(專家調優) |
// 預轉置 B 矩陣,實現連續訪問
double *BT = new double[m*m];
for (int i = 0; i < m; ++i)
for (int j = 0; j < m; ++j)
BT[j*m + i] = B[i*m + j];
for (int jj = 0; jj < m; jj += BF)
for (int kk = 0; kk < m; kk += BF)
for (int i = 0; i < m; ++i) {
int im = i * m;
int minj = min(jj + BF, m);
int mink = min(kk + BF, m);
for (int j = jj; j < minj; ++j) {
double r = 0;
int jm = j * m; // BT 行首
for (int k = kk; k < mink; ++k)
r += A[im + k] * BT[jm + k]; // 連續訪問
C[im + j] += r;
}
}
delete[] BT;
cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, m, m, m, 1.0, A, m, B, m, 0.0, C, m);BF 需根據 L1/L2 緩存大小經驗調整(典型 32-128)。-O3 -march=native -ffast-math -funroll-loops(GCC/Clang),/O2 /arch:AVX2(MSVC)。perf、VTune、gprof 定位熱點與缺失。矩陣乘法優化是計算機體系結構、編譯器技術、數值線性代數交叉的經典課題。手寫高性能 GEMM 需深度理解硬體特性,工程實踐首選成熟數學庫,自研僅作教學或極端受限場景。