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

C++算法封装为DLL后性能下降问题排查及跨平台问询

MKL加速C++算法封装为DLL后性能下降问题

原本使用MKL加速的C++算法,10轮计算耗时约280ms,但封装为DLL后10轮耗时升至500ms。排除MKL本身的影响(注释MKL代码仅慢1ms),已尝试const引用传参、提前加载DLL、调整编译优化(/O2、/Ot)等手段,但性能仍未达标(目标10轮≤400ms),怀疑是DLL封装或调用方式存在问题。同时需要了解该DLL在Unity/Android平台使用时,是否会因VS调试功能导致性能进一步下降。

原C++代码

auto starttime = system_clock::now();
cleanData = ssveP.getWarmFilter(newData);

std::vector<std::vector<double>> eps;
std::vector<std::vector<double>> pred;

vector<vector<vector<vector<double>>>> corr;
vector<vector<vector<double>>>filterData;

ssveP.testPhaseOnlineADA(res, pred, eps, corr, ssveP, filterData, cleanData, M, method, T, 0);

duration<double> diff = system_clock::now() - starttime;
std::cout << endl << "所耗时间为:" << diff.count() << "s";

DLL导出函数代码

__declspec(dllexport) Result testPhaseOnlineADA(std::vector<std::vector<double>> newData)
{
    Result result;
    std::vector<std::vector<double>> epsilons;
    std::vector<std::vector<double>> predLabels;
    vector<vector<vector<vector<double>>>> corrCoef;
    vector<vector<vector<double>>>filterData;
    int res = -1;
    string method = "DW11";
    double T = -0.005;
    int C = 0;
    vector<vector<vector<double>>>cleanData;
    cleanData = DWT.getWarmFilter(newData);
    DWT.testPhaseOnlineADA(res, predLabels, epsilons, corrCoef, DWT, filterData, cleanData, M, method, T, C);

    double epsMin;
    epsMin = epsilons[0][0];
    int wIdx = 0;
    for (int m = 0; m < epsilons.size(); m++)
    {
        if (epsMin > epsilons[m][0])
        {
            epsMin = epsilons[m][0];
            wIdx = m;
        }
    }
    if (epsMin < T)
    {
        res = predLabels[wIdx][0] + 1;
    }

    result.res = res;
    result.wIdx = wIdx; // 原代码此处遗漏赋值,已修正
    result.cleanData = cleanData;
    return result;
}

DLL调用代码

auto starttime = system_clock::now();

Result result = testPhaseOnlineADA(newData);

duration<double> diff = system_clock::now() - starttime;
std::cout << "testPhaseOnlineADA所耗时间为:" << diff.count() << "s" << std::endl;

补充测试与尝试(2024.04.11)

已执行操作

  • 提前在主函数开头加载DLL,避免循环内加载开销,无效果
  • 将大数据拆分为50*140的三维数据块
  • 使用const vector<vector<double>>& newData传参,耗时仍超400ms;且在getWarmFilter()中用此方式时耗时反而增加30ms

测试结论

  • 注释MKL代码仅变慢1ms,排除MKL计算导致性能下降的可能
  • 原C++中testPhaseADA单轮耗时约40ms,DLL封装后单轮约70ms,10轮累计超400ms
  • 在DLL内部计时,testPhaseADA函数本身耗时仍为70ms,已开启/O2、/Ot优化,性能仍不及原代码

性能优化建议

1. 修复代码逻辑错误

原DLL代码中result.wIdx;是无效语句,未完成赋值,虽不直接影响性能,但属于逻辑错误,需修正为result.wIdx = wIdx;。

2. 彻底优化数据传递

  • 避免vector深拷贝:当前DLL函数参数std::vector<std::vector<double>> newData是值传递,会触发完整深拷贝。即使使用const引用,若getWarmFilter内部存在编译器无法判定的修改操作,仍可能产生额外开销。建议:
    • 改用原始指针+尺寸参数传递数据,例如double* newDataPtr, int rows, int cols,彻底规避vector拷贝开销
    • 若必须使用vector,确保所有跨DLL的vector传递都用const std::vector<std::vector<double>>&,同时检查getWarmFilter实现,确认其可接受const引用且内部无修改操作

3. 统一编译配置

  • 确保DLL与调用端使用完全一致的编译选项:包括编译器版本、优化等级(/O2)、运行时库(MT/MD/MTd/MDd)、MKL链接方式(静态/动态)。不一致的配置会导致编译器无法进行跨模块优化,甚至生成额外兼容代码。
  • 开启链接时优化(LTO):在VS中启用/LTCG选项,让编译器在链接阶段对DLL和调用端代码进行整体优化,消除跨模块调用的额外开销。

4. 减少跨DLL的对象传递

当前DLL返回的Result对象包含vector<vector<vector<double>>> cleanData,会触发深拷贝。建议:

  • 若cleanData不需要返回给调用端,直接在DLL内部处理或释放
  • 若必须返回,改用指针/引用传递,或将数据存储在DLL内部的全局缓冲区(需注意线程安全),调用端通过指针访问

5. 检查DWT对象状态

原代码中DWT.testPhaseOnlineADA传递了DWT本身作为参数,需确认该对象在DLL内部是否重复初始化或存在状态冗余。原C++代码中ssveP是复用对象,若DLL中每次调用都重新初始化DWT,会产生额外开销,需确保DWT仅初始化一次。


Unity/Android平台性能疑问

  • VS调试功能影响:在Unity/Android平台使用时,若通过VS附加调试,会启用调试模式、禁用部分优化,导致性能下降。但发布版本(非调试)不受此影响,只要DLL是用Release配置编译的,性能与Windows下Release版本一致。
  • Android平台额外注意事项:Windows编译的DLL无法直接在Android上使用,需使用NDK编译为.so库。此时需确认:
    • MKL对ARM架构的支持情况,使用适配Android的MKL版本
    • 减少JNI调用次数,批量传递数据,降低跨JNI调用的开销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:17:11