* Первичная строка:: Описание содержимого первичной строки.
* Вызывающие:: Описание содержимого строк вызывающих функций.
* Подпрограммы:: Описание содержимого строк вызываемых функций.
* Циклы:: Описание взаимно-рекурсивных функций, таких, как
`a' вызывает `b', а `b' вызывает `a'.
"Первичная строка" каждой записи описывает функцию, к которой относится эта запись и представляет общую статистику для этой функции.
Для изучения мы повторим первичную строку записи для функции `report' из вышеприведенного примера, вместе со строками заголовков, содержащих имена полей:
index % time self children called name
...
[3] 100.0 0.00 0.05 1 report [3]
Что же означают поля в первичной строке:
Записи нумеруются последовательными целыми числами. Поэтому каждая функция имеет индексный номер, указываемый в начале первичной строки ее записи.
Любая перекрестная ссылка на функцию, будь то вызывающая или вызываемая, содержит индекс функции, так же, как и ее имя. Индекс поможет вам отыскать запись для этой функции.
Это процент от общего времени исполнения вашей программы, затраченный на выполнение этой функции и вызванных из нее подпрограмм.
Время, затраченное на эту функцию, также подсчитывается для функций, вызвавших данную. Следовательно, простое суммирование этих процентов лишено всякого смысла.
Это количество секунд выполнения, подсчитанных только для этой функции. Оно должно быть идентично числу, указанному в поле `собственных секунд' в простом профиле для этой функции.
Это количество секунд выполнения, подсчитанных только для вызванных этой функцией подпрограмм. Оно должно быть идентично сумме `собственных секунд' и `секунд в подпрограммах' для всех укзанных ниже вызываемых функций [в этой записи].
Это общее количество вызовов этой функции--сколько раз она была вызвана.
Если эта функция вызывает себя рекурсивно, то будут указаны два числа, разделенные `+'. Первое число показывает количество нерекурсивных вызовов, а второе--рекурсивных.
В вышеприведенном примере функция `report' была один раз вызвана из функции `main'.
Это имя текущей функции. Индексный номер повторяется после него.
Если функция является частью цикла взаимной рекурсии, то номер цикла выводится между именем функции и индексным номером (*См. Циклы::). Например, если функция `gnurr'--часть цикла номер один и имеет индекс `двенадцать', то первичная строка ее записи будет завершена так:
gnurr <cycle 1> [12]
Запись функции содержит строку для каждой функции, которая вызывала данную. Их поля соответствуют полям в первичной строке, но смысл их отличен из-за различий в содержании.
Для изучения мы повторим две строки из записи для функции `report'--первичную строку и одну из предшествующих строк вызывающей функции, вместе со строками заголовков, содержащих имена полей:
index % time self children called name
...
0.00 0.05 1/1 main [2]
[3] 100.0 0.00 0.05 1 report [3]
Что же означают поля в строке вызывающей функции (для `report',
вызванной из `main'):
Оценка времени, потраченного самой функцией `report', когда она была вызвана из функции `main'.
Оценка времени, потраченного подпрограммами функции `report', когда `report' была вызвана из функции `main'.
Сумма `собственных секунд' и `секунд в подпрограммах' является приблизительной оценкой времени выполнения `report', вызываемой из `main'.
Два числа: количество вызовов `report' из `main', за которым следует общее количество нерекурсивных вызовов `report' изо всех функций, которые ее вообще вызывали.
Имя функции, вызвавшей `report', к которой относится эта строка, и следом указан индекс этой функции.
Не все функции имеют записи в графе вызовов; некоторые из опций `gprof' требуют пропустить некоторые функции. Если вызывающая функция не имеет записи о себе, она, тем не менее, имеет строку вызывающей функции в записях тех функций, которые она вызывает.
Если вызывающая функция является частью рекурсивного цикла, то номер цикла выводится между именем и индексным номером.
Запись функции содержит по строке на каждую из ее подпрограмм - другими словами, по строке на каждую другую функцию, которую она вызывает. Их поля соответствуют полям в первичной строке, но смысл их отличен из-за различий в содержании.
Для изучения мы повторим две строки из записи для функции `main'-- первичную строку и одну из последующих строк вызванной ею функции, вместе со строками заголовков, содержащих имена полей:
index % time self children called name
...
[2] 100.0 0.00 0.05 1 main [2]
0.00 0.05 1/1 report [3]
Что же означают поля в строке вызванной функции (для `main',
вызывающей `report'):
Оценка времени, потраченного самой функцией `report', когда она была вызвана из функции `main'.
Оценка времени, потраченного подпрограммами функции `report', когда `report' была вызвана из функции `main'.
Сумма `собственных секунд' и `секунд в подпрограммах' является приблизительной оценкой времени выполнения `report', вызываемой из `main'.
Два числа: количество вызовов `report' из `main', за которым следует общее количество нерекурсивных вызовов `report'.
Имя функции, вызванной из `main', к которой относится эта строка, и следом указан индекс этой функции.
Если вызывающая функция является частью рекурсивного цикла, то номер цикла выводится между именем и индексным номером.
Картина может быть осложнена наличием "циклической рекурсии" в графе вызовов. Цикл возникает, когда некоторая функция вызывает другую функцию, которая (прямо или опосредованно) вызывает (или пытается это сделать) первую. Например, если `a' вызывает `b', а затем `b' вызывает `a', то `a' и `b' организуют циклическую рекурсию.
Когда бы вызовы ни прошли по обоим путям между двумя функциями, они принадлежат к одному и тому же циклу. Если `a' и `b' вызывают друг друга, и `b' и `c' вызывают друг друга, то все три функции находятся в одном и том же цикле. Однако следует заметить, что даже если только `b' вызывает `a', но при этом сама не была вызвана из `a', то `gprof' не способен распознать это, и, таким образом, `a' и `b' все же считаются в цикле.
Циклы нумеруются последовательными целыми числами. Если функция принадлежит циклу, всякий раз, когда ее имя встречается в графе вызовов, за ним следует `<cycle NUMBER>' (`<цикл НОМЕР>')
Циклы создают проблему, заключающуюся в том, что циклы делают парадоксальными значения времен в графе вызовов. Поле `время в подпрограммах' для `a' должно включать в себя время, затраченное на вызываемую `b' и все ее подпрограммы--но одной из подпрограмм `b' является `a'! А сколько времени выполнения `a' должно быть включено во `время в подпрограммах' функции `a', если `a' непосредственно рекурсивна?
Спсоб, которым `gprof' разрешает этот парадокс, заключается в создании простой записи для цикла как для единого целого. Первичная строка этой записи описывает общее время, затраченное на непосредственное выполнение функций цикла. "Подпрограммами" цикла являются отдельные его функции, а также все вызываемые из них функции. "Вызывающими" функциями для цикла являются такие функции, которые не входят в сам цикл, но вызывают функции цикла.
Вот пример части графа вызовов, в котором показан цикл, содержащий функции `a' и `b'. Цикл начинался вызовом `a' из `main'; обе, `a' и `b', вызывали `c'.
index % time self children called name
----------------------------------------
1.77 0 1/1 main [2]
[3] 91.71 1.77 0 1+5 <cycle 1 as a whole> [3]
1.02 0 3 b <cycle 1> [4]
0.75 0 2 a <cycle 1> [5]
----------------------------------------
3 a <cycle 1> [5]
[4] 52.85 1.02 0 0 b <cycle 1> [4]
2 a <cycle 1> [5]
0 0 3/6 c [6]
----------------------------------------
1.77 0 1/1 main [2]
2 b <cycle 1> [4]
[5] 38.86 0.75 0 1 a <cycle 1> [5]
3 b <cycle 1> [4]
0 0 3/6 c [6]
----------------------------------------
(Полный граф вызовов для этой программы содержит также запись для
`main', которая вызывает `a', и запись для `c', которую вызывают `a' и
`b').
index % time self children called name
<spontaneous>
[1] 100.00 0 1.93 0 start [1]
0.16 1.77 1/1 main [2]
----------------------------------------
0.16 1.77 1/1 start [1]
[2] 100.00 0.16 1.77 1 main [2]
1.77 0 1/1 a <cycle 1> [5]
----------------------------------------
1.77 0 1/1 main [2]
[3] 91.71 1.77 0 1+5 <cycle 1 as a whole> [3]
1.02 0 3 b <cycle 1> [4]
0.75 0 2 a <cycle 1> [5]
0 0 6/6 c [6]
----------------------------------------
3 a <cycle 1> [5]
[4] 52.85 1.02 0 0 b <cycle 1> [4]
2 a <cycle 1> [5]
0 0 3/6 c [6]
----------------------------------------
1.77 0 1/1 main [2]
2 b <cycle 1> [4]
[5] 38.86 0.75 0 1 a <cycle 1> [5]
3 b <cycle 1> [4]
0 0 3/6 c [6]
----------------------------------------
0 0 3/6 b <cycle 1> [4]
0 0 3/6 a <cycle 1> [5]
[6] 0.00 0 0 6 c [6]
----------------------------------------
Поле `self' в первичной строке цикла--общее время выполнения всех
функций цикла. Оно равно сумме полей `self' для каждой отдельной функции
цикла, взятых из записей вызываемых функций.
Поле `children' в первичной строке цикла и строки подпрограмм содержат времена только тех функций, которые не входят в цикл. Хотя `a' и вызывает `b', время таких вызовов `b' не подсчитывается для `a' в поле `children'. Таким образом, мы не натыкаемся на проблему: что делать, если время в этих вызовах `b' включает опосредованные рекурсивные вызовы `a'.
Поле `children' в строках вызывающих функций в записи цикла оценивают время, затрачиваемое *на весь цикл в целом*, и на другие его подпрограммы, в том случае, когда эта функция вызывает одну из функций цикла.
Поле `calls' в первичной строке цикла содержит два числа: во-первых, количество вызовов функций цикла функциями извне цикла; во-вторых, количество вызовов функций цикла функциями цикла (включая количество вызовов самой себя). Это обобщение обычного разделения вызовов на рекурсивные и нерекурсивные.
Поле `calls' в строке вызываемой подпрограммы, входящей в цикл, в записи цикла сообщает, сколько раз эта функция была вызвана из функций цикла. Общее же их количество показано вторым числом в поле `calls' в первичной строке.
В отдельных записях для каждой функции цикла могут встречаться другие функции, указанные и как вызывающие, и как вызываемые. Эти строки показывают, сколько раз каждая из функций цикла вызывала или была вызвана из других функций цикла. Поля `self' и `children' таких строк не заполняются, так как затруднительно определить их смысл (значение), когда начинается рекурсия.