【源碼分析】動態分析 C 程式函數調用關係,源碼函數

來源:互聯網
上載者:User

【源碼分析】動態分析 C 程式函數調用關係,源碼函數

By Falcon of TinyLab.org
2015/04/15

緣由

源碼分析是程式員離不開的話題。無論是研究開源項目,還是平時做各類移植、開發,都避免不了對源碼的深入解讀。

工欲善其事,必先利其器。

之前已經介紹了如何通過 Callgraph 靜態分析原始碼,這裡介紹如何剖析器運行時的實際函數執行情況,考慮到應用部分和核心部分有比較大的差異,該篇先介紹應用部分。

主要介紹三款工具,一款是 gprof,另外一款是 valgrind,再一款則是能夠把前兩款的結果匯出為 dot 圖形的工具,叫 gprof2dot,它的功能有點類似於我們上次介紹的 tree2dotx

準備

需要事先準備好幾個相關的工具。

  • gprof2dot: converts the output from many profilers into a dot graph

    $ sudo apt-get install python python-pip$ sudo pip install gprof2dot
  • graphviz: dot 格式處理

    $ sudo apt-get install graphviz
  • gprof: display call graph profile data

    $ sudo apt-get install gprof
  • valgrind: a suite of tools for debugging and profiling programs

    $ sudo apt-get install valgrind

工具好了,再來一個典型的 C 程式,儲存為:fib.c

#include <stdio.h>int fibonacci(int n);int main(int argc, char **argv){    int fib;    int n;    for (n = 0; n <= 42; n++) {        fib = fibonacci(n);        printf("fibonnaci(%d) = %dn", n, fib);    }    return 0;}int fibonacci(int n){    int fib;    if (n <= 0) {        fib = 0;    } else if (n == 1) {        fib = 1;    } else {        fib = fibonacci(n -1) + fibonacci(n - 2);    }    return fib;}
gprof

Gprof 用於對某次應用的運行時代碼執行情況進行分析。

它需要對原始碼採用 -pg 編譯,然後運行:

$ gcc -pg -o fib fib.c$ ./fib

運行完以後,會產生一份記錄檔:

$ ls gmon.outgmon.out

可以分析之:

$ gprof -b ./fib | gprof2dot | dot -Tsvg -o fib-gprof.svg

查看 fib-gprof.svg 如下:

可以觀察到,這個圖表除了調用關係,還有每個函數的執行次數以及百分比。

Valgrind s callgrind

Valgrind 是開源的效能分析利器。它不僅可以用來檢查記憶體流失等問題,還可以用來產生函數的調用圖。

Valgrind 不依賴 -pg 編譯選項,可以直接編譯運行:

$ gcc -o fib fib.c$ valgrind --tool=callgrind ./fib

然後會看到一份記錄檔:

$ ls callgrind*callgrind.out.22737

然後用 gprof2dot 分析:

$ gprof2dot -f callgrind ./callgrind.out.22737 | dot -Tsvg -o fib-callgrind.svg

查看 fib-callgrind.svg 如下:

需要提到的是 Valgrind 提取出了比 gprof 更多的資訊,包括 main 函數的父函數。

不過 Valgrind 實際提供了更多的資訊,用 -n0 -e0 把執行百分比限制去掉,所有執行過的全部展示出來:

$ gprof2dot -f callgrind -n0 -e0 ./callgrind.out.22737 | dot -Tsvg -o fib-callgrind-all.svg

結果如下:

所有的調用情況都展示出來了。熱點調用分支用紅色標記了出來。因為實際上一個程式運行時背後做了很多其他的事情,比如動態符號連結,還有比如 main 實際代碼裡頭也調用到 printf,雖然佔比很低。

考慮到上述結果太多,不便於分析,如果只想關心某個函數的調用情況,以 main 為例,則可以:

$ gprof2dot -f callgrind -n0 -e0 ./callgrind.out.22737 --root=main | dot -Tsvg -o fib-callgrind-main.svg

需要提到的是,實際上除了 gprof2dotkcachegrind 也可以用來展示 Valgrind's callgrind 的資料:

$ sudo apt-get install kcachegrind$ kcachegrind ./callgrind.out.22737

通過 File --> Export Graph 可以匯出調用圖。只不過一個是圖形工具,一個是命令列,而且 kcachegrind 不能一次展示所有分支,不過它可以靈活逐個節點查看。

小結

上文我們展示了從運行時角度來分析源碼的實際執行路徑,目前只是深入到了函數層次。

結果上跟上次的靜態分析稍微有些差異。

  • 實際運行時,不同分支的調用次數有差異,甚至有些分支可能根本就執行不到。這些資料為我們進行效能最佳化提供了可以切入的熱點。
  • 實際運行時,我們觀察到除了代碼中有的函數外,還有關於 main 的父函數,甚至還有庫函數如 printf的內部調用細節,給我們提供了一種途徑去理解程式背後啟動並執行細節。

本文只是介紹到了應用程式部分(實際上是程式運行時的使用者空間),下回我們將分析,當某個應用程式執行時,哪些核心介面(系統調用)被調用到,那些介面的執行情況以及深入到核心空間的函數調用情況。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.