Skip to content

Commit 92d6021

Browse files
committed
Add worker and main functions for subprocess serialization and timing metrics
1 parent 8cd9e02 commit 92d6021

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# main.jl
2+
using Serialization
3+
using Printf
4+
5+
"""
6+
run_with_serialization(timeout_s::Real) -> (result::Dict, success::Bool)
7+
8+
Spawns `worker.jl` in a subprocess, passing it a temp‐file path.
9+
Waits up to `timeout_s` seconds (covering Julia startup + your work).
10+
On success: reads & returns the deserialized Dict, then deletes the file.
11+
On timeout or failure: kills the process, deletes any stale file, and returns `(nothing,false)`.
12+
"""
13+
function run_with_serialization(timeout_s::Real)
14+
outfile = tempname() * ".bin"
15+
script = abspath("dev/blocking_timeout/worker.jl")
16+
17+
# Don't use pipeline - it can create zombie processes
18+
proc = run(`julia --startup-file=no $script $outfile`, wait=false)
19+
20+
deadline = time() + timeout_s
21+
while process_running(proc) && time() < deadline
22+
sleep(0.01)
23+
end
24+
25+
if process_running(proc)
26+
# Force kill on Windows
27+
if Sys.iswindows()
28+
# First try Julia's SIGKILL
29+
try
30+
kill(proc, Base.SIGKILL)
31+
sleep(0.1) # Give it a moment
32+
catch
33+
end
34+
35+
# If still running, use OS-level kill
36+
if process_running(proc)
37+
try
38+
run(`taskkill /F /PID $(getpid(proc))`)
39+
catch
40+
end
41+
end
42+
else
43+
kill(proc)
44+
end
45+
46+
# Don't wait after force kill - it might hang
47+
isfile(outfile) && rm(outfile; force=true)
48+
return nothing, false
49+
else
50+
# Process finished normally
51+
wait(proc)
52+
if isfile(outfile)
53+
result = open(deserialize, outfile, "r")
54+
rm(outfile; force=true)
55+
return result, true
56+
else
57+
return nothing, false
58+
end
59+
end
60+
end
61+
62+
63+
64+
"""
65+
display_metrics(res::Dict, tic_spawn::Real)
66+
67+
Given the worker’s `res` Dict (with keys
68+
:script_start, :work_elapsed, :serialize_elapsed
69+
) and the `tic_spawn` timestamp from before you spawned it,
70+
this will print a formatted timing summary to the REPL.
71+
72+
Example:
73+
```julia
74+
# after `res, ok = run_with_serialization(TIMEOUT)`:
75+
if ok
76+
display_metrics(res, tic_spawn)
77+
end
78+
```
79+
"""
80+
function display_metrics(res::Dict, tic_spawn::Real)
81+
# compute each metric
82+
spawn_overhead = res[:script_start] - tic_spawn
83+
work_elapsed = res[:work_elapsed]
84+
serialize_elapsed = res[:serialize_elapsed]
85+
86+
# print table
87+
println("\n=== Timing Summary ===")
88+
println(rpad("Stage", 20), " | ", "Seconds")
89+
println(repeat('-', 32))
90+
@printf("%-20s | %8.6f\n", "Spawn Overhead", spawn_overhead)
91+
@printf("%-20s | %8.6f\n", "Work Elapsed", work_elapsed)
92+
@printf("%-20s | %8.6f\n", "Serialize Elapsed", serialize_elapsed)
93+
end
94+
95+
96+
# ==== Usage Example ====
97+
const TIMEOUT2 = 4.0 # seconds
98+
const TIMEOUT1 = 7.0 # seconds
99+
100+
101+
tic_spawn = time()
102+
res, ok = run_with_serialization(TIMEOUT2)
103+
104+
if ok
105+
display_metrics(res, tic_spawn)
106+
else
107+
println("✗ timed out or no output after $(TIMEOUT2) s")
108+
end

dev/blocking_timeout/worker.jl

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# worker.jl
2+
3+
4+
5+
using Serialization
6+
7+
outfile = ARGS[1]
8+
9+
# 1) record script start
10+
script_start = time()
11+
12+
# 2) do your work
13+
sleep(5.0)
14+
work_end = time()
15+
work_elapsed = work_end - script_start
16+
17+
# 3) build result without file timings
18+
res = Dict(
19+
:script_start => script_start,
20+
:work_elapsed => work_elapsed,
21+
:payload => rand(3)
22+
)
23+
24+
# 4) serialize into memory & measure that
25+
buf = IOBuffer()
26+
t0 = time()
27+
serialize(buf, res)
28+
serialize_elapsed = time() - t0
29+
30+
# 5) annotate timing into the same dict
31+
res[:serialize_elapsed] = serialize_elapsed
32+
33+
# 6) now write the **final** dict out exactly once
34+
open(outfile, "w") do io
35+
serialize(io, res)
36+
end

0 commit comments

Comments
 (0)