Profiling on Unix, Windows and WinCE

為什麼我們要作 Profiling?因為我們想要知道這個程式的 bottleneck 在哪?到底哪裡最花時間。當然,我們可以手動在每個程式的進入點和 return 前用 clock 紀錄,但是那實在是太繁複了,如果你的程式有五萬個 function,你就必須加入五萬次紀錄用的 funtion。

我想到之前 linda 有講過 gprof 是 GNU profiler。使用上並不困難,你只要在 gcc 的編譯參數加上 -pg,就能夠使編譯出的 binary 支援 profiling。但 library 呢?如果必須針對 library 作 profiling,那也必須在 library 編譯時加上 -pg。

就以 Standard C Library (libc, -lc) 而言,如果你要 libc 支援 profiling 的話,你就必須從原先的 -lc 改用 -lc_p,而其他的如 -lm 也該改用 -lm_p,如果有興趣的話,你可以去 /usr/lib 一窺究竟,到底還有哪些 library 有 _p 結尾。

就如同一般執行一樣。

./a.out # 在這個時候會產生 a.out.gmon
gprof a.out # 就會印出 profiling 相關的資訊,哪個 function 花的時間最久

但是,回到 Windows 來看,那要怎麼去作呢?

我在一開始所說,我們應該是在 function 的進入點以及離開的時候試圖去紀錄時間、這個 function 被呼叫了幾次這樣的資訊,那麼,有沒有比較簡單的方式可以做 (Hook) 到這件事情呢?

在 VC 的編譯選項當中,/Gh 和 /GH 分別代表 Enable _penter Hook Function,以及 Enable _pexit Hook Function。我們需要的只是適當的對 _penter 還有 _pexit 去作一些紀錄,紀錄 function 的一些資訊,以方便我們之後的分析。

雖然在 Embedded Visual C++ 可以用 cecap.lib 搭配 Remote Call Profiler,但是到了 Windows Mobile 5.0 與 Visual Studio 2005 的搭配上又發生了問題。土法煉鋼的作法像是 /fastcap 之後去寫 _CAP_Start_Profiling、_CAP_End_Profiling,就像之前 _penter 還有 _pexit 的狀況是一樣的。

但是,有沒有想過一個問題呢?我要怎麼從 _CAP_Start_Profiling 的 TargetProcAddr 轉成 function name 呢?而 Windows CE 上似乎又沒有 SymFromAddr 這樣的東西,結果就看到了 Resolving Symbols Manually on Windows CE (ADDRESS –> SYMBOL)

其實還有一些有趣的東西,像是 kprof,還有一些商用的 profiling tool,像是 AQTimeSpeedDemon Profiler

而故事似乎就說完了,但是研究(?)還是要繼續下去。

Leave a Reply

Your email address will not be published. Required fields are marked *