[英]Performance penalty for large C++ dll's with autogenerated C code
我正在开发一个需要调用一系列优化求解器的软件。 每个解算器都是一个自动生成的C代码,有数千行代码。 我使用了200个这样的求解器,只是要解决的优化问题的大小不同。
总而言之,这些自动生成的解算器提供了大约180MB的C代码,我在Visual Studio 2008中使用extern "C"{ /*200 solvers' headers*/ }
语法编译为C ++。编译全部这非常慢(使用“最大速度/ O2”优化标志,大约需要8小时)。 出于这个原因,我认为将解算器编译成单个DLL是个好主意,然后我可以从一个单独的软件调用它(这将有一个合理的编译时间,并允许我抽象出所有这些extern“ C“来自更高级别代码的东西”。 编译后的DLL大约是37MB。
问题是当使用DLL执行这些解算器之一时,执行需要大约30ms。 如果我只将那个单个解算器编译成DLL,并从同一个程序调用它,那么执行速度大约快100倍(<1ms)。 为什么是这样? 我可以绕过吗?
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。 如果不是全部内联,那么这些建议可能会有所帮助。
你的解决方案可能会被...改进
A)1)将项目划分为200个独立的dll。 然后使用.bat文件或类似文件构建。 2)在每个名为“MyEntryPoint”的dll中创建导出函数,然后使用动态链接在需要时加载库。 这将相当于一个繁忙的音乐程序,加载了很多小的DLL插件。 使用GetProcAddress获取一个指向EntryPoint的函数指针。
要么...
B)将每个解决方案构建为单独的.lib文件。 然后,每个解决方案将非常快速地编译,然后您可以将它们全部链接在一起。 构建一个指向所有函数的函数指针数组,并通过查找来调用它。
result = SolveInterceptWhichStep;
将所有libs组合成一个大型lib不应该花费8个小时。 如果花了那么长时间,你就会做一些非常错误的事情。
和...
尝试将代码放入不同的实际.cpp文件中。 也许特定的编译器如果它们都在不同的单元等中会做得更好......然后一旦编译了每个单元,如果你没有改变任何东西,它将保持编译。
确保测量并平均多次调用优化器的时间,因为可能是在第一次调用之前设置有很大的开销。
然后还要检查200分支条件语句(您的开关)对您的性能做了什么! 尝试删除该开关进行测试,只调用测试项目中的一个解算器,但链接DLL中的所有解算器。 你还看到性能缓慢吗?
我假设您生成代码的原因是为了获得更好的运行时性能,以及更好的正确性。 我做同样的事情。
我建议你尝试这种技术来找出运行时性能问题。
如果您看到100:1的性能差异,这意味着每次中断它并查看程序的状态,您有99%的机会看到问题所在。
就构建时间而言,确定模块化是有意义的。 这些都不会对运行时间产生太大影响,除非它意味着你正在做疯狂的I / O.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.