aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2018-11-12 12:55:35 -0800
committerGitHub <noreply@github.com>2018-11-12 12:55:35 -0800
commit498faf93e13cc8555d70a1040c4eff7a10905492 (patch)
treeb584a99fc898c1951a7a092e0954e717de82ae1c /tools
parentd18c2f23d381b47cf14fd7edd099be40a3e21b62 (diff)
downloadriscv-openocd-498faf93e13cc8555d70a1040c4eff7a10905492.zip
riscv-openocd-498faf93e13cc8555d70a1040c4eff7a10905492.tar.gz
riscv-openocd-498faf93e13cc8555d70a1040c4eff7a10905492.tar.bz2
Add utility to combine runs of lines in log files. (#317)
Hopefully satisfies #193. Change-Id: I427d763aeca2322b05ed88b42fd4a5f0446a654b
Diffstat (limited to 'tools')
-rwxr-xr-xtools/filter_openocd_log.py119
1 files changed, 119 insertions, 0 deletions
diff --git a/tools/filter_openocd_log.py b/tools/filter_openocd_log.py
new file mode 100755
index 0000000..b7ae6e0
--- /dev/null
+++ b/tools/filter_openocd_log.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+
+import sys
+
+# This function is the only OpenOCD-specific part of this script.
+def make_canonical(line):
+ # Remove the line number and time stamp.
+ parts = line.split(None, 3)
+ if len(parts) > 3:
+ return "%s - - %s" % (parts[0], parts[3])
+ else:
+ return line
+
+def buf_startswith(buf, sequence):
+ if len(buf) < len(sequence):
+ return False
+ for i, entry in enumerate(sequence):
+ if entry[1] != buf[i][1]:
+ return False
+ return True
+
+def shorten_buffer(outfd, buf, current_repetition):
+ """Do something to the buffer to make it shorter. If we can't compress
+ anything, then print out the first line and remove it."""
+ length_before = len(buf)
+
+ if current_repetition:
+ while buf_startswith(buf, current_repetition[0]):
+ del buf[:len(current_repetition[0])]
+ current_repetition[1] += 1
+ if len(buf) < length_before:
+ return current_repetition
+ outfd.write("## The following %d lines repeat %d times:\n" % (
+ len(current_repetition[0]), current_repetition[1]))
+ for entry in current_repetition[0]:
+ outfd.write("# %s" % entry[1])
+
+ # Look for repeated sequences...
+ repetitions = []
+ for length in range(1, len(buf)/2):
+ # Is there a repeating sequence of `length` lines?
+ matched_lines = 0
+ for i, entry in enumerate(buf[length:]):
+ if entry[1] == buf[i % length][1]:
+ matched_lines += 1
+ else:
+ break
+ if matched_lines >= length:
+ repetitions.append((matched_lines + length, length))
+
+ if repetitions:
+ repetitions.sort(key=lambda entry: (entry[0] * (entry[1] / entry[0]), -entry[1]))
+ matched_lines, length = repetitions[-1]
+ repeated = matched_lines / length
+ if repeated * length >= 3:
+ sequence = buf[:length]
+ del buf[:repeated * length]
+
+ if matched_lines == length_before:
+ # Could be continued...
+ return [sequence, repeated]
+
+ else:
+ outfd.write("## The following %d lines repeat %d times:\n" %
+ (length, repeated))
+ for entry in sequence:
+ outfd.write("# %s" % entry[1])
+ return None
+
+ if len(buf) >= length_before:
+ line, _ = buf[0]
+ outfd.write(line)
+ buf.pop(0)
+
+ if length_before <= len(buf):
+ print "Buffer:"
+ for entry in buf:
+ print "%r" % entry[0]
+ assert False
+
+ return None
+
+def compress_log(infd, outfd, window):
+ """Compress log by finding repeated runs of lines. Runs in O(lines *
+ window**2), which can probably be improved."""
+ # Contains line, canonical tuples
+ buf = []
+ current_repetition = None
+
+ for line in infd:
+ buf.append((line, make_canonical(line)))
+ if len(buf) > window:
+ current_repetition = shorten_buffer(outfd, buf, current_repetition)
+
+ while len(buf) > 0:
+ current_repetition = shorten_buffer(outfd, buf, current_repetition)
+
+def main(args):
+ import argparse
+ parser = argparse.ArgumentParser(
+ description='Combine repeated OpenOCD debug output lines. This is '
+ 'very helpful when looking at verbose log files where e.g. target '
+ 'polling is repeated over and over.',
+ epilog='If no files are specified, read standard input.',
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument('file', nargs='*', help='input file')
+ parser.add_argument('-o', '--output', help='output file', default=sys.stdout)
+ parser.add_argument('-w', '--window', type=int, default=100,
+ help='number of lines to consider when looking for repetitions')
+ args = parser.parse_args(args)
+
+ if args.file:
+ for f in args.file:
+ compress_log(open(f, "r"), args.output, args.window)
+ else:
+ compress_log(sys.stdin, args.output, args.window)
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))