| #!/usr/bin/env python |
| |
| import os, sys, re |
| |
| class multidict: |
| def __init__(self, elts=()): |
| self.data = {} |
| for key,value in elts: |
| self[key] = value |
| |
| def __getitem__(self, item): |
| return self.data[item] |
| def __setitem__(self, key, value): |
| if key in self.data: |
| self.data[key].append(value) |
| else: |
| self.data[key] = [value] |
| def items(self): |
| return self.data.items() |
| def values(self): |
| return self.data.values() |
| def keys(self): |
| return self.data.keys() |
| def __len__(self): |
| return len(self.data) |
| |
| kDiagnosticRE = re.compile(': (error|warning): (.*)') |
| kAssertionRE = re.compile('Assertion failed: (.*, function .*, file .*, line [0-9]+\\.)') |
| |
| def readInfo(path, opts): |
| lastProgress = [-100,0] |
| def progress(pos): |
| pct = (100. * pos) / (size * 2) |
| if (pct - lastProgress[0]) >= 10: |
| lastProgress[0] = pct |
| print '%d/%d = %.2f%%' % (pos, size*2, pct) |
| |
| f = open(path) |
| data = f.read() |
| f.close() |
| |
| if opts.truncate != -1: |
| data = data[:opts.truncate] |
| |
| size = len(data) |
| warnings = multidict() |
| errors = multidict() |
| for m in kDiagnosticRE.finditer(data): |
| progress(m.end()) |
| if m.group(1) == 'error': |
| d = errors |
| else: |
| d = warnings |
| d[m.group(2)] = m |
| warnings = warnings.items() |
| errors = errors.items() |
| assertions = multidict() |
| for m in kAssertionRE.finditer(data): |
| print '%d/%d = %.2f%%' % (size + m.end(), size, (float(m.end()) / (size*2)) * 100.) |
| assertions[m.group(1)] = m |
| assertions = assertions.items() |
| |
| # Manual scan for stack traces |
| aborts = multidict() |
| if 0: |
| prevLine = None |
| lnIter = iter(data.split('\n')) |
| for ln in lnIter: |
| m = kStackDumpLineRE.match(ln) |
| if m: |
| stack = [m.group(2)] |
| for ln in lnIter: |
| m = kStackDumpLineRE.match(ln) |
| if not m: |
| break |
| stack.append(m.group(2)) |
| if prevLine is None or not kAssertionRE.match(prevLine): |
| aborts[tuple(stack)] = stack |
| prevLine = ln |
| |
| sections = [ |
| (warnings, 'Warnings'), |
| (errors, 'Errors'), |
| (assertions, 'Assertions'), |
| (aborts.items(), 'Aborts'), |
| ] |
| |
| if opts.ascending: |
| sections.reverse() |
| |
| for l,title in sections: |
| l.sort(key = lambda (a,b): -len(b)) |
| if l: |
| print '-- %d %s (%d kinds) --' % (sum([len(b) for a,b in l]), title, len(l)) |
| for name,elts in l: |
| print '%5d:' % len(elts), name |
| |
| def main(): |
| global options |
| from optparse import OptionParser |
| parser = OptionParser("usage: %prog [options] {inputs}") |
| parser.add_option("", "--ascending", dest="ascending", |
| help="Print output in ascending order of severity.", |
| action="store_true", default=False) |
| parser.add_option("", "--truncate", dest="truncate", |
| help="Truncate input file (for testing).", |
| type=int, action="store", default=-1) |
| (opts, args) = parser.parse_args() |
| |
| if not args: |
| parser.error('No inputs specified') |
| |
| for arg in args: |
| readInfo(arg, opts) |
| |
| if __name__=='__main__': |
| main() |