stdlib: Implement Simpoint Resources

This patches does the following:
- Adds 'SimpointResource' which encapsulates Simpoint data and
  functionality. It replaces the old 'gem5.util.simpoint.SimPoint'
  class. Simpoints can be loaded from gem5-resources using the
  `obtain_resource` function.
- Adds 'SimpointDirectoryResource'. This inherits form
  'SimpointResource'. While 'SimpointResource' takes raw Simpoint data
  via parameters, 'SimpointDirectoryResource' assumes the data exists
  in files, in a directory.
- Updates the
  "configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py"
  and
  "configs/example/gem5_library/checkpoints/simpoints-se-restory.py"
  example files to utilize this new Simpoint resource classes.

**Note**: While the old "SimPoint" class
("src/python/gem5/util/simpoint.py") is marked as deprecated, it may be
difficult to utilize given updates to the APIs in the gem5 stdlib Cores
and Simulator modules.

Change-Id: I9bed5c643ffc735838c9f22a58c53547941010e7
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/67339
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Bobby Bruce <bbruce@ucdavis.edu>
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
This commit is contained in:
Bobby R. Bruce
2023-01-20 13:40:22 +00:00
committed by Zhantong Qiu
parent cc838d72a6
commit e1601954f0
9 changed files with 354 additions and 77 deletions

View File

@@ -31,8 +31,8 @@ from ...resources.resource import (
BinaryResource,
CheckpointResource,
SimpointResource,
SimpointDirectoryResource,
)
from gem5.utils.simpoint import SimPoint
from m5.objects import SEWorkload, Process
@@ -125,7 +125,7 @@ class SEBinaryWorkload:
self,
binary: BinaryResource,
arguments: List[str] = [],
simpoint: Union[SimpointResource, SimPoint] = None,
simpoint: SimpointResource = None,
checkpoint: Optional[Union[Path, CheckpointResource]] = None,
) -> None:
"""Set up the system to run a SimPoint workload.
@@ -135,28 +135,23 @@ 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 simpoint: The SimPoint object or Resource that contains the list of
:param simpoint: The SimpointResource that contains the list of
SimPoints starting instructions, the list of weights, and the SimPoints
interval
:param checkpoint: The checkpoint directory. Used to restore the
simulation to that checkpoint.
"""
# convert input to SimPoint if necessary
if isinstance(simpoint, SimpointResource):
self._simpoint_object = SimPoint(simpoint)
else:
assert isinstance(simpoint, SimPoint)
self._simpoint_object = simpoint
self._simpoint_resource = simpoint
if self.get_processor().get_num_cores() > 1:
warn("SimPoints only works with one core")
self.get_processor().get_cores()[0]._set_simpoint(
inst_starts=self._simpoint_object.get_simpoint_start_insts(),
inst_starts=self._simpoint_resource.get_simpoint_start_insts(),
board_initialized=False,
)
@@ -167,11 +162,11 @@ class SEBinaryWorkload:
checkpoint=checkpoint,
)
def get_simpoint(self) -> SimPoint:
def get_simpoint(self) -> SimpointResource:
"""
Returns the SimPoint object set. If no SimPoint object has been set an
exception is thrown.
Returns the SimpointResorce object set. If no SimpointResource object
has been set an exception is thrown.
"""
if getattr(self, "_simpoint_object", None):
return self._simpoint_object
if getattr(self, "_simpoint_resource", None):
return self._simpoint_resource
raise Exception("This board does not have a simpoint set.")

View File

@@ -27,13 +27,13 @@
from abc import ABCMeta
import os
from pathlib import Path
from m5.util import warn
from m5.util import warn, fatal
from .downloader import get_resource, get_resources_json_obj
from ..isas import ISA, get_isa_from_str
from typing import Optional, Dict, Union, Type
from typing import Optional, Dict, Union, Type, Tuple, List
"""
Resources are items needed to run a simulation, such as a disk image, kernel,
@@ -72,7 +72,7 @@ class AbstractResource:
):
"""
:param local_path: The path on the host system where this resource is
located
located.
:param documentation: Documentation describing this resource. Not a
required parameter. By default is None.
:param source: The source (as in "source code") for this resource. This
@@ -280,22 +280,205 @@ class CheckpointResource(DirectoryResource):
)
class SimpointResource(DirectoryResource):
"""A simpoint resource."""
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.
"""
def __init__(
self,
local_path: str,
simpoint_interval: int = None,
simpoint_list: List[int] = None,
weight_list: List[float] = None,
warmup_interval: int = 0,
workload_name: Optional[str] = None,
documentation: Optional[str] = None,
source: Optional[str] = None,
local_path: Optional[str] = None,
**kwargs,
):
"""
: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.
"""
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
self._weight_list = weight_list
self._simpoint_list = simpoint_list
self._simpoint_interval = simpoint_interval
self._warmup_interval = warmup_interval
self._workload_name = workload_name
self._simpoint_start_insts = list(
inst * simpoint_interval for inst in self.get_simpoint_list()
)
if self._warmup_interval != 0:
self._warmup_list = self._set_warmup_list()
else:
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."""
return self._simpoint_list
def get_simpoint_start_insts(self) -> List[int]:
"""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."""
return self._simpoint_start_insts
def get_warmup_interval(self) -> int:
"""Returns the instruction length of the warmup interval."""
return self._warmup_interval
def get_weight_list(self) -> List[float]:
"""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]`."""
return self._weight_list
def get_simpoint_interval(self) -> int:
"""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]`."""
return self._warmup_list
def get_workload_name(self) -> Optional[str]:
"""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
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 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.
"""
warmup_list = []
for index, start_inst in enumerate(self.get_simpoint_start_insts()):
warmup_inst = start_inst - self.get_warmup_interval()
if warmup_inst < 0:
warmup_inst = start_inst
else:
warmup_inst = self.get_warmup_interval()
warmup_list.append(warmup_inst)
# change the starting instruction of a SimPoint to include the
# warmup instruction length
self._simpoint_start_insts[index] = start_inst - warmup_inst
return warmup_list
class SimpointDirectoryResource(SimpointResource):
"""A Simpoint diretory resource. This Simpoint Resource assumes the
existance of a directory containing a simpoint file and a weight file."""
def __init__(
self,
local_path: str,
simpoint_file: str,
weight_file: str,
simpoint_interval: int,
warmup_interval: int,
workload_name: Optional[str] = None,
documentation: Optional[str] = None,
source: Optional[str] = None,
**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.
"""
self._simpoint_file = simpoint_file
self._weight_file = weight_file
# This is a little hack. The functions `get_simpoint_file` and
# `get_weight_file` use the local path, so we set it here despite it
# also being set in the `AbstractResource` constructor. This isn't
# elegant but does not harm.
self._local_path = local_path
(
simpoint_list,
weight_list,
) = self._get_weights_and_simpoints_from_file()
super().__init__(
simpoint_interval=simpoint_interval,
simpoint_list=simpoint_list,
weight_list=weight_list,
warmup_interval=warmup_interval,
workload_name=workload_name,
local_path=local_path,
documentation=documentation,
source=source,
)
def get_simpoint_file(self) -> Path:
"""Return the Simpoint File path."""
return Path(Path(self._local_path) / self._simpoint_file)
def get_weight_file(self) -> Path:
"""Returns the Weight File path."""
return Path(Path(self._local_path) / self._weight_file)
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
the files.
"""
simpoint_weight_pair = []
with open(self.get_simpoint_file()) as simpoint_file, open(
self.get_weight_file()
) as weight_file:
while True:
line = simpoint_file.readline()
if not line:
break
interval = int(line.split(" ", 1)[0])
line = weight_file.readline()
if not line:
fatal("not engough weights")
weight = float(line.split(" ", 1)[0])
simpoint_weight_pair.append((interval, weight))
simpoint_weight_pair.sort(key=lambda obj: obj[0])
# use simpoint to sort
weight_list = []
simpoint_list = []
for simpoint, weight in simpoint_weight_pair:
simpoint_list.append(simpoint)
weight_list.append(weight)
return simpoint_list, weight_list
def obtain_resource(
resource_name: str,
@@ -529,5 +712,6 @@ _get_resource_json_type_map = {
"file": FileResource,
"directory": DirectoryResource,
"simpoint": SimpointResource,
"simpoint-directory": SimpointDirectoryResource,
"resource": Resource,
}

View File

@@ -28,7 +28,7 @@ from typing import Generator, Optional
import m5.stats
from ..components.processors.abstract_processor import AbstractProcessor
from ..components.processors.switchable_processor import SwitchableProcessor
from ..utils.simpoint import SimPoint
from ..resources.resource import SimpointResource
from m5.util import warn
from pathlib import Path
@@ -134,7 +134,7 @@ def skip_generator():
def simpoints_save_checkpoint_generator(
checkpoint_dir: Path, simpoint: SimPoint
checkpoint_dir: Path, simpoint: SimpointResource
):
"""
A generator for taking multiple checkpoints for SimPoints. It will save the

View File

@@ -24,10 +24,10 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.util import fatal
from m5.util import fatal, warn
from pathlib import Path
from typing import List, Tuple
from gem5.resources.resource import Resource, CustomResource
from gem5.resources.resource import SimpointResource
class SimPoint:
@@ -39,7 +39,7 @@ class SimPoint:
def __init__(
self,
simpoint_resource: CustomResource = None,
simpoint_resource: SimpointResource = None,
simpoint_interval: int = None,
simpoint_file_path: Path = None,
weight_file_path: Path = None,
@@ -70,12 +70,19 @@ class SimPoint:
The warmup_list only works correctly with sorted simpoint_list.
"""
warn(
"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."
)
# initalize input if you're passing in a CustomResource
if simpoint_resource is not None:
simpoint_directory = str(simpoint_resource.get_local_path())
simpoint_file_path = Path(simpoint_directory + "/simpoint.simpt")
weight_file_path = Path(simpoint_directory + "/simpoint.weight")
simpoint_file_path = simpoint_directory.get_simpoint_file()
weight_file_path = simpoint_resource.get_weight_file()
simpoint_interval = (
simpoint_resource.get_metadata()
.get("additional_metadata")