Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ RowMajor和ColMajor数据排列矩阵行求和的奇怪性能差异_C++_Performance_Gcc_Memory_Eigen - Fatal编程技术网

C++ RowMajor和ColMajor数据排列矩阵行求和的奇怪性能差异

C++ RowMajor和ColMajor数据排列矩阵行求和的奇怪性能差异,c++,performance,gcc,memory,eigen,C++,Performance,Gcc,Memory,Eigen,我决定检查矩阵中的数据排列如何影响简单操作的性能。 我使用Eigen::Matrix作为数据存储编写了简单的行求和算法。 我认为,由于缓存利用率提高,RowMajor存储应该表现出更好的性能 我使用了带有-O2选项的g++编译器,它给出了以下结果: ColMajor:40791546µs RowMajor:28790948µs 很好。但是对于-O3来说,它给了我一个非常奇怪的区别: ColMajor:10353619µs RowMajor:28359348µs 看起来ColMajor在使用-O3

我决定检查矩阵中的数据排列如何影响简单操作的性能。 我使用
Eigen::Matrix
作为数据存储编写了简单的行求和算法。 我认为,由于缓存利用率提高,RowMajor存储应该表现出更好的性能

我使用了带有
-O2
选项的
g++
编译器,它给出了以下结果:

ColMajor:
40791546µs
RowMajor:
28790948µs

很好。但是对于
-O3
来说,它给了我一个非常奇怪的区别:

ColMajor:
10353619µs
RowMajor:
28359348µs

看起来ColMajor在使用
-O3
时变得非常快。为什么从
-O2
切换到
-O3
会极大地改变性能

我的CPU:intel i7-6700K,gcc版本:
7.5.0-3ubuntu1~19.10

我的“基准”:

#包括
#包括
#包括
#包括“特征/核心”
模板
无效运行测试(常数特征::MatrixBase&mat,特征::MatrixBase&res){
const int64_t nRows=mat.rows();
常量int64_t nCols=mat.cols();
对于(int64_t row=0;rowstd::cout基于
ColMajor
的循环在
-O3
中要快得多,因为GCC 7.5能够自动将其矢量化,而不是基于
RowMajor
的循环。您可以看到(
L11
-标记的循环)。 自动矢量化是非常重要的

事实上,提到的缓存效应特别适用于不适合缓存的大矩阵,对于相对较小的矩阵,矢量化可能比缓存效率更重要。问题是GCC在简单约化的矢量化方面有一些困难。 您可以帮助他使用OpenMP指令,例如
#pragma omp simd reduction(+:acgregatorvar)
。或者,您可以使用应矢量化的Eigen提供的行求和(特别是对于连续数据)。 生成的代码应该是以前所有代码中最快的。 是生成的程序集代码

#include <iostream>
#include <vector>
#include <chrono>
#include "Eigen/Core"


template<typename DerivedMat, typename DerivedRes>
void runTest(const Eigen::MatrixBase<DerivedMat> &mat, Eigen::MatrixBase<DerivedRes> &res) {
    const int64_t nRows = mat.rows();
    const int64_t nCols = mat.cols();
    for(int64_t row = 0; row < nRows; ++row){
        for(int64_t col = 0; col < nCols; ++col){
            res(row, 0) += mat(row, col);
        }
    }
}


const int64_t nRows = 300;
const int64_t nCols = 5000;
const int nAttempts = 20000;

template<int Alignment>
void bench() {
    Eigen::Matrix<float, -1, -1, Alignment> mat(nRows, nCols);
    srand(42);
    mat.setRandom();

    Eigen::VectorXf res(nRows);
    res.setZero();

    std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
    for(int iter = 0; iter < nAttempts; ++iter)
        runTest(mat, res);
    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
    std::cout << "Elapsed " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl;
}

int main() {
    bench<Eigen::ColMajor>();
    //bench<Eigen::RowMajor>();
    return 0;
}