@@ -31,21 +31,29 @@ function parse_args(args)
3131 while i <= length (args)
3232 a = args[i]
3333 if a == " --list"
34- opts[" list" ] = abspath (args[i+ 1 ]); i += 2
34+ opts[" list" ] = abspath (args[i+ 1 ])
35+ i += 2
3536 elseif a == " --root"
36- opts[" root" ] = abspath (args[i+ 1 ]); i += 2
37+ opts[" root" ] = abspath (args[i+ 1 ])
38+ i += 2
3739 elseif a == " --out"
38- opts[" out" ] = abspath (args[i+ 1 ]); i += 2
40+ opts[" out" ] = abspath (args[i+ 1 ])
41+ i += 2
3942 elseif a == " --template"
40- opts[" template" ] = abspath (args[i+ 1 ]); i += 2
43+ opts[" template" ] = abspath (args[i+ 1 ])
44+ i += 2
4145 elseif a == " --workers"
42- opts[" workers" ] = parse (Int, args[i+ 1 ]); i += 2
46+ opts[" workers" ] = parse (Int, args[i+ 1 ])
47+ i += 2
4348 elseif a == " --threads"
44- opts[" threads" ] = parse (Int, args[i+ 1 ]); i += 2
49+ opts[" threads" ] = parse (Int, args[i+ 1 ])
50+ i += 2
4551 elseif a == " --timeout"
46- opts[" timeout" ] = parse (Float64, args[i+ 1 ]); i += 2
52+ opts[" timeout" ] = parse (Float64, args[i+ 1 ])
53+ i += 2
4754 elseif a == " --limit"
48- opts[" limit" ] = parse (Int, args[i+ 1 ]); i += 2
55+ opts[" limit" ] = parse (Int, args[i+ 1 ])
56+ i += 2
4957 else
5058 error (" unknown argument $a " )
5159 end
@@ -77,16 +85,19 @@ function main(args)
7785 template = corpus_template (opts[" template" ])
7886 exeflags = [" --project=$(Base. active_project ()) " , " --threads=$(opts[" threads" ]) " ]
7987
80- # Worker-side case runner; defined on each worker after it is spawned .
81- worker_setup = quote
88+ # Worker-side case runner; the imports are evaluated first so the macros below resolve .
89+ worker_imports = quote
8290 using LinearAlgebra, TOML, Printf
8391 using GeneralizedPerturbedEquilibrium
92+ end
93+ worker_setup = quote
8494 const GPE = GeneralizedPerturbedEquilibrium
8595 const FFS = GPE. ForceFreeStates
8696 function read_q_profile (path)
8797 lines = readlines (path)
8898 hdr = lines[1 ]
89- nw = parse (Int, hdr[53 : 56 ]); nh = parse (Int, hdr[57 : 60 ])
99+ nw = parse (Int, hdr[53 : 56 ])
100+ nh = parse (Int, hdr[57 : 60 ])
90101 nums = Float64[]
91102 for l in lines[2 : end ]
92103 for m in eachmatch (r" [-+]?\d *\.\d +(?:[eE][-+]?\d +)?" , l)
@@ -137,23 +148,42 @@ function main(args)
137148 total_steps= odet. total_steps, t_equil, t_prep, t_int, t_free, t_dp,
138149 et1= get (et, 1 , NaN ), et2= get (et, 2 , NaN ), et3= get (et, 3 , NaN ), dp, message= " " )
139150 end
151+ # Errors are turned into a row on the worker: a raised exception would carry method
152+ # instances the driver process cannot deserialize.
153+ function run_case_safe (geqdsk:: String , template:: Dict{String,Any} )
154+ t0 = time ()
155+ try
156+ return run_case (geqdsk, template)
157+ catch err
158+ msg = first (sprint (showerror, err), 400 )
159+ return (status= " failed" , elapsed= time () - t0, nw= 0 , q0= NaN , qmin= NaN , psi_qmin= NaN , qedge= NaN , N= 0 , msing= 0 , surfaces= " " ,
160+ total_steps= 0 , t_equil= NaN , t_prep= NaN , t_int= NaN , t_free= NaN , t_dp= NaN , et1= NaN , et2= NaN , et3= NaN , dp= " " , message= msg)
161+ end
162+ end
163+ nothing # the eval's return value travels back to the driver; a function object would not deserialize there
140164 end
141165
142166 function spawn_worker ()
143167 pid = only (addprocs (1 ; exeflags= exeflags))
168+ remotecall_fetch (Core. eval, pid, Main, worker_imports)
144169 remotecall_fetch (Core. eval, pid, Main, worker_setup)
170+ remotecall_fetch (Core. eval, pid, Main, :(const TEMPLATE = $ template))
145171 return pid
146172 end
147173
148174 io = open (opts[" out" ], " w" )
149175 println (io, HEADER)
150176 flush (io)
151177 write_row (idx, rel, r) = begin
152- println (io, join ([idx, rel, r. status, @sprintf (" %.1f" , r. elapsed), r. nw, @sprintf (" %.4f" , r. q0), @sprintf (" %.4f" , r. qmin),
153- @sprintf (" %.3f" , r. psi_qmin), @sprintf (" %.3f" , r. qedge), r. N, r. msing, r. surfaces, r. total_steps,
154- @sprintf (" %.2f" , r. t_equil), @sprintf (" %.2f" , r. t_prep), @sprintf (" %.2f" , r. t_int), @sprintf (" %.2f" , r. t_free),
155- @sprintf (" %.2f" , r. t_dp), @sprintf (" %.8e" , r. et1), @sprintf (" %.8e" , r. et2), @sprintf (" %.8e" , r. et3), r. dp,
156- replace (r. message, " ," => " ;" , " \n " => " " )], " ," ))
178+ println (
179+ io,
180+ join (
181+ [idx, rel, r. status, @sprintf (" %.1f" , r. elapsed), r. nw, @sprintf (" %.4f" , r. q0), @sprintf (" %.4f" , r. qmin),
182+ @sprintf (" %.3f" , r. psi_qmin), @sprintf (" %.3f" , r. qedge), r. N, r. msing, r. surfaces, r. total_steps,
183+ @sprintf (" %.2f" , r. t_equil), @sprintf (" %.2f" , r. t_prep), @sprintf (" %.2f" , r. t_int), @sprintf (" %.2f" , r. t_free),
184+ @sprintf (" %.2f" , r. t_dp), @sprintf (" %.8e" , r. et1), @sprintf (" %.8e" , r. et2), @sprintf (" %.8e" , r. et3), r. dp,
185+ replace (r. message, " ," => " ;" , " \n " => " " )], " ," )
186+ )
157187 flush (io)
158188 end
159189 blank (status, elapsed, msg) = (status, elapsed, nw= 0 , q0= NaN , qmin= NaN , psi_qmin= NaN , qedge= NaN , N= 0 , msing= 0 , surfaces= " " , total_steps= 0 ,
@@ -172,15 +202,15 @@ function main(args)
172202 for (idx, rel) in queue
173203 path = joinpath (opts[" root" ], rel)
174204 t0 = time ()
175- task = @async remotecall_fetch (Main . run_case , pid, path, template )
205+ task = @async remotecall_fetch (Core . eval , pid, Main, :( run_case_safe ( $ path, TEMPLATE)) )
176206 while ! istaskdone (task) && time () - t0 < opts[" timeout" ]
177207 sleep (1 )
178208 end
179209 r = if istaskdone (task)
180210 try
181211 fetch (task)
182212 catch err
183- blank (" failed" , time () - t0, sprint (showerror, err)[ 1 : min ( end , 300 )] )
213+ blank (" failed" , time () - t0, first ( sprint (showerror, err), 300 ))
184214 end
185215 else
186216 rmprocs (pid; waitfor= 5 )
0 commit comments