【问题标题】:Eigen: Should i use aligned map for intensive computations?Eigen:我应该使用对齐的地图进行密集计算吗?
【发布时间】:2019-12-23 11:34:37
【问题描述】:

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

我决定通过 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
.......

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

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

2) 我的比较正确吗?

PS 对不起我的英语不好

【问题讨论】:

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


    【解决方案1】:

    1) 数据对齐指定应该如何访问和排列数据的方式。这意味着如果您使用Eigen::MatrixXf,它指的是编译时未知维度的矩阵,数据类型为float,则数据指针应在4 字节(32 位)上对齐 边界(假设浮点数在您的系统上使用 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::Matrix 和Eigen::Vector 不同,Eigen::Map 享有无需复制数据即可初始化矩阵和向量的优势。我很确定Eigen::Map 和Eigen::Matrix 对下面的对象使用相同的操作来进行乘法、加法等操作,只是引用不同。我可以从使用Eigen::Matrix 看到的唯一性能优势是空间局部性 在缓存性能方面,如果Eigen::Map 引用两个在内存中相距很远的矩阵/向量并且在处理巨大的矩阵大小时.当然,假设您将两个Eigen::Matrix 对象一个接一个地初始化,这样它们在内存中是连续的。

    【讨论】:

      【解决方案2】:

      主要区别在于矢量化加载是对齐加载还是非对齐加载(或跨越缓存线边界时)。在现代桌面 CPU(例如任何带有 AVX、IIRC 的 CPU)上,差异会很小,并且与实际工作相比相形见绌。在其他设备上,未对齐负载的惩罚可能会有很大差异。

      如果Eigen::Map保证内存是对齐的,则加载都可以是对齐的加载,而如果不能保证,那么加载必须都是未对齐的加载。这将对您的应用程序产生多大影响取决于您所针对的硬件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-13
        • 1970-01-01
        • 2018-10-11
        相关资源
        最近更新 更多