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

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