1#!/usr/bin/env python2.7 2 3# Copyright (c) 2010-2013 Advanced Micro Devices, Inc. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer; 10# redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution; 13# neither the name of the copyright holders nor the names of its 14# contributors may be used to endorse or promote products derived from 15# this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29""" 30SYNOPSIS 31 32 ./regression/verify_output.py <McPAT output> 33 34DESCRIPTION 35 36 Verify the output from McPAT. In particular, ensure that the values in the 37 file sum up hierarchically. 38 39AUTHORS 40 41 Joel Hestness <hestness@cs.wisc.edu> (while interning at AMD) 42 Yasuko Eckert <yasuko.eckert@amd.com> 43 44""" 45 46import os 47import sys 48import optparse 49import re 50 51root = None 52curr_node = None 53 54optionsparser = optparse.OptionParser( 55 formatter = optparse.TitledHelpFormatter(), 56 usage = globals()['__doc__']) 57optionsparser.add_option( 58 "-v", "--verbose", action = "store_true", default = False, 59 help = "verbose output") 60(options, args) = optionsparser.parse_args() 61 62def warning(msg): 63 global options 64 if options.verbose: 65 print "WARNING: %s" %(msg) 66 67def toNumber(value): 68 try: 69 to_return = float(value) 70 except: 71 warning("Value, %s, is not a number" % value) 72 to_return = value 73 74 return to_return 75 76def withinTolerance(reference, calculated, tolerance = 0.001): 77 if tolerance > 1: 78 warning("Tolernance is too large: %s" % tolerance) 79 upper_bound = reference * (1 + tolerance) 80 lower_bound = reference * (1 - tolerance) 81 return calculated <= upper_bound and calculated >= lower_bound 82 83class Component: 84 def __init__(self): 85 self.parent = None 86 self.name = None 87 self.area = None 88 self.peak_dynamic_power = None 89 self.subthreshold_leakage = None 90 self.gate_leakage = None 91 self.runtime_dynamic_power = None 92 self.runtime_dynamic_energy = None 93 self.total_runtime_energy = None 94 self.children = [] 95 self.hierarchy_level = None 96 97 def print_data(self): 98 print "%s:" % self.name 99 print " Area = %s" % self.area 100 print " Peak Dynamic Power = %s" % self.peak_dynamic_power 101 print " Subthreshold Leakage = %s" % self.subthreshold_leakage 102 print " Gate Leakage = %s" % self.gate_leakage 103 print " Runtime Dynamic Power = %s" % self.runtime_dynamic_power 104 print " Runtime Dynamic Energy = %s" % self.runtime_dynamic_energy 105 print " Total Runtime Energy = %s" % self.total_runtime_energy 106 107 def set_name_and_level(self, name_string): 108 self.name = name_string.lstrip().rstrip(":") 109 self.hierarchy_level = (len(re.match(r"\s*", name_string).group()) - 2) / 4 110 111 def verify_values(self): 112 if len(self.children) == 0: 113 return 114 temp_node = Component() 115 temp_node.area = 0 116 temp_node.peak_dynamic_power = 0 117 temp_node.subthreshold_leakage = 0 118 temp_node.gate_leakage = 0 119 temp_node.runtime_dynamic_power = 0 120 temp_node.runtime_dynamic_energy = 0 121 temp_node.total_runtime_energy = 0 122 for child in self.children: 123 if child != self: 124 temp_node.area += child.area 125 temp_node.peak_dynamic_power += child.peak_dynamic_power 126 temp_node.subthreshold_leakage += child.subthreshold_leakage 127 temp_node.gate_leakage += child.gate_leakage 128 temp_node.runtime_dynamic_power += child.runtime_dynamic_power 129 temp_node.runtime_dynamic_energy += child.runtime_dynamic_energy 130 temp_node.total_runtime_energy += child.total_runtime_energy 131 child.verify_values() 132 133 if not withinTolerance(self.area, temp_node.area): 134 print "WRONG: %s.area = %s != %s" % \ 135 (self.name, self.area, temp_node.area) 136 137 if not withinTolerance( 138 self.peak_dynamic_power, temp_node.peak_dynamic_power): 139 print "WRONG: %s.peak_dynamic_power = %s != %s" % \ 140 (self.name, self.peak_dynamic_power, 141 temp_node.peak_dynamic_power) 142 143 if not withinTolerance( 144 self.subthreshold_leakage, temp_node.subthreshold_leakage): 145 print "WRONG: %s.subthreshold_leakage = %s != %s" % \ 146 (self.name, self.subthreshold_leakage, 147 temp_node.subthreshold_leakage) 148 149 if not withinTolerance(self.gate_leakage, temp_node.gate_leakage): 150 print "WRONG: %s.gate_leakage = %s != %s" % \ 151 (self.name, self.gate_leakage, temp_node.gate_leakage) 152 153 if not withinTolerance( 154 self.runtime_dynamic_power, temp_node.runtime_dynamic_power): 155 print "WRONG: %s.runtime_dynamic_power = %s != %s" % \ 156 (self.name, self.runtime_dynamic_power, 157 temp_node.runtime_dynamic_power) 158 159 if not withinTolerance( 160 self.runtime_dynamic_energy, temp_node.runtime_dynamic_energy): 161 print "WRONG: %s.runtime_dynamic_energy = %s != %s" % \ 162 (self.name, self.runtime_dynamic_energy, 163 temp_node.runtime_dynamic_energy) 164 165 if not withinTolerance( 166 self.total_runtime_energy, temp_node.total_runtime_energy): 167 print "WRONG: %s.total_runtime_energy = %s != %s" % \ 168 (self.name, self.total_runtime_energy, 169 temp_node.total_runtime_energy) 170 171if len(args) < 1: 172 print "ERROR: Must specify a McPAT output file to verify" 173 exit(0) 174 175# check params 176mcpat_output = args[0]; 177if not os.path.exists(mcpat_output): 178 print "ERROR: Output file does not exist: %s" % mcpat_output 179 exit(0) 180 181output_file_handle = open(mcpat_output, 'r') 182for line in output_file_handle: 183 line = line.rstrip() 184 if ":" in line: 185 # Start a new component 186 new_node = Component() 187 if root is None: 188 root = new_node 189 curr_node = new_node 190 else: 191 if ((curr_node.area is None) or 192 (curr_node.peak_dynamic_power is None) or 193 (curr_node.subthreshold_leakage is None) or 194 (curr_node.gate_leakage is None) or 195 (curr_node.runtime_dynamic_power is None) or 196 (curr_node.runtime_dynamic_energy is None) or 197 (curr_node.total_runtime_energy is None)): 198 print "ERROR: Some value is not specified for %s" % curr_node.name 199 curr_node.print_data() 200 exit(0) 201 202 new_node.set_name_and_level(line) 203 while ( 204 (new_node.hierarchy_level <= curr_node.hierarchy_level) and 205 not curr_node is root): 206 curr_node = curr_node.parent 207 new_node.parent = curr_node 208 curr_node.children.append(new_node) 209 curr_node = new_node 210 211 elif line is not "": 212 tokens = line.split() 213 if "Area" in line: 214 curr_node.area = toNumber(tokens[2]) 215 elif "Peak Dynamic Power" in line: 216 curr_node.peak_dynamic_power = toNumber(tokens[4]) 217 elif "Peak Dynamic" in line: 218 curr_node.peak_dynamic_power = toNumber(tokens[3]) 219 elif "Subthreshold Leakage Power" in line: 220 curr_node.subthreshold_leakage = toNumber(tokens[4]) 221 elif "Subthreshold Leakage" in line: 222 curr_node.subthreshold_leakage = toNumber(tokens[3]) 223 elif "Gate Leakage Power" in line: 224 curr_node.gate_leakage = toNumber(tokens[4]) 225 elif "Gate Leakage" in line: 226 curr_node.gate_leakage = toNumber(tokens[3]) 227 elif "Runtime Dynamic Power" in line: 228 curr_node.runtime_dynamic_power = toNumber(tokens[4]) 229 elif "Runtime Dynamic Energy" in line: 230 curr_node.runtime_dynamic_energy = toNumber(tokens[4]) 231 elif "Total Runtime Energy" in line: 232 curr_node.total_runtime_energy = toNumber(tokens[4]) 233 else: 234 warning("ERROR: Line not matched: %s" % line) 235 236curr_node = root 237 238curr_node.verify_values() 239