Графические плагины процессора для Python

Графические графики процессоров Brendan Gregg – это способ визуализации использования ЦП в течение определенного периода времени на основе стеков вызовов.

Его проект github FlameGraph предоставляет независимый от языка способ построения этих графиков:

Для каждого языка FlameGraph требует способа ввода стека в виде таких строк:

grandparent_func;parent_func;func 42 

Это означает, что в инструментальной программе наблюдалась работа функции func , где она parent_func из parent_func , в свою очередь parent_func из функции grandparent_func верхнего уровня. В нем говорится, что стек вызовов наблюдался 42 раза.

Как я могу собрать информацию о стеке из программ Python и предоставить его FlameGraph?

Для бонусных очков: как это можно расширить, чтобы показать как C, так и Python стек или даже до ядра на Linux (аналогично некоторым диаграммам пламени Java и node.js на веб-сайте Brendan)?

введите описание изображения здесь

Возможно, вы можете попробовать sys.setprofile , который является основой стандартного profile профилирования python и cProfile . Этот метод устанавливает привязку к событиям «вызова» и «возврата» каждой функции, включая функции C-API.

Функция профиля системы вызывается аналогично функции трассировки системы (см. Параметр settrace ()), но она не вызывается для каждой исполняемой строки кода (только при вызове и возврате, но событие возврата сообщается, даже когда исключение было задавать).

Ниже приведен рабочий пример:

 from time import clock t0 = clock() def getFun(frame): code = frame.f_code return code.co_name+' in '+code.co_filename+':'+str(code.co_firstlineno) def trace_dispatch(frame, event, arg): if event in [ "c_call" , 'call', 'return', 'c_return']: t = int((clock()-t0)*1000) f = frame stack=[] while(f): stack.insert( 0,getFun(f) ) f = f.f_back print event, '\t', '; '.join(stack), '; ', t import sys sys.setprofile(trace_dispatch) try: execfile('test.py') finally: sys.setprofile(None) в from time import clock t0 = clock() def getFun(frame): code = frame.f_code return code.co_name+' in '+code.co_filename+':'+str(code.co_firstlineno) def trace_dispatch(frame, event, arg): if event in [ "c_call" , 'call', 'return', 'c_return']: t = int((clock()-t0)*1000) f = frame stack=[] while(f): stack.insert( 0,getFun(f) ) f = f.f_back print event, '\t', '; '.join(stack), '; ', t import sys sys.setprofile(trace_dispatch) try: execfile('test.py') finally: sys.setprofile(None) 

Test.py

 def f(x): return x+1 def main(x): return f(x) main(10) 

Это распечатает

 c_call 0 call <module> in test.py:2 ; 1 call <module> in test.py:2; main in test.py:5 ; 1 call <module> in test.py:2; main in test.py:5; f in test.py:2 ; 5 return <module> in test.py:2; main in test.py:5; f in test.py:2 ; 8 return <module> in test.py:2; main in test.py:5 ; 11 return <module> in test.py:2 ; 14 c_return 18 c_call 21 

См. Более полную функцию профилирования здесь .

C в python

Вы не можете получить доступ к стеку C в интерпретаторе python. Необходимо использовать отладчик или профилировщик, который поддерживает C / C ++. Я бы рекомендовал python gdb .