239 lines
9.2 KiB
Python
239 lines
9.2 KiB
Python
|
#!/usr/bin/env python
|
||
|
|
||
|
# Copyright (c) 2010-2013 Advanced Micro Devices, Inc.
|
||
|
# All rights reserved.
|
||
|
#
|
||
|
# 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.
|
||
|
|
||
|
"""
|
||
|
SYNOPSIS
|
||
|
|
||
|
./regression/verify_output.py <McPAT output>
|
||
|
|
||
|
DESCRIPTION
|
||
|
|
||
|
Verify the output from McPAT. In particular, ensure that the values in the
|
||
|
file sum up hierarchically.
|
||
|
|
||
|
AUTHORS
|
||
|
|
||
|
Joel Hestness <hestness@cs.wisc.edu> (while interning at AMD)
|
||
|
Yasuko Eckert <yasuko.eckert@amd.com>
|
||
|
|
||
|
"""
|
||
|
|
||
|
import os
|
||
|
import sys
|
||
|
import optparse
|
||
|
import re
|
||
|
|
||
|
root = None
|
||
|
curr_node = None
|
||
|
|
||
|
optionsparser = optparse.OptionParser(
|
||
|
formatter = optparse.TitledHelpFormatter(),
|
||
|
usage = globals()['__doc__'])
|
||
|
optionsparser.add_option(
|
||
|
"-v", "--verbose", action = "store_true", default = False,
|
||
|
help = "verbose output")
|
||
|
(options, args) = optionsparser.parse_args()
|
||
|
|
||
|
def warning(msg):
|
||
|
global options
|
||
|
if options.verbose:
|
||
|
print "WARNING: %s" %(msg)
|
||
|
|
||
|
def toNumber(value):
|
||
|
try:
|
||
|
to_return = float(value)
|
||
|
except:
|
||
|
warning("Value, %s, is not a number" % value)
|
||
|
to_return = value
|
||
|
|
||
|
return to_return
|
||
|
|
||
|
def withinTolerance(reference, calculated, tolerance = 0.001):
|
||
|
if tolerance > 1:
|
||
|
warning("Tolernance is too large: %s" % tolerance)
|
||
|
upper_bound = reference * (1 + tolerance)
|
||
|
lower_bound = reference * (1 - tolerance)
|
||
|
return calculated <= upper_bound and calculated >= lower_bound
|
||
|
|
||
|
class Component:
|
||
|
def __init__(self):
|
||
|
self.parent = None
|
||
|
self.name = None
|
||
|
self.area = None
|
||
|
self.peak_dynamic_power = None
|
||
|
self.subthreshold_leakage = None
|
||
|
self.gate_leakage = None
|
||
|
self.runtime_dynamic_power = None
|
||
|
self.runtime_dynamic_energy = None
|
||
|
self.total_runtime_energy = None
|
||
|
self.children = []
|
||
|
self.hierarchy_level = None
|
||
|
|
||
|
def print_data(self):
|
||
|
print "%s:" % self.name
|
||
|
print " Area = %s" % self.area
|
||
|
print " Peak Dynamic Power = %s" % self.peak_dynamic_power
|
||
|
print " Subthreshold Leakage = %s" % self.subthreshold_leakage
|
||
|
print " Gate Leakage = %s" % self.gate_leakage
|
||
|
print " Runtime Dynamic Power = %s" % self.runtime_dynamic_power
|
||
|
print " Runtime Dynamic Energy = %s" % self.runtime_dynamic_energy
|
||
|
print " Total Runtime Energy = %s" % self.total_runtime_energy
|
||
|
|
||
|
def set_name_and_level(self, name_string):
|
||
|
self.name = name_string.lstrip().rstrip(":")
|
||
|
self.hierarchy_level = (len(re.match(r"\s*", name_string).group()) - 2) / 4
|
||
|
|
||
|
def verify_values(self):
|
||
|
if len(self.children) == 0:
|
||
|
return
|
||
|
temp_node = Component()
|
||
|
temp_node.area = 0
|
||
|
temp_node.peak_dynamic_power = 0
|
||
|
temp_node.subthreshold_leakage = 0
|
||
|
temp_node.gate_leakage = 0
|
||
|
temp_node.runtime_dynamic_power = 0
|
||
|
temp_node.runtime_dynamic_energy = 0
|
||
|
temp_node.total_runtime_energy = 0
|
||
|
for child in self.children:
|
||
|
if child != self:
|
||
|
temp_node.area += child.area
|
||
|
temp_node.peak_dynamic_power += child.peak_dynamic_power
|
||
|
temp_node.subthreshold_leakage += child.subthreshold_leakage
|
||
|
temp_node.gate_leakage += child.gate_leakage
|
||
|
temp_node.runtime_dynamic_power += child.runtime_dynamic_power
|
||
|
temp_node.runtime_dynamic_energy += child.runtime_dynamic_energy
|
||
|
temp_node.total_runtime_energy += child.total_runtime_energy
|
||
|
child.verify_values()
|
||
|
|
||
|
if not withinTolerance(self.area, temp_node.area):
|
||
|
print "WRONG: %s.area = %s != %s" % \
|
||
|
(self.name, self.area, temp_node.area)
|
||
|
|
||
|
if not withinTolerance(
|
||
|
self.peak_dynamic_power, temp_node.peak_dynamic_power):
|
||
|
print "WRONG: %s.peak_dynamic_power = %s != %s" % \
|
||
|
(self.name, self.peak_dynamic_power,
|
||
|
temp_node.peak_dynamic_power)
|
||
|
|
||
|
if not withinTolerance(
|
||
|
self.subthreshold_leakage, temp_node.subthreshold_leakage):
|
||
|
print "WRONG: %s.subthreshold_leakage = %s != %s" % \
|
||
|
(self.name, self.subthreshold_leakage,
|
||
|
temp_node.subthreshold_leakage)
|
||
|
|
||
|
if not withinTolerance(self.gate_leakage, temp_node.gate_leakage):
|
||
|
print "WRONG: %s.gate_leakage = %s != %s" % \
|
||
|
(self.name, self.gate_leakage, temp_node.gate_leakage)
|
||
|
|
||
|
if not withinTolerance(
|
||
|
self.runtime_dynamic_power, temp_node.runtime_dynamic_power):
|
||
|
print "WRONG: %s.runtime_dynamic_power = %s != %s" % \
|
||
|
(self.name, self.runtime_dynamic_power,
|
||
|
temp_node.runtime_dynamic_power)
|
||
|
|
||
|
if not withinTolerance(
|
||
|
self.runtime_dynamic_energy, temp_node.runtime_dynamic_energy):
|
||
|
print "WRONG: %s.runtime_dynamic_energy = %s != %s" % \
|
||
|
(self.name, self.runtime_dynamic_energy,
|
||
|
temp_node.runtime_dynamic_energy)
|
||
|
|
||
|
if not withinTolerance(
|
||
|
self.total_runtime_energy, temp_node.total_runtime_energy):
|
||
|
print "WRONG: %s.total_runtime_energy = %s != %s" % \
|
||
|
(self.name, self.total_runtime_energy,
|
||
|
temp_node.total_runtime_energy)
|
||
|
|
||
|
if len(args) < 1:
|
||
|
print "ERROR: Must specify a McPAT output file to verify"
|
||
|
exit(0)
|
||
|
|
||
|
# check params
|
||
|
mcpat_output = args[0];
|
||
|
if not os.path.exists(mcpat_output):
|
||
|
print "ERROR: Output file does not exist: %s" % mcpat_output
|
||
|
exit(0)
|
||
|
|
||
|
output_file_handle = open(mcpat_output, 'r')
|
||
|
for line in output_file_handle:
|
||
|
line = line.rstrip()
|
||
|
if ":" in line:
|
||
|
# Start a new component
|
||
|
new_node = Component()
|
||
|
if root is None:
|
||
|
root = new_node
|
||
|
curr_node = new_node
|
||
|
else:
|
||
|
if ((curr_node.area is None) or
|
||
|
(curr_node.peak_dynamic_power is None) or
|
||
|
(curr_node.subthreshold_leakage is None) or
|
||
|
(curr_node.gate_leakage is None) or
|
||
|
(curr_node.runtime_dynamic_power is None) or
|
||
|
(curr_node.runtime_dynamic_energy is None) or
|
||
|
(curr_node.total_runtime_energy is None)):
|
||
|
print "ERROR: Some value is not specified for %s" % curr_node.name
|
||
|
curr_node.print_data()
|
||
|
exit(0)
|
||
|
|
||
|
new_node.set_name_and_level(line)
|
||
|
while (
|
||
|
(new_node.hierarchy_level <= curr_node.hierarchy_level) and
|
||
|
not curr_node is root):
|
||
|
curr_node = curr_node.parent
|
||
|
new_node.parent = curr_node
|
||
|
curr_node.children.append(new_node)
|
||
|
curr_node = new_node
|
||
|
|
||
|
elif line is not "":
|
||
|
tokens = line.split()
|
||
|
if "Area" in line:
|
||
|
curr_node.area = toNumber(tokens[2])
|
||
|
elif "Peak Dynamic Power" in line:
|
||
|
curr_node.peak_dynamic_power = toNumber(tokens[4])
|
||
|
elif "Peak Dynamic" in line:
|
||
|
curr_node.peak_dynamic_power = toNumber(tokens[3])
|
||
|
elif "Subthreshold Leakage Power" in line:
|
||
|
curr_node.subthreshold_leakage = toNumber(tokens[4])
|
||
|
elif "Subthreshold Leakage" in line:
|
||
|
curr_node.subthreshold_leakage = toNumber(tokens[3])
|
||
|
elif "Gate Leakage Power" in line:
|
||
|
curr_node.gate_leakage = toNumber(tokens[4])
|
||
|
elif "Gate Leakage" in line:
|
||
|
curr_node.gate_leakage = toNumber(tokens[3])
|
||
|
elif "Runtime Dynamic Power" in line:
|
||
|
curr_node.runtime_dynamic_power = toNumber(tokens[4])
|
||
|
elif "Runtime Dynamic Energy" in line:
|
||
|
curr_node.runtime_dynamic_energy = toNumber(tokens[4])
|
||
|
elif "Total Runtime Energy" in line:
|
||
|
curr_node.total_runtime_energy = toNumber(tokens[4])
|
||
|
else:
|
||
|
warning("ERROR: Line not matched: %s" % line)
|
||
|
|
||
|
curr_node = root
|
||
|
|
||
|
curr_node.verify_values()
|