Привет! Я тут писал, что собираюсь делать что-то вроде профилировщика для программ на сях под x86/x86-64. Работает пока только под фрёй и драгонфлаем (это то, чем я пользуюсь) Вот что вышло:
https://github.com/shamazmazum/vsprofiler
Профайлер анализирует instruction pointer и стек (используя регистр ebp/rbp, т.е. компилировать надо с -fno-omit-frame-pointer) по сигналу таймера. Он пока не строит граф вызовов, а печатает flat report. Там 2 важных поля: self - количество семплов, когда instruction pointer был внутри данной функции и cumul - когда выполняется эта функция и когда выполняются функции, вызванные из неё (а сама она лежит на стеке).
Там на жидхабе есть пример использования (и за одно тест) - программа, которая хитро наполняет некий буфер и считает для него CRC. Дерево вызовов такое (написал в виде списка-копипасты, будет непонятно, пишите):
("main" ("get_value" ("factor")) ("crc8"))
Тест заключается в проверке значений
CUMUL(main) - SELF(main) - CUMUL(get_value) - CUMUL (crc8)
CUMUL(get_value) - SELF(get_value) - CUMUL(factor)
CUMUL(factor) - SELF(factor)
CUMUL(crc8) - SELF(crc8)
Понятно, что в идеале они должны быть равны 0 (так как у main 2 вызывающиеся функции - get_value и crc8, итд)
Но я получаю это (по gmake test): http://pastebin.com/Ntf37Gyc
Т.е. значения 38 и -54 для первых двух выражений.
Предположил, что ошибка из-за того, что instruction pointer находится где-то в прелюдии или эпилоге функций. clang генерирует такое:
00000000004008c0 <get_value>:
4008c0: 55 push %rbp (Вот тут RIP уже в get_value, а кадр на стеке не создан)
4008c1: 48 89 e5 mov %rsp,%rbp (Аналогично)
4008c4: 48 83 ec 10 sub $0x10,%rsp (Тут уже всё OK)
4008e7: 48 83 c4 10 add $0x10,%rsp
4008eb: 5d pop %rbp
4008ec: c3 retq (тут кадра уже нет, а RIP всё ещё в функции)
Изменил программу в соответствии со сказанным (чтобы она уходила с таких мест): перед сохранением бектрейса проверяю, где находится выполнение (функция restore_frame_if_needed):
https://github.com/shamazmazum/vsprofiler/commit/c2dcb87633a27f596bc96516761f...
И получаю непонятный результат в тесте:
(C-S)(main) - C(get_value) - C(crc8) = 23
(C-S)(get_value) - C(factor) = -23
(C-S)(factor) - = 0
(C-S)(crc8) - = 0
Т.е. значения 23 и -23, которые из раза в раз всегда противоположные, как будто get_value не попадает в бектрейс.
Какие у вас есть мысли? Пропустил я ещё какие-то краевые случаи или как? Посмотрите, если можете, тот коммит, понять там можно. А запустить у вас может и не выйдет, там анализатор на CL