Как изменить программу на C, чтобы gprof мог ее профилировать?

Когда я запускаю gprof в своей программе на языке C, он говорит, что не было накоплено времени для моей программы и отображается 0 раз для всех вызовов функций. Однако он подсчитывает вызовы функций.

Как мне изменить мою программу, чтобы gprof смог подсчитать, сколько времени требуется для запуска?

Ответ 1

Вы указывали -pg при компиляции?

http://sourceware.org/binutils/docs-2.20/gprof/Compiling.html#Compiling

Как только он скомпилирован, вы запустите программу, а затем запустите gprof в двоичном формате.

например:.

test.c:

#include <stdio.h>

int main ()
{
    int i;
    for (i = 0; i < 10000; i++) {
        printf ("%d\n", i);
    }
    return 0;
}

Скомпилируйте как cc -pg test.c, затем запустите его как a.out, затем gprof a.out, дайте мне

granularity: each sample hit covers 4 byte(s) for 1.47% of 0.03 seconds

  %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name    
 45.6       0.02     0.02    10000     0.00     0.00  __sys_write [10]
 45.6       0.03     0.02        0  100.00%           .mcount (26)
  2.9       0.03     0.00    20000     0.00     0.00  __sfvwrite [6]
  1.5       0.03     0.00    20000     0.00     0.00  memchr [11]
  1.5       0.03     0.00    10000     0.00     0.00  __ultoa [12]
  1.5       0.03     0.00    10000     0.00     0.00  _swrite [9]
  1.5       0.03     0.00    10000     0.00     0.00  vfprintf [2]

Что вы получаете?

Ответ 2

Я попытался запустить пример Kinopiko, но я увеличил число итераций в 100 раз.

test.c:

#include <stdio.h>

int main ()
{
    int i;
    for (i = 0; i < 1000000; i++) {
        printf ("%d\n", i);
    }
    return 0;
}

Затем я взял 10 stackshots (под VC, но вы можете использовать pstack). Вот стеки:

9 copies of this stack:
NTDLL! 7c90e514()
KERNEL32! 7c81cbfe()
KERNEL32! 7c81cc75()
KERNEL32! 7c81cc89()
_write() line 168 + 57 bytes
_flush() line 162 + 23 bytes
_ftbuf() line 171 + 9 bytes
printf() line 62 + 14 bytes
main() line 7 + 14 bytes
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817077()

1 copy of this stack:
KERNEL32! 7c81cb96()
KERNEL32! 7c81cc75()
KERNEL32! 7c81cc89()
_write() line 168 + 57 bytes
_flush() line 162 + 23 bytes
_ftbuf() line 171 + 9 bytes
printf() line 62 + 14 bytes
main() line 7 + 14 bytes
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817077()

Если это не очевидно, это говорит вам, что:

mainCRTStartup() line 206 + 25 bytes Cost ~100% of the time
main() line 7 + 14 bytes             Cost ~100% of the time
printf() line 62 + 14 bytes          Cost ~100% of the time
_ftbuf() line 171 + 9 bytes          Cost ~100% of the time
_flush() line 162 + 23 bytes         Cost ~100% of the time
_write() line 168 + 57 bytes         Cost ~100% of the time

Вкратце, программа тратит ~ 100% времени на сброс на диск (или консоль) выходного буфера как часть printf в строке 7.

(То, что я подразумеваю под "Стоимость строки", - это доля общего времени, затраченного на запрос этой строки, и это примерно доля проб, которые его содержат. Если бы эту линию можно было занять некоторое время, например, удалив ее, пропустив ее или пропустив ее работу до бесконечно быстрого сопроцессора, эта временная доля зависит от того, сколько будет сокращаться общее время. Поэтому, если можно избежать выполнения любой из этих строк кода, время будет сокращаться где-то в диапазоне от 95% до 100%. Если бы вы спросили: "Как насчет рекурсии?", Ответ Без разницы.)

Теперь, может быть, вы хотите узнать что-то еще, например, сколько времени потрачено в цикле, например. Чтобы узнать это, удалите printf, потому что он все время забивает. Возможно, вы хотите узнать, сколько процентов времени затрачено исключительно на процессорное время, а не на системные вызовы. Чтобы получить это, просто выбросьте любые стеки, которые не заканчиваются в вашем коде.

То, что я пытаюсь сделать, это если вы ищете то, что можете исправить, чтобы сделать код быстрее, данные gprof дают вам, даже если вы его понимаете, почти бесполезный. Для сравнения, если есть какой-то из вашего кода, который вызывает больше времени настенных часов, чем вы хотели бы, stackshots будут его определять.

Ответ 4

Сначала скомпилируйте приложение с помощью -g и проверьте, какие счетчики CPU вы используете. Если ваше приложение работает очень быстро, а gprof может просто пропустить все события или меньше требуемых (уменьшить количество событий для чтения).

Фактически профилирование должно показывать вам события CPU_CLK_UNHALTED или INST_RETIRED без каких-либо специальных переключателей. Но с такими данными вы сможете только сказать, насколько хорошо ваш код выполняет: INST_RETIRED/CPU_CLK_UNHALTED.

Попробуйте использовать профилировщик Intel VTune - он бесплатный в течение 30 дней и для обучения.