簡體   English   中英

使用Visual Studio Compiler分析內聯C ++函數

[英]Profiling inlined C++ functions with Visual Studio Compiler

當大量代碼被編譯器內聯時,我怎樣才能理解Windows上的C ++分析數據? 即我當然想要測量實際運行的代碼,因此根據定義,我將測量代碼的優化構建。 但似乎我嘗試實際設法解決內聯函數的工具都沒有。

我已經嘗試過Visual Studio 2017 Professional和VTune 2018中的采樣分析器。我嘗試啟用/Zo ,但它似乎沒有任何影響。

我發現以下資源似乎表明只有Visual Studio Ultimate或Premium支持內聯框架信息 - 這仍然適用於Visual Studio 2017嗎? https://social.msdn.microsoft.com/Forums/en-US/9df15363-5aae-4f0b-a5ad-dd9939917d4c/which-functions-arent-pgo-optimized-using-profile-data?forum=vsdebug

這是一個示例代碼:

#include <cmath>
#include <random>
#include <iostream>

inline double burn()
{
    std::uniform_real_distribution<double> uniform(-1E5, 1E5);
    std::default_random_engine engine;
    double s = 0;
    for (int i = 0; i < 100000000; ++i) {
        s += uniform(engine);
    }
    return s;
}

int main()
{
    std::cout << "random sum: " << burn() << '\n';
    return 0;
}

在發布模式下使用Visual Studio編譯它。 或者在命令行上,嘗試cl /O2 /Zi /Zo /EHsc main.cpp 然后嘗試使用Visual Studio中的CPU Sampling Profiler對其進行配置。 你最多會看到這樣的事情:

由於缺少內聯框架,導致配置文件混亂

VTune 2018在Windows上看起來很相似。 在Linux上,perf和VTune顯示來自內聯函數的幀沒有問題...這個功能,在我看來對C ++工具至關重要,真的不是非Premium / Ultimate Visual Studio工具鏈的一部分嗎? Windows上的人們如何處理這個問題? 那么/Zo什么意義呢?

編輯:我只是嘗試用clang編譯上面的最小例子,它產生不同的,但仍然不滿意的結果? 我編譯了clang 6.0.0(trunk),從LLVM rev 318844和clang rev 318874構建。然后我用clang++ -std=c++17 -O2 -g main.cpp -o main.exe編譯我的代碼並運行結果再次使用Visual Studio中的Sampling Profiler執行,結果是:

在使用clang編譯后,內聯框架顯示在配置文件中

所以現在我看到了burn功能,但丟失了源文件信息。 此外, uniform_real_distribution仍然沒有在任何地方顯示。

編輯2:正如意見建議,我現在也嘗試了clang-cl用的相同的參數cl之上,即: clang-cl.exe /O2 /Zi /Zo /EHsc main.cpp 這產生與clang.exe相同的結果,但我們也得到了一些有效的源映射:

clang-cl顯示內聯和一些功能源映射

編輯3:我原本以為clang會神奇地解決這個問題。 遺憾的是,它沒有。 大多數內聯框架仍然缺失:(

編輯4: VTune中不支持內聯框架,用於使用MSVC / PDB版本構建的應用程序: https//software.intel.com/en-us/forums/intel-vtune-amplifier-xe/topic/749363

我已經嘗試過Visual Studio 2017 Professional和VTune 2018中的采樣分析器。我嘗試啟用/ Zo,但它似乎沒有任何影響。

我發現以下資源似乎表明只有Visual Studio Ultimate或Premium支持內聯框架信息 - 這仍然適用於Visual Studio 2017嗎?

幸運的是,我已經安裝了三個不同版本的VS. 我可以告訴您有關內聯函數信息功能支持的更多信息,如您引用的文章中所述:

  • 即使我指定/ d2Zi +,VS Community 2013 Update 5也不支持顯示內聯函數。 它似乎只在VS 2013 Premium或Ultimate中得到支持。
  • VS社區2015更新3確實支持表示內聯函數(在所討論的特征的文章 )。 默認情況下,指定/ Zi。 / Zo使用/ Zi隱式啟用 ,因此您不必明確指定它。 因此,您不需要VS 2015 Premium或Ultimate。
  • 帶有最新更新的VS Community 2017不支持顯示內聯功能,無論/ Zi和/ Zo如何。 它似乎僅在VS 2017 Professional和/或Enterprise中受支持。

VC ++博客上沒有關於VS 2017采樣分析器的任何改進的公告,所以我認為與VS Community 2015的分析器相比沒有任何改進。

請注意,編譯器的不同版本可能會做出不同的優化決策。 例如,我觀察到VS 2013和2015沒有內聯burn功能。

通過使用VS Community 2015 Update 3,我得到的分析結果與第三張圖片中顯示的結果非常相似,並突出顯示相同的代碼。

現在,我將討論在解釋分析結果時這些附加信息如何有用,如何通過更多工作手動獲得這些信息,以及如何在內聯函數的情況下解釋結果。

當大量代碼被編譯器內聯時,我怎樣才能理解Windows上的C ++分析數據?

VS剖析器僅將成本歸因於未內聯的函數。 對於內聯函數,成本將被累加並包含在一些未內聯的調用函數中(在本例中為burn函數)。

通過將來自burn的非內聯調用函數的估計執行時間相加(如圖所示),得到31.3 + 22.7 + 4.7 + 1.1 = 59.8%。 此外,如圖所示, Function Body的估計執行時間為40.2%。 請注意,59.8%+ 40.2%= 100%的burn時間,應該是這樣。 換句話說,在burn中花費的時間的40.2%花費在函數的主體中以及在其中內嵌的任何函數中。

40.2%是很多。 下一個合乎邏輯的問題是,哪些函數在burn被內聯? 通過使用我之前討論過的功能(可在VS Community 2015中獲得),我可以確定在burn中內聯了以下功能:

std::mersenne_twister_engine<unsigned int,32,624,397,31,2567483615,11,4294967295,7,2636928640,15,4022730752,18,1812433253>::{ctor};
std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>::{ctor};
std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>::seed;
std::uniform_real<double>::operator();
std::uniform_real<double>::_Eval;
std::generate_canonical;

如果沒有該功能,則必須手動反匯編發出的可執行二進制文件(使用VS調試器或使用dumpbin )並找到所有x86 call指令。 通過將其與源代碼中調用的函數進行比較,您可以確定內聯哪些函數。

此時,VS采樣分析器的功能(包括VS 2017)將結束。 但這確實不是一個重要的限制。 通常,由於編譯器對每個函數的大小施加了硬上限,因此在同一函數中沒有很多函數被內聯。 因此,通常可以手動檢查每個內聯函數的源代碼和/或匯編代碼,並查看該代碼是否會顯着影響執行時間。 我做到了這一點,很可能是burn體(不包括內聯函數)和這兩個內聯函數主要負責40.2%。

std::mersenne_twister<unsigned int,32,624,397,31,2567483615,11,7,2636928640,15,4022730752,18>::seed;
std::uniform_real<double>::_Eval;

綜合考慮所有這些因素,我在這里看到的唯一潛在優化機會就是記住log2的結果。

VTune采樣分析器肯定比VS采樣分析器更強大。 特別是,VTune將成本歸因於各個源代碼行或匯編指令。 但是,這種歸因非常接近並且通常是荒謬的。 所以在解釋以這種方式可視化的結果時我會非常小心。 我不確定VTune是否支持增強優化調試信息,或者它支持在何種程度上支持內聯函數的成本。 提出這些問題的最佳地點是英特爾VTune Amplifier社區論壇

我不確定我是否理解你問題中描述的問題。 在您的網站上,我會嘗試使用/ Ob0 Visual C ++編譯器選項。 它必須禁用內聯擴展。

/ Ob編譯器選項控制函數的內聯擴展。 它必須跟隨數字0,12。

0禁用內聯擴展。 默認情況下,編譯器會根據所有函數自行決定擴展,通常稱為自動內聯。

1僅允許擴展標記為inline,__ inline或__forceinline的函數,或者擴展為類聲明中定義的C ++成員函數。

2默認值。 允許擴展標記為內聯,__ inline或__forceinline的函數,以及編譯器選擇的任何其他函數。

當使用/ O1/ O2 (最小化尺寸,最大化速度)或/ Ox (啟用最高速度優化)時, / Ob2有效。

此選項要求您使用/ O1/ O2/ Ox/ Og啟用優化。

在Visual Studio開發環境中設置此編譯器選項

  1. 打開項目的“屬性頁”對話框。 有關詳細信息,請參閱使用項目屬性。
  2. 展開“配置屬性”,“C / C ++”,然后選擇“優化”。
  3. 修改內聯函數擴展屬性。

在此輸入圖像描述

有關更多信息,請閱讀文章/ Ob(內聯函數擴展)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM