Как профилировать EXE и DLL, которые он загружал одновременно?
Я использую компилятор MinGW GCC на Windows. Если я добавлю ключ -pg к компилятору, я могу сгенерировать как EXE, так и DLL с данными профиля.
Gmon.out генерируется. Но проблема в том, что когда я использую
gprof myprogram.exe gmon.out
Я не получаю вывод профиля (кроме заголовков таблицы и другого текста).
gprof mydll.dll gmon.out
Я получаю вывод только для этой конкретной DLL, но не для основного EXE-файла.
Возможно, и exe, и dll захотели сгенерировать один и тот же файл, и dll победила.
Цель состоит в том, чтобы получить статистику для функций в EXE и DLL в одном выводе.
Может ли gprof сделать это? Если нет, есть ли инструмент, который может сделать это в Windows?
1 ответ
Кажется, gprof не может этого сделать. sprof недоступен в MinGw. Вот и прокатился мой собственный профилировщик.
я использовал -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. И функция в 0x691C83B9 в DLL действительно является неоптимальной функцией со сложностью O(n³) и вызывается много раз, я должен рефакторинг, что... Я полностью забыл, что эта функция даже существует... 0x004390F9 - это WinMain.