c++ - Eigen:我应该使用对齐 map 进行密集计算吗?

标签 c++ eigen matrix-multiplication memory-alignment eigen3

我想对外部分配的数据执行大量计算,尤其是矩阵乘法。可以通过Eigen::Map来完成。不幸的是,我不是矢量化计算方面的专家,但据我所知,可以指定 Aligned Map 的标志。

我决定通过 Eigen::MatrixXf 检查矩阵乘法之间的性能差异和 'Eigen::Map':

void testMatProduct(
        const Eigen::MatrixXf &a,
        const Eigen::MatrixXf &b,
        Eigen::MatrixXf &res)
{
    const auto startTime = std::chrono::high_resolution_clock::now();
    res.noalias() = a * b;
    const auto endTime = std::chrono::high_resolution_clock::now();
    const auto duration = std::chrono::duration_cast<std::chrono::microseconds>( endTime - startTime ).count();
    std::cout << "Mat product elapsed " << duration / 1.0e6 << std::endl;
}

using EigenMap = Eigen::Map<Eigen::MatrixXf, Eigen::Unaligned>;

void testMapProduct(
        const EigenMap &a,
        const EigenMap &b,
        EigenMap &res)
{
    const auto startTime = std::chrono::high_resolution_clock::now();
    res.noalias() = a * b;
    const auto endTime = std::chrono::high_resolution_clock::now();
    const auto duration = std::chrono::duration_cast<std::chrono::microseconds>( endTime - startTime ).count();
    std::cout << "Map product elapsed " << duration / 1.0e6 << std::endl;
}

int main(int, char **)
{    
    srand(42);
    const int64_t N = 7000;
    const int64_t K = 6000;
    const int64_t M = 100;
    Eigen::MatrixXf mat1 = Eigen::MatrixXf::Random(N, K);
    Eigen::MatrixXf mat2 = Eigen::MatrixXf::Random(K, M);
    Eigen::MatrixXf matRes = Eigen::MatrixXf::Zero(N, M);

    // Copy data from mats to vecs
    Eigen::VectorXf vec1 = Eigen::Map<Eigen::MatrixXf>(mat1.data(), mat1.rows() * mat1.cols(), 1);
    Eigen::VectorXf vec2 = Eigen::Map<Eigen::MatrixXf>(mat2.data(), mat2.rows() * mat2.cols(), 1);
    Eigen::VectorXf vecRes = Eigen::VectorXf::Zero(N * M);

    EigenMap map1 = EigenMap(vec1.data(), mat1.rows(), mat1.cols());
    EigenMap map2 = EigenMap(vec2.data(), mat2.rows(), mat2.cols());
    EigenMap mapRes = EigenMap(vecRes.data(), matRes.rows(), matRes.cols());
    for(int i = 0; i < 10; ++i){
        testMapProduct(map1, map2, mapRes);
        testMatProduct(mat1, mat2, matRes);
        matRes.setZero();
        vecRes.setZero();
    }

    return 0;
}

我很确定这不是一个有效的基准,但它应该给我一些直觉。我用 -march=native 编译它它打印以下输出:

Map product elapsed 0.102751
Mat product elapsed 0.10224
Map product elapsed 0.10022
Mat product elapsed 0.100726
Map product elapsed 0.09963
Mat product elapsed 0.100697
Map product elapsed 0.099673
Mat product elapsed 0.100809
Map product elapsed 0.100195
.......

所以在我看来, map 乘积和矩阵乘积之间没有太大区别。

我的问题是: 1)Map<MatrixXf, Unaligned>有什么区别和Map<MatrixXf, Aligned>在性能方面?我应该关心Map其他操作的对齐,例如点积、元素加法等

2)我的比较正确吗?

PS抱歉我的英语不好

最佳答案

1) 数据对齐指定数据应该如何访问和排列的方式。这意味着如果您使用 Eigen::MatrixXf ,它指的是编译时维度未知、数据类型为 float 的矩阵。 ,数据指针应在 4 字节(32 位) 边界上对齐(假设 float 在系统上使用 32 位表示)。

不同的数据对齐规范对性能有什么影响?为了回答这个问题,我们将看一下以下讨论:
Talk: On a 32-bit architecture, would a 16-bit value not aligned on a 32-bit boundary be accessed more slowly?

  • 它影响性能的主要论点:将两个 16 位值打包到 32 位寄存器中意味着您必须花费资源将数据从一种格式转换为另一种格式

有人可能会说,C/C++ 等语言支持子字访问,这意味着您不必转换它们,这意味着您可以节省内存空间并且不会对性能产生负面影响.

我假设 Eigen 库会自动检测 Eigen::MatrixXf 的数据指针在 4 字节边界上对齐,因此如果省略 MapOption 不会对性能产生影响。模板或将其分配给Eigen::Unaligned 。如果您想确定使用 Eigen::Aligned4 (回想一下 Eigen::Aligned 已被弃用,并且是 Aligned16 的同义词,因此为 128 位)。您可以查看对齐枚举器 here .

2) Eigen::MapEigen::Matrix 不同,矩阵和 vector 可以在不复制数据的情况下进行初始化。和Eigen::Vector 。我很确定Eigen::MapEigen::Matrix对下面的对象使用相同的乘法、加法等操作,只是引用不同。我从使用 Eigen::Matrix 中看到的唯一性能优势就缓存性能而言,是空间局部性,如果 Eigen::Map引用内存中相距很远的两个矩阵/vector ,并且在处理巨大的矩阵大小时。当然假设您初始化了两个 Eigen::Matrix对象紧挨着一个,这样它们在内存中是连续的。

关于c++ - Eigen:我应该使用对齐 map 进行密集计算吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59454660/

相关文章:

c++ - 为什么/etc/目录下没有创建文件

c++ - 为什么需要为每一帧调用 OMSetRenderTargets DirectX 方法

c++ - Enterprise Architect - 单独的代码生成 header 和实现

c++ - 如何使用 Eigen 在 C++ 中计算稀疏矩阵的差异

matlab - 在 MATLAB 中将两个非常大的稀疏矩阵相乘时出现内存不足错误

c++ - 为什么我会收到运行时检查失败 #2 - 变量 'x' 周围的堆栈已损坏?

c++ - 有没有直接快速的方法将 "map"list<VectorXd> 转换为 MatrixXd?

c++ - 如何在 Eigen 中实现高性能分段线性传递函数?

c - 矩阵乘法的动态内存分配

CUDA/C 矩阵乘法