Index: tools/valgrind/drmemory_analyze.py |
=================================================================== |
--- tools/valgrind/drmemory_analyze.py (revision 111527) |
+++ tools/valgrind/drmemory_analyze.py (working copy) |
@@ -7,6 +7,8 @@ |
''' Given a Dr. Memory output file, parses errors and uniques them.''' |
+from collections import defaultdict |
+import common |
import logging |
import optparse |
import os |
@@ -15,31 +17,14 @@ |
import sys |
import time |
-class _StackTraceLine(object): |
- def __init__(self, line, address, binary): |
- self.raw_line_ = line |
- self.address = address |
- self.binary = binary |
- def __str__(self): |
- return self.raw_line_ |
-class DrMemoryAnalyze: |
+class DrMemoryAnalyzer: |
''' Given a set of Dr.Memory output files, parse all the errors out of |
them, unique them and output the results.''' |
- def __init__(self, source_dir, files): |
- '''Reads in a set of files. |
+ def __init__(self): |
+ self.known_errors = set() |
- Args: |
- source_dir: Path to top of source tree for this build |
- files: A list of filenames. |
- ''' |
- |
- self.reports = [] |
- self.used_suppressions = [] |
- for file in files: |
- self.ParseReportFile(file) |
- |
def ReadLine(self): |
self.line_ = self.cur_fd_.readline() |
@@ -52,8 +37,9 @@ |
return result |
def ParseReportFile(self, filename): |
- self.cur_fd_ = open(filename, 'r') |
+ ret = [] |
+ self.cur_fd_ = open(filename, 'r') |
while True: |
self.ReadLine() |
if (self.line_ == ''): break |
@@ -62,7 +48,7 @@ |
if match: |
self.line_ = match.groups()[0].strip() + "\n" |
tmp = self.ReadSection() |
- self.reports.append(tmp) |
+ ret.append("".join(tmp).strip()) |
if re.search("SUPPRESSIONS USED:", self.line_): |
self.ReadLine() |
@@ -70,53 +56,59 @@ |
line = self.line_.strip() |
(count, name) = re.match(" *([0-9]+)x(?: \(leaked .*\))?: (.*)", |
line).groups() |
- self.used_suppressions.append("%7s %s" % (count, name)) |
+ count = int(count) |
+ self.used_suppressions[name] += count |
self.ReadLine() |
if self.line_.startswith("ASSERT FAILURE"): |
- self.reports.append(self.line_.strip()) |
+ ret.append(self.line_.strip()) |
self.cur_fd_.close() |
+ return ret |
- def Report(self, check_sanity): |
+ def Report(self, filenames, testcase, check_sanity): |
sys.stdout.flush() |
- #TODO(timurrrr): support positive tests / check_sanity==True |
+ # TODO(timurrrr): support positive tests / check_sanity==True |
- if self.used_suppressions: |
- print "-----------------------------------------------------" |
- # TODO(timurrrr): sum up the counts from different wrappers (e.g. ui_tests) |
- # or does it work now already? Or add the memcheck-like per-test printing. |
- print "Suppressions used:\n count name\n%s" % ( |
- "\n".join(self.used_suppressions)) |
- print "-----------------------------------------------------" |
- sys.stdout.flush() |
+ to_report = [] |
+ self.used_suppressions = defaultdict(int) |
+ for f in filenames: |
+ cur_reports = self.ParseReportFile(f) |
- if len(self.reports) > 0: |
- logging.error("Found %i error reports" % len(self.reports)) |
- for report_list in self.reports: |
- report = '' |
- for line in report_list: |
- report += str(line) |
- logging.error('\n' + report) |
- logging.error("Total: %i error reports" % len(self.reports)) |
- return -1 |
- logging.info("PASS: No error reports found") |
- return 0 |
+ # Filter out the reports that were there in previous tests. |
+ for r in cur_reports: |
+ if r in self.known_errors: |
+ pass # TODO: print out a hash once we add hashes to the reports. |
+ else: |
+ self.known_errors.add(r) |
+ to_report.append(r) |
+ common.PrintUsedSuppressionsList(self.used_suppressions) |
+ |
+ if not to_report: |
+ logging.info("PASS: No error reports found") |
+ return 0 |
+ |
+ logging.error("Found %i error reports" % len(to_report)) |
+ for report in to_report: |
+ if testcase: |
+ logging.error("\n%s\nNote: observed on `%s`\n" % |
+ (report, testcase)) |
+ else: |
+ logging.error("\n%s\n" % report) |
+ logging.error("Total: %i error reports" % len(to_report)) |
+ return -1 |
+ |
if __name__ == '__main__': |
- '''For testing only. The DrMemoryAnalyze class should be imported instead.''' |
+ '''For testing only. The DrMemoryAnalyzer class should be imported instead.''' |
retcode = 0 |
- parser = optparse.OptionParser("usage: %prog [options] <files to analyze>") |
- parser.add_option("", "--source_dir", |
- help="path to top of source tree for this build" |
- "(used to normalize source paths in baseline)") |
- |
+ parser = optparse.OptionParser("usage: %prog <files to analyze>") |
(options, args) = parser.parse_args() |
if len(args) == 0: |
parser.error("no filename specified") |
filenames = args |
- analyzer = DrMemoryAnalyze(options.source_dir, filenames) |
- retcode = analyzer.Report(False) |
+ analyzer = DrMemoryAnalyzer() |
+ retcode = analyzer.Report(filenames, None, False) |
sys.exit(retcode) |