Сообщить об ошибке.

Отслеживание вызовов функций, просмотр стека, профилирование кода

В разделе разобраны функции модуля sys, которые предоставляют информацию о трассировке и профилировании Python кода.

Содержание:


sys.gettrace():

Функция sys.gettrace() предоставляет информацию о функции трассировки, которая была установлена при помощи функции sys.settrace().

sys.settrace(tracefunc):

Функция sys.settrace() устанавливает функцию трассировки системы tracefunc, которая позволяет реализовать отладчик исходного кода Python на Python.

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

Функции трассировки должны иметь три аргумента: frame, event и arg. Аргумент frame это текущий кадр стека. Событие event является строка: 'call', 'line', 'return', 'exception' или 'opcode'. Аргумент arg зависит от типа события.

Функция трассировки вызывается при установленном событии 'call' всякий раз, когда вводится новая локальная область. Она должна возвращать ссылку на локальную функцию трассировки, которая будет использоваться для новой области или None если область не должна отслеживаться.

Функция локальной трассировки должна возвращать ссылку на себя или на другую функцию для дальнейшей трассировки в этой области или None отключает трассировку в этой области.

Если в функции трассировки произошла какая-либо, ошибка она будет сброшена, как это происходит для вызова sys.settrace(None).

События имеют следующее значение:

  • 'call' - вызвана функция или введен какой-то другой блок кода. Глобальная функция трассировки вызывается, arg устанавливается в None, возвращаемое значение указывает локальную функцию трассировки.
  • 'line' - интерпретатор собирается выполнить новую строку кода или повторно выполнить условие цикла. Вызвана локальная функция трассировки, arg устанавливается в None, возвращаемое значение указывает новую локальную функцию трассировки. Отдельные события могут быть отключены для кадра, если f_trace_lines установлено значение False для этого кадра.
  • 'return' - функция или другой блок кода собираются возвращать результат. Вызвана локальная функция трассировки. arg - это значение, которое будет возвращено или будет None если событие вызвано исключением. Возвращаемое значение функции трассировки игнорируется.
  • 'exception' - произошло исключение. Вызвана локальная функция трассировки, arg - это кортеж (exception, value, traceback), возвращаемое значение указывает новую локальную функцию трассировки.
  • 'opcode' - интерпретатор собирается выполнить новый код операции. Вызвана локальная функция трассировки, arg устанавливается в None, возвращаемое значение указывает новую локальную функцию трассировки. События Per-opcode не выдаются по умолчанию: они должны быть явно запрошены, установив на кадре f_trace_opcodes в True.

Обратите внимание, на то как исключение распространяется по цепочке вызывающих сторон, событие 'exception' генерируется на каждом уровне.

Для более детального использования можно установить функцию трассировки, явно назначив frame.f_trace=tracefunc, вместо того, чтобы полагаться на ее косвенную установку через возвращаемое значение из уже установленной функции трассировки. Это также необходимо для активации функции трассировки в текущем кадре, чего не делает sys.settrace().

Обратите внимание: для того, чтобы это работало, должна быть установлена глобальная функция трассировки с sys.settrace(), чтобы включить механизм трассировки во время выполнения. Но это не обязательно должна быть та же самая функция трассировки, например это может быть функция с низкими накладными расходами, которая просто возвращает None, чтобы отключать себя на каждом кадре.

Вызывает событие аудита sys.settrace без аргументов.

sys.call_tracing(func, args):

Функция sys.call_tracing() вызывает func(*args), пока включена трассировка. Состояние трассировки сохраняется, а затем восстанавливается. Функция sys.call_tracing() предназначена для вызова отладчика из контрольной точки, чтобы рекурсивно отлаживать какой-то другой код.

sys.tracebacklimit:

Когда для переменной sys.tracebacklimit задано целочисленное значение, оно определяет максимальное количество уровней информации трассировки, выводимой при возникновении необработанного исключения. По умолчанию это 1000. Если установлено значение 0 или меньше, вся информация о трассировке подавляется и печатаются только тип и значение исключения.

sys.setprofile(profilefunc):

Функция sys.setprofile() устанавливает функцию profilefunc, которая позволяет реализовать профилирование исходного кода Python в Python.

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

Функция sys.setprofile() зависит от потока, но профилировщик не может знать о переключениях контекста между потоками, поэтому нет смысла использовать ее при наличии нескольких потоков. Кроме того, его возвращаемое значение не используется, поэтому она может просто вернуть None. Ошибка в функции профиля приведет к отключению самой себя.

Функции профилирования должны иметь три аргумента: frame, event, и arg. frame - текущий кадр стека. Событие event представляет собой строку: 'call', 'return', 'c_call', 'c_return' или 'c_exception'. Текущий кадр стека arg зависит от типа события.

Вызывает событие аудита sys.setprofile без аргументов.

События имеют следующий смысл:

  • 'call' - вызывается функция или вводится какой-либо другой кодовый блок. Вызывается функция профиля. arg - это None.
  • 'return' - функция или другой кодовый блок вот-вот вернет результат. Вызывается функция профиля. arg - это значение, которое будет возвращено или None, если событие вызвано вызванным исключением.
  • 'c_call' - функция C вот-вот будет вызвана. Это может быть функция расширения или встроенная функция. arg - это функция-объект.
  • 'c_return' - функция C вернула результат. arg - это функция-объект.
  • 'c_exception' - функция C вызвала исключение. arg - это функция-объект.

sys.setdlopenflags(n):

Функция sys.setdlopenflags() устанавливает флаги n, используемые интерпретатором для вызовов Unix dlopen(), например, когда интерпретатор загружает модули расширения. Помимо прочего, это позволит лениво разрешать символы при импорте модуля, если он вызывается как sys.setdlopenflags(0).

Чтобы совместно использовать символы между модулями расширения, вызовите sys.setdlopenflags(os.RTLD_GLOBAL).

Символические имена значений флагов:

  • os.RTLD_LAZY,
  • os.RTLD_NOW,
  • os.RTLD_GLOBAL,
  • os.RTLD_LOCAL,
  • os.RTLD_NODELETE,
  • os.RTLD_NOLOAD,
  • os.RTLD_DEEPBIND.

    Что означают эти флаги, смотрите на странице руководства Unix dlopen(3).

Доступность: Unix.

Примеры использования трассировки и профилирования кода.

Событие call генерируется перед каждым вызовом функции. Кадр, переданный в функцию обратного вызова, можно использовать для определения, какая функция вызывается и откуда. В этом примере игнорируются вызовы write(), используемые print() для записи в sys.stdout.

# test_settracel.py

import sys

def trace_calls(frame, event, arg):
    if event != 'call':
        return
    co = frame.f_code
    func_name = co.co_name
    if func_name == 'write':
        # Игнорировать вызовы write() при печати
        return
    func_line_no = frame.f_lineno
    func_filename = co.co_filename
    if not func_filename.endswith('test_settracel.py'):
        # Игнорировать вызовы не в этом модуле
        return
    caller = frame.f_back
    caller_line_no = caller.f_lineno
    caller_filename = caller.f_code.co_filename
    print(f'- Call to {func_name}')
    print(f'-  on line {func_line_no} of {func_filename}')
    print(f'-  from line {caller_line_no} of {caller_filename}')
    return

def b():
    print('inside b()\n')

def a():
    print('inside a()\n')
    b()

sys.settrace(trace_calls)
a()

# - Call to a
# -  on line 31 of test_settracel.py
# -  from line 36 of test_settracel.py
# inside a()

# - Call to b
# -  on line 28 of test_settracel.py
# -  from line 33 of test_settracel.py
# inside b()

Еще один полезный способ использования ловушек - следить за тем, какие функции вызываются и каковы их возвращаемые значения. Для отслеживания возвращаемых значений, нужно следить за событием return.

import sys

def trace_calls_returns(frame, event, arg):
    co = frame.f_code
    func_name = co.co_name
    if func_name == 'write':
        # Игнорировать вызовы write()
        return
    line_no = frame.f_lineno
    filename = co.co_filename
    if not filename.endswith('sys_settrace_return.py'):
        # Игнорировать вызовы не в этом модуле
        return
    if event == 'call':
        print(f'- Call to {func_name} on line {line_no} of {filename}')
        return trace_calls_returns
    elif event == 'return':
        print(f'- {func_name} => {arg}')
    return

def b():
    print('inside b()')
    return 'response_from_b '

def a():
    print('inside a()')
    val = b()
    return val * 2


sys.settrace(trace_calls_returns)
a()

# - Call to a on line 32 of sys_settrace_return.py
# inside a()
# - Call to b on line 27 of sys_settrace_return.py
# inside b()
# - b => response_from_b
# - a => response_from_b response_from_b

Локальная функция трассировки используется для отслеживания возвращаемых событий, поэтому функция trace_calls_returns() при вызове должна возвращать ссылку на себя, чтобы можно было отслеживать возвращаемое значение.