You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Eigen链式操作性能异常低下:求助原因与规避方案

Eigen链式调用计算行向量方差的性能陷阱问题

在计算大型矩阵行向量的方差时,发现Eigen存在反常表现:全链式调用的性能极低,分步计算中间结果再执行相同操作的速度却快得多,这和Eigen文档/FAQ里建议避免临时变量的内容完全相反。

想知道:

  • Eigen有没有需要规避的已知性能陷阱?
  • 如何识别会出现这类性能下降的场景?

测试环境与性能差距

测试在Windows环境下进行,分别用MSVC(-O2优化)和MinGW GCC(-O3优化)编译:

  • 分步计算版本("row variance with partial eval"):GCC下耗时约560ms,MSVC下约1s
  • 全链式调用版本("row variance"):GCC下耗时约90s,MSVC下约104s
    两者性能差距极为悬殊,原生for循环的速度应该远快于90秒。

测试代码

#include <iostream>
#include <vector>
#include <chrono>
#include <random>
#include <functional>

#include "Eigen/Dense"

void printTimespan(std::chrono::nanoseconds timeSpan)
{
    using namespace std::chrono;
    std::cout << "Timing ended:\n"
        << "\t ms: " << duration_cast<milliseconds>(timeSpan).count() << '\n'
        << "\t us: " << duration_cast<microseconds>(timeSpan).count() << '\n'
        << "\t ns: " << timeSpan.count() << '\n';
}

class Timer
{
    std::chrono::steady_clock::time_point start_;
public:
    void start()
    {
        start_ = std::chrono::steady_clock::now();
    }
    void stop()
    {
        timings.push_back((std::chrono::steady_clock::now() - start_).count());
    }
    std::vector<long long> timings;
};

std::vector<float> buildBuffer(size_t rows, size_t cols)
{
    std::vector<float> buffer;
    buffer.reserve(rows * cols);
    for (size_t i = 0; i < rows; i++)
    {
        for (size_t j = 0; j < cols; j++)
        {
            buffer.push_back(std::rand() % 1000);
        }
    }
    return buffer;
}

using EigenArr = Eigen::Array<float, -1, -1, Eigen::RowMajor>;
using EigenMap = Eigen::Map<EigenArr>;

std::vector<float> benchmark(std::function<EigenArr(const EigenMap&)> func)
{
    constexpr size_t rows = 2000, cols = 200, repetitions = 1000;
    std::vector<float> buffer = buildBuffer(rows, cols);
    EigenMap map(buffer.data(), rows, cols);
    EigenArr res;
    std::vector<float> means; // 防止编译器因结果未被使用而跳过计算

    Timer timer;
    for (size_t i = 0; i < repetitions; i++)
    {
        timer.start();
        res = func(map);
        timer.stop();
        means.push_back(res.mean());
    }

    Eigen::Map<Eigen::Vector<long long, -1>> timingsMap(timer.timings.data(), timer.timings.size());
    printTimespan(std::chrono::nanoseconds(timingsMap.sum()));
    return means;
}


int main()
{
    std::cout << "mean center rows\n";
    benchmark([](const EigenMap& map)
    {
        return (map.colwise() - map.rowwise().mean()).eval(); 
    });

    std::cout << "squared deviations\n";
    benchmark([](const EigenMap& map)
    {
        return (map.colwise() - map.rowwise().mean()).square().eval();
    });

    std::cout << "row variance with partial eval\n";
    benchmark([](const EigenMap& map)
    {
        EigenArr partial = (map.colwise() - map.rowwise().mean()).square().eval();
        return (partial.rowwise().sum() / (map.cols() - 1)).eval();
    });

    std::cout << "row variance\n";
    benchmark([](const EigenMap& map)
    {
        return ((map.colwise() - map.rowwise().mean()).square().rowwise().sum() / (map.cols() - 1)).eval();
    });
}

内容的提问来源于stack exchange,提问作者Janilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 17:10:39