OILS / test / syscall.py View on Github | oilshell.org

222 lines, 132 significant
1#!/usr/bin/env python2
2"""test/syscall.py
3
4Print a results table.
5
6Input looks like
7
801-dash
901-dash
1001-osh
1101-osh
1201-osh
13...
14"""
15from __future__ import print_function
16
17import collections
18import optparse
19import re
20import sys
21
22
23def log(msg, *args):
24 if args:
25 msg = msg % args
26 print(msg, file=sys.stderr)
27
28
29def Cell(i):
30 """Visually show number of processes.
31
32 ^ ^^ ^^^ etc.
33 """
34 s = '^' * i
35 return '%6s' % s
36
37
38# lines look like this:
39#
40# 554 01-osh.1234
41# 553 01-osh.1235
42
43WC_LINE = re.compile(
44 r'''
45\s*
46(\d+) # number of lines
47\s+
48(\d{2}) # case ID
49\.
50([a-z-]+) # shell name
51''', re.VERBOSE)
52
53assert WC_LINE.match(' 68 01.osh-cpp.19610')
54
55
56def WriteHeader(f, shells, col=''):
57 f.write("ID\t")
58 for sh in shells:
59 f.write("%6s\t" % sh)
60 f.write('%s\t' % col)
61 f.write('Description')
62 f.write("\n")
63
64
65def Options():
66 """Returns an option parser instance."""
67 p = optparse.OptionParser()
68 p.add_option(
69 '--not-minimum',
70 dest='not_minimum',
71 type=int,
72 default=0,
73 help=
74 "Expected number of cases where OSH doesn't start the minimum number of"
75 "processes")
76 p.add_option(
77 '--more-than-bash',
78 dest='more_than_bash',
79 type=int,
80 default=0,
81 help=
82 'Expected number of cases where OSH starts more processes than bash')
83 return p
84
85
86def main(argv):
87 o = Options()
88 opts, argv = o.parse_args(argv[1:])
89
90 code_strs = {}
91 with open(argv[0]) as f:
92 for line in f:
93 case_id, code_str = line.split(None, 1) # whitespace
94 code_strs[case_id] = code_str
95
96 cases = set()
97 shells = set()
98
99 num_procs = collections.defaultdict(int)
100 procs_by_shell = collections.defaultdict(int)
101
102 num_syscalls = collections.defaultdict(int)
103 syscalls_by_shell = collections.defaultdict(int)
104
105 #
106 # Summarize Data
107 #
108
109 for line in sys.stdin:
110 m = WC_LINE.match(line)
111 if not m:
112 raise RuntimeError('Invalid line %r' % line)
113 num_sys, case, sh = m.groups()
114 num_sys = int(num_sys)
115
116 cases.add(case)
117 shells.add(sh)
118
119 num_procs[case, sh] += 1
120 num_syscalls[case, sh] += num_sys
121
122 procs_by_shell[sh] += 1
123 syscalls_by_shell[sh] += num_sys
124
125 f = sys.stdout
126
127 # Orders columns by how good the results are, then shell name.
128 proc_sh = sorted(procs_by_shell, key=lambda sh: (procs_by_shell[sh], sh))
129 syscall_sh = sorted(syscalls_by_shell,
130 key=lambda sh: (syscalls_by_shell[sh], sh))
131
132 #
133 # Print Tables
134 #
135
136 f.write('Number of Processes Started, by shell and test case\n\n')
137
138 WriteHeader(f, proc_sh, col='osh>min')
139
140 not_minimum = 0
141 more_than_bash = 0
142 fewer_than_bash = 0
143
144 for case_id in sorted(cases):
145 f.write(case_id + "\t")
146 min_procs = 20
147 for sh in proc_sh:
148 n = num_procs[case_id, sh]
149 f.write(Cell(n) + "\t")
150 min_procs = min(n, min_procs)
151
152 osh_count = num_procs[case_id, 'osh']
153 if osh_count != min_procs:
154 f.write('%d>%d\t' % (osh_count, min_procs))
155 not_minimum += 1
156 else:
157 f.write('\t')
158
159 bash_count = num_procs[case_id, 'bash']
160 if osh_count > bash_count:
161 more_than_bash += 1
162 if osh_count < bash_count:
163 fewer_than_bash += 1
164
165 f.write(code_strs[case_id])
166 f.write("\n")
167
168 f.write("TOTAL\t")
169 for sh in proc_sh:
170 f.write('%6d\t' % procs_by_shell[sh])
171 f.write('\n\n')
172 f.write("Cases where ...\n")
173 f.write(" OSH isn't the minimum: %d\n" % not_minimum)
174 f.write(" OSH starts more than bash: %d\n" % more_than_bash)
175 f.write(" OSH starts fewer than bash: %d\n\n" % fewer_than_bash)
176
177 #
178 # Print Table of Syscall Counts
179 #
180
181 f.write('Number of Syscalls\n\n')
182
183 WriteHeader(f, syscall_sh)
184
185 for case_id in sorted(cases):
186 f.write(case_id + "\t")
187 #min_procs = 20
188 for sh in syscall_sh:
189 n = num_syscalls[case_id, sh]
190 f.write('%6d\t' % n)
191 #min_procs = min(n, min_procs)
192
193 f.write('\t')
194
195 f.write(code_strs[case_id])
196 f.write("\n")
197
198 f.write("TOTAL\t")
199 for sh in syscall_sh:
200 f.write('%6d\t' % syscalls_by_shell[sh])
201 f.write('\n\n')
202
203 ok = True
204 if more_than_bash != opts.more_than_bash:
205 log('Expected %d more than bash, got %d', opts.more_than_bash,
206 more_than_bash)
207 ok = False
208
209 if not_minimum != opts.not_minimum:
210 log('Expected %d that are not minimal, got %d', opts.not_minimum,
211 not_minimum)
212 ok = False
213
214 return 0 if ok else 1
215
216
217if __name__ == '__main__':
218 try:
219 sys.exit(main(sys.argv))
220 except RuntimeError as e:
221 print('FATAL: %s' % e, file=sys.stderr)
222 sys.exit(1)