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 <jason@lowepower.com>
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Gabe Black
2017-11-10 02:04:00 -08:00
parent 49cf9fded0
commit 0a67a7a7ce

View File

@@ -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:
return float(value)
def toInteger(value):
value = toFloat(value)
# 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 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')