Skip to content

Commit e409371

Browse files
authored
zjit_bisect.rb: Fix pipe deadlock; log when timed out [ci skip]
I spent a long time bisecting some largish program before realizing that failure was in fact coming from the child timing out due to zjit_bisect.rb not clearing the stdout and stderr pipe. Fix the pipe deadlock by redirecting to /dev/null. This sacrifices the debug output during boot, but for that we also get to remove a lot of code and the dependency on Open3.
1 parent 49e4d21 commit e409371

File tree

1 file changed

+19
-26
lines changed

1 file changed

+19
-26
lines changed

tool/zjit_bisect.rb

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/usr/bin/env ruby
22
require 'logger'
3-
require 'open3'
43
require 'optparse'
54
require 'shellwords'
65
require 'tempfile'
@@ -73,26 +72,22 @@ def run_bisect(command, items)
7372
end
7473

7574
def run_ruby *cmd
76-
stdout_data = nil
77-
stderr_data = nil
78-
status = nil
79-
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
80-
pid = wait_thr.pid
81-
begin
82-
Timeout.timeout(ARGS[:timeout]) do
83-
stdout_data = stdout.read
84-
stderr_data = stderr.read
85-
status = wait_thr.value
86-
end
87-
rescue Timeout::Error
88-
Process.kill("KILL", pid)
89-
stderr_data = "(killed due to timeout)"
90-
# Wait for the process to be reaped
91-
wait_thr.value
92-
status = 1
75+
pid = Process.spawn(*cmd, {
76+
in: :close,
77+
out: [File::NULL, File::RDWR],
78+
err: [File::NULL, File::RDWR],
79+
})
80+
begin
81+
status = Timeout.timeout(ARGS[:timeout]) do
82+
Process::Status.wait(pid)
9383
end
84+
rescue Timeout::Error
85+
Process.kill("KILL", pid)
86+
LOGGER.warn("Timed out after #{ARGS[:timeout]} seconds")
87+
status = Process::Status.wait(pid)
9488
end
95-
[stdout_data, stderr_data, status]
89+
90+
status
9691
end
9792

9893
def run_with_jit_list(ruby, options, jit_list)
@@ -107,9 +102,8 @@ def run_with_jit_list(ruby, options, jit_list)
107102
end
108103

109104
# Try running with no JIT list to get a stable baseline
110-
_, stderr, exitcode = run_with_jit_list(RUBY, OPTIONS, [])
111-
if exitcode != 0
112-
raise "Command failed with empty JIT list: #{stderr}"
105+
unless run_with_jit_list(RUBY, OPTIONS, []).success?
106+
raise "Command failed with empty JIT list"
113107
end
114108
# Collect the JIT list from the failing Ruby process
115109
jit_list = nil
@@ -119,14 +113,13 @@ def run_with_jit_list(ruby, options, jit_list)
119113
end
120114
LOGGER.info("Starting with JIT list of #{jit_list.length} items.")
121115
# Try running without the optimizer
122-
_, stderr, exitcode = run_with_jit_list(RUBY, ["--zjit-disable-hir-opt", *OPTIONS], jit_list)
123-
if exitcode == 0
116+
status = run_with_jit_list(RUBY, ["--zjit-disable-hir-opt", *OPTIONS], jit_list)
117+
if status.success?
124118
LOGGER.warn "*** Command suceeded with HIR optimizer disabled. HIR optimizer is probably at fault. ***"
125119
end
126120
# Now narrow it down
127121
command = lambda do |items|
128-
_, _, exitcode = run_with_jit_list(RUBY, OPTIONS, items)
129-
exitcode == 0
122+
run_with_jit_list(RUBY, OPTIONS, items).success?
130123
end
131124
result = run_bisect(command, jit_list)
132125
File.open("jitlist.txt", "w") do |file|

0 commit comments

Comments
 (0)