Files
fail/tools/analysis/faultspaceplot/fsp.plot.py
Horst Schirmeier ee8759f6b8 faultspaceplot: don't round down ymin
Before this change, ymin was rounded down to the nearest Y value
divisible by 1000, showing an empty, white area in the lower part of
the plot.  With this change, the initial Y-axis zoom level is
maximized to exactly show all non-white areas.

Change-Id: I1aea52a3afc331e7f11fe76ff2c5de3c71c61c71
2016-03-11 20:41:52 +01:00

168 lines
5.3 KiB
Python
Executable File

#!/usr/bin/env python
# -------------------------------------------------------------------------
# Import modules
import csv, sys
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
import matplotlib.pylab as pylab
ENTRY_COUNT_PER_LINE = 6
RESULT_RECT_HEIGHT = 1.0/8
# -------------------------------------------------------------------------
# Basic drawing class
class Rectangle:
def __init__(self, x, y, w, h, color):
# w
self.xpos = x # |-------------------|
self.ypos = y # | | h
self.width = w # | |
self.height = h # (x,y)---------------|
self.color = color # fill color
self.alpha = None # transparency level [0,1]
def draw(self):
""" Draw the rectangle. """
if self.color == (1,1,1):
return
tmp = self.xpos, self.ypos,
p = mpatches.Rectangle(tmp, self.width, self.height, color=self.color, \
alpha=self.alpha)
plt.gca().add_patch(p)
# -------------------------------------------------------------------------
# Check provided arguments:
if len(sys.argv) <= 1:
print "ERROR: Not enough arguments provided! See -h for more infos."
exit(1)
if sys.argv[1] == '-h':
print "Displays experiment results for the weather-monitor-experiment."
print " CALL-SYNTAX: fsp.plot.py DATA_FILE [USER_TAG_FILE]"
print "DATA_FILE is a CSV-file, storing the tab-separated values"
print "retrieved by the experiment run. USER_TAG_FILE is an optional"
print "CSV-file which can be used to add user-specific marks to the"
print "plot." # TODO: be more precise here
exit(0)
print "Opening and processing \"" + sys.argv[1] + "\"..."
file = open(sys.argv[1], "r")
dialect = csv.Sniffer().sniff(file.read(1024))
file.seek(0)
reader = csv.reader(file, dialect)
reader.next() # Move down a line to skip the header
if len(sys.argv) >= 3:
print "Opening and processing \"" + sys.argv[2] + "\"..."
symbolfile = open(sys.argv[2], "r")
dialect = csv.Sniffer().sniff(symbolfile.read(1024))
symbolfile.seek(0)
symbolreader = csv.reader(symbolfile, dialect)
symbolreader.next() # Move down a line to skip the header
have_symbols = True
else:
have_symbols = False
fig = plt.figure()
xmin = 99999999
xmax = 0
ymin = 99999999
ymax = 0
line_counter = 1
for row in reader:
line_counter += 1
# Check if there are at least ENTRY_COUNT_PER_LINE entries per line:
if len(row) != ENTRY_COUNT_PER_LINE:
print "ERROR: Line " + str(line_counter) + " is invalid (" +\
str(ENTRY_COUNT_PER_LINE) + " entries expected)"
sys.exit(1)
# Some constants to access the row-entries much easier:
IDX_INSTR1 = 0; IDX_INSTR2 = 1; IDX_DATA_ADDRESS = 2;
IDX_BITNR = 3; IDX_BITWIDTH = 4; IDX_COLOR = 5;
# Update xmin/xmax/ymin/ymax
x1 = int(row[IDX_INSTR1])
x2 = int(row[IDX_INSTR2]) + 1 # inclusive
width = x2 - x1
if xmin > x1:
xmin = x1
if xmax < x2:
xmax = x2
y1 = float(row[IDX_DATA_ADDRESS]) + float(row[IDX_BITNR]) / 8.0
height = float(row[IDX_BITWIDTH]) / 8.0
y2 = y1 + height
if ymin > y1:
ymin = y1
if ymax < y2:
ymax = y2
Rectangle(x1, y1, width, height, row[IDX_COLOR]).draw()
if line_counter == 50000: # debug stuff
pass
#break
# round down to nearest 1000
#ymin = int(ymin / 1000) * 1000
file.close()
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
plt.ylabel('Data Memory (RAM)')
plt.xlabel('Time (Cycles)')
# show symbols
if have_symbols:
# Adding 2nd y-axis for object names
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax2.set_ylabel('Symbols')
# necessary for proper symbol placement
plt.ylim(ymin, ymax)
ticks = []
symbols = []
IDX_SYMBOL_ADDRESS = 0; IDX_SYMBOL_SIZE = 1; IDX_SYMBOL_NAME = 2;
for row in symbolreader:
# TODO: somehow plot size as well
address = int(row[IDX_SYMBOL_ADDRESS])
size = int(row[IDX_SYMBOL_SIZE])
if (address >= ymin) and (address <= ymax):
ticks.append(address)
symbols.append(row[IDX_SYMBOL_NAME])
#print "symbol: " + str(address) + " " + str(size) + " " + row[IDX_SYMBOL_NAME]
elif (address < ymin) and (address + size >= ymin):
ticks.append(ymin)
symbols.append("(" + row[IDX_SYMBOL_NAME] + ")")
#print "partial symbol: " + str(address) + " " + str(size) + " " + row[IDX_SYMBOL_NAME]
else:
#print "skipped symbol: " + str(address) + " " + str(size) + " " + row[IDX_SYMBOL_NAME]
pass
# list of interesting addresses
ax2.yaxis.set_ticks(ticks)
ax2.yaxis.grid(b=True, color='gray')
# create minor ticks centered between major tick marks
centered_ticks = []
major_locator = ax2.yaxis.get_major_locator()
major_locs = major_locator()
for i in range(1,len(major_locs)):
y_last,y = major_locs[i-1],major_locs[i]
centered_ticks.append(0.5*(y+y_last))
ax2.yaxis.set_ticks(centered_ticks, minor=True)
# list of corresponding symbol names
ax2.set_yticklabels(symbols, minor=False, rotation=0, rotation_mode='anchor')
plt.show()
#pylab.savefig('baseline.pdf', bbox_inches='tight')