plot_sdcard.py revision 39c016f875b793296a121f41de5775b88f6fa1c9
139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania#!/usr/bin/python2.5
239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania#
339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania# Copyright 2009 Google Inc. All Rights Reserved.
439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania"""plot_sdcard: A module to plot the results of an sdcard perf test.
639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
739c016f875b793296a121f41de5775b88f6fa1c9Nicolas CataniaRequires Gnuplot python v 1.8
839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
939c016f875b793296a121f41de5775b88f6fa1c9Nicolas CataniaTypical usage:
1039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
1139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniapython
1239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania>>> import plot_sdcard as p
1339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania>>> (metadata, data) = p.parse('/tmp/data.txt')
1439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania>>> p.plotIterations(metadata, data)
1539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania>>> p.plotTimes(metadata, data)
1639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
1739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania"""
1839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
1939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania#TODO: provide a main so we can pipe the result from the run
2039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania#TODO: more comments...
2139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
2239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniaimport Gnuplot
2339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniafrom numpy import *
2439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniaimport sys
2539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniaimport re
2639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniafrom itertools import izip
2739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
2839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniaclass DataSet(object):
2939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def __init__(self, line):
3039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    res = re.search('# StopWatch ([\w]+) total/cumulative duration ([0-9.]+)\. Samples: ([0-9]+)', line)
3139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.time = []
3239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.data = []
3339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.name = res.group(1)
3439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.duration = float(res.group(2))
3539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.iteration = int(res.group(3))
3639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    print "Name: %s Duration: %f Iterations: %d" % (self.name, self.duration, self.iteration)
3739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.summary = re.match('([a-z_]+)_total', self.name)
3839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
3939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def __repr__(self):
4039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    return str(zip(self.time, self.data))
4139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
4239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def add(self, time, value):
4339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.time.append(time)
4439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.data.append(value)
4539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
4639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def rescaleTo(self, length):
4739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    factor = len(self.data) / length
4839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
4939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    if factor > 1:
5039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      new_time = []
5139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      new_data = []
5239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      accum = 0.0
5339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      idx = 1
5439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      for t,d in izip(self.time, self.data):
5539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        accum += d
5639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        if idx % factor == 0:
5739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania          new_time.append(t)
5839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania          new_data.append(accum / factor)
5939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania          accum = 0
6039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        idx += 1
6139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.time = new_time
6239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.data = new_data
6339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
6439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
6539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniaclass Metadata(object):
6639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def __init__(self):
6739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.kernel = ''
6839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.command_line = ''
6939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.sched = ''
7039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.name = ''
7139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.fadvise = ''
7239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.iterations = 0
7339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.duration = 0.0
7439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.complete = False
7539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
7639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def parse(self, line):
7739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    if line.startswith('# Kernel:'):
7839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.kernel = re.search('Linux version ([0-9.]+-[0-9]+)', line).group(1)
7939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    elif line.startswith('# Command:'):
8039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.command_line = re.search('# Command: [/\w_]+ (.*)', line).group(1)
8139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.command_line = self.command_line.replace(' --', '-')
8239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.command_line = self.command_line.replace(' -d', '')
8339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.command_line = self.command_line.replace('--test=', '')
8439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    elif line.startswith('# Iterations'):
8539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.iterations = int(re.search('# Iterations: ([0-9]+)', line).group(1))
8639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    elif line.startswith('# Fadvise'):
8739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.fadvise = int(re.search('# Fadvise: ([\w]+)', line).group(1))
8839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    elif line.startswith("# Sched"):
8939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.sched = re.search('# Sched features: ([\w]+)', line).group(1)
9039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      self.complete = True
9139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
9239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def asTitle(self):
9339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    return "%s-duration:%f\\n-%s\\n%s" % (self.kernel, self.duration, self.command_line, self.sched)
9439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
9539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  def updateWith(self, dataset):
9639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.duration = max(self.duration, dataset.duration)
9739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    self.name = dataset.name
9839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
9939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
10039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniadef plotIterations(metadata, data):
10139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp = Gnuplot.Gnuplot(persist = 1)
10239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp('set data style lines')
10339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.clear()
10439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.xlabel("iterations")
10539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.ylabel("duration in second")
10639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.title(metadata.asTitle())
10739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  styles = {}
10839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  line_style = 1
10939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
11039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  for dataset in data:
11139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    dataset.rescaleTo(metadata.iterations)
11239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    x = arange(len(dataset.data), dtype='int_')
11339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    if not dataset.name in styles:
11439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      styles[dataset.name] = line_style
11539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      line_style += 1
11639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      d = Gnuplot.Data(x, dataset.data,
11739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania                       title=dataset.name,
11839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania                       with_='lines ls %d' % styles[dataset.name])
11939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    else: # no need to repeat a title that exists already.
12039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      d = Gnuplot.Data(x, dataset.data,
12139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania                       with_='lines ls %d' % styles[dataset.name])
12239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
12339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    gp.replot(d)
12439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.hardcopy('/tmp/%s-%s-%f.png' % (metadata.name, metadata.kernel, metadata.duration), terminal='png')
12539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
12639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniadef plotTimes(metadata, data):
12739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp = Gnuplot.Gnuplot(persist = 1)
12839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp('set data style impulses')
12939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp('set xtics 1')
13039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.clear()
13139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.xlabel("seconds")
13239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.ylabel("duration in second")
13339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.title(metadata.asTitle())
13439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  styles = {}
13539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  line_style = 1
13639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
13739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  for dataset in data:
13839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    #dataset.rescaleTo(metadata.iterations)
13939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    x = array(dataset.time, dtype='float_')
14039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    if not dataset.name in styles:
14139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      styles[dataset.name] = line_style
14239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      line_style += 1
14339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      d = Gnuplot.Data(x, dataset.data,
14439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania                       title=dataset.name,
14539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania                       with_='impulses ls %d' % styles[dataset.name])
14639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    else: # no need to repeat a title that exists already.
14739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      d = Gnuplot.Data(x, dataset.data,
14839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania                       with_='impulses ls %d' % styles[dataset.name])
14939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
15039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    gp.replot(d)
15139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  gp.hardcopy('/tmp/%s-%s-%f.png' % (metadata.name, metadata.kernel, metadata.duration), terminal='png')
15239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
15339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
15439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Cataniadef parse(filename):
15539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  f = open(filename, 'r')
15639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
15739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  metadata = Metadata()
15839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  data = []  # array of dataset
15939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  dataset = None
16039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
16139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  for num, line in enumerate(f):
16239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    try:
16339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      line = line.strip()
16439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      if not line: continue
16539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
16639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      if not metadata.complete:
16739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        metadata.parse(line)
16839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        continue
16939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
17039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      if re.match('[a-z_]', line):
17139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        continue
17239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
17339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      if line.startswith('# StopWatch'): # Start of a new dataset
17439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        if dataset:
17539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania          if dataset.summary:
17639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania            metadata.updateWith(dataset)
17739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania          else:
17839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania            data.append(dataset)
17939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
18039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        dataset = DataSet(line)
18139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        continue
18239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
18339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      if line.startswith('#'):
18439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        continue
18539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
18639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      # must be data at this stage
18739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      try:
18839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        (time, value) = line.split(None, 1)
18939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      except ValueError:
19039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        print "skipping line %d: %s" % (num, line)
19139c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        continue
19239c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
19339c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      if dataset and not dataset.summary:
19439c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania        dataset.add(float(time), float(value))
19539c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania
19639c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania    except Exception, e:
19739c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      print "Error parsing line %d" % num, sys.exc_info()[0]
19839c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania      raise
19939c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  data.append(dataset)
20039c016f875b793296a121f41de5775b88f6fa1c9Nicolas Catania  return (metadata, data)
201