python: Apply Black formatter to Python files

The command executed was `black src configs tests util`.

Change-Id: I8dfaa6ab04658fea37618127d6ac19270028d771
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/47024
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Bobby R. Bruce
2022-07-05 11:02:25 -07:00
committed by Giacomo Travaglini
parent 1cfaa8da83
commit 787204c92d
980 changed files with 35668 additions and 22233 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -46,7 +46,8 @@ if in_gem5:
from . import objects
from . import params
from . import stats
if defines.buildEnv['USE_SYSTEMC']:
if defines.buildEnv["USE_SYSTEMC"]:
from . import systemc
from . import tlm
from . import util
@@ -54,4 +55,3 @@ if in_gem5:
from .event import *
from .main import main
from .simulate import *

View File

@@ -31,30 +31,37 @@ from _m5.debug import SimpleFlag, CompoundFlag
from _m5.debug import schedBreak, setRemoteGDBPort
from m5.util import printList
def help():
sorted_flags = sorted(flags.items(), key=lambda kv: kv[0])
print("Base Flags:")
for name, flag in filter(lambda kv: isinstance(kv[1], SimpleFlag)
and not kv[1].isFormat, sorted_flags):
for name, flag in filter(
lambda kv: isinstance(kv[1], SimpleFlag) and not kv[1].isFormat,
sorted_flags,
):
print(" %s: %s" % (name, flag.desc))
print()
print("Compound Flags:")
for name, flag in filter(lambda kv: isinstance(kv[1], CompoundFlag),
sorted_flags):
for name, flag in filter(
lambda kv: isinstance(kv[1], CompoundFlag), sorted_flags
):
print(" %s: %s" % (name, flag.desc))
# The list of kids for flag "All" is too long, so it is not printed
if name != "All":
printList([ c.name for c in flag.kids() ], indent=8)
printList([c.name for c in flag.kids()], indent=8)
else:
print(" All Base Flags")
print()
print("Formatting Flags:")
for name, flag in filter(lambda kv: isinstance(kv[1], SimpleFlag)
and kv[1].isFormat, sorted_flags):
for name, flag in filter(
lambda kv: isinstance(kv[1], SimpleFlag) and kv[1].isFormat,
sorted_flags,
):
print(" %s: %s" % (name, flag.desc))
print()
class AllFlags(Mapping):
def __init__(self):
self._version = -1
@@ -98,4 +105,5 @@ class AllFlags(Mapping):
self._update()
return self._dict.items()
flags = AllFlags()

View File

@@ -47,6 +47,7 @@ from _m5.event import getEventQueue, setEventQueue
mainq = None
class EventWrapper(Event):
"""Helper class to wrap callable objects in an Event base class"""
@@ -54,8 +55,9 @@ class EventWrapper(Event):
super().__init__(**kwargs)
if not callable(func):
raise RuntimeError("Can't wrap '%s', object is not callable" % \
str(func))
raise RuntimeError(
"Can't wrap '%s', object is not callable" % str(func)
)
self._func = func
@@ -63,7 +65,7 @@ class EventWrapper(Event):
self._func()
def __str__(self):
return "EventWrapper(%s)" % (str(self._func), )
return "EventWrapper(%s)" % (str(self._func),)
class ProgressEvent(Event):
@@ -74,7 +76,7 @@ class ProgressEvent(Event):
self.eventq.schedule(self, m5.curTick() + self.period)
def __call__(self):
print("Progress! Time now %fs" % (m5.curTick()/1e12))
print("Progress! Time now %fs" % (m5.curTick() / 1e12))
self.eventq.schedule(self, m5.curTick() + self.period)
@@ -83,5 +85,12 @@ def create(func, priority=Event.Default_Pri):
return EventWrapper(func, priority=priority)
__all__ = [ 'Event', 'EventWrapper', 'ProgressEvent', 'SimExit',
'mainq', 'create' ]
__all__ = [
"Event",
"EventWrapper",
"ProgressEvent",
"SimExit",
"mainq",
"create",
]

View File

@@ -34,4 +34,3 @@
# 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.

File diff suppressed because it is too large Load Diff

View File

@@ -33,11 +33,11 @@ from .timeconversion import TimeConversion
from .jsonloader import JsonLoader
__all__ = [
"Group",
"SimStat",
"Statistic",
"TimeConversion",
"StorageType",
"JsonSerializable",
"JsonLoader",
]
"Group",
"SimStat",
"Statistic",
"TimeConversion",
"StorageType",
"JsonSerializable",
"JsonLoader",
]

View File

@@ -25,13 +25,22 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import re
from typing import Callable, Dict, Iterator, List, Mapping, Optional, Pattern,\
Union
from typing import (
Callable,
Dict,
Iterator,
List,
Mapping,
Optional,
Pattern,
Union,
)
from .jsonserializable import JsonSerializable
from .statistic import Scalar, Statistic
from .timeconversion import TimeConversion
class Group(JsonSerializable):
"""
Used to create the heirarchical stats structure. A Group object contains a
@@ -41,10 +50,14 @@ class Group(JsonSerializable):
type: Optional[str]
time_conversion: Optional[TimeConversion]
def __init__(self, type: Optional[str] = None,
time_conversion: Optional[TimeConversion] = None,
**kwargs: Dict[str, Union["Group",Statistic,List["Group"],
List["Statistic"]]]):
def __init__(
self,
type: Optional[str] = None,
time_conversion: Optional[TimeConversion] = None,
**kwargs: Dict[
str, Union["Group", Statistic, List["Group"], List["Statistic"]]
]
):
if type is None:
self.type = "Group"
else:
@@ -52,11 +65,12 @@ class Group(JsonSerializable):
self.time_conversion = time_conversion
for key,value in kwargs.items():
for key, value in kwargs.items():
setattr(self, key, value)
def children(self, predicate: Optional[Callable[[str], bool]] = None
) -> Iterator[Union["Group", Statistic]]:
def children(
self, predicate: Optional[Callable[[str], bool]] = None
) -> Iterator[Union["Group", Statistic]]:
""" Iterate through all of the children, optionally with a predicate
```
@@ -71,7 +85,8 @@ class Group(JsonSerializable):
"""
for attr in self.__dict__:
# Check the provided predicate. If not a match, skip this child
if predicate and not predicate(attr): continue
if predicate and not predicate(attr):
continue
obj = getattr(self, attr)
if isinstance(obj, Group) or isinstance(obj, Statistic):
yield obj
@@ -100,8 +115,9 @@ class Group(JsonSerializable):
"""
yield from self.children(lambda _name: _name in name)
def find_re(self, regex: Union[str, Pattern]
) -> Iterator[Union["Group", Statistic]]:
def find_re(
self, regex: Union[str, Pattern]
) -> Iterator[Union["Group", Statistic]]:
""" Find all stats that match the name
This function searches all of the "children" in this group. It yields
@@ -124,6 +140,7 @@ class Group(JsonSerializable):
pattern = regex
yield from self.children(lambda _name: bool(pattern.search(_name)))
class Vector(Group):
"""
The Vector class is used to store vector information. However, in gem5
@@ -132,5 +149,6 @@ class Vector(Group):
accordance to decisions made in relation to
https://gem5.atlassian.net/browse/GEM5-867.
"""
def __init__(self, scalar_map: Mapping[str,Scalar]):
def __init__(self, scalar_map: Mapping[str, Scalar]):
super().__init__(type="Vector", time_conversion=None, **scalar_map)

View File

@@ -31,6 +31,7 @@ from .group import Group, Vector
import json
from typing import IO, Union
class JsonLoader(json.JSONDecoder):
"""
Subclass of JSONDecoder that overrides 'object_hook'. Converts JSON object
@@ -49,26 +50,26 @@ class JsonLoader(json.JSONDecoder):
def __init__(self):
super().__init__(self, object_hook=self.__json_to_simstat)
def __json_to_simstat(self, d: dict) -> Union[SimStat,Statistic,Group]:
if 'type' in d:
if d['type'] == 'Scalar':
d.pop('type', None)
def __json_to_simstat(self, d: dict) -> Union[SimStat, Statistic, Group]:
if "type" in d:
if d["type"] == "Scalar":
d.pop("type", None)
return Scalar(**d)
elif d['type'] == 'Distribution':
d.pop('type', None)
elif d["type"] == "Distribution":
d.pop("type", None)
return Distribution(**d)
elif d['type'] == 'Accumulator':
d.pop('type', None)
elif d["type"] == "Accumulator":
d.pop("type", None)
return Accumulator(**d)
elif d['type'] == 'Group':
elif d["type"] == "Group":
return Group(**d)
elif d['type'] == 'Vector':
d.pop('type', None)
d.pop('time_conversion', None)
elif d["type"] == "Vector":
d.pop("type", None)
d.pop("time_conversion", None)
return Vector(d)
else:
@@ -78,6 +79,7 @@ class JsonLoader(json.JSONDecoder):
else:
return SimStat(**d)
def load(json_file: IO) -> SimStat:
"""
Wrapper function that provides a cleaner interface for using the
@@ -95,4 +97,3 @@ def load(json_file: IO) -> SimStat:
simstat_object = json.load(json_file, cls=JsonLoader)
return simstat_object

View File

@@ -30,6 +30,7 @@ from typing import Dict, List, Union, Any, IO
from .storagetype import StorageType
class JsonSerializable:
"""
Classes which inherit from JsonSerializable can be translated into JSON
@@ -61,8 +62,9 @@ class JsonSerializable:
model_dct[key] = new_value
return model_dct
def __process_json_value(self,
value: Any) -> Union[str,int,float,Dict,List,None]:
def __process_json_value(
self, value: Any
) -> Union[str, int, float, Dict, List, None]:
"""
Translate values into a value which can be handled by the Python stdlib
JSON package.
@@ -91,7 +93,6 @@ class JsonSerializable:
return None
def dumps(self, **kwargs) -> str:
"""
This function mirrors the Python stdlib JSON module method
@@ -126,8 +127,8 @@ class JsonSerializable:
"""
# Setting the default indentation to something readable.
if 'indent' not in kwargs:
kwargs['indent'] = 4
if "indent" not in kwargs:
kwargs["indent"] = 4
return json.dumps(obj=self.to_json(), **kwargs)
@@ -161,7 +162,7 @@ class JsonSerializable:
"""
# Setting the default indentation to something readable.
if 'indent' not in kwargs:
kwargs['indent'] = 4
if "indent" not in kwargs:
kwargs["indent"] = 4
json.dump(obj=self.to_json(), fp=fp, **kwargs)
json.dump(obj=self.to_json(), fp=fp, **kwargs)

View File

@@ -32,6 +32,7 @@ from .group import Group
from .statistic import Statistic
from .timeconversion import TimeConversion
class SimStat(JsonSerializable):
"""
Contains all the statistics for a given simulation.
@@ -42,15 +43,18 @@ class SimStat(JsonSerializable):
simulated_begin_time: Optional[Union[int, float]]
simulated_end_time: Optional[Union[int, float]]
def __init__(self, creation_time: Optional[datetime] = None,
time_conversion: Optional[TimeConversion] = None,
simulated_begin_time: Optional[Union[int, float]] = None,
simulated_end_time: Optional[Union[int, float]] = None,
**kwargs: Dict[str, Union[Group,Statistic,List[Group]]]):
def __init__(
self,
creation_time: Optional[datetime] = None,
time_conversion: Optional[TimeConversion] = None,
simulated_begin_time: Optional[Union[int, float]] = None,
simulated_end_time: Optional[Union[int, float]] = None,
**kwargs: Dict[str, Union[Group, Statistic, List[Group]]]
):
self.creation_time = creation_time
self.time_conversion = time_conversion
self.simulated_begin_time = simulated_begin_time
self.simulated_end_time = simulated_end_time
for key,value in kwargs.items():
setattr(self, key, value)
for key, value in kwargs.items():
setattr(self, key, value)

View File

@@ -30,6 +30,7 @@ from typing import Any, Iterable, Optional, Union, List
from .jsonserializable import JsonSerializable
from .storagetype import StorageType
class Statistic(ABC, JsonSerializable):
"""
The abstract base class for all Python statistics.
@@ -41,16 +42,21 @@ class Statistic(ABC, JsonSerializable):
description: Optional[str]
datatype: Optional[StorageType]
def __init__(self, value: Any, type: Optional[str] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None):
def __init__(
self,
value: Any,
type: Optional[str] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None,
):
self.value = value
self.type = type
self.unit = unit
self.description = description
self.datatype = datatype
class Scalar(Statistic):
"""
A scalar Python statistic type.
@@ -58,26 +64,44 @@ class Scalar(Statistic):
value: Union[float, int]
def __init__(self, value: Any,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None):
super().__init__(value=value, type="Scalar", unit=unit,
description=description, datatype=datatype)
def __init__(
self,
value: Any,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None,
):
super().__init__(
value=value,
type="Scalar",
unit=unit,
description=description,
datatype=datatype,
)
class BaseScalarVector(Statistic):
"""
An abstract base class for classes containing a vector of Scalar values.
"""
value: List[Union[int,float]]
def __init__(self, value: Iterable[Union[int,float]],
type: Optional[str] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None):
super().__init__(value=list(value), type=type, unit=unit,
description=description, datatype=datatype)
value: List[Union[int, float]]
def __init__(
self,
value: Iterable[Union[int, float]],
type: Optional[str] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None,
):
super().__init__(
value=list(value),
type=type,
unit=unit,
description=description,
datatype=datatype,
)
def mean(self) -> float:
"""
@@ -88,10 +112,11 @@ class BaseScalarVector(Statistic):
float
The mean value across all bins.
"""
assert(self.value != None)
assert(isinstance(self.value, List))
assert self.value != None
assert isinstance(self.value, List)
from statistics import mean as statistics_mean
return statistics_mean(self.value)
def count(self) -> float:
@@ -103,7 +128,7 @@ class BaseScalarVector(Statistic):
float
The sum of all bin values.
"""
assert(self.value != None)
assert self.value != None
return sum(self.value)
@@ -127,21 +152,29 @@ class Distribution(BaseScalarVector):
overflow: Optional[int]
logs: Optional[float]
def __init__(self, value: Iterable[int],
min: Union[float, int],
max: Union[float, int],
num_bins: int,
bin_size: Union[float, int],
sum: Optional[int] = None,
sum_squared: Optional[int] = None,
underflow: Optional[int] = None,
overflow: Optional[int] = None,
logs: Optional[float] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None):
super().__init__(value=value, type="Distribution", unit=unit,
description=description, datatype=datatype)
def __init__(
self,
value: Iterable[int],
min: Union[float, int],
max: Union[float, int],
num_bins: int,
bin_size: Union[float, int],
sum: Optional[int] = None,
sum_squared: Optional[int] = None,
underflow: Optional[int] = None,
overflow: Optional[int] = None,
logs: Optional[float] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None,
):
super().__init__(
value=value,
type="Distribution",
unit=unit,
description=description,
datatype=datatype,
)
self.min = min
self.max = max
@@ -154,8 +187,9 @@ class Distribution(BaseScalarVector):
self.sum_squared = sum_squared
# These check some basic conditions of a distribution.
assert(self.bin_size >= 0)
assert(self.num_bins >= 1)
assert self.bin_size >= 0
assert self.num_bins >= 1
class Accumulator(BaseScalarVector):
"""
@@ -167,16 +201,24 @@ class Accumulator(BaseScalarVector):
max: Union[int, float]
sum_squared: Optional[int]
def __init__(self, value: Iterable[Union[int,float]],
count: int,
min: Union[int, float],
max: Union[int, float],
sum_squared: Optional[int] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None):
super().__init__(value=value, type="Accumulator", unit=unit,
description=description, datatype=datatype)
def __init__(
self,
value: Iterable[Union[int, float]],
count: int,
min: Union[int, float],
max: Union[int, float],
sum_squared: Optional[int] = None,
unit: Optional[str] = None,
description: Optional[str] = None,
datatype: Optional[StorageType] = None,
):
super().__init__(
value=value,
type="Accumulator",
unit=unit,
description=description,
datatype=datatype,
)
self._count = count
self.min = min

View File

@@ -27,6 +27,7 @@
from enum import Enum
from typing import Dict
class StorageType(Enum):
"""
An enum used to declare what C++ data type was used to store a value.
@@ -34,9 +35,10 @@ class StorageType(Enum):
E.g. 's64' indicates a 64 bit signed integer
"""
u32: str = "u32"
u64: str = "u64"
s32: str = "s32"
s64: str = "s64"
f32: str = "f32"
f64: str = "f64"
f64: str = "f64"

View File

@@ -26,14 +26,16 @@
from typing import Optional
class TimeConversion:
"""
A class for specifying a scale factor necessary to translate a simulation
time measurement (e.g. ticks) into seconds.
"""
scale_factor: float
description: Optional[str]
def __init__(self, scale_factor: float, description: Optional[str] = None):
self.scale_factor = scale_factor
self.description = description
self.description = description

View File

@@ -40,5 +40,5 @@ import inspect
import _m5
for name, module in inspect.getmembers(_m5):
if name.startswith('param_') or name.startswith('enum_'):
if name.startswith("param_") or name.startswith("enum_"):
exec("from _m5.%s import *" % name)

View File

@@ -42,14 +42,17 @@ import os
import socket
import sys
__all__ = [ 'options', 'arguments', 'main' ]
__all__ = ["options", "arguments", "main"]
usage="%prog [gem5 options] script.py [script options]"
brief_copyright=\
usage = "%prog [gem5 options] script.py [script options]"
brief_copyright = (
"gem5 is copyrighted software; use the --copyright option for details."
)
def _stats_help(option, opt, value, parser):
import m5
print("A stat file can either be specified as a URI or a plain")
print("path. When specified as a path, gem5 uses the default text ")
print("format.")
@@ -67,95 +70,220 @@ def parse_options():
option = options.add_option
group = options.set_group
listener_modes = ( "on", "off", "auto" )
listener_modes = ("on", "off", "auto")
# Help options
option('-B', "--build-info", action="store_true", default=False,
help="Show build information")
option('-C', "--copyright", action="store_true", default=False,
help="Show full copyright information")
option('-R', "--readme", action="store_true", default=False,
help="Show the readme")
option(
"-B",
"--build-info",
action="store_true",
default=False,
help="Show build information",
)
option(
"-C",
"--copyright",
action="store_true",
default=False,
help="Show full copyright information",
)
option(
"-R",
"--readme",
action="store_true",
default=False,
help="Show the readme",
)
# Options for configuring the base simulator
option('-d', "--outdir", metavar="DIR", default="m5out",
help="Set the output directory to DIR [Default: %default]")
option('-r', "--redirect-stdout", action="store_true", default=False,
help="Redirect stdout (& stderr, without -e) to file")
option('-e', "--redirect-stderr", action="store_true", default=False,
help="Redirect stderr to file")
option("--silent-redirect", action="store_true", default=False,
help="Suppress printing a message when redirecting stdout or stderr")
option("--stdout-file", metavar="FILE", default="simout",
help="Filename for -r redirection [Default: %default]")
option("--stderr-file", metavar="FILE", default="simerr",
help="Filename for -e redirection [Default: %default]")
option("--listener-mode", metavar="{on,off,auto}",
choices=listener_modes, default="auto",
help="Port (e.g., gdb) listener mode (auto: Enable if running " \
"interactively) [Default: %default]")
option("--allow-remote-connections", action="store_true", default=False,
option(
"-d",
"--outdir",
metavar="DIR",
default="m5out",
help="Set the output directory to DIR [Default: %default]",
)
option(
"-r",
"--redirect-stdout",
action="store_true",
default=False,
help="Redirect stdout (& stderr, without -e) to file",
)
option(
"-e",
"--redirect-stderr",
action="store_true",
default=False,
help="Redirect stderr to file",
)
option(
"--silent-redirect",
action="store_true",
default=False,
help="Suppress printing a message when redirecting stdout or stderr",
)
option(
"--stdout-file",
metavar="FILE",
default="simout",
help="Filename for -r redirection [Default: %default]",
)
option(
"--stderr-file",
metavar="FILE",
default="simerr",
help="Filename for -e redirection [Default: %default]",
)
option(
"--listener-mode",
metavar="{on,off,auto}",
choices=listener_modes,
default="auto",
help="Port (e.g., gdb) listener mode (auto: Enable if running "
"interactively) [Default: %default]",
)
option(
"--allow-remote-connections",
action="store_true",
default=False,
help="Port listeners will accept connections from anywhere (0.0.0.0). "
"Default is only localhost.")
option('-i', "--interactive", action="store_true", default=False,
help="Invoke the interactive interpreter after running the script")
option("--pdb", action="store_true", default=False,
help="Invoke the python debugger before running the script")
option('-p', "--path", metavar="PATH[:PATH]", action='append', split=':',
help="Prepend PATH to the system path when invoking the script")
option('-q', "--quiet", action="count", default=0,
help="Reduce verbosity")
option('-v', "--verbose", action="count", default=0,
help="Increase verbosity")
"Default is only localhost.",
)
option(
"-i",
"--interactive",
action="store_true",
default=False,
help="Invoke the interactive interpreter after running the script",
)
option(
"--pdb",
action="store_true",
default=False,
help="Invoke the python debugger before running the script",
)
option(
"-p",
"--path",
metavar="PATH[:PATH]",
action="append",
split=":",
help="Prepend PATH to the system path when invoking the script",
)
option("-q", "--quiet", action="count", default=0, help="Reduce verbosity")
option(
"-v", "--verbose", action="count", default=0, help="Increase verbosity"
)
# Statistics options
group("Statistics Options")
option("--stats-file", metavar="FILE", default="stats.txt",
help="Sets the output file for statistics [Default: %default]")
option("--stats-help",
action="callback", callback=_stats_help,
help="Display documentation for available stat visitors")
option(
"--stats-file",
metavar="FILE",
default="stats.txt",
help="Sets the output file for statistics [Default: %default]",
)
option(
"--stats-help",
action="callback",
callback=_stats_help,
help="Display documentation for available stat visitors",
)
# Configuration Options
group("Configuration Options")
option("--dump-config", metavar="FILE", default="config.ini",
help="Dump configuration output file [Default: %default]")
option("--json-config", metavar="FILE", default="config.json",
help="Create JSON output of the configuration [Default: %default]")
option("--dot-config", metavar="FILE", default="config.dot",
help="Create DOT & pdf outputs of the configuration [Default: %default]")
option("--dot-dvfs-config", metavar="FILE", default=None,
help="Create DOT & pdf outputs of the DVFS configuration" + \
" [Default: %default]")
option(
"--dump-config",
metavar="FILE",
default="config.ini",
help="Dump configuration output file [Default: %default]",
)
option(
"--json-config",
metavar="FILE",
default="config.json",
help="Create JSON output of the configuration [Default: %default]",
)
option(
"--dot-config",
metavar="FILE",
default="config.dot",
help="Create DOT & pdf outputs of the configuration [Default: %default]",
)
option(
"--dot-dvfs-config",
metavar="FILE",
default=None,
help="Create DOT & pdf outputs of the DVFS configuration"
+ " [Default: %default]",
)
# Debugging options
group("Debugging Options")
option("--debug-break", metavar="TICK[,TICK]", action='append', split=',',
help="Create breakpoint(s) at TICK(s) " \
"(kills process if no debugger attached)")
option("--debug-help", action='store_true',
help="Print help on debug flags")
option("--debug-flags", metavar="FLAG[,FLAG]", action='append', split=',',
help="Sets the flags for debug output (-FLAG disables a flag)")
option("--debug-start", metavar="TICK", type='int',
help="Start debug output at TICK")
option("--debug-end", metavar="TICK", type='int',
help="End debug output at TICK")
option("--debug-file", metavar="FILE", default="cout",
option(
"--debug-break",
metavar="TICK[,TICK]",
action="append",
split=",",
help="Create breakpoint(s) at TICK(s) "
"(kills process if no debugger attached)",
)
option(
"--debug-help", action="store_true", help="Print help on debug flags"
)
option(
"--debug-flags",
metavar="FLAG[,FLAG]",
action="append",
split=",",
help="Sets the flags for debug output (-FLAG disables a flag)",
)
option(
"--debug-start",
metavar="TICK",
type="int",
help="Start debug output at TICK",
)
option(
"--debug-end",
metavar="TICK",
type="int",
help="End debug output at TICK",
)
option(
"--debug-file",
metavar="FILE",
default="cout",
help="Sets the output file for debug. Append '.gz' to the name for it"
" to be compressed automatically [Default: %default]")
option("--debug-ignore", metavar="EXPR", action='append', split=':',
help="Ignore EXPR sim objects")
option("--remote-gdb-port", type='int', default=7000,
help="Remote gdb base port (set to 0 to disable listening)")
" to be compressed automatically [Default: %default]",
)
option(
"--debug-ignore",
metavar="EXPR",
action="append",
split=":",
help="Ignore EXPR sim objects",
)
option(
"--remote-gdb-port",
type="int",
default=7000,
help="Remote gdb base port (set to 0 to disable listening)",
)
# Help options
group("Help Options")
option("--list-sim-objects", action='store_true', default=False,
help="List all built-in SimObjects, their params and default values")
option(
"--list-sim-objects",
action="store_true",
default=False,
help="List all built-in SimObjects, their params and default values",
)
arguments = options.parse_args()
return options,arguments
return options, arguments
def interact(scope):
banner = "gem5 Interactive Console"
@@ -172,8 +300,9 @@ def interact(scope):
cfg = Config()
cfg.PromptManager.in_template = prompt_in1
cfg.PromptManager.out_template = prompt_out
ipshell = InteractiveShellEmbed(config=cfg, user_ns=scope,
banner1=banner)
ipshell = InteractiveShellEmbed(
config=cfg, user_ns=scope, banner1=banner
)
except ImportError:
pass
@@ -193,6 +322,7 @@ def _check_tracing():
fatal("Tracing is not enabled. Compile with TRACING_ON")
def main():
import m5
import _m5.core
@@ -235,29 +365,29 @@ def main():
# Now redirect stdout/stderr as desired
if options.redirect_stdout:
redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
redir_fd = os.open(stdout_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
os.dup2(redir_fd, sys.stdout.fileno())
if not options.redirect_stderr:
os.dup2(redir_fd, sys.stderr.fileno())
if options.redirect_stderr:
redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
redir_fd = os.open(stderr_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
os.dup2(redir_fd, sys.stderr.fileno())
done = False
if options.build_info:
done = True
print('Build information:')
print("Build information:")
print()
print('gem5 version %s' % defines.gem5Version)
print('compiled %s' % defines.compileDate)
print('build options:')
print("gem5 version %s" % defines.gem5Version)
print("compiled %s" % defines.compileDate)
print("build options:")
keys = list(defines.buildEnv.keys())
keys.sort()
for key in keys:
val = defines.buildEnv[key]
print(' %s = %s' % (key, val))
print(" %s = %s" % (key, val))
print()
if options.copyright:
@@ -267,7 +397,7 @@ def main():
if options.readme:
done = True
print('Readme:')
print("Readme:")
print()
print(info.README)
print()
@@ -279,6 +409,7 @@ def main():
if options.list_sim_objects:
from . import SimObject
done = True
print("SimObjects:")
objects = list(SimObject.allClasses.keys())
@@ -291,13 +422,19 @@ def main():
params.sort()
for pname in params:
param = obj._params[pname]
default = getattr(param, 'default', '')
default = getattr(param, "default", "")
print(terminal_formatter.format_output(pname, indent=8))
if default:
print(terminal_formatter.format_output(
str(default), label="default: ", indent=21))
print(terminal_formatter.format_output(
param.desc, label="desc: ", indent=21))
print(
terminal_formatter.format_output(
str(default), label="default: ", indent=21
)
)
print(
terminal_formatter.format_output(
param.desc, label="desc: ", indent=21
)
)
print()
print()
@@ -317,13 +454,17 @@ def main():
print("gem5 version %s" % _m5.core.gem5Version)
print("gem5 compiled %s" % _m5.core.compileDate)
print("gem5 started %s" %
datetime.datetime.now().strftime("%b %e %Y %X"))
print("gem5 executing on %s, pid %d" %
(socket.gethostname(), os.getpid()))
print(
"gem5 started %s" % datetime.datetime.now().strftime("%b %e %Y %X")
)
print(
"gem5 executing on %s, pid %d"
% (socket.gethostname(), os.getpid())
)
# in Python 3 pipes.quote() is moved to shlex.quote()
import pipes
print("command line:", " ".join(map(pipes.quote, sys.argv)))
print()
@@ -371,7 +512,7 @@ def main():
off_flags = []
for flag in options.debug_flags:
off = False
if flag.startswith('-'):
if flag.startswith("-"):
flag = flag[1:]
off = True
@@ -403,13 +544,12 @@ def main():
trace.ignore(ignore)
sys.argv = arguments
sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
sys.path = [os.path.dirname(sys.argv[0])] + sys.path
filename = sys.argv[0]
filedata = open(filename, 'r').read()
filecode = compile(filedata, filename, 'exec')
scope = { '__file__' : filename,
'__name__' : '__m5_main__' }
filedata = open(filename, "r").read()
filecode = compile(filedata, filename, "exec")
scope = {"__file__": filename, "__name__": "__m5_main__"}
# if pdb was requested, execfile the thing under pdb, otherwise,
# just do the execfile normally
@@ -421,7 +561,7 @@ def main():
try:
pdb.run(filecode, scope)
except SystemExit:
print("The program exited via sys.exit(). Exit status: ", end=' ')
print("The program exited via sys.exit(). Exit status: ", end=" ")
print(sys.exc_info()[1])
except:
traceback.print_exc()
@@ -429,7 +569,7 @@ def main():
t = sys.exc_info()[2]
while t.tb_next is not None:
t = t.tb_next
pdb.interaction(t.tb_frame,t)
pdb.interaction(t.tb_frame, t)
else:
exec(filecode, scope)

View File

@@ -24,6 +24,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.SimObject import *
# The ByteOrder enum is defined in params. Expose it here so we can declare it
# to SCons, since there's no normal SimObject file to make it a part of.
from m5.params import ByteOrder

View File

@@ -25,5 +25,5 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
for module in __spec__.loader_state:
if module.startswith('m5.objects.'):
if module.startswith("m5.objects."):
exec("from %s import *" % module)

View File

@@ -29,11 +29,15 @@ import sys
from optparse import *
class nodefault(object): pass
class nodefault(object):
pass
class splitter(object):
def __init__(self, split):
self.split = split
def __call__(self, option, opt_str, value, parser):
values = value.split(self.split)
dest = getattr(parser.values, option.dest)
@@ -42,9 +46,10 @@ class splitter(object):
else:
dest.extend(values)
class OptionParser(dict):
def __init__(self, *args, **kwargs):
kwargs.setdefault('formatter', optparse.TitledHelpFormatter())
kwargs.setdefault("formatter", optparse.TitledHelpFormatter())
self._optparse = optparse.OptionParser(*args, **kwargs)
self._optparse.disable_interspersed_args()
@@ -57,24 +62,24 @@ class OptionParser(dict):
return self._optparse.set_defaults(*args, **kwargs)
def set_group(self, *args, **kwargs):
'''set the current option group'''
"""set the current option group"""
if not args and not kwargs:
self._group = self._optparse
else:
self._group = self._optparse.add_option_group(*args, **kwargs)
def add_option(self, *args, **kwargs):
'''add an option to the current option group, or global none set'''
"""add an option to the current option group, or global none set"""
# if action=split, but allows the option arguments
# themselves to be lists separated by the split variable'''
if kwargs.get('action', None) == 'append' and 'split' in kwargs:
split = kwargs.pop('split')
kwargs['default'] = []
kwargs['type'] = 'string'
kwargs['action'] = 'callback'
kwargs['callback'] = splitter(split)
if kwargs.get("action", None) == "append" and "split" in kwargs:
split = kwargs.pop("split")
kwargs["default"] = []
kwargs["type"] = "string"
kwargs["action"] = "callback"
kwargs["callback"] = splitter(split)
option = self._group.add_option(*args, **kwargs)
dest = option.dest
@@ -84,12 +89,12 @@ class OptionParser(dict):
return option
def bool_option(self, name, default, help):
'''add a boolean option called --name and --no-name.
Display help depending on which is the default'''
"""add a boolean option called --name and --no-name.
Display help depending on which is the default"""
tname = '--%s' % name
fname = '--no-%s' % name
dest = name.replace('-', '_')
tname = "--%s" % name
fname = "--no-%s" % name
dest = name.replace("-", "_")
if default:
thelp = optparse.SUPPRESS_HELP
fhelp = help
@@ -97,15 +102,17 @@ class OptionParser(dict):
thelp = help
fhelp = optparse.SUPPRESS_HELP
topt = self.add_option(tname, action="store_true", default=default,
help=thelp)
fopt = self.add_option(fname, action="store_false", dest=dest,
help=fhelp)
topt = self.add_option(
tname, action="store_true", default=default, help=thelp
)
fopt = self.add_option(
fname, action="store_false", dest=dest, help=fhelp
)
return topt,fopt
return topt, fopt
def __getattr__(self, attr):
if attr.startswith('_'):
if attr.startswith("_"):
return super().__getattribute__(attr)
if attr in self:
@@ -114,10 +121,10 @@ class OptionParser(dict):
return super().__getattribute__(attr)
def __setattr__(self, attr, value):
if attr.startswith('_'):
if attr.startswith("_"):
super().__setattr__(attr, value)
elif attr in self._allopts:
defaults = { attr : value }
defaults = {attr: value}
self.set_defaults(**defaults)
if attr in self:
self[attr] = value
@@ -125,9 +132,9 @@ class OptionParser(dict):
super().__setattr__(attr, value)
def parse_args(self):
opts,args = self._optparse.parse_args()
opts, args = self._optparse.parse_args()
for key,val in opts.__dict__.items():
for key, val in opts.__dict__.items():
if val is not None or key not in self:
self[key] = val
@@ -137,4 +144,3 @@ class OptionParser(dict):
self._optparse.print_help()
if exitcode is not None:
sys.exit(exitcode)

File diff suppressed because it is too large Load Diff

View File

@@ -44,6 +44,7 @@
import copy
class BaseProxy(object):
def __init__(self, search_self, search_up):
self._search_self = search_self
@@ -52,49 +53,52 @@ class BaseProxy(object):
def __str__(self):
if self._search_self and not self._search_up:
s = 'Self'
s = "Self"
elif not self._search_self and self._search_up:
s = 'Parent'
s = "Parent"
else:
s = 'ConfusedProxy'
return s + '.' + self.path()
s = "ConfusedProxy"
return s + "." + self.path()
def __setattr__(self, attr, value):
if not attr.startswith('_'):
if not attr.startswith("_"):
raise AttributeError(
"cannot set attribute '%s' on proxy object" % attr)
"cannot set attribute '%s' on proxy object" % attr
)
super().__setattr__(attr, value)
def _gen_op(operation):
def op(self, operand):
if not (isinstance(operand, (int, float)) or \
isproxy(operand)):
if not (isinstance(operand, (int, float)) or isproxy(operand)):
raise TypeError(
"Proxy operand must be a constant or a proxy to a param")
"Proxy operand must be a constant or a proxy to a param"
)
self._ops.append((operation, operand))
return self
return op
# Support for multiplying proxies by either constants or other proxies
__mul__ = _gen_op(lambda operand_a, operand_b : operand_a * operand_b)
__mul__ = _gen_op(lambda operand_a, operand_b: operand_a * operand_b)
__rmul__ = __mul__
# Support for dividing proxies by either constants or other proxies
__truediv__ = _gen_op(lambda operand_a, operand_b :
operand_a / operand_b)
__floordiv__ = _gen_op(lambda operand_a, operand_b :
operand_a // operand_b)
__truediv__ = _gen_op(lambda operand_a, operand_b: operand_a / operand_b)
__floordiv__ = _gen_op(lambda operand_a, operand_b: operand_a // operand_b)
# Support for dividing constants by proxies
__rtruediv__ = _gen_op(lambda operand_a, operand_b :
operand_b / operand_a.getValue())
__rfloordiv__ = _gen_op(lambda operand_a, operand_b :
operand_b // operand_a.getValue())
__rtruediv__ = _gen_op(
lambda operand_a, operand_b: operand_b / operand_a.getValue()
)
__rfloordiv__ = _gen_op(
lambda operand_a, operand_b: operand_b // operand_a.getValue()
)
# After all the operators and operands have been defined, this function
# should be called to perform the actual operation
def _opcheck(self, result, base):
from . import params
for operation, operand in self._ops:
# Get the operand's value
if isproxy(operand):
@@ -132,8 +136,9 @@ class BaseProxy(object):
if not done:
raise AttributeError(
"Can't resolve proxy '%s' of type '%s' from '%s'" % \
(self.path(), self._pdesc.ptype_str, base.path()))
"Can't resolve proxy '%s' of type '%s' from '%s'"
% (self.path(), self._pdesc.ptype_str, base.path())
)
if isinstance(result, BaseProxy):
if result == self:
@@ -153,6 +158,7 @@ class BaseProxy(object):
# if index is 0 and item is not subscriptable, just
# use item itself (so cpu[0] works on uniprocessors)
return obj
getindex = staticmethod(getindex)
# This method should be called once the proxy is assigned to a
@@ -161,6 +167,7 @@ class BaseProxy(object):
def set_param_desc(self, pdesc):
self._pdesc = pdesc
class AttrProxy(BaseProxy):
def __init__(self, search_self, search_up, attr):
super().__init__(search_self, search_up)
@@ -169,11 +176,12 @@ class AttrProxy(BaseProxy):
def __getattr__(self, attr):
# python uses __bases__ internally for inheritance
if attr.startswith('_'):
if attr.startswith("_"):
return super().__getattr__(self, attr)
if hasattr(self, '_pdesc'):
raise AttributeError("Attribute reference on bound proxy "
f"({self}.{attr})")
if hasattr(self, "_pdesc"):
raise AttributeError(
"Attribute reference on bound proxy " f"({self}.{attr})"
)
# Return a copy of self rather than modifying self in place
# since self could be an indirect reference via a variable or
# parameter
@@ -185,7 +193,7 @@ class AttrProxy(BaseProxy):
def __getitem__(self, key):
if not isinstance(key, int):
raise TypeError("Proxy object requires integer index")
if hasattr(self, '_pdesc'):
if hasattr(self, "_pdesc"):
raise AttributeError("Index operation on bound proxy")
new_self = copy.deepcopy(self)
new_self._modifiers.append(key)
@@ -195,8 +203,8 @@ class AttrProxy(BaseProxy):
try:
val = getattr(obj, self._attr)
visited = False
if hasattr(val, '_visited'):
visited = getattr(val, '_visited')
if hasattr(val, "_visited"):
visited = getattr(val, "_visited")
if visited:
return None, False
@@ -217,7 +225,7 @@ class AttrProxy(BaseProxy):
elif isinstance(m, int):
val = val[m]
else:
assert("Item must be string or integer")
assert "Item must be string or integer"
while isproxy(val):
val = val.unproxy(obj)
return val, True
@@ -226,19 +234,21 @@ class AttrProxy(BaseProxy):
p = self._attr
for m in self._modifiers:
if isinstance(m, str):
p += '.%s' % m
p += ".%s" % m
elif isinstance(m, int):
p += '[%d]' % m
p += "[%d]" % m
else:
assert("Item must be string or integer")
assert "Item must be string or integer"
return p
class AnyProxy(BaseProxy):
def find(self, obj):
return obj.find_any(self._pdesc.ptype)
def path(self):
return 'any'
return "any"
# The AllProxy traverses the entire sub-tree (not only the children)
# and adds all objects of a specific type
@@ -247,10 +257,12 @@ class AllProxy(BaseProxy):
return obj.find_all(self._pdesc.ptype)
def path(self):
return 'all'
return "all"
def isproxy(obj):
from . import params
if isinstance(obj, (BaseProxy, params.EthernetAddr)):
return True
elif isinstance(obj, (list, tuple)):
@@ -259,24 +271,26 @@ def isproxy(obj):
return True
return False
class ProxyFactory(object):
def __init__(self, search_self, search_up):
self.search_self = search_self
self.search_up = search_up
def __getattr__(self, attr):
if attr == 'any':
if attr == "any":
return AnyProxy(self.search_self, self.search_up)
elif attr == 'all':
elif attr == "all":
if self.search_up:
assert("Parant.all is not supported")
assert "Parant.all is not supported"
return AllProxy(self.search_self, self.search_up)
else:
return AttrProxy(self.search_self, self.search_up, attr)
# global objects for handling proxies
Parent = ProxyFactory(search_self = False, search_up = True)
Self = ProxyFactory(search_self = True, search_up = False)
Parent = ProxyFactory(search_self=False, search_up=True)
Self = ProxyFactory(search_self=True, search_up=False)
# limit exports on 'from proxy import *'
__all__ = ['Parent', 'Self']
__all__ = ["Parent", "Self"]

View File

@@ -58,11 +58,11 @@ from .util import fatal
from .util import attrdict
# define a MaxTick parameter, unsigned 64 bit
MaxTick = 2**64 - 1
MaxTick = 2 ** 64 - 1
_drain_manager = _m5.drain.DrainManager.instance()
_instantiated = False # Has m5.instantiate() been called?
_instantiated = False # Has m5.instantiate() been called?
# The final call to instantiate the SimObject graph and initialize the
# system.
@@ -85,13 +85,15 @@ def instantiate(ckpt_dir=None):
# Make sure SimObject-valued params are in the configuration
# hierarchy so we catch them with future descendants() walks
for obj in root.descendants(): obj.adoptOrphanParams()
for obj in root.descendants():
obj.adoptOrphanParams()
# Unproxy in sorted order for determinism
for obj in root.descendants(): obj.unproxyParams()
for obj in root.descendants():
obj.unproxyParams()
if options.dump_config:
ini_file = open(os.path.join(options.outdir, options.dump_config), 'w')
ini_file = open(os.path.join(options.outdir, options.dump_config), "w")
# Print ini sections in sorted order for easier diffing
for obj in sorted(root.descendants(), key=lambda o: o.path()):
obj.print_ini(ini_file)
@@ -100,8 +102,10 @@ def instantiate(ckpt_dir=None):
if options.json_config:
try:
import json
json_file = open(
os.path.join(options.outdir, options.json_config), 'w')
os.path.join(options.outdir, options.json_config), "w"
)
d = root.get_config_as_dict()
json.dump(d, json_file, indent=4)
json_file.close()
@@ -116,21 +120,26 @@ def instantiate(ckpt_dir=None):
stats.initSimStats()
# Create the C++ sim objects and connect ports
for obj in root.descendants(): obj.createCCObject()
for obj in root.descendants(): obj.connectPorts()
for obj in root.descendants():
obj.createCCObject()
for obj in root.descendants():
obj.connectPorts()
# Do a second pass to finish initializing the sim objects
for obj in root.descendants(): obj.init()
for obj in root.descendants():
obj.init()
# Do a third pass to initialize statistics
stats._bindStatHierarchy(root)
root.regStats()
# Do a fourth pass to initialize probe points
for obj in root.descendants(): obj.regProbePoints()
for obj in root.descendants():
obj.regProbePoints()
# Do a fifth pass to connect probe listeners
for obj in root.descendants(): obj.regProbeListeners()
for obj in root.descendants():
obj.regProbeListeners()
# We want to generate the DVFS diagram for the system. This can only be
# done once all of the CPP objects have been created and initialised so
@@ -145,15 +154,20 @@ def instantiate(ckpt_dir=None):
if ckpt_dir:
_drain_manager.preCheckpointRestore()
ckpt = _m5.core.getCheckpoint(ckpt_dir)
for obj in root.descendants(): obj.loadState(ckpt)
for obj in root.descendants():
obj.loadState(ckpt)
else:
for obj in root.descendants(): obj.initState()
for obj in root.descendants():
obj.initState()
# Check to see if any of the stat events are in the past after resuming from
# a checkpoint, If so, this call will shift them to be at a valid time.
updateStatEvents()
need_startup = True
def simulate(*args, **kwargs):
global need_startup
global _instantiated
@@ -163,7 +177,8 @@ def simulate(*args, **kwargs):
if need_startup:
root = objects.Root.getInstance()
for obj in root.descendants(): obj.startup()
for obj in root.descendants():
obj.startup()
need_startup = False
# Python exit handlers happen in reverse order.
@@ -189,6 +204,7 @@ def simulate(*args, **kwargs):
return sim_out
def drain():
"""Drain the simulator in preparation of a checkpoint or memory mode
switch.
@@ -212,7 +228,7 @@ def drain():
# WARNING: if a valid exit event occurs while draining, it
# will not get returned to the user script
exit_event = _m5.event.simulate()
while exit_event.getCause() != 'Finished drain':
while exit_event.getCause() != "Finished drain":
exit_event = simulate()
return False
@@ -224,14 +240,17 @@ def drain():
assert _drain_manager.isDrained(), "Drain state inconsistent"
def memWriteback(root):
for obj in root.descendants():
obj.memWriteback()
def memInvalidate(root):
for obj in root.descendants():
obj.memInvalidate()
def checkpoint(dir):
root = objects.Root.getInstance()
if not isinstance(root, objects.Root):
@@ -242,15 +261,19 @@ def checkpoint(dir):
print("Writing checkpoint")
_m5.core.serializeAll(dir)
def _changeMemoryMode(system, mode):
if not isinstance(system, (objects.Root, objects.System)):
raise TypeError("Parameter of type '%s'. Must be type %s or %s." % \
(type(system), objects.Root, objects.System))
raise TypeError(
"Parameter of type '%s'. Must be type %s or %s."
% (type(system), objects.Root, objects.System)
)
if system.getMemoryMode() != mode:
system.setMemoryMode(mode)
else:
print("System already in target mode. Memory mode unchanged.")
def switchCpus(system, cpuList, verbose=True):
"""Switch CPUs in a system.
@@ -283,21 +306,25 @@ def switchCpus(system, cpuList, verbose=True):
raise TypeError("%s is not of type BaseCPU" % new_cpu)
if new_cpu in old_cpu_set:
raise RuntimeError(
"New CPU (%s) is in the list of old CPUs." % (old_cpu,))
"New CPU (%s) is in the list of old CPUs." % (old_cpu,)
)
if not new_cpu.switchedOut():
raise RuntimeError("New CPU (%s) is already active." % (new_cpu,))
if not new_cpu.support_take_over():
raise RuntimeError(
"New CPU (%s) does not support CPU handover." % (old_cpu,))
"New CPU (%s) does not support CPU handover." % (old_cpu,)
)
if new_cpu.memory_mode() != memory_mode_name:
raise RuntimeError(
"%s and %s require different memory modes." % (new_cpu,
new_cpus[0]))
"%s and %s require different memory modes."
% (new_cpu, new_cpus[0])
)
if old_cpu.switchedOut():
raise RuntimeError("Old CPU (%s) is inactive." % (new_cpu,))
if not old_cpu.support_take_over():
raise RuntimeError(
"Old CPU (%s) does not support CPU handover." % (old_cpu,))
"Old CPU (%s) does not support CPU handover." % (old_cpu,)
)
MemoryMode = params.allEnums["MemoryMode"]
try:
@@ -326,11 +353,15 @@ def switchCpus(system, cpuList, verbose=True):
for old_cpu, new_cpu in cpuList:
new_cpu.takeOverFrom(old_cpu)
def notifyFork(root):
for obj in root.descendants():
obj.notifyFork()
fork_count = 0
def fork(simout="%(parent)s.f%(fork_seq)i"):
"""Fork the simulator.
@@ -353,6 +384,7 @@ def fork(simout="%(parent)s.f%(fork_seq)i"):
pid of the child process or 0 if running in the child.
"""
from m5 import options
global fork_count
if not _m5.core.listenersDisabled():
@@ -375,16 +407,17 @@ def fork(simout="%(parent)s.f%(fork_seq)i"):
# Setup a new output directory
parent = options.outdir
options.outdir = simout % {
"parent" : parent,
"fork_seq" : fork_count,
"pid" : os.getpid(),
}
"parent": parent,
"fork_seq": fork_count,
"pid": os.getpid(),
}
_m5.core.setOutputDir(options.outdir)
else:
fork_count += 1
return pid
from _m5.core import disableAllListeners, listenersDisabled
from _m5.core import listenersLoopbackOnly
from _m5.core import curTick

View File

@@ -53,12 +53,13 @@ outputList = []
# Dictionary of stat visitor factories populated by the _url_factory
# visitor.
factories = { }
factories = {}
# List of all factories. Contains tuples of (factory, schemes,
# enabled).
all_factories = []
def _url_factory(schemes, enable=True):
"""Wrap a plain Python function with URL parsing helpers
@@ -101,19 +102,23 @@ def _url_factory(schemes, enable=True):
# values into proper Python types.
def parse_value(key, values):
if len(values) == 0 or (len(values) == 1 and not values[0]):
fatal("%s: '%s' doesn't have a value." % (
url.geturl(), key))
fatal(
"%s: '%s' doesn't have a value." % (url.geturl(), key)
)
elif len(values) > 1:
fatal("%s: '%s' has multiple values." % (
url.geturl(), key))
fatal(
"%s: '%s' has multiple values." % (url.geturl(), key)
)
else:
try:
return key, literal_eval(values[0])
except ValueError:
fatal("%s: %s isn't a valid Python literal" \
% (url.geturl(), values[0]))
fatal(
"%s: %s isn't a valid Python literal"
% (url.geturl(), values[0])
)
kwargs = dict([ parse_value(k, v) for k, v in qs.items() ])
kwargs = dict([parse_value(k, v) for k, v in qs.items()])
try:
return func("%s%s" % (url.netloc, url.path), **kwargs)
@@ -128,7 +133,8 @@ def _url_factory(schemes, enable=True):
return decorator
@_url_factory([ None, "", "text", "file", ])
@_url_factory([None, "", "text", "file"])
def _textFactory(fn, desc=True, spaces=True):
"""Output stats in text format.
@@ -147,7 +153,8 @@ def _textFactory(fn, desc=True, spaces=True):
return _m5.stats.initText(fn, desc, spaces)
@_url_factory([ "h5", ], enable=hasattr(_m5.stats, "initHDF5"))
@_url_factory(["h5"], enable=hasattr(_m5.stats, "initHDF5"))
def _hdf5Factory(fn, chunking=10, desc=True, formulas=True):
"""Output stats in HDF5 format.
@@ -183,6 +190,7 @@ def _hdf5Factory(fn, chunking=10, desc=True, formulas=True):
return _m5.stats.initHDF5(fn, chunking, desc, formulas)
@_url_factory(["json"])
def _jsonFactory(fn):
"""Output stats in JSON format.
@@ -194,6 +202,7 @@ def _jsonFactory(fn):
return JsonOutputVistor(fn)
def addStatVisitor(url):
"""Add a stat visitor specified using a URL string
@@ -225,6 +234,7 @@ def addStatVisitor(url):
outputList.append(factory(parsed))
def printStatVisitorTypes():
"""List available stat visitors and their documentation"""
@@ -235,17 +245,19 @@ def printStatVisitorTypes():
print("| %s" % line)
print()
enabled_visitors = [ x for x in all_factories if x[2] ]
enabled_visitors = [x for x in all_factories if x[2]]
for factory, schemes, _ in enabled_visitors:
print("%s:" % ", ".join(filter(lambda x: x is not None, schemes)))
# Try to extract the factory doc string
print_doc(inspect.getdoc(factory))
def initSimStats():
_m5.stats.initSimStats()
_m5.stats.registerPythonStatsHandlers()
def _visit_groups(visitor, root=None):
if root is None:
root = Root.getInstance()
@@ -253,12 +265,15 @@ def _visit_groups(visitor, root=None):
visitor(group)
_visit_groups(visitor, root=group)
def _visit_stats(visitor, root=None):
def for_each_stat(g):
for stat in g.getStats():
visitor(g, stat)
_visit_groups(for_each_stat, root=root)
def _bindStatHierarchy(root):
def _bind_obj(name, obj):
if isNullPointer(obj):
@@ -278,33 +293,39 @@ def _bindStatHierarchy(root):
if isinstance(obj.getCCObject(), _m5.stats.Group):
parent = root
while parent:
if hasattr(parent, 'addStatGroup'):
if hasattr(parent, "addStatGroup"):
parent.addStatGroup(name, obj.getCCObject())
break
parent = parent.get_parent();
parent = parent.get_parent()
_bindStatHierarchy(obj)
for name, obj in root._children.items():
_bind_obj(name, obj)
names = []
stats_dict = {}
stats_list = []
def enable():
'''Enable the statistics package. Before the statistics package is
"""Enable the statistics package. Before the statistics package is
enabled, all statistics must be created and initialized and once
the package is enabled, no more statistics can be created.'''
the package is enabled, no more statistics can be created."""
def check_stat(group, stat):
if not stat.check() or not stat.baseCheck():
fatal("statistic '%s' (%d) was not properly initialized " \
"by a regStats() function\n", stat.name, stat.id)
fatal(
"statistic '%s' (%d) was not properly initialized "
"by a regStats() function\n",
stat.name,
stat.id,
)
if not (stat.flags & flags.display):
stat.name = "__Stat%06d" % stat.id
# Legacy stat
global stats_list
stats_list = list(_m5.stats.statsList())
@@ -312,21 +333,21 @@ def enable():
for stat in stats_list:
check_stat(None, stat)
stats_list.sort(key=lambda s: s.name.split('.'))
stats_list.sort(key=lambda s: s.name.split("."))
for stat in stats_list:
stats_dict[stat.name] = stat
stat.enable()
# New stats
_visit_stats(check_stat)
_visit_stats(lambda g, s: s.enable())
_m5.stats.enable();
_m5.stats.enable()
def prepare():
'''Prepare all stats for data access. This must be done before
dumping and serialization.'''
"""Prepare all stats for data access. This must be done before
dumping and serialization."""
# Legacy stats
for stat in stats_list:
@@ -335,6 +356,7 @@ def prepare():
# New stats
_visit_stats(lambda g, s: s.prepare())
def _dump_to_visitor(visitor, roots=None):
# New stats
def dump_group(group):
@@ -361,12 +383,14 @@ def _dump_to_visitor(visitor, roots=None):
for stat in stats_list:
stat.visit(visitor)
lastDump = 0
# List[SimObject].
global_dump_roots = []
def dump(roots=None):
'''Dump all statistics data to the registered outputs'''
"""Dump all statistics data to the registered outputs"""
all_roots = []
if roots is not None:
@@ -391,7 +415,7 @@ def dump(roots=None):
# Notify new-style stats group that we are about to dump stats.
sim_root = Root.getInstance()
if sim_root:
sim_root.preDumpStats();
sim_root.preDumpStats()
prepare()
for output in outputList:
@@ -406,8 +430,9 @@ def dump(roots=None):
_dump_to_visitor(output, roots=all_roots)
output.end()
def reset():
'''Reset all statistics to the base state'''
"""Reset all statistics to the base state"""
# call reset stats on all SimObjects
root = Root.getInstance()
@@ -420,14 +445,17 @@ def reset():
_m5.stats.processResetQueue()
flags = attrdict({
'none' : 0x0000,
'init' : 0x0001,
'display' : 0x0002,
'total' : 0x0010,
'pdf' : 0x0020,
'cdf' : 0x0040,
'dist' : 0x0080,
'nozero' : 0x0100,
'nonan' : 0x0200,
})
flags = attrdict(
{
"none": 0x0000,
"init": 0x0001,
"display": 0x0002,
"total": 0x0010,
"pdf": 0x0020,
"cdf": 0x0040,
"dist": 0x0080,
"nozero": 0x0100,
"nonan": 0x0200,
}
)

View File

@@ -39,11 +39,13 @@ from m5.ext.pystats.simstat import *
from m5.ext.pystats.statistic import *
from m5.ext.pystats.storagetype import *
class JsonOutputVistor():
class JsonOutputVistor:
"""
This is a helper vistor class used to include a JSON output via the stats
API (`src/python/m5/stats/__init__.py`).
"""
file: str
json_args: Dict
@@ -77,10 +79,11 @@ class JsonOutputVistor():
The Root, or List of roots, whose stats are are to be dumped JSON.
"""
with open(self.file, 'w') as fp:
with open(self.file, "w") as fp:
simstat = get_simstat(root=roots, prepare_stats=False)
simstat.dump(fp=fp, **self.json_args)
def get_stats_group(group: _m5.stats.Group) -> Group:
"""
Translates a gem5 Group object into a Python stats Group object. A Python
@@ -113,6 +116,7 @@ def get_stats_group(group: _m5.stats.Group) -> Group:
return Group(**stats_dict)
def __get_statistic(statistic: _m5.stats.Info) -> Optional[Statistic]:
"""
Translates a _m5.stats.Info object into a Statistic object, to process
@@ -130,7 +134,7 @@ def __get_statistic(statistic: _m5.stats.Info) -> Optional[Statistic]:
cannot be translated.
"""
assert(isinstance(statistic, _m5.stats.Info))
assert isinstance(statistic, _m5.stats.Info)
statistic.prepare()
if isinstance(statistic, _m5.stats.ScalarInfo):
@@ -146,6 +150,7 @@ def __get_statistic(statistic: _m5.stats.Info) -> Optional[Statistic]:
return None
def __get_scaler(statistic: _m5.stats.ScalarInfo) -> Scalar:
value = statistic.value
unit = statistic.unit
@@ -154,11 +159,9 @@ def __get_scaler(statistic: _m5.stats.ScalarInfo) -> Scalar:
datatype = StorageType["f64"]
return Scalar(
value=value,
unit=unit,
description=description,
datatype=datatype,
)
value=value, unit=unit, description=description, datatype=datatype
)
def __get_distribution(statistic: _m5.stats.DistInfo) -> Distribution:
unit = statistic.unit
@@ -177,20 +180,21 @@ def __get_distribution(statistic: _m5.stats.DistInfo) -> Distribution:
datatype = StorageType["f64"]
return Distribution(
value=value,
min=min,
max=max,
num_bins=num_bins,
bin_size=bin_size,
sum = sum_val,
sum_squared = sum_squared,
underflow = underflow,
overflow = overflow,
logs = logs,
unit=unit,
description=description,
datatype=datatype,
)
value=value,
min=min,
max=max,
num_bins=num_bins,
bin_size=bin_size,
sum=sum_val,
sum_squared=sum_squared,
underflow=underflow,
overflow=overflow,
logs=logs,
unit=unit,
description=description,
datatype=datatype,
)
def __get_vector(statistic: _m5.stats.VectorInfo) -> Vector:
to_add = dict()
@@ -212,14 +216,12 @@ def __get_vector(statistic: _m5.stats.VectorInfo) -> Vector:
index_string = str(index)
to_add[index_string] = Scalar(
value=value,
unit=unit,
description=description,
datatype=datatype,
)
value=value, unit=unit, description=description, datatype=datatype
)
return Vector(scalar_map=to_add)
def _prepare_stats(group: _m5.stats.Group):
"""
Prepares the statistics for dumping.
@@ -234,8 +236,9 @@ def _prepare_stats(group: _m5.stats.Group):
_prepare_stats(child)
def get_simstat(root: Union[SimObject, List[SimObject]],
prepare_stats: bool = True) -> SimStat:
def get_simstat(
root: Union[SimObject, List[SimObject]], prepare_stats: bool = True
) -> SimStat:
"""
This function will return the SimStat object for a simulation given a
SimObject (typically a Root SimObject), or list of SimObjects. The returned
@@ -262,7 +265,7 @@ def get_simstat(root: Union[SimObject, List[SimObject]],
"""
stats_map = {}
creation_time = datetime.now()
time_converstion = None # TODO https://gem5.atlassian.net/browse/GEM5-846
time_converstion = None # TODO https://gem5.atlassian.net/browse/GEM5-846
final_tick = Root.getInstance().resolveStat("finalTick").value
sim_ticks = Root.getInstance().resolveStat("simTicks").value
simulated_begin_time = int(final_tick - sim_ticks)
@@ -284,16 +287,16 @@ def get_simstat(root: Union[SimObject, List[SimObject]],
_prepare_stats(r)
stats_map[r.get_name()] = get_stats_group(r)
else:
raise TypeError("Object (" + str(r) + ") passed is not a "
"SimObject. " + __name__ + " only processes "
"SimObjects, or a list of SimObjects.")
raise TypeError(
"Object (" + str(r) + ") passed is not a "
"SimObject. " + __name__ + " only processes "
"SimObjects, or a list of SimObjects."
)
return SimStat(
creation_time=creation_time,
time_conversion=time_converstion,
simulated_begin_time=simulated_begin_time,
simulated_end_time=simulated_end_time,
**stats_map,
)
creation_time=creation_time,
time_conversion=time_converstion,
simulated_begin_time=simulated_begin_time,
simulated_end_time=simulated_end_time,
**stats_map,
)

View File

@@ -32,8 +32,10 @@ from m5.util import warn
# fix the global frequency
def fixGlobalFrequency():
import _m5.core
_m5.core.fixClockFrequency()
def setGlobalFrequency(ticksPerSecond):
from m5.util import convert
import _m5.core
@@ -46,12 +48,15 @@ def setGlobalFrequency(ticksPerSecond):
tps = round(convert.anyToFrequency(ticksPerSecond))
else:
raise TypeError(
"wrong type '%s' for ticksPerSecond" % type(ticksPerSecond))
"wrong type '%s' for ticksPerSecond" % type(ticksPerSecond)
)
_m5.core.setClockFrequency(int(tps))
# how big does a rounding error need to be before we warn about it?
frequency_tolerance = 0.001 # 0.1%
def fromSeconds(value):
import _m5.core
@@ -62,7 +67,8 @@ def fromSeconds(value):
# had better be fixed
if not _m5.core.clockFrequencyFixed():
raise AttributeError(
"In order to do conversions, the global frequency must be fixed")
"In order to do conversions, the global frequency must be fixed"
)
if value == 0:
return 0
@@ -71,12 +77,21 @@ def fromSeconds(value):
value *= _m5.core.getClockFrequency()
int_value = int(
decimal.Decimal(value).to_integral_value( decimal.ROUND_HALF_UP))
decimal.Decimal(value).to_integral_value(decimal.ROUND_HALF_UP)
)
err = (value - int_value) / value
if err > frequency_tolerance:
warn("rounding error > tolerance\n %f rounded to %d", value,
int_value)
warn(
"rounding error > tolerance\n %f rounded to %d",
value,
int_value,
)
return int_value
__all__ = [ 'setGlobalFrequency', 'fixGlobalFrequency', 'fromSeconds',
'frequency_tolerance' ]
__all__ = [
"setGlobalFrequency",
"fixGlobalFrequency",
"fromSeconds",
"frequency_tolerance",
]

View File

@@ -52,65 +52,77 @@ from .multidict import multidict
# ever happen regardless of what the user does (i.e., an acutal m5
# bug).
def panic(fmt, *args):
print('panic:', fmt % args, file=sys.stderr)
print("panic:", fmt % args, file=sys.stderr)
sys.exit(1)
# fatal() should be called when the simulation cannot continue due to
# some condition that is the user's fault (bad configuration, invalid
# arguments, etc.) and not a simulator bug.
def fatal(fmt, *args):
print('fatal:', fmt % args, file=sys.stderr)
print("fatal:", fmt % args, file=sys.stderr)
sys.exit(1)
# warn() should be called when the user should be warned about some condition
# that may or may not be the user's fault, but that they should be made aware
# of as it may affect the simulation or results.
def warn(fmt, *args):
print('warn:', fmt % args, file=sys.stderr)
print("warn:", fmt % args, file=sys.stderr)
# inform() should be called when the user should be informed about some
# condition that they may be interested in.
def inform(fmt, *args):
print('info:', fmt % args, file=sys.stdout)
print("info:", fmt % args, file=sys.stdout)
def callOnce(func):
"""Decorator that enables to run a given function only once. Subsequent
calls are discarded."""
@wraps(func)
def wrapper(*args, **kwargs):
if not wrapper.has_run:
wrapper.has_run = True
return func(*args, **kwargs)
wrapper.has_run = False
return wrapper
def deprecated(replacement=None, logger=warn):
"""This decorator warns the user about a deprecated function."""
def decorator(func):
@callOnce
def notifyDeprecation():
try:
func_name = lambda f: f.__module__ + '.' + f.__qualname__
message = f'Function {func_name(func)} is deprecated.'
func_name = lambda f: f.__module__ + "." + f.__qualname__
message = f"Function {func_name(func)} is deprecated."
if replacement:
message += f' Prefer {func_name(replacement)} instead.'
message += f" Prefer {func_name(replacement)} instead."
except AttributeError:
message = f'Function {func} is deprecated.'
message = f"Function {func} is deprecated."
if replacement:
message += f' Prefer {replacement} instead.'
message += f" Prefer {replacement} instead."
logger(message)
notifyDeprecation()
return func
return decorator
class Singleton(type):
def __call__(cls, *args, **kwargs):
if hasattr(cls, '_instance'):
if hasattr(cls, "_instance"):
return cls._instance
cls._instance = super().__call__(*args, **kwargs)
return cls._instance
def addToPath(path):
"""Prepend given directory to system module search path. We may not
need this anymore if we can structure our config library more like a
@@ -125,6 +137,7 @@ def addToPath(path):
# so place the new dir right after that.
sys.path.insert(1, path)
def repoPath():
"""
Return the abspath of the gem5 repository.
@@ -132,15 +145,15 @@ def repoPath():
<gem5-repo>/build/<ISA>/gem5.[opt,debug...]
"""
return os.path.dirname(
os.path.dirname(
os.path.dirname(sys.executable)))
return os.path.dirname(os.path.dirname(os.path.dirname(sys.executable)))
# Apply method to object.
# applyMethod(obj, 'meth', <args>) is equivalent to obj.meth(<args>)
def applyMethod(obj, meth, *args, **kwargs):
return getattr(obj, meth)(*args, **kwargs)
# If the first argument is an (non-sequence) object, apply the named
# method with the given arguments. If the first argument is a
# sequence, apply the method to each element of the sequence (a la
@@ -151,6 +164,7 @@ def applyOrMap(objOrSeq, meth, *args, **kwargs):
else:
return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq]
def crossproduct(items):
if len(items) == 1:
for i in items[0]:
@@ -160,6 +174,7 @@ def crossproduct(items):
for j in crossproduct(items[1:]):
yield (i,) + j
def flatten(items):
while items:
item = items.pop(0)
@@ -168,25 +183,28 @@ def flatten(items):
else:
yield item
# force scalars to one-element lists for uniformity
def makeList(objOrList):
if isinstance(objOrList, list):
return objOrList
return [objOrList]
def printList(items, indent=4):
line = ' ' * indent
for i,item in enumerate(items):
line = " " * indent
for i, item in enumerate(items):
if len(line) + len(item) > 76:
print(line)
line = ' ' * indent
line = " " * indent
if i < len(items) - 1:
line += '%s, ' % item
line += "%s, " % item
else:
line += item
print(line)
def isInteractive():
"""Check if the simulator is run interactively or in a batch environment"""

View File

@@ -24,17 +24,19 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
__all__ = [ 'attrdict', 'multiattrdict', 'optiondict' ]
__all__ = ["attrdict", "multiattrdict", "optiondict"]
class attrdict(dict):
"""Wrap dict, so you can use attribute access to get/set elements"""
def __getattr__(self, attr):
if attr in self:
return self.__getitem__(attr)
return super().__getattribute__(attr)
def __setattr__(self, attr, value):
if attr in dir(self) or attr.startswith('_'):
if attr in dir(self) or attr.startswith("_"):
return super().__setattr__(attr, value)
return self.__setitem__(attr, value)
@@ -49,40 +51,45 @@ class attrdict(dict):
def __setstate__(self, state):
self.update(state)
class multiattrdict(attrdict):
"""Wrap attrdict so that nested attribute accesses automatically create
nested dictionaries."""
def __getattr__(self, attr):
try:
return super().__getattr__(attr)
except AttributeError:
if attr.startswith('_'):
if attr.startswith("_"):
raise
d = multiattrdict()
setattr(self, attr, d)
return d
class optiondict(attrdict):
"""Modify attrdict so that a missing attribute just returns None"""
def __getattr__(self, attr):
try:
return super().__getattr__(attr)
except AttributeError:
return None
if __name__ == '__main__':
if __name__ == "__main__":
x = attrdict()
x.y = 1
x['z'] = 2
print(x['y'], x.y)
print(x['z'], x.z)
x["z"] = 2
print(x["y"], x.y)
print(x["z"], x.z)
print(dir(x))
print(x)
print()
del x['y']
del x["y"]
del x.z
print(dir(x))
print(x)

View File

@@ -38,10 +38,10 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# metric prefixes
atto = 1.0e-18
atto = 1.0e-18
femto = 1.0e-15
pico = 1.0e-12
nano = 1.0e-9
pico = 1.0e-12
nano = 1.0e-9
micro = 1.0e-6
milli = 1.0e-3
@@ -50,7 +50,7 @@ mega = 1.0e6
giga = 1.0e9
tera = 1.0e12
peta = 1.0e15
exa = 1.0e18
exa = 1.0e18
# power of 2 prefixes
kibi = 1024
@@ -61,47 +61,49 @@ pebi = tebi * 1024
exbi = pebi * 1024
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,
"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,
"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))
def _split_suffix(value, suffixes):
'''Split a string based on a suffix from a list of suffixes.
"""Split a string based on a suffix from a list of suffixes.
:param value: String value to test for a matching suffix.
:param suffixes: Container of suffixes to test.
@@ -109,16 +111,15 @@ def _split_suffix(value, suffixes):
:returns: A tuple of (value, suffix). Suffix is the empty string
if there is no match.
'''
matches = [ sfx for sfx in suffixes if value.endswith(sfx) ]
"""
matches = [sfx for sfx in suffixes if value.endswith(sfx)]
assert len(matches) <= 1
return (value[:-len(matches[0])], matches[0]) if matches \
else (value, '')
return (value[: -len(matches[0])], matches[0]) if matches else (value, "")
def toNum(value, target_type, units, prefixes, converter):
'''Convert a string using units and prefixes to (typically) a float or
"""Convert a string using units and prefixes to (typically) a float or
integer.
String values are assumed to either be a naked magnitude without a
@@ -133,7 +134,7 @@ def toNum(value, target_type, units, prefixes, converter):
:returns: Tuple of (converted value, unit)
'''
"""
assertStr(value)
def convert(val):
@@ -141,7 +142,8 @@ def toNum(value, target_type, units, prefixes, converter):
return converter(val)
except ValueError:
raise ValueError(
"cannot convert '%s' to %s" % (value, target_type))
"cannot convert '%s' to %s" % (value, target_type)
)
# Units can be None, the empty string, or a list/tuple. Convert
# to a tuple for consistent handling.
@@ -159,56 +161,67 @@ def toNum(value, target_type, units, prefixes, converter):
magnitude, prefix = _split_suffix(magnitude_prefix, prefixes)
scale = prefixes[prefix] if prefix else 1
else:
magnitude, prefix, scale = magnitude_prefix, '', 1
magnitude, prefix, scale = magnitude_prefix, "", 1
return convert(magnitude) * scale, unit
def toFloat(value, target_type='float', units=None, prefixes=[]):
def toFloat(value, target_type="float", units=None, prefixes=[]):
return toNum(value, target_type, units, prefixes, float)[0]
def toMetricFloat(value, target_type='float', units=None):
def toMetricFloat(value, target_type="float", units=None):
return toFloat(value, target_type, units, metric_prefixes)
def toBinaryFloat(value, target_type='float', units=None):
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=[]):
return toNum(value, target_type, units, prefixes,
lambda x: int(x, 0))[0]
def toMetricInteger(value, target_type='integer', units=None):
def toInteger(value, target_type="integer", units=None, prefixes=[]):
return toNum(value, target_type, units, prefixes, lambda x: int(x, 0))[0]
def toMetricInteger(value, target_type="integer", units=None):
return toInteger(value, target_type, units, metric_prefixes)
def toBinaryInteger(value, target_type='integer', units=None):
def toBinaryInteger(value, target_type="integer", units=None):
return toInteger(value, target_type, units, binary_prefixes)
def toBool(value):
assertStr(value)
value = value.lower()
if value in ('true', 't', 'yes', 'y', '1'):
if value in ("true", "t", "yes", "y", "1"):
return True
if value in ('false', 'f', 'no', 'n', '0'):
if value in ("false", "f", "no", "n", "0"):
return False
raise ValueError("cannot convert '%s' to bool" % value)
def toFrequency(value):
return toMetricFloat(value, 'frequency', 'Hz')
return toMetricFloat(value, "frequency", "Hz")
def toLatency(value):
return toMetricFloat(value, 'latency', 's')
return toMetricFloat(value, "latency", "s")
def anyToLatency(value):
"""Convert a magnitude and unit to a clock period."""
magnitude, unit = toNum(value,
target_type='latency',
units=('Hz', 's'),
prefixes=metric_prefixes,
converter=float)
if unit == 's':
magnitude, unit = toNum(
value,
target_type="latency",
units=("Hz", "s"),
prefixes=metric_prefixes,
converter=float,
)
if unit == "s":
return magnitude
elif unit == 'Hz':
elif unit == "Hz":
try:
return 1.0 / magnitude
except ZeroDivisionError:
@@ -216,17 +229,20 @@ def anyToLatency(value):
else:
raise ValueError(f"'{value}' needs a valid unit to be unambiguous.")
def anyToFrequency(value):
"""Convert a magnitude and unit to a clock frequency."""
magnitude, unit = toNum(value,
target_type='frequency',
units=('Hz', 's'),
prefixes=metric_prefixes,
converter=float)
if unit == 'Hz':
magnitude, unit = toNum(
value,
target_type="frequency",
units=("Hz", "s"),
prefixes=metric_prefixes,
converter=float,
)
if unit == "Hz":
return magnitude
elif unit == 's':
elif unit == "s":
try:
return 1.0 / magnitude
except ZeroDivisionError:
@@ -234,40 +250,49 @@ def anyToFrequency(value):
else:
raise ValueError(f"'{value}' needs a valid unit to be unambiguous.")
def toNetworkBandwidth(value):
return toMetricFloat(value, 'network bandwidth', 'bps')
return toMetricFloat(value, "network bandwidth", "bps")
def toMemoryBandwidth(value):
return toBinaryFloat(value, 'memory bandwidth', 'B/s')
return toBinaryFloat(value, "memory bandwidth", "B/s")
def toMemorySize(value):
return toBinaryInteger(value, 'memory size', 'B')
return toBinaryInteger(value, "memory size", "B")
def toIpAddress(value):
if not isinstance(value, str):
raise TypeError("wrong type '%s' should be str" % type(value))
bytes = value.split('.')
bytes = value.split(".")
if len(bytes) != 4:
raise ValueError('invalid ip address %s' % value)
raise ValueError("invalid ip address %s" % value)
for byte in bytes:
if not 0 <= int(byte) <= 0xff:
raise ValueError('invalid ip address %s' % value)
if not 0 <= int(byte) <= 0xFF:
raise ValueError("invalid ip address %s" % value)
return (
(int(bytes[0]) << 24)
| (int(bytes[1]) << 16)
| (int(bytes[2]) << 8)
| (int(bytes[3]) << 0)
)
return (int(bytes[0]) << 24) | (int(bytes[1]) << 16) | \
(int(bytes[2]) << 8) | (int(bytes[3]) << 0)
def toIpNetmask(value):
if not isinstance(value, str):
raise TypeError("wrong type '%s' should be str" % type(value))
(ip, netmask) = value.split('/')
(ip, netmask) = value.split("/")
ip = toIpAddress(ip)
netmaskParts = netmask.split('.')
netmaskParts = netmask.split(".")
if len(netmaskParts) == 1:
if not 0 <= int(netmask) <= 32:
raise ValueError('invalid netmask %s' % netmask)
raise ValueError("invalid netmask %s" % netmask)
return (ip, int(netmask))
elif len(netmaskParts) == 4:
netmaskNum = toIpAddress(netmask)
@@ -275,45 +300,52 @@ def toIpNetmask(value):
return (ip, 0)
testVal = 0
for i in range(32):
testVal |= (1 << (31 - i))
testVal |= 1 << (31 - i)
if testVal == netmaskNum:
return (ip, i + 1)
raise ValueError('invalid netmask %s' % netmask)
raise ValueError("invalid netmask %s" % netmask)
else:
raise ValueError('invalid netmask %s' % netmask)
raise ValueError("invalid netmask %s" % netmask)
def toIpWithPort(value):
if not isinstance(value, str):
raise TypeError("wrong type '%s' should be str" % type(value))
(ip, port) = value.split(':')
(ip, port) = value.split(":")
ip = toIpAddress(ip)
if not 0 <= int(port) <= 0xffff:
raise ValueError('invalid port %s' % port)
if not 0 <= int(port) <= 0xFFFF:
raise ValueError("invalid port %s" % port)
return (ip, int(port))
def toVoltage(value):
return toMetricFloat(value, 'voltage', 'V')
return toMetricFloat(value, "voltage", "V")
def toCurrent(value):
return toMetricFloat(value, 'current', 'A')
return toMetricFloat(value, "current", "A")
def toEnergy(value):
return toMetricFloat(value, 'energy', 'J')
return toMetricFloat(value, "energy", "J")
def toTemperature(value):
"""Convert a string value specified to a temperature in Kelvin"""
magnitude, unit = toNum(value,
target_type='temperature',
units=('K', 'C', 'F'),
prefixes=metric_prefixes,
converter=float)
if unit == 'K':
magnitude, unit = toNum(
value,
target_type="temperature",
units=("K", "C", "F"),
prefixes=metric_prefixes,
converter=float,
)
if unit == "K":
kelvin = magnitude
elif unit == 'C':
elif unit == "C":
kelvin = magnitude + 273.15
elif unit == 'F':
elif unit == "F":
kelvin = (magnitude + 459.67) / 1.8
else:
raise ValueError(f"'{value}' needs a valid temperature unit.")

View File

@@ -57,11 +57,13 @@ import m5, os, re
from m5.SimObject import isRoot, isSimObjectVector
from m5.params import PortRef, isNullPointer
from m5.util import warn
try:
import pydot
except:
pydot = False
def simnode_children(simNode):
for child in simNode._children.values():
if isNullPointer(child):
@@ -73,15 +75,16 @@ def simnode_children(simNode):
else:
yield child
# need to create all nodes (components) before creating edges (memory channels)
def dot_create_nodes(simNode, callgraph):
if isRoot(simNode):
label = "root"
else:
label = simNode._name
full_path = re.sub('\.', '_', simNode.path())
full_path = re.sub("\.", "_", simNode.path())
# add class name under the label
label = "\"" + label + " \\n: " + simNode.__class__.__name__ + "\""
label = '"' + label + " \\n: " + simNode.__class__.__name__ + '"'
# each component is a sub-graph (cluster)
cluster = dot_create_cluster(simNode, full_path, label)
@@ -100,12 +103,13 @@ def dot_create_nodes(simNode, callgraph):
callgraph.add_subgraph(cluster)
# create all edges according to memory hierarchy
def dot_create_edges(simNode, callgraph):
for port_name in simNode._ports.keys():
port = simNode._port_refs.get(port_name, None)
if port != None:
full_path = re.sub('\.', '_', simNode.path())
full_path = re.sub("\.", "_", simNode.path())
full_port_name = full_path + "_" + port_name
port_node = dot_create_node(simNode, full_port_name, port_name)
# create edges
@@ -121,24 +125,25 @@ def dot_create_edges(simNode, callgraph):
for child in simnode_children(simNode):
dot_create_edges(child, callgraph)
def dot_add_edge(simNode, callgraph, full_port_name, port):
peer = port.peer
full_peer_path = re.sub('\.', '_', peer.simobj.path())
full_peer_path = re.sub("\.", "_", peer.simobj.path())
full_peer_port_name = full_peer_path + "_" + peer.name
# Each edge is encountered twice, once for each peer. We only want one
# edge, so we'll arbitrarily chose which peer "wins" based on their names.
if full_peer_port_name < full_port_name:
dir_type = {
(False, False) : 'both',
(True, False) : 'forward',
(False, True) : 'back',
(True, True) : 'none'
}[ (port.is_source,
peer.is_source) ]
(False, False): "both",
(True, False): "forward",
(False, True): "back",
(True, True): "none",
}[(port.is_source, peer.is_source)]
edge = pydot.Edge(full_port_name, full_peer_port_name, dir=dir_type)
callgraph.add_edge(edge)
def dot_create_cluster(simNode, full_path, label):
# get the parameter values of the node and use them as a tooltip
ini_strings = []
@@ -146,42 +151,45 @@ def dot_create_cluster(simNode, full_path, label):
value = simNode._values.get(param)
if value != None:
# parameter name = value in HTML friendly format
ini_strings.append(str(param) + "&#61;" +
simNode._values[param].ini_str())
ini_strings.append(
str(param) + "&#61;" + simNode._values[param].ini_str()
)
# join all the parameters with an HTML newline
# Pydot limit line length to 16384.
# Account for the quotes added later around the tooltip string
tooltip = "&#10;\\".join(ini_strings)
max_tooltip_length = 16384 - 2
if len(tooltip) > max_tooltip_length:
truncated = '... (truncated)'
tooltip = tooltip[:max_tooltip_length-len(truncated)] + truncated
truncated = "... (truncated)"
tooltip = tooltip[: max_tooltip_length - len(truncated)] + truncated
return pydot.Cluster(
full_path,
shape="box",
label=label,
tooltip='"' + tooltip + '"',
style='"rounded, filled"',
color="#000000",
fillcolor=dot_gen_colour(simNode),
fontname="Arial",
fontsize="14",
fontcolor="#000000",
)
return pydot.Cluster( \
full_path, \
shape = "box", \
label = label, \
tooltip = "\"" + tooltip + "\"", \
style = "\"rounded, filled\"", \
color = "#000000", \
fillcolor = dot_gen_colour(simNode), \
fontname = "Arial", \
fontsize = "14", \
fontcolor = "#000000" \
)
def dot_create_node(simNode, full_path, label):
return pydot.Node( \
full_path, \
shape = "box", \
label = label, \
style = "\"rounded, filled\"", \
color = "#000000", \
fillcolor = dot_gen_colour(simNode, True), \
fontname = "Arial", \
fontsize = "14", \
fontcolor = "#000000" \
)
return pydot.Node(
full_path,
shape="box",
label=label,
style='"rounded, filled"',
color="#000000",
fillcolor=dot_gen_colour(simNode, True),
fontname="Arial",
fontsize="14",
fontcolor="#000000",
)
# an enumerator for different kinds of node types, at the moment we
# discern the majority of node types, with the caches being the
@@ -194,17 +202,20 @@ class NodeType:
DEV = 4
OTHER = 5
# based on the sim object, determine the node type
def get_node_type(simNode):
if isinstance(simNode, m5.objects.System):
return NodeType.SYS
# NULL ISA has no BaseCPU or PioDevice, so check if these names
# exists before using them
elif 'BaseCPU' in dir(m5.objects) and \
isinstance(simNode, m5.objects.BaseCPU):
elif "BaseCPU" in dir(m5.objects) and isinstance(
simNode, m5.objects.BaseCPU
):
return NodeType.CPU
elif 'PioDevice' in dir(m5.objects) and \
isinstance(simNode, m5.objects.PioDevice):
elif "PioDevice" in dir(m5.objects) and isinstance(
simNode, m5.objects.PioDevice
):
return NodeType.DEV
elif isinstance(simNode, m5.objects.BaseXBar):
return NodeType.XBAR
@@ -213,6 +224,7 @@ def get_node_type(simNode):
else:
return NodeType.OTHER
# based on the node type, determine the colour as an RGB tuple, the
# palette is rather arbitrary at this point (some coherent natural
# tones), and someone that feels artistic should probably have a look
@@ -231,9 +243,10 @@ def get_type_colour(nodeType):
# use a relatively gray shade
return (186, 182, 174)
# generate colour for a node, either corresponding to a sim object or a
# port
def dot_gen_colour(simNode, isPort = False):
def dot_gen_colour(simNode, isPort=False):
# determine the type of the current node, and also its parent, if
# the node is not the same type as the parent then we use the base
# colour for its type
@@ -269,35 +282,38 @@ def dot_gen_colour(simNode, isPort = False):
return dot_rgb_to_html(r, g, b)
def dot_rgb_to_html(r, g, b):
return "#%.2x%.2x%.2x" % (int(r), int(g), int(b))
# We need to create all of the clock domains. We abuse the alpha channel to get
# the correct domain colouring.
def dot_add_clk_domain(c_dom, v_dom):
label = "\"" + str(c_dom) + "\ :\ " + str(v_dom) + "\""
label = re.sub('\.', '_', str(label))
full_path = re.sub('\.', '_', str(c_dom))
return pydot.Cluster( \
full_path, \
shape = "box", \
label = label, \
style = "\"rounded, filled, dashed\"", \
color = "#000000", \
fillcolor = "#AFC8AF8F", \
fontname = "Arial", \
fontsize = "14", \
fontcolor = "#000000" \
)
label = '"' + str(c_dom) + "\ :\ " + str(v_dom) + '"'
label = re.sub("\.", "_", str(label))
full_path = re.sub("\.", "_", str(c_dom))
return pydot.Cluster(
full_path,
shape="box",
label=label,
style='"rounded, filled, dashed"',
color="#000000",
fillcolor="#AFC8AF8F",
fontname="Arial",
fontsize="14",
fontcolor="#000000",
)
def dot_create_dvfs_nodes(simNode, callgraph, domain=None):
if isRoot(simNode):
label = "root"
else:
label = simNode._name
full_path = re.sub('\.', '_', simNode.path())
full_path = re.sub("\.", "_", simNode.path())
# add class name under the label
label = "\"" + label + " \\n: " + simNode.__class__.__name__ + "\""
label = '"' + label + " \\n: " + simNode.__class__.__name__ + '"'
# each component is a sub-graph (cluster)
cluster = dot_create_cluster(simNode, full_path, label)
@@ -316,12 +332,12 @@ def dot_create_dvfs_nodes(simNode, callgraph, domain=None):
# recurse to children
for child in simnode_children(simNode):
try:
c_dom = child.__getattr__('clk_domain')
v_dom = c_dom.__getattr__('voltage_domain')
c_dom = child.__getattr__("clk_domain")
v_dom = c_dom.__getattr__("voltage_domain")
except AttributeError:
# Just re-use the domain from above
c_dom = domain
v_dom = c_dom.__getattr__('voltage_domain')
v_dom = c_dom.__getattr__("voltage_domain")
pass
if c_dom == domain or c_dom == None:
@@ -339,16 +355,19 @@ def dot_create_dvfs_nodes(simNode, callgraph, domain=None):
callgraph.add_subgraph(cluster)
def do_dot(root, outdir, dotFilename):
if not pydot:
warn("No dot file generated. " +
"Please install pydot to generate the dot file and pdf.")
warn(
"No dot file generated. "
+ "Please install pydot to generate the dot file and pdf."
)
return
# * use ranksep > 1.0 for for vertical separation between nodes
# especially useful if you need to annotate edges using e.g. visio
# which accepts svg format
# * no need for hoizontal separation as nothing moves horizonally
callgraph = pydot.Dot(graph_type='digraph', ranksep='1.3')
callgraph = pydot.Dot(graph_type="digraph", ranksep="1.3")
dot_create_nodes(root, callgraph)
dot_create_edges(root, callgraph)
dot_filename = os.path.join(outdir, dotFilename)
@@ -361,16 +380,19 @@ def do_dot(root, outdir, dotFilename):
except:
warn("failed to generate dot output from %s", dot_filename)
def do_dvfs_dot(root, outdir, dotFilename):
if not pydot:
warn("No dot file generated. " +
"Please install pydot to generate the dot file and pdf.")
warn(
"No dot file generated. "
+ "Please install pydot to generate the dot file and pdf."
)
return
# There is a chance that we are unable to resolve the clock or
# voltage domains. If so, we fail silently.
try:
dvfsgraph = pydot.Dot(graph_type='digraph', ranksep='1.3')
dvfsgraph = pydot.Dot(graph_type="digraph", ranksep="1.3")
dot_create_dvfs_nodes(root, dvfsgraph)
dot_create_edges(root, dvfsgraph)
dot_filename = os.path.join(outdir, dotFilename)

View File

@@ -38,6 +38,7 @@
import os
import m5
from m5.util import warn
try:
import pydot
except:
@@ -47,55 +48,56 @@ except:
def _dot_rgb_to_html(r, g, b):
return "#%.2x%.2x%.2x" % (r, g, b)
def _dot_create_router_node(full_path, label):
return pydot.Node( \
full_path, \
shape = "Mrecord", \
label = label, \
style = "\"rounded, filled\"", \
color = "#000000", \
fillcolor = _dot_rgb_to_html(204, 230, 252), \
fontname = "Arial", \
fontsize = "14", \
fontcolor = "#000000" \
)
return pydot.Node(
full_path,
shape="Mrecord",
label=label,
style='"rounded, filled"',
color="#000000",
fillcolor=_dot_rgb_to_html(204, 230, 252),
fontname="Arial",
fontsize="14",
fontcolor="#000000",
)
def _dot_create_ctrl_node(full_path, label):
return pydot.Node( \
full_path, \
shape = "Mrecord", \
label = label, \
style = "\"rounded, filled\"", \
color = "#000000", \
fillcolor = _dot_rgb_to_html(229, 188, 208), \
fontname = "Arial", \
fontsize = "14", \
fontcolor = "#000000" \
)
return pydot.Node(
full_path,
shape="Mrecord",
label=label,
style='"rounded, filled"',
color="#000000",
fillcolor=_dot_rgb_to_html(229, 188, 208),
fontname="Arial",
fontsize="14",
fontcolor="#000000",
)
def _dot_create_int_edge(src, dst):
return pydot.Edge(src, dst,
weight = .5,
color = '#042d50',
dir = 'forward')
return pydot.Edge(src, dst, weight=0.5, color="#042d50", dir="forward")
def _dot_create_ext_edge(src, dst):
return pydot.Edge(src, dst,
weight = 1.0,
color = '#381526',
dir = 'both')
return pydot.Edge(src, dst, weight=1.0, color="#381526", dir="both")
def _dot_create(network, callgraph):
for r in network.routers:
callgraph.add_node(_dot_create_router_node(r.path(),
'R %d' % r.router_id))
callgraph.add_node(
_dot_create_router_node(r.path(), "R %d" % r.router_id)
)
# One link for each direction but draw one edge only
connected = dict()
for link in network.int_links:
if (link.src_node.path() in connected) and \
(connected[link.src_node.path()] == link.dst_node.path()):
continue
if (link.src_node.path() in connected) and (
connected[link.src_node.path()] == link.dst_node.path()
):
continue
callgraph.add_edge(
_dot_create_int_edge(link.src_node.path(), link.dst_node.path())
)
@@ -106,44 +108,45 @@ def _dot_create(network, callgraph):
rpaths = [link.ext_node.path()[::-1] for link in network.ext_links]
preffix = os.path.commonprefix(paths)
suffix = os.path.commonprefix(rpaths)[::-1]
def strip_right(text, suffix):
if not text.endswith(suffix):
return text
return text[:len(text)-len(suffix)]
return text[: len(text) - len(suffix)]
def strip_left(text, prefix):
if not text.startswith(prefix):
return text
return text[len(prefix):]
return text[len(prefix) :]
for link in network.ext_links:
ctrl = link.ext_node
label = strip_right(strip_left(ctrl.path(), preffix), suffix)
if hasattr(ctrl, '_node_type'):
label += ' (' + ctrl._node_type + ')'
callgraph.add_node(
_dot_create_ctrl_node(ctrl.path(), label)
if hasattr(ctrl, "_node_type"):
label += " (" + ctrl._node_type + ")"
callgraph.add_node(_dot_create_ctrl_node(ctrl.path(), label))
callgraph.add_edge(
_dot_create_ext_edge(link.ext_node.path(), link.int_node.path())
)
callgraph.add_edge(_dot_create_ext_edge(
link.ext_node.path(), link.int_node.path()))
def _do_dot(network, outdir, dotFilename):
callgraph = pydot.Dot(graph_type='graph', rankdir='LR')
callgraph = pydot.Dot(graph_type="graph", rankdir="LR")
_dot_create(network, callgraph)
dot_filename = os.path.join(outdir, dotFilename)
callgraph.write(dot_filename)
try:
# dot crashes if the figure is extremely wide.
# So avoid terminating simulation unnecessarily
callgraph.write_svg(dot_filename + ".svg", prog='neato')
callgraph.write_pdf(dot_filename + ".pdf", prog='neato')
callgraph.write_svg(dot_filename + ".svg", prog="neato")
callgraph.write_pdf(dot_filename + ".pdf", prog="neato")
except:
warn("failed to generate dot output from %s", dot_filename)
def do_ruby_dot(root, outdir, dotFilename):
RubyNetwork = getattr(m5.objects, 'RubyNetwork', None)
RubyNetwork = getattr(m5.objects, "RubyNetwork", None)
if not pydot or not RubyNetwork:
return
@@ -154,6 +157,7 @@ def do_ruby_dot(root, outdir, dotFilename):
for network in filter(is_ruby_network, root.descendants()):
# We assume each ruby system has a single network.
rubydotFilename = dotFilename.replace(".dot",
"." + network.get_parent().path() + ".dot")
rubydotFilename = dotFilename.replace(
".dot", "." + network.get_parent().path() + ".dot"
)
_do_dot(network, outdir, rubydotFilename)

View File

@@ -41,12 +41,16 @@ import os
from m5.SimObject import SimObject
from m5.util import fatal
class FdtProperty(pyfdt.FdtProperty):
"""Create a property without values."""
pass
class FdtPropertyWords(pyfdt.FdtPropertyWords):
"""Create a property with word (32-bit unsigned) values."""
def __init__(self, name, words):
if type(words) != list:
words = [words]
@@ -55,15 +59,19 @@ class FdtPropertyWords(pyfdt.FdtPropertyWords):
words = [int(w, base=0) if type(w) == str else int(w) for w in words]
super().__init__(name, words)
class FdtPropertyStrings(pyfdt.FdtPropertyStrings):
"""Create a property with string values."""
def __init__(self, name, strings):
if type(strings) == str:
strings = [strings]
strings = [str(string) for string in strings] # Make all values strings
strings = [
str(string) for string in strings
] # Make all values strings
super().__init__(name, strings)
class FdtPropertyBytes(pyfdt.FdtPropertyBytes):
"""Create a property with integer (8-bit signed) values."""
@@ -72,10 +80,12 @@ class FdtPropertyBytes(pyfdt.FdtPropertyBytes):
values = [values]
# Make sure all values are ints (use automatic base detection if the
# type is str)
values = [int(v, base=0)
if isinstance(v, str) else int(v) for v in values]
values = [
int(v, base=0) if isinstance(v, str) else int(v) for v in values
]
super().__init__(name, values)
class FdtState(object):
"""Class for maintaining state while recursively generating a flattened
device tree. The state tracks address, size and CPU address cell sizes, and
@@ -88,10 +98,10 @@ class FdtState(object):
"""Instantiate values of this state. The state can only be initialized
once."""
self.addr_cells = kwargs.pop('addr_cells', 0)
self.size_cells = kwargs.pop('size_cells', 0)
self.cpu_cells = kwargs.pop('cpu_cells', 0)
self.interrupt_cells = kwargs.pop('interrupt_cells', 0)
self.addr_cells = kwargs.pop("addr_cells", 0)
self.size_cells = kwargs.pop("size_cells", 0)
self.cpu_cells = kwargs.pop("cpu_cells", 0)
self.interrupt_cells = kwargs.pop("interrupt_cells", 0)
def phandle(self, obj):
"""Return a unique phandle number for a key. The key can be a SimObject
@@ -104,7 +114,7 @@ class FdtState(object):
try:
key = str(obj)
except ValueError:
raise ValueError('Phandle keys must be castable to str')
raise ValueError("Phandle keys must be castable to str")
if not key in FdtState.phandles:
FdtState.phandle_counter += 1
@@ -123,7 +133,9 @@ class FdtState(object):
if (value >> (32 * cells)) != 0:
fatal("Value %d doesn't fit in %d cells" % (value, cells))
return [(value >> 32*(x-1)) & 0xFFFFFFFF for x in range(cells, 0, -1)]
return [
(value >> 32 * (x - 1)) & 0xFFFFFFFF for x in range(cells, 0, -1)
]
def addrCells(self, addr):
"""Format an integer type according to the address_cells value of this
@@ -166,8 +178,10 @@ class FdtState(object):
class FdtNop(pyfdt.FdtNop):
"""Create an empty node."""
pass
class FdtNode(pyfdt.FdtNode):
def __init__(self, name, obj=None):
"""Create a new node and immediately set the phandle property, if obj
@@ -180,7 +194,7 @@ class FdtNode(pyfdt.FdtNode):
"""Change the behavior of the normal append to override if a node with
the same name already exists or merge if the name exists and is a node
type. Can also take a list of subnodes, that each get appended."""
if not hasattr(subnodes, '__iter__'):
if not hasattr(subnodes, "__iter__"):
subnodes = [subnodes]
for subnode in subnodes:
@@ -193,8 +207,9 @@ class FdtNode(pyfdt.FdtNode):
except ValueError:
item = None
if isinstance(item, pyfdt.FdtNode) and \
isinstance(subnode, pyfdt.FdtNode):
if isinstance(item, pyfdt.FdtNode) and isinstance(
subnode, pyfdt.FdtNode
):
item.merge(subnode)
subnode = item
@@ -210,7 +225,7 @@ class FdtNode(pyfdt.FdtNode):
strings."""
if isinstance(compatible, str):
compatible = [compatible]
self.append(FdtPropertyStrings('compatible', compatible))
self.append(FdtPropertyStrings("compatible", compatible))
def appendPhandle(self, obj):
"""Append a phandle property to this node with the phandle of the
@@ -221,6 +236,7 @@ class FdtNode(pyfdt.FdtNode):
phandle = state.phandle(obj)
self.append(FdtPropertyWords("phandle", [phandle]))
class Fdt(pyfdt.Fdt):
def sortNodes(self, node):
"""Move all properties to the beginning and subnodes to the end
@@ -251,7 +267,7 @@ class Fdt(pyfdt.Fdt):
"""Convert the device tree to DTB and write to a file."""
filename = os.path.realpath(filename)
try:
with open(filename, 'wb') as f:
with open(filename, "wb") as f:
f.write(self.to_dtb())
return filename
except IOError:
@@ -261,7 +277,7 @@ class Fdt(pyfdt.Fdt):
"""Convert the device tree to DTS and write to a file."""
filename = os.path.realpath(filename)
try:
with open(filename, 'w') as f:
with open(filename, "w") as f:
f.write(self.to_dts())
return filename
except IOError:

View File

@@ -24,10 +24,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
__all__ = [ 'multidict' ]
__all__ = ["multidict"]
class multidict(object):
def __init__(self, parent = {}, **kwargs):
def __init__(self, parent={}, **kwargs):
self.local = dict(**kwargs)
self.parent = parent
self.deleted = {}
@@ -67,13 +68,13 @@ class multidict(object):
return len(self.local) + len(self.parent)
def next(self):
for key,value in self.local.items():
yield key,value
for key, value in self.local.items():
yield key, value
if self.parent:
for key,value in self.parent.next():
for key, value in self.parent.next():
if key not in self.local and key not in self.deleted:
yield key,value
yield key, value
def has_key(self, key):
return key in self
@@ -83,11 +84,11 @@ class multidict(object):
yield item
def keys(self):
for key,value in self.next():
for key, value in self.next():
yield key
def values(self):
for key,value in self.next():
for key, value in self.next():
yield value
def get(self, key, default=None):
@@ -105,10 +106,10 @@ class multidict(object):
return default
def _dump(self):
print('multidict dump')
print("multidict dump")
node = self
while isinstance(node, multidict):
print(' ', node.local)
print(" ", node.local)
node = node.parent
def _dumpkey(self, key):
@@ -120,52 +121,53 @@ class multidict(object):
node = node.parent
print(key, values)
if __name__ == '__main__':
if __name__ == "__main__":
test1 = multidict()
test2 = multidict(test1)
test3 = multidict(test2)
test4 = multidict(test3)
test1['a'] = 'test1_a'
test1['b'] = 'test1_b'
test1['c'] = 'test1_c'
test1['d'] = 'test1_d'
test1['e'] = 'test1_e'
test1["a"] = "test1_a"
test1["b"] = "test1_b"
test1["c"] = "test1_c"
test1["d"] = "test1_d"
test1["e"] = "test1_e"
test2['a'] = 'test2_a'
del test2['b']
test2['c'] = 'test2_c'
del test1['a']
test2["a"] = "test2_a"
del test2["b"]
test2["c"] = "test2_c"
del test1["a"]
test2.setdefault('f', multidict)
test2.setdefault("f", multidict)
print('test1>', list(test1.items()))
print('test2>', list(test2.items()))
#print(test1['a'])
print(test1['b'])
print(test1['c'])
print(test1['d'])
print(test1['e'])
print("test1>", list(test1.items()))
print("test2>", list(test2.items()))
# print(test1['a'])
print(test1["b"])
print(test1["c"])
print(test1["d"])
print(test1["e"])
print(test2['a'])
#print(test2['b'])
print(test2['c'])
print(test2['d'])
print(test2['e'])
print(test2["a"])
# print(test2['b'])
print(test2["c"])
print(test2["d"])
print(test2["e"])
for key in test2.keys():
print(key)
test2.get('g', 'foo')
#test2.get('b')
test2.get('b', 'bar')
test2.setdefault('b', 'blah')
test2.get("g", "foo")
# test2.get('b')
test2.get("b", "bar")
test2.setdefault("b", "blah")
print(test1)
print(test2)
print(repr(test2))
print(len(test2))
test3['a'] = [ 0, 1, 2, 3 ]
test3["a"] = [0, 1, 2, 3]
print(test4)

View File

@@ -35,11 +35,13 @@
from abc import *
class PyBindExport(object, metaclass=ABCMeta):
@abstractmethod
def export(self, code, cname):
pass
class PyBindProperty(PyBindExport):
def __init__(self, name, cxx_name=None, writable=True):
self.name = name
@@ -50,14 +52,21 @@ class PyBindProperty(PyBindExport):
export = "def_readwrite" if self.writable else "def_readonly"
code('.${export}("${{self.name}}", &${cname}::${{self.cxx_name}})')
class PyBindMethod(PyBindExport):
def __init__(self, name, cxx_name=None, args=None,
return_value_policy=None, static=False):
def __init__(
self,
name,
cxx_name=None,
args=None,
return_value_policy=None,
static=False,
):
self.name = name
self.cxx_name = cxx_name if cxx_name else name
self.args = args
self.return_value_policy = return_value_policy
self.method_def = 'def_static' if static else 'def'
self.method_def = "def_static" if static else "def"
def _conv_arg(self, value):
if isinstance(value, bool):
@@ -68,18 +77,23 @@ class PyBindMethod(PyBindExport):
raise TypeError("Unsupported PyBind default value type")
def export(self, code, cname):
arguments = [ '"${{self.name}}"', '&${cname}::${{self.cxx_name}}' ]
arguments = ['"${{self.name}}"', "&${cname}::${{self.cxx_name}}"]
if self.return_value_policy:
arguments.append('pybind11::return_value_policy::'
'${{self.return_value_policy}}')
arguments.append(
"pybind11::return_value_policy::"
"${{self.return_value_policy}}"
)
if self.args:
def get_arg_decl(arg):
if isinstance(arg, tuple):
name, default = arg
return 'py::arg("%s") = %s' % (
name, self._conv_arg(default))
name,
self._conv_arg(default),
)
else:
return 'py::arg("%s")' % arg
arguments.extend(list([ get_arg_decl(a) for a in self.args ]))
code('.' + self.method_def + '(' + ', '.join(arguments) + ')')
arguments.extend(list([get_arg_decl(a) for a in self.args]))
code("." + self.method_def + "(" + ", ".join(arguments) + ")")

View File

@@ -52,39 +52,47 @@ color_names = "Black Red Green Yellow Blue Magenta Cyan".split()
# Please feel free to add information about other terminals here.
#
capability_map = {
'Bold': 'bold',
'Dim': 'dim',
'Blink': 'blink',
'Underline': 'smul',
'Reverse': 'rev',
'Standout': 'smso',
'Normal': 'sgr0'
"Bold": "bold",
"Dim": "dim",
"Blink": "blink",
"Underline": "smul",
"Reverse": "rev",
"Standout": "smso",
"Normal": "sgr0",
}
capability_names = list(capability_map.keys())
def null_cap_string(s, *args):
return ''
return ""
try:
import curses
curses.setupterm()
def cap_string(s, *args):
cap = curses.tigetstr(s)
if cap:
return curses.tparm(cap, *args).decode('utf-8')
return curses.tparm(cap, *args).decode("utf-8")
else:
return ''
return ""
except:
cap_string = null_cap_string
class ColorStrings(object):
def __init__(self, cap_string):
for i, c in enumerate(color_names):
setattr(self, c, cap_string('setaf', i))
setattr(self, c, cap_string("setaf", i))
for name, cap in capability_map.items():
setattr(self, name, cap_string(cap))
termcap = ColorStrings(cap_string)
no_termcap = ColorStrings(null_cap_string)
@@ -93,7 +101,8 @@ if sys.stdout.isatty():
else:
tty_termcap = no_termcap
def get_termcap(use_colors = None):
def get_termcap(use_colors=None):
if use_colors:
return termcap
elif use_colors is None:
@@ -102,19 +111,27 @@ def get_termcap(use_colors = None):
else:
return no_termcap
def test_termcap(obj):
for c_name in color_names:
c_str = getattr(obj, c_name)
print(c_str + c_name + obj.Normal)
for attr_name in capability_names:
if attr_name == 'Normal':
if attr_name == "Normal":
continue
attr_str = getattr(obj, attr_name)
print(attr_str + c_str + attr_name + " " + c_name + obj.Normal)
print(obj.Bold + obj.Underline +
c_name + "Bold Underline " + c + obj.Normal)
print(
obj.Bold
+ obj.Underline
+ c_name
+ "Bold Underline "
+ c
+ obj.Normal
)
if __name__ == '__main__':
if __name__ == "__main__":
print("=== termcap enabled ===")
test_termcap(termcap)
print(termcap.Normal)

View File

@@ -26,8 +26,8 @@
import textwrap
class TerminalFormatter:
class TerminalFormatter:
def __init__(self, max_width=80):
# text_width holds the actual width we'll be wrapping to.
# This takes into account the current terminal size.
@@ -35,9 +35,13 @@ class TerminalFormatter:
def __terminal_size(self):
import fcntl, termios, struct
h, w, hp, wp = struct.unpack('HHHH',
fcntl.ioctl(0, termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0)))
h, w, hp, wp = struct.unpack(
"HHHH",
fcntl.ioctl(
0, termios.TIOCGWINSZ, struct.pack("HHHH", 0, 0, 0, 0)
),
)
return w, h
def __get_paragraphs(self, text, flatten=False):
@@ -74,15 +78,17 @@ class TerminalFormatter:
for line in text.splitlines():
stripped = line.strip()
if not stripped: #I.e. a blank line.
if not stripped: # I.e. a blank line.
paragraphs.append(
{False: "\n", True: " "}[flatten].join(cur_paragraph))
{False: "\n", True: " "}[flatten].join(cur_paragraph)
)
cur_paragraph = []
else:
cur_paragraph.append(stripped)
paragraphs.append(
{False: "\n", True: " "}[flatten].join(cur_paragraph))
{False: "\n", True: " "}[flatten].join(cur_paragraph)
)
return paragraphs
@@ -115,15 +121,19 @@ class TerminalFormatter:
paragraphs = self.__get_paragraphs(text, True)
# Wrap and Indent the paragraphs
wrapper = textwrap.TextWrapper(width =
max((self.__text_width - indent),1))
wrapper = textwrap.TextWrapper(
width=max((self.__text_width - indent), 1)
)
# The first paragraph is special case due to the inclusion of the label
formatted_paragraphs = [' ' * max((indent - len(label)),0) \
+ label + wrapper.wrap(paragraphs[0])[0]]
formatted_paragraphs = [
" " * max((indent - len(label)), 0)
+ label
+ wrapper.wrap(paragraphs[0])[0]
]
for paragraph in paragraphs:
for line in wrapper.wrap(paragraph[1:])[1:]:
formatted_paragraphs.append(' ' * indent + line)
formatted_paragraphs.append('\n')
formatted_paragraphs.append(" " * indent + line)
formatted_paragraphs.append("\n")
# Remove the last line break
return '\n'.join(formatted_paragraphs[:-1])
return "\n".join(formatted_paragraphs[:-1])