Move all of the parameters of the Root SimObject so they are
directly configured by python. Move stuff from root.(cc|hh) to core.(cc|hh) since it really belogs there now. In the process, simplify how ticks are used in the python code. --HG-- extra : convert_revision : cf82ee1ea20f9343924f30bacc2a38d4edee8df3
This commit is contained in:
@@ -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,7 +139,7 @@ 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)
|
||||
|
||||
@@ -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):
|
||||
|
||||
42
src/python/m5/event.py
Normal file
42
src/python/m5/event.py
Normal file
@@ -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()
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
@@ -632,47 +633,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 +666,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 +693,12 @@ class Frequency(NumericParamValue):
|
||||
return Latency(self)
|
||||
raise AttributeError, "Frequency object has no attribute '%s'" % attr
|
||||
|
||||
# convert frequency to ticks per period
|
||||
# convert latency to ticks
|
||||
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
|
||||
|
||||
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 +709,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 +735,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 +759,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 +1017,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',
|
||||
|
||||
89
src/python/m5/ticks.py
Normal file
89
src/python/m5/ticks.py
Normal file
@@ -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' ]
|
||||
@@ -41,15 +41,23 @@
|
||||
extern const char *compileDate;
|
||||
%}
|
||||
|
||||
%include "stdint.i"
|
||||
%include "std_string.i"
|
||||
%include "sim/host.hh"
|
||||
|
||||
void setOutputDir(const std::string &dir);
|
||||
void setOutputFile(const std::string &file);
|
||||
void loadIniFile(PyObject *);
|
||||
void SimStartup();
|
||||
void doExitCleanup();
|
||||
|
||||
char *compileDate;
|
||||
|
||||
void setClockFrequency(Tick ticksPerSecond);
|
||||
|
||||
%immutable curTick;
|
||||
Tick curTick;
|
||||
|
||||
%wrapper %{
|
||||
// fix up module name to reflect the fact that it's inside the m5 package
|
||||
#undef SWIG_name
|
||||
|
||||
@@ -53,9 +53,6 @@ class CountedDrainEvent : public Event {
|
||||
CountedDrainEvent *createCountedDrain();
|
||||
void cleanupCountedDrain(Event *drain_event);
|
||||
|
||||
%immutable curTick;
|
||||
Tick curTick;
|
||||
|
||||
// minimal definition of SimExitEvent interface to wrap
|
||||
class SimLoopExitEvent {
|
||||
public:
|
||||
@@ -74,8 +71,6 @@ class SimLoopExitEvent {
|
||||
SimLoopExitEvent *simulate(Tick num_cycles = MaxTick);
|
||||
void exitSimLoop(const std::string &message, int exit_code);
|
||||
|
||||
Tick curTick;
|
||||
|
||||
%wrapper %{
|
||||
// fix up module name to reflect the fact that it's inside the m5 package
|
||||
#undef SWIG_name
|
||||
|
||||
Reference in New Issue
Block a user