misc, stdlib: Update documentation to adhere to RST formatting. (#631)
This PR updates files in `src/python` to adhere to reStructuredText formatting.
This commit is contained in:
@@ -59,7 +59,7 @@ class AbstractBoard:
|
||||
Boards are used as the object which can connect together all other
|
||||
components. This abstract class defines the external interface that other
|
||||
boards must provide. Boards can be specialized for different ISAs or system
|
||||
designs (e.g., core counts, cache types, memory channels, I/O devices, etc)
|
||||
designs (e.g., core counts, cache types, memory channels, I/O devices, etc).
|
||||
|
||||
In addition to providing the place that system components are connected,
|
||||
the board also exposes an interface for the caches, processor, and memory
|
||||
@@ -68,7 +68,7 @@ class AbstractBoard:
|
||||
The board also exposes an interface to set up I/O devices which needs to be
|
||||
specialized for each ISA and/or platform.
|
||||
|
||||
Board inherits from System and can therefore be used as a System simobject
|
||||
Board inherits from System and can therefore be used as a System SimObject
|
||||
when required.
|
||||
"""
|
||||
|
||||
@@ -87,7 +87,7 @@ class AbstractBoard:
|
||||
:param memory: The memory for this board.
|
||||
:param cache_hierarchy: The Cache Hierarchy for this board.
|
||||
In some boards caches can be optional. If so,
|
||||
that board must override `_connect_things`.
|
||||
that board must override ``_connect_things``.
|
||||
"""
|
||||
|
||||
if not isinstance(self, System):
|
||||
@@ -143,8 +143,10 @@ class AbstractBoard:
|
||||
def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]:
|
||||
"""Get the memory ports exposed on this board
|
||||
|
||||
Note: The ports should be returned such that the address ranges are
|
||||
in ascending order.
|
||||
.. note::
|
||||
|
||||
The ports should be returned such that the address ranges are
|
||||
in ascending order.
|
||||
"""
|
||||
return self.get_memory().get_mem_ports()
|
||||
|
||||
@@ -175,6 +177,7 @@ class AbstractBoard:
|
||||
|
||||
def get_clock_domain(self) -> ClockDomain:
|
||||
"""Get the clock domain.
|
||||
|
||||
:returns: The clock domain.
|
||||
"""
|
||||
return self.clk_domain
|
||||
@@ -192,7 +195,7 @@ class AbstractBoard:
|
||||
|
||||
def is_fullsystem(self) -> bool:
|
||||
"""
|
||||
Returns True if the board is to be run in FS mode. Otherwise the board
|
||||
Returns ``True`` if the board is to be run in FS mode. Otherwise the board
|
||||
is to be run in Se mode. An exception will be thrown if this has not
|
||||
been set.
|
||||
|
||||
@@ -213,10 +216,10 @@ class AbstractBoard:
|
||||
Set the workload for this board to run.
|
||||
|
||||
This function will take the workload specified and run the correct
|
||||
workload function (e.g., `set_kernel_disk_workload`) with the correct
|
||||
workload function (e.g., ``set_kernel_disk_workload``) with the correct
|
||||
parameters
|
||||
|
||||
:params workload: The workload to be set to this board.
|
||||
:param workload: The workload to be set to this board.
|
||||
"""
|
||||
|
||||
try:
|
||||
@@ -244,7 +247,7 @@ class AbstractBoard:
|
||||
"""
|
||||
This function is called in the AbstractBoard constructor, before the
|
||||
memory, processor, and cache hierarchy components are incorporated via
|
||||
`_connect_thing()`, but after the `_setup_memory_ranges()` function.
|
||||
``_connect_thing()``, but after the ``_setup_memory_ranges()`` function.
|
||||
This function should be overridden by boards to specify components,
|
||||
connections unique to that board.
|
||||
"""
|
||||
@@ -257,7 +260,7 @@ class AbstractBoard:
|
||||
def has_dma_ports(self) -> bool:
|
||||
"""Determine whether the board has DMA ports or not.
|
||||
|
||||
:returns: True if the board has DMA ports, otherwise False.
|
||||
:returns: ``True`` if the board has DMA ports, otherwise ``False``.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -276,13 +279,14 @@ class AbstractBoard:
|
||||
def has_io_bus(self) -> bool:
|
||||
"""Determine whether the board has an IO bus or not.
|
||||
|
||||
:returns: True if the board has an IO bus, otherwise False.
|
||||
:returns: ``True`` if the board has an IO bus, otherwise ``False``.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_io_bus(self) -> IOXBar:
|
||||
"""Get the board's IO Bus.
|
||||
|
||||
This abstract method must be implemented within the subclasses if they
|
||||
support DMA and/or full system simulation.
|
||||
|
||||
@@ -299,14 +303,15 @@ class AbstractBoard:
|
||||
def has_coherent_io(self) -> bool:
|
||||
"""Determine whether the board needs coherent I/O
|
||||
|
||||
:returns: True if the board needs coherent I/O, false otherwise
|
||||
:returns: ``True`` if the board needs coherent I/O, ``False`` otherwise.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_mem_side_coherent_io_port(self):
|
||||
"""Get the memory-side coherent I/O port.
|
||||
This abstract method must be implemented if has_coherent_io is true.
|
||||
|
||||
This abstract method must be implemented if ``has_coherent_io`` is ``True``.
|
||||
|
||||
This returns a *port* (not a bus) that should be connected to a
|
||||
CPU-side port for which coherent I/O (DMA) is issued.
|
||||
@@ -318,8 +323,8 @@ class AbstractBoard:
|
||||
"""
|
||||
Set the memory ranges for this board and memory system.
|
||||
|
||||
This is called in the constructor, prior to `_setup_board` and
|
||||
`_connect_things`. It should query the board's memory to determine the
|
||||
This is called in the constructor, prior to ``_setup_board`` and
|
||||
``_connect_things``. It should query the board's memory to determine the
|
||||
size and the set the memory ranges on the memory system and on the
|
||||
board.
|
||||
|
||||
@@ -327,11 +332,11 @@ class AbstractBoard:
|
||||
of memory and memory system's range to be the same as the board. Full
|
||||
system implementations will likely need something more complicated.
|
||||
|
||||
Notes
|
||||
-----
|
||||
* This *must* be called prior to the incorporation of the cache
|
||||
hierarchy (via `_connect_things`) as cache hierarchies depend upon
|
||||
knowing the memory system's ranges.
|
||||
.. note::
|
||||
|
||||
This *must* be called prior to the incorporation of the cache
|
||||
hierarchy (via ``_connect_things``) as cache hierarchies depend upon
|
||||
knowing the memory system's ranges.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -346,14 +351,13 @@ class AbstractBoard:
|
||||
|
||||
Developers may build upon this assumption when creating components.
|
||||
|
||||
Notes
|
||||
-----
|
||||
.. note::
|
||||
|
||||
* The processor is incorporated after the cache hierarchy due to a bug
|
||||
noted here: https://gem5.atlassian.net/browse/GEM5-1113. Until this
|
||||
bug is fixed, this ordering must be maintained.
|
||||
* Once this function is called `_connect_things_called` *must* be set
|
||||
to `True`.
|
||||
* The processor is incorporated after the cache hierarchy due to a bug
|
||||
noted here: https://gem5.atlassian.net/browse/GEM5-1113. Until this
|
||||
bug is fixed, this ordering must be maintained.
|
||||
* Once this function is called ``_connect_things_called`` *must* be set
|
||||
to ``True``.
|
||||
"""
|
||||
|
||||
if self._connect_things_called:
|
||||
@@ -374,15 +378,15 @@ class AbstractBoard:
|
||||
self._connect_things_called = True
|
||||
|
||||
def _post_instantiate(self):
|
||||
"""Called to set up anything needed after m5.instantiate"""
|
||||
"""Called to set up anything needed after ``m5.instantiate``."""
|
||||
self.get_processor()._post_instantiate()
|
||||
if self.get_cache_hierarchy():
|
||||
self.get_cache_hierarchy()._post_instantiate()
|
||||
self.get_memory()._post_instantiate()
|
||||
|
||||
def _pre_instantiate(self):
|
||||
"""To be called immediately before m5.instantiate. This is where
|
||||
`_connect_things` is executed by default."""
|
||||
"""To be called immediately before ``m5.instantiate``. This is where
|
||||
``_connect_things`` is executed by default."""
|
||||
|
||||
# Connect the memory, processor, and cache hierarchy.
|
||||
self._connect_things()
|
||||
@@ -392,28 +396,28 @@ class AbstractBoard:
|
||||
Here we check that connect things has been called and throw an
|
||||
Exception if it has not.
|
||||
|
||||
Since v22.1 `_connect_things` function has
|
||||
Since v22.1 ``_connect_things`` function has
|
||||
been moved from the AbstractBoard constructor to the
|
||||
`_pre_instantation` function. Users who have used the gem5 stdlib
|
||||
``_pre_instantation`` function. Users who have used the gem5 stdlib
|
||||
components (i.e., boards which inherit from AbstractBoard) and the
|
||||
Simulator module should notice no change. Those who do not use the
|
||||
Simulator module and instead called `m5.instantiate` directly must
|
||||
call `AbstractBoard._pre_instantation` prior so `_connect_things` is
|
||||
Simulator module and instead called ``m5.instantiate`` directly must
|
||||
call ``AbstractBoard._pre_instantation`` prior to ``_connect_things`` is
|
||||
called. In order to avoid confusion, this check has been incorporated
|
||||
and the Exception thrown explains the fix needed to convert old scripts
|
||||
to function with v22.1.
|
||||
to function with `v22.1`.
|
||||
|
||||
This function is called in `AbstractSystemBoard.createCCObject` and
|
||||
ArmBoard.createCCObject`. Both these functions override
|
||||
`SimObject.createCCObject`. We can not do that here as AbstractBoard
|
||||
This function is called in ``AbstractSystemBoard.createCCObject`` and
|
||||
``ArmBoard.createCCObject``. Both these functions override
|
||||
``SimObject.createCCObject``. We can not do that here as AbstractBoard
|
||||
does not inherit form System.
|
||||
"""
|
||||
if not self._connect_things_called:
|
||||
raise Exception(
|
||||
"""
|
||||
AbstractBoard's `_connect_things` function has not been called. This is likely
|
||||
AbstractBoard's ``_connect_things`` function has not been called. This is likely
|
||||
due to not running a board outside of the gem5 Standard Library Simulator
|
||||
module. If this is the case, this can be resolved by calling
|
||||
`<AbstractBoard>._pre_instantiate()` prior to `m5.instantiate()`.
|
||||
``<AbstractBoard>._pre_instantiate()`` prior to ``m5.instantiate()``.
|
||||
"""
|
||||
)
|
||||
|
||||
@@ -61,8 +61,8 @@ class AbstractSystemBoard(System, AbstractBoard):
|
||||
|
||||
@overrides(SimObject)
|
||||
def createCCObject(self):
|
||||
"""We override this function as it is called in `m5.instantiate`. This
|
||||
means we can insert a check to ensure the `_connect_things` function
|
||||
"""We override this function as it is called in ``m5.instantiate``. This
|
||||
means we can insert a check to ensure the ``_connect_things`` function
|
||||
has been run.
|
||||
"""
|
||||
super()._connect_things_check()
|
||||
|
||||
@@ -194,7 +194,7 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload):
|
||||
|
||||
def _setup_io_devices(self) -> None:
|
||||
"""
|
||||
This method first sets up the platform. ARM uses `realview` platform.
|
||||
This method first sets up the platform. ARM uses ``realview`` platform.
|
||||
Most of the on-chip and off-chip devices are setup by the realview
|
||||
platform. Once realview is setup, we connect the I/O devices to the
|
||||
I/O bus.
|
||||
@@ -334,16 +334,19 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload):
|
||||
self.generateDtb(self._get_dtb_filename())
|
||||
|
||||
def _get_dtb_filename(self) -> str:
|
||||
"""Returns the dtb file location.
|
||||
"""Returns the ``dtb`` file location.
|
||||
|
||||
**Note**: This may be the _expected_ file location when generated. A
|
||||
file may not exist at this location when this function is called."""
|
||||
.. note::
|
||||
|
||||
This may be the ``_expected_`` file location when generated. A
|
||||
file may not exist at this location when this function is called.
|
||||
"""
|
||||
|
||||
return os.path.join(m5.options.outdir, "device.dtb")
|
||||
|
||||
def _add_pci_device(self, pci_device: PciVirtIO) -> None:
|
||||
"""Attaches the PCI Device to the board. All devices will be added to
|
||||
`self.pci_device` as a pre-instantiation setup.
|
||||
``self.pci_device`` as a pre-instantiation setup.
|
||||
|
||||
:param pci_device: The PCI Device to add.
|
||||
"""
|
||||
@@ -374,7 +377,7 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload):
|
||||
def _setup_memory_ranges(self) -> None:
|
||||
"""
|
||||
The ArmBoard's memory can only be setup after realview is setup. We set
|
||||
this up in the `_setup_board` function.
|
||||
this up in the ``_setup_board`` function.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -393,8 +396,8 @@ class ArmBoard(ArmSystem, AbstractBoard, KernelDiskWorkload):
|
||||
|
||||
@overrides(SimObject)
|
||||
def createCCObject(self):
|
||||
"""We override this function as it is called in `m5.instantiate`. This
|
||||
means we can insert a check to ensure the `_connect_things` function
|
||||
"""We override this function as it is called in ``m5.instantiate``. This
|
||||
means we can insert a check to ensure the ``_connect_things`` function
|
||||
has been run.
|
||||
"""
|
||||
super()._connect_things_check()
|
||||
|
||||
@@ -216,7 +216,7 @@ class LupvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
]
|
||||
|
||||
def _setup_io_devices(self) -> None:
|
||||
"""Connect the I/O devices to the I/O bus"""
|
||||
"""Connect the I/O devices to the I/O bus."""
|
||||
for device in self._off_chip_devices:
|
||||
device.pio = self.iobus.mem_side_ports
|
||||
self.lupio_blk.dma = self.iobus.cpu_side_ports
|
||||
@@ -234,7 +234,7 @@ class LupvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
]
|
||||
|
||||
def _setup_pma(self) -> None:
|
||||
"""Set the PMA devices on each core"""
|
||||
"""Set the PMA devices on each core."""
|
||||
uncacheable_range = [
|
||||
AddrRange(dev.pio_addr, size=dev.pio_size)
|
||||
for dev in self._on_chip_devices + self._off_chip_devices
|
||||
@@ -278,9 +278,11 @@ class LupvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
memory.set_memory_range(self.mem_ranges)
|
||||
|
||||
def _generate_device_tree(self, outdir: str) -> None:
|
||||
"""Creates the dtb and dts files.
|
||||
Creates two files in the outdir: 'device.dtb' and 'device.dts'
|
||||
:param outdir: Directory to output the files
|
||||
"""Creates the ``dtb`` and ``dts`` files.
|
||||
|
||||
Creates two files in the outdir: ``device.dtb`` and ``device.dts``.
|
||||
|
||||
:param outdir: Directory to output the files.
|
||||
"""
|
||||
state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1)
|
||||
root = FdtNode("/")
|
||||
|
||||
@@ -53,25 +53,25 @@ class KernelDiskWorkload:
|
||||
added as a superclass to a board and the abstract methods implemented.
|
||||
E.g.:
|
||||
|
||||
```
|
||||
class X86Board(AbstractBoard, KernelDiskWorkload):
|
||||
...
|
||||
@overrides(KernelDiskWorkload)
|
||||
def get_default_kernel_args(self) -> List[str]:
|
||||
return [
|
||||
"earlyprintk=ttyS0",
|
||||
"console=ttyS0",
|
||||
"lpj=7999923",
|
||||
"root={root_value}",
|
||||
]
|
||||
...
|
||||
```
|
||||
.. code-block:: python
|
||||
|
||||
Notes
|
||||
-----
|
||||
class X86Board(AbstractBoard, KernelDiskWorkload):
|
||||
...
|
||||
@overrides(KernelDiskWorkload)
|
||||
def get_default_kernel_args(self) -> List[str]:
|
||||
return [
|
||||
"earlyprintk=ttyS0",
|
||||
"console=ttyS0",
|
||||
"lpj=7999923",
|
||||
"root={root_value}",
|
||||
]
|
||||
...
|
||||
|
||||
* This assumes only one disk is set.
|
||||
* This assumes the Linux kernel is used.
|
||||
|
||||
.. note::
|
||||
|
||||
* This assumes only one disk is set.
|
||||
* This assumes the Linux kernel is used.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
@@ -79,9 +79,9 @@ class KernelDiskWorkload:
|
||||
"""
|
||||
Returns a default list of arguments for the workload kernel. We assume
|
||||
the following strings may be used as placeholders, to be replaced when
|
||||
`set_kernel_disk_workload` is executed:
|
||||
``set_kernel_disk_workload`` is executed:
|
||||
|
||||
* `{root_value}` : set to `get_default_kernel_root_val()`.
|
||||
* `{root_value}` : set to ``get_default_kernel_root_val()``.
|
||||
|
||||
:returns: A default list of arguments for the workload kernel.
|
||||
"""
|
||||
@@ -101,8 +101,10 @@ class KernelDiskWorkload:
|
||||
"""
|
||||
Sets the configuration needed to add the disk image to the board.
|
||||
|
||||
**Note:** This will be executed at the end of the
|
||||
`set_kernel_disk_workload` function.
|
||||
.. note::
|
||||
|
||||
This will be executed at the end of the
|
||||
``set_kernel_disk_workload`` function.
|
||||
|
||||
:param disk_image: The disk image to add to the system.
|
||||
"""
|
||||
@@ -124,14 +126,14 @@ class KernelDiskWorkload:
|
||||
) -> str:
|
||||
"""
|
||||
Get the default kernel root value to be passed to the kernel. This is
|
||||
determined by the value implemented in the `get_disk_device()`
|
||||
determined by the value implemented in the ``get_disk_device()``
|
||||
function, and the disk image partition, obtained from
|
||||
`get_disk_root_partition()`
|
||||
|
||||
``get_disk_root_partition()``
|
||||
|
||||
:param disk_image: The disk image to be added to the system.
|
||||
:returns: The default value for the 'root' argument to be passed to the
|
||||
kernel.
|
||||
|
||||
:returns: The default value for the ``root`` argument to be passed to the
|
||||
kernel.
|
||||
"""
|
||||
return self.get_disk_device() + (
|
||||
self.get_disk_root_partition(disk_image) or ""
|
||||
@@ -156,19 +158,23 @@ class KernelDiskWorkload:
|
||||
:param kernel: The kernel to boot.
|
||||
:param disk_image: The disk image to mount.
|
||||
:param bootloader: The current implementation of the ARM board requires
|
||||
three resources to operate -- kernel, disk image, and, a bootloader.
|
||||
three resources to operate -- kernel, disk image,
|
||||
and, a bootloader.
|
||||
:param readfile: An optional parameter stating the file to be read by
|
||||
by `m5 readfile`.
|
||||
by ``m5 readfile``.
|
||||
:param readfile_contents: An optional parameter stating the contents of
|
||||
the readfile file. If set with `readfile`, the contents of `readfile`
|
||||
will be overwritten with `readfile_contents`, otherwise a new file will
|
||||
be created with the value of `readfile_contents`.
|
||||
the readfile file. If set with ``readfile``,
|
||||
the contents of `readfile` will be overwritten
|
||||
with ``readfile_contents``, otherwise a new file
|
||||
will be created with the value of
|
||||
``readfile_contents``.
|
||||
:param kernel_args: An optional parameter for setting arguments to be
|
||||
passed to the kernel. By default set to `get_default_kernel_args()`.
|
||||
passed to the kernel. By default set to
|
||||
``get_default_kernel_args()``.
|
||||
:param exit_on_work_items: Whether the simulation should exit on work
|
||||
items. True by default.
|
||||
items. ``True`` by default.
|
||||
:param checkpoint: The checkpoint directory. Used to restore the
|
||||
simulation to that checkpoint.
|
||||
simulation to that checkpoint.
|
||||
"""
|
||||
|
||||
# We assume this this is in a multiple-inheritance setup with an
|
||||
|
||||
@@ -38,10 +38,10 @@ class MemMode(Enum):
|
||||
|
||||
def mem_mode_to_string(mem_mode: MemMode) -> str:
|
||||
"""
|
||||
Returns the string form of the mem_mode, compatible with the gem5
|
||||
Returns the string form of the ``mem_mode``, compatible with the gem5
|
||||
simulator.
|
||||
|
||||
:returns: The string form of the mem_mode
|
||||
:returns: The string form of the ``mem_mode``.
|
||||
"""
|
||||
if mem_mode == MemMode.TIMING:
|
||||
return "timing"
|
||||
|
||||
@@ -69,7 +69,7 @@ from .kernel_disk_workload import KernelDiskWorkload
|
||||
|
||||
class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
"""
|
||||
A board capable of full system simulation for RISC-V
|
||||
A board capable of full system simulation for RISC-V.
|
||||
|
||||
At a high-level, this is based on the HiFive Unmatched board from SiFive.
|
||||
|
||||
@@ -138,7 +138,7 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
self._off_chip_devices = [self.platform.uart, self.disk, self.rng]
|
||||
|
||||
def _setup_io_devices(self) -> None:
|
||||
"""Connect the I/O devices to the I/O bus"""
|
||||
"""Connect the I/O devices to the I/O bus."""
|
||||
# Add PCI
|
||||
self.platform.pci_host.pio = self.iobus.mem_side_ports
|
||||
|
||||
@@ -177,7 +177,7 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
self.bridge.ranges.append(AddrRange(0x40000000, size="512MB"))
|
||||
|
||||
def _setup_pma(self) -> None:
|
||||
"""Set the PMA devices on each core"""
|
||||
"""Set the PMA devices on each core."""
|
||||
|
||||
uncacheable_range = [
|
||||
AddrRange(dev.pio_addr, size=dev.pio_size)
|
||||
@@ -230,11 +230,11 @@ class RiscvBoard(AbstractSystemBoard, KernelDiskWorkload):
|
||||
memory.set_memory_range(self.mem_ranges)
|
||||
|
||||
def generate_device_tree(self, outdir: str) -> None:
|
||||
"""Creates the dtb and dts files.
|
||||
"""Creates the ``dtb`` and ``dts`` files.
|
||||
|
||||
Creates two files in the outdir: 'device.dtb' and 'device.dts'
|
||||
Creates two files in the outdir: ``device.dtb`` and ``device.dts``.
|
||||
|
||||
:param outdir: Directory to output the files
|
||||
:param outdir: Directory to output the files.
|
||||
"""
|
||||
|
||||
state = FdtState(addr_cells=2, size_cells=2, cpu_cells=1)
|
||||
|
||||
@@ -57,13 +57,15 @@ class SEBinaryWorkload:
|
||||
This class is used to enable simple Syscall-Execution (SE) mode execution
|
||||
of a binary.
|
||||
|
||||
For this to function correctly the SEBinaryWorkload class should be added
|
||||
For this to function correctly the `SEBinaryWorkload` class should be added
|
||||
as a superclass to a board (i.e., something that inherits from
|
||||
AbstractBoard).
|
||||
`AbstractBoard`).
|
||||
|
||||
**Important Notes:** At present this implementation is limited. A single
|
||||
process is added to all cores as the workload. Therefore, despite allowing
|
||||
for multi-core setups, multi-program workloads are not presently supported.
|
||||
.. note::
|
||||
|
||||
At present this implementation is limited. A single
|
||||
process is added to all cores as the workload. Therefore, despite allowing
|
||||
for multi-core setups, multi-program workloads are not presently supported.
|
||||
"""
|
||||
|
||||
def set_se_binary_workload(
|
||||
@@ -85,14 +87,14 @@ class SEBinaryWorkload:
|
||||
|
||||
:param binary: The resource encapsulating the binary to be run.
|
||||
:param exit_on_work_items: Whether the simulation should exit on work
|
||||
items. True by default.
|
||||
items. ``True`` by default.
|
||||
:param stdin_file: The input file for the binary
|
||||
:param stdout_file: The output file for the binary
|
||||
:param stderr_file: The error output file for the binary
|
||||
:param env_list: The environment variables defined for the binary
|
||||
:param arguments: The input arguments for the binary
|
||||
:param checkpoint: The checkpoint directory. Used to restore the
|
||||
simulation to that checkpoint.
|
||||
simulation to that checkpoint.
|
||||
"""
|
||||
|
||||
# We assume this this is in a multiple-inheritance setup with an
|
||||
@@ -166,15 +168,17 @@ class SEBinaryWorkload:
|
||||
* Dynamically linked executables are partially supported when the host
|
||||
ISA and the simulated ISA are the same.
|
||||
|
||||
**Warning:** Simpoints only works with one core
|
||||
.. warning::
|
||||
|
||||
SimPoints only works with one core
|
||||
|
||||
:param binary: The resource encapsulating the binary to be run.
|
||||
:param arguments: The input arguments for the binary
|
||||
:param arguments: The input arguments for the binary.
|
||||
:param simpoint: The SimpointResource that contains the list of
|
||||
SimPoints starting instructions, the list of weights, and the SimPoints
|
||||
interval
|
||||
SimPoints starting instructions, the list of
|
||||
weights, and the SimPoints interval.
|
||||
:param checkpoint: The checkpoint directory. Used to restore the
|
||||
simulation to that checkpoint.
|
||||
simulation to that checkpoint.
|
||||
"""
|
||||
|
||||
self._simpoint_resource = simpoint
|
||||
@@ -218,11 +222,11 @@ class SEBinaryWorkload:
|
||||
|
||||
:param binary: The resource encapsulating the binary to be run.
|
||||
:param looppoint: The LoopPoint object that contain all the information
|
||||
gather from the LoopPoint files and a LoopPointManager that will raise
|
||||
exit events for LoopPoints
|
||||
:param arguments: The input arguments for the binary
|
||||
gather from the LoopPoint files and a LoopPointManager
|
||||
that will raise exit events for LoopPoints.
|
||||
:param arguments: The input arguments for the binary.
|
||||
:param region_id: If set, will only load the Looppoint region
|
||||
corresponding to that ID.
|
||||
corresponding to that ID.
|
||||
"""
|
||||
|
||||
assert isinstance(looppoint, Looppoint)
|
||||
@@ -251,10 +255,10 @@ class SEBinaryWorkload:
|
||||
* Dynamically linked executables are partially supported when the host
|
||||
ISA and the simulated ISA are the same.
|
||||
|
||||
:param elfie: The resource encapsulating the binary elfie to be run.
|
||||
:param elfie: The resource encapsulating the binary ELFie to be run.
|
||||
:param elfie_info: The ELFieInfo object that contain all the
|
||||
information for the ELFie
|
||||
:param arguments: The input arguments for the binary
|
||||
information for the ELFie.
|
||||
:param arguments: The input arguments for the binary.
|
||||
"""
|
||||
|
||||
assert isinstance(elfie_info, ELFieInfo)
|
||||
|
||||
@@ -48,7 +48,7 @@ class SimpleBoard(AbstractSystemBoard, SEBinaryWorkload):
|
||||
**Limitations**
|
||||
* Only supports SE mode
|
||||
|
||||
You can run a binary executable via the `set_se_binary_workload` function.
|
||||
You can run a binary executable via the ``set_se_binary_workload`` function.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -98,7 +98,7 @@ class SimpleBoard(AbstractSystemBoard, SEBinaryWorkload):
|
||||
@overrides(AbstractSystemBoard)
|
||||
def get_mem_side_coherent_io_port(self) -> Port:
|
||||
raise NotImplementedError(
|
||||
"SimpleBoard does not have any I/O ports. Use has_coherent_io to "
|
||||
"SimpleBoard does not have any I/O ports. Use `has_coherent_io` to "
|
||||
"check this."
|
||||
)
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class TestBoard(AbstractSystemBoard):
|
||||
|
||||
To work as a traffic generator board, pass a generator as a processor.
|
||||
|
||||
This board does not require a cache hierarchy (it can be none) in which
|
||||
This board does not require a cache hierarchy (it can be ``none``) in which
|
||||
case the processor (generator) will be directly connected to the memory.
|
||||
The clock frequency is only used if there is a cache hierarchy or when
|
||||
using the GUPS generators.
|
||||
|
||||
@@ -67,8 +67,8 @@ class X86Board(AbstractSystemBoard, KernelDiskWorkload):
|
||||
A board capable of full system simulation for X86.
|
||||
|
||||
**Limitations**
|
||||
* Currently, this board's memory is hardcoded to 3GB
|
||||
* Much of the I/O subsystem is hard coded
|
||||
* Currently, this board's memory is hardcoded to 3GB.
|
||||
* Much of the I/O subsystem is hard coded.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -108,8 +108,10 @@ class X86Board(AbstractSystemBoard, KernelDiskWorkload):
|
||||
def _setup_io_devices(self):
|
||||
"""Sets up the x86 IO devices.
|
||||
|
||||
Note: This is mostly copy-paste from prior X86 FS setups. Some of it
|
||||
may not be documented and there may be bugs.
|
||||
.. note::
|
||||
|
||||
This is mostly copy-paste from prior X86 FS setups. Some of it
|
||||
may not be documented and there may be bugs.
|
||||
"""
|
||||
|
||||
# Constants similar to x86_traits.hh
|
||||
|
||||
@@ -57,9 +57,7 @@ class AbstractCacheHierarchy(SubSystem):
|
||||
unique for each setup.
|
||||
|
||||
:param board: The board in which the cache heirarchy is to be
|
||||
incorporated.
|
||||
|
||||
:type board: AbstractBoard
|
||||
incorporated.
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
@@ -70,10 +68,10 @@ class AbstractCacheHierarchy(SubSystem):
|
||||
Specifies whether this cache hierarchy is using the Ruby memory system
|
||||
or not.
|
||||
|
||||
:returns: True if the cache hierarchy is ruby. Otherwise False.
|
||||
:returns: ``True`` if the cache hierarchy is ruby. Otherwise ``False``.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def _post_instantiate(self):
|
||||
"""Called to set up anything needed after m5.instantiate"""
|
||||
"""Called to set up anything needed after ``m5.instantiate``."""
|
||||
pass
|
||||
|
||||
@@ -43,27 +43,15 @@ class AbstractTwoLevelCacheHierarchy:
|
||||
"""
|
||||
:param l1i_size: The size of the L1 Instruction cache (e.g. "32kB").
|
||||
|
||||
:type l1i_size: str
|
||||
|
||||
:param l1i_assoc:
|
||||
|
||||
:type l1i_assoc: int
|
||||
|
||||
:param l1d_size: The size of the L1 Data cache (e.g. "32kB").
|
||||
|
||||
:type l1d_size: str
|
||||
|
||||
:param l1d_assoc:
|
||||
|
||||
:type l1d_assoc: int
|
||||
|
||||
:param l2_size: The size of the L2 cache (e.g., "256kB").
|
||||
|
||||
:type l2_size: str
|
||||
|
||||
:param l2_assoc:
|
||||
|
||||
:type l2_assoc: int
|
||||
"""
|
||||
self._l1i_size = l1i_size
|
||||
self._l1i_assoc = l1i_assoc
|
||||
|
||||
@@ -40,6 +40,7 @@ from .abstract_node import TriggerMessageBuffer
|
||||
class MemCtrlMessageBuffer(MessageBuffer):
|
||||
"""
|
||||
MessageBuffer exchanging messages with the memory
|
||||
|
||||
These buffers should also not be affected by the Ruby tester randomization.
|
||||
"""
|
||||
|
||||
@@ -48,7 +49,7 @@ class MemCtrlMessageBuffer(MessageBuffer):
|
||||
|
||||
|
||||
class MemoryController(Memory_Controller):
|
||||
"""A controller that connects to memory"""
|
||||
"""A controller that connects to memory."""
|
||||
|
||||
_version = 0
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ class PrivateL1CacheHierarchy(AbstractRubyCacheHierarchy):
|
||||
self, core: AbstractCore, core_num: int, board: AbstractBoard
|
||||
) -> SubSystem:
|
||||
"""Given the core and the core number this function creates a cluster
|
||||
for the core with a split I/D cache
|
||||
for the core with a split I/D cache.
|
||||
"""
|
||||
cluster = SubSystem()
|
||||
cluster.dcache = PrivateL1MOESICache(
|
||||
|
||||
@@ -39,8 +39,8 @@ class L1DCache(Cache):
|
||||
"""
|
||||
A simple L1 data cache with default values.
|
||||
|
||||
If the cache has a mostly exclusive downstream cache, writeback_clean
|
||||
should be set to True.
|
||||
If the cache has a mostly exclusive downstream cache, ``writeback_clean``
|
||||
should be set to ``True``.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -40,7 +40,7 @@ class L1ICache(Cache):
|
||||
A simple L1 instruction cache with default values.
|
||||
|
||||
If the cache does not have a downstream cache or the downstream cache
|
||||
is mostly inclusive as usual, writeback_clean should be set to False.
|
||||
is mostly inclusive as usual, ``writeback_clean`` should be set to ``False``.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -38,7 +38,7 @@ class MMUCache(Cache):
|
||||
A simple Memory Management Unit (MMU) cache with default values.
|
||||
|
||||
If the cache does not have a downstream cache or the downstream cache
|
||||
is mostly inclusive as usual, writeback_clean should be set to False.
|
||||
is mostly inclusive as usual, ``writeback_clean`` should be set to ``False``.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -46,20 +46,22 @@ class NoCache(AbstractClassicCacheHierarchy):
|
||||
By default a SystemXBar of width 64bit is used, though this can be
|
||||
configured via the constructor.
|
||||
|
||||
NOTE: At present this does not work with FS. The following error is
|
||||
received:
|
||||
.. note::
|
||||
|
||||
At present this does not work with FS. The following error is
|
||||
received:
|
||||
|
||||
.. code-block::
|
||||
...
|
||||
build/X86/mem/snoop_filter.cc:277: panic: panic condition
|
||||
(sf_item.requested & req_mask).none() occurred: SF value
|
||||
0000000000000000000000000000000000000000000000000000000000000000 ...
|
||||
missing the original request
|
||||
Memory Usage: 3554472 KBytes
|
||||
Program aborted at tick 1668400099164
|
||||
--- BEGIN LIBC BACKTRACE ---
|
||||
...
|
||||
|
||||
```
|
||||
...
|
||||
build/X86/mem/snoop_filter.cc:277: panic: panic condition
|
||||
(sf_item.requested & req_mask).none() occurred: SF value
|
||||
0000000000000000000000000000000000000000000000000000000000000000 ...
|
||||
missing the original request
|
||||
Memory Usage: 3554472 KBytes
|
||||
Program aborted at tick 1668400099164
|
||||
--- BEGIN LIBC BACKTRACE ---
|
||||
...
|
||||
```
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
@@ -85,7 +87,8 @@ class NoCache(AbstractClassicCacheHierarchy):
|
||||
) -> None:
|
||||
"""
|
||||
:param membus: The memory bus for this setup. This parameter is
|
||||
optional and will default toa 64 bit width SystemXBar is not specified.
|
||||
optional and will default toa 64 bit width SystemXBar
|
||||
is not specified.
|
||||
|
||||
:type membus: BaseXBar
|
||||
"""
|
||||
|
||||
@@ -54,7 +54,7 @@ class PrivateL1CacheHierarchy(AbstractClassicCacheHierarchy):
|
||||
the PrivateL1CacheHierarchy.
|
||||
|
||||
:returns: The default memory bus for the PrivateL1PrivateL2
|
||||
CacheHierarchy.
|
||||
CacheHierarchy.
|
||||
"""
|
||||
membus = SystemXBar(width=64)
|
||||
membus.badaddr_responder = BadAddr()
|
||||
@@ -73,7 +73,7 @@ class PrivateL1CacheHierarchy(AbstractClassicCacheHierarchy):
|
||||
:param l1i_size: The size of the L1 Instruction Cache (e.g., "32kB").
|
||||
|
||||
:param membus: The memory bus. This parameter is optional parameter and
|
||||
will default to a 64 bit width SystemXBar is not specified.
|
||||
will default to a 64 bit width SystemXBar is not specified.
|
||||
"""
|
||||
|
||||
AbstractClassicCacheHierarchy.__init__(self=self)
|
||||
|
||||
@@ -60,9 +60,8 @@ class PrivateL1PrivateL2CacheHierarchy(
|
||||
the PrivateL1PrivateL2 CacheHierarchy.
|
||||
|
||||
:returns: The default memory bus for the PrivateL1PrivateL2
|
||||
CacheHierarchy.
|
||||
CacheHierarchy.
|
||||
|
||||
:rtype: SystemXBar
|
||||
"""
|
||||
membus = SystemXBar(width=64)
|
||||
membus.badaddr_responder = BadAddr()
|
||||
@@ -79,20 +78,12 @@ class PrivateL1PrivateL2CacheHierarchy(
|
||||
"""
|
||||
:param l1d_size: The size of the L1 Data Cache (e.g., "32kB").
|
||||
|
||||
:type l1d_size: str
|
||||
|
||||
:param l1i_size: The size of the L1 Instruction Cache (e.g., "32kB").
|
||||
|
||||
:type l1i_size: str
|
||||
|
||||
:param l2_size: The size of the L2 Cache (e.g., "256kB").
|
||||
|
||||
:type l2_size: str
|
||||
|
||||
:param membus: The memory bus. This parameter is optional parameter and
|
||||
will default to a 64 bit width SystemXBar is not specified.
|
||||
|
||||
:type membus: BaseXBar
|
||||
will default to a 64 bit width SystemXBar is not specified.
|
||||
"""
|
||||
|
||||
AbstractClassicCacheHierarchy.__init__(self=self)
|
||||
|
||||
@@ -61,7 +61,7 @@ class PrivateL1SharedL2CacheHierarchy(
|
||||
the PrivateL1SharedL2 CacheHierarchy.
|
||||
|
||||
:returns: The default memory bus for the PrivateL1SharedL2
|
||||
CacheHierarchy.
|
||||
CacheHierarchy.
|
||||
|
||||
:rtype: SystemXBar
|
||||
"""
|
||||
@@ -88,7 +88,7 @@ class PrivateL1SharedL2CacheHierarchy(
|
||||
:param l1i_assoc: The associativity of the L1 Instruction Cache.
|
||||
:param l2_assoc: The associativity of the L2 Cache.
|
||||
:param membus: The memory bus. This parameter is optional parameter and
|
||||
will default to a 64 bit width SystemXBar is not specified.
|
||||
will default to a 64 bit width SystemXBar is not specified.
|
||||
"""
|
||||
|
||||
AbstractClassicCacheHierarchy.__init__(self=self)
|
||||
|
||||
@@ -58,22 +58,22 @@ class AbstractMemorySystem(SubSystem):
|
||||
|
||||
@abstractmethod
|
||||
def get_mem_ports(self) -> Sequence[Tuple[AddrRange, Port]]:
|
||||
"""Get the ports to connect this memory system to the cache"""
|
||||
"""Get the ports to connect this memory system to the cache."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_memory_controllers(self) -> List[MemCtrl]:
|
||||
"""Get all of the memory controllers in this memory system"""
|
||||
"""Get all of the memory controllers in this memory system."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def get_size(self) -> int:
|
||||
"""Returns the total size of the memory system"""
|
||||
"""Returns the total size of the memory system."""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def set_memory_range(self, ranges: List[AddrRange]) -> None:
|
||||
"""Set the total range for this memory system
|
||||
"""Set the total range for this memory system.
|
||||
|
||||
May pass multiple non-overlapping ranges. The total size of the ranges
|
||||
should match the size of the memory.
|
||||
@@ -84,5 +84,5 @@ class AbstractMemorySystem(SubSystem):
|
||||
raise NotImplementedError
|
||||
|
||||
def _post_instantiate(self) -> None:
|
||||
"""Called to set up anything needed after m5.instantiate"""
|
||||
"""Called to set up anything needed after ``m5.instantiate``."""
|
||||
pass
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
These memory "interfaces" contain the timing, energy, etc. parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
|
||||
"""Interfaces for DDR4 memories
|
||||
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
These memory "interfaces" contain the timing, energy, etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
@@ -55,7 +55,9 @@ class DDR4_2400_16x4(DRAMInterface):
|
||||
A single DDR4-2400 x64 channel (one command and address bus), with
|
||||
timings based on a DDR4-2400 8 Gbit datasheet (Micron MT40A2G4)
|
||||
in an 16x4 configuration.
|
||||
Total channel capacity is 32GiB
|
||||
|
||||
Total channel capacity is 32GiB.
|
||||
|
||||
16 devices/rank * 2 ranks/channel * 1GiB/device = 32GiB/channel
|
||||
"""
|
||||
|
||||
@@ -170,7 +172,9 @@ class DDR4_2400_8x8(DDR4_2400_16x4):
|
||||
A single DDR4-2400 x64 channel (one command and address bus), with
|
||||
timings based on a DDR4-2400 8 Gbit datasheet (Micron MT40A1G8)
|
||||
in an 8x8 configuration.
|
||||
Total channel capacity is 16GiB
|
||||
|
||||
Total channel capacity is 16GiB.
|
||||
|
||||
8 devices/rank * 2 ranks/channel * 1GiB/device = 16GiB/channel
|
||||
"""
|
||||
|
||||
@@ -201,7 +205,9 @@ class DDR4_2400_4x16(DDR4_2400_16x4):
|
||||
A single DDR4-2400 x64 channel (one command and address bus), with
|
||||
timings based on a DDR4-2400 8 Gbit datasheet (Micron MT40A512M16)
|
||||
in an 4x16 configuration.
|
||||
Total channel capacity is 4GiB
|
||||
|
||||
Total channel capacity is 4GiB.
|
||||
|
||||
4 devices/rank * 1 ranks/channel * 1GiB/device = 4GiB/channel
|
||||
"""
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
|
||||
"""Interfaces for GDDR memory devices
|
||||
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
These memory "interfaces" contain the timing, energy, etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
|
||||
"""Interfaces for HBM memory devices
|
||||
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
These memory "interfaces" contain the timing, energy, etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
@@ -56,15 +56,18 @@ class HBM_1000_4H_1x128(DRAMInterface):
|
||||
default timings based on data publically released
|
||||
("HBM: Memory Solution for High Performance Processors", MemCon, 2014),
|
||||
IDD measurement values, and by extrapolating data from other classes.
|
||||
Architecture values based on published HBM spec
|
||||
|
||||
Architecture values based on published HBM spec.
|
||||
|
||||
A 4H stack is defined, 2Gb per die for a total of 1GiB of memory.
|
||||
|
||||
**IMPORTANT**
|
||||
HBM gen1 supports up to 8 128-bit physical channels
|
||||
Configuration defines a single channel, with the capacity
|
||||
set to (full_ stack_capacity / 8) based on 2Gb dies
|
||||
To use all 8 channels, set 'channels' parameter to 8 in
|
||||
system configuration
|
||||
set to (full_ stack_capacity / 8) based on 2Gb dies.
|
||||
|
||||
To use all 8 channels, set ``channels`` parameter to 8 in
|
||||
system configuration.
|
||||
"""
|
||||
|
||||
# 128-bit interface legacy mode
|
||||
@@ -149,16 +152,17 @@ class HBM_1000_4H_1x64(HBM_1000_4H_1x128):
|
||||
default timings based on HBM gen1 and data publically released
|
||||
A 4H stack is defined, 8Gb per die for a total of 4GiB of memory.
|
||||
Note: This defines a pseudo-channel with a unique controller
|
||||
instantiated per pseudo-channel
|
||||
instantiated per pseudo-channel.
|
||||
|
||||
Stay at same IO rate (1Gbps) to maintain timing relationship with
|
||||
HBM gen1 class (HBM_1000_4H_x128) where possible
|
||||
HBM gen1 class (HBM_1000_4H_x128) where possible.
|
||||
|
||||
**IMPORTANT**
|
||||
For HBM gen2 with pseudo-channel mode, configure 2X channels.
|
||||
Configuration defines a single pseudo channel, with the capacity
|
||||
set to (full_ stack_capacity / 16) based on 8Gb dies
|
||||
To use all 16 pseudo channels, set 'channels' parameter to 16 in
|
||||
system configuration
|
||||
set to (full_ stack_capacity / 16) based on 8Gb dies.
|
||||
To use all 16 pseudo channels, set ``channels`` parameter to 16 in
|
||||
system configuration.
|
||||
"""
|
||||
|
||||
# 64-bit pseudo-channel interface
|
||||
|
||||
@@ -40,10 +40,10 @@
|
||||
|
||||
"""Interfaces for HMC memory devices
|
||||
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
These memory "interfaces" contain the timing, energy, etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
|
||||
Note that HMC is configured differently than some other DRAM interfaces.
|
||||
@@ -58,22 +58,29 @@ class HMC_2500_1x32(DDR3_1600_8x8):
|
||||
uses RC (resistance-capacitance) and CV (capacitance-voltage) models to
|
||||
estimate the DRAM bank latency and power numbers.
|
||||
[2] High performance AXI-4.0 based interconnect for extensible smart memory
|
||||
cubes (E. Azarkhish et. al)
|
||||
cubes (E. Azarkhish et. al).
|
||||
Assumed for the HMC model is a 30 nm technology node.
|
||||
The modelled HMC consists of 4 Gbit layers which sum up to 2GiB of memory
|
||||
(4 layers).
|
||||
Each layer has 16 vaults and each vault consists of 2 banks per layer.
|
||||
In order to be able to use the same controller used for 2D DRAM generations
|
||||
for HMC, the following analogy is done:
|
||||
|
||||
Channel (DDR) => Vault (HMC)
|
||||
|
||||
device_size (DDR) => size of a single layer in a vault
|
||||
|
||||
ranks per channel (DDR) => number of layers
|
||||
|
||||
banks per rank (DDR) => banks per layer
|
||||
|
||||
devices per rank (DDR) => devices per layer ( 1 for HMC).
|
||||
|
||||
The parameters for which no input is available are inherited from the DDR3
|
||||
configuration.
|
||||
|
||||
This configuration includes the latencies from the DRAM to the logic layer
|
||||
of the HMC
|
||||
of the HMC.
|
||||
"""
|
||||
|
||||
# size of device
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
@@ -54,10 +54,12 @@ class LPDDR5_5500_1x16_BG_BL32(DRAMInterface):
|
||||
"""
|
||||
A single LPDDR5 x16 interface (one command/address bus)
|
||||
for a single x16 channel with default timings based on
|
||||
initial JEDEC specification
|
||||
Starting with 5.5Gbps data rates and 8Gbit die
|
||||
initial JEDEC specification.
|
||||
|
||||
Starting with 5.5Gbps data rates and 8Gbit die.
|
||||
|
||||
Configuring for 16-bank mode with bank-group architecture
|
||||
burst of 32, which means bursts can be interleaved
|
||||
burst of 32, which means bursts can be interleaved.
|
||||
"""
|
||||
|
||||
# Increase buffer size to account for more bank resources
|
||||
@@ -208,9 +210,11 @@ class LPDDR5_5500_1x16_8B_BL32(LPDDR5_5500_1x16_BG_BL32):
|
||||
"""
|
||||
A single LPDDR5 x16 interface (one command/address bus)
|
||||
for a single x16 channel with default timings based on
|
||||
initial JEDEC specification
|
||||
Starting with 5.5Gbps data rates and 8Gbit die
|
||||
Configuring for 8-bank mode, burst of 32
|
||||
initial JEDEC specification.
|
||||
|
||||
Starting with 5.5Gbps data rates and 8Gbit die.
|
||||
|
||||
Configuring for 8-bank mode, burst of 32.
|
||||
"""
|
||||
|
||||
# 4KiB page with 8B mode
|
||||
@@ -249,10 +253,12 @@ class LPDDR5_6400_1x16_BG_BL32(LPDDR5_5500_1x16_BG_BL32):
|
||||
"""
|
||||
A single LPDDR5 x16 interface (one command/address bus)
|
||||
for a single x16 channel with default timings based on
|
||||
initial JEDEC specification
|
||||
6.4Gbps data rates and 8Gbit die
|
||||
initial JEDEC specification.
|
||||
|
||||
6.4Gbps data rates and 8Gbit die.
|
||||
|
||||
Configuring for 16-bank mode with bank-group architecture
|
||||
burst of 32, which means bursts can be interleaved
|
||||
burst of 32, which means bursts can be interleaved.
|
||||
"""
|
||||
|
||||
# 5.5Gb/s DDR with 4:1 WCK:CK ratio for 687.5 MHz CK
|
||||
@@ -297,9 +303,11 @@ class LPDDR5_6400_1x16_BG_BL16(LPDDR5_6400_1x16_BG_BL32):
|
||||
"""
|
||||
A single LPDDR5 x16 interface (one command/address bus)
|
||||
for a single x16 channel with default timings based on initial
|
||||
JEDEC specifcation
|
||||
6.4Gbps data rates and 8Gbit die
|
||||
Configuring for 16-bank mode with bank-group architecture, burst of 16
|
||||
JEDEC specifcation.
|
||||
|
||||
6.4Gbps data rates and 8Gbit die.
|
||||
|
||||
Configuring for 16-bank mode with bank-group architecture, burst of 16.
|
||||
"""
|
||||
|
||||
# LPDDR5 is a BL16 or BL32 device
|
||||
@@ -321,9 +329,11 @@ class LPDDR5_6400_1x16_8B_BL32(LPDDR5_6400_1x16_BG_BL32):
|
||||
"""
|
||||
A single LPDDR5 x16 interface (one command/address bus)
|
||||
for a single x16 channel with default timings based on
|
||||
initial JEDEC specification
|
||||
6.4Gbps data rates and 8Gbit die
|
||||
Configuring for 8-bank mode, burst of 32
|
||||
initial JEDEC specification.
|
||||
|
||||
6.4Gbps data rates and 8Gbit die.
|
||||
|
||||
Configuring for 8-bank mode, burst of 32.
|
||||
"""
|
||||
|
||||
# 4KiB page with 8B mode
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
These memory "interfaces" contain the timing,energy,etc parameters for each
|
||||
memory type and are usually based on datasheets for the memory devices.
|
||||
|
||||
You can use these interfaces in the MemCtrl object as the `dram` timing
|
||||
You can use these interfaces in the MemCtrl object as the ``dram`` timing
|
||||
interface.
|
||||
"""
|
||||
|
||||
|
||||
@@ -24,10 +24,12 @@ from .abstract_memory_system import AbstractMemorySystem
|
||||
def config_ds3(mem_type: str, num_chnls: int) -> Tuple[str, str]:
|
||||
"""
|
||||
This function creates a config file that will be used to create a memory
|
||||
controller of type DRAMSim3. It stores the config file in /tmp/ directory.
|
||||
controller of type DRAMSim3. It stores the config file in ``/tmp/`` directory.
|
||||
|
||||
:param mem_type: The name for the type of the memory to be configured.
|
||||
|
||||
:param num_chnls: The number of channels to configure for the memory
|
||||
|
||||
:returns: A tuple containing the output file and the output directory.
|
||||
"""
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
@@ -70,17 +70,18 @@ class HighBandwidthMemory(ChanneledMemory):
|
||||
) -> None:
|
||||
"""
|
||||
:param dram_interface_class: The DRAM interface type to create with
|
||||
this memory controller
|
||||
this memory controller.
|
||||
:param num_channels: The number of channels that needs to be
|
||||
simulated
|
||||
simulated.
|
||||
:param size: Optionally specify the size of the DRAM controller's
|
||||
address space. By default, it starts at 0 and ends at the size of
|
||||
the DRAM device specified
|
||||
address space. By default, it starts at 0 and ends at
|
||||
the size of the DRAM device specified.
|
||||
:param addr_mapping: Defines the address mapping scheme to be used.
|
||||
If None, it is defaulted to addr_mapping from dram_interface_class.
|
||||
If ``None``, it is defaulted to ``addr_mapping``
|
||||
from ``dram_interface_class``.
|
||||
:param interleaving_size: Defines the interleaving size of the multi-
|
||||
channel memory system. By default, it is equivalent to the atom
|
||||
size, i.e., 64.
|
||||
channel memory system. By default, it is
|
||||
equivalent to the atom size, i.e., 64.
|
||||
"""
|
||||
super().__init__(
|
||||
dram_interface_class,
|
||||
|
||||
@@ -82,17 +82,18 @@ class ChanneledMemory(AbstractMemorySystem):
|
||||
) -> None:
|
||||
"""
|
||||
:param dram_interface_class: The DRAM interface type to create with
|
||||
this memory controller
|
||||
this memory controller.
|
||||
:param num_channels: The number of channels that needs to be
|
||||
simulated
|
||||
simulated.
|
||||
:param size: Optionally specify the size of the DRAM controller's
|
||||
address space. By default, it starts at 0 and ends at the size of
|
||||
the DRAM device specified
|
||||
address space. By default, it starts at 0 and ends at
|
||||
the size of the DRAM device specified.
|
||||
:param addr_mapping: Defines the address mapping scheme to be used.
|
||||
If None, it is defaulted to addr_mapping from dram_interface_class.
|
||||
If ``None``, it is defaulted to ``addr_mapping`` from
|
||||
``dram_interface_class``.
|
||||
:param interleaving_size: Defines the interleaving size of the multi-
|
||||
channel memory system. By default, it is equivalent to the atom
|
||||
size, i.e., 64.
|
||||
channel memory system. By default, it is
|
||||
equivalent to the atom size, i.e., 64.
|
||||
"""
|
||||
num_channels = _try_convert(num_channels, int)
|
||||
interleaving_size = _try_convert(interleaving_size, int)
|
||||
|
||||
@@ -41,7 +41,7 @@ def DualChannelDDR3_1600(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A dual channel memory system using DDR3_1600_8x8 based DIMM
|
||||
A dual channel memory system using DDR3_1600_8x8 based DIMM.
|
||||
"""
|
||||
return ChanneledMemory(DDR3_1600_8x8, 2, 64, size=size)
|
||||
|
||||
@@ -50,7 +50,7 @@ def DualChannelDDR3_2133(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A dual channel memory system using DDR3_2133_8x8 based DIMM
|
||||
A dual channel memory system using DDR3_2133_8x8 based DIMM.
|
||||
"""
|
||||
return ChanneledMemory(DDR3_2133_8x8, 2, 64, size=size)
|
||||
|
||||
@@ -59,7 +59,7 @@ def DualChannelDDR4_2400(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A dual channel memory system using DDR4_2400_8x8 based DIMM
|
||||
A dual channel memory system using DDR4_2400_8x8 based DIMM.
|
||||
"""
|
||||
return ChanneledMemory(DDR4_2400_8x8, 2, 64, size=size)
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ def SingleChannelDDR3_1600(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A single channel memory system using DDR3_1600_8x8 based DIMM
|
||||
A single channel memory system using DDR3_1600_8x8 based DIMM.
|
||||
"""
|
||||
return ChanneledMemory(DDR3_1600_8x8, 1, 64, size=size)
|
||||
|
||||
@@ -55,7 +55,7 @@ def SingleChannelDDR3_2133(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A single channel memory system using DDR3_2133_8x8 based DIMM
|
||||
A single channel memory system using DDR3_2133_8x8 based DIMM.
|
||||
"""
|
||||
return ChanneledMemory(DDR3_2133_8x8, 1, 64, size=size)
|
||||
|
||||
@@ -64,7 +64,7 @@ def SingleChannelDDR4_2400(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A single channel memory system using DDR4_2400_8x8 based DIMM
|
||||
A single channel memory system using DDR4_2400_8x8 based DIMM.
|
||||
"""
|
||||
return ChanneledMemory(DDR4_2400_8x8, 1, 64, size=size)
|
||||
|
||||
@@ -87,7 +87,7 @@ def DIMM_DDR5_4400(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A single DIMM of DDR5 has two channels
|
||||
A single DIMM of DDR5 has two channels.
|
||||
"""
|
||||
return ChanneledMemory(DDR5_4400_4x8, 2, 64, size=size)
|
||||
|
||||
@@ -96,7 +96,7 @@ def DIMM_DDR5_6400(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A single DIMM of DDR5 has two channels
|
||||
A single DIMM of DDR5 has two channels.
|
||||
"""
|
||||
return ChanneledMemory(DDR5_6400_4x8, 2, 64, size=size)
|
||||
|
||||
@@ -105,6 +105,6 @@ def DIMM_DDR5_8400(
|
||||
size: Optional[str] = None,
|
||||
) -> AbstractMemorySystem:
|
||||
"""
|
||||
A single DIMM of DDR5 has two channels
|
||||
A single DIMM of DDR5 has two channels.
|
||||
"""
|
||||
return ChanneledMemory(DDR5_8400_4x8, 2, 64, size=size)
|
||||
|
||||
@@ -58,9 +58,9 @@ class AbstractCore(SubSystem):
|
||||
def requires_send_evicts(self) -> bool:
|
||||
"""True if the CPU model or ISA requires sending evictions from caches
|
||||
to the CPU. Scenarios warrant forwarding evictions to the CPU:
|
||||
1. The O3 model must keep the LSQ coherent with the caches
|
||||
2. The x86 mwait instruction is built on top of coherence
|
||||
3. The local exclusive monitor in ARM systems
|
||||
1. The O3 model must keep the LSQ coherent with the caches.
|
||||
2. The x86 mwait instruction is built on top of coherence.
|
||||
3. The local exclusive monitor in ARM systems.
|
||||
"""
|
||||
return False
|
||||
|
||||
@@ -96,11 +96,11 @@ class AbstractCore(SubSystem):
|
||||
@abstractmethod
|
||||
def connect_walker_ports(self, port1: Port, port2: Port) -> None:
|
||||
"""
|
||||
Connect the response port from itb and dtb to their respective request
|
||||
Connect the response port from ``itb`` and ``dtb`` to their respective request
|
||||
ports in the core.
|
||||
|
||||
:param port1: The response port from itb walker to connect to.
|
||||
:param port2: The response port from dtb walker to connect to.
|
||||
:param port1: The response port from ``itb`` walker to connect to.
|
||||
:param port2: The response port from ``dtb`` walker to connect to.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@@ -139,15 +139,16 @@ class AbstractCore(SubSystem):
|
||||
) -> None:
|
||||
"""Schedule simpoint exit events for the core.
|
||||
|
||||
This is used to raise SIMPOINT_BEGIN exit events in the gem5 standard
|
||||
library. This is called through the set_workload functions and should
|
||||
not be called directly. Duplicate instruction counts in the inst_starts list will not
|
||||
be scheduled.
|
||||
This is used to raise ``SIMPOINT_BEGIN`` exit events in the gem5 standard
|
||||
library. This is called through the ``set_workload`` functions and should
|
||||
not be called directly. Duplicate instruction counts in the ``inst_starts``
|
||||
list will not be scheduled.
|
||||
|
||||
:param inst_starts: a list of SimPoints starting instructions
|
||||
:param board_initialized: True if the board has already been
|
||||
initialized, otherwise False. This parameter is necessary as simpoints
|
||||
are setup differently dependent on this.
|
||||
:param inst_starts: A list of SimPoints starting instructions.
|
||||
:param board_initialized: ``True`` if the board has already been
|
||||
initialized, otherwise ``False``. This parameter is
|
||||
necessary as SimPoints are setup differently
|
||||
dependent on this.
|
||||
"""
|
||||
raise NotImplementedError("This core type does not support simpoints")
|
||||
|
||||
@@ -159,12 +160,13 @@ class AbstractCore(SubSystem):
|
||||
given number of instructions. This is called through the simulator
|
||||
module and should not be called directly.
|
||||
|
||||
This is used to raise MAX_INSTS exit event in the gem5 standard library
|
||||
This is used to raise ``MAX_INSTS`` exit event in the gem5 standard library.
|
||||
|
||||
:param inst: a number of instructions
|
||||
:param board_initialized: True if the board has already been
|
||||
initialized, otherwise False. This parameter is necessary as the
|
||||
instruction stop is setup differently dependent on this.
|
||||
:param board_initialized: ``True`` if the board has already been
|
||||
initialized, otherwise ``False``. This parameter is
|
||||
necessary as the instruction stop is setup
|
||||
differently dependent on this.
|
||||
"""
|
||||
raise NotImplementedError("This core type does not support MAX_INSTS")
|
||||
|
||||
|
||||
@@ -60,11 +60,12 @@ class AbstractGenerator(AbstractProcessor):
|
||||
Create a list of AbstractGeneratorCore (which is an AbstractCore),
|
||||
to pass to the constructor of the AbstractProcessor. Due to the
|
||||
different prototypes for the constructor of different generator types
|
||||
inputs are noted as *args. This way the abstract method _create_cores
|
||||
inputs are noted as *args. This way the abstract ``method _create_cores``
|
||||
could be called without AbstractGenerator having to know what the
|
||||
prototype for the constructor of the inheriting class is. It also
|
||||
limits the _create_cores function to only using positional arguments.
|
||||
keyword (optional arguments) are still allowable in the constructor of
|
||||
limits the ``_create_cores`` function to only using positional arguments.
|
||||
|
||||
Keyword (optional arguments) are still allowable in the constructor of
|
||||
the inheriting classes.
|
||||
"""
|
||||
super().__init__(cores=cores)
|
||||
|
||||
@@ -68,7 +68,7 @@ class AbstractGeneratorCore(AbstractCore):
|
||||
def connect_icache(self, port: Port) -> None:
|
||||
"""
|
||||
Generator cores only have one request port which we will connect to
|
||||
the data cache not the icache. Just connect the icache to the
|
||||
the data cache not the ``icache``. Just connect the ``icache`` to the
|
||||
PortTerminator here.
|
||||
"""
|
||||
self.port_end.req_ports = port
|
||||
@@ -109,6 +109,7 @@ class AbstractGeneratorCore(AbstractCore):
|
||||
def start_traffic(self):
|
||||
"""
|
||||
External interface to start generating the trace of addresses.
|
||||
|
||||
Depending on what SimObject is wrapped by this component this method
|
||||
might need be implemented.
|
||||
"""
|
||||
|
||||
@@ -50,8 +50,9 @@ class AbstractProcessor(SubSystem):
|
||||
isa: ISA = ISA.NULL,
|
||||
) -> None:
|
||||
"""Set the cores on the processor
|
||||
|
||||
Cores are optional for some processor types. If a processor does not
|
||||
set the cores here, it must override `get_num_cores` and `get_cores`
|
||||
set the cores here, it must override ``get_num_cores`` and ``get_cores``.
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
@@ -80,5 +81,5 @@ class AbstractProcessor(SubSystem):
|
||||
raise NotImplementedError
|
||||
|
||||
def _post_instantiate(self) -> None:
|
||||
"""Called to set up anything needed after m5.instantiate"""
|
||||
"""Called to set up anything needed after ``m5.instantiate``."""
|
||||
pass
|
||||
|
||||
@@ -55,7 +55,6 @@ class BaseCPUProcessor(AbstractProcessor):
|
||||
|
||||
Disclaimer
|
||||
----------
|
||||
|
||||
Multiple cores comprising of different BaseCPU types has not been tested
|
||||
and is not officially supported.
|
||||
"""
|
||||
|
||||
@@ -70,18 +70,19 @@ class ComplexGenerator(AbstractGenerator):
|
||||
generator with the params specified.
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
ranges = partition_range(min_addr, max_addr, len(self.cores))
|
||||
for i, core in enumerate(self.cores):
|
||||
@@ -110,18 +111,19 @@ class ComplexGenerator(AbstractGenerator):
|
||||
generator with the params specified.
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
for core in self.cores:
|
||||
core.add_random(
|
||||
@@ -141,7 +143,7 @@ class ComplexGenerator(AbstractGenerator):
|
||||
Sets the traffic pattern defined by generator argument.
|
||||
|
||||
:param generator: A python generator object that creates traffic
|
||||
patterns through calls to methods of PyTrafficGen.
|
||||
patterns through calls to methods of PyTrafficGen.
|
||||
"""
|
||||
for core in self.cores:
|
||||
core.set_traffic_from_python_generator(generator)
|
||||
|
||||
@@ -47,7 +47,8 @@ from .abstract_generator_core import AbstractGeneratorCore
|
||||
|
||||
class TrafficModes(Enum):
|
||||
"""The traffic mode class
|
||||
This class is an enum to store traffic mode in a more meaningful way
|
||||
|
||||
This class is an enum to store traffic mode in a more meaningful way.
|
||||
"""
|
||||
|
||||
linear = 0
|
||||
@@ -67,9 +68,10 @@ class ComplexTrafficParams:
|
||||
data_limit: int,
|
||||
):
|
||||
"""The complex traffic params class
|
||||
|
||||
This class is a container for parameters to create either a linear or
|
||||
random traffic. The complex generator core stores a list of complex
|
||||
traffic params for resolution after m5.instantiate is called.
|
||||
traffic params for resolution after ``m5.instantiate`` is called.
|
||||
"""
|
||||
self._mode = mode
|
||||
self._duration = duration
|
||||
@@ -86,7 +88,7 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
"""The complex generator core interface.
|
||||
|
||||
This class defines the interface for a generator core that will create
|
||||
a series of different types of traffic. This core uses PyTrafficGen to
|
||||
a series of different types of traffic. This core uses `PyTrafficGen` to
|
||||
create and inject the synthetic traffic. This generator could be used
|
||||
to create more complex traffics that consist of linear and random
|
||||
traffic in different phases.
|
||||
@@ -114,22 +116,23 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
"""
|
||||
This function will add the params for a linear traffic to the list of
|
||||
traffic params in this generator core. These params will be later
|
||||
resolved by the start_traffic call. This core uses a PyTrafficGen to
|
||||
resolved by the ``start_traffic`` call. This core uses a `PyTrafficGen` to
|
||||
create the traffic based on the specified params below.
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
param = ComplexTrafficParams(
|
||||
TrafficModes.linear,
|
||||
@@ -157,22 +160,23 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
"""
|
||||
This function will add the params for a random traffic to the list of
|
||||
traffic params in this generator core. These params will be later
|
||||
resolved by the start_traffic call. This core uses a PyTrafficGen to
|
||||
resolved by the ``start_traffic`` call. This core uses a PyTrafficGen to
|
||||
create the traffic based on the specified params below.
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
param = ComplexTrafficParams(
|
||||
TrafficModes.random,
|
||||
@@ -192,13 +196,13 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
"""
|
||||
This function first checks if there are any pending traffics that
|
||||
require creation, if so it will create the pending traffics based on
|
||||
traffic_params list and adds them to the traffic list, then it starts
|
||||
``traffic_params`` list and adds them to the traffic list, then it starts
|
||||
generating the traffic at the top of the traffic list. It also pops the
|
||||
first element in the list so that every time this function is called a
|
||||
new traffic is generated, each instance of a call to this function
|
||||
should happen before each instance of the call to m5.simulate(). All
|
||||
should happen before each instance of the call to ``m5.simulate()``. All
|
||||
the instances of calls to this function should happen after
|
||||
m5.instantiate()
|
||||
``m5.instantiate()``.
|
||||
"""
|
||||
if not self._traffic_set:
|
||||
self._set_traffic()
|
||||
@@ -254,15 +258,15 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
) -> None:
|
||||
"""
|
||||
Function to set the traffic from a user defined python generator.
|
||||
The generator should only only assume one input argument (positional)
|
||||
The generator should only assume one input argument (positional)
|
||||
for the actual PyTrafficGen object to create the traffic. This is possible
|
||||
either through using a generator with hardcoded parameters in the
|
||||
function calls to PyTrafficGen methods or by compiling a flexible
|
||||
python generator into a generator object with only one
|
||||
input argument (positional) using functools.partial.
|
||||
input argument (positional) using ``functools.partial``.
|
||||
|
||||
:param generator: A python generator object that creates traffic
|
||||
patterns through calls to methods of PyTrafficGen.
|
||||
patterns through calls to methods of PyTrafficGen.
|
||||
"""
|
||||
if not self._traffic_set:
|
||||
self._set_traffic()
|
||||
@@ -284,18 +288,19 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
used to exit the simulation).
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
duration = fromSeconds(toLatency(duration))
|
||||
rate = toMemoryBandwidth(rate)
|
||||
@@ -330,18 +335,19 @@ class ComplexGeneratorCore(AbstractGeneratorCore):
|
||||
used to exit the simulation).
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
duration = fromSeconds(toLatency(duration))
|
||||
rate = toMemoryBandwidth(rate)
|
||||
|
||||
@@ -52,7 +52,7 @@ def get_cpu_type_from_str(input: str) -> CPUTypes:
|
||||
the enum's value. E.g., "kvm" will return ISA.KVM. Throws an exception if
|
||||
the input string is invalid.
|
||||
|
||||
`get_cpu_types_str_set()` can be used to determine the valid strings.
|
||||
``get_cpu_types_str_set()`` can be used to determine the valid strings.
|
||||
|
||||
This is for parsing text inputs that specify CPU Type targets.
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class GUPSGenerator(AbstractGenerator):
|
||||
clk_freq: Optional[str] = None,
|
||||
):
|
||||
"""The GUPSGenerator class
|
||||
|
||||
This class defines the interface for a single core GUPSGenerator, this
|
||||
generator could be used in place of a processor. For multicore versions
|
||||
of this generator look at GUPSGeneraorEP (EP stands for embarrassingly
|
||||
@@ -51,10 +52,11 @@ class GUPSGenerator(AbstractGenerator):
|
||||
|
||||
:param start_addr: The start address for allocating the update table.
|
||||
:param mem_size: The size of memory to allocate for the update table.
|
||||
Should be a power of 2.
|
||||
Should be a power of 2.
|
||||
:param update_limit: The number of updates to do before terminating
|
||||
simulation. Pass zero to run the benchmark to completion (The amount of
|
||||
time it takes to simulate depends on )
|
||||
simulation. Pass zero to run the benchmark to
|
||||
completion (The amount of time it takes to simulate
|
||||
depends on it).
|
||||
"""
|
||||
super().__init__(
|
||||
cores=[
|
||||
@@ -70,7 +72,7 @@ class GUPSGenerator(AbstractGenerator):
|
||||
@overrides(AbstractGenerator)
|
||||
def start_traffic(self):
|
||||
"""
|
||||
Since GUPSGeneratorCore does not need a call to start_traffic to
|
||||
Since GUPSGeneratorCore does not need a call to ``start_traffic`` to
|
||||
start generation. This function is just pass.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -45,6 +45,7 @@ class GUPSGeneratorEP(AbstractGenerator):
|
||||
clk_freq: Optional[str] = None,
|
||||
):
|
||||
"""The GUPSGeneratorEP class
|
||||
|
||||
This class defines the interface for multi core GUPSGenerator, this
|
||||
generator could be used in place of a processor. In terms of
|
||||
benchmarking this generator implements the embarrassigly parallel
|
||||
@@ -52,10 +53,11 @@ class GUPSGeneratorEP(AbstractGenerator):
|
||||
|
||||
:param start_addr: The start address for allocating the update table.
|
||||
:param mem_size: The size of memory to allocate for the update table.
|
||||
Should be a power of 2.
|
||||
Should be a power of 2.
|
||||
:param update_limit: The number of updates to do before terminating
|
||||
simulation. Pass zero to run the benchmark to completion (The amount of
|
||||
time it takes to simulate depends on )
|
||||
simulation. Pass zero to run the benchmark to
|
||||
completion (The amount of time it takes to simulate
|
||||
depends on it).
|
||||
"""
|
||||
super().__init__(
|
||||
cores=self._create_cores(
|
||||
@@ -94,7 +96,7 @@ class GUPSGeneratorEP(AbstractGenerator):
|
||||
@overrides(AbstractGenerator)
|
||||
def start_traffic(self):
|
||||
"""
|
||||
Since GUPSGeneratorCore does not need a call to start_traffic to
|
||||
Since GUPSGeneratorCore does not need a call to ``start_traffic`` to
|
||||
start generation. This function is just pass.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -46,6 +46,7 @@ class GUPSGeneratorPAR(AbstractGenerator):
|
||||
clk_freq: Optional[str] = None,
|
||||
):
|
||||
"""The GUPSGeneratorPAR class
|
||||
|
||||
This class defines the interface for multi core GUPSGenerator, this
|
||||
generator could be used in place of a processor. In terms of
|
||||
benchmarking this generator implements the parallel (3rd)
|
||||
@@ -53,10 +54,11 @@ class GUPSGeneratorPAR(AbstractGenerator):
|
||||
|
||||
:param start_addr: The start address for allocating the update table.
|
||||
:param mem_size: The size of memory to allocate for the update table.
|
||||
Should be a power of 2.
|
||||
Should be a power of 2.
|
||||
:param update_limit: The number of updates to do before terminating
|
||||
simulation. Pass zero to run the benchmark to completion (The amount of
|
||||
time it takes to simulate depends on )
|
||||
simulation. Pass zero to run the benchmark to
|
||||
completion (The amount of time it takes to simulate
|
||||
depends on it).
|
||||
"""
|
||||
super().__init__(
|
||||
cores=self._create_cores(
|
||||
@@ -89,7 +91,7 @@ class GUPSGeneratorPAR(AbstractGenerator):
|
||||
@overrides(AbstractGenerator)
|
||||
def start_traffic(self):
|
||||
"""
|
||||
Since GUPSGeneratorCore does not need a call to start_traffic to
|
||||
Since GUPSGeneratorCore does not need a call to ``start_traffic`` to
|
||||
start generation. This function is just pass.
|
||||
"""
|
||||
pass
|
||||
|
||||
@@ -65,18 +65,19 @@ class LinearGenerator(AbstractGenerator):
|
||||
|
||||
:param num_cores: The number of linear generator cores to create.
|
||||
:param duration: The number of ticks for the generator to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
|
||||
def _create_cores(
|
||||
|
||||
@@ -61,18 +61,19 @@ class LinearGeneratorCore(AbstractGeneratorCore):
|
||||
uses PyTrafficGen to create and inject the synthetic traffic.
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
self.generator = PyTrafficGen()
|
||||
self._duration = duration
|
||||
|
||||
@@ -64,18 +64,19 @@ class RandomGenerator(AbstractGenerator):
|
||||
|
||||
:param num_cores: The number of linear generator cores to create.
|
||||
:param duration: The number of ticks for the generator to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
|
||||
def _create_cores(
|
||||
|
||||
@@ -61,18 +61,19 @@ class RandomGeneratorCore(AbstractGeneratorCore):
|
||||
PyTrafficGen to create and inject the synthetic traffic.
|
||||
|
||||
:param duration: The number of ticks for the generator core to generate
|
||||
traffic.
|
||||
traffic.
|
||||
:param rate: The rate at which the synthetic data is read/written.
|
||||
:param block_size: The number of bytes to be read/written with each
|
||||
request.
|
||||
request.
|
||||
:param min_addr: The lower bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param max_addr: The upper bound of the address range the generator
|
||||
will read/write from/to.
|
||||
will read/write from/to.
|
||||
:param rd_perc: The percentage of read requests among all the generated
|
||||
requests. The write percentage would be equal to 100 - rd_perc.
|
||||
requests. The write percentage would be equal to
|
||||
``100 - rd_perc``.
|
||||
:param data_limit: The amount of data in bytes to read/write by the
|
||||
generator before stopping generation.
|
||||
generator before stopping generation.
|
||||
"""
|
||||
self.generator = PyTrafficGen()
|
||||
self._duration = duration
|
||||
|
||||
@@ -37,8 +37,8 @@ from .cpu_types import CPUTypes
|
||||
|
||||
class SimpleCore(BaseCPUCore):
|
||||
"""
|
||||
A SimpleCore instantiates a core based on the CPUType enum pass. The
|
||||
SimpleCore creates a single SimObject of that type.
|
||||
A `SimpleCore` instantiates a core based on the CPUType enum pass. The
|
||||
`SimpleCore` creates a single `SimObject` of that type.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -46,13 +46,14 @@ class SimpleProcessor(BaseCPUProcessor):
|
||||
) -> None:
|
||||
"""
|
||||
:param cpu_type: The CPU type for each type in the processor.
|
||||
|
||||
:param num_cores: The number of CPU cores in the processor.
|
||||
|
||||
:param isa: The ISA of the processor. This argument is optional. If not
|
||||
set the `runtime.get_runtime_isa` is used to determine the ISA at
|
||||
runtime. **WARNING**: This functionality is deprecated. It is
|
||||
recommended you explicitly set your ISA via SimpleProcessor
|
||||
construction.
|
||||
set the ``runtime.get_runtime_isa`` is used to determine the
|
||||
ISA at runtime. **WARNING**: This functionality is deprecated.
|
||||
It is recommended you explicitly set your ISA via SimpleProcessor
|
||||
construction.
|
||||
"""
|
||||
if not isa:
|
||||
warn(
|
||||
|
||||
@@ -57,16 +57,16 @@ class SimpleSwitchableProcessor(SwitchableProcessor):
|
||||
) -> None:
|
||||
"""
|
||||
:param starting_core_type: The CPU type for each type in the processor
|
||||
to start with (i.e., when the simulation has just started).
|
||||
to start with (i.e., when the simulation has
|
||||
just started).
|
||||
|
||||
:param switch_core_types: The CPU type for each core, to be switched
|
||||
to..
|
||||
:param switch_core_types: The CPU type for each core, to be switched to.
|
||||
|
||||
:param isa: The ISA of the processor. This argument is optional. If not
|
||||
set the `runtime.get_runtime_isa` is used to determine the ISA at
|
||||
runtime. **WARNING**: This functionality is deprecated. It is
|
||||
recommended you explicitly set your ISA via SimpleSwitchableProcessor
|
||||
construction.
|
||||
set the ``runtime.get_runtime_isa`` is used to determine the
|
||||
ISA at runtime. **WARNING**: This functionality is deprecated.
|
||||
It is recommended you explicitly set your ISA via
|
||||
SimpleSwitchableProcessor construction.
|
||||
"""
|
||||
|
||||
if not isa:
|
||||
|
||||
@@ -46,7 +46,7 @@ class SwitchableProcessor(AbstractProcessor):
|
||||
system using SimpleCores.
|
||||
|
||||
Though this class can be used directly, it is best inherited from. See
|
||||
"SimpleSwitchableCPU" for an example of this.
|
||||
SimpleSwitchableCPU for an example of this.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -45,8 +45,8 @@ class TrafficGenerator(AbstractGenerator):
|
||||
generator cores that could replace the processing cores in a board.
|
||||
|
||||
:param config_file_list: A list containing the path to configuration
|
||||
file each describing the traffic pattern that should be created by
|
||||
each core of the generator.
|
||||
file each describing the traffic pattern that
|
||||
should be created by each core of the generator.
|
||||
"""
|
||||
|
||||
def _create_cores(
|
||||
|
||||
@@ -42,8 +42,8 @@ class TrafficGeneratorCore(AbstractGeneratorCore):
|
||||
a compound traffic specified by the parameters below. It uses
|
||||
TrafficGen to create the traffic.
|
||||
|
||||
:param config_file: path to the configuration file specifying the
|
||||
pattern of traffic.
|
||||
:param config_file: Path to the configuration file specifying the
|
||||
pattern of traffic.
|
||||
"""
|
||||
|
||||
def __init__(self, config_file: str):
|
||||
|
||||
@@ -42,10 +42,11 @@ class ISA(Enum):
|
||||
|
||||
E.g., to check if the X86 ISA is compiled:
|
||||
|
||||
```
|
||||
if buildEnv[f"USE_{ISA.X86.value}_ISA"]:
|
||||
.. code-block::
|
||||
|
||||
if buildEnv[f"USE_{ISA.X86.value}_ISA"]:
|
||||
...
|
||||
```
|
||||
|
||||
"""
|
||||
|
||||
X86 = "x86"
|
||||
@@ -70,7 +71,7 @@ def get_isa_from_str(input: str) -> ISA:
|
||||
the enum's value. E.g., "x86" will return ISA.X86. Throws an exception if
|
||||
the input string is invalid.
|
||||
|
||||
`get_isas_str_set()` can be used to determine the valid strings.
|
||||
``get_isas_str_set()`` can be used to determine the valid strings.
|
||||
|
||||
This is for parsing text inputs that specify ISA targets.
|
||||
|
||||
|
||||
@@ -54,14 +54,14 @@ class X86DemoBoard(X86Board):
|
||||
-------
|
||||
|
||||
An example of using the X86DemoBoard can be found in
|
||||
`configs/example/gem5_library/x86-ubuntu-run.py`.
|
||||
``configs/example/gem5_library/x86-ubuntu-run.py``.
|
||||
|
||||
To run:
|
||||
|
||||
```
|
||||
scons build/X86/gem5.opt -j`nproc`
|
||||
./build/X86/gem5.opt configs/example/gem5_library/x86-ubuntu-run.py
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
scons build/X86/gem5.opt -j`nproc`
|
||||
./build/X86/gem5.opt configs/example/gem5_library/x86-ubuntu-run.py
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -76,11 +76,14 @@ from .riscvmatched_processor import U74Processor
|
||||
def U74Memory():
|
||||
"""
|
||||
Memory for the U74 board.
|
||||
|
||||
DDR4 Subsystem with 16GB of memory.
|
||||
|
||||
Starts at 0x80000000.
|
||||
|
||||
Details at: Section 23, page 195 of the datasheet.
|
||||
|
||||
return: ChanneledMemory
|
||||
:return: ChanneledMemory
|
||||
"""
|
||||
memory = SingleChannelDDR4_2400("16GB")
|
||||
memory.set_memory_range(
|
||||
@@ -96,14 +99,15 @@ class RISCVMatchedBoard(
|
||||
A board capable of full system simulation for RISC-V
|
||||
|
||||
At a high-level, this is based on the HiFive Unmatched board from SiFive.
|
||||
Based on : src/python/gem5/components/boards/riscv_board.py
|
||||
Based on : ``src/python/gem5/components/boards/riscv_board.py``
|
||||
|
||||
This board assumes that you will be booting Linux for fullsystem emulation.
|
||||
|
||||
The frequency of the RTC for the system is set to 1MHz.
|
||||
Details can be found on page 77, section 7.1 of the datasheet.
|
||||
|
||||
Datasheet for inbuilt params can be found here: https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
|
||||
Datasheet for inbuilt params can be found here:
|
||||
https://sifive.cdn.prismic.io/sifive/1a82e600-1f93-4f41-b2d8-86ed8b16acba_fu740-c000-manual-v1p6.pdf
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -307,9 +311,9 @@ class RISCVMatchedBoard(
|
||||
memory.set_memory_range(self.mem_ranges)
|
||||
|
||||
def generate_device_tree(self, outdir: str) -> None:
|
||||
"""Creates the dtb and dts files.
|
||||
"""Creates the ``dtb`` and ``dts`` files.
|
||||
|
||||
Creates two files in the outdir: 'device.dtb' and 'device.dts'
|
||||
Creates two files in the outdir: ``device.dtb`` and ``device.dts``
|
||||
|
||||
:param outdir: Directory to output the files
|
||||
"""
|
||||
|
||||
@@ -60,7 +60,9 @@ class RISCVMatchedCacheHierarchy(
|
||||
|
||||
A cache setup where each core has a private L1 Data and Instruction Cache,
|
||||
and a shared L2 cache.
|
||||
|
||||
The HiFive board has a partially inclusive cache hierarchy, hence this hierarchy is chosen.
|
||||
|
||||
The details of the cache hierarchy are in Table 7, page 36 of the datasheet.
|
||||
|
||||
- L1 Instruction Cache:
|
||||
@@ -78,7 +80,6 @@ class RISCVMatchedCacheHierarchy(
|
||||
) -> None:
|
||||
"""
|
||||
:param l2_size: The size of the L2 Cache (e.g., "256kB").
|
||||
:type l2_size: str
|
||||
"""
|
||||
AbstractClassicCacheHierarchy.__init__(self=self)
|
||||
AbstractTwoLevelCacheHierarchy.__init__(
|
||||
@@ -165,7 +166,7 @@ class RISCVMatchedCacheHierarchy(
|
||||
self.membus.cpu_side_ports = self.l2cache.mem_side
|
||||
|
||||
def _setup_io_cache(self, board: AbstractBoard) -> None:
|
||||
"""Create a cache for coherent I/O connections"""
|
||||
"""Create a cache for coherent I/O connections."""
|
||||
self.iocache = Cache(
|
||||
assoc=8,
|
||||
tag_latency=50,
|
||||
|
||||
@@ -113,7 +113,7 @@ class U74CPU(RiscvMinorCPU):
|
||||
"""
|
||||
The fetch, decode, and execute stage parameters from the ARM HPI CPU
|
||||
This information about the CPU can be found on page 15 of
|
||||
gem5_rsk_gem5-21.2.pdf at https://github.com/arm-university/arm-gem5-rsk
|
||||
`gem5_rsk_gem5-21.2.pdf` at https://github.com/arm-university/arm-gem5-rsk
|
||||
|
||||
The parameters that are changed are:
|
||||
- threadPolicy:
|
||||
@@ -206,8 +206,11 @@ class U74Core(BaseCPUCore):
|
||||
- globalCtrBits: 4
|
||||
- choiceCtrBits: 4
|
||||
- localHistoryTableSize: 4096 B
|
||||
NOTE: The TournamentBP deviates from the actual BP.
|
||||
This configuration performs the best in relation to the hardware.
|
||||
|
||||
.. note::
|
||||
|
||||
The TournamentBP deviates from the actual BP.
|
||||
This configuration performs the best in relation to the hardware.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -47,9 +47,11 @@ from .client_api.client_wrapper import ClientWrapper
|
||||
|
||||
def getFileContent(file_path: Path) -> Dict:
|
||||
"""
|
||||
Get the content of the file at the given path
|
||||
:param file_path: The path of the file
|
||||
:return: The content of the file
|
||||
Get the content of the file at the given path.
|
||||
|
||||
:param file_path: The path of the file.
|
||||
|
||||
:return: The content of the file.
|
||||
"""
|
||||
if file_path.exists():
|
||||
with open(file_path) as file:
|
||||
@@ -136,10 +138,10 @@ def list_resources(
|
||||
|
||||
:param clients: The list of clients to query
|
||||
:param gem5_version: The gem5 version of the resource to get. By default,
|
||||
it is the gem5 version of the current build. If set to none, it will return
|
||||
all gem5 versions of the resource.
|
||||
it is the gem5 version of the current build. If set to
|
||||
``None``, it will return all gem5 versions of the resource.
|
||||
:return: A Python Dict where the key is the resource id and the value is
|
||||
a list of all the supported resource versions.
|
||||
a list of all the supported resource versions.
|
||||
"""
|
||||
return _get_clientwrapper().list_resources(clients, gem5_version)
|
||||
|
||||
@@ -151,13 +153,15 @@ def get_resource_json_obj(
|
||||
gem5_version: Optional[str] = core.gem5Version,
|
||||
) -> Dict:
|
||||
"""
|
||||
Get the resource json object from the clients wrapper
|
||||
:param resource_id: The resource id
|
||||
:param resource_version: The resource version
|
||||
:param clients: The list of clients to query
|
||||
Get the resource json object from the clients wrapper.
|
||||
|
||||
:param resource_id: The resource id.
|
||||
:param resource_version: The resource version.
|
||||
:param clients: The list of clients to query.
|
||||
:param gem5_version: The gem5 versions to filter the resources based on
|
||||
compatibility. By default, it is the gem5 version of the current build.
|
||||
If None, filtering based on compatibility is not performed.
|
||||
compatibility. By default, it is the gem5 version of the
|
||||
current build. If ``None``, filtering based on compatibility
|
||||
is not performed.
|
||||
"""
|
||||
|
||||
return _get_clientwrapper().get_resource_json_obj_from_client(
|
||||
|
||||
@@ -41,8 +41,10 @@ class AbstractClient(ABC):
|
||||
def _url_validator(self, url: str) -> bool:
|
||||
"""
|
||||
Validates the provided URL.
|
||||
|
||||
:param url: The URL to be validated.
|
||||
:return: True if the URL is valid, False otherwise.
|
||||
|
||||
:return: ``True`` if the URL is valid, ``False`` otherwise.
|
||||
"""
|
||||
try:
|
||||
result = urllib.parse.urlparse(url)
|
||||
@@ -59,12 +61,13 @@ class AbstractClient(ABC):
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
:param resource_id: The ID of the Resource. Optional, if not set, all
|
||||
resources will be returned.
|
||||
:param resource_version: The version of the Resource. Optional, if
|
||||
not set, all resource versions will be returned. Note: If `resource_id`
|
||||
is not set, this parameter will be ignored.
|
||||
resources will be returned.
|
||||
:param resource_version: The version of the `Resource`. Optional, if
|
||||
not set, all resource versions will be returned.
|
||||
Note: If ``resource_id`` is not set, this
|
||||
parameter will be ignored.
|
||||
:param gem5_version: The version of gem5. Optional, if not set, all
|
||||
versions will be returned.
|
||||
versions will be returned.
|
||||
:return: A list of all the Resources with the given ID.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
@@ -74,15 +77,19 @@ class AbstractClient(ABC):
|
||||
resources_to_filter: List[Dict[str, Any]],
|
||||
gem5_version: Optional[str] = None,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Returns a filtered list resources based on gem5 version
|
||||
"""
|
||||
Returns a filtered list resources based on gem5 version
|
||||
compatibility.
|
||||
|
||||
Note: This function assumes if the minor component of
|
||||
a resource's gem5_version is not specified, the resource is compatible
|
||||
with all minor versions of the same major version.
|
||||
Likewise, if no hot-fix component is specified, it is assumed that
|
||||
the resource is compatible with all hot-fix versions of the same
|
||||
minor version.
|
||||
.. note::
|
||||
|
||||
This function assumes if the minor component of a resource's
|
||||
gem5_version is not specified, the resource is compatible with all
|
||||
minor versions of the same major version.
|
||||
|
||||
Likewise, if no hot-fix component is specified, it is assumed that
|
||||
the resource is compatible with all hot-fix versions of the same
|
||||
minor version.
|
||||
|
||||
* '20.1' would be compatible with gem5 '20.1.1.0' and '20.1.2.0'.
|
||||
* '21.5.2' would be compatible with gem5 '21.5.2.0' and '21.5.2.0'.
|
||||
@@ -90,8 +97,9 @@ class AbstractClient(ABC):
|
||||
|
||||
:param resources_to_filter: The list of resources to filter.
|
||||
:param gem5_version: The gem5 version in which the filtered resources
|
||||
should be compatible. If None, no filtering will be done.
|
||||
:
|
||||
should be compatible. If ``None``, no filtering will
|
||||
be done.
|
||||
|
||||
"""
|
||||
if not gem5_version:
|
||||
return resources_to_filter
|
||||
@@ -106,6 +114,7 @@ class AbstractClient(ABC):
|
||||
def get_resources_by_id(self, resource_id: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
:param resource_id: The ID of the Resource.
|
||||
|
||||
:return: A list of all the Resources with the given ID.
|
||||
"""
|
||||
return self.get_resources(resource_id=resource_id)
|
||||
|
||||
@@ -76,6 +76,7 @@ class AtlasClient(AbstractClient):
|
||||
def __init__(self, config: Dict[str, str]):
|
||||
"""
|
||||
Initializes a connection to a MongoDB Atlas database.
|
||||
|
||||
:param uri: The URI for connecting to the MongoDB server.
|
||||
:param db: The name of the database to connect to.
|
||||
:param collection: The name of the collection within the database.
|
||||
|
||||
@@ -52,8 +52,10 @@ class ClientWrapper:
|
||||
"""
|
||||
This function creates respective client object for each source in the
|
||||
config file according to the type of source.
|
||||
Params: config: config file containing the source information
|
||||
Returns: clients: dictionary of clients for each source
|
||||
|
||||
:param config: config file containing the source information
|
||||
|
||||
:returns: clients: dictionary of clients for each source
|
||||
"""
|
||||
clients = {}
|
||||
for client in config["sources"]:
|
||||
@@ -106,9 +108,10 @@ class ClientWrapper:
|
||||
"""
|
||||
This function returns all the resources with the given id from all the
|
||||
sources.
|
||||
|
||||
:param resource_id: The id of the resource to search for.
|
||||
:param clients: A list of clients to search through. If None, all
|
||||
clients are searched.
|
||||
:param clients: A list of clients to search through. If ``None``, all
|
||||
clients are searched.
|
||||
:return: A list of resources as Python dictionaries.
|
||||
"""
|
||||
resources = []
|
||||
@@ -147,15 +150,16 @@ class ClientWrapper:
|
||||
"""
|
||||
This function returns the resource object from the client with the
|
||||
given id and version.
|
||||
|
||||
:param resource_id: The id of the resource to search for.
|
||||
:param resource_version: The version of the resource to search for.
|
||||
:param clients: A list of clients to search through. If None, all
|
||||
clients are searched.
|
||||
:param clients: A list of clients to search through. If ``None``, all
|
||||
clients are searched.
|
||||
:param gem5_version: The gem5 version to check compatibility with. If
|
||||
None, no compatibility check is performed. By default, is the current
|
||||
version of gem5.
|
||||
``None``, no compatibility check is performed. By
|
||||
default, is the current version of gem5.
|
||||
:return: The resource object as a Python dictionary if found.
|
||||
If not found, exception is thrown.
|
||||
If not found, exception is thrown.
|
||||
"""
|
||||
# getting all the resources with the given id from the dictionary
|
||||
resources = self.get_all_resources_by_id(resource_id, clients)
|
||||
@@ -196,10 +200,12 @@ class ClientWrapper:
|
||||
"""
|
||||
Searches for the resource with the given version. If the resource is
|
||||
not found, an exception is thrown.
|
||||
|
||||
:param resources: A list of resources to search through.
|
||||
:param resource_version: The version of the resource to search for.
|
||||
|
||||
:return: The resource object as a Python dictionary if found.
|
||||
If not found, None is returned.
|
||||
If not found, ``None`` is returned.
|
||||
"""
|
||||
return_resource = next(
|
||||
iter(
|
||||
@@ -226,23 +232,29 @@ class ClientWrapper:
|
||||
"""
|
||||
Returns a list of compatible resources with the current gem5 version.
|
||||
|
||||
Note: This function assumes if the minor component of
|
||||
a resource's gem5_version is not specified, it that the
|
||||
resource is compatible all minor versions of the same major version.
|
||||
Likewise, if no hot-fix component is specified, it is assumed that
|
||||
the resource is compatible with all hot-fix versions of the same
|
||||
minor version.
|
||||
.. note::
|
||||
|
||||
This function assumes if the minor component of a resource's
|
||||
gem5_version is not specified, it that the resource is compatible
|
||||
all minor versions of the same major version.
|
||||
|
||||
Likewise, if no hot-fix component is specified, it is assumed that
|
||||
the resource is compatible with all hot-fix versions of the same
|
||||
minor version.
|
||||
|
||||
* '20.1' would be compatible with gem5 '20.1.1.0' and '20.1.2.0'.
|
||||
* '21.5.2' would be compatible with gem5 '21.5.2.0' and '21.5.2.0'.
|
||||
* '22.3.2.4' would only be compatible with gem5 '22.3.2.4'.
|
||||
|
||||
:param resources: A list of resources to filter.
|
||||
|
||||
:return: A list of compatible resources as Python dictionaries.
|
||||
|
||||
**Note**: This is a big duplication of code. This functionality already
|
||||
exists in the `AbstractClient` class. This code should be refactored
|
||||
to avoid this duplication.
|
||||
.. note::
|
||||
|
||||
This is a big duplication of code. This functionality already
|
||||
exists in the `AbstractClient` class. This code should be refactored
|
||||
to avoid this duplication.
|
||||
"""
|
||||
|
||||
compatible_resources = []
|
||||
@@ -255,8 +267,11 @@ class ClientWrapper:
|
||||
def _sort_resources(self, resources: List) -> List:
|
||||
"""
|
||||
Sorts the resources by ID.
|
||||
|
||||
If the IDs are the same, the resources are sorted by version.
|
||||
|
||||
:param resources: A list of resources to sort.
|
||||
|
||||
:return: A list of sorted resources.
|
||||
"""
|
||||
|
||||
@@ -264,7 +279,7 @@ class ClientWrapper:
|
||||
"""This is used for sorting resources by ID and version. First
|
||||
the ID is sorted, then the version. In cases where the version
|
||||
contains periods, it's assumed this is to separate a
|
||||
"major.minor.hotfix" style versioning system. In which case, the
|
||||
``major.minor.hotfix`` style versioning system. In which case, the
|
||||
value separated in the most-significant position is sorted before
|
||||
those less significant. If the value is a digit it is cast as an
|
||||
int, otherwise, it is cast as a string, to lower-case.
|
||||
@@ -288,11 +303,13 @@ class ClientWrapper:
|
||||
) -> bool:
|
||||
"""
|
||||
Checks if the resource is compatible with the gem5 version.
|
||||
|
||||
Prints a warning if the resource is not compatible.
|
||||
|
||||
:param resource: The resource to check.
|
||||
:optional param gem5_version: The gem5 version to check
|
||||
compatibility with.
|
||||
:return: True if the resource is compatible, False otherwise.
|
||||
compatibility with.
|
||||
:return: ``True`` if the resource is compatible, ``False`` otherwise.
|
||||
"""
|
||||
if not resource:
|
||||
return False
|
||||
|
||||
@@ -47,6 +47,7 @@ class JSONClient(AbstractClient):
|
||||
def __init__(self, path: str):
|
||||
"""
|
||||
Initializes a JSON client.
|
||||
|
||||
:param path: The path to the Resource, either URL or local.
|
||||
"""
|
||||
self.path = path
|
||||
|
||||
@@ -73,8 +73,8 @@ def _download(url: str, download_to: str, max_attempts: int = 6) -> None:
|
||||
:param download_to: The location the downloaded file is to be stored.
|
||||
|
||||
:param max_attempts: The max number of download attempts before stopping.
|
||||
The default is 6. This translates to roughly 1 minute of retrying before
|
||||
stopping.
|
||||
The default is 6. This translates to roughly 1 minute
|
||||
of retrying before stopping.
|
||||
"""
|
||||
|
||||
# TODO: This whole setup will only work for single files we can get via
|
||||
@@ -188,16 +188,18 @@ def list_resources(
|
||||
Lists all available resources. Returns a dictionary where the key is the
|
||||
id of the resources and the value is a list of that resource's versions.
|
||||
|
||||
:param clients: A list of clients to use when listing resources. If None,
|
||||
all clients will be used. None by default.
|
||||
:param clients: A list of clients to use when listing resources. If ``None``,
|
||||
all clients will be used. ``None`` by default.
|
||||
|
||||
:param gem5_version: The gem5 version to which all resources should be
|
||||
compatible with. If None, compatibility of resources is not considered and
|
||||
all resources will be returned.
|
||||
compatible with. If ``None``, compatibility of resources
|
||||
is not considered and all resources will be returned.
|
||||
|
||||
**Note**: This function is here for legacy reasons. The `list_resources`
|
||||
function was originally stored here. In order to remain backwards
|
||||
compatible, this function will call the `client_list_resources` function
|
||||
.. note::
|
||||
|
||||
This function is here for legacy reasons. The ``list_resources``
|
||||
function was originally stored here. In order to remain backwards
|
||||
compatible, this function will call the ``client_list_resources`` function.
|
||||
|
||||
"""
|
||||
return client_list_resources(clients=clients, gem5_version=gem5_version)
|
||||
@@ -221,36 +223,39 @@ def get_resource(
|
||||
:param resource_name: The resource to be obtained.
|
||||
|
||||
:param to_path: The location in the file system the resource is to be
|
||||
stored. The filename should be included.
|
||||
stored. The filename should be included.
|
||||
|
||||
:param unzip: If true, gzipped resources will be unzipped prior to saving
|
||||
to `to_path`. True by default.
|
||||
:param unzip: If ``True``, gzipped resources will be unzipped prior to saving
|
||||
to ``to_path``. ``True`` by default.
|
||||
|
||||
:param untar: If true, tar achieve resource will be unpacked prior to
|
||||
saving to `to_path`. True by default.
|
||||
:param untar: If ``True``, tar achieve resource will be unpacked prior to
|
||||
saving to ``to_path``. ``True`` by default.
|
||||
|
||||
:param download_md5_mismatch: If a resource is present with an incorrect
|
||||
hash (e.g., an outdated version of the resource is present), `get_resource`
|
||||
will delete this local resource and re-download it if this parameter is
|
||||
True. True by default.
|
||||
hash (e.g., an outdated version of the resource
|
||||
is present), ``get_resource`` will delete this
|
||||
local resource and re-download it if this parameter
|
||||
is ``True``. ``True`` by default.
|
||||
|
||||
:param resource_version: The version of the resource to be obtained. If
|
||||
None, the latest version of the resource compatible with the working
|
||||
directory's gem5 version will be obtained. None by default.
|
||||
``None``, the latest version of the resource compatible
|
||||
with the working directory's gem5 version will be obtained.
|
||||
``None`` by default.
|
||||
|
||||
:param clients: A list of clients to use when obtaining the resource. If
|
||||
None, all clients will be used. None by default.
|
||||
``None``, all clients will be used. ``None`` by default.
|
||||
|
||||
:param gem5_version: The gem5 version to use when obtaining the resource.
|
||||
By default, the version of gem5 being used is used. This is used primarily
|
||||
for testing purposes.
|
||||
By default, the version of gem5 being used is used. This
|
||||
is used primarily for testing purposes.
|
||||
|
||||
:param quiet: If true, no output will be printed to the console (baring
|
||||
exceptions). False by default.
|
||||
:param quiet: If ``True``, no output will be printed to the console (baring
|
||||
exceptions). ``False`` by default.
|
||||
|
||||
:raises Exception: An exception is thrown if a file is already present at
|
||||
`to_path` but it does not have the correct md5 sum. An exception will also
|
||||
be thrown is a directory is present at `to_path`
|
||||
``to_path`` but it does not have the correct md5 sum. An
|
||||
exception will also be thrown is a directory is present
|
||||
at ``to_path``.
|
||||
"""
|
||||
|
||||
# We apply a lock for a specific resource. This is to avoid circumstances
|
||||
@@ -402,11 +407,12 @@ def get_resource(
|
||||
|
||||
def _file_uri_to_path(uri: str) -> Optional[Path]:
|
||||
"""
|
||||
If the URI uses the File scheme (e.g, `file://host/path`) then
|
||||
a Path object for the local path is returned, otherwise None.
|
||||
If the URI uses the File scheme (e.g, ``file://host/path``) then
|
||||
a Path object for the local path is returned, otherwise ``None``.
|
||||
|
||||
**Note:** Only files from localhost are permitted. An exception
|
||||
is thrown otherwise.
|
||||
.. note::
|
||||
|
||||
Only files from localhost are permitted. An exception is thrown otherwise.
|
||||
|
||||
:param uri: The file URI to convert.
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ from m5.params import PcCountPair
|
||||
|
||||
|
||||
class ELFieInfo:
|
||||
"""Stores information to load/run ELFies
|
||||
"""Stores information to load/run ELFies.
|
||||
|
||||
See https://github.com/intel/pinball2elf for more information
|
||||
See https://github.com/intel/pinball2elf for more information.
|
||||
"""
|
||||
|
||||
def __init__(self, start: PcCountPair, end: PcCountPair):
|
||||
@@ -50,6 +50,7 @@ class ELFieInfo:
|
||||
A function is used to setup a PC tracker in all the cores and
|
||||
connect all the tracker to the PC tracker manager to perform
|
||||
multithread PC tracking.
|
||||
|
||||
:param processor: The processor used in the simulation configuration.
|
||||
"""
|
||||
for core in processor.get_cores():
|
||||
|
||||
@@ -43,9 +43,11 @@ from m5.params import PcCountPair
|
||||
class LooppointRegionPC:
|
||||
"""A data structure for storing the Looppoint region's PC information.
|
||||
|
||||
**Note**: This is not intended to be a user-facing class. The classes
|
||||
`LooppointJsonLoader` and `LooppointCSVLoader` can be used to load
|
||||
and restore Simpoint data.
|
||||
.. note::
|
||||
|
||||
This is not intended to be a user-facing class. The classes
|
||||
LooppointJsonLoader and LooppointCSVLoader can be used to load
|
||||
and restore Simpoint data.
|
||||
"""
|
||||
|
||||
def __init__(self, pc: int, globl: int, relative: Optional[int] = None):
|
||||
@@ -97,9 +99,11 @@ class LooppointRegionPC:
|
||||
class LooppointRegionWarmup:
|
||||
"""A data structure for storing a Looppoint region's warmup data.
|
||||
|
||||
**Note**: This is not intended to be a user-facing class. The classes
|
||||
`LooppointJsonLoader` and `LooppointCSVLoader` can be used to load
|
||||
and restore Simpoint data.
|
||||
.. note::
|
||||
|
||||
This is not intended to be a user-facing class. The classes
|
||||
LooppointJsonLoader and LooppointCSVLoader can be used to load
|
||||
and restore SimPoint data.
|
||||
"""
|
||||
|
||||
def __init__(self, start: PcCountPair, end: PcCountPair):
|
||||
@@ -140,9 +144,11 @@ class LooppointRegionWarmup:
|
||||
class LooppointSimulation:
|
||||
"""A data structure to store the simulation region start and end region.
|
||||
|
||||
**Note**: This is not intended to be a user-facing class. The classes
|
||||
`LooppointJsonLoader` and `LooppointCSVLoader` can be used to load
|
||||
and restore Simpoint data.
|
||||
.. note::
|
||||
|
||||
This is not intended to be a user-facing class. The classes
|
||||
LooppointJsonLoader and LooppointCSVLoader can be used to load
|
||||
and restore Simpoint data.
|
||||
"""
|
||||
|
||||
def __init__(self, start: LooppointRegionPC, end: LooppointRegionPC):
|
||||
@@ -193,9 +199,11 @@ class LooppointSimulation:
|
||||
class LooppointRegion:
|
||||
"""A data structure to store Looppoint region information.
|
||||
|
||||
**Note**: This is not intended to be a user-facing class. The classes
|
||||
`LooppointJsonLoader` and `LooppointCSVLoader` can be used to load
|
||||
and restore Simpoint data.
|
||||
.. note::
|
||||
|
||||
This is not intended to be a user-facing class. The classes
|
||||
LooppointJsonLoader and LooppointCSVLoader can be used to load
|
||||
and restore SimPoint data.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -205,11 +213,11 @@ class LooppointRegion:
|
||||
warmup: Optional[LooppointRegionWarmup] = None,
|
||||
):
|
||||
"""
|
||||
:param simulation: The simulation information for this Looppoint
|
||||
region.
|
||||
:param multiplier: The multiplier for this Looppoint region.
|
||||
:param warmup: The warmup information for this Looppoint region.
|
||||
Optional.
|
||||
:param simulation: The simulation information for this LoopPoint
|
||||
region.
|
||||
:param multiplier: The multiplier for this LoopPoint region.
|
||||
:param warmup: The warmup information for this LoopPoint region.
|
||||
Optional.
|
||||
"""
|
||||
self._simulation = simulation
|
||||
self._multiplier = multiplier
|
||||
@@ -224,24 +232,24 @@ class LooppointRegion:
|
||||
return self._multiplier
|
||||
|
||||
def get_warmup(self) -> Optional[LooppointRegionWarmup]:
|
||||
"""If set, returns the warmup region information. Otherwise None."""
|
||||
"""If set, returns the warmup region information. Otherwise ``None``."""
|
||||
return self._warmup
|
||||
|
||||
def get_pc_count_pairs(self) -> List[PcCountPair]:
|
||||
"""Returns the PC count pairs for this Looppoint region."""
|
||||
"""Returns the PC count pairs for this LoopPoint region."""
|
||||
pc_count_pairs = self.get_simulation().get_pc_count_pairs()
|
||||
if self.get_warmup():
|
||||
pc_count_pairs.extend(self.get_warmup().get_pc_count_pairs())
|
||||
return pc_count_pairs
|
||||
|
||||
def update_relatives_counts(self, manager: PcCountTrackerManager) -> None:
|
||||
"""Updates the relative counds of this Looppoint region."""
|
||||
"""Updates the relative counds of this LoopPoint region."""
|
||||
self.get_simulation().update_relatives_counts(
|
||||
manager=manager, include_start=bool(self.get_warmup())
|
||||
)
|
||||
|
||||
def get_start(self) -> PcCountPair:
|
||||
"""Returns the correct starting PcCountPair for this Looppoint
|
||||
"""Returns the correct starting PcCountPair for this LoopPoint
|
||||
region."""
|
||||
if self.get_warmup():
|
||||
return self.get_warmup().get_start()
|
||||
@@ -260,19 +268,19 @@ class LooppointRegion:
|
||||
|
||||
|
||||
class Looppoint:
|
||||
"""Stores all the Looppoint information for a gem5 workload."""
|
||||
"""Stores all the LoopPoint information for a gem5 workload."""
|
||||
|
||||
def __init__(self, regions: Dict[Union[str, int], LooppointRegion]):
|
||||
"""
|
||||
:param regions: A dictionary mapping the region_ids with the
|
||||
LooppointRegions.
|
||||
:param regions: A dictionary mapping the ``region_ids`` with the
|
||||
LoopPointRegions.
|
||||
"""
|
||||
self._regions = regions
|
||||
self._manager = PcCountTrackerManager()
|
||||
self._manager.targets = self.get_targets()
|
||||
|
||||
def set_target_region_id(self, region_id: Union[str, int]) -> None:
|
||||
"""There are use-cases where we want to obtain a looppoint data
|
||||
"""There are use-cases where we want to obtain a LoopPoint data
|
||||
structure containing a single target region via its ID. This function
|
||||
will remove all irrelevant regions."""
|
||||
|
||||
@@ -286,7 +294,7 @@ class Looppoint:
|
||||
self._manager.targets = self.get_targets()
|
||||
|
||||
def get_manager(self) -> PcCountTrackerManager:
|
||||
"""Returns the PcCountTrackerManager for this Looppoint data
|
||||
"""Returns the PcCountTrackerManager for this LoopPoint data
|
||||
structure."""
|
||||
return self._manager
|
||||
|
||||
@@ -323,7 +331,7 @@ class Looppoint:
|
||||
|
||||
def get_current_region(self) -> Optional[Union[str, int]]:
|
||||
"""Returns the region id if the current PC Count pair if significant
|
||||
(e.g. beginning of the checkpoint), otherwise, it returns None to
|
||||
(e.g. beginning of the checkpoint), otherwise, it returns ``None`` to
|
||||
indicate the current PC Count pair is not significant.
|
||||
"""
|
||||
current_pair = self.get_current_pair()
|
||||
@@ -359,7 +367,7 @@ class Looppoint:
|
||||
|
||||
def to_json(self) -> Dict[Union[int, str], Dict]:
|
||||
"""Returns this data-structure as a dictionary for serialization via
|
||||
the `output_json_file` function."""
|
||||
the ``output_json_file`` function."""
|
||||
to_return = {}
|
||||
for region_id in self.get_regions():
|
||||
to_return[region_id] = self.get_regions()[region_id].to_json()
|
||||
@@ -371,18 +379,18 @@ class Looppoint:
|
||||
filepath: str = os.path.join(m5.options.outdir, "looppoint.json"),
|
||||
) -> Dict[int, Dict]:
|
||||
"""
|
||||
This function is used to output the _json_file into a json file
|
||||
This function is used to output the ``_json_file`` into a json file.
|
||||
|
||||
:param input_indent: the indent value of the json file
|
||||
:param filepath: the path of the output json file
|
||||
:param input_indent: The indent value of the json file.
|
||||
:param filepath: The path of the output json file.
|
||||
"""
|
||||
with open(filepath, "w") as file:
|
||||
json.dump(self.to_json(), file, indent=input_indent)
|
||||
|
||||
|
||||
class LooppointCsvLoader(Looppoint):
|
||||
"""This class will create a Looppoint data structure from data extracted
|
||||
from a Looppoint pinpoints file."""
|
||||
"""This class will create a LoopPoint data structure from data extracted
|
||||
from a LoopPoint pinpoints file."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -391,10 +399,10 @@ class LooppointCsvLoader(Looppoint):
|
||||
):
|
||||
"""
|
||||
:params pinpoints_file: The pinpoints file in which the data is to be
|
||||
expected.
|
||||
expected.
|
||||
:params region_id: If set, will only load the specified region data.
|
||||
Otherwise, all region info is loaded. Is used when restoring to a
|
||||
particular region.
|
||||
Otherwise, all region info is loaded. Is used when
|
||||
restoring to a particular region.
|
||||
"""
|
||||
|
||||
regions = {}
|
||||
@@ -470,8 +478,8 @@ class LooppointCsvLoader(Looppoint):
|
||||
|
||||
|
||||
class LooppointJsonLoader(Looppoint):
|
||||
"""This class will create a generate a Looppoint data structure from data
|
||||
extracted from a Looppoint json file."""
|
||||
"""This class will create a generate a LoopPoint data structure from data
|
||||
extracted from a LoopPoint json file."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -479,11 +487,11 @@ class LooppointJsonLoader(Looppoint):
|
||||
region_id: Optional[Union[str, int]] = None,
|
||||
) -> None:
|
||||
"""
|
||||
:param looppoint_file: a json file generated by gem5 that has all the
|
||||
LoopPoint data information
|
||||
:param looppoint_file: A json file generated by gem5 that has all the
|
||||
LoopPoint data information.
|
||||
:params region_id: If set, will only load the specified region data.
|
||||
Otherwise, all region info is loaded. Is used when restoring to a
|
||||
particular region.
|
||||
Otherwise, all region info is loaded. Is used when
|
||||
restoring to a particular region.
|
||||
"""
|
||||
|
||||
_path = (
|
||||
|
||||
@@ -70,8 +70,8 @@ def _md5_update_from_dir(
|
||||
|
||||
def md5(path: Path) -> str:
|
||||
"""
|
||||
Gets the md5 value of a file or directory. `md5_file` is used if the path
|
||||
is a file and `md5_dir` is used if the path is a directory. An exception
|
||||
Gets the md5 value of a file or directory. ``md5_file`` is used if the path
|
||||
is a file and ``md5_dir`` is used if the path is a directory. An exception
|
||||
is returned if the path is not a valid file or directory.
|
||||
|
||||
:param path: The path to get the md5 of.
|
||||
@@ -86,7 +86,7 @@ def md5(path: Path) -> str:
|
||||
|
||||
def md5_file(filename: Path) -> str:
|
||||
"""
|
||||
Gives the md5 hash of a file
|
||||
Gives the md5 hash of a file.
|
||||
|
||||
:filename: The file in which the md5 is to be calculated.
|
||||
"""
|
||||
@@ -99,7 +99,9 @@ def md5_dir(directory: Path) -> str:
|
||||
|
||||
This is achieved by getting the md5 hash of all files in the directory.
|
||||
|
||||
Note: The path of files are also hashed so the md5 of the directory changes
|
||||
if empty files are included or filenames are changed.
|
||||
.. note::
|
||||
|
||||
The path of files are also hashed so the md5 of the directory changes
|
||||
if empty files are included or filenames are changed.
|
||||
"""
|
||||
return str(_md5_update_from_dir(directory, hashlib.md5()).hexdigest())
|
||||
|
||||
@@ -61,22 +61,24 @@ from .looppoint import (
|
||||
"""
|
||||
Resources are items needed to run a simulation, such as a disk image, kernel,
|
||||
or binary. The gem5 project provides pre-built resources, with sources, at
|
||||
<resources.gem5.org>. Here we provide the `AbstractResource` class and its
|
||||
<resources.gem5.org>. Here we provide the AbstractResource class and its
|
||||
various implementations which are designed to encapsulate a resource for use
|
||||
in the gem5 Standard Library.
|
||||
|
||||
These classes may be contructed directly. E.g.:
|
||||
|
||||
```python
|
||||
binary = BinaryResource(local_path="/path/to/binary")
|
||||
```
|
||||
.. code-block:: python
|
||||
|
||||
or obtained via the gem5-resources infrastructure with the `obtain_resource`
|
||||
binary = BinaryResource(local_path="/path/to/binary")
|
||||
|
||||
|
||||
or obtained via the gem5-resources infrastructure with the ``obtain_resource``
|
||||
function:
|
||||
|
||||
```python
|
||||
binary = obtain_resource("resource name here")
|
||||
```
|
||||
.. code-block:: python
|
||||
|
||||
binary = obtain_resource("resource name here")
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -97,12 +99,13 @@ class AbstractResource:
|
||||
):
|
||||
"""
|
||||
:param local_path: The path on the host system where this resource is
|
||||
located.
|
||||
located.
|
||||
:param description: Description describing this resource. Not a
|
||||
required parameter. By default is None.
|
||||
required parameter. By default is ``None``.
|
||||
:param source: The source (as in "source code") for this resource. This
|
||||
string should navigate users to where the source for this resource
|
||||
may be found. Not a required parameter. By default is None.
|
||||
string should navigate users to where the source for this
|
||||
resource may be found. Not a required parameter. By default
|
||||
is ``None``.
|
||||
:param resource_version: Version of the resource itself.
|
||||
"""
|
||||
|
||||
@@ -379,10 +382,10 @@ class CheckpointResource(DirectoryResource):
|
||||
|
||||
|
||||
class SimpointResource(AbstractResource):
|
||||
"""A simpoint resource. This resource stores all information required to
|
||||
perform a Simpoint creation and restore. It contains the Simpoint, the
|
||||
Simpoint interval, the weight for each Simpoint, the full warmup length,
|
||||
and the warmup length for each Simpoint.
|
||||
"""A SimPoint resource. This resource stores all information required to
|
||||
perform a SimPoint creation and restore. It contains the SimPoint, the
|
||||
SimPoint interval, the weight for each SimPoint, the full warmup length,
|
||||
and the warmup length for each SimPoint.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -400,15 +403,17 @@ class SimpointResource(AbstractResource):
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
:param simpoint_interval: The simpoint interval.
|
||||
:param simpoint_list: The simpoint list.
|
||||
:param simpoint_interval: The SimPoint interval.
|
||||
:param simpoint_list: The SimPoint list.
|
||||
:param weight_list: The weight list.
|
||||
:param warmup_interval: The warmup interval. Default to zero (a value
|
||||
of zero means effectively not set).
|
||||
:param workload_name: Simpoints are typically associated with a
|
||||
particular workload due to their dependency on chosen input parameters.
|
||||
This field helps backtrack to that resource if required. This should
|
||||
relate to a workload "name" field in the resource.json file.
|
||||
of zero means effectively not set).
|
||||
:param workload_name: SimPoints are typically associated with a
|
||||
particular workload due to their dependency on
|
||||
chosen input parameters.
|
||||
This field helps backtrack to that resource if
|
||||
required. This should relate to a workload "name"
|
||||
field in the ``resource.json`` file.
|
||||
"""
|
||||
|
||||
super().__init__(
|
||||
@@ -435,13 +440,13 @@ class SimpointResource(AbstractResource):
|
||||
self._warmup_list = [0] * len(self.get_simpoint_start_insts)
|
||||
|
||||
def get_simpoint_list(self) -> List[int]:
|
||||
"""Returns the a list containing all the Simpoints for the workload."""
|
||||
"""Returns the a list containing all the SimPoints for the workload."""
|
||||
return self._simpoint_list
|
||||
|
||||
def get_simpoint_start_insts(self) -> List[int]:
|
||||
"""Returns a lst containing all the Simpoint starting instrunction
|
||||
"""Returns a lst containing all the SimPoint starting instrunction
|
||||
points for the workload. This was calculated by multiplying the
|
||||
Simpoint with the Simpoint interval when it was generated."""
|
||||
SimPoint with the SimPoint interval when it was generated."""
|
||||
return self._simpoint_start_insts
|
||||
|
||||
def get_warmup_interval(self) -> int:
|
||||
@@ -449,35 +454,35 @@ class SimpointResource(AbstractResource):
|
||||
return self._warmup_interval
|
||||
|
||||
def get_weight_list(self) -> List[float]:
|
||||
"""Returns the list that contains the weight for each Simpoint. The
|
||||
"""Returns the list that contains the weight for each SimPoint. The
|
||||
order of the weights matches that of the list returned by
|
||||
`get_simpoint_list(). I.e. `get_weight_list()[3]` is the weight for
|
||||
simpoint `get_simpoint_list()[3]`."""
|
||||
``get_simpoint_list()``. I.e. ``get_weight_list()[3]`` is the weight for
|
||||
SimPoint ``get_simpoint_list()[3]``."""
|
||||
return self._weight_list
|
||||
|
||||
def get_simpoint_interval(self) -> int:
|
||||
"""Returns the Simpoint interval value."""
|
||||
"""Returns the SimPoint interval value."""
|
||||
return self._simpoint_interval
|
||||
|
||||
def get_warmup_list(self) -> List[int]:
|
||||
"""Returns the a list containing the warmup length for each Simpoint.
|
||||
Each warmup length in this list corresponds to the Simpoint at the same
|
||||
index in `get_simpoint_list()`. I.e., `get_warmup_list()[4]` is the
|
||||
warmup length for Simpoint `get_simpoint_list()[4]`."""
|
||||
"""Returns the a list containing the warmup length for each SimPoint.
|
||||
Each warmup length in this list corresponds to the SimPoint at the same
|
||||
index in ``get_simpoint_list()``. I.e., ``get_warmup_list()[4]`` is the
|
||||
warmup length for SimPoint ``get_simpoint_list()[4]``."""
|
||||
return self._warmup_list
|
||||
|
||||
def get_workload_name(self) -> Optional[str]:
|
||||
"""Return the workload name this Simpoint is associated with."""
|
||||
"""Return the workload name this SimPoint is associated with."""
|
||||
return self._workload_name
|
||||
|
||||
def _set_warmup_list(self) -> List[int]:
|
||||
"""
|
||||
This function uses the warmup_interval, fits it into the
|
||||
simpoint_start_insts, and outputs a list of warmup instruction lengths
|
||||
This function uses the ``warmup_interval``, fits it into the
|
||||
``simpoint_start_insts``, and outputs a list of warmup instruction lengths
|
||||
for each SimPoint.
|
||||
|
||||
The warmup instruction length is calculated using the starting
|
||||
instruction of a SimPoint to minus the warmup_interval and the ending
|
||||
instruction of a SimPoint to minus the ``warmup_interval`` and the ending
|
||||
instruction of the last SimPoint. If it is less than 0, then the warmup
|
||||
instruction length is the gap between the starting instruction of a
|
||||
SimPoint and the ending instruction of the last SimPoint.
|
||||
@@ -500,8 +505,8 @@ class SimpointResource(AbstractResource):
|
||||
|
||||
|
||||
class LooppointCsvResource(FileResource, LooppointCsvLoader):
|
||||
"""This Looppoint resource used to create a Looppoint resource from a
|
||||
pinpoints CSV file"""
|
||||
"""This LoopPoint resource used to create a LoopPoint resource from a
|
||||
pinpoints CSV file."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -554,8 +559,8 @@ class LooppointJsonResource(FileResource, LooppointJsonLoader):
|
||||
|
||||
|
||||
class SimpointDirectoryResource(SimpointResource):
|
||||
"""A Simpoint diretory resource. This Simpoint Resource assumes the
|
||||
existance of a directory containing a simpoint file and a weight file."""
|
||||
"""A SimPoint diretory resource. This SimPoint Resource assumes the
|
||||
existance of a directory containing a SimPoint file and a weight file."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -572,11 +577,11 @@ class SimpointDirectoryResource(SimpointResource):
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
:param simpoint_file: The Simpoint file. This file is a list of
|
||||
Simpoints, each on its own line. It should map 1-to-1 to the weights
|
||||
file.
|
||||
:param weight_file: The Simpoint weights file. This file is a list of
|
||||
weights, each on its own line.
|
||||
:param simpoint_file: The SimPoint file. This file is a list of
|
||||
SimPoints, each on its own line. It should map
|
||||
1-to-1 to the weights file.
|
||||
:param weight_file: The SimPoint weights file. This file is a list of
|
||||
weights, each on its own line.
|
||||
"""
|
||||
self._simpoint_file = simpoint_file
|
||||
self._weight_file = weight_file
|
||||
@@ -605,7 +610,7 @@ class SimpointDirectoryResource(SimpointResource):
|
||||
)
|
||||
|
||||
def get_simpoint_file(self) -> Path:
|
||||
"""Return the Simpoint File path."""
|
||||
"""Return the SimPoint File path."""
|
||||
return Path(Path(self._local_path) / self._simpoint_file)
|
||||
|
||||
def get_weight_file(self) -> Path:
|
||||
@@ -615,7 +620,7 @@ class SimpointDirectoryResource(SimpointResource):
|
||||
def _get_weights_and_simpoints_from_file(
|
||||
self,
|
||||
) -> Tuple[List[int], List[int]]:
|
||||
"""This is a helper function to extract the weights and simpoints from
|
||||
"""This is a helper function to extract the weights and SimPoints from
|
||||
the files.
|
||||
"""
|
||||
simpoint_weight_pair = []
|
||||
@@ -666,14 +671,15 @@ class SuiteResource(AbstractResource):
|
||||
**kwargs,
|
||||
) -> None:
|
||||
"""
|
||||
:param workloads: A list of `WorkloadResource` objects
|
||||
created from the `_workloads` parameter.
|
||||
:param workloads: A list of ``WorkloadResource`` objects
|
||||
created from the ``_workloads`` parameter.
|
||||
:param local_path: The path on the host system where this resource is
|
||||
located.
|
||||
located.
|
||||
:param description: Description describing this resource. Not a
|
||||
required parameter. By default is None.
|
||||
required parameter. By default is ``None``.
|
||||
:param source: The source (as in "source code") for this resource
|
||||
on gem5-resources. Not a required parameter. By default is None.
|
||||
on gem5-resources. Not a required parameter. By default
|
||||
is ``None``.
|
||||
:param resource_version: Version of the resource itself.
|
||||
"""
|
||||
self._workloads = workloads
|
||||
@@ -709,12 +715,9 @@ class SuiteResource(AbstractResource):
|
||||
|
||||
def with_input_group(self, input_group: str) -> "SuiteResource":
|
||||
"""
|
||||
Returns a new SuiteResource object with only the workloads that use the
|
||||
specified input group.
|
||||
|
||||
:param input_group: The input group to filter the workloads by.
|
||||
:returns: A new SuiteResource object with only the workloads that use
|
||||
the specified input group.
|
||||
the specified input group.
|
||||
"""
|
||||
|
||||
if input_group not in self.get_input_groups():
|
||||
@@ -739,8 +742,6 @@ class SuiteResource(AbstractResource):
|
||||
|
||||
def get_input_groups(self) -> Set[str]:
|
||||
"""
|
||||
Returns a set of all input groups used by the workloads in a suite.
|
||||
|
||||
:returns: A set of all input groups used by the workloads in a suite.
|
||||
"""
|
||||
return {
|
||||
@@ -792,8 +793,8 @@ class WorkloadResource(AbstractResource):
|
||||
"""
|
||||
Returns the name of the workload function to be run.
|
||||
|
||||
This function is called via the AbstractBoard's `set_workload`
|
||||
function. The parameters from the `get_parameters` function are passed
|
||||
This function is called via the AbstractBoard's ``set_workload``
|
||||
function. The parameters from the ``get_parameters`` function are passed
|
||||
to this function.
|
||||
"""
|
||||
return self._func
|
||||
@@ -803,7 +804,7 @@ class WorkloadResource(AbstractResource):
|
||||
Returns a dictionary mapping the workload parameters to their values.
|
||||
|
||||
These parameters are passed to the function specified by
|
||||
`get_function_str` via the AbstractBoard's `set_workload` function.
|
||||
``get_function_str`` via the AbstractBoard's ``set_workload`` function.
|
||||
"""
|
||||
return self._params
|
||||
|
||||
@@ -832,32 +833,36 @@ def obtain_resource(
|
||||
) -> AbstractResource:
|
||||
"""
|
||||
This function primarily serves as a factory for resources. It will return
|
||||
the correct `AbstractResource` implementation based on the resource
|
||||
the correct AbstractResource implementation based on the resource
|
||||
requested.
|
||||
|
||||
:param resource_name: The name of the gem5 resource as it appears under the
|
||||
"id" field in the `resource.json` file.
|
||||
"id" field in the ``resource.json`` file.
|
||||
:param resource_directory: The location of the directory in which the
|
||||
resource is to be stored. If this parameter is not set, it will set to
|
||||
the environment variable `GEM5_RESOURCE_DIR`. If the environment is not
|
||||
set it will default to `~/.cache/gem5` if available, otherwise the CWD.
|
||||
**Note**: This argument is ignored if the `to_path` parameter is specified.
|
||||
:param download_md5_mismatch: If the resource is present, but does not
|
||||
have the correct md5 value, the resoruce will be deleted and
|
||||
re-downloaded if this value is True. Otherwise an exception will be
|
||||
thrown. True by default.
|
||||
resource is to be stored. If this parameter is not
|
||||
set, it will set to the environment variable
|
||||
``GEM5_RESOURCE_DIR``. If the environment is not set
|
||||
it will default to ``~/.cache/gem5`` if available,
|
||||
otherwise the CWD. *Note*: This argument is ignored
|
||||
if the ``to_path`` parameter is specified.
|
||||
:param download_md5_mismatch: If the resource is present, but does not have
|
||||
the correct md5 value, the resource will be
|
||||
deleted and re-downloaded if this value is ``True``.
|
||||
Otherwise an exception will be thrown. ``True`` by
|
||||
default.
|
||||
:param resource_version: Version of the resource itself.
|
||||
Not a required parameter. None by default.
|
||||
Not a required parameter. ``None`` by default.
|
||||
:param clients: A list of clients to search for the resource. If this
|
||||
parameter is not set, it will default search all clients.
|
||||
parameter is not set, it will default search all clients.
|
||||
:param gem5_version: The gem5 version to use to filter incompatible
|
||||
resource versions. By default set to the current gem5 version. If None,
|
||||
this filtering is not performed.
|
||||
resource versions. By default set to the current gem5
|
||||
version. If `None`, this filtering is not performed.
|
||||
:param to_path: The path to which the resource is to be downloaded. If
|
||||
None, the resource will be downloaded to the resource directory with
|
||||
the file/directory name equal to the ID of the resource. **Note**: Usage
|
||||
of this parameter will override the `resource_directory` parameter.
|
||||
:param quiet: If True, suppress output. False by default.
|
||||
``None``, the resource will be downloaded to the resource directory
|
||||
with the file/directory name equal to the ID of the resource.
|
||||
**Note**: Usage of this parameter will override the
|
||||
``resource_directory`` parameter.
|
||||
:param quiet: If ``True``, suppress output. ``False`` by default.
|
||||
"""
|
||||
|
||||
# Obtain the resource object entry for this resource
|
||||
@@ -1033,16 +1038,17 @@ class CustomResource(AbstractResource):
|
||||
by a gem5 user as opposed to one available within the gem5 resources
|
||||
repository.
|
||||
|
||||
**Warning**: This class is deprecated and will be removed in future
|
||||
releases of gem5. Please use the correct `AbstractResource` subclass
|
||||
instead.
|
||||
.. warning::
|
||||
|
||||
This class is deprecated and will be removed in future releases of gem5.
|
||||
Please use the correct AbstractResource subclass instead.
|
||||
"""
|
||||
|
||||
def __init__(self, local_path: str, metadata: Dict = {}):
|
||||
"""
|
||||
:param local_path: The path of the resource on the host system.
|
||||
:param metadata: Add metadata for the custom resource. **Warning:**
|
||||
As of v22.1.1, this parameter is not used.
|
||||
As of v22.1.1, this parameter is not used.
|
||||
"""
|
||||
warn(
|
||||
"The `CustomResource` class is deprecated. Please use an "
|
||||
@@ -1061,9 +1067,11 @@ class CustomDiskImageResource(DiskImageResource):
|
||||
A custom disk image gem5 resource. It can be used to specify a custom,
|
||||
local disk image.
|
||||
|
||||
**Warning**: This class is deprecated and will be removed in future
|
||||
releases of gem5. Please use the `DiskImageResource` class instead. This
|
||||
class is merely a wrapper for it.
|
||||
.. warning::
|
||||
|
||||
This class is deprecated and will be removed in future releases of gem5.
|
||||
Please use the DiskImageResource class instead. This class is merely
|
||||
a wrapper for it.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -1077,7 +1085,7 @@ class CustomDiskImageResource(DiskImageResource):
|
||||
:param local_path: The path of the disk image on the host system.
|
||||
:param root_partition: The root disk partition to use.
|
||||
:param metadata: Metadata for the resource. **Warning:** As of "
|
||||
"v22.1.1, this parameter is not used.
|
||||
"v22.1.1, this parameter is not used.
|
||||
:param resource_version: Version of the resource itself.
|
||||
"""
|
||||
warn(
|
||||
@@ -1105,12 +1113,12 @@ def Resource(
|
||||
clients: Optional[List[str]] = None,
|
||||
) -> AbstractResource:
|
||||
"""
|
||||
This function was created to maintain backwards compability for v21.1.0
|
||||
This function was created to maintain backwards compatibility for v21.1.0
|
||||
and prior releases of gem5 where `Resource` was a class.
|
||||
|
||||
In the interests of gem5-resource specialization, the `Resource` class
|
||||
has been dropped. Instead users are advized to use the `obtain_resource`
|
||||
function which will return the correct `AbstractResource` implementation.
|
||||
In the interests of gem5-resource specialization, the ``Resource`` class
|
||||
has been dropped. Instead users are advised to use the ``obtain_resource``
|
||||
function which will return the correct AbstractResource implementation.
|
||||
This function (disguised as a class) wraps this function.
|
||||
"""
|
||||
|
||||
|
||||
@@ -47,12 +47,14 @@ def CustomWorkload(function: str, parameters: Dict[str, Any]):
|
||||
A custom workload gem5 resource. It can be used to specify a custom,
|
||||
local workload.
|
||||
|
||||
**Warning**: This `CustomWorkload` class is deprecated. It will be removed in a
|
||||
future release of gem5. Please use the `gem5.resources.resource.WorkloadResource`
|
||||
class instead.
|
||||
.. warning::
|
||||
|
||||
This ``CustomWorkload`` class is deprecated. It will be removed in a
|
||||
future release of gem5. Please use the
|
||||
``gem5.resources.resource.WorkloadResource`` class instead.
|
||||
|
||||
The class has been stealthily converted to a function which wraps the
|
||||
`WorkloadResource` class.
|
||||
``WorkloadResource`` class.
|
||||
"""
|
||||
warn(
|
||||
"The `CustomWorkload` class is deprecated. Please use "
|
||||
@@ -69,12 +71,14 @@ def Workload(
|
||||
gem5_version: Optional[str] = core.gem5Version,
|
||||
):
|
||||
"""
|
||||
**Warning**: The `Workload` class is deprecated. It will be removed in a
|
||||
future release of gem5. Please use the `gem5.resources.resource.WorkloadResource`
|
||||
.. warning::
|
||||
|
||||
The ``Workload`` class is deprecated. It will be removed in a future
|
||||
release of gem5. Please use the ``gem5.resources.resource.WorkloadResource``
|
||||
class instead.
|
||||
|
||||
The class has been stealthily converted to a function which wraps the
|
||||
`WorkloadResource` class.
|
||||
``WorkloadResource`` class.
|
||||
"""
|
||||
warn(
|
||||
"`Workload` has been deprecated. Please use the `obtain_resource` "
|
||||
|
||||
@@ -69,9 +69,10 @@ def get_runtime_isa() -> ISA:
|
||||
one ISA. If neither the "TARGET_ISA" parameter is set and there are
|
||||
multiple ISA targets, an exception is thrown.
|
||||
|
||||
**WARNING**: This function is deprecated and may be removed in future
|
||||
versions of gem5. This function should not be relied upon to run gem5
|
||||
simulations.
|
||||
.. warning::
|
||||
|
||||
This function is deprecated and may be removed in future versions of
|
||||
gem5. This function should not be relied upon to run gem5 simulations.
|
||||
|
||||
:returns: The target ISA.
|
||||
"""
|
||||
@@ -98,6 +99,7 @@ def get_runtime_isa() -> ISA:
|
||||
|
||||
def get_runtime_coherence_protocol() -> CoherenceProtocol:
|
||||
"""Gets the cache coherence protocol.
|
||||
|
||||
This can be inferred at runtime.
|
||||
|
||||
:returns: The cache coherence protocol.
|
||||
|
||||
@@ -60,10 +60,11 @@ class ExitEvent(Enum):
|
||||
This function will translate common exit strings to their correct
|
||||
ExitEvent categorization.
|
||||
|
||||
.. note::
|
||||
|
||||
**Note:** At present, we do not guarantee this list is complete, as
|
||||
there are no bounds on what string may be returned by the simulator
|
||||
given an exit event.
|
||||
At present, we do not guarantee this list is complete, as
|
||||
there are no bounds on what string may be returned by the simulator
|
||||
given an exit event.
|
||||
"""
|
||||
|
||||
if exit_string == "m5_workbegin instruction encountered":
|
||||
|
||||
@@ -61,7 +61,7 @@ def warn_default_decorator(gen: Generator, type: str, effect: str):
|
||||
|
||||
def exit_generator():
|
||||
"""
|
||||
A default generator for an exit event. It will return True, indicating that
|
||||
A default generator for an exit event. It will return ``True``, indicating that
|
||||
the Simulator run loop should exit.
|
||||
"""
|
||||
while True:
|
||||
@@ -86,6 +86,7 @@ def dump_reset_generator():
|
||||
"""
|
||||
A generator for doing statstic dump and reset. It will reset the simulation
|
||||
statistics and then dump simulation statistics.
|
||||
|
||||
The Simulation run loop will continue after executing the behavior of the
|
||||
generator.
|
||||
"""
|
||||
@@ -98,7 +99,8 @@ def dump_reset_generator():
|
||||
def save_checkpoint_generator(checkpoint_dir: Optional[Path] = None):
|
||||
"""
|
||||
A generator for taking a checkpoint. It will take a checkpoint with the
|
||||
input path and the current simulation Ticks.
|
||||
input path and the current simulation ``Ticks``.
|
||||
|
||||
The Simulation run loop will continue after executing the behavior of the
|
||||
generator.
|
||||
"""
|
||||
@@ -133,6 +135,7 @@ def dump_stats_generator():
|
||||
def skip_generator():
|
||||
"""
|
||||
This generator does nothing when on the exit event.
|
||||
|
||||
The simulation will continue after this generator.
|
||||
"""
|
||||
while True:
|
||||
@@ -144,9 +147,9 @@ def simpoints_save_checkpoint_generator(
|
||||
):
|
||||
"""
|
||||
A generator for taking multiple checkpoints for SimPoints. It will save the
|
||||
checkpoints in the checkpoint_dir path with the SimPoints' index.
|
||||
checkpoints in the ``checkpoint_dir`` path with the SimPoints' index.
|
||||
The Simulation run loop will continue after executing the behavior of the
|
||||
generator until all the SimPoints in the simpoint_list has taken a
|
||||
generator until all the SimPoints in the ``simpoint_list`` has taken a
|
||||
checkpoint.
|
||||
"""
|
||||
simpoint_list = simpoint.get_simpoint_start_insts()
|
||||
@@ -184,17 +187,19 @@ def looppoint_save_checkpoint_generator(
|
||||
"""
|
||||
A generator for taking a checkpoint for LoopPoint. It will save the
|
||||
checkpoints in the checkpoint_dir path with the Region id.
|
||||
|
||||
(i.e. "cpt.Region10) It only takes a checkpoint if the current PC Count
|
||||
pair is a significant PC Count Pair. This is determined in the LoopPoint
|
||||
module. The simulation loop continues after exiting this generator.
|
||||
:param checkpoint_dir: where to save the checkpoints
|
||||
:param loopoint: the looppoint object used in the configuration script
|
||||
:param update_relative: if the generator should update the relative count
|
||||
information in the output json file, then it should be True. It is default
|
||||
as True.
|
||||
:param exit_when_empty: if the generator should exit the simulation loop if
|
||||
all PC paris have been discovered, then it should be True. It is default as
|
||||
True.
|
||||
|
||||
:param checkpoint_dir: Where to save the checkpoints.
|
||||
:param loopoint: The LoopPoint object used in the configuration script
|
||||
:param update_relative: If the generator should update the relative count
|
||||
information in the output json file, then it should
|
||||
be ``True``. It is default as ``True``.
|
||||
:param exit_when_empty: If the generator should exit the simulation loop if
|
||||
all PC paris have been discovered, then it should be
|
||||
``True``. It is default as ``True``.
|
||||
"""
|
||||
if exit_when_empty:
|
||||
total_pairs = len(looppoint.get_targets())
|
||||
|
||||
@@ -63,15 +63,17 @@ class Simulator:
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Examples using the Simulator class can be found under
|
||||
`configs/example/gem5_library`.
|
||||
``configs/example/gem5_library``.
|
||||
|
||||
The most basic run would be as follows:
|
||||
|
||||
```
|
||||
simulator = Simulator(board=board)
|
||||
simulator.run()
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
simulator = Simulator(board=board)
|
||||
simulator.run()
|
||||
|
||||
|
||||
This will run a simulation and execute default behavior for exit events.
|
||||
"""
|
||||
@@ -106,64 +108,72 @@ class Simulator:
|
||||
"""
|
||||
:param board: The board to be simulated.
|
||||
:param full_system: Whether to run as a full-system simulation or not.
|
||||
This is optional and used to override default behavior. If not set,
|
||||
whether or not to run in FS mode will be determined via the board's
|
||||
`is_fullsystem()` function.
|
||||
This is optional and used to override default
|
||||
behavior. If not set, whether or not to run in FS
|
||||
mode will be determined via the board's
|
||||
``is_fullsystem()`` function.
|
||||
:param on_exit_event: An optional map to specify what to execute on
|
||||
each exit event. There are three possibilities here: a generator, a
|
||||
list of functions, or a single function.:
|
||||
1. Generator: The generator may yield a boolean each time the
|
||||
associated exit event is encountered. If True the simulator will exit
|
||||
the simulation loop.
|
||||
2. List of functions: Each function must be callable with no mandatory
|
||||
arguments and return a boolean specifying if the Simulation should exit
|
||||
the simulation loop. Upon each exit event the list will pop the start
|
||||
of the list and execute it. If the list is empty the default behavior
|
||||
for that exit event will be executed.
|
||||
3. Single function: The function must be callable with no mandatory
|
||||
arguments and return a boolean specifying if the Simulation should exit
|
||||
or not. This function is executed each time the associated exit event
|
||||
is encountered.
|
||||
:param checkpoint_path: An optional parameter specifying the directory
|
||||
of the checkpoint to instantiate from. When the path is None, no
|
||||
checkpoint will be loaded. By default, the path is None. **This
|
||||
parameter is deprecated. Please set the checkpoint when setting the
|
||||
board's workload**.
|
||||
each exit event. There are three possibilities here:
|
||||
a generator, a list of functions, or a single function.
|
||||
|
||||
`on_exit_event` usage notes
|
||||
1. Generator: The generator may yield a boolean each
|
||||
time the associated exit event is encountered. If
|
||||
``True`` the simulator will exit the simulation loop.
|
||||
|
||||
2. List of functions: Each function must be callable
|
||||
with no mandatory arguments and return a boolean
|
||||
specifying if the Simulation should exit the
|
||||
simulation loop. Upon each exit event the list will
|
||||
pop the start of the list and execute it. If the list
|
||||
is empty the default behavior for that exit event will
|
||||
be executed.
|
||||
|
||||
3. Single function: The function must be callable with
|
||||
no mandatory arguments and return a boolean specifying
|
||||
if the Simulation should exit or not. This function is
|
||||
executed each time the associated exit event is encountered.
|
||||
:param checkpoint_path: An optional parameter specifying the directory of
|
||||
the checkpoint to instantiate from. When the path
|
||||
is ``None``, no checkpoint will be loaded. By default,
|
||||
the path is ``None``. **This parameter is deprecated.
|
||||
Please set the checkpoint when setting the board's
|
||||
workload**.
|
||||
|
||||
``on_exit_event`` usage notes
|
||||
---------------------------
|
||||
|
||||
With Generators
|
||||
===============
|
||||
|
||||
The `on_exit_event` parameter specifies a Python generator for each
|
||||
The ``on_exit_event`` parameter specifies a Python generator for each
|
||||
exit event. `next(<generator>)` is run each time an exit event. The
|
||||
generator may yield a boolean. If this value of this boolean is True
|
||||
generator may yield a boolean. If this value of this boolean is ``True``
|
||||
the Simulator run loop will exit, otherwise
|
||||
the Simulator run loop will continue execution. If the generator has
|
||||
finished (i.e. a `StopIteration` exception is thrown when
|
||||
`next(<generator>)` is executed), then the default behavior for that
|
||||
finished (i.e. a ``StopIteration`` exception is thrown when
|
||||
``next(<generator>)`` is executed), then the default behavior for that
|
||||
exit event is run.
|
||||
|
||||
As an example, a user may specify their own exit event setup like so:
|
||||
|
||||
```
|
||||
def unique_exit_event():
|
||||
processor.switch()
|
||||
yield False
|
||||
m5.stats.dump()
|
||||
yield False
|
||||
yield True
|
||||
.. code-block::
|
||||
|
||||
simulator = Simulator(
|
||||
board=board
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : unique_exit_event(),
|
||||
},
|
||||
)
|
||||
```
|
||||
def unique_exit_event():
|
||||
processor.switch()
|
||||
yield False
|
||||
m5.stats.dump()
|
||||
yield False
|
||||
yield True
|
||||
|
||||
This will execute `processor.switch()` the first time an exit event is
|
||||
simulator = Simulator(
|
||||
board=board
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : unique_exit_event(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
This will execute ``processor.switch()`` the first time an exit event is
|
||||
encountered, will dump gem5 statistics the second time an exit event is
|
||||
encountered, and will terminate the Simulator run loop the third time.
|
||||
|
||||
@@ -176,41 +186,42 @@ class Simulator:
|
||||
|
||||
An example:
|
||||
|
||||
```
|
||||
def stop_simulation() -> bool:
|
||||
return True
|
||||
.. code-block::
|
||||
|
||||
def switch_cpus() -> bool:
|
||||
processor.switch()
|
||||
return False
|
||||
def stop_simulation() -> bool:
|
||||
return True
|
||||
|
||||
def print_hello() -> None:
|
||||
# Here we don't explicitly return a boolean, but the simulator
|
||||
# treats a None return as False. Ergo the Simulation loop is not
|
||||
# terminated.
|
||||
print("Hello")
|
||||
def switch_cpus() -> bool:
|
||||
processor.switch()
|
||||
return False
|
||||
|
||||
def print_hello() -> None:
|
||||
# Here we don't explicitly return a boolean, but the simulator
|
||||
# treats a None return as False. Ergo the Simulation loop is not
|
||||
# terminated.
|
||||
print("Hello")
|
||||
|
||||
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : [
|
||||
print_hello,
|
||||
switch_cpus,
|
||||
print_hello,
|
||||
stop_simulation
|
||||
],
|
||||
},
|
||||
)
|
||||
```
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : [
|
||||
print_hello,
|
||||
switch_cpus,
|
||||
print_hello,
|
||||
stop_simulation
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
Upon each `EXIT` type exit event the list will function as a queue,
|
||||
|
||||
Upon each ``EXIT`` type exit event the list will function as a queue,
|
||||
with the top function of the list popped and executed. Therefore, in
|
||||
this example, the first `EXIT` type exit event will cause `print_hello`
|
||||
to be executed, and the second `EXIT` type exit event will cause the
|
||||
`switch_cpus` function to run. The third will execute `print_hello`
|
||||
this example, the first ``EXIT`` type exit event will cause ``print_hello``
|
||||
to be executed, and the second ``EXIT`` type exit event will cause the
|
||||
``switch_cpus`` function to run. The third will execute ``print_hello``
|
||||
again before finally, on the forth exit event will call
|
||||
`stop_simulation` which will stop the simulation as it returns False.
|
||||
``stop_simulation`` which will stop the simulation as it returns ``False``.
|
||||
|
||||
With a function
|
||||
===============
|
||||
@@ -219,18 +230,20 @@ class Simulator:
|
||||
accept any mandatory parameters and return a boolean specifying if the
|
||||
simulation loop should end after it is executed.
|
||||
An example:
|
||||
```
|
||||
def print_hello() -> bool:
|
||||
print("Hello")
|
||||
return False
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : print_hello
|
||||
},
|
||||
)
|
||||
```
|
||||
The above will print "Hello" on every `Exit` type Exit Event. As the
|
||||
|
||||
.. code-block::
|
||||
|
||||
def print_hello() -> bool:
|
||||
print("Hello")
|
||||
return False
|
||||
simulator = Simulator(
|
||||
board=board,
|
||||
on_exit_event = {
|
||||
ExitEvent.Exit : print_hello
|
||||
},
|
||||
)
|
||||
|
||||
The above will print "Hello" on every ``Exit`` type Exit Event. As the
|
||||
function returns False, the simulation loop will not end on these
|
||||
events.
|
||||
|
||||
@@ -244,7 +257,7 @@ class Simulator:
|
||||
* ExitEvent.EXIT: exit simulation
|
||||
* ExitEvent.CHECKPOINT: take a checkpoint
|
||||
* ExitEvent.FAIL : exit simulation
|
||||
* ExitEvent.SWITCHCPU: call `switch` on the processor
|
||||
* ExitEvent.SWITCHCPU: call ``switch`` on the processor
|
||||
* ExitEvent.WORKBEGIN: reset stats
|
||||
* ExitEvent.WORKEND: exit simulation
|
||||
* ExitEvent.USER_INTERRUPT: exit simulation
|
||||
@@ -253,7 +266,7 @@ class Simulator:
|
||||
* ExitEvent.SIMPOINT_BEGIN: reset stats
|
||||
* ExitEvent.MAX_INSTS: exit simulation
|
||||
|
||||
These generators can be found in the `exit_event_generator.py` module.
|
||||
These generators can be found in the ``exit_event_generator.py`` module.
|
||||
|
||||
"""
|
||||
|
||||
@@ -346,12 +359,15 @@ class Simulator:
|
||||
|
||||
def schedule_simpoint(self, simpoint_start_insts: List[int]) -> None:
|
||||
"""
|
||||
Schedule SIMPOINT_BEGIN exit events
|
||||
Schedule ``SIMPOINT_BEGIN`` exit events
|
||||
|
||||
**Warning:** SimPoints only work with one core
|
||||
.. warning::
|
||||
|
||||
:param simpoint_start_insts: a list of number of instructions
|
||||
indicating the starting point of the simpoints
|
||||
SimPoints only work with one core.
|
||||
|
||||
:param simpoint_start_insts: A list of number of instructions
|
||||
indicating the starting point of
|
||||
the SimPoints.
|
||||
"""
|
||||
if self._board.get_processor().get_num_cores() > 1:
|
||||
warn("SimPoints only work with one core")
|
||||
@@ -361,10 +377,10 @@ class Simulator:
|
||||
|
||||
def schedule_max_insts(self, inst: int) -> None:
|
||||
"""
|
||||
Schedule a MAX_INSTS exit event when any thread in any core reaches the
|
||||
given number of instructions.
|
||||
Schedule a ``MAX_INSTS`` exit event when any thread in any core
|
||||
reaches the given number of instructions.
|
||||
|
||||
:param insts: a number of instructions to run to.
|
||||
:param insts: A number of instructions to run to.
|
||||
"""
|
||||
for core in self._board.get_processor().get_cores():
|
||||
core._set_inst_stop_any_thread(inst, self._instantiated)
|
||||
@@ -375,19 +391,19 @@ class Simulator:
|
||||
to a JSON-style schema.
|
||||
|
||||
:raises Exception: An exception is raised if this function is called
|
||||
before `run()`. The board must be initialized before obtaining
|
||||
statistics.
|
||||
before ``run()``. The board must be initialized
|
||||
before obtaining statistics.
|
||||
"""
|
||||
|
||||
return self.get_simstats().to_json()
|
||||
|
||||
def get_simstats(self) -> SimStat:
|
||||
"""
|
||||
Obtains the SimStat of the current simulation.
|
||||
Obtains the `SimStat` of the current simulation.
|
||||
|
||||
:raises Exception: An exception is raised if this function is called
|
||||
before `run()`. The board must be initialized before obtaining
|
||||
statistics.
|
||||
before ``run()``. The board must be initialized
|
||||
before obtaining statistics.
|
||||
"""
|
||||
|
||||
if not self._instantiated:
|
||||
@@ -545,9 +561,10 @@ class Simulator:
|
||||
events accordingly.
|
||||
|
||||
:param max_ticks: The maximum number of ticks to execute per simulation
|
||||
run. If this max_ticks value is met, a MAX_TICK exit event is
|
||||
received, if another simulation exit event is met the tick count is
|
||||
reset. This is the **maximum number of ticks per simulation run**.
|
||||
run. If this ``max_ticks`` value is met, a ``MAX_TICK``
|
||||
exit event is received, if another simulation exit
|
||||
event is met the tick count is reset. This is the
|
||||
**maximum number of ticks per simulation run**.
|
||||
"""
|
||||
|
||||
# Check to ensure no banned module has been imported.
|
||||
@@ -620,6 +637,6 @@ class Simulator:
|
||||
This function will save the checkpoint to the specified directory.
|
||||
|
||||
:param checkpoint_dir: The path to the directory where the checkpoint
|
||||
will be saved.
|
||||
will be saved.
|
||||
"""
|
||||
m5.checkpoint(str(checkpoint_dir))
|
||||
|
||||
@@ -35,7 +35,7 @@ class FileLockException(Exception):
|
||||
class FileLock:
|
||||
"""A file locking mechanism that has context-manager support so
|
||||
you can use it in a with statement. This should be relatively cross
|
||||
compatible as it doesn't rely on msvcrt or fcntl for the locking.
|
||||
compatible as it doesn't rely on ``msvcrt`` or ``fcntl`` for the locking.
|
||||
"""
|
||||
|
||||
def __init__(self, file_name, timeout=10, delay=0.05):
|
||||
@@ -54,8 +54,8 @@ class FileLock:
|
||||
|
||||
def acquire(self):
|
||||
"""Acquire the lock, if possible. If the lock is in use, it check again
|
||||
every `wait` seconds. It does this until it either gets the lock or
|
||||
exceeds `timeout` number of seconds, in which case it throws
|
||||
every ``wait`` seconds. It does this until it either gets the lock or
|
||||
exceeds ``timeout`` number of seconds, in which case it throws
|
||||
an exception.
|
||||
"""
|
||||
start_time = time.time()
|
||||
@@ -91,7 +91,8 @@ class FileLock:
|
||||
|
||||
def release(self):
|
||||
"""Get rid of the lock by deleting the lockfile.
|
||||
When working in a `with` statement, this gets automatically
|
||||
|
||||
When working in a ``with`` statement, this gets automatically
|
||||
called at the end.
|
||||
"""
|
||||
if self.is_locked:
|
||||
@@ -101,6 +102,7 @@ class FileLock:
|
||||
|
||||
def __enter__(self):
|
||||
"""Activated when used in the with statement.
|
||||
|
||||
Should automatically acquire a lock to be used in the with block.
|
||||
"""
|
||||
if not self.is_locked:
|
||||
@@ -109,6 +111,7 @@ class FileLock:
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
"""Activated at the end of the with statement.
|
||||
|
||||
It automatically releases the lock if it isn't locked.
|
||||
"""
|
||||
if self.is_locked:
|
||||
|
||||
@@ -89,7 +89,7 @@ def _gem5_args_for_multiprocessing(name):
|
||||
|
||||
def get_command_line(name, **kwds):
|
||||
"""
|
||||
Returns prefix of command line used for spawning a child process
|
||||
Returns prefix of command line used for spawning a child process.
|
||||
"""
|
||||
if getattr(sys, "frozen", False):
|
||||
return [sys.executable, "--multiprocessing-fork"] + [
|
||||
|
||||
@@ -30,6 +30,7 @@ def overrides(interface_class):
|
||||
Function override annotation.
|
||||
Corollary to @abc.abstractmethod where the override is not of an
|
||||
abstractmethod.
|
||||
|
||||
Modified from answer https://stackoverflow.com/a/8313042/471376
|
||||
"""
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
|
||||
class FakeTQDM:
|
||||
"""This is a fake wrapper so that the tqdm calls work whether or not it
|
||||
"""This is a fake wrapper so that the ``tqdm`` calls work whether or not it
|
||||
has been installed.
|
||||
"""
|
||||
|
||||
|
||||
@@ -65,11 +65,11 @@ def requires(
|
||||
|
||||
:param isa_required: The ISA(s) gem5 must be compiled to.
|
||||
:param coherence_protocol_required: The coherence protocol gem5 must be
|
||||
compiled to.
|
||||
compiled to.
|
||||
:param kvm_required: The host system must have the Kernel-based Virtual
|
||||
Machine available.
|
||||
Machine available.
|
||||
:raises Exception: Raises an exception if the required ISA or coherence
|
||||
protocol do not match that of the current gem5 binary.
|
||||
protocol do not match that of the current gem5 binary.
|
||||
"""
|
||||
|
||||
supported_isas = get_supported_isas()
|
||||
|
||||
@@ -41,7 +41,7 @@ from gem5.resources.resource import SimpointResource
|
||||
class SimPoint:
|
||||
"""
|
||||
This SimPoint class is used to manage the information needed for SimPoints
|
||||
in workload
|
||||
in workload.
|
||||
|
||||
"""
|
||||
|
||||
@@ -56,33 +56,33 @@ class SimPoint:
|
||||
warmup_interval: int = 0,
|
||||
) -> None:
|
||||
"""
|
||||
:param simpoint_interval: the length of each SimPoints interval
|
||||
:param simpoint_file_path: the path to the SimPoints result file
|
||||
generated by Simpoint3.2 or gem5
|
||||
:param weight_file_path: the path to the weight result file generated
|
||||
by Simpoint3.2 or gem5
|
||||
:param simpoint_interval: The length of each SimPoints interval.
|
||||
:param simpoint_file_path: The path to the SimPoints result file
|
||||
generated by Simpoint3.2 or gem5.
|
||||
:param weight_file_path: The path to the weight result file generated
|
||||
by Simpoint3.2 or gem5.
|
||||
|
||||
:param simpoint_list: a list of SimPoints starting instructions
|
||||
:param weight_list: a list of SimPoints weights
|
||||
:param warmup_interval: a number of instructions for warming up before
|
||||
restoring a SimPoints checkpoint
|
||||
:param simpoint_list: A list of SimPoints starting instructions.
|
||||
:param weight_list: A list of SimPoints weights.
|
||||
:param warmup_interval: A number of instructions for warming up before
|
||||
restoring a SimPoints checkpoint.
|
||||
|
||||
usage note
|
||||
-----------
|
||||
Need to pass in the paths or the lists for the SimPoints and their
|
||||
weights. If the paths are passed in, no actions will be done to the
|
||||
list.
|
||||
.. note::
|
||||
|
||||
When passing in simpoint_list and weight_list, passing in sorted lists
|
||||
(sorted by SimPoints in ascending order) is strongly suggested.
|
||||
The warmup_list only works correctly with sorted simpoint_list.
|
||||
Need to pass in the paths or the lists for the SimPoints and their
|
||||
weights. If the paths are passed in, no actions will be done to the
|
||||
list.
|
||||
|
||||
When passing in ``simpoint_list`` and ``weight_list``, passing in sorted lists
|
||||
(sorted by SimPoints in ascending order) is strongly suggested.
|
||||
The ``warmup_list`` only works correctly with sorted ``simpoint_list``.
|
||||
"""
|
||||
|
||||
warn(
|
||||
"This `SimPoint` class has been deprecated in favor of "
|
||||
"This SimPoint class has been deprecated in favor of "
|
||||
"`SimpointResource` and `SimpointDirectory` resource which may be "
|
||||
"found in `gem5.resources.resource`. Please utilize these. This "
|
||||
"`SimPoint` class will be removed in future releases of gem5."
|
||||
"SimPoint class will be removed in future releases of gem5."
|
||||
)
|
||||
|
||||
# initalize input if you're passing in a CustomResource
|
||||
@@ -133,7 +133,7 @@ class SimPoint:
|
||||
) -> Tuple[List[int], List[int]]:
|
||||
"""
|
||||
This function takes in file paths and outputs a list of SimPoints
|
||||
instruction starts and a list of weights
|
||||
instruction starts and a list of weights.
|
||||
"""
|
||||
simpoint = []
|
||||
with open(simpoint_path) as simpoint_file, open(
|
||||
@@ -160,12 +160,12 @@ class SimPoint:
|
||||
|
||||
def set_warmup_intervals(self, warmup_interval: int) -> List[int]:
|
||||
"""
|
||||
This function takes the warmup_interval, fits it into the
|
||||
_simpoint_start_insts, and outputs a list of warmup instruction lengths
|
||||
This function takes the ``warmup_interval``, fits it into the
|
||||
``_simpoint_start_insts``, and outputs a list of warmup instruction lengths
|
||||
for each SimPoint.
|
||||
|
||||
The warmup instruction length is calculated using the starting
|
||||
instruction of a SimPoint to minus the warmup_interval and the ending
|
||||
instruction of a SimPoint to minus the ``warmup_interval`` and the ending
|
||||
instruction of the last SimPoint. If it is less than 0, then the warmup
|
||||
instruction length is the gap between the starting instruction of a
|
||||
SimPoint and the ending instruction of the last SimPoint.
|
||||
|
||||
@@ -1322,7 +1322,6 @@ class SimObject(metaclass=MetaSimObject):
|
||||
The format is the same as that supported by SimObjectCliWrapper.
|
||||
|
||||
:param simobj_path: Current state to be in.
|
||||
:type simobj_path: str
|
||||
"""
|
||||
d = self._apply_config_get_dict()
|
||||
return eval(simobj_path, d)
|
||||
|
||||
@@ -50,15 +50,16 @@ class AbstractStat(SerializableStat):
|
||||
) -> List["AbstractStat"]:
|
||||
"""Iterate through all of the children, optionally with a predicate
|
||||
|
||||
```
|
||||
>>> system.children(lambda _name: 'cpu' in name)
|
||||
[cpu0, cpu1, cpu2]
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
:param: predicate(str) -> bool: Optional. Each child's name is passed
|
||||
to this function. If it returns true, then the child is
|
||||
yielded. Otherwise, the child is skipped.
|
||||
If not provided then all children are returned.
|
||||
>>> system.children(lambda _name: 'cpu' in name)
|
||||
[cpu0, cpu1, cpu2]
|
||||
|
||||
|
||||
:param predicate: Optional. Each child's name is passed to this function.
|
||||
If it returns ``True``, then the child is yielded.
|
||||
Otherwise, the child is skipped. If not provided then
|
||||
all children are returned.
|
||||
"""
|
||||
|
||||
to_return = []
|
||||
@@ -78,15 +79,18 @@ class AbstractStat(SerializableStat):
|
||||
"""Find all stats that match the name, recursively through all the
|
||||
SimStats.
|
||||
|
||||
.. code-block::
|
||||
|
||||
```
|
||||
>>> system.find('cpu[0-9]')
|
||||
[cpu0, cpu1, cpu2]
|
||||
```
|
||||
Note: The above will not match `cpu_other`.
|
||||
>>> system.find('cpu[0-9]')
|
||||
[cpu0, cpu1, cpu2]
|
||||
|
||||
:param: regex: The regular expression used to search. Can be a
|
||||
precompiled regex or a string in regex format
|
||||
|
||||
.. note::
|
||||
|
||||
The above will not match ``cpu_other``.
|
||||
|
||||
:param regex: The regular expression used to search. Can be a
|
||||
precompiled regex or a string in regex format.
|
||||
"""
|
||||
if isinstance(regex, str):
|
||||
pattern = re.compile(regex)
|
||||
|
||||
@@ -46,17 +46,19 @@ from .statistic import (
|
||||
|
||||
class JsonLoader(json.JSONDecoder):
|
||||
"""
|
||||
Subclass of JSONDecoder that overrides 'object_hook'. Converts JSON object
|
||||
Subclass of JSONDecoder that overrides ``object_hook``. Converts JSON object
|
||||
into a SimStat object.
|
||||
|
||||
Usage
|
||||
-----
|
||||
```
|
||||
from m5.ext.pystats.jsonloader import JsonLoader
|
||||
|
||||
with open(path) as f:
|
||||
simstat_object = json.load(f, cls=JsonLoader)
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
from m5.ext.pystats.jsonloader import JsonLoader
|
||||
|
||||
with open(path) as f:
|
||||
simstat_object = json.load(f, cls=JsonLoader)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@@ -99,12 +101,14 @@ def load(json_file: IO) -> SimStat:
|
||||
|
||||
Usage
|
||||
-----
|
||||
```
|
||||
import m5.ext.pystats as pystats
|
||||
|
||||
with open(path) as f:
|
||||
pystats.jsonloader.load(f)
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
import m5.ext.pystats as pystats
|
||||
|
||||
with open(path) as f:
|
||||
pystats.jsonloader.load(f)
|
||||
|
||||
"""
|
||||
|
||||
simstat_object = json.load(json_file, cls=JsonLoader)
|
||||
|
||||
@@ -44,22 +44,21 @@ class SerializableStat:
|
||||
|
||||
Usage
|
||||
-----
|
||||
```
|
||||
import m5.pystats.gem5stats as gem5stats
|
||||
|
||||
simstat = gem5stats.get_simstat(root)
|
||||
print(simstat.dumps())
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
import m5.pystats.gem5stats as gem5stats
|
||||
|
||||
simstat = gem5stats.get_simstat(root)
|
||||
print(simstat.dumps())
|
||||
|
||||
"""
|
||||
|
||||
def to_json(self) -> Dict:
|
||||
"""
|
||||
Translates the current object into a JSON dictionary.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict
|
||||
The JSON dictionary.
|
||||
:returns: The JSON dictionary.
|
||||
"""
|
||||
|
||||
model_dct = {}
|
||||
@@ -75,15 +74,9 @@ class SerializableStat:
|
||||
Translate values into a value which can be handled by the Python stdlib
|
||||
JSON package.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
value: Any
|
||||
The value to be translated.
|
||||
:param value: The value to be translated.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Union[str,int,float,Dict,List]
|
||||
A value which can be handled by the Python stdlib JSON package.
|
||||
:returns: A value which can be handled by the Python stdlib JSON package.
|
||||
"""
|
||||
|
||||
if isinstance(value, SerializableStat):
|
||||
@@ -102,31 +95,26 @@ class SerializableStat:
|
||||
def dumps(self, **kwargs) -> str:
|
||||
"""
|
||||
This function mirrors the Python stdlib JSON module method
|
||||
`json.dumps`. It is used to obtain the gem5 statistics output to a
|
||||
``json.dumps``. It is used to obtain the gem5 statistics output to a
|
||||
JSON string.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root: Root
|
||||
The root of the simulation.
|
||||
:param root: The root of the simulation.
|
||||
|
||||
kwargs: Dict[str, Any]
|
||||
Additional parameters to be passed to the `json.dumps` method.
|
||||
:param kwargs: Additional parameters to be passed to the ``json.dumps`` method.
|
||||
|
||||
Returns
|
||||
-------
|
||||
str
|
||||
A string of the gem5 Statistics in a JSON format.
|
||||
:returns: A string of the gem5 Statistics in a JSON format.
|
||||
|
||||
|
||||
Usage Example
|
||||
-------------
|
||||
```
|
||||
import m5.pystats.gem5stats as gem5stats
|
||||
|
||||
simstat = gem5stats.get_simstat(root)
|
||||
print(simstat.dumps(indent=6))
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
import m5.pystats.gem5stats as gem5stats
|
||||
|
||||
simstat = gem5stats.get_simstat(root)
|
||||
print(simstat.dumps(indent=6))
|
||||
|
||||
|
||||
The above will print the simulation statistic JSON string. The
|
||||
indentation will be 6 (by default the indentation is 4).
|
||||
@@ -141,27 +129,24 @@ class SerializableStat:
|
||||
def dump(self, fp: IO[str], **kwargs) -> None:
|
||||
"""
|
||||
This function mirrors the Python stdlib JSON module method
|
||||
`json.dump`. The root of the simulation is passed, and the JSON is
|
||||
``json.dump``. The root of the simulation is passed, and the JSON is
|
||||
output to the specified.
|
||||
|
||||
:param fp: The Text IO stream to output the JSON to.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
fp: IO[str]
|
||||
The Text IO stream to output the JSON to.
|
||||
|
||||
**kwargs:
|
||||
Additional parameters to be passed to the ``json.dump`` method.
|
||||
:param kwargs: Additional parameters to be passed to the ``json.dump`` method.
|
||||
|
||||
Usage
|
||||
-----
|
||||
```
|
||||
import m5.pystats.gem5stats as gem5stats
|
||||
|
||||
simstat = gem5stats.get_simstat(root)
|
||||
with open("test.json") as f:
|
||||
simstat.dump(fp=f, indent=6)
|
||||
```
|
||||
.. code-block::
|
||||
|
||||
import m5.pystats.gem5stats as gem5stats
|
||||
|
||||
simstat = gem5stats.get_simstat(root)
|
||||
with open("test.json") as f:
|
||||
simstat.dump(fp=f, indent=6)
|
||||
|
||||
|
||||
The above will dump the json output to the 'test.json' file. The
|
||||
indentation will be of 6 (by default the indentation is 4).
|
||||
|
||||
@@ -116,10 +116,7 @@ class BaseScalarVector(Statistic):
|
||||
"""
|
||||
Returns the mean of the value vector.
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The mean value across all bins.
|
||||
:returns: The mean value across all bins.
|
||||
"""
|
||||
assert self.value != None
|
||||
assert isinstance(self.value, List)
|
||||
@@ -132,10 +129,7 @@ class BaseScalarVector(Statistic):
|
||||
"""
|
||||
Returns the count across all the bins.
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
The sum of all bin values.
|
||||
:returns: The sum of all bin values.
|
||||
"""
|
||||
assert self.value != None
|
||||
return sum(self.value)
|
||||
@@ -146,7 +140,7 @@ class Distribution(BaseScalarVector):
|
||||
A statistic type that stores information relating to distributions. Each
|
||||
distribution has a number of bins (>=1)
|
||||
between this range. The values correspond to the value of each bin.
|
||||
E.g., value[3]` is the value of the 4th bin.
|
||||
E.g., ``value[3]`` is the value of the 4th bin.
|
||||
|
||||
It is assumed each bucket is of equal size.
|
||||
"""
|
||||
|
||||
@@ -244,15 +244,15 @@ def scheduleTickExitFromCurrent(
|
||||
ticks: int, exit_string: str = "Tick exit reached"
|
||||
) -> None:
|
||||
"""Schedules a tick exit event from the current tick. I.e., if ticks == 100
|
||||
then an exit event will be scheduled at tick `curTick() + 100`.
|
||||
then an exit event will be scheduled at tick ``curTick() + 100``.
|
||||
|
||||
The default `exit_string` value is used by the stdlib Simulator module to
|
||||
declare this exit event as `ExitEvent.SCHEDULED_TICK`.
|
||||
The default ``exit_string`` value is used by the stdlib Simulator module to
|
||||
declare this exit event as ``ExitEvent.SCHEDULED_TICK``.
|
||||
|
||||
:param ticks: The simulation ticks, from `curTick()` to schedule the exit
|
||||
event.
|
||||
:param ticks: The simulation ticks, from ``curTick()`` to schedule the exit
|
||||
event.
|
||||
:param exit_string: The exit string to return when the exit event is
|
||||
triggered.
|
||||
triggered.
|
||||
"""
|
||||
scheduleTickExitAbsolute(tick=ticks + curTick(), exit_string=exit_string)
|
||||
|
||||
@@ -263,12 +263,12 @@ def scheduleTickExitAbsolute(
|
||||
"""Schedules a tick exit event using absolute ticks. I.e., if tick == 100
|
||||
then an exit event will be scheduled at tick 100.
|
||||
|
||||
The default `exit_string` value is used by the stdlib Simulator module to
|
||||
declare this exit event as `ExitEvent.SCHEDULED_TICK`.
|
||||
The default ``exit_string`` value is used by the stdlib Simulator module to
|
||||
declare this exit event as ``ExitEvent.SCHEDULED_TICK``.
|
||||
|
||||
:param tick: The absolute simulation tick to schedule the exit event.
|
||||
:param exit_string: The exit string to return when the exit event is
|
||||
triggered.
|
||||
triggered.
|
||||
"""
|
||||
if tick <= curTick():
|
||||
warn("Tick exit scheduled for the past. This will not be triggered.")
|
||||
@@ -351,9 +351,11 @@ def _changeMemoryMode(system, mode):
|
||||
def switchCpus(system, cpuList, verbose=True):
|
||||
"""Switch CPUs in a system.
|
||||
|
||||
Note: This method may switch the memory mode of the system if that
|
||||
is required by the CPUs. It may also flush all caches in the
|
||||
system.
|
||||
.. note::
|
||||
|
||||
This method may switch the memory mode of the system if that
|
||||
is required by the CPUs. It may also flush all caches in the
|
||||
system.
|
||||
|
||||
Arguments:
|
||||
system -- Simulated system.
|
||||
|
||||
@@ -48,7 +48,7 @@ import _m5.stats
|
||||
class JsonOutputVistor:
|
||||
"""
|
||||
This is a helper vistor class used to include a JSON output via the stats
|
||||
API (`src/python/m5/stats/__init__.py`).
|
||||
API (``src/python/m5/stats/__init__.py``).
|
||||
"""
|
||||
|
||||
file: str
|
||||
@@ -56,14 +56,9 @@ class JsonOutputVistor:
|
||||
|
||||
def __init__(self, file: str, **kwargs):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
:param file: The output file location in which the JSON will be dumped.
|
||||
|
||||
file: str
|
||||
The output file location in which the JSON will be dumped.
|
||||
|
||||
kwargs: Dict[str, Any]
|
||||
Additional parameters to be passed to the `json.dumps` method.
|
||||
:param kwargs: Additional parameters to be passed to the ``json.dumps`` method.
|
||||
"""
|
||||
|
||||
self.file = file
|
||||
@@ -74,14 +69,13 @@ class JsonOutputVistor:
|
||||
Dumps the stats of a simulation root (or list of roots) to the output
|
||||
JSON file specified in the JsonOutput constructor.
|
||||
|
||||
WARNING: This dump assumes the statistics have already been prepared
|
||||
for the target root.
|
||||
.. warning::
|
||||
|
||||
Parameters
|
||||
----------
|
||||
This dump assumes the statistics have already been prepared
|
||||
for the target root.
|
||||
|
||||
roots: Union[List[Root], Root]]
|
||||
The Root, or List of roots, whose stats are are to be dumped JSON.
|
||||
|
||||
:param roots: The Root, or List of roots, whose stats are are to be dumped JSON.
|
||||
"""
|
||||
|
||||
with open(self.file, "w") as fp:
|
||||
@@ -93,20 +87,14 @@ def get_stats_group(group: _m5.stats.Group) -> Group:
|
||||
"""
|
||||
Translates a gem5 Group object into a Python stats Group object. A Python
|
||||
statistic Group object is a dictionary of labeled Statistic objects. Any
|
||||
gem5 object passed to this will have its `getStats()` and `getStatGroups`
|
||||
gem5 object passed to this will have its ``getStats()`` and ``getStatGroups``
|
||||
function called, and all the stats translated (inclusive of the stats
|
||||
further down the hierarchy).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
group: _m5.stats.Group
|
||||
The gem5 _m5.stats.Group object to be translated to be a Python stats
|
||||
Group object. Typically this will be a gem5 SimObject.
|
||||
:param group: The gem5 _m5.stats.Group object to be translated to be a Python
|
||||
stats Group object. Typically this will be a gem5 SimObject.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Group
|
||||
The stats group object translated from the input gem5 object.
|
||||
:returns: The stats group object translated from the input gem5 object.
|
||||
"""
|
||||
|
||||
stats_dict = {}
|
||||
@@ -127,16 +115,10 @@ def __get_statistic(statistic: _m5.stats.Info) -> Optional[Statistic]:
|
||||
Translates a _m5.stats.Info object into a Statistic object, to process
|
||||
statistics at the Python level.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
statistic: Info
|
||||
The Info object to be translated to a Statistic object.
|
||||
:param statistic: The Info object to be translated to a Statistic object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Optional[Statistic]
|
||||
The Statistic object of the Info object. Returns None if Info object
|
||||
cannot be translated.
|
||||
:returns: The Statistic object of the Info object. Returns ``None`` if
|
||||
Info object cannot be translated.
|
||||
"""
|
||||
|
||||
assert isinstance(statistic, _m5.stats.Info)
|
||||
@@ -250,22 +232,16 @@ def get_simstat(
|
||||
SimStat object will contain all the stats for all the SimObjects contained
|
||||
within the "root", inclusive of the "root" SimObject/SimObjects.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
root: Union[SimObject, List[SimObject]]
|
||||
A SimObject, or list of SimObjects, of the simulation for translation
|
||||
into a SimStat object. Typically this is the simulation's Root
|
||||
SimObject as this will obtain the entirety of a run's statistics in a
|
||||
single SimStat object.
|
||||
:param root: A SimObject, or list of SimObjects, of the simulation for
|
||||
translation into a SimStat object. Typically this is the
|
||||
simulation's Root SimObject as this will obtain the entirety
|
||||
of a run's statistics in a single SimStat object.
|
||||
|
||||
prepare_stats: bool
|
||||
Dictates whether the stats are to be prepared prior to creating the
|
||||
SimStat object. By default this is 'True'.
|
||||
:param prepare_stats: Dictates whether the stats are to be prepared prior
|
||||
to creating the SimStat object. By default this is
|
||||
``True``.
|
||||
|
||||
Returns
|
||||
-------
|
||||
SimStat
|
||||
The SimStat Object of the current simulation.
|
||||
:Returns: The SimStat Object of the current simulation.
|
||||
|
||||
"""
|
||||
stats_map = {}
|
||||
|
||||
@@ -69,7 +69,7 @@ class multiattrdict(attrdict):
|
||||
|
||||
|
||||
class optiondict(attrdict):
|
||||
"""Modify attrdict so that a missing attribute just returns None"""
|
||||
"""Modify attrdict so that a missing attribute just returns ``None``."""
|
||||
|
||||
def __getattr__(self, attr):
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user