From 0a67a7a7ce42fd1af0f5013b9723126e18f45378 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 10 Nov 2017 02:04:00 -0800 Subject: util: Simplify/consolidate the python conversion module. The python conversion module was really repetitive and fragmented, where some types of conversions use common code, and some use hand written case statements which did something very similar. Also, some types like Voltage could only handle V and mV but no other scaling prefix. This change restructures the module to centralize a lot of the unit handling code into toFloat, and makes the various other functions use it. Change-Id: Ic8529203cc226c9b551b8535a444e3f2f25ad1eb Reviewed-on: https://gem5-review.googlesource.com/5621 Reviewed-by: Jason Lowe-Power Reviewed-by: Andreas Sandberg Maintainer: Andreas Sandberg --- src/python/m5/util/convert.py | 283 +++++++++++++++--------------------------- 1 file changed, 103 insertions(+), 180 deletions(-) diff --git a/src/python/m5/util/convert.py b/src/python/m5/util/convert.py index 351ee1ee0..cffa1bb49 100644 --- a/src/python/m5/util/convert.py +++ b/src/python/m5/util/convert.py @@ -29,19 +29,19 @@ # Gabe Black # metric prefixes -exa = 1.0e18 -peta = 1.0e15 -tera = 1.0e12 -giga = 1.0e9 -mega = 1.0e6 -kilo = 1.0e3 - -milli = 1.0e-3 -micro = 1.0e-6 -nano = 1.0e-9 -pico = 1.0e-12 -femto = 1.0e-15 atto = 1.0e-18 +femto = 1.0e-15 +pico = 1.0e-12 +nano = 1.0e-9 +micro = 1.0e-6 +milli = 1.0e-3 + +kilo = 1.0e3 +mega = 1.0e6 +giga = 1.0e9 +tera = 1.0e12 +peta = 1.0e15 +exa = 1.0e18 # power of 2 prefixes kibi = 1024 @@ -51,122 +51,115 @@ tebi = gibi * 1024 pebi = tebi * 1024 exbi = pebi * 1024 -# memory size configuration stuff -def toFloat(value): +metric_prefixes = { + 'Ei': exbi, + 'E': exa, + 'Pi': pebi, + 'P': peta, + 'Ti': tebi, + 'T': tera, + 'Gi': gibi, + 'G': giga, + 'M': mega, + 'ki': kibi, + 'k': kilo, + 'Mi': mebi, + 'm': milli, + 'u': micro, + 'n': nano, + 'p': pico, + 'f': femto, + 'a': atto, +} + +binary_prefixes = { + 'Ei': exbi, + 'E' : exbi, + 'Pi': pebi, + 'P' : pebi, + 'Ti': tebi, + 'T' : tebi, + 'Gi': gibi, + 'G' : gibi, + 'Mi': mebi, + 'M' : mebi, + 'ki': kibi, + 'k' : kibi, +} + +def assertStr(value): if not isinstance(value, str): raise TypeError, "wrong type '%s' should be str" % type(value) - if value.endswith('Ei'): - return float(value[:-2]) * exbi - elif value.endswith('Pi'): - return float(value[:-2]) * pebi - elif value.endswith('Ti'): - return float(value[:-2]) * tebi - elif value.endswith('Gi'): - return float(value[:-2]) * gibi - elif value.endswith('Mi'): - return float(value[:-2]) * mebi - elif value.endswith('ki'): - return float(value[:-2]) * kibi - elif value.endswith('E'): - return float(value[:-1]) * exa - elif value.endswith('P'): - return float(value[:-1]) * peta - elif value.endswith('T'): - return float(value[:-1]) * tera - elif value.endswith('G'): - return float(value[:-1]) * giga - elif value.endswith('M'): - return float(value[:-1]) * mega - elif value.endswith('k'): - return float(value[:-1]) * kilo - elif value.endswith('m'): - return float(value[:-1]) * milli - elif value.endswith('u'): - return float(value[:-1]) * micro - elif value.endswith('n'): - return float(value[:-1]) * nano - elif value.endswith('p'): - return float(value[:-1]) * pico - elif value.endswith('f'): - return float(value[:-1]) * femto - else: + +# memory size configuration stuff +def toFloat(value, target_type='float', units=None, prefixes=[]): + assertStr(value) + + if units and not value.endswith(units): + units = None + if not units: + try: + return float(value) + except ValueError: + raise ValueError, "cannot convert '%s' to %s" % \ + (value, target_type) + + value = value[:-len(units)] + + prefix = next((p for p in prefixes.keys() if value.endswith(p)), None) + if not prefix: return float(value) + value = value[:-len(prefix)] + + return float(value) * prefixes[prefix] + +def toMetricFloat(value, target_type='float', units=None): + return toFloat(value, target_type, units, metric_prefixes) -def toInteger(value): - value = toFloat(value) +def toBinaryFloat(value, target_type='float', units=None): + return toFloat(value, target_type, units, binary_prefixes) + +def toInteger(value, target_type='integer', units=None, prefixes=[]): + value = toFloat(value, target_type, units, prefixes) result = long(value) if value != result: - raise ValueError, "cannot convert '%s' to integer" % value + raise ValueError, "cannot convert '%s' to integer %s" % \ + (value, target_type) return result -_bool_dict = { - 'true' : True, 't' : True, 'yes' : True, 'y' : True, '1' : True, - 'false' : False, 'f' : False, 'no' : False, 'n' : False, '0' : False - } +def toMetricInteger(value, target_type='integer', units=None): + return toInteger(value, target_type, units, metric_prefixes) + +def toBinaryInteger(value, target_type='integer', units=None): + return toInteger(value, target_type, units, binary_prefixes) def toBool(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) + assertStr(value) value = value.lower() - result = _bool_dict.get(value, None) - if result == None: - raise ValueError, "cannot convert '%s' to bool" % value + if value in ('true', 't', 'yes', 'y', '1'): + return True + if value in ('false', 'f', 'no', 'n', '0'): + return False return result def toFrequency(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('THz'): - return float(value[:-3]) * tera - elif value.endswith('GHz'): - return float(value[:-3]) * giga - elif value.endswith('MHz'): - return float(value[:-3]) * mega - elif value.endswith('kHz'): - return float(value[:-3]) * kilo - elif value.endswith('Hz'): - return float(value[:-2]) - - raise ValueError, "cannot convert '%s' to frequency" % value + return toMetricFloat(value, 'frequency', 'Hz') def toLatency(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('ps'): - return float(value[:-2]) * pico - elif value.endswith('ns'): - return float(value[:-2]) * nano - elif value.endswith('us'): - return float(value[:-2]) * micro - elif value.endswith('ms'): - return float(value[:-2]) * milli - elif value.endswith('s'): - return float(value[:-1]) - - raise ValueError, "cannot convert '%s' to latency" % value + return toMetricFloat(value, 'latency', 's') def anyToLatency(value): """result is a clock period""" - - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - try: - val = toFrequency(value) - if val != 0: - val = 1 / val - return val - except ValueError: + return 1 / toFrequency(value) + except ValueError, ZeroDivisionError: pass try: - val = toLatency(value) - return val + return toLatency(value) except ValueError: pass @@ -174,82 +167,26 @@ def anyToLatency(value): def anyToFrequency(value): """result is a clock period""" - - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - try: - val = toFrequency(value) - return val + return toFrequency(value) except ValueError: pass try: - val = toLatency(value) - if val != 0: - val = 1 / val - return val - except ValueError: + return 1 / toLatency(value) + except ValueError, ZeroDivisionError: pass raise ValueError, "cannot convert '%s' to clock period" % value def toNetworkBandwidth(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('Tbps'): - return float(value[:-4]) * tera - elif value.endswith('Gbps'): - return float(value[:-4]) * giga - elif value.endswith('Mbps'): - return float(value[:-4]) * mega - elif value.endswith('kbps'): - return float(value[:-4]) * kilo - elif value.endswith('bps'): - return float(value[:-3]) - else: - return float(value) - - raise ValueError, "cannot convert '%s' to network bandwidth" % value + return toMetricFloat(value, 'network bandwidth', 'bps') def toMemoryBandwidth(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('PB/s'): - return float(value[:-4]) * pebi - elif value.endswith('TB/s'): - return float(value[:-4]) * tebi - elif value.endswith('GB/s'): - return float(value[:-4]) * gibi - elif value.endswith('MB/s'): - return float(value[:-4]) * mebi - elif value.endswith('kB/s'): - return float(value[:-4]) * kibi - elif value.endswith('B/s'): - return float(value[:-3]) - - raise ValueError, "cannot convert '%s' to memory bandwidth" % value + return toBinaryFloat(value, 'memory bandwidth', 'B/s') def toMemorySize(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('PB'): - return long(value[:-2]) * pebi - elif value.endswith('TB'): - return long(value[:-2]) * tebi - elif value.endswith('GB'): - return long(value[:-2]) * gibi - elif value.endswith('MB'): - return long(value[:-2]) * mebi - elif value.endswith('kB'): - return long(value[:-2]) * kibi - elif value.endswith('B'): - return long(value[:-1]) - - raise ValueError, "cannot convert '%s' to memory size" % value + return toBinaryInteger(value, 'memory size', 'B') def toIpAddress(value): if not isinstance(value, str): @@ -301,21 +238,7 @@ def toIpWithPort(value): return (ip, int(port)) def toVoltage(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('mV'): - return float(value[:-2]) * milli - elif value.endswith('V'): - return float(value[:-1]) - - raise ValueError, "cannot convert '%s' to voltage" % value + return toMetricFloat(value, 'voltage', 'V') def toCurrent(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('A'): - return toFloat(value[:-1]) - - raise ValueError, "cannot convert '%s' to current" % value + return toMetricFloat(value, 'current', 'A') -- cgit v1.2.3