gdb/gdb-no-dg-extract-results-p...

590 lines
24 KiB
Diff

diff -dup -ruNp gdb-7.8.90.20150202-orig/gdb/testsuite/dg-extract-results.py gdb-7.8.90.20150202/gdb/testsuite/dg-extract-results.py
--- gdb-7.8.90.20150202-orig/gdb/testsuite/dg-extract-results.py 2015-02-02 02:58:29.000000000 +0100
+++ gdb-7.8.90.20150202/gdb/testsuite/dg-extract-results.py 1970-01-01 01:00:00.000000000 +0100
@@ -1,585 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright (C) 2014-2015 Free Software Foundation, Inc.
-#
-# This script is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3, or (at your option)
-# any later version.
-
-import sys
-import getopt
-import re
-import io
-from datetime import datetime
-from operator import attrgetter
-
-# True if unrecognised lines should cause a fatal error. Might want to turn
-# this on by default later.
-strict = False
-
-# True if the order of .log segments should match the .sum file, false if
-# they should keep the original order.
-sort_logs = True
-
-# A version of open() that is safe against whatever binary output
-# might be added to the log.
-def safe_open (filename):
- if sys.version_info >= (3, 0):
- return open (filename, 'r', errors = 'surrogateescape')
- return open (filename, 'r')
-
-# Force stdout to handle escape sequences from a safe_open file.
-if sys.version_info >= (3, 0):
- sys.stdout = io.TextIOWrapper (sys.stdout.buffer,
- errors = 'surrogateescape')
-
-class Named:
- def __init__ (self, name):
- self.name = name
-
-class ToolRun (Named):
- def __init__ (self, name):
- Named.__init__ (self, name)
- # The variations run for this tool, mapped by --target_board name.
- self.variations = dict()
-
- # Return the VariationRun for variation NAME.
- def get_variation (self, name):
- if name not in self.variations:
- self.variations[name] = VariationRun (name)
- return self.variations[name]
-
-class VariationRun (Named):
- def __init__ (self, name):
- Named.__init__ (self, name)
- # A segment of text before the harness runs start, describing which
- # baseboard files were loaded for the target.
- self.header = None
- # The harnesses run for this variation, mapped by filename.
- self.harnesses = dict()
- # A list giving the number of times each type of result has
- # been seen.
- self.counts = []
-
- # Return the HarnessRun for harness NAME.
- def get_harness (self, name):
- if name not in self.harnesses:
- self.harnesses[name] = HarnessRun (name)
- return self.harnesses[name]
-
-class HarnessRun (Named):
- def __init__ (self, name):
- Named.__init__ (self, name)
- # Segments of text that make up the harness run, mapped by a test-based
- # key that can be used to order them.
- self.segments = dict()
- # Segments of text that make up the harness run but which have
- # no recognized test results. These are typically harnesses that
- # are completely skipped for the target.
- self.empty = []
- # A list of results. Each entry is a pair in which the first element
- # is a unique sorting key and in which the second is the full
- # PASS/FAIL line.
- self.results = []
-
- # Add a segment of text to the harness run. If the segment includes
- # test results, KEY is an example of one of them, and can be used to
- # combine the individual segments in order. If the segment has no
- # test results (e.g. because the harness doesn't do anything for the
- # current configuration) then KEY is None instead. In that case
- # just collect the segments in the order that we see them.
- def add_segment (self, key, segment):
- if key:
- assert key not in self.segments
- self.segments[key] = segment
- else:
- self.empty.append (segment)
-
-class Segment:
- def __init__ (self, filename, start):
- self.filename = filename
- self.start = start
- self.lines = 0
-
-class Prog:
- def __init__ (self):
- # The variations specified on the command line.
- self.variations = []
- # The variations seen in the input files.
- self.known_variations = set()
- # The tools specified on the command line.
- self.tools = []
- # Whether to create .sum rather than .log output.
- self.do_sum = True
- # Regexps used while parsing.
- self.test_run_re = re.compile (r'^Test Run By (\S+) on (.*)$')
- self.tool_re = re.compile (r'^\t\t=== (.*) tests ===$')
- self.result_re = re.compile (r'^(PASS|XPASS|FAIL|XFAIL|UNRESOLVED'
- r'|WARNING|ERROR|UNSUPPORTED|UNTESTED'
- r'|KFAIL):\s*(.+)')
- self.completed_re = re.compile (r'.* completed at (.*)')
- # Pieces of text to write at the head of the output.
- # start_line is a pair in which the first element is a datetime
- # and in which the second is the associated 'Test Run By' line.
- self.start_line = None
- self.native_line = ''
- self.target_line = ''
- self.host_line = ''
- self.acats_premable = ''
- # Pieces of text to write at the end of the output.
- # end_line is like start_line but for the 'runtest completed' line.
- self.acats_failures = []
- self.version_output = ''
- self.end_line = None
- # Known summary types.
- self.count_names = [
- '# of expected passes\t\t',
- '# of unexpected failures\t',
- '# of unexpected successes\t',
- '# of expected failures\t\t',
- '# of unknown successes\t\t',
- '# of known failures\t\t',
- '# of untested testcases\t\t',
- '# of unresolved testcases\t',
- '# of unsupported tests\t\t'
- ]
- self.runs = dict()
-
- def usage (self):
- name = sys.argv[0]
- sys.stderr.write ('Usage: ' + name
- + ''' [-t tool] [-l variant-list] [-L] log-or-sum-file ...
-
- tool The tool (e.g. g++, libffi) for which to create a
- new test summary file. If not specified then output
- is created for all tools.
- variant-list One or more test variant names. If the list is
- not specified then one is constructed from all
- variants in the files for <tool>.
- sum-file A test summary file with the format of those
- created by runtest from DejaGnu.
- If -L is used, merge *.log files instead of *.sum. In this
- mode the exact order of lines may not be preserved, just different
- Running *.exp chunks should be in correct order.
-''')
- sys.exit (1)
-
- def fatal (self, what, string):
- if not what:
- what = sys.argv[0]
- sys.stderr.write (what + ': ' + string + '\n')
- sys.exit (1)
-
- # Parse the command-line arguments.
- def parse_cmdline (self):
- try:
- (options, self.files) = getopt.getopt (sys.argv[1:], 'l:t:L')
- if len (self.files) == 0:
- self.usage()
- for (option, value) in options:
- if option == '-l':
- self.variations.append (value)
- elif option == '-t':
- self.tools.append (value)
- else:
- self.do_sum = False
- except getopt.GetoptError as e:
- self.fatal (None, e.msg)
-
- # Try to parse time string TIME, returning an arbitrary time on failure.
- # Getting this right is just a nice-to-have so failures should be silent.
- def parse_time (self, time):
- try:
- return datetime.strptime (time, '%c')
- except ValueError:
- return datetime.now()
-
- # Parse an integer and abort on failure.
- def parse_int (self, filename, value):
- try:
- return int (value)
- except ValueError:
- self.fatal (filename, 'expected an integer, got: ' + value)
-
- # Return a list that represents no test results.
- def zero_counts (self):
- return [0 for x in self.count_names]
-
- # Return the ToolRun for tool NAME.
- def get_tool (self, name):
- if name not in self.runs:
- self.runs[name] = ToolRun (name)
- return self.runs[name]
-
- # Add the result counts in list FROMC to TOC.
- def accumulate_counts (self, toc, fromc):
- for i in range (len (self.count_names)):
- toc[i] += fromc[i]
-
- # Parse the list of variations after 'Schedule of variations:'.
- # Return the number seen.
- def parse_variations (self, filename, file):
- num_variations = 0
- while True:
- line = file.readline()
- if line == '':
- self.fatal (filename, 'could not parse variation list')
- if line == '\n':
- break
- self.known_variations.add (line.strip())
- num_variations += 1
- return num_variations
-
- # Parse from the first line after 'Running target ...' to the end
- # of the run's summary.
- def parse_run (self, filename, file, tool, variation, num_variations):
- header = None
- harness = None
- segment = None
- final_using = 0
-
- # If this is the first run for this variation, add any text before
- # the first harness to the header.
- if not variation.header:
- segment = Segment (filename, file.tell())
- variation.header = segment
-
- # Parse up until the first line of the summary.
- if num_variations == 1:
- end = '\t\t=== ' + tool.name + ' Summary ===\n'
- else:
- end = ('\t\t=== ' + tool.name + ' Summary for '
- + variation.name + ' ===\n')
- while True:
- line = file.readline()
- if line == '':
- self.fatal (filename, 'no recognised summary line')
- if line == end:
- break
-
- # Look for the start of a new harness.
- if line.startswith ('Running ') and line.endswith (' ...\n'):
- # Close off the current harness segment, if any.
- if harness:
- segment.lines -= final_using
- harness.add_segment (first_key, segment)
- name = line[len ('Running '):-len(' ...\n')]
- harness = variation.get_harness (name)
- segment = Segment (filename, file.tell())
- first_key = None
- final_using = 0
- continue
-
- # Record test results. Associate the first test result with
- # the harness segment, so that if a run for a particular harness
- # has been split up, we can reassemble the individual segments
- # in a sensible order.
- #
- # dejagnu sometimes issues warnings about the testing environment
- # before running any tests. Treat them as part of the header
- # rather than as a test result.
- match = self.result_re.match (line)
- if match and (harness or not line.startswith ('WARNING:')):
- if not harness:
- self.fatal (filename, 'saw test result before harness name')
- name = match.group (2)
- # Ugly hack to get the right order for gfortran.
- if name.startswith ('gfortran.dg/g77/'):
- name = 'h' + name
- key = (name, len (harness.results))
- harness.results.append ((key, line))
- if not first_key and sort_logs:
- first_key = key
-
- # 'Using ...' lines are only interesting in a header. Splitting
- # the test up into parallel runs leads to more 'Using ...' lines
- # than there would be in a single log.
- if line.startswith ('Using '):
- final_using += 1
- else:
- final_using = 0
-
- # Add other text to the current segment, if any.
- if segment:
- segment.lines += 1
-
- # Close off the final harness segment, if any.
- if harness:
- segment.lines -= final_using
- harness.add_segment (first_key, segment)
-
- # Parse the rest of the summary (the '# of ' lines).
- if len (variation.counts) == 0:
- variation.counts = self.zero_counts()
- while True:
- before = file.tell()
- line = file.readline()
- if line == '':
- break
- if line == '\n':
- continue
- if not line.startswith ('# '):
- file.seek (before)
- break
- found = False
- for i in range (len (self.count_names)):
- if line.startswith (self.count_names[i]):
- count = line[len (self.count_names[i]):-1].strip()
- variation.counts[i] += self.parse_int (filename, count)
- found = True
- break
- if not found:
- self.fatal (filename, 'unknown test result: ' + line[:-1])
-
- # Parse an acats run, which uses a different format from dejagnu.
- # We have just skipped over '=== acats configuration ==='.
- def parse_acats_run (self, filename, file):
- # Parse the preamble, which describes the configuration and logs
- # the creation of support files.
- record = (self.acats_premable == '')
- if record:
- self.acats_premable = '\t\t=== acats configuration ===\n'
- while True:
- line = file.readline()
- if line == '':
- self.fatal (filename, 'could not parse acats preamble')
- if line == '\t\t=== acats tests ===\n':
- break
- if record:
- self.acats_premable += line
-
- # Parse the test results themselves, using a dummy variation name.
- tool = self.get_tool ('acats')
- variation = tool.get_variation ('none')
- self.parse_run (filename, file, tool, variation, 1)
-
- # Parse the failure list.
- while True:
- before = file.tell()
- line = file.readline()
- if line.startswith ('*** FAILURES: '):
- self.acats_failures.append (line[len ('*** FAILURES: '):-1])
- continue
- file.seek (before)
- break
-
- # Parse the final summary at the end of a log in order to capture
- # the version output that follows it.
- def parse_final_summary (self, filename, file):
- record = (self.version_output == '')
- while True:
- line = file.readline()
- if line == '':
- break
- if line.startswith ('# of '):
- continue
- if record:
- self.version_output += line
- if line == '\n':
- break
-
- # Parse a .log or .sum file.
- def parse_file (self, filename, file):
- tool = None
- target = None
- num_variations = 1
- while True:
- line = file.readline()
- if line == '':
- return
-
- # Parse the list of variations, which comes before the test
- # runs themselves.
- if line.startswith ('Schedule of variations:'):
- num_variations = self.parse_variations (filename, file)
- continue
-
- # Parse a testsuite run for one tool/variation combination.
- if line.startswith ('Running target '):
- name = line[len ('Running target '):-1]
- if not tool:
- self.fatal (filename, 'could not parse tool name')
- if name not in self.known_variations:
- self.fatal (filename, 'unknown target: ' + name)
- self.parse_run (filename, file, tool,
- tool.get_variation (name),
- num_variations)
- # If there is only one variation then there is no separate
- # summary for it. Record any following version output.
- if num_variations == 1:
- self.parse_final_summary (filename, file)
- continue
-
- # Parse the start line. In the case where several files are being
- # parsed, pick the one with the earliest time.
- match = self.test_run_re.match (line)
- if match:
- time = self.parse_time (match.group (2))
- if not self.start_line or self.start_line[0] > time:
- self.start_line = (time, line)
- continue
-
- # Parse the form used for native testing.
- if line.startswith ('Native configuration is '):
- self.native_line = line
- continue
-
- # Parse the target triplet.
- if line.startswith ('Target is '):
- self.target_line = line
- continue
-
- # Parse the host triplet.
- if line.startswith ('Host is '):
- self.host_line = line
- continue
-
- # Parse the acats premable.
- if line == '\t\t=== acats configuration ===\n':
- self.parse_acats_run (filename, file)
- continue
-
- # Parse the tool name.
- match = self.tool_re.match (line)
- if match:
- tool = self.get_tool (match.group (1))
- continue
-
- # Skip over the final summary (which we instead create from
- # individual runs) and parse the version output.
- if tool and line == '\t\t=== ' + tool.name + ' Summary ===\n':
- if file.readline() != '\n':
- self.fatal (filename, 'expected blank line after summary')
- self.parse_final_summary (filename, file)
- continue
-
- # Parse the completion line. In the case where several files
- # are being parsed, pick the one with the latest time.
- match = self.completed_re.match (line)
- if match:
- time = self.parse_time (match.group (1))
- if not self.end_line or self.end_line[0] < time:
- self.end_line = (time, line)
- continue
-
- # Sanity check to make sure that important text doesn't get
- # dropped accidentally.
- if strict and line.strip() != '':
- self.fatal (filename, 'unrecognised line: ' + line[:-1])
-
- # Output a segment of text.
- def output_segment (self, segment):
- with safe_open (segment.filename) as file:
- file.seek (segment.start)
- for i in range (segment.lines):
- sys.stdout.write (file.readline())
-
- # Output a summary giving the number of times each type of result has
- # been seen.
- def output_summary (self, tool, counts):
- for i in range (len (self.count_names)):
- name = self.count_names[i]
- # dejagnu only prints result types that were seen at least once,
- # but acats always prints a number of unexpected failures.
- if (counts[i] > 0
- or (tool.name == 'acats'
- and name.startswith ('# of unexpected failures'))):
- sys.stdout.write ('%s%d\n' % (name, counts[i]))
-
- # Output unified .log or .sum information for a particular variation,
- # with a summary at the end.
- def output_variation (self, tool, variation):
- self.output_segment (variation.header)
- for harness in sorted (variation.harnesses.values(),
- key = attrgetter ('name')):
- sys.stdout.write ('Running ' + harness.name + ' ...\n')
- if self.do_sum:
- harness.results.sort()
- for (key, line) in harness.results:
- sys.stdout.write (line)
- else:
- # Rearrange the log segments into test order (but without
- # rearranging text within those segments).
- for key in sorted (harness.segments.keys()):
- self.output_segment (harness.segments[key])
- for segment in harness.empty:
- self.output_segment (segment)
- if len (self.variations) > 1:
- sys.stdout.write ('\t\t=== ' + tool.name + ' Summary for '
- + variation.name + ' ===\n\n')
- self.output_summary (tool, variation.counts)
-
- # Output unified .log or .sum information for a particular tool,
- # with a summary at the end.
- def output_tool (self, tool):
- counts = self.zero_counts()
- if tool.name == 'acats':
- # acats doesn't use variations, so just output everything.
- # It also has a different approach to whitespace.
- sys.stdout.write ('\t\t=== ' + tool.name + ' tests ===\n')
- for variation in tool.variations.values():
- self.output_variation (tool, variation)
- self.accumulate_counts (counts, variation.counts)
- sys.stdout.write ('\t\t=== ' + tool.name + ' Summary ===\n')
- else:
- # Output the results in the usual dejagnu runtest format.
- sys.stdout.write ('\n\t\t=== ' + tool.name + ' tests ===\n\n'
- 'Schedule of variations:\n')
- for name in self.variations:
- if name in tool.variations:
- sys.stdout.write (' ' + name + '\n')
- sys.stdout.write ('\n')
- for name in self.variations:
- if name in tool.variations:
- variation = tool.variations[name]
- sys.stdout.write ('Running target '
- + variation.name + '\n')
- self.output_variation (tool, variation)
- self.accumulate_counts (counts, variation.counts)
- sys.stdout.write ('\n\t\t=== ' + tool.name + ' Summary ===\n\n')
- self.output_summary (tool, counts)
-
- def main (self):
- self.parse_cmdline()
- try:
- # Parse the input files.
- for filename in self.files:
- with safe_open (filename) as file:
- self.parse_file (filename, file)
-
- # Decide what to output.
- if len (self.variations) == 0:
- self.variations = sorted (self.known_variations)
- else:
- for name in self.variations:
- if name not in self.known_variations:
- self.fatal (None, 'no results for ' + name)
- if len (self.tools) == 0:
- self.tools = sorted (self.runs.keys())
-
- # Output the header.
- if self.start_line:
- sys.stdout.write (self.start_line[1])
- sys.stdout.write (self.native_line)
- sys.stdout.write (self.target_line)
- sys.stdout.write (self.host_line)
- sys.stdout.write (self.acats_premable)
-
- # Output the main body.
- for name in self.tools:
- if name not in self.runs:
- self.fatal (None, 'no results for ' + name)
- self.output_tool (self.runs[name])
-
- # Output the footer.
- if len (self.acats_failures) > 0:
- sys.stdout.write ('*** FAILURES: '
- + ' '.join (self.acats_failures) + '\n')
- sys.stdout.write (self.version_output)
- if self.end_line:
- sys.stdout.write (self.end_line[1])
- except IOError as e:
- self.fatal (e.filename, e.strerror)
-
-Prog().main()