Skip to content

Commit

Permalink
Always close profiler output file.
Browse files Browse the repository at this point in the history
Reported by Guilherme Batalheiro.

(cherry picked from commit fca6633)

Before the patch, a function `prof_finish` wrote a string
`No samples collected` to a profiler output file and then exited.
Due to early exit, the output file handle stay open. This patch
fixes the condition and the file handle is closed even if the
number of samples is equal to 0.

Sergey Bronnikov:
* added the description and the test for the problem

Part of tarantool/tarantool#11055
  • Loading branch information
Mike Pall authored and ligurio committed Mar 5, 2025
1 parent dd0db0c commit 4873c85
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 3 deletions.
4 changes: 1 addition & 3 deletions src/jit/p.lua
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,7 @@ local function prof_finish()
local samples = prof_samples
if samples == 0 then
if prof_raw ~= true then out:write("[No samples collected]\n") end
return
end
if prof_ann then
elseif prof_ann then
prof_annotate(prof_count1, samples)
else
prof_top(prof_count1, prof_count2, samples, "")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
local tap = require('tap')
-- Test file to demonstrate LuaJIT incorrect behaviour with missed
-- closing a file handle for the profile output file.
-- See also: https://github.com/LuaJIT/LuaJIT/issues/1304.
local test = tap.test('lj-1304-close-profile-dump-with-0-samples')
local profilename = require('utils').tools.profilename

test:plan(2)

local filename = profilename('sysprof')
-- An interval of the profiling is set to a huge enough value to
-- be sure that there are no samples collected.
local jit_p_options = 'i9999999'

local function close_profile_dump_with_0_samples(subtest)
local jit_p = require('jit.p')

subtest:plan(1)

collectgarbage('stop')

jit_p.start(jit_p_options, filename)
jit_p.stop()

local f = io.open(filename, 'r')
local p_content = f:read('a*')
subtest:is(p_content, '[No samples collected]\n',
'profile dump has no samples')
f:close()

-- Teardown.
collectgarbage('restart')
os.remove(filename)
end

local function close_profile_dump_with_0_samples_with_unload(subtest)
local jit_p = require('jit.p')

subtest:plan(1)

collectgarbage('stop')
jit_p.start(jit_p_options, filename)
jit_p.stop()

-- Unload the module and clean the local.
package.loaded['jit.p'] = nil
jit_p = nil -- luacheck: no unused
collectgarbage('collect')

local f = io.open(filename, 'r')
local p_content = f:read('a*')
subtest:is(p_content, '[No samples collected]\n',
'profile dump has no samples')
f:close()

-- Teardown.
collectgarbage('restart')
os.remove(filename)
end

test:test('close profile dump with 0 samples',
close_profile_dump_with_0_samples)
test:test('close profile dump with 0 samples and profile module unload',
close_profile_dump_with_0_samples_with_unload)

test:done(true)

0 comments on commit 4873c85

Please sign in to comment.