xref: /xnu-11215.41.3/tools/format_vm_parameter_validation.py (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1*33de042dSApple OSS Distributions#!/usr/bin/python3
2*33de042dSApple OSS Distributions
3*33de042dSApple OSS Distributions# format_vm_parameter_validation.py
4*33de042dSApple OSS Distributions# Pretty-print the output of tests/vm/vm_parameter_validation.c
5*33de042dSApple OSS Distributions#
6*33de042dSApple OSS Distributions# usage:
7*33de042dSApple OSS Distributions#     vm_parameter_validation | format_vm_parameter_validation.py
8*33de042dSApple OSS Distributions
9*33de042dSApple OSS Distributionsimport re
10*33de042dSApple OSS Distributionsimport sys
11*33de042dSApple OSS Distributionsimport copy
12*33de042dSApple OSS Distributionsimport itertools
13*33de042dSApple OSS Distributions
14*33de042dSApple OSS Distributions# magic return values used for in-band signalling
15*33de042dSApple OSS Distributions# fixme duplicated in vm_parameter_validation.c
16*33de042dSApple OSS Distributions# fixme also duplicated in other_return_values below
17*33de042dSApple OSS DistributionsRESULT_SUCCESS  = 0
18*33de042dSApple OSS DistributionsRESULT_BUSTED   = -99
19*33de042dSApple OSS DistributionsRESULT_IGNORED  = -98
20*33de042dSApple OSS DistributionsRESULT_ZEROSIZE = -97
21*33de042dSApple OSS DistributionsRESULT_PANIC    = -96
22*33de042dSApple OSS DistributionsRESULT_GUARD    = -95
23*33de042dSApple OSS DistributionsRESULT_MISMATCH = -94
24*33de042dSApple OSS DistributionsRESULT_OUT_PARAM_BAD = -93
25*33de042dSApple OSS DistributionsRESULT_MACH_SEND_INVALID_MEMORY = 0x1000000c
26*33de042dSApple OSS Distributions
27*33de042dSApple OSS Distributions# output formatting
28*33de042dSApple OSS Distributionsformat_result = {
29*33de042dSApple OSS Distributions    RESULT_SUCCESS  : '  .',
30*33de042dSApple OSS Distributions    RESULT_BUSTED   : ' **',
31*33de042dSApple OSS Distributions    RESULT_MISMATCH : ' ##',
32*33de042dSApple OSS Distributions    RESULT_IGNORED  : '   ',
33*33de042dSApple OSS Distributions    RESULT_ZEROSIZE : '  o',
34*33de042dSApple OSS Distributions    RESULT_PANIC    : ' pp',
35*33de042dSApple OSS Distributions    RESULT_GUARD    : ' gg',
36*33de042dSApple OSS Distributions    RESULT_OUT_PARAM_BAD: ' ot',
37*33de042dSApple OSS Distributions    RESULT_MACH_SEND_INVALID_MEMORY : ' mi',
38*33de042dSApple OSS Distributions}
39*33de042dSApple OSS Distributions
40*33de042dSApple OSS Distributionsformat_default = '%3d'
41*33de042dSApple OSS Distributionsformat_col_width = 3
42*33de042dSApple OSS Distributionsformat_empty_col = format_col_width * ' '
43*33de042dSApple OSS Distributionsformat_indent_width = 4
44*33de042dSApple OSS Distributionsformat_indent = format_indent_width * ' '
45*33de042dSApple OSS Distributions
46*33de042dSApple OSS Distributions
47*33de042dSApple OSS Distributions# record the result of one trial:
48*33de042dSApple OSS Distributions# ret: the return value from the tested function
49*33de042dSApple OSS Distributions# parameters: array of the input parameter names for that trial
50*33de042dSApple OSS Distributions#   (for example ["start PGSZ-2", "size -1"])
51*33de042dSApple OSS Distributionsclass Result:
52*33de042dSApple OSS Distributions    def __init__(self, new_ret, new_parameters):
53*33de042dSApple OSS Distributions        self.ret = new_ret
54*33de042dSApple OSS Distributions        self.parameters = new_parameters
55*33de042dSApple OSS Distributions    def __repr__(self):
56*33de042dSApple OSS Distributions        return str(self.ret) + " = " + str(self.parameters)
57*33de042dSApple OSS Distributions
58*33de042dSApple OSS Distributions# record the results of all trials in one test
59*33de042dSApple OSS Distributions# testname: the name of the test (including the function being tested)
60*33de042dSApple OSS Distributions# config: a string describing OS, CPU, etc
61*33de042dSApple OSS Distributions# compat: code for error compatibility
62*33de042dSApple OSS Distributions# results: an array of Result, one per trial
63*33de042dSApple OSS Distributionsclass Test:
64*33de042dSApple OSS Distributions    def __init__(self, new_name, new_config, new_compat, new_results = []):
65*33de042dSApple OSS Distributions        self.testname = new_name
66*33de042dSApple OSS Distributions        self.config = new_config
67*33de042dSApple OSS Distributions        self.compat = new_compat
68*33de042dSApple OSS Distributions        self.results = new_results
69*33de042dSApple OSS Distributions
70*33de042dSApple OSS Distributions# print column labels under some output
71*33de042dSApple OSS Distributions# example output given indent=2 col_width=4 labels=[foo,bar,baz,qux]:
72*33de042dSApple OSS Distributions#  |   |   |   |
73*33de042dSApple OSS Distributions#  |   |   |   qux
74*33de042dSApple OSS Distributions#  |   |   baz
75*33de042dSApple OSS Distributions#  |   bar
76*33de042dSApple OSS Distributions#  foo
77*33de042dSApple OSS Distributionsdef print_column_labels(labels, indent_width, col_width):
78*33de042dSApple OSS Distributions    indent = indent_width * ' '
79*33de042dSApple OSS Distributions    empty_column = '|' + (col_width-1) * ' '
80*33de042dSApple OSS Distributions
81*33de042dSApple OSS Distributions    unprinted = len(labels)
82*33de042dSApple OSS Distributions    print(indent + unprinted*empty_column)
83*33de042dSApple OSS Distributions
84*33de042dSApple OSS Distributions    for label in reversed(labels):
85*33de042dSApple OSS Distributions        unprinted -= 1
86*33de042dSApple OSS Distributions        print(indent + unprinted*empty_column + label)
87*33de042dSApple OSS Distributions
88*33de042dSApple OSS Distributions# pretty-print one function return code
89*33de042dSApple OSS Distributionsdef print_one_result(ret):
90*33de042dSApple OSS Distributions    if ret in format_result:
91*33de042dSApple OSS Distributions        print(format_result[ret], end='')
92*33de042dSApple OSS Distributions    else:
93*33de042dSApple OSS Distributions        print(format_default % (ret), end='')
94*33de042dSApple OSS Distributions
95*33de042dSApple OSS Distributions# choose the appropriate error code table for a test
96*33de042dSApple OSS Distributions# (either errno_return_values or kern_return_values)
97*33de042dSApple OSS Distributionsdef error_code_values_for_test(test):
98*33de042dSApple OSS Distributions    errno_fns = ['mprotect', 'msync', 'minherit', 'mincore', 'mlock', 'munlock',
99*33de042dSApple OSS Distributions                 'mmap', 'munmap', 'mremap_encrypted', 'vslock', 'vsunlock',
100*33de042dSApple OSS Distributions                 'madvise', 'useracc']
101*33de042dSApple OSS Distributions    for fn in errno_fns:
102*33de042dSApple OSS Distributions        if test.testname.startswith(fn):
103*33de042dSApple OSS Distributions            return errno_return_values
104*33de042dSApple OSS Distributions    else:
105*33de042dSApple OSS Distributions        return kern_return_values
106*33de042dSApple OSS Distributions
107*33de042dSApple OSS Distributions# print a helpful description of the return values seen in results
108*33de042dSApple OSS Distributions# fixme these won't include RESULT_MISMATCH
109*33de042dSApple OSS Distributionsdef print_legend(test):
110*33de042dSApple OSS Distributions    # find all error codes represented in the results
111*33de042dSApple OSS Distributions    codes = {}
112*33de042dSApple OSS Distributions    for result in test.results:
113*33de042dSApple OSS Distributions        codes[result.ret] = True
114*33de042dSApple OSS Distributions
115*33de042dSApple OSS Distributions    known_return_values = error_code_values_for_test(test)
116*33de042dSApple OSS Distributions
117*33de042dSApple OSS Distributions    # print the names of the detected error codes
118*33de042dSApple OSS Distributions    output = []
119*33de042dSApple OSS Distributions    for code in sorted(codes.keys()):
120*33de042dSApple OSS Distributions        if code in known_return_values:
121*33de042dSApple OSS Distributions            output.append(str(code) + ': ' + known_return_values[code])
122*33de042dSApple OSS Distributions        elif code in other_return_values:
123*33de042dSApple OSS Distributions            output.append(other_return_values[code])
124*33de042dSApple OSS Distributions        elif code != 0:
125*33de042dSApple OSS Distributions            output.append(str(code) + ': ????')
126*33de042dSApple OSS Distributions
127*33de042dSApple OSS Distributions    print(format_indent + '(' + ', '.join(output) + ')')
128*33de042dSApple OSS Distributions
129*33de042dSApple OSS Distributions# display names for error codes returned in errno
130*33de042dSApple OSS Distributionserrno_return_values = {
131*33de042dSApple OSS Distributions    1: 'EPERM',
132*33de042dSApple OSS Distributions    9: 'EBADF',
133*33de042dSApple OSS Distributions    12: 'ENOMEM',
134*33de042dSApple OSS Distributions    13: 'EACCES',
135*33de042dSApple OSS Distributions    14: 'EFAULT',
136*33de042dSApple OSS Distributions    22: 'EINVAL',
137*33de042dSApple OSS Distributions}
138*33de042dSApple OSS Distributions
139*33de042dSApple OSS Distributions# display names for error codes returned in kern_return_t
140*33de042dSApple OSS Distributionskern_return_values = {
141*33de042dSApple OSS Distributions    1: 'KERN_INVALID_ADDRESS',
142*33de042dSApple OSS Distributions    2: 'KERN_PROTECTION_FAILURE',
143*33de042dSApple OSS Distributions    3: 'KERN_NO_SPACE',
144*33de042dSApple OSS Distributions    4: 'KERN_INVALID_ARGUMENT',
145*33de042dSApple OSS Distributions    5: 'KERN_FAILURE',
146*33de042dSApple OSS Distributions    6: 'KERN_RESOURCE_SHORTAGE',
147*33de042dSApple OSS Distributions    7: 'KERN_NOT_RECEIVER',
148*33de042dSApple OSS Distributions    8: 'KERN_NO_ACCESS',
149*33de042dSApple OSS Distributions    9: 'KERN_MEMORY_FAILURE',
150*33de042dSApple OSS Distributions    10: 'KERN_MEMORY_ERROR',
151*33de042dSApple OSS Distributions    11: 'KERN_ALREADY_IN_SET',
152*33de042dSApple OSS Distributions    12: 'KERN_NOT_IN_SET',
153*33de042dSApple OSS Distributions    13: 'KERN_NAME_EXISTS',
154*33de042dSApple OSS Distributions    14: 'KERN_ABORTED',
155*33de042dSApple OSS Distributions    15: 'KERN_INVALID_NAME',
156*33de042dSApple OSS Distributions    16: 'KERN_INVALID_TASK',
157*33de042dSApple OSS Distributions    17: 'KERN_INVALID_RIGHT',
158*33de042dSApple OSS Distributions    18: 'KERN_INVALID_VALUE',
159*33de042dSApple OSS Distributions    19: 'KERN_UREFS_OVERFLOW',
160*33de042dSApple OSS Distributions    20: 'KERN_INVALID_CAPABILITY',
161*33de042dSApple OSS Distributions    21: 'KERN_RIGHT_EXISTS',
162*33de042dSApple OSS Distributions    22: 'KERN_INVALID_HOST',
163*33de042dSApple OSS Distributions    23: 'KERN_MEMORY_PRESENT',
164*33de042dSApple OSS Distributions    24: 'KERN_MEMORY_DATA_MOVED',
165*33de042dSApple OSS Distributions    25: 'KERN_MEMORY_RESTART_COPY',
166*33de042dSApple OSS Distributions    26: 'KERN_INVALID_PROCESSOR_SET',
167*33de042dSApple OSS Distributions    27: 'KERN_POLICY_LIMIT',
168*33de042dSApple OSS Distributions    28: 'KERN_INVALID_POLICY',
169*33de042dSApple OSS Distributions    29: 'KERN_INVALID_OBJECT',
170*33de042dSApple OSS Distributions    30: 'KERN_ALREADY_WAITING',
171*33de042dSApple OSS Distributions    31: 'KERN_DEFAULT_SET',
172*33de042dSApple OSS Distributions    32: 'KERN_EXCEPTION_PROTECTED',
173*33de042dSApple OSS Distributions    33: 'KERN_INVALID_LEDGER',
174*33de042dSApple OSS Distributions    34: 'KERN_INVALID_MEMORY_CONTROL',
175*33de042dSApple OSS Distributions    35: 'KERN_INVALID_SECURITY',
176*33de042dSApple OSS Distributions    36: 'KERN_NOT_DEPRESSED',
177*33de042dSApple OSS Distributions    37: 'KERN_TERMINATED',
178*33de042dSApple OSS Distributions    38: 'KERN_LOCK_SET_DESTROYED',
179*33de042dSApple OSS Distributions    39: 'KERN_LOCK_UNSTABLE',
180*33de042dSApple OSS Distributions    40: 'KERN_LOCK_OWNED',
181*33de042dSApple OSS Distributions    41: 'KERN_LOCK_OWNED_SELF',
182*33de042dSApple OSS Distributions    42: 'KERN_SEMAPHORE_DESTROYED',
183*33de042dSApple OSS Distributions    43: 'KERN_RPC_SERVER_TERMINATED',
184*33de042dSApple OSS Distributions    44: 'KERN_RPC_TERMINATE_ORPHAN',
185*33de042dSApple OSS Distributions    45: 'KERN_RPC_CONTINUE_ORPHAN',
186*33de042dSApple OSS Distributions    46: 'KERN_NOT_SUPPORTED',
187*33de042dSApple OSS Distributions    47: 'KERN_NODE_DOWN',
188*33de042dSApple OSS Distributions    48: 'KERN_NOT_WAITING',
189*33de042dSApple OSS Distributions    49: 'KERN_OPERATION_TIMED_OUT',
190*33de042dSApple OSS Distributions    50: 'KERN_CODESIGN_ERROR',
191*33de042dSApple OSS Distributions    51: 'KERN_POLICY_STATIC',
192*33de042dSApple OSS Distributions    52: 'KERN_INSUFFICIENT_BUFFER_SIZE',
193*33de042dSApple OSS Distributions    53: 'KERN_DENIED',
194*33de042dSApple OSS Distributions    54: 'KERN_MISSING_KC',
195*33de042dSApple OSS Distributions    55: 'KERN_INVALID_KC',
196*33de042dSApple OSS Distributions    56: 'KERN_NOT_FOUND',
197*33de042dSApple OSS Distributions    100: 'KERN_RETURN_MAX',
198*33de042dSApple OSS Distributions    -304: 'MIG_BAD_ARGUMENTS (server type check failure)',
199*33de042dSApple OSS Distributions    0x1000000c : 'MACH_SEND_INVALID_MEMORY',
200*33de042dSApple OSS Distributions}
201*33de042dSApple OSS Distributions
202*33de042dSApple OSS Distributions# display names for the special return values used by the test machinery
203*33de042dSApple OSS Distributionsother_return_values = {
204*33de042dSApple OSS Distributions    RESULT_BUSTED: format_result[RESULT_BUSTED].lstrip() + ': trial broken, not performed',
205*33de042dSApple OSS Distributions    RESULT_IGNORED: '<empty> trial ignored, not performed',
206*33de042dSApple OSS Distributions    RESULT_ZEROSIZE: format_result[RESULT_ZEROSIZE].lstrip() + ': size == 0',
207*33de042dSApple OSS Distributions    RESULT_PANIC: format_result[RESULT_PANIC].lstrip() + ': trial is believed to panic, not performed',
208*33de042dSApple OSS Distributions    RESULT_GUARD: format_result[RESULT_GUARD].lstrip() + ': trial is believed to throw EXC_GUARD, not performed',
209*33de042dSApple OSS Distributions    RESULT_OUT_PARAM_BAD: format_result[RESULT_OUT_PARAM_BAD].lstrip() + ': trial set incorrect values to out parameters',
210*33de042dSApple OSS Distributions}
211*33de042dSApple OSS Distributions
212*33de042dSApple OSS Distributions# inside line, replace 'return 123' with 'return ERR_CODE_NAME'
213*33de042dSApple OSS Distributionsdef replace_error_code_return(test, line):
214*33de042dSApple OSS Distributions    known_return_values = error_code_values_for_test(test)
215*33de042dSApple OSS Distributions    for code, name in known_return_values.items():
216*33de042dSApple OSS Distributions        line = line.replace('return ' + str(code) + ';', 'return ' + name + ';')
217*33de042dSApple OSS Distributions    return line
218*33de042dSApple OSS Distributions
219*33de042dSApple OSS Distributionsdef dimensions(results):
220*33de042dSApple OSS Distributions    if len(results) == 0:
221*33de042dSApple OSS Distributions        return 0
222*33de042dSApple OSS Distributions    return len(results[0].parameters)
223*33de042dSApple OSS Distributions
224*33de042dSApple OSS Distributions# given one k-dimensional results
225*33de042dSApple OSS Distributions# return a list of k counts that is the size of each dimension
226*33de042dSApple OSS Distributionsdef count_each_dimension(results):
227*33de042dSApple OSS Distributions    if len(results) == 0:
228*33de042dSApple OSS Distributions        return []
229*33de042dSApple OSS Distributions    first = results[0].parameters
230*33de042dSApple OSS Distributions    k = dimensions(results)
231*33de042dSApple OSS Distributions    counts = []
232*33de042dSApple OSS Distributions    step = 1
233*33de042dSApple OSS Distributions    for dim in range(k-1, -1, -1):
234*33de042dSApple OSS Distributions        count = round(len(results) / step)
235*33de042dSApple OSS Distributions        for i in range(0, len(results), step):
236*33de042dSApple OSS Distributions            cur = results[i].parameters
237*33de042dSApple OSS Distributions            if i != 0 and cur[dim] == first[dim]:
238*33de042dSApple OSS Distributions                count = round(i / step)
239*33de042dSApple OSS Distributions                break;
240*33de042dSApple OSS Distributions        step *= count
241*33de042dSApple OSS Distributions        counts.append(count)
242*33de042dSApple OSS Distributions
243*33de042dSApple OSS Distributions    counts.reverse()
244*33de042dSApple OSS Distributions    return counts;
245*33de042dSApple OSS Distributions
246*33de042dSApple OSS Distributions# Reduce one k-dimensional results to many (k-1) dimensional results
247*33de042dSApple OSS Distributions# Yields a sequence of [results, name] pairs
248*33de042dSApple OSS Distributions# where results has k-1 dimensions
249*33de042dSApple OSS Distributions# and name is the parameter name from the removed dimension
250*33de042dSApple OSS Distributionsdef iterate_dimension(results, dim = 0):
251*33de042dSApple OSS Distributions    if len(results) == 0:
252*33de042dSApple OSS Distributions        return
253*33de042dSApple OSS Distributions
254*33de042dSApple OSS Distributions    k = dimensions(results)
255*33de042dSApple OSS Distributions    dim_counts = count_each_dimension(results)
256*33de042dSApple OSS Distributions
257*33de042dSApple OSS Distributions    inner_count = 1
258*33de042dSApple OSS Distributions    for d in range(dim+1, k):
259*33de042dSApple OSS Distributions        inner_count *= dim_counts[d]
260*33de042dSApple OSS Distributions
261*33de042dSApple OSS Distributions    outer_step = len(results)
262*33de042dSApple OSS Distributions    for d in range(0, dim):
263*33de042dSApple OSS Distributions        outer_step = int(outer_step / dim_counts[d])
264*33de042dSApple OSS Distributions
265*33de042dSApple OSS Distributions    for r in range(dim_counts[dim]):
266*33de042dSApple OSS Distributions        start = r * inner_count
267*33de042dSApple OSS Distributions        name = results[start].parameters[dim]
268*33de042dSApple OSS Distributions        new_results = []
269*33de042dSApple OSS Distributions        for i in range(start, len(results), outer_step):
270*33de042dSApple OSS Distributions            for j in range(inner_count):
271*33de042dSApple OSS Distributions                new_result = copy.deepcopy(results[i+j])
272*33de042dSApple OSS Distributions                del new_result.parameters[dim]
273*33de042dSApple OSS Distributions                new_results.append(new_result)
274*33de042dSApple OSS Distributions        yield [new_results, name]
275*33de042dSApple OSS Distributions
276*33de042dSApple OSS Distributions# Print the results of a test that has two parameters (for example a test of start/size)
277*33de042dSApple OSS Distributions# If overrides!=None, use any non-SUCCESS return values from override in place of the other results.
278*33de042dSApple OSS Distributionsdef print_results_2D(results, overrides=None):
279*33de042dSApple OSS Distributions    # complain if results and override have different dimensions
280*33de042dSApple OSS Distributions    if overrides:
281*33de042dSApple OSS Distributions        if len(overrides) != len(results):
282*33de042dSApple OSS Distributions            print("WARNING: override results have a different height; overrides ignored")
283*33de042dSApple OSS Distributions        for i, result in enumerate(results):
284*33de042dSApple OSS Distributions            if len(overrides[i].parameters) != len(result.parameters):
285*33de042dSApple OSS Distributions                print("WARNING: override results have a different width; overrides ignored")
286*33de042dSApple OSS Distributions
287*33de042dSApple OSS Distributions    columns = []
288*33de042dSApple OSS Distributions    prev_row_label = ''
289*33de042dSApple OSS Distributions    first_row_label = ''
290*33de042dSApple OSS Distributions    for i, result in enumerate(results):
291*33de042dSApple OSS Distributions        if overrides: override = overrides[i].ret
292*33de042dSApple OSS Distributions
293*33de042dSApple OSS Distributions        if first_row_label == '':
294*33de042dSApple OSS Distributions            # record first row's name so we can use it to find columns
295*33de042dSApple OSS Distributions            # (assumes every row has the same column labels)
296*33de042dSApple OSS Distributions            first_row_label = result.parameters[0]
297*33de042dSApple OSS Distributions
298*33de042dSApple OSS Distributions        if result.parameters[0] == first_row_label:
299*33de042dSApple OSS Distributions            # record column names in the first row
300*33de042dSApple OSS Distributions            columns.append(result.parameters[1])
301*33de042dSApple OSS Distributions
302*33de042dSApple OSS Distributions        if result.parameters[0] != prev_row_label:
303*33de042dSApple OSS Distributions            # new row
304*33de042dSApple OSS Distributions            if prev_row_label != '': print(format_indent + prev_row_label)
305*33de042dSApple OSS Distributions            print(format_indent, end='')
306*33de042dSApple OSS Distributions            prev_row_label = result.parameters[0]
307*33de042dSApple OSS Distributions
308*33de042dSApple OSS Distributions        if overrides and override != RESULT_SUCCESS:
309*33de042dSApple OSS Distributions            print_one_result(override)
310*33de042dSApple OSS Distributions        else:
311*33de042dSApple OSS Distributions            print_one_result(result.ret)
312*33de042dSApple OSS Distributions
313*33de042dSApple OSS Distributions    if prev_row_label: print(format_indent + prev_row_label)
314*33de042dSApple OSS Distributions    print_column_labels(columns, format_indent_width + format_col_width - 1, format_col_width)
315*33de042dSApple OSS Distributions
316*33de042dSApple OSS Distributionsdef print_results_2D_try_condensed(results):
317*33de042dSApple OSS Distributions    if 0 == len(results):
318*33de042dSApple OSS Distributions        return
319*33de042dSApple OSS Distributions    singleton = results[0].ret
320*33de042dSApple OSS Distributions    if any([result.ret != singleton for result in results]):
321*33de042dSApple OSS Distributions        print_results_2D(results)
322*33de042dSApple OSS Distributions        return
323*33de042dSApple OSS Distributions    # will print as condensed
324*33de042dSApple OSS Distributions    rows = set()
325*33de042dSApple OSS Distributions    cols = set()
326*33de042dSApple OSS Distributions    for result in results:
327*33de042dSApple OSS Distributions        rows.add(result.parameters[0].split()[1])
328*33de042dSApple OSS Distributions        cols.add(result.parameters[1].split()[1])
329*33de042dSApple OSS Distributions    print_one_result(result.ret)
330*33de042dSApple OSS Distributions    print(" for all pairs")
331*33de042dSApple OSS Distributions
332*33de042dSApple OSS Distributionsdef print_results_3D(results, testname):
333*33de042dSApple OSS Distributions    # foreach parameter[1], print 2D table of parameter[0] and parameter[2]
334*33de042dSApple OSS Distributions    for results2D, name in iterate_dimension(results, 1):
335*33de042dSApple OSS Distributions        print(testname + ': ' + name)
336*33de042dSApple OSS Distributions        print_results_2D(results2D)
337*33de042dSApple OSS Distributions
338*33de042dSApple OSS Distributions    # foreach parameter[0], print 2D table of parameter[1] and parameter[2]
339*33de042dSApple OSS Distributions    # This is redundant but can be useful for human readers.
340*33de042dSApple OSS Distributions    for results2D, name in iterate_dimension(results, 0):
341*33de042dSApple OSS Distributions        print(testname + ': ' + name)
342*33de042dSApple OSS Distributions        print_results_2D(results2D)
343*33de042dSApple OSS Distributions
344*33de042dSApple OSS Distributionsdef print_results_4D(results):
345*33de042dSApple OSS Distributions    x, y, z = '', '', ''
346*33de042dSApple OSS Distributions    # Make a map[{3rd_param, 4th_param, ...}] = {all options}
347*33de042dSApple OSS Distributions    # For now, we print 2d tables of 1st, 2nd param for each possible combination of remaining values
348*33de042dSApple OSS Distributions
349*33de042dSApple OSS Distributions    map_of_results = {}
350*33de042dSApple OSS Distributions    for _, result in enumerate(results):
351*33de042dSApple OSS Distributions        k = tuple(result.parameters[2:])
352*33de042dSApple OSS Distributions
353*33de042dSApple OSS Distributions        if k not in map_of_results:
354*33de042dSApple OSS Distributions            map_of_results[k] = [result]
355*33de042dSApple OSS Distributions        else:
356*33de042dSApple OSS Distributions            map_of_results[k].append(result)
357*33de042dSApple OSS Distributions
358*33de042dSApple OSS Distributions    # prepare to iterate
359*33de042dSApple OSS Distributions    prev_matrix = []
360*33de042dSApple OSS Distributions    iterable = []
361*33de042dSApple OSS Distributions    for k, result_list in map_of_results.items():
362*33de042dSApple OSS Distributions        one_2d_result = []
363*33de042dSApple OSS Distributions        matrix = []
364*33de042dSApple OSS Distributions        for result in result_list:
365*33de042dSApple OSS Distributions            x = result.parameters[0]
366*33de042dSApple OSS Distributions            y = result.parameters[1]
367*33de042dSApple OSS Distributions            repl_result = Result(result.ret, (x, y))
368*33de042dSApple OSS Distributions            one_2d_result.append(repl_result)
369*33de042dSApple OSS Distributions            matrix.append(result.ret)
370*33de042dSApple OSS Distributions        if matrix == prev_matrix:
371*33de042dSApple OSS Distributions            # if the return codes are the same everywhere, we will print successive tables only once
372*33de042dSApple OSS Distributions            # note that this assumes that the sets of 2D labels are the same everywhere, and doesn't check that assumption
373*33de042dSApple OSS Distributions            iterable[-1][0].append(k)
374*33de042dSApple OSS Distributions        else:
375*33de042dSApple OSS Distributions            iterable.append(([k], one_2d_result))
376*33de042dSApple OSS Distributions        prev_matrix = matrix
377*33de042dSApple OSS Distributions
378*33de042dSApple OSS Distributions    # print
379*33de042dSApple OSS Distributions    for iter in iterable:
380*33de042dSApple OSS Distributions        print(iter[0])
381*33de042dSApple OSS Distributions        print_results_2D_try_condensed(iter[1])
382*33de042dSApple OSS Distributions
383*33de042dSApple OSS Distributions
384*33de042dSApple OSS Distributions# Print the results of a test that has two parameters
385*33de042dSApple OSS Distributions# (for example a test of addr only, or size only)
386*33de042dSApple OSS Distributions# If overrides!=None, use any non-SUCCESS return values from override in place of the other results.
387*33de042dSApple OSS Distributionsdef print_results_1D(results, overrides=None):
388*33de042dSApple OSS Distributions    # complain if results and overrides have different dimensions
389*33de042dSApple OSS Distributions    if overrides:
390*33de042dSApple OSS Distributions        if len(overrides) != len(results):
391*33de042dSApple OSS Distributions            print("WARNING: override results have a different height; overrides ignored")
392*33de042dSApple OSS Distributions        for i, result in enumerate(results):
393*33de042dSApple OSS Distributions            if len(overrides[i].parameters) != len(result.parameters):
394*33de042dSApple OSS Distributions                print("WARNING: override results have a different width; overrides ignored")
395*33de042dSApple OSS Distributions
396*33de042dSApple OSS Distributions    for i, result in enumerate(results):
397*33de042dSApple OSS Distributions        if overrides: override = overrides[i].ret
398*33de042dSApple OSS Distributions
399*33de042dSApple OSS Distributions        # indent, value, indent, label
400*33de042dSApple OSS Distributions        print(format_indent, end='')
401*33de042dSApple OSS Distributions        if overrides and override != RESULT_SUCCESS:
402*33de042dSApple OSS Distributions            print_one_result(override)
403*33de042dSApple OSS Distributions        else:
404*33de042dSApple OSS Distributions            print_one_result(result.ret)
405*33de042dSApple OSS Distributions        print(format_indent + result.parameters[0])
406*33de042dSApple OSS Distributions
407*33de042dSApple OSS Distributionsdef print_results_nD(results, testname, overrides=None):
408*33de042dSApple OSS Distributions    if (dimensions(results) == 1):
409*33de042dSApple OSS Distributions        print_results_1D(results, overrides)
410*33de042dSApple OSS Distributions    elif (dimensions(results) == 2):
411*33de042dSApple OSS Distributions        print_results_2D(results, overrides)
412*33de042dSApple OSS Distributions    elif dimensions(results) == 3:
413*33de042dSApple OSS Distributions        print_results_3D(results, testname)
414*33de042dSApple OSS Distributions    elif dimensions(results) == 4:
415*33de042dSApple OSS Distributions        print_results_4D(results)
416*33de042dSApple OSS Distributions    else:
417*33de042dSApple OSS Distributions        print(format_indent + 'too many dimensions')
418*33de042dSApple OSS Distributions
419*33de042dSApple OSS Distributions
420*33de042dSApple OSS Distributionsdef main():
421*33de042dSApple OSS Distributions    data = sys.stdin.readlines()
422*33de042dSApple OSS Distributions
423*33de042dSApple OSS Distributions
424*33de042dSApple OSS Distributions    # remove any lines that don't start with "TESTNAME" or "TESTCONFIG" or "RESULT"
425*33de042dSApple OSS Distributions    # (including darwintest output like "PASS" or "FAIL")
426*33de042dSApple OSS Distributions    # and print them now
427*33de042dSApple OSS Distributions    # Also verify that the counts of "TEST BEGIN" == "TEST END"
428*33de042dSApple OSS Distributions    # (they will mismatch if a test suite crashed)
429*33de042dSApple OSS Distributions    testbegincount = 0
430*33de042dSApple OSS Distributions    testendcount = 0
431*33de042dSApple OSS Distributions    testlines = []
432*33de042dSApple OSS Distributions    for line in data:
433*33de042dSApple OSS Distributions        unmodified_line = line
434*33de042dSApple OSS Distributions        # count TEST BEGIN and TEST END
435*33de042dSApple OSS Distributions        if ('TEST BEGIN' in line):
436*33de042dSApple OSS Distributions            testbegincount += 1
437*33de042dSApple OSS Distributions        if ('TEST END' in line):
438*33de042dSApple OSS Distributions            testendcount += 1
439*33de042dSApple OSS Distributions        # remove any T_LOG() timestamp prefixes and KTEST prefixes
440*33de042dSApple OSS Distributions        line = re.sub('^\s*\d+:\d+:\d+ ', '', line)
441*33de042dSApple OSS Distributions        line = re.sub('^\[KTEST\]\s+[A-Z]+\s+\d+\s+(\d+\s+)?\S+\s+\d+\s+', '', line)
442*33de042dSApple OSS Distributions        line = line.lstrip()
443*33de042dSApple OSS Distributions
444*33de042dSApple OSS Distributions        if (line.startswith('TESTNAME') or line.startswith('RESULT')
445*33de042dSApple OSS Distributions            or line.startswith('TESTCONFIG') or line.startswith('TESTCOMPAT')):
446*33de042dSApple OSS Distributions            testlines.append(line)  # line is test output
447*33de042dSApple OSS Distributions        elif line == '':
448*33de042dSApple OSS Distributions            pass # ignore empty lines
449*33de042dSApple OSS Distributions        else:
450*33de042dSApple OSS Distributions            print(unmodified_line, end='')  # line is other output
451*33de042dSApple OSS Distributions
452*33de042dSApple OSS Distributions    # parse test output into Test and Result objects
453*33de042dSApple OSS Distributions
454*33de042dSApple OSS Distributions    testnum = 0
455*33de042dSApple OSS Distributions    def group_by_test(line):
456*33de042dSApple OSS Distributions        nonlocal testnum
457*33de042dSApple OSS Distributions        if line.startswith('TESTNAME '):
458*33de042dSApple OSS Distributions            testnum = testnum+1
459*33de042dSApple OSS Distributions        return testnum
460*33de042dSApple OSS Distributions
461*33de042dSApple OSS Distributions    tests = []
462*33de042dSApple OSS Distributions    for _, group in itertools.groupby(testlines, group_by_test):
463*33de042dSApple OSS Distributions        lines = list(group)
464*33de042dSApple OSS Distributions
465*33de042dSApple OSS Distributions        name = lines.pop(0).removeprefix('TESTNAME ').rstrip()
466*33de042dSApple OSS Distributions        config = lines.pop(0).removeprefix('TESTCONFIG ').rstrip()
467*33de042dSApple OSS Distributions        compat = []
468*33de042dSApple OSS Distributions        results = []
469*33de042dSApple OSS Distributions        for line in lines:
470*33de042dSApple OSS Distributions            if line.startswith('RESULT'):
471*33de042dSApple OSS Distributions                components = line.removeprefix('RESULT ').rstrip().split(', ')
472*33de042dSApple OSS Distributions                ret = int(components.pop(0))
473*33de042dSApple OSS Distributions                results.append(Result(ret, components))
474*33de042dSApple OSS Distributions
475*33de042dSApple OSS Distributions        tests.append(Test(name, config, compat, results))
476*33de042dSApple OSS Distributions
477*33de042dSApple OSS Distributions    print('found %d tests' % (len(tests)))
478*33de042dSApple OSS Distributions
479*33de042dSApple OSS Distributions    # stats to print at the end
480*33de042dSApple OSS Distributions    test_count = len(tests)
481*33de042dSApple OSS Distributions    all_configurations = set()
482*33de042dSApple OSS Distributions
483*33de042dSApple OSS Distributions    # print test output
484*33de042dSApple OSS Distributions    for test in tests:
485*33de042dSApple OSS Distributions        # print test name and test config on separate lines
486*33de042dSApple OSS Distributions        # `diff` handles this better than putting both on the same line
487*33de042dSApple OSS Distributions        print('test ' + test.testname)
488*33de042dSApple OSS Distributions
489*33de042dSApple OSS Distributions        print(format_indent + 'config ' + test.config)
490*33de042dSApple OSS Distributions        all_configurations.add(test.config)
491*33de042dSApple OSS Distributions
492*33de042dSApple OSS Distributions        if len(test.results) == 0:
493*33de042dSApple OSS Distributions            print(format_indent + 'no results')
494*33de042dSApple OSS Distributions        else:
495*33de042dSApple OSS Distributions            print_legend(test)
496*33de042dSApple OSS Distributions            print_results_nD(test.results, test.testname)
497*33de042dSApple OSS Distributions
498*33de042dSApple OSS Distributions
499*33de042dSApple OSS Distributions        print('end  ' + test.testname)
500*33de042dSApple OSS Distributions
501*33de042dSApple OSS Distributions    print()
502*33de042dSApple OSS Distributions    print(str(test_count) + ' test(s) performed')
503*33de042dSApple OSS Distributions
504*33de042dSApple OSS Distributions    if (testbegincount != testendcount):
505*33de042dSApple OSS Distributions        print('### error: %d TEST BEGINs, %d TEST ENDs - some tests may have crashed'
506*33de042dSApple OSS Distributions              % (testbegincount, testendcount))
507*33de042dSApple OSS Distributions
508*33de042dSApple OSS Distributions    print(str(len(all_configurations)) + ' configuration(s) tested:')
509*33de042dSApple OSS Distributions    for config in sorted(all_configurations):
510*33de042dSApple OSS Distributions        print(format_indent + '[' + config + ']')
511*33de042dSApple OSS Distributions
512*33de042dSApple OSS Distributions
513*33de042dSApple OSS Distributionsmain()
514