2012-09-07 57 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操作。