Skip to content

Commit 491350b

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 491350b

File tree

2 files changed

+105
-0
lines changed

2 files changed

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

0 commit comments

Comments
 (0)