我知道這種“特征加速”問題經常出現,但是在閱讀了其中的許多問題并嘗試了幾個標志之后,與執行轉置的傳統方式相比,我無法更好地使用 c 特征。實際上使用阻塞更有效。以下是代碼
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <iostream>
#include <Eigen/Dense>
#define min( a, b ) ( ((a) < (b)) ? (a) : (b) )
int main(){
const int n = 10000;
const int csize = 32;
float **a, **b;
clock_t cputime1, cputime2;
int i,j,k,ii,jj,kk;
// Allocating memory for array/matrix
a = new float * [n];
for (i=0; i<n; i ){
a[i] = new float [n];
}
b = new float * [n];
for (i=0; i<n; i ){
b[i] = new float[n];
}
// eigen matrices
Eigen::MatrixXf M1 = Eigen::MatrixXf::Constant(n, n, 0.0);
Eigen::MatrixXf M2 = Eigen::MatrixXf::Constant(n, n, 0.0);
// Filling matrices with zeros
for(i=0; i<n; i)
for (j=0; j<n; j)
a[i][j] = 0;
for(i=0; i<n; i)
for (j=0; j<n; j)
b[i][j] = 0;
// Direct (inefficient) transposition
cputime1 = clock();
for (i=0; i<n; i)
for (j=0; j<n; j)
a[i][j] = b[j][i];
cputime2 = clock() - cputime1;
std::printf("Time for transposition: %f\n", ((double)cputime2)/CLOCKS_PER_SEC);
// Transposition using cache-blocking
cputime1 = clock();
for (ii=0; ii<n; ii =csize)
for (jj=0; jj<n; jj =csize)
for (i=ii; i<min(n,ii csize-1); i)
for (j=jj; j<min(n,jj csize-1); j)
a[i][j] = b[j][i];
cputime2 = clock() - cputime1;
std::printf("Time for transposition: %f\n", ((double)cputime2)/CLOCKS_PER_SEC);
// eigen
cputime1 = clock();
M1.noalias() = M2.transpose();
cputime2 = clock() - cputime1;
std::printf("Time for transposition with eigen: %f\n", ((double)cputime2)/CLOCKS_PER_SEC);
// use data
std::cout << a[n/2][n/2] << std::endl;
std::cout << b[n/2][n/2] << std::endl;
std::cout << M1(n/2,n/2) << std::endl;
return 0;
}
我使用的編譯命令是
g -fno-math-errno -ffast-math -march=native -fopenmp -O2 -msse2 -DNDEBUG blocking_and_eigen.cpp
有結果
Time for transposition: 1.926674
Time for transposition: 0.280653
Time for transposition with eigen: 2.018217
我正在使用 eigen 3.4.0 和 g 11.2.0。
您有什么建議可以提高本征性能嗎?提前致謝
uj5u.com熱心網友回復:
正如 INS 在評論中所建議的那樣,矩陣的實際復制會導致性能下降,我稍微修改了您的示例以使用一些數字而不是全零(以避免任何型別的優化):
for(i=0; i<n; i) {
for (j=0; j<n; j) {
a[i][j] = i j;
M1(i,j) = i j;
}
}
for(i=0; i<n; i) {
for (j=0; j<n; j) {
b[i][j] = i j;
M1(i,j) = i j;
}
}
此外,我修改了最終的列印陳述句,并對結果進行了全面檢查(如果未到位,將針對 M2 執行檢查):
for (i=0; i<n; i)
for (j=0; j<n; j)
if (a[i][j] != M1(i,j))
std::cout << "Diff here! " << std::endl;
然后我嘗試了幾個測驗:
預分配和分配
Eigen::MatrixXf M2 = Eigen::MatrixXf::Constant(n, n, 0.0); ... 這里有一些代碼 ... M2 = M1.transpose();
復制建構式
Eigen::MatrixXf M2(M1.transpose());
到位
M1.transposeInPlace();
使用 auto 和 c 17 的復制構造
自動 M2{ M1.transpose() };
這是最令人費解的,表現出色,我認為故事有兩個部分,如果我為案例2和案例4列印M2的typeid名稱,它們是不同的,名稱錯位但它給了我們一個線索:
N5特征6矩陣IfLin1ELin1ELi0ELin1ELin1EEE N5特征9轉置INS_6矩陣IfLin1ELin1ELi0ELin1ELin1EEEEE
auto 關鍵字決議為特定于轉置矩陣的不同型別。故事的第二部分是 M1 之后不會修改的事實,所以要么編譯器移動它,要么很可能 EigenTransposeMatrix ( https://eigen.tuxfamily.org/dox/classEigen_1_1Transpose.html ) 只保留一個參考的原始矩陣,它不復制它。
結果
| 測驗 | 直接 | 快取塊 | 特征 (s) |
|---|---|---|---|
| 1 | 2.633 | 0.312 | 1.861 |
| 2 | 2.599 | 0.262 | 1.968 |
| 3 | 2.602 | 0.262 | 0.216 |
| 4 | 2.552 | 0.280 | 0.000002 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/363486.html
