我正在开发一款需要调用一系列优化求解器的软件。每个求解器都是一段自动生成的 C 代码,有数千行代码。我使用了 200 个这样的求解器,不同之处仅在于要解决的优化问题的大小。
总而言之,这些自动生成的求解器有大约 180MB 的 C 代码,我使用 extern "C"{/*200 求解器的头文件*/}
编译成 C++语法,在 Visual Studio 2008 中。编译所有这些非常慢(使用“最大速度/O2”优化标志,大约需要 8 小时)。出于这个原因,我认为将求解器编译成一个 DLL 是个好主意,然后我可以从一个单独的软件中调用它(这将有一个合理的编译时间,并允许我抽象出所有这些外部“C”来自更高级别代码的东西)。编译后的 DLL 约为 37MB。
问题是,当使用 DLL 执行这些解算器之一时,执行需要大约 30 毫秒。如果我只将那个单一的求解器编译成一个 DLL,并从同一个程序中调用它,执行速度大约快 100 倍(<1 毫秒)。为什么是这样?我可以绕过它吗?
DLL 如下所示。每个求解器使用相同的结构(即它们具有相同的成员变量),但它们具有不同的名称,因此所有类型转换。
extern "C"{
#include "../Generated/include/optim_001.h"
#include "../Generated/include/optim_002.h"
/*etc.*/
#include "../Generated/include/optim_200.h"
}
namespace InterceptionTrajectorySolver
{
__declspec(dllexport) InterceptionTrajectoryExitFlag SolveIntercept(unsigned numSteps, InputParams params, double* optimSoln, OutputInfo* infoOut)
{
int exitFlag;
switch(numSteps)
{
case 1:
exitFlag = optim_001_solve((optim_001_params*) ¶ms, (optim_001_output*) optimSoln, (optim_001_info*) &infoOut);
break;
case 2:
exitFlag = optim_002_solve((optim_002_params*) ¶ms, (optim_002_output*) optimSoln, (optim_002_info*) &infoOut);
break;
/*
...
etc.
...
*/
case 200:
exitFlag = optim_200_solve((optim_200_params*) ¶ms, (optim_200_output*) optimSoln, (optim_200_info*) &infoOut);
break;
}
return exitFlag;
};
};
最佳答案
我不知道您的代码是否内联到示例中的每个案例部分。如果你的函数是内联函数并且你将它全部放在一个函数中那么它会慢得多,因为代码是在虚拟内存中布局的,这将需要 CPU 在代码执行时跳来跳去。如果不是全部内联,那么这些建议可能会有所帮助。
您的解决方案可能会通过...得到改进
一个) 1) 将项目分成 200 个独立的 dll。然后使用 .bat 文件或类似文件构建。 2) 在每个名为“MyEntryPoint”的dll 中创建导出函数,然后使用动态链接在需要的库中加载它们。这将相当于一个繁忙的音乐程序,加载了很多小的 dll 插件。使用 GetProcAddress 获取指向 EntryPoint 的函数指针。
或者...
B) 将每个解决方案构建为单独的 .lib 文件。然后这将根据解决方案非常快速地编译,然后您可以将它们全部链接在一起。构建一个指向所有函数的函数指针数组,然后通过查找来调用它。
result = SolveInterceptWhichStep;
将所有库合并成一个大库应该不会花费八个小时。如果需要那么长时间,那么你就做错了。
和...
尝试将代码放入不同的实际 .cpp 文件中。如果它们都在不同的单元等中,也许那个特定的编译器会做得更好......然后一旦每个单元都被编译,如果你不改变任何东西它就会保持编译状态。
关于c++ - 使用自动生成的 C 代码的大型 C++ dll 的性能损失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12313698/