diff options
Diffstat (limited to 'src/python/m5')
-rw-r--r-- | src/python/m5/__init__.py | 13 | ||||
-rw-r--r-- | src/python/m5/convert.py | 23 | ||||
-rw-r--r-- | src/python/m5/event.py | 42 | ||||
-rw-r--r-- | src/python/m5/main.py | 3 | ||||
-rw-r--r-- | src/python/m5/objects/BaseCPU.py | 4 | ||||
-rw-r--r-- | src/python/m5/objects/PhysicalMemory.py | 2 | ||||
-rw-r--r-- | src/python/m5/objects/Root.py | 7 | ||||
-rw-r--r-- | src/python/m5/params.py | 131 | ||||
-rw-r--r-- | src/python/m5/ticks.py | 89 |
9 files changed, 231 insertions, 83 deletions
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index 1c4a79020..6eac7b6d7 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -36,7 +36,7 @@ import internal # import a few SWIG-wrapped items (those that are likely to be used # directly by user scripts) completely into this module for # convenience -from internal.event import SimLoopExitEvent +import event # import the m5 compile options import defines @@ -80,7 +80,9 @@ env.update(os.environ) # The final hook to generate .ini files. Called from the user script # once the config is built. def instantiate(root): - params.ticks_per_sec = float(root.clock.frequency) + # we need to fix the global frequency + ticks.fixGlobalFrequency() + root.unproxy_all() # ugly temporary hack to get output to config.ini sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w') @@ -94,6 +96,7 @@ def instantiate(root): # Initialize the global statistics internal.stats.initSimStats() + # Create the C++ sim objects and connect ports root.createCCObject() root.connectPorts() @@ -136,11 +139,13 @@ def simulate(*args, **kwargs): # Export curTick to user script. def curTick(): - return internal.event.cvar.curTick + return internal.core.cvar.curTick + +# Python exit handlers happen in reverse order. We want to dump stats last. +atexit.register(internal.stats.dump) # register our C++ exit callback function with Python atexit.register(internal.core.doExitCleanup) -atexit.register(internal.stats.dump) # This loops until all objects have been fully drained. def doDrain(root): diff --git a/src/python/m5/convert.py b/src/python/m5/convert.py index 580a579bc..bb9e3e1f1 100644 --- a/src/python/m5/convert.py +++ b/src/python/m5/convert.py @@ -148,7 +148,7 @@ def toLatency(value): raise ValueError, "cannot convert '%s' to latency" % value -def toClockPeriod(value): +def anyToLatency(value): """result is a clock period""" if not isinstance(value, str): @@ -170,6 +170,27 @@ def toClockPeriod(value): raise ValueError, "cannot convert '%s' to clock period" % 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 + except ValueError: + pass + + try: + val = toLatency(value) + if val != 0: + val = 1 / val + return val + except ValueError: + pass + + raise ValueError, "cannot convert '%s' to clock period" % value def toNetworkBandwidth(value): if not isinstance(value, str): diff --git a/src/python/m5/event.py b/src/python/m5/event.py new file mode 100644 index 000000000..2d6497464 --- /dev/null +++ b/src/python/m5/event.py @@ -0,0 +1,42 @@ +# Copyright (c) 2006 The Regents of The University of Michigan +# 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. +# +# Authors: Nathan Binkert + +from internal.event import create +from internal.event import SimLoopExitEvent as SimExit + +class ProgressEvent(object): + def __init__(self, period): + self.period = int(period) + self.schedule() + + def schedule(self): + create(self, m5.curTick() + self.period) + + def __call__(self): + print "Progress! Time now %fs" % (m5.curTick()/1e12) + self.schedule() diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 54368b91e..1695ed75f 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -188,6 +188,7 @@ def parse_args(): def main(): import defines + import event import info import internal @@ -295,7 +296,7 @@ def main(): if options.trace_start: def enable_trace(): internal.trace.cvar.enabled = True - internal.event.create(enable_trace, int(options.trace_start)) + event.create(enable_trace, int(options.trace_start)) else: internal.trace.cvar.enabled = True diff --git a/src/python/m5/objects/BaseCPU.py b/src/python/m5/objects/BaseCPU.py index 67a28a61e..986220c3f 100644 --- a/src/python/m5/objects/BaseCPU.py +++ b/src/python/m5/objects/BaseCPU.py @@ -47,8 +47,8 @@ class BaseCPU(SimObject): defer_registration = Param.Bool(False, "defer registration with system (for sampling)") - clock = Param.Clock(Parent.clock, "clock speed") - phase = Param.Latency("0ns", "clock phase") + clock = Param.Clock('1t', "clock speed") + phase = Param.Latency('0ns', "clock phase") _mem_ports = [] diff --git a/src/python/m5/objects/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py index b8df6229e..c389e4a7f 100644 --- a/src/python/m5/objects/PhysicalMemory.py +++ b/src/python/m5/objects/PhysicalMemory.py @@ -8,7 +8,7 @@ class PhysicalMemory(MemObject): functional = Port("Functional Access Port") range = Param.AddrRange(AddrRange('128MB'), "Device Address") file = Param.String('', "memory mapped file") - latency = Param.Latency(Parent.clock, "latency of an access") + latency = Param.Latency('1t', "latency of an access") zero = Param.Bool(False, "zero initialize memory") class DRAMMemory(PhysicalMemory): diff --git a/src/python/m5/objects/Root.py b/src/python/m5/objects/Root.py index 8db4fa5a2..2b0e736e7 100644 --- a/src/python/m5/objects/Root.py +++ b/src/python/m5/objects/Root.py @@ -3,9 +3,4 @@ from m5.params import * class Root(SimObject): type = 'Root' - clock = Param.RootClock('1THz', "tick frequency") - max_tick = Param.Tick('0', "maximum simulation ticks (0 = infinite)") - progress_interval = Param.Tick('0', - "print a progress message every n ticks (0 = never)") - output_file = Param.String('cout', "file to dump simulator output to") - checkpoint = Param.String('', "checkpoint file to load") + dummy = Param.Int(0, "We don't support objects without params") diff --git a/src/python/m5/params.py b/src/python/m5/params.py index e71e1c3c5..9892df97c 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -51,6 +51,7 @@ import sys import time import convert +import ticks from util import * # Dummy base class to identify types that are legitimate for SimObject @@ -360,6 +361,7 @@ class MemorySize(CheckedInt): self._check() class MemorySize32(CheckedInt): + cxx_type = 'uint32_t' size = 32 unsigned = True def __init__(self, value): @@ -632,47 +634,29 @@ class Enum(ParamValue): def __str__(self): return self.value -ticks_per_sec = None - # how big does a rounding error need to be before we warn about it? frequency_tolerance = 0.001 # 0.1% -# convert a floting-point # of ticks to integer, and warn if rounding -# discards too much precision -def tick_check(float_ticks): - if float_ticks == 0: - return 0 - int_ticks = int(round(float_ticks)) - err = (float_ticks - int_ticks) / float_ticks - if err > frequency_tolerance: - print >> sys.stderr, "Warning: rounding error > tolerance" - print >> sys.stderr, " %f rounded to %d" % (float_ticks, int_ticks) - #raise ValueError - return int_ticks - -def getLatency(value): - if isinstance(value, Latency) or isinstance(value, Clock): - return value.value - elif isinstance(value, Frequency) or isinstance(value, RootClock): - return 1 / value.value - elif isinstance(value, str): - try: - return convert.toLatency(value) - except ValueError: - try: - return 1 / convert.toFrequency(value) - except ValueError: - pass # fall through - raise ValueError, "Invalid Frequency/Latency value '%s'" % value - - -class Latency(NumericParamValue): +class TickParamValue(NumericParamValue): cxx_type = 'Tick' cxx_predecls = ['#include "sim/host.hh"'] swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + '%import "sim/host.hh"'] + +class Latency(TickParamValue): def __init__(self, value): - self.value = getLatency(value) + if isinstance(value, (Latency, Clock)): + self.ticks = value.ticks + self.value = value.value + elif isinstance(value, Frequency): + self.ticks = value.ticks + self.value = 1.0 / value.value + elif value.endswith('t'): + self.ticks = True + self.value = int(value[:-1]) + else: + self.ticks = False + self.value = convert.toLatency(value) def __getattr__(self, attr): if attr in ('latency', 'period'): @@ -683,15 +667,25 @@ class Latency(NumericParamValue): # convert latency to ticks def ini_str(self): - return str(tick_check(self.value * ticks_per_sec)) + if self.ticks or self.value == 0: + return '%d' % self.value + else: + return '%d' % (ticks.fromSeconds(self.value)) -class Frequency(NumericParamValue): - cxx_type = 'Tick' - cxx_predecls = ['#include "sim/host.hh"'] - swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + - '%import "sim/host.hh"'] +class Frequency(TickParamValue): def __init__(self, value): - self.value = 1 / getLatency(value) + if isinstance(value, (Latency, Clock)): + if value.value == 0: + self.value = 0 + else: + self.value = 1.0 / value.value + self.ticks = value.ticks + elif isinstance(value, Frequency): + self.value = value.value + self.ticks = value.ticks + else: + self.ticks = False + self.value = convert.toFrequency(value) def __getattr__(self, attr): if attr == 'frequency': @@ -700,30 +694,12 @@ class Frequency(NumericParamValue): return Latency(self) raise AttributeError, "Frequency object has no attribute '%s'" % attr - # convert frequency to ticks per period - def ini_str(self): - return self.period.ini_str() - -# Just like Frequency, except ini_str() is absolute # of ticks per sec (Hz). -# We can't inherit from Frequency because we don't want it to be directly -# assignable to a regular Frequency parameter. -class RootClock(ParamValue): - cxx_type = 'Tick' - cxx_predecls = ['#include "sim/host.hh"'] - swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + - '%import "sim/host.hh"'] - def __init__(self, value): - self.value = 1 / getLatency(value) - - def __getattr__(self, attr): - if attr == 'frequency': - return Frequency(self) - if attr in ('latency', 'period'): - return Latency(self) - raise AttributeError, "Frequency object has no attribute '%s'" % attr - + # convert latency to ticks def ini_str(self): - return str(tick_check(self.value)) + if self.ticks or self.value == 0: + return '%d' % self.value + else: + return '%d' % (ticks.fromSeconds(1.0 / self.value)) # A generic frequency and/or Latency value. Value is stored as a latency, # but to avoid ambiguity this object does not support numeric ops (* or /). @@ -734,7 +710,18 @@ class Clock(ParamValue): swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + '%import "sim/host.hh"'] def __init__(self, value): - self.value = getLatency(value) + if isinstance(value, (Latency, Clock)): + self.ticks = value.ticks + self.value = value.value + elif isinstance(value, Frequency): + self.ticks = value.ticks + self.value = 1.0 / value.value + elif value.endswith('t'): + self.ticks = True + self.value = int(value[:-1]) + else: + self.ticks = False + self.value = convert.anyToLatency(value) def __getattr__(self, attr): if attr == 'frequency': @@ -749,18 +736,23 @@ class Clock(ParamValue): class NetworkBandwidth(float,ParamValue): cxx_type = 'float' def __new__(cls, value): - val = convert.toNetworkBandwidth(value) / 8.0 + # convert to bits per second + val = convert.toNetworkBandwidth(value) return super(cls, NetworkBandwidth).__new__(cls, val) def __str__(self): return str(self.val) def ini_str(self): - return '%f' % (ticks_per_sec / float(self)) + # convert to seconds per byte + value = 8.0 / float(self) + # convert to ticks per byte + return '%f' % (ticks.fromSeconds(value)) class MemoryBandwidth(float,ParamValue): cxx_type = 'float' def __new__(self, value): + # we want the number of ticks per byte of data val = convert.toMemoryBandwidth(value) return super(cls, MemoryBandwidth).__new__(cls, val) @@ -768,7 +760,10 @@ class MemoryBandwidth(float,ParamValue): return str(self.val) def ini_str(self): - return '%f' % (ticks_per_sec / float(self)) + # convert to seconds per byte + value = 1.0 / float(self) + # convert to ticks per byte + return '%f' % (ticks.fromSeconds(value)) # # "Constants"... handy aliases for various values. @@ -1023,7 +1018,7 @@ __all__ = ['Param', 'VectorParam', 'Counter', 'Addr', 'Tick', 'Percent', 'TcpPort', 'UdpPort', 'EthernetAddr', 'MemorySize', 'MemorySize32', - 'Latency', 'Frequency', 'RootClock', 'Clock', + 'Latency', 'Frequency', 'Clock', 'NetworkBandwidth', 'MemoryBandwidth', 'Range', 'AddrRange', 'TickRange', 'MaxAddr', 'MaxTick', 'AllMemory', diff --git a/src/python/m5/ticks.py b/src/python/m5/ticks.py new file mode 100644 index 000000000..e91b470ff --- /dev/null +++ b/src/python/m5/ticks.py @@ -0,0 +1,89 @@ +# Copyright (c) 2007 The Regents of The University of Michigan +# 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. +# +# Authors: Nathan Binkert + +import sys + +import convert +import internal + +tps = 1.0e12 # default to 1 THz (1 Tick == 1 ps) +tps_fixed = False # once set to true, can't be changed + +# fix the global frequency and tell C++ about it +def fixGlobalFrequency(): + global tps, tps_fixed + if not tps_fixed: + tps_fixed = True + internal.core.setClockFrequency(int(tps)) + print "Global frequency set at %d ticks per second" % int(tps) + +def setGlobalFrequency(ticksPerSecond): + global tps, tps_fixed + + if tps_fixed: + raise AttributeError, \ + "Global frequency already fixed at %f ticks/s." % tps + + if isinstance(ticksPerSecond, (int, long)): + tps = ticksPerSecond + elif isinstance(ticksPerSecond, float): + tps = ticksPerSecond + elif isinstance(ticksPerSecond, str): + tps = round(convert.anyToFrequency(ticksPerSecond)) + else: + raise TypeError, \ + "wrong type '%s' for ticksPerSecond" % type(ticksPerSecond) + +# how big does a rounding error need to be before we warn about it? +frequency_tolerance = 0.001 # 0.1% + +def fromSeconds(value): + if not isinstance(value, float): + raise TypeError, "can't convert '%s' to type tick" % type(value) + + # once someone needs to convert to seconds, the global frequency + # had better be fixed + if not tps_fixed: + raise AttributeError, \ + "In order to do conversions, the global frequency must be fixed" + + if value == 0: + return 0 + + # convert the value from time to ticks + value *= tps + + int_value = int(round(value)) + err = (value - int_value) / value + if err > frequency_tolerance: + print >>sys.stderr, "Warning: rounding error > tolerance" + print >>sys.stderr, " %f rounded to %d" % (value, int_value) + return int_value + +__all__ = [ 'setGlobalFrequency', 'fixGlobalFrequency', 'fromSeconds', + 'frequency_tolerance' ] |