Skip to content

Commit 616c810

Browse files
committed
tests/lapi: add sysprof test
The patch adds a test for sysprof built into LuaJIT and Tarantool's sysprof.
1 parent 6bc3b61 commit 616c810

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

.luacheckrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
-- Tarantool introduces a global for misc API namespace.
2+
read_globals = { "misc" }
3+
14
-- Defined functions is unused in preamble,
25
-- but could be used by generated Lua programs.
36
files["tests/capi/luaL_loadbuffer_proto/preamble.lua"] = {

tests/lapi/misc_sysprof_test.lua

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
--[[
2+
SPDX-License-Identifier: ISC
3+
Copyright (c) 2025, Sergey Bronnikov.
4+
5+
LuaJIT platform profiler,
6+
https://luajit.org/ext_profiler.html
7+
https://www.tarantool.io/en/doc/latest/tooling/luajit_sysprof/
8+
]]
9+
10+
local luzer = require("luzer")
11+
local test_lib = require("lib")
12+
13+
local MAX_INT = test_lib.MAX_INT
14+
local MIN_INT = test_lib.MIN_INT
15+
16+
local has_tnt_sysprof, sysprof = pcall(require, "misc.sysprof")
17+
if not has_tnt_sysprof then
18+
sysprof = require("jit.profile")
19+
end
20+
21+
local SYSPROF_OPTIONS = {
22+
"f", -- Profile with precision down to the function level.
23+
"l", -- Profile with precision down to the line level.
24+
"i", -- Sampling interval in milliseconds (default 10ms).
25+
}
26+
27+
local SYSPROF_DEFAULT_INTERVAL = 10 -- ms
28+
29+
local function sysprof_start(fdp)
30+
if has_tnt_sysprof then
31+
local mode = fdp:oneof({"D", "L", "C"})
32+
local _, err = misc.sysprof.start({
33+
interval = SYSPROF_DEFAULT_INTERVAL,
34+
mode = mode,
35+
path = "/dev/null",
36+
})
37+
assert(err)
38+
else
39+
local option = fdp:oneof(SYSPROF_OPTIONS)
40+
if option == "i" then
41+
option = ("i%d"):format(SYSPROF_DEFAULT_INTERVAL)
42+
end
43+
local cb = function(_thread, _samples, _vmstate)
44+
-- Nope.
45+
end
46+
sysprof.start(option, cb)
47+
end
48+
end
49+
50+
local function sysprof_report()
51+
if has_tnt_sysprof then
52+
misc.sysprof.report()
53+
end
54+
end
55+
56+
local DUMPSTACK_FMT = {
57+
"p", -- Preserve the full path for module names.
58+
"f", -- Dump the function name if it can be derived.
59+
"F", -- Ditto, but dump module:name.
60+
"l", -- Dump module:line.
61+
"Z", -- Zap the following characters for the last dumped frame.
62+
}
63+
64+
local function sysprof_dumpstack(fdp)
65+
if not has_tnt_sysprof then
66+
local fmt = fdp:oneof(DUMPSTACK_FMT)
67+
local depth = fdp:consume_integer(MIN_INT, MAX_INT)
68+
local dump = sysprof.dumpstack(fmt, depth)
69+
assert(dump)
70+
end
71+
end
72+
73+
local function sysprof_stop()
74+
sysprof.stop()
75+
end
76+
77+
local function TestOneInput(buf)
78+
local fdp = luzer.FuzzedDataProvider(buf)
79+
local mode = fdp:oneof({"t", "b"})
80+
-- LuaJIT ASSERT lj_bcread.c:123: bcread_byte: buffer read
81+
-- overflow.
82+
if test_lib.lua_version() == "LuaJIT" then
83+
mode = "t"
84+
end
85+
local chunk = fdp:consume_string(test_lib.MAX_STR_LEN)
86+
local func = load(chunk, "luzer", mode)
87+
sysprof_start(fdp)
88+
pcall(func)
89+
sysprof_report()
90+
sysprof_dumpstack(fdp)
91+
sysprof_stop()
92+
end
93+
94+
local args = {
95+
artifact_prefix = "misc_sysprof_",
96+
}
97+
luzer.Fuzz(TestOneInput, nil, args)

0 commit comments

Comments
 (0)