Ответ 1
Хорошо, допустим, временно игнорировать разницу между call-графами звонящего и вызываемого, главным образом потому, что, когда я сравниваю результаты между этими двумя параметрами на своей машине, я вижу только эффекты внутри DSO kernel.kallsyms
по причинам, я понимаю - относительно новое для меня.
Я обнаружил, что для вашего примера немного легче прочитать все дерево. Итак, используя --stdio
, посмотрим на все дерево для __sin_sse2
:
# Overhead Command Shared Object Symbol
# ........ ......... ................. ......................
#
94.72% perf-test libm-2.19.so [.] __sin_sse2
|
--- __sin_sse2
|
|--44.20%-- foo
| |
| --100.00%-- main
| __libc_start_main
| _start
| 0x0
|
|--27.95%-- baz
| |
| |--51.78%-- bar
| | foo
| | main
| | __libc_start_main
| | _start
| | 0x0
| |
| --48.22%-- foo
| main
| __libc_start_main
| _start
| 0x0
|
--27.84%-- bar
|
--100.00%-- foo
main
__libc_start_main
_start
0x0
Итак, способ, которым я читал это: 44% времени, sin
вызывается из foo
; 27% времени он вызвал от baz
и 27% от бара.
Документация для -g поучительна:
-g [type,min[,limit],order[,key]], --call-graph
Display call chains using type, min percent threshold, optional print limit and order. type can be either:
· flat: single column, linear exposure of call chains.
· graph: use a graph tree, displaying absolute overhead rates.
· fractal: like graph, but displays relative rates. Each branch of the tree is considered as a new profiled object.
order can be either:
- callee: callee based call graph.
- caller: inverted caller based call graph.
key can be:
- function: compare on functions
- address: compare on individual code addresses
Default: fractal,0.5,callee,function.
Важным здесь является то, что по умолчанию фрактал, а в фрактальном режиме каждая ветвь является новым объектом.
Итак, вы можете видеть, что 50% времени, которое вызывается baz
, вызывается из bar
, а остальные 50% - из foo
.
Это не всегда самая полезная мера, поэтому поучительно смотреть на результаты с помощью -g graph
:
94.72% perf-test libm-2.19.so [.] __sin_sse2
|
--- __sin_sse2
|
|--41.87%-- foo
| |
| --41.48%-- main
| __libc_start_main
| _start
| 0x0
|
|--26.48%-- baz
| |
| |--13.50%-- bar
| | foo
| | main
| | __libc_start_main
| | _start
| | 0x0
| |
| --12.57%-- foo
| main
| __libc_start_main
| _start
| 0x0
|
--26.38%-- bar
|
--26.17%-- foo
main
__libc_start_main
_start
0x0
Это изменяется на использование абсолютных процентов, где каждый процент времени сообщается для этой цепочки вызовов: So foo->bar
составляет 26% от общего количества тиков (что в свою очередь вызывает baz
) и foo->baz
(direct) составляет 12% от общего количества клещей.
Я до сих пор не знаю, почему я не вижу различий между диаграммами вызываемого и вызывающего, хотя с точки зрения __sin_sse2
.
Update
Одна вещь, которую я действительно изменил из вашей командной строки, - это то, как собирались callgrraphs. Linux perf по умолчанию использует метод указателя кадра для восстановления стоп-копов. Это может быть проблемой, когда компилятор использует -fomit-frame-pointer
как default. Поэтому я использовал
perf record --call-graph dwarf ./perf-test