Профилировщик платформы LuaJIT
Стандартные параметры профилирования LuaJIT недостаточно детальны для полного анализа производительности.
Например, perf отображает только стек хоста, поэтому все вызовы Lua показываются как единый pcall(). Наоборот,
модуль jit.p, поставляемый с LuaJIT, не дает информации о стеке хоста.
Начиная с версии 2.10.0, в Tarantool встроен модуль misc.sysprof, реализующий сэмплинг-профилировщик платформы LuaJIT
(далее в этом разделе – профилировщик платформы). Профилировщик платформы может одновременно фиксировать стеки гостя и
хоста, а также состояния виртуальной машины, показывая полную картину происходящего.
Доступны три режима профилирования:
- Default: показывает только счетчики состояний виртуальной машины.
- Leaf: показывает последний кадр в стеке.
- Callchain: выполняет полный дамп стека.
Вместе с профилировщиком платформы поставляется парсер по умолчанию, формирующий вывод в формате, подходящем
для flamegraph.pl.
Использование профилировщика платформы включает два шага:
- Сбор данных и формирование бинарного профиля стеков (далее – сэмплинг-профиль).
- Разбор собранного сэмплинг-профиля для получения человекочитаемого отчета профилирования.
Чтобы собрать сэмплинг-профиль для определенного участка кода на Lua и C, этот участок нужно поместить между
двумя функциями модуля misc.sysprof, а именно - misc.sysprof.start() и misc.sysprof.stop() – а затем выполнить
код в Tarantool.
Ниже приведен фрагмент Lua-кода с именем test.lua иллюстрирующий это.
local function payload()local function fib(n)if n <= 1 thenreturn nendreturn fib(n - 1) + fib(n - 2)endreturn fib(32)endpayload()local res, err = misc.sysprof.start({mode = 'C', interval = 1, path = 'sysprof.bin'})assert(res, err)payload()res, err = misc.sysprof.stop()assert(res, err)
Lua-код для запуска профилировщика платформы – как в строке 13 в приведенном выше примере test.lua – выглядит так:
local str, err = misc.sysprof.start({mode = 'C', interval = 1, path = 'sysprof.bin'})
где:
mode– режим профилирования;interval– интервал сэмплирования;sysprof.bin– имя бинарного файла, в который записываются события профилирования.
Если операция завершается неудачей – например, не удается открыть файл для записи или профилировщик платформы
уже запущен – misc.sysprof.start() возвращает nil в качестве первого результата, строку с сообщением об
ошибке в качестве второго результата и зависящий от системы код ошибки в качестве третьего результата.
При успешном выполнении misc.sysprof.start() возвращает true.
Lua-код для остановки профилировщика платформы – как в строке 18 в приведенном выше примере test.lua – выглядит так:
local res, err = misc.sysprof.stop()
Если операция завершается неудачей – например, при ошибке закрытия файлового дескриптора или при сбое во
время формирования отчета – misc.sysprof.stop() возвращает nil в качестве первого результата, строку с
сообщением об ошибке в качестве второго результата и зависящий от системы код ошибки в качестве третьего результата.
При успешном выполнении misc.sysprof.stop() возвращает true.
Чтобы сгенерировать файл с профилем в бинарном формате (в примере кода test.lua
выше имя такого файла – sysprof.bin), выполните код в Tarantool:
$ tarantool test.lua
Tarantool собирает события профилирования в sysprof.bin, помещает файл в
рабочий каталог и закрывает сессию.
После получения профиля платформы в бинарном формате следующим шагом является его разбор для получения
человекочитаемого отчета профилирования. Это можно сделать с помощью Tarantool посредством следующей команды
(обратите внимание на дефис - перед именем файла):
$ tarantool -e 'require("sysprof")(arg)' - sysprof.bin > tmp$ curl -O https://raw.githubusercontent.com/brendangregg/FlameGraph/refs/heads/master/flamegraph.pl$ perl flamegraph.pl tmp > sysprof.svg
где sysprof.bin – сэмплинг-профиль, сгенерированный ранее
командой tarantool test.lua.
Что касается исследования Lua-кода с помощью отчетов профилирования, то здесь все зависит от конкретного кода, и точных рекомендаций на этот счет быть не может. Тем не менее, некоторые моменты рассмотрены далее в примере анализа отчета профилирования ниже.
Профилировщик платформы предоставляет Lua-интерфейс:
misc.sysprof.start(opts);misc.sysprof.stop();misc.sysprof.report().
Первые две функции возвращают булевы значения res и err, где err равен nil при успешном выполнении и
содержит сообщение об ошибке при неудаче.
misc.sysprof.report возвращает Lua-таблицу, содержащую следующие счетчики:
{"samples" = int,"INTERP" = int,"LFUNC" = int,"FFUNC" = int,"CFUNC" = int,"GC" = int,"EXIT" = int,"RECORD" = int,"OPT" = int,"ASM" = int,"TRACE" = int}
Аргумент opts функции misc.sysprof.start может содержать следующие параметры:
-
mode(обязательный) – один из поддерживаемых режимов профилирования:'D'= DEFAULT;'L'= LEAF;'C'= CALLGRAPH.
-
interval(необязательный) – интервал сэмплирования в миллисекундах (по умолчанию 10 мс). -
path(необязательный) – путь к файлу для хранения данных профиля (по умолчаниюsysprof.bin).
Профилировщик платформы предоставляет низкоуровневый C-интерфейс:
int luaM_sysprof_set_writer(sp_writer writer)– устанавливает функцию записи для sysprof.int luaM_sysprof_set_on_stop(sp_on_stop on_stop)– устанавливает функцию обратного вызова при остановке дляsysprof(для очистки ресурсов).int luaM_sysprof_set_backtracer(sp_backtracer backtracer)– устанавливает функцию обратной трассировки. Если аргументbacktracerравен NULL, устанавливается функция обратной трассировки по умолчанию.
int luaM_sysprof_start(lua_State *L, const struct luam_Sysprof_Options *opt)– см. Параметры профилировщика платформы;int luaM_sysprof_stop(lua_State *L);int luaM_sysprof_report(struct luam_Sysprof_Counters *counters)– записывает счетчики профилирования для каждого vmstate.
Все функции возвращают 0 при успешном выполнении и код ошибки при неудаче.
Параметры конфигурации профилировщика платформы включают:
-
typedef size_t (*sp_writer)(const void **data, size_t len, void *ctx)– функция записи для событий профиля.Должна быть async-safe, см. также
man 7 signal-safety.Должна возвращать количество записанных байт при успешном выполнении или ноль в случае ошибки.
Установка
*dataв NULL означает конец профилирования. Подробности см. вlj_wbuf.h. -
typedef int (*sp_on_stop)(void *ctx, uint8_t *buf)– функция обратного вызова при остановке профилировщика платформы.Требуется для корректной очистки при финализации VM, если профилировщик платформы все еще работает.
Возвращает ноль при успешном выполнении.
-
typedef void (*sp_backtracer)(void *(*frame_writer)(int frame_no, void *addr))– функция обратной трассировки для стека хоста.Должна вызывать
frame_writerдля каждого кадра в стеке в порядке от вершины стека к его основанию.Функция
frame_writerреализована внутриsysprofи передается в функциюbacktracer.Если
frame_writerвозвращает NULL, обратная трассировка должна быть остановлена. Еслиframe_writerвозвращает не NULL, обратная трассировка должна быть продолжена, если остались кадры.
Структура параметров для luaM_sysprof_start выглядит следующим образом:
struct luam_Sysprof_Options {/* Режим профилирования. */uint8_t mode;/* Интервал сэмплирования в мс. */uint64_t interval;/* Пользовательский буфер для записи данных. */uint8_t *buf;/* Размер буфера. */size_t len;/* Контекст для функции записи профиля и финального обратного вызова. */void *ctx;};
Профилировщик платформы поддерживает три режима профилирования:
- Режим
DEFAULTсобирает только данные дляluam_sysprof_counters, которые хранятся в памяти и могут быть получены с помощьюluaM_sysprof_reportпосле остановки профилировщика платформы. - Режим
LEAF=DEFAULT+ потоковая передача сэмплов, содержащих только верхние кадры стеков хоста и гостя в формате, описанном вlj_sysprof.h. - Режим
CALLGRAPH= DEFAULT + потоковая передача сэмплов с полными цепочками вызовов стеков хоста и гостя в формате, описанном вlj_sysprof.h.
#define LUAM_SYSPROF_DEFAULT 0#define LUAM_SYSPROF_LEAF 1#define LUAM_SYSPROF_CALLGRAPH 2
Структура счетчиков для luaM_sysprof_report выглядит следующим образом:
struct luam_Sysprof_Counters {uint64_t vmst_interp;uint64_t vmst_lfunc;uint64_t vmst_ffunc;uint64_t vmst_cfunc;uint64_t vmst_gc;uint64_t vmst_exit;uint64_t vmst_record;uint64_t vmst_opt;uint64_t vmst_asm;uint64_t vmst_trace;uint64_t samples;};
- Задание функций записи, обратной трассировки и других параметров в режиме
Defaultне имеет смысла, поскольку в этом режиме собираются только счетчики. - Для
sysprofНЕТ конфигурации по умолчанию, поэтомуluaM_Sysprof_Configureдолжен быть вызван перед первым запускомsysprof. Учитывайте требования async safety.