xref: /openbsd/gnu/llvm/llvm/utils/lit/lit/display.py (revision 73471bf0)
109467b48Spatrickimport sys
209467b48Spatrick
309467b48Spatrick
409467b48Spatrickdef create_display(opts, tests, total_tests, workers):
509467b48Spatrick    if opts.quiet:
609467b48Spatrick        return NopDisplay()
709467b48Spatrick
8*73471bf0Spatrick    num_tests = len(tests)
9*73471bf0Spatrick    of_total = (' of %d' % total_tests) if (num_tests != total_tests) else ''
10*73471bf0Spatrick    header = '-- Testing: %d%s tests, %d workers --' % (
11*73471bf0Spatrick        num_tests, of_total, workers)
1209467b48Spatrick
1309467b48Spatrick    progress_bar = None
1409467b48Spatrick    if opts.succinct and opts.useProgressBar:
1509467b48Spatrick        import lit.ProgressBar
1609467b48Spatrick        try:
1709467b48Spatrick            tc = lit.ProgressBar.TerminalController()
1809467b48Spatrick            progress_bar = lit.ProgressBar.ProgressBar(tc, header)
1909467b48Spatrick            header = None
2009467b48Spatrick        except ValueError:
2109467b48Spatrick            progress_bar = lit.ProgressBar.SimpleProgressBar('Testing: ')
2209467b48Spatrick
2309467b48Spatrick    return Display(opts, tests, header, progress_bar)
2409467b48Spatrick
2509467b48Spatrick
26*73471bf0Spatrickclass ProgressPredictor(object):
27*73471bf0Spatrick    def __init__(self, tests):
28*73471bf0Spatrick        self.completed = 0
29*73471bf0Spatrick        self.time_elapsed = 0.0
30*73471bf0Spatrick        self.predictable_tests_remaining = 0
31*73471bf0Spatrick        self.predictable_time_remaining = 0.0
32*73471bf0Spatrick        self.unpredictable_tests_remaining = 0
33*73471bf0Spatrick
34*73471bf0Spatrick        for test in tests:
35*73471bf0Spatrick            if test.previous_elapsed:
36*73471bf0Spatrick                self.predictable_tests_remaining += 1
37*73471bf0Spatrick                self.predictable_time_remaining += test.previous_elapsed
38*73471bf0Spatrick            else:
39*73471bf0Spatrick                self.unpredictable_tests_remaining += 1
40*73471bf0Spatrick
41*73471bf0Spatrick    def update(self, test):
42*73471bf0Spatrick        self.completed += 1
43*73471bf0Spatrick        self.time_elapsed += test.result.elapsed
44*73471bf0Spatrick
45*73471bf0Spatrick        if test.previous_elapsed:
46*73471bf0Spatrick            self.predictable_tests_remaining -= 1
47*73471bf0Spatrick            self.predictable_time_remaining -= test.previous_elapsed
48*73471bf0Spatrick        else:
49*73471bf0Spatrick            self.unpredictable_tests_remaining -= 1
50*73471bf0Spatrick
51*73471bf0Spatrick        # NOTE: median would be more precise, but might be too slow.
52*73471bf0Spatrick        average_test_time = (self.time_elapsed + self.predictable_time_remaining) / \
53*73471bf0Spatrick            (self.completed + self.predictable_tests_remaining)
54*73471bf0Spatrick        unpredictable_time_remaining = average_test_time * \
55*73471bf0Spatrick            self.unpredictable_tests_remaining
56*73471bf0Spatrick        total_time_remaining = self.predictable_time_remaining + unpredictable_time_remaining
57*73471bf0Spatrick        total_time = self.time_elapsed + total_time_remaining
58*73471bf0Spatrick
59*73471bf0Spatrick        if total_time > 0:
60*73471bf0Spatrick            return self.time_elapsed / total_time
61*73471bf0Spatrick        return 0
62*73471bf0Spatrick
63*73471bf0Spatrick
6409467b48Spatrickclass NopDisplay(object):
6509467b48Spatrick    def print_header(self): pass
6609467b48Spatrick    def update(self, test): pass
6709467b48Spatrick    def clear(self, interrupted): pass
6809467b48Spatrick
6909467b48Spatrick
7009467b48Spatrickclass Display(object):
7109467b48Spatrick    def __init__(self, opts, tests, header, progress_bar):
7209467b48Spatrick        self.opts = opts
73*73471bf0Spatrick        self.num_tests = len(tests)
7409467b48Spatrick        self.header = header
75*73471bf0Spatrick        self.progress_predictor = ProgressPredictor(
76*73471bf0Spatrick            tests) if progress_bar else None
7709467b48Spatrick        self.progress_bar = progress_bar
7809467b48Spatrick        self.completed = 0
7909467b48Spatrick
8009467b48Spatrick    def print_header(self):
8109467b48Spatrick        if self.header:
8209467b48Spatrick            print(self.header)
8309467b48Spatrick        if self.progress_bar:
8409467b48Spatrick            self.progress_bar.update(0.0, '')
8509467b48Spatrick
8609467b48Spatrick    def update(self, test):
8709467b48Spatrick        self.completed += 1
8809467b48Spatrick
8909467b48Spatrick        show_result = test.isFailure() or \
9009467b48Spatrick                self.opts.showAllOutput or \
9109467b48Spatrick                (not self.opts.quiet and not self.opts.succinct)
9209467b48Spatrick        if show_result:
9309467b48Spatrick            if self.progress_bar:
9409467b48Spatrick                self.progress_bar.clear(interrupted=False)
9509467b48Spatrick            self.print_result(test)
9609467b48Spatrick
9709467b48Spatrick        if self.progress_bar:
9809467b48Spatrick            if test.isFailure():
9909467b48Spatrick                self.progress_bar.barColor = 'RED'
100*73471bf0Spatrick            percent = self.progress_predictor.update(test)
10109467b48Spatrick            self.progress_bar.update(percent, test.getFullName())
10209467b48Spatrick
10309467b48Spatrick    def clear(self, interrupted):
10409467b48Spatrick        if self.progress_bar:
10509467b48Spatrick            self.progress_bar.clear(interrupted)
10609467b48Spatrick
10709467b48Spatrick    def print_result(self, test):
10809467b48Spatrick        # Show the test result line.
10909467b48Spatrick        test_name = test.getFullName()
11009467b48Spatrick        print('%s: %s (%d of %d)' % (test.result.code.name, test_name,
111*73471bf0Spatrick                                     self.completed, self.num_tests))
11209467b48Spatrick
11309467b48Spatrick        # Show the test failure output, if requested.
11409467b48Spatrick        if (test.isFailure() and self.opts.showOutput) or \
11509467b48Spatrick           self.opts.showAllOutput:
11609467b48Spatrick            if test.isFailure():
11709467b48Spatrick                print("%s TEST '%s' FAILED %s" % ('*'*20, test.getFullName(),
11809467b48Spatrick                                                  '*'*20))
11909467b48Spatrick            out = test.result.output
12009467b48Spatrick            # Encode/decode so that, when using Python 3.6.5 in Windows 10,
12109467b48Spatrick            # print(out) doesn't raise UnicodeEncodeError if out contains
12209467b48Spatrick            # special characters.  However, Python 2 might try to decode
12309467b48Spatrick            # as part of the encode call if out is already encoded, so skip
12409467b48Spatrick            # encoding if it raises UnicodeDecodeError.
12509467b48Spatrick            if sys.stdout.encoding:
12609467b48Spatrick                try:
12709467b48Spatrick                    out = out.encode(encoding=sys.stdout.encoding,
12809467b48Spatrick                                     errors="replace")
12909467b48Spatrick                except UnicodeDecodeError:
13009467b48Spatrick                    pass
131097a140dSpatrick                # Python 2 can raise UnicodeDecodeError here too in cases
132097a140dSpatrick                # where the stdout encoding is ASCII. Ignore decode errors
133097a140dSpatrick                # in this case.
134097a140dSpatrick                out = out.decode(encoding=sys.stdout.encoding, errors="ignore")
13509467b48Spatrick            print(out)
13609467b48Spatrick            print("*" * 20)
13709467b48Spatrick
13809467b48Spatrick        # Report test metrics, if present.
13909467b48Spatrick        if test.result.metrics:
14009467b48Spatrick            print("%s TEST '%s' RESULTS %s" % ('*'*10, test.getFullName(),
14109467b48Spatrick                                               '*'*10))
14209467b48Spatrick            items = sorted(test.result.metrics.items())
14309467b48Spatrick            for metric_name, value in items:
14409467b48Spatrick                print('%s: %s ' % (metric_name, value.format()))
14509467b48Spatrick            print("*" * 10)
14609467b48Spatrick
14709467b48Spatrick        # Report micro-tests, if present
14809467b48Spatrick        if test.result.microResults:
14909467b48Spatrick            items = sorted(test.result.microResults.items())
15009467b48Spatrick            for micro_test_name, micro_test in items:
15109467b48Spatrick                print("%s MICRO-TEST: %s" %
15209467b48Spatrick                         ('*'*3, micro_test_name))
15309467b48Spatrick
15409467b48Spatrick                if micro_test.metrics:
15509467b48Spatrick                    sorted_metrics = sorted(micro_test.metrics.items())
15609467b48Spatrick                    for metric_name, value in sorted_metrics:
15709467b48Spatrick                        print('    %s:  %s ' % (metric_name, value.format()))
15809467b48Spatrick
15909467b48Spatrick        # Ensure the output is flushed.
16009467b48Spatrick        sys.stdout.flush()
161