aboutsummaryrefslogtreecommitdiff
path: root/tools/gst-plot-timeline.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/gst-plot-timeline.py')
-rwxr-xr-xtools/gst-plot-timeline.py314
1 files changed, 0 insertions, 314 deletions
diff --git a/tools/gst-plot-timeline.py b/tools/gst-plot-timeline.py
deleted file mode 100755
index e52e265..0000000
--- a/tools/gst-plot-timeline.py
+++ /dev/null
@@ -1,314 +0,0 @@
-#!/usr/bin/env python
-#
-# based on plot-timeline.py by Federico Mena-Quintero <federico at ximian dotcom>
-# example:
-# GST_DEBUG_COLOR_MODE=off GST_DEBUG="*:3" gst-launch-1.0 2>debug.log audiotestsrc num-buffers=10 ! audioconvert ! alsasink
-# gst-plot-timeline.py debug.log --output=debug.png
-
-import math
-import optparse
-import os
-import re
-import sys
-
-import cairo
-
-FONT_NAME = "Bitstream Vera Sans"
-FONT_SIZE = 8
-# how many pixels for a second on the timeline
-PIXELS_PER_SECOND = 300
-# how many pixels for one line of log
-PIXELS_PER_LINE = 10
-PLOT_WIDTH = 1400
-TIME_SCALE_WIDTH = 20
-SYSCALL_MARKER_WIDTH = 20
-LOG_TEXT_XPOS = 400
-LOG_MARKER_WIDTH = 20
-BACKGROUND_COLOR = (0, 0, 0)
-
-# assumes GST_DEBUG_LOG_COLOR=1
-# timestamp pid thread level category,file,line,msg
-mark_regex = re.compile (r'^(\d+:\d+:\d+\.\d+) +\d+ +0?x?[0-9a-f]+ [A-Z]+ +([-a-zA-Z0-9_]+ )(.*)')
-mark_timestamp_group = 1
-mark_program_group = 2
-mark_log_group = 3
-
-success_result = "0"
-
-skip_lines = 0
-max_lines = 500
-filter_regex = re.compile ('')
-skip_regex = re.compile('')
-
-class BaseMark:
- colors = 0, 0, 0
- def __init__(self, timestamp, log):
- self.timestamp = timestamp
- self.log = log
- self.timestamp_ypos = 0
- self.log_ypos = 0
-
-class AccessMark(BaseMark):
- pass
-
-class LastMark(BaseMark):
- colors = 1.0, 0, 0
-
-class FirstMark(BaseMark):
- colors = 1.0, 0, 0
-
-class ExecMark(BaseMark):
-# colors = 0.75, 0.33, 0.33
- colors = (1.0, 0.0, 0.0)
- def __init__(self, timestamp, log):
- BaseMark.__init__(self, timestamp,
- 'execve: ' + os.path.basename(log))
-
-class Metrics:
- def __init__(self):
- self.width = 0
- self.height = 0
-
-# don't use black or red
-palette = [
- (0.12, 0.29, 0.49),
- (0.36, 0.51, 0.71),
- (0.75, 0.31, 0.30),
- (0.62, 0.73, 0.38),
- (0.50, 0.40, 0.63),
- (0.29, 0.67, 0.78),
- (0.96, 0.62, 0.34)
- ]
-
-class SyscallParser:
- def __init__ (self):
- self.syscalls = []
-
- def add_line (self, str):
- m = mark_regex.search (str)
- if m:
- timestr = m.group (mark_timestamp_group).split(':')
- timestamp = float (timestr[2]) + (float (timestr[1]) * 60.0) + (float (timestr[0]) * 3600.0)
- program = m.group (mark_program_group)
- text = program + m.group (mark_log_group)
- if text == 'last':
- self.syscalls.append (LastMark (timestamp, text))
- elif text == 'first':
- self.syscalls.append (FirstMark (timestamp, text))
- else:
- s = AccessMark (timestamp, text)
- program_hash = program.__hash__ ()
- s.colors = palette[program_hash % len (palette)]
- self.syscalls.append (s)
- else:
- print 'No log in %s' % str
- return
-
-def parse_strace(filename):
- parser = SyscallParser ()
-
- global skip_lines
- global max_lines
- global skip_regex
-
- skip_found = False
-
- for line in file(filename, "r").readlines():
- if line == "":
- break
-
- if not skip_found:
- if skip_regex.search(line):
- skip_found = True
- else:
- continue
-
- if skip_lines > 0:
- skip_lines -= 1
- continue
-
- if len(parser.syscalls) >= max_lines:
- break
-
- if filter_regex.search(line):
- parser.add_line (line)
-
- return parser.syscalls
-
-def normalize_timestamps(syscalls):
-
- first_timestamp = syscalls[0].timestamp
-
- for syscall in syscalls:
- syscall.timestamp -= first_timestamp
-
-def compute_syscall_metrics(syscalls):
- global PIXELS_PER_SECOND
- global PIXELS_PER_LINE
-
- num_syscalls = len(syscalls)
-
- metrics = Metrics()
- metrics.width = PLOT_WIDTH
-
- last_timestamp = syscalls[num_syscalls - 1].timestamp
-
- time_height = int(math.ceil(last_timestamp * PIXELS_PER_SECOND))
- line_height = num_syscalls * PIXELS_PER_LINE
-
- if time_height > line_height:
- metrics.height = time_height
- print "Adjusting PIXELS_PER_LINE = %d" % PIXELS_PER_LINE
- PIXELS_PER_LINE = metrics.height / num_syscalls
- print " PIXELS_PER_LINE = %d" % PIXELS_PER_LINE
- else:
- metrics.height = line_height
- print "Adjusting PIXELS_PER_SECOND %d" % PIXELS_PER_SECOND
- PIXELS_PER_SECOND = int(math.ceil(metrics.height / last_timestamp))
- print " PIXELS_PER_SECOND %d" % PIXELS_PER_SECOND
-
- text_ypos = 0
-
- for syscall in syscalls:
- syscall.timestamp_ypos = syscall.timestamp * PIXELS_PER_SECOND
- syscall.log_ypos = text_ypos + FONT_SIZE
-
- text_ypos += PIXELS_PER_LINE
-
- return metrics
-
-def plot_time_scale(surface, ctx, metrics):
- num_seconds = (metrics.height + PIXELS_PER_SECOND - 1) / PIXELS_PER_SECOND
-
- ctx.set_source_rgb(0.5, 0.5, 0.5)
- ctx.set_line_width(1.0)
-
- for i in range(num_seconds):
- ypos = i * PIXELS_PER_SECOND
-
- ctx.move_to(0, ypos + 0.5)
- ctx.line_to(TIME_SCALE_WIDTH, ypos + 0.5)
- ctx.stroke()
-
- ctx.move_to(0, ypos + 2 + FONT_SIZE)
- ctx.show_text("%d s" % i)
-
-def plot_syscall(surface, ctx, syscall):
- ctx.set_source_rgb(*syscall.colors)
-
- # Line
-
- ctx.move_to(TIME_SCALE_WIDTH, syscall.timestamp_ypos)
- ctx.line_to(TIME_SCALE_WIDTH + SYSCALL_MARKER_WIDTH, syscall.timestamp_ypos)
- ctx.line_to(LOG_TEXT_XPOS - LOG_MARKER_WIDTH, syscall.log_ypos - FONT_SIZE / 2 + 0.5)
- ctx.line_to(LOG_TEXT_XPOS, syscall.log_ypos - FONT_SIZE / 2 + 0.5)
- ctx.stroke()
-
- # Log text
-
- ctx.move_to(LOG_TEXT_XPOS, syscall.log_ypos)
- ctx.show_text("%8.5f: %s" % (syscall.timestamp, syscall.log))
-
-def plot_syscalls_to_surface(syscalls, metrics):
- num_syscalls = len(syscalls)
-
- print 'picture size: %d x %d' % (metrics.width, metrics.height);
-
- surface = cairo.ImageSurface(cairo.FORMAT_RGB24,
- metrics.width, metrics.height)
-
- ctx = cairo.Context(surface)
- ctx.select_font_face(FONT_NAME)
- ctx.set_font_size(FONT_SIZE)
-
- # Background
-
- ctx.set_source_rgb (*BACKGROUND_COLOR)
- ctx.rectangle(0, 0, metrics.width, metrics.height)
- ctx.fill()
-
- # Time scale
-
- plot_time_scale(surface, ctx, metrics)
-
- # Contents
-
- ctx.set_line_width(1.0)
-
- for syscall in syscalls:
- plot_syscall(surface, ctx, syscall)
-
- return surface
-
-def main(args):
-
- global skip_lines
- global max_lines
- global filter_regex
- global skip_regex
-
- option_parser = optparse.OptionParser(
- usage="usage: %prog -o output.png <debug.log>")
- option_parser.add_option("-o",
- "--output", dest="output",
- metavar="FILE",
- help="Name of output file (output is a PNG file)")
- option_parser.add_option("-s",
- "--skip", dest="skip",
- metavar="LINES",
- help="Skip a number of loglines at the beginning of the file or wait till a regular expression happens")
- option_parser.add_option("-m",
- "--max-lines", dest="max",
- help="max lines that need to be plotted")
- option_parser.add_option("-f",
- "--filter", dest="filter",
- help="filter the log lines on a regular expression")
-
- options, args = option_parser.parse_args()
-
- if not options.output:
- print 'Please specify an output filename with "-o file.png" or "--output=file.png".'
- return 1
-
- if len(args) != 1:
- print 'Please specify only one input filename, which is an debug log taken with "GST_DEBUG_COLOR_MODE=off GST_DEBUG=XXX <application>"'
- return 1
-
- in_filename = args[0]
- out_filename = options.output
-
- if options.skip:
- try:
- skip_lines = int(options.skip)
- except:
- skip_regex = re.compile(options.skip)
- skip_lines = 0
-
- if options.max:
- max_lines = int(options.max)
-
- if options.filter:
- filter_regex = re.compile(options.filter)
-
- syscalls = []
- for syscall in parse_strace(in_filename):
- syscalls.append(syscall)
- if isinstance(syscall, FirstMark):
- syscalls = []
- elif isinstance(syscall, LastMark):
- break
-
- if not syscalls:
- print 'No logs in %s' % in_filename
- return 1
-
- normalize_timestamps(syscalls)
- metrics = compute_syscall_metrics(syscalls)
-
- surface = plot_syscalls_to_surface(syscalls, metrics)
- surface.write_to_png(out_filename)
-
- return 0
-
-if __name__ == "__main__":
- sys.exit(main(sys.argv))