2012-09-07 56 views
4

我正在研究需要调用一组优化求解器的软件。每个求解器都是一段自动生成的C代码,包含数千行代码。我使用了200个这样的解算器,仅在要解决的优化问题的大小上有所不同。总而言之,这些自动生成的求解器大约有180MB的C代码,我在Visual Studio 2008中使用extern "C"{ /*200 solvers' headers*/ }语法编译为C++。编译所有这些都非常慢(“最大值速度/ O2“优化标志,大约需要8小时)。出于这个原因,我认为将解算器编译成单个DLL是个好主意,然后我可以从一个单独的软件中调用它(这将具有合理的编译时间,并且允许我抽象出所有这个extern“ C“来自更高级代码的东西)。编译后的DLL大约为37MB。大C++ dll的自动生成C代码的性能损失

问题是,当使用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*) &params, (optim_001_output*) optimSoln, (optim_001_info*) &infoOut); 
    break; 
    case 2: 
    exitFlag = optim_002_solve((optim_002_params*) &params, (optim_002_output*) optimSoln, (optim_002_info*) &infoOut); 
    break; 
    /* 
    ... 
    etc. 
    ... 
    */ 
    case 200: 
    exitFlag = optim_200_solve((optim_200_params*) &params, (optim_200_output*) optimSoln, (optim_200_info*) &infoOut); 
    break; 
    } 

    return exitFlag; 
}; 

}; 
+0

你在哪个平台上观察过?在32位体系结构的Linux上,'.so'文件需要'-fPIC'来占用一个寄存器,因此代码运行速度可能会慢5%(因为编译器溢出了更多)。 –

+1

提到Visual Studio和DLL,它说Windows。 – themel

+0

@Basile,themel:是的,它全部在Windows上,使用VS2008编译。 – mwmwm

回答

1

我不知道你的代码是否内联到示例中的每个case部分。如果你的函数是内联函数,并且你把它全部放在一个函数中,那么它会慢得多,因为代码被放置在虚拟内存中,随着代码的执行,这将需要大量的CPU跳转。如果不是全部内联,那么这些建议可能会有所帮助。

您的解决方案可能是由...

A) 1得到改善)将项目分成200倍单独的DLL。然后用.bat文件或类似文件构建。 2)在每个dll中创建名为“MyEntryPoint”的导出函数,然后根据需要使用动态链接加载库。这将是一个繁忙的音乐程序,加载了很多小dll插件。用GetProcAddress函数指针指向EntryPoint。

或...

B)将每个解决方案构建为单独的.lib文件。然后,这将根据解决方案快速编译,然后您可以将它们链接在一起。为所有函数构建一个函数指针数组,然后通过lookup调用它。

result = SolveInterceptWhichStep;

将所有的libs合并成一个大的lib应该不需要8个小时。如果需要那么长时间,那么你做的事情是非常错误的。

AND ...

尝试把代码放到不同的实际.cpp文件。也许这个特定的编译器如果它们全都在不同的单元中,它们会做得更好......然后一旦每个单元被编译完成,如果你不改变任何东西,它将保持编译。

0

确保你测量和平均时间多次调用优化,因为这可能是因为有一个大的开销,以第一次调用之前的设置。

然后还要检查200分条件语句(您的开关)对您的性能做了什么!尝试消除该测试开关,在测试项目中调用一个解算器,但将它们全部链接到DLL中。你仍然看到表现缓慢?

+0

我的平均通话量超过100次,但第一次通话似乎没有明显差异。我会尝试链接所有的求解器,但是要移除开关 - 不幸的是,这个测试将涉及整个项目的编译/代码生成,所以需要一天的时间来完成。 – mwmwm

0

我假设您生成代码的原因是为了获得更好的运行时性能以及更好的正确性。 我做同样的事情。

我建议您尝试this technique以了解运行时性能问题。

如果您看到100:1的性能差异,这意味着每次中断它并查看程序状态时,您将有99%的机会看到问题所在。

就构建时间而言,确保将模块化是有意义的。 这些都不会对运行时间产生太大影响,除非这意味着您正在执行疯狂的I/O操作。