9 import subprocess as SUB
13 (usage = "%prog [-t] [-d FILE] [-j JOBS] [-n SAMPLES] [-r REF] VAR ...")
14 op.disable_interspersed_args()
15 for short, long, kw in \
16 [("-d", "--dictionary",
17 dict(type = "string", metavar = "DICT",
18 dest = "dict", default = "/usr/share/dict/words",
19 help = "word list to process")),
21 dict(type = "int", metavar = "JOBS",
22 dest = "njobs", default = 1,
23 help = "number of jobs to run concurrently")),
25 dict(type = "int", metavar = "SAMPLES",
26 dest = "nsamples", default = 5,
27 help = "number of samples for each variant")),
29 dict(type = "string", metavar = "REF",
30 dest = "ref", default = None,
31 help = "reference output data expected")),
33 dict(action = "store_true", dest = "terminal", default = None,
34 help = "show progress display"))]:
35 op.add_option(short, long, **kw)
36 OPTS, ARGS = op.parse_args()
40 REF = "REF.%s" % OS.path.basename(OPTS.dict)
41 if not OS.path.exists(REF): REF = None
47 class BasicVariant (object):
49 def __init__(me, name, row):
53 me._prog = "./chain.%s" % name
58 return len(me.samples)
62 fd = OS.open(OPTS.dict, OS.O_RDONLY)
63 if fd != 0: OS.dup2(fd, 0); OS.close(fd)
65 fd = OS.open(out, OS.O_WRONLY | OS.O_CREAT | OS.O_TRUNC, 0o666)
66 if fd != 1: OS.dup2(fd, 1); OS.close(fd)
67 OS.execv(me._prog, [me._prog])
70 me.samples.append(time)
73 class LispVariant (BasicVariant):
74 def __init__(me, name, *args, **kw):
75 super(LispVariant, me).__init__(name, *args, **kw)
76 me._time = "time.%s" % name
78 me._prog = "chain.lisp"
82 fd = OS.open(out, OS.O_WRONLY | OS.O_CREAT | OS.O_TRUNC, 0o666)
83 if fd != 1: OS.dup2(fd, 1); OS.close(fd)
84 OS.execvp("runlisp", ["runlisp", "-L%s" % me._lisp,
85 me._prog, "-T%s" % me._time, OPTS.dict])
88 #with open(me._time) as f: time = 1000*float(f.read())
90 me.samples.append(time)
94 if OS.WIFEXITED(st): return "rc = %d" % OS.WEXITSTATUS(st)
95 elif OS.WIFSIGNALED(st): return "signal = %d" % OS.WTERMSIG(st)
96 else: return "?st = %d" % st
110 def _setdpy(me, dpy):
114 if arg.startswith("lisp-"): var = LispVariant(arg, me._nextrow)
115 else: var = BasicVariant(arg, me._nextrow)
116 me.vars.append(var); me.idle.append(var); me._nextrow += 1
119 if me.idle and not me.bad and len(me.live) < OPTS.njobs:
121 k = RND.randrange(n); pick = me.idle[k]; assert pick.state == IDLE
122 me.idle[k] = me.idle[n - 1]; me.idle.pop()
124 if not kid: pick.start("chain.%s.out" % pick.name)
125 #me._dpy.msg(";; start %s\n" % pick.name)
126 me.live[kid] = pick; pick.state = LIVE
127 me._dpy.paint_var(pick)
130 kid, st, ru = OS.wait3(0)
131 try: var = me.live.pop(kid)
133 me._dpy.msg("ignoring unexpected child %d (%s)" %
136 assert var.state == LIVE
137 if not (OS.WIFEXITED(st) and OS.WEXITSTATUS(st) == 0):
138 me._dpy.msg("chain.%s failed (%s)" % (var.name, strwait(st)))
141 out = "chain.%s.out" % var.name
143 if SUB.call(["./chkref", out, REF]):
144 me._dpy.msg("chain.%s produced incorrect output" % var.name)
148 time = var.end(1000*(ru.ru_utime + ru.ru_stime))
149 #me._dpy.msg(";; end %s, time = %.3f s" % (var.name, time))
150 if var.n < OPTS.nsamples:
151 me.idle.append(var); var.state = IDLE
153 me.done.append(var); var.state = DONE
154 #me._dpy.msg(";; done %s\n" % var.name)
155 me._dpy.paint_var(var)
160 if OPTS.terminal or SYS.stdout.isatty():
162 class Display (object):
164 def __init__(me, state):
168 for var in me._st.vars:
169 if len(var.name) >= namewd: namewd = len(var.name) + 1
170 me._a_idle = CU.A_NORMAL
171 me._a_live = CU.A_BOLD
177 if not SYS.stdout.isatty():
178 ttyfd = OS.open("/dev/tty", OS.O_RDWR)
179 SYS.stdout = OS.fdopen(OS.dup(1), "w")
183 me._scr = CU.initscr()
186 CU.use_default_colors()
187 if CU.COLORS and CU.COLOR_PAIRS >= 3:
188 CU.init_pair(1, CU.COLOR_GREEN, -1)
189 me._a_done = CU.color_pair(1)
190 CU.init_pair(2, CU.COLOR_BLACK, CU.COLOR_GREEN)
191 CU.init_pair(3, CU.COLOR_BLACK, CU.COLOR_YELLOW)
192 me._a_bar_left = CU.color_pair(2)
193 me._a_bar_right = CU.color_pair(3)
195 me._a_live = CU.A_DIM
196 me._a_bar_left = CU.A_REVERSE
197 me._a_bar_right = None
198 me._msgrow = min(len(me._st.vars) + 1, me._ht - 1)
199 me._nmsgs = me._ht - me._msgrow
200 me._scr.setscrreg(me._msgrow, me._ht - 1)
201 me._scr.scrollok(True)
204 def __exit__(me, exval, exty, tb):
206 for m in me._msgs: SYS.stderr.write(m + "\n")
209 me._ht, me._wd = me._scr.getmaxyx()
210 barwd = me._wd - me._namewd
211 if OPTS.nsamples <= barwd: me._barsc = 1
212 else: me._barsc = float(barwd)/OPTS.nsamples
214 def paint_var(me, var, refresh = True):
215 if var.row >= me._ht - 2: return
216 rbar = int(me._barsc*OPTS.nsamples + 0.5)
217 if var.state == LIVE: attr = me._a_live
218 elif var.state == DONE: attr = me._a_done
219 else: attr = me._a_idle
220 me._scr.addstr(var.row, 0, var.name, attr)
221 mbar = int(me._barsc*len(var.samples))
222 me._scr.attrset(me._a_bar_left)
223 me._scr.hline(var.row, me._namewd, " ", mbar)
224 if me._a_bar_right is not None:
225 me._scr.attrset(me._a_bar_right)
226 me._scr.hline(var.row, me._namewd + mbar, " ", rbar - mbar)
227 me._scr.move(var.row, me._namewd + rbar)
229 me._scr.move(var.row, me._namewd + mbar)
232 avg = "%.3f ms" % (sum(var.samples)/len(var.samples))
233 if me._wd - (me._namewd + rbar) > len(avg):
234 me._scr.addstr(var.row, me._namewd + rbar + 1, avg)
236 if refresh: me._scr.refresh()
242 me._scr.addstr(min(me._msgrow + n, me._ht - 1), 0, msg)
248 for var in me._st.vars: me.paint_var(var, refresh = False)
249 n = len(me._msgs); y = me._msgrow
250 for i in range(max(0, n - me._nmsgs), n):
251 me._scr.addstr(y, 0, me._msg[i]); y += 1
256 class Display (object):
258 def __init__(me, state):
264 def __exit__(me, exval, exty, tb):
267 def paint_var(me, var):
268 if var.state == IDLE:
269 SYS.stderr.write(";; end %s, time = %.3f ms\n" %
270 (var.name, var.samples[-1]))
271 elif var.state == LIVE:
272 SYS.stderr.write(";; start %s\n" % var.name)
273 elif var.state == DONE:
274 SYS.stderr.write(";; %s all done\n" % var.name)
277 SYS.stderr.write("%s\n" % msg)
281 for arg in ARGS: STATE.addvar(arg)
283 while STATE.cycle(): pass
284 if STATE.bad: SYS.exit(2)
290 if not k%4: return x[j]
291 else: return (x[j] + x[j + 1])/2
294 q1, mid, q3 = quartile(1, x), quartile(2, x), quartile(3, x)
296 locut = BS.bisect_left(x, q1 - 1.5*iqr); lo = x[locut]
297 hicut = BS.bisect_right(x, q3 + 1.5*iqr); hi = x[hicut - 1]
299 return lo, q1, mid, avg, q3, hi
302 done.sort(key = lambda var: var.name)
303 n = OPTS.nsamples - 1
305 x = [xi for xi in var.samples]; x.sort()
306 lo, q1, mid, avg, q3, hi = stats(x)
307 print("%-16s %s; %s" %
309 " ".join("%.3f" % xi for xi in var.samples),
310 " ".join("%.3f" % xi for xi in [lo, q1, mid, avg, q3, hi])))