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