Linux C++ 開發9 - 手把手教你使用gprof效能分析工具

陌尘(MoChen)發表於2024-09-23
  • 1. 什麼是gprof?
  • 2. gprof的用法
    • 2.1. 編譯程式
    • 2.2. 執行程式
    • 2.3. 生成分析報告
    • 2.4. gprof常用引數說明
    • 2.5. 分析報告解讀
      • 2.5.1. Flat profile 各個欄位的含義
      • 2.5.2. Call graph 各個欄位的含義
  • 3. Demo演示
    • 3.1. demo04.cpp 原始碼
    • 3.2. 編譯、執行和分析
    • 3.3. 檢視分析報告

1. 什麼是gprof?

gprof 這是一個GNU的效能分析工具,它是GCC(GNU Compiler Collection,GNU編譯器套件)的一部分,與GCC編譯器緊密整合。可用於分析程式的函式呼叫關係和每個函式的執行時間。它透過在編譯時插入效能分析程式碼來收集函式呼叫資訊和執行時間,來幫助開發者識別效能瓶頸。

gprof的優點:

  • 可以方便的分析程式的函式呼叫關係和每個函式的執行時間。
  • gprof對於程式碼大部分是使用者空間的CPU密集型的程式用處明顯。

gprof的缺點:

  • 對於大部分時間執行在核心空間或者由於外部因素(例如作業系統的 I/O 子系統過載)而執行得非常慢的程式難以進行最佳化。
  • gprof預設不支援多執行緒程式。(gprof採用ITIMER_PROF訊號,在多執行緒內只有主執行緒才能響應該訊號)
  • 預設不支援共享庫程式。

2. gprof的用法

2.1. 編譯程式

首先,需要使用 -pg 選項編譯你的程式:

g++ -pg -o my_program my_program.cpp

除了-pg外,還有一個引數-p,它可以生成適合prof效能分析工具的程式碼,他們之間的區別如下:

  • -p: 可以生成適合prof效能分析工具的程式碼。
  • -pg: 可以生成適合gprof效能分析工具的程式碼,也就是profile information for gprof的含義。

要理解上面描述,又不得不瞭解profgprof兩個工具的關係了。

  • prof是一個較早的效能分析工具,最初在UNIX系統上使用。編譯時加上-p選項,生成的可執行檔案會在執行時收集效能分析資料。然後透過prof工具再生成效能分析報告。
  • gprof是GNU專案的一部分,是一個更現代的效能分析工具,它的功能與prof類似,但比prof提供了更多的功能和更好的使用者體驗。而且程式執行時輸出的效能分析資料也更豐富、詳細。現在gprof幾乎取代了prof

2.2. 執行程式

編譯完成後,執行你的程式:

./my_program

執行過程中,gprof 會生成一個名為 gmon.out 的檔案,其中包含了效能分析資料。

2.3. 生成分析報告

執行完程式後,使用 gprof 工具生成分析報告:

gprof my_program gmon.out > analysis_report.txt

生成的 analysis_report.txt 檔案中包含了函式的呼叫時間、呼叫次數等詳細資訊。

2.4. gprof常用引數說明

gprof命令格式:

gprof [options] [executable-file [profile-data-files…]] [> outputfile] Gprof命令列格式 Gprof command line format

options引數說明:

命令 中文解釋 英文解釋
-b 簡潔輸出,不顯示冗長的解釋 Brief output. Do not display verbose explanations
-s 將多個gmon.out檔案合併 Summarize: merge several profile data files for cumulative stats
-p 顯示程式的每個函式的執行時間統計 Display program’s functions execution time statistics
-q 顯示程式的每個函式的呼叫關係 Display program’s

2.5. 分析報告解讀

gprof 生成的報告通常包含以下幾個部分:

  • Flat profile: 顯示每個函式的執行時間、呼叫次數等資訊。
  • Call graph: 顯示函式之間的呼叫關係和每個函式的執行時間。

2.5.1. Flat profile 各個欄位的含義

欄位 含義
% time 該函式消耗時間佔程式所有時間百分比
Cumulative seconds 程式的累積執行時間(只是包括gprof能夠監控到的函式)
Self Seconds 該函式本身執行時間(所有被呼叫次數的合共時間)
Calls 函式被呼叫次數
Self TS/call 函式平均執行時間(不包括被呼叫時間,函式的單次執行時間)
Total TS/call 函式平均執行時間(包括被呼叫時間,函式的單次執行時間)
name 函式名

2.5.2. Call graph 各個欄位的含義

欄位 含義
Index 索引值
%time 函式消耗時間佔所有時間百分比
Self 函式本身執行時間
Children 執行子函式所用時間
Called 被呼叫次數
Name 函式名

3. Demo演示

3.1. demo04.cpp 原始碼

#include <iostream>

int64_t add(int64_t a, int64_t b)
{
    return a + b;
}

void func1()
{
    int sum = 0;
    for (int i = 0; i < 1000000; ++i)
    {
        sum = add(sum, i);
    }
    std::cout << "Sum of 0 to 999999 is " << sum << std::endl;
}

void func2()
{
    int sum = 0;
    for (int i = 0; i < 500000; ++i)
    {
        sum = add(sum, i);
    }
    std::cout << "Sum of 0 to 499999 is " << sum << std::endl;
}

int main()
{
    func1();
    func2();
    return 0;
}

3.2. 編譯、執行和分析

# 編譯程式
g++ -pg ./demo04.cpp -o ./demo04.out
# 執行程式
./demo04.out
# 生成分析報告
gprof ./demo04.out ./gmon.out > analysis_report04.txt
# 也可以使用下面的命令,生成的報告更加簡潔,沒有冗餘資訊
gprof -b ./demo04.out ./gmon.out > analysis_report04.txt

3.3. 檢視分析報告

開啟analysis_report04.txt,可以看到類似如下的輸出:

Flat profile:

Each sample counts as 0.01 seconds.
 no time accumulated

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  Ts/call  Ts/call  name    
  0.00      0.00     0.00  1500000     0.00     0.00  add(long, long)
  0.00      0.00     0.00        1     0.00     0.00  func1()
  0.00      0.00     0.00        1     0.00     0.00  func2()

...

Call graph (explanation follows)


granularity: each sample hit covers 4 byte(s) no time propagated

index % time    self  children    called     name
                0.00    0.00  500000/1500000     func2() [10]
                0.00    0.00 1000000/1500000     func1() [9]
[8]      0.0    0.00    0.00 1500000         add(long, long) [8]
-----------------------------------------------
                0.00    0.00       1/1           main [6]
[9]      0.0    0.00    0.00       1         func1() [9]
                0.00    0.00 1000000/1500000     add(long, long) [8]
-----------------------------------------------
                0.00    0.00       1/1           main [6]
[10]     0.0    0.00    0.00       1         func2() [10]
                0.00    0.00  500000/1500000     add(long, long) [8]
-----------------------------------------------

...

Index by function name

   [8] add(long, long)         [9] func1()                [10] func2()

透過這些資訊,可以清楚地看到 func1 和 func2 的執行時間和呼叫次數,從而進行針對性的最佳化。

歷史文章推薦:

  • Linux C++ 開發10 - 手把手教你使用valgrind效能分析工具

  • Linux C++ 開發9 - 手把手教你使用gprof效能分析工具

  • Linux C++ 開發8 - 效能分析工具彙總

  • Linux C++ 開發7 - GDB常用命令彙總

  • Linux C++ 開發6 - GDB除錯入門指南

  • Linux C++ 開發5 - 一文了解CMake構建

  • Linux C++ 開發4 - 入門makefile一篇文章就夠了

  • Linux C++ 開發3 - 你寫的Hello world經過哪些過程才被計算機理解和執行?

  • Linux C++ 開發2 - 編寫、編譯、執行第一個程式

  • VSCode系列2 - 如何用VSCode搭建C++高效開發環境?

  • Linux C++ 開發1 - 搭建C++開發環境


大家好,我是陌塵。

IT從業10年+, 北漂過也深漂過,目前暫定居於杭州,未來不知還會飄向何方。

搞了8年C++,也幹過2年前端;用Python寫過書,也玩過一點PHP,未來還會折騰更多東西,不死不休。

感謝大家的關注,期待與你一起成長。



【SunLogging】
Linux C++ 開發9 - 手把手教你使用gprof效能分析工具
掃碼二維碼,關注微信公眾號,閱讀更多精彩內容

相關文章