2014-12-28 22 views
0

我在Windows上使用MinGW GCC編譯器。如果我添加-pg切換到編譯器,我可以使用配置文件數據生成EXE和DLL。如何分析一個EXE和它在同一時間加載的DLL?

gmon.out生成。但問題是,當我使用

gprof myprogram.exe gmon.out 

我沒有得到任何的個人資料輸出(比表格標題和其他文本等)。

gprof mydll.dll gmon.out 

我只得到該特定DLL的輸出,但不是主要的exe。

也許exe和dll都希望生成相同的文件並獲得dll。

目標是在一個輸出中獲取EXE和DLL中函數的統計信息。

gprof能做到嗎?如果沒有,有什麼工具可以在Windows上做到這一點?

回答

0

看來gprof不能這樣做。 MinGw中不提供sprof。所以推出了我自己的分析器。

我用-finstrument-functions所以兩個函數__cyg_profile_func_enter__cyg_profile_func_exit將分別在每個函數之前和之後調用。

實際的分析函數被導出到一個DLL中並在這些函數中調用,並且該DLL被鏈接到所討論的所有EXE和DLL。因此它可以分析他們兩個

庫中的代碼是這樣的(刪除混亂:斷言,錯誤檢查,簡化函數調用爲清晰)。

static void proflib_init() 
{ 
    atexit(proflib_finalize); 

    empty(callstack); 
    empty(trackingData); 
    proflibIntialized = 1; 
} 

static void proflib_finalize() 
{ 
    /* Make a log. */ 
    FILE *f = fopen("proflib_log.txt", "wt"); 
    int i; 

    sortBySelftime(trackingData); 

    fprintf(f, "%10s%15s%15s%15s\n", "Func name", "Cumulative", "Self time", "Count"); 
    for (i = 0; i < getlength(trackingData); i++) 
    { 
     FunctionTimeInfo *fri = trackingData[i]; 

     fprintf(f, "%10p%15"PRIu64"%15"PRIu64"%20d\n", fri->addr, fri->cumulative, fri->selfTime, fri->count); 
    } 

    fclose(f); 
} 

void proflib_func_enter(void *func, void *caller) 
{ 
    FunctionTimeInfo elem; 
    long long pc; 

    pc = rdtsc(); /* Read timestamp counter from CPU. */ 

    if (!is_prolib_initialized()) 
    { 
     proflib_init(); 
    } 

    /* Register self time as control moves to the child function. */ 
    if (!isEmpty(callstack)) 
    { 
     FunctionTimeInfo *top = gettop(callstack); 

     top->selfTime += pc - top->selfSample; 
    } 

    elem.addr = func; /* Address of function. */ 
    elem.cumulative = pc; /* Time spent in function and functions called by this. (so far store the reference point only.)*/ 
    elem.selfSample = pc; /* Reference point for self time counting. */ 
    elem.count = 1; /* Number of this the function is counted. */ 
    elem.selfTime = 0; /* Time spent in the function not including called functions. */ 

    push(callstack, elem); 
} 

void proflib_func_exit(void *func, void *caller) 
{ 
    FunctionTimeInfo *fti; 
    FunctionTimeInfo *storedStat; 
    long long pc; 

    pc = rdtsc(); 

    fti = gettop(callstack); 

    fti->cumulative = pc - fti->cumulative; /* Finalize the time. */ 
    fti->selfTime += pc - fti->selfSample; 
    pop(callstack); 

    { 
     FunctionTimeInfo *top = gettop(callstack); 

     top->selfSample = pc; /* Set new self reference for the parent. */ 
    } 

    storedStat = find(trackingData, func); 

    if (storedStat) 
    { 
     /* Already have an entry. */ 
     storedStat->cumulative += fti->cumulative; 
     storedStat->selfTime += fti->selfTime; 
     storedStat->count++; 
    } 
    else 
    { 
     /* Add it as new entry. */ 
     add(trackingData, fti); 
    } 
} 

而且它產生的日誌是這樣的:

Func name  Cumulative  Self time   Count 
    691C83B9 1138235861408 1138235861408    1137730 
    00416396 539018507364 539018507364   16657216 
    0040A0DC 259288775768 199827541522    1914832 
    0041067D 876519599063 163253984165   92203200 
    691C9E0E 785372027387 150744125859    190020 
    004390F9 3608742795672 149177603708     1 
    0042E6A4 141485929006 116938396343    37753 
    00428CB8 456357355541 112610168088    193304 
    0041C2A4 340078363426 84539535634   114437798 
    691CB980 402228058455 82958191728    29675 
    00408A0A 79628811602 77769403982    512220 
    0040D8CD 93610151071 63396331438   87773597 
    0040D91A 60276409516 60276409516   175547194 
    00427C36 72489783460 58130405593     1 
    691C7C3D 56702394950 56702394950    3455819 
    691C949F 101350487028 47913486509    2977100 
    691CBBF3 241451044787 45153581905    29771 
    0043702E 920148247934 41990658926    25612 
    ... 

的函數名稱可以從MAP文件中找到了。而DLL中0x691C83B9的函數實際上是一個次優函數,具有O(n³)的複雜性,並且被稱爲很多次,我必須重構該函數......我完全忘記了該函數甚至存在... 0x004390F9是WinMain。

+0

您也可以使用'GDB',使用Ctrl-C和'bt' 10次,並且您會在棧上看到該例程大約3次,告訴您它佔了大約33%的時間。您還將看到它的參數是什麼,例程中的哪些代碼行佔用了該時間,哪些代碼行通常從中調用,等等。這可以告訴你如何減少時間。也許論證有時是相同的。也許它被稱爲比必要的更頻繁。也許它的內部代碼可能被展開或者其他東西。少量的詳細樣本可以爲您提供更多信息。 –

+0

@MikeDunlavey有問題的功能導致零星的微凍死。這是一個GUI應用程序,一個遊戲。當你處於全屏遊戲中的行動中時,你不能簡單地在GDB中使用Ctrl-C。 – Calmarius

+0

如果你真的有問題,你會不會介意暫停遊戲找到它,是嗎?無論如何,如果這種情況只是偶爾發生在逐幀圖像中,那麼這種方式有一種笨拙而有效的方式。它是安排一個看門狗定時器,它只會在幀的運行時間超過N ms時中斷。在那裏設置一個斷點,當它觸發時,堆棧應該告訴你爲什麼需要額外的時間。 –

相關問題