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