convert.py revision 13696:b303ca652433
1# Copyright (c) 2005 The Regents of The University of Michigan 2# Copyright (c) 2010 Advanced Micro Devices, Inc. 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions are 7# met: redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer; 9# redistributions in binary form must reproduce the above copyright 10# notice, this list of conditions and the following disclaimer in the 11# documentation and/or other materials provided with the distribution; 12# neither the name of the copyright holders nor the names of its 13# contributors may be used to endorse or promote products derived from 14# this software without specific prior written permission. 15# 16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27# 28# Authors: Nathan Binkert 29# Gabe Black 30 31# metric prefixes 32atto = 1.0e-18 33femto = 1.0e-15 34pico = 1.0e-12 35nano = 1.0e-9 36micro = 1.0e-6 37milli = 1.0e-3 38 39kilo = 1.0e3 40mega = 1.0e6 41giga = 1.0e9 42tera = 1.0e12 43peta = 1.0e15 44exa = 1.0e18 45 46# power of 2 prefixes 47kibi = 1024 48mebi = kibi * 1024 49gibi = mebi * 1024 50tebi = gibi * 1024 51pebi = tebi * 1024 52exbi = pebi * 1024 53 54metric_prefixes = { 55 'Ei': exbi, 56 'E': exa, 57 'Pi': pebi, 58 'P': peta, 59 'Ti': tebi, 60 'T': tera, 61 'Gi': gibi, 62 'G': giga, 63 'M': mega, 64 'ki': kibi, 65 'k': kilo, 66 'Mi': mebi, 67 'm': milli, 68 'u': micro, 69 'n': nano, 70 'p': pico, 71 'f': femto, 72 'a': atto, 73} 74 75binary_prefixes = { 76 'Ei': exbi, 77 'E' : exbi, 78 'Pi': pebi, 79 'P' : pebi, 80 'Ti': tebi, 81 'T' : tebi, 82 'Gi': gibi, 83 'G' : gibi, 84 'Mi': mebi, 85 'M' : mebi, 86 'ki': kibi, 87 'k' : kibi, 88} 89 90def assertStr(value): 91 if not isinstance(value, str): 92 raise TypeError("wrong type '%s' should be str" % type(value)) 93 94 95# memory size configuration stuff 96def toNum(value, target_type, units, prefixes, converter): 97 assertStr(value) 98 99 def convert(val): 100 try: 101 return converter(val) 102 except ValueError: 103 raise ValueError( 104 "cannot convert '%s' to %s" % (value, target_type)) 105 106 if units and not value.endswith(units): 107 units = None 108 if not units: 109 return convert(value) 110 111 value = value[:-len(units)] 112 113 prefix = next((p for p in prefixes.keys() if value.endswith(p)), None) 114 if not prefix: 115 return convert(value) 116 value = value[:-len(prefix)] 117 118 return convert(value) * prefixes[prefix] 119 120def toFloat(value, target_type='float', units=None, prefixes=[]): 121 return toNum(value, target_type, units, prefixes, float) 122 123def toMetricFloat(value, target_type='float', units=None): 124 return toFloat(value, target_type, units, metric_prefixes) 125 126def toBinaryFloat(value, target_type='float', units=None): 127 return toFloat(value, target_type, units, binary_prefixes) 128 129def toInteger(value, target_type='integer', units=None, prefixes=[]): 130 intifier = lambda x: int(x, 0) 131 return toNum(value, target_type, units, prefixes, intifier) 132 133def toMetricInteger(value, target_type='integer', units=None): 134 return toInteger(value, target_type, units, metric_prefixes) 135 136def toBinaryInteger(value, target_type='integer', units=None): 137 return toInteger(value, target_type, units, binary_prefixes) 138 139def toBool(value): 140 assertStr(value) 141 142 value = value.lower() 143 if value in ('true', 't', 'yes', 'y', '1'): 144 return True 145 if value in ('false', 'f', 'no', 'n', '0'): 146 return False 147 return result 148 149def toFrequency(value): 150 return toMetricFloat(value, 'frequency', 'Hz') 151 152def toLatency(value): 153 return toMetricFloat(value, 'latency', 's') 154 155def anyToLatency(value): 156 """result is a clock period""" 157 try: 158 return 1 / toFrequency(value) 159 except (ValueError, ZeroDivisionError): 160 pass 161 162 try: 163 return toLatency(value) 164 except ValueError: 165 pass 166 167 raise ValueError("cannot convert '%s' to clock period" % value) 168 169def anyToFrequency(value): 170 """result is a clock period""" 171 try: 172 return toFrequency(value) 173 except ValueError: 174 pass 175 176 try: 177 return 1 / toLatency(value) 178 except ValueError as ZeroDivisionError: 179 pass 180 181 raise ValueError("cannot convert '%s' to clock period" % value) 182 183def toNetworkBandwidth(value): 184 return toMetricFloat(value, 'network bandwidth', 'bps') 185 186def toMemoryBandwidth(value): 187 return toBinaryFloat(value, 'memory bandwidth', 'B/s') 188 189def toMemorySize(value): 190 return toBinaryInteger(value, 'memory size', 'B') 191 192def toIpAddress(value): 193 if not isinstance(value, str): 194 raise TypeError("wrong type '%s' should be str" % type(value)) 195 196 bytes = value.split('.') 197 if len(bytes) != 4: 198 raise ValueError('invalid ip address %s' % value) 199 200 for byte in bytes: 201 if not 0 <= int(byte) <= 0xff: 202 raise ValueError('invalid ip address %s' % value) 203 204 return (int(bytes[0]) << 24) | (int(bytes[1]) << 16) | \ 205 (int(bytes[2]) << 8) | (int(bytes[3]) << 0) 206 207def toIpNetmask(value): 208 if not isinstance(value, str): 209 raise TypeError("wrong type '%s' should be str" % type(value)) 210 211 (ip, netmask) = value.split('/') 212 ip = toIpAddress(ip) 213 netmaskParts = netmask.split('.') 214 if len(netmaskParts) == 1: 215 if not 0 <= int(netmask) <= 32: 216 raise ValueError('invalid netmask %s' % netmask) 217 return (ip, int(netmask)) 218 elif len(netmaskParts) == 4: 219 netmaskNum = toIpAddress(netmask) 220 if netmaskNum == 0: 221 return (ip, 0) 222 testVal = 0 223 for i in range(32): 224 testVal |= (1 << (31 - i)) 225 if testVal == netmaskNum: 226 return (ip, i + 1) 227 raise ValueError('invalid netmask %s' % netmask) 228 else: 229 raise ValueError('invalid netmask %s' % netmask) 230 231def toIpWithPort(value): 232 if not isinstance(value, str): 233 raise TypeError("wrong type '%s' should be str" % type(value)) 234 235 (ip, port) = value.split(':') 236 ip = toIpAddress(ip) 237 if not 0 <= int(port) <= 0xffff: 238 raise ValueError('invalid port %s' % port) 239 return (ip, int(port)) 240 241def toVoltage(value): 242 return toMetricFloat(value, 'voltage', 'V') 243 244def toCurrent(value): 245 return toMetricFloat(value, 'current', 'A') 246 247def toEnergy(value): 248 return toMetricFloat(value, 'energy', 'J') 249