util: Add script to plot DRAM low power sweep

This change adds a script to generate graphs from the stats file
output by the configuration script low_power_sweep.py.

The graphs show stacked bars for time spent and energy consumed
wherein each component of the stacked bar represents a DRAM power
state (Idle, Refresh, Active, Active Power-down, Precharge Power-down
and Self-refresh). The script generates one plot per delay value. It
also generates a pdf (--pdf option) in which the graphs are laid out
such that you can easily compare how the increasing delay and other
swept params affect the resulting energy.

Change-Id: Id80b0947bfde27e11e5505b23a3adb30f793a43f
Reviewed-by: Wendy Elsasser <wendy.elsasser@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/5727
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Radhika Jagtap
2017-06-21 11:17:43 +01:00
committed by Andreas Sandberg
parent 1695c9933b
commit 9b4e797cdd
4 changed files with 459 additions and 0 deletions

308
util/plot_dram/PlotPowerStates.py Executable file
View File

@@ -0,0 +1,308 @@
# Copyright (c) 2017 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Radhika Jagtap
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
import numpy as np
import os
# global results dict
results = {}
idleResults = {}
# global vars for bank utilisation and seq_bytes values swept in the experiment
bankUtilValues = []
seqBytesValues = []
delayValues = []
# settings for 3 values of bank util and 3 values of seq_bytes
stackHeight = 6.0
stackWidth = 18.0
barWidth = 0.5
plotFontSize = 18
States = ['IDLE', 'ACT', 'REF', 'ACT_PDN', 'PRE_PDN', 'SREF']
EnergyStates = ['ACT_E',
'PRE_E',
'READ_E',
'REF_E',
'ACT_BACK_E',
'PRE_BACK_E',
'ACT_PDN_E',
'PRE_PDN_E',
'SREF_E']
StackColors = {
'IDLE' : 'black', # time spent in states
'ACT' : 'lightskyblue',
'REF' : 'limegreen',
'ACT_PDN' : 'crimson',
'PRE_PDN' : 'orange',
'SREF' : 'gold',
'ACT_E' : 'lightskyblue', # energy of states
'PRE_E' : 'black',
'READ_E' : 'white',
'REF_E' : 'limegreen',
'ACT_BACK_E' : 'lightgray',
'PRE_BACK_E' : 'gray',
'ACT_PDN_E' : 'crimson',
'PRE_PDN_E' : 'orange',
'SREF_E' : 'gold'
}
StatToKey = {
'system.mem_ctrls_0.actEnergy' : 'ACT_E',
'system.mem_ctrls_0.preEnergy' : 'PRE_E',
'system.mem_ctrls_0.readEnergy' : 'READ_E',
'system.mem_ctrls_0.refreshEnergy' : 'REF_E',
'system.mem_ctrls_0.actBackEnergy' : 'ACT_BACK_E',
'system.mem_ctrls_0.preBackEnergy' : 'PRE_BACK_E',
'system.mem_ctrls_0.actPowerDownEnergy' : 'ACT_PDN_E',
'system.mem_ctrls_0.prePowerDownEnergy' : 'PRE_PDN_E',
'system.mem_ctrls_0.selfRefreshEnergy' : 'SREF_E'
}
# Skipping write energy, the example script issues 100% reads by default
# 'system.mem_ctrls_0.writeEnergy' : "WRITE"
def plotLowPStates(plot_dir, stats_fname, bank_util_list, seqbytes_list,
delay_list):
"""
plotLowPStates generates plots by parsing statistics output by the DRAM
sweep simulation described in the the configs/dram/low_power_sweep.py
script.
The function outputs eps format images for the following plots
(1) time spent in the DRAM Power states as a stacked bar chart
(2) energy consumed by the DRAM Power states as a stacked bar chart
(3) idle plot for the last stats dump corresponding to an idle period
For all plots, the time and energy values of the first rank (i.e. rank0)
are plotted because the way the script is written means stats across ranks
are similar.
@param plot_dir: the dir to output the plots
@param stats_fname: the stats file name of the low power sweep sim
@param bank_util_list: list of bank utilisation values (e.g. [1, 4, 8])
@param seqbytes_list: list of seq_bytes values (e.g. [64, 456, 512])
@param delay_list: list of itt max multipliers (e.g. [1, 20, 200])
"""
stats_file = open(stats_fname, 'r')
global bankUtilValues
bankUtilValues = bank_util_list
global seqBytesValues
seqBytesValues = seqbytes_list
global delayValues
delayValues = delay_list
initResults()
# throw away the first two lines of the stats file
stats_file.readline()
stats_file.readline() # the 'Begin' line
#######################################
# Parse stats file and gather results
########################################
for delay in delayValues:
for bank_util in bankUtilValues:
for seq_bytes in seqBytesValues:
for line in stats_file:
if 'Begin' in line:
break
if len(line.strip()) == 0:
continue
#### state time values ####
if 'system.mem_ctrls_0.memoryStateTime' in line:
# remove leading and trailing white spaces
line = line.strip()
# Example format:
# 'system.mem_ctrls_0.memoryStateTime::ACT 1000000'
statistic, stime = line.split()[0:2]
# Now grab the state, i.e. 'ACT'
state = statistic.split('::')[1]
# store the value of the stat in the results dict
results[delay][bank_util][seq_bytes][state] = \
int(stime)
#### state energy values ####
elif line.strip().split()[0] in StatToKey.keys():
# Example format:
# system.mem_ctrls_0.actEnergy 35392980
statistic, e_val = line.strip().split()[0:2]
senergy = int(float(e_val))
state = StatToKey[statistic]
# store the value of the stat in the results dict
results[delay][bank_util][seq_bytes][state] = senergy
# To add last traffic gen idle period stats to the results dict
for line in stats_file:
if 'system.mem_ctrls_0.memoryStateTime' in line:
line = line.strip() # remove leading and trailing white spaces
# Example format:
# 'system.mem_ctrls_0.memoryStateTime::ACT 1000000'
statistic, stime = line.split()[0:2]
# Now grab the state energy, .e.g 'ACT'
state = statistic.split('::')[1]
idleResults[state] = int(stime)
if state == 'ACT_PDN':
break
########################################
# Call plot functions
########################################
# one plot per delay value
for delay in delayValues:
plot_path = plot_dir + delay + '-'
plotStackedStates(delay, States, 'IDLE', stateTimePlotName(plot_path),
'Time (ps) spent in a power state')
plotStackedStates(delay, EnergyStates, 'ACT_E',
stateEnergyPlotName(plot_path),
'Energy (pJ) of a power state')
plotIdle(plot_dir)
def plotIdle(plot_dir):
"""
Create a bar chart for the time spent in power states during the idle phase
@param plot_dir: the dir to output the plots
"""
fig, ax = plt.subplots()
width = 0.35
ind = np.arange(len(States))
l1 = ax.bar(ind, map(lambda x : idleResults[x], States), width)
ax.xaxis.set_ticks(ind + width/2)
ax.xaxis.set_ticklabels(States)
ax.set_ylabel('Time (ps) spent in a power state')
fig.suptitle("Idle 50 us")
print "saving plot:", idlePlotName(plot_dir)
plt.savefig(idlePlotName(plot_dir), format='eps')
plt.close(fig)
def plotStackedStates(delay, states_list, bottom_state, plot_name, ylabel_str):
"""
Create a stacked bar chart for the list that is passed in as arg, which
is either time spent or energy consumed in power states.
@param delay: one plot is output per delay value
@param states_list: list of either time or energy state names
@param bottom_state: the bottom-most component of the stacked bar
@param plot_name: the file name of the image to write the plot to
@param ylabel_str: Y-axis label depending on plotting time or energy
"""
fig, ax = plt.subplots(1, len(bankUtilValues), sharey=True)
fig.set_figheight(stackHeight)
fig.set_figwidth(stackWidth)
width = barWidth
plt.rcParams.update({'font.size': plotFontSize})
# Get the number of seq_bytes values
N = len(seqBytesValues)
ind = np.arange(N)
for sub_idx, bank_util in enumerate(bankUtilValues):
l_states = {}
p_states = {}
# Must have a bottom of the stack first
state = bottom_state
l_states[state] = map(lambda x: results[delay][bank_util][x][state],
seqBytesValues)
p_states[state] = ax[sub_idx].bar(ind, l_states[state], width,
color=StackColors[state])
time_sum = l_states[state]
for state in states_list[1:]:
l_states[state] = map(lambda x:
results[delay][bank_util][x][state],
seqBytesValues)
# Now add on top of the bottom = sum of values up until now
p_states[state] = ax[sub_idx].bar(ind, l_states[state], width,
color=StackColors[state],
bottom=time_sum)
# Now add the bit of the stack that we just ploted to the bottom
# resulting in a new bottom for the next iteration
time_sum = [prev_sum + new_s for prev_sum, new_s in \
zip(time_sum, l_states[state])]
ax[sub_idx].set_title('Bank util %s' % bank_util)
ax[sub_idx].xaxis.set_ticks(ind + width/2.)
ax[sub_idx].xaxis.set_ticklabels(seqBytesValues, rotation=45)
ax[sub_idx].set_xlabel('Seq. bytes')
if bank_util == bankUtilValues[0]:
ax[sub_idx].set_ylabel(ylabel_str)
myFontSize='small'
fontP = FontProperties()
fontP.set_size(myFontSize)
fig.legend(map(lambda x: p_states[x], states_list), states_list,
prop=fontP)
plt.savefig(plot_name, format='eps', bbox_inches='tight')
print "saving plot:", plot_name
plt.close(fig)
# These plat name functions are also called in the main script
def idlePlotName(plot_dir):
return (plot_dir + 'idle.eps')
def stateTimePlotName(plot_dir):
return (plot_dir + 'state-time.eps')
def stateEnergyPlotName(plot_dir):
return (plot_dir + 'state-energy.eps')
def initResults():
for delay in delayValues:
results[delay] = {}
for bank_util in bankUtilValues:
results[delay][bank_util] = {}
for seq_bytes in seqBytesValues:
results[delay][bank_util][seq_bytes] = {}

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env python2
# Copyright (c) 2015 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Andreas Hansson
try:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
except ImportError:
print "Failed to import matplotlib and numpy"
exit(-1)
import sys
import re
# This script is intended to post process and plot the output from
# running configs/dram/lat_mem_rd.py, as such it parses the simout and
# stats.txt to get the relevant data points.
def main():
if len(sys.argv) != 2:
print "Usage: ", sys.argv[0], "<simout directory>"
exit(-1)
try:
stats = open(sys.argv[1] + '/stats.txt', 'r')
except IOError:
print "Failed to open ", sys.argv[1] + '/stats.txt', " for reading"
exit(-1)
try:
simout = open(sys.argv[1] + '/simout', 'r')
except IOError:
print "Failed to open ", sys.argv[1] + '/simout', " for reading"
exit(-1)
# Get the address ranges
got_ranges = False
ranges = []
iterations = 1
for line in simout:
if got_ranges:
ranges.append(int(line) / 1024)
match = re.match("lat_mem_rd with (\d+) iterations, ranges:.*", line)
if match:
got_ranges = True
iterations = int(match.groups(0)[0])
simout.close()
if not got_ranges:
print "Failed to get address ranges, ensure simout is up-to-date"
exit(-1)
# Now parse the stats
raw_rd_lat = []
for line in stats:
match = re.match(".*readLatencyHist::mean\s+(.+)\s+#.*", line)
if match:
raw_rd_lat.append(float(match.groups(0)[0]) / 1000)
stats.close()
# The stats also contain the warming, so filter the latency stats
i = 0
filtered_rd_lat = []
for l in raw_rd_lat:
if i % (iterations + 1) == 0:
pass
else:
filtered_rd_lat.append(l)
i = i + 1
# Next we need to take care of the iterations
rd_lat = []
for i in range(iterations):
rd_lat.append(filtered_rd_lat[i::iterations])
final_rd_lat = map(lambda p: min(p), zip(*rd_lat))
# Sanity check
if not (len(ranges) == len(final_rd_lat)):
print "Address ranges (%d) and read latency (%d) do not match" % \
(len(ranges), len(final_rd_lat))
exit(-1)
for (r, l) in zip(ranges, final_rd_lat):
print r, round(l, 2)
# lazy version to check if an integer is a power of two
def is_pow2(num):
return num != 0 and ((num & (num - 1)) == 0)
plt.semilogx(ranges, final_rd_lat)
# create human readable labels
xticks_locations = [r for r in ranges if is_pow2(r)]
xticks_labels = []
for x in xticks_locations:
if x < 1024:
xticks_labels.append('%d kB' % x)
else:
xticks_labels.append('%d MB' % (x / 1024))
plt.xticks(xticks_locations, xticks_labels, rotation=-45)
plt.minorticks_off()
plt.xlim((xticks_locations[0], xticks_locations[-1]))
plt.ylabel("Latency (ns)")
plt.grid(True)
plt.show()
if __name__ == "__main__":
main()

193
util/plot_dram/dram_sweep_plot.py Executable file
View File

@@ -0,0 +1,193 @@
#!/usr/bin/env python2
# Copyright (c) 2014 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Andreas Hansson
try:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
except ImportError:
print "Failed to import matplotlib and numpy"
exit(-1)
import sys
import re
# Determine the parameters of the sweep from the simout output, and
# then parse the stats and plot the 3D surface corresponding to the
# different combinations of parallel banks, and stride size, as
# generated by the config/dram/sweep.py script
def main():
if len(sys.argv) != 3:
print "Usage: ", sys.argv[0], "-u|p|e <simout directory>"
exit(-1)
if len(sys.argv[1]) != 2 or sys.argv[1][0] != '-' or \
not sys.argv[1][1] in "upe":
print "Choose -u (utilisation), -p (total power), or -e " \
"(power efficiency)"
exit(-1)
# Choose the appropriate mode, either utilisation, total power, or
# efficiency
mode = sys.argv[1][1]
try:
stats = open(sys.argv[2] + '/stats.txt', 'r')
except IOError:
print "Failed to open ", sys.argv[2] + '/stats.txt', " for reading"
exit(-1)
try:
simout = open(sys.argv[2] + '/simout', 'r')
except IOError:
print "Failed to open ", sys.argv[2] + '/simout', " for reading"
exit(-1)
# Get the burst size, number of banks and the maximum stride from
# the simulation output
got_sweep = False
for line in simout:
match = re.match("DRAM sweep with "
"burst: (\d+), banks: (\d+), max stride: (\d+)", line)
if match:
burst_size = int(match.groups(0)[0])
banks = int(match.groups(0)[1])
max_size = int(match.groups(0)[2])
got_sweep = True
simout.close()
if not got_sweep:
print "Failed to establish sweep details, ensure simout is up-to-date"
exit(-1)
# Now parse the stats
peak_bw = []
bus_util = []
avg_pwr = []
for line in stats:
match = re.match(".*busUtil\s+(\d+\.\d+)\s+#.*", line)
if match:
bus_util.append(float(match.groups(0)[0]))
match = re.match(".*peakBW\s+(\d+\.\d+)\s+#.*", line)
if match:
peak_bw.append(float(match.groups(0)[0]))
match = re.match(".*averagePower\s+(\d+\.?\d*)\s+#.*", line)
if match:
avg_pwr.append(float(match.groups(0)[0]))
stats.close()
# Sanity check
if not (len(peak_bw) == len(bus_util) and len(bus_util) == len(avg_pwr)):
print "Peak bandwidth, bus utilisation, and average power do not match"
exit(-1)
# Collect the selected metric as our Z-axis, we do this in a 2D
# grid corresponding to each iteration over the various stride
# sizes.
z = []
zs = []
i = 0
for j in range(len(peak_bw)):
if mode == 'u':
z.append(bus_util[j])
elif mode == 'p':
z.append(avg_pwr[j])
elif mode == 'e':
# avg_pwr is in mW, peak_bw in MiByte/s, bus_util in percent
z.append(avg_pwr[j] / (bus_util[j] / 100.0 * peak_bw[j] / 1000.0))
else:
print "Unexpected mode %s" % mode
exit(-1)
i += 1
# If we have completed a sweep over the stride sizes,
# start anew
if i == max_size / burst_size:
zs.append(z)
z = []
i = 0
# We should have a 2D grid with as many columns as banks
if len(zs) != banks:
print "Unexpected number of data points in stats output"
exit(-1)
fig = plt.figure()
ax = fig.gca(projection='3d')
X = np.arange(burst_size, max_size + 1, burst_size)
Y = np.arange(1, banks + 1, 1)
X, Y = np.meshgrid(X, Y)
# the values in the util are banks major, so we see groups for each
# stride size in order
Z = np.array(zs)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Change the tick frequency to 64
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end + 1, 64))
ax.set_xlabel('Bytes per activate')
ax.set_ylabel('Banks')
if mode == 'u':
ax.set_zlabel('Utilisation (%)')
elif mode == 'p':
ax.set_zlabel('Power (mW)')
elif mode == 'e':
ax.set_zlabel('Power efficiency (mW / GByte / s)')
# Add a colorbar
fig.colorbar(surf, shrink=0.5, pad=.1, aspect=10)
plt.show()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,151 @@
#! /usr/bin/python
#
# Copyright (c) 2017 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Authors: Radhika Jagtap
import PlotPowerStates as plotter
import argparse
import os
from subprocess import call
parser = argparse.ArgumentParser(formatter_class=
argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("--statsfile", required=True, help="stats file path")
parser.add_argument("--bankutils", default="b1 b2 b3", help="target bank " \
"utilization values separated by space, e.g. \"1 4 8\"")
parser.add_argument("--seqbytes", default="s1 s2 s3", help="no. of " \
"sequential bytes requested by each traffic gen request." \
" e.g. \"64 256 512\"")
parser.add_argument("--delays", default="d1 d2 d3", help="string of delay"
" values separated by a space. e.g. \"1 20 100\"")
parser.add_argument("--outdir", help="directory to output plots",
default='plot_test')
parser.add_argument("--pdf", action='store_true', help="output Latex and pdf")
def main():
args = parser.parse_args()
if not os.path.isfile(args.statsfile):
exit('Error! File not found: %s' % args.statsfile)
if not os.path.isdir(args.outdir):
os.mkdir(args.outdir)
bank_util_list = args.bankutils.strip().split()
seqbyte_list = args.seqbytes.strip().split()
delays = args.delays.strip().split()
plotter.plotLowPStates(args.outdir + '/', args.statsfile, bank_util_list,
seqbyte_list, delays)
if args.pdf:
textwidth = '0.5'
### Time and energy plots ###
#############################
# place tex and pdf files in outdir
os.chdir(args.outdir)
texfile_s = 'stacked_lowp_sweep.tex'
print "\t", texfile_s
outfile = open(texfile_s, 'w')
startDocText(outfile)
outfile.write("\\begin{figure} \n\centering\n")
## Time plots for all delay values
for delay in delays:
# Time
filename = plotter.stateTimePlotName(str(delay) + '-')
outfile.write(wrapForGraphic(filename, textwidth))
outfile.write(getCaption(delay))
outfile.write("\end{figure}\n")
# Energy plots for all delay values
outfile.write("\\begin{figure} \n\centering\n")
for delay in delays:
# Energy
filename = plotter.stateEnergyPlotName(str(delay) + '-')
outfile.write(wrapForGraphic(filename, textwidth))
outfile.write(getCaption(delay))
outfile.write("\end{figure}\n")
endDocText(outfile)
outfile.close()
print "\n Generating pdf file"
print "*******************************"
print "\tpdflatex ", texfile_s
# Run pdflatex to generate to pdf
call(["pdflatex", texfile_s])
call(["open", texfile_s.split('.')[0] + '.pdf'])
def getCaption(delay):
return ('\caption{' +
'itt delay = ' + str(delay) +
'}\n')
def wrapForGraphic(filename, width='1.0'):
# \t is tab and needs to be escaped, therefore \\textwidth
return '\includegraphics[width=' + width + \
'\\textwidth]{' + filename + '}\n'
def startDocText(outfile):
start_stuff = '''
\documentclass[a4paper,landscape,twocolumn]{article}
\usepackage{graphicx}
\usepackage[margin=0.5cm]{geometry}
\\begin{document}
'''
outfile.write(start_stuff)
def endDocText(outfile):
end_stuff = '''
\end{document}
'''
outfile.write(end_stuff)
# Call main
if __name__ == '__main__':
main()