stdlib: Specialize the gem5-resources

This commit specializes the Resource class into specific sub-types.

The `Resource`, `CustomResource` and `CustomDiskImageResource` classes
have been deprecated in favor of the `AbstractResource` subclasses.
Custom Resources can be created via the resource specialization
constructor. Resources can be obtained via the gem5-resource
infrastructure with the `obtain_resource` function.

Fully implemented:

- DiskImageResource
- BinaryResource
- KernelResource
- BootloaderResource
- FileResource
- DirectoryResource

Partially implemented:

- SimpointResource
- CheckpointResource

While the schema of the resource.json file has changed, efforts have
been made to ensure backwards compatibility is maintained during this
transition.

Tests are included in this commit to verify this feature works as
expected.

**Note:** The Simpoint tests are disabled in this commit, to be
reenabled when Simpoint resource specialization is fully incorporated
here:
https://gem5-review.googlesource.com/c/public/gem5/+/67339

Change-Id: I77277ecaffc7abc86db08526aacc0b606ef04fe8
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/67175
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-06 16:58:16 +00:00
committed by Zhantong Qiu
parent 3892ee029a
commit 4ee724e054
9 changed files with 837 additions and 197 deletions

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2021 The Regents of the University of California
# Copyright (c) 2021, 2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,7 +27,12 @@
from abc import abstractmethod
from .abstract_board import AbstractBoard
from ...resources.resource import AbstractResource
from ...resources.resource import (
DiskImageResource,
BootloaderResource,
CheckpointResource,
KernelResource,
)
from typing import List, Optional, Union
import os
@@ -89,7 +94,7 @@ class KernelDiskWorkload:
raise NotImplementedError
@abstractmethod
def _add_disk_to_board(self, disk_image: AbstractResource) -> None:
def _add_disk_to_board(self, disk_image: DiskImageResource) -> None:
"""
Sets the configuration needed to add the disk image to the board.
@@ -101,7 +106,7 @@ class KernelDiskWorkload:
raise NotImplementedError
def get_disk_root_partition(
cls, disk_image: AbstractResource
cls, disk_image: DiskImageResource
) -> Optional[str]:
"""
Obtains the root partition of a disk image by inspecting the resource's
@@ -109,14 +114,11 @@ class KernelDiskWorkload:
:returns: The disk image's root partition.
"""
try:
return disk_image.get_metadata()["additional_metadata"][
"root_partition"
]
except KeyError:
return None
return disk_image.get_root_partition()
def get_default_kernel_root_val(self, disk_image: AbstractResource) -> str:
def get_default_kernel_root_val(
self, disk_image: DiskImageResource
) -> 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()`
@@ -134,14 +136,14 @@ class KernelDiskWorkload:
def set_kernel_disk_workload(
self,
kernel: AbstractResource,
disk_image: AbstractResource,
bootloader: Optional[AbstractResource] = None,
kernel: KernelResource,
disk_image: DiskImageResource,
bootloader: Optional[BootloaderResource] = None,
readfile: Optional[str] = None,
readfile_contents: Optional[str] = None,
kernel_args: Optional[List[str]] = None,
exit_on_work_items: bool = True,
checkpoint: Optional[Union[Path, AbstractResource]] = None,
checkpoint: Optional[Union[Path, CheckpointResource]] = None,
) -> None:
"""
This function allows the setting of a full-system run with a Kernel
@@ -212,11 +214,11 @@ class KernelDiskWorkload:
if checkpoint:
if isinstance(checkpoint, Path):
self._checkpoint = checkpoint
elif isinstance(checkpoint, AbstractResource):
elif isinstance(checkpoint, CheckpointResource):
self._checkpoint = Path(checkpoint.get_local_path())
else:
# The checkpoint_dir must be None, Path, Or AbstractResource.
raise Exception(
"Checkpoints must be passed as a Path or an "
"AbstractResource."
"CheckpointResource."
)

View File

@@ -25,7 +25,13 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .abstract_board import AbstractBoard
from ...resources.resource import AbstractResource
from ...resources.resource import (
FileResource,
AbstractResource,
BinaryResource,
CheckpointResource,
SimpointResource,
)
from gem5.utils.simpoint import SimPoint
from m5.objects import SEWorkload, Process
@@ -51,13 +57,13 @@ class SEBinaryWorkload:
def set_se_binary_workload(
self,
binary: AbstractResource,
binary: BinaryResource,
exit_on_work_items: bool = True,
stdin_file: Optional[AbstractResource] = None,
stdin_file: Optional[FileResource] = None,
stdout_file: Optional[Path] = None,
stderr_file: Optional[Path] = None,
arguments: List[str] = [],
checkpoint: Optional[Union[Path, AbstractResource]] = None,
checkpoint: Optional[Union[Path, CheckpointResource]] = None,
) -> None:
"""Set up the system to run a specific binary.
@@ -117,10 +123,10 @@ class SEBinaryWorkload:
def set_se_simpoint_workload(
self,
binary: AbstractResource,
binary: BinaryResource,
arguments: List[str] = [],
simpoint: Union[AbstractResource, SimPoint] = None,
checkpoint: Optional[Union[Path, AbstractResource]] = None,
simpoint: Union[SimpointResource, SimPoint] = None,
checkpoint: Optional[Union[Path, CheckpointResource]] = None,
) -> None:
"""Set up the system to run a SimPoint workload.
@@ -141,7 +147,7 @@ class SEBinaryWorkload:
"""
# convert input to SimPoint if necessary
if isinstance(simpoint, AbstractResource):
if isinstance(simpoint, SimpointResource):
self._simpoint_object = SimPoint(simpoint)
else:
assert isinstance(simpoint, SimPoint)

View File

@@ -323,7 +323,11 @@ def list_resources() -> List[str]:
:returns: A list of resources by name.
"""
return _get_resources(valid_types={"resource"}).keys()
from .resource import _get_resource_json_type_map
return _get_resources(
valid_types=_get_resource_json_type_map.keys()
).keys()
def get_workload_json_obj(workload_name: str) -> Dict:
@@ -356,7 +360,11 @@ def get_resources_json_obj(resource_name: str) -> Dict:
:raises Exception: An exception is raised if the specified resources does
not exist.
"""
resource_map = _get_resources(valid_types={"resource"})
from .resource import _get_resource_json_type_map
resource_map = _get_resources(
valid_types=_get_resource_json_type_map.keys()
)
if resource_name not in resource_map:
raise Exception(

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2021 The Regents of the University of California
# Copyright (c) 2021-2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -27,43 +27,401 @@
from abc import ABCMeta
import os
from pathlib import Path
from m5.util import warn
from .downloader import get_resource, get_resources_json_obj
from typing import Optional, Dict
from ..isas import ISA, get_isa_from_str
from typing import Optional, Dict, Union, Type
"""
A Resource object encapsulates a gem5 resource. 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>.
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
various implementations which are designed to encapsulate a resource for use
in the gem5 Standard Library.
The purpose of this encapsulation is two fold:
These classes may be contructed directly. E.g.:
1. It allows automatic retrieval of gem5 resources. E.g., specifying a resource
which is not local will initiate a download.
2. It provides a location where code may be added to record the resources used
within a simulation. At present this is a TODO work-item.
```python
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")
```
"""
class AbstractResource:
"""
An abstract class which all Resource classes inherit from.
"""
__metaclass__ = ABCMeta
def __init__(self, local_path: str, metadata: Dict = {}):
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
):
"""
:param local_path: The path on the host system where this resource is
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
string should navigate users to where the source for this resource
may be found. Not a required parameter. By default is None.
"""
if not os.path.exists(local_path):
raise Exception(
f"Local path specified for resource, '{local_path}', does not "
"exist."
)
self._local_path = local_path
self._metadata = metadata
self._documentation = documentation
self._source = source
def get_local_path(self) -> str:
"""Returns the local path of the resource."""
return self._local_path
def get_metadata(self) -> Dict:
def get_documentation(self) -> Optional[str]:
"""Returns documentation associated with this resource."""
return self._documentation
def get_source(self) -> Optional[str]:
"""Returns information as to where the source for this resource may be
found.
"""
Returns the raw data from this resource, as seen in the
`resources.json` file. A user may specify the metadata of a local
resource.
"""
return self._metadata
return self._source
class FileResource(AbstractResource):
"""A resource consisting of a single file."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
**kwargs,
):
if not os.path.isfile(local_path):
raise Exception(
f"FileResource path specified, '{local_path}', is not a file."
)
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
class DirectoryResource(AbstractResource):
"""A resource consisting of a directory."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
**kwargs,
):
if not os.path.isdir(local_path):
raise Exception(
f"DirectoryResource path specified, {local_path}, is not a "
"directory."
)
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
class DiskImageResource(FileResource):
"""A Disk Image resource."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
root_partition: Optional[str] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
self._root_partition = root_partition
def get_root_partition(self) -> Optional[str]:
"""Returns, if applicable, the Root Partition of the disk image."""
return self._root_partition
class BinaryResource(FileResource):
"""A binary resource."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
architecture: Optional[Union[ISA, str]] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
self._architecture = None
if architecture:
if isinstance(architecture, str):
self._architecture = get_isa_from_str(architecture)
elif isinstance(architecture, ISA):
self._architecture = architecture
def get_architecture(self) -> Optional[ISA]:
"""Returns the ISA this binary is compiled to."""
return self._architecture
class BootloaderResource(BinaryResource):
"""A bootloader resource."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
architecture: Optional[Union[ISA, str]] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
architecture=architecture,
source=source,
)
class GitResource(DirectoryResource):
"""A git resource."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
class KernelResource(BinaryResource):
"""A kernel resource."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
architecture: Optional[Union[ISA, str]] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
architecture=architecture,
)
class CheckpointResource(DirectoryResource):
"""A checkpoint resource. The following directory structure is expected:
<local_path>:
- board.physmem.store0.pmem
- m5.cpt
"""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
class SimpointResource(DirectoryResource):
"""A simpoint resource."""
def __init__(
self,
local_path: str,
documentation: Optional[str] = None,
source: Optional[str] = None,
**kwargs,
):
super().__init__(
local_path=local_path,
documentation=documentation,
source=source,
)
def obtain_resource(
resource_name: str,
resource_directory: Optional[str] = None,
download_md5_mismatch: bool = True,
) -> AbstractResource:
"""
This function primarily serves as a factory for resources. It will return
the correct `AbstractResource` implementation based on the resource
requested, by referencing the "resource.json" file (by default, that hosted
at https://resources.gem5.org/resources.json). In addition to this, this
function will download the resource if not detected in the
`resource_directory`.
:param resource_name: The name of the gem5 resource as it appears under the
"name" 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.
: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.
"""
# If the `resource_directory` parameter is not set via this function, we
# check the "GEM5_RESOURCE_DIR" environment variable. If this too is not
# set we call `_get_default_resource_dir()` to determine where the
# resource directory is, or should be, located.
if resource_directory == None:
resource_directory = os.getenv(
"GEM5_RESOURCE_DIR", _get_default_resource_dir()
)
# Small checks here to ensure the resource directory is valid.
if os.path.exists(resource_directory):
if not os.path.isdir(resource_directory):
raise Exception(
"gem5 resource directory, "
"'{}', exists but is not a directory".format(
resource_directory
)
)
else:
# `exist_ok=True` here as, occasionally, if multiple instance of
# gem5 are started simultaneously, a race condition can exist to
# create the resource directory. Without `exit_ok=True`, threads
# which lose this race will thrown a `FileExistsError` exception.
# `exit_ok=True` ensures no exception is thrown.
os.makedirs(resource_directory, exist_ok=True)
# This is the path to which the resource is to be stored.
to_path = os.path.join(resource_directory, resource_name)
# Download the resource if it does not already exist.
get_resource(
resource_name=resource_name,
to_path=os.path.join(resource_directory, resource_name),
download_md5_mismatch=download_md5_mismatch,
)
# Obtain the JSON resource entry for this resource
resource_json = get_resources_json_obj(resource_name)
# Obtain the type from the JSON. From this we will determine what subclass
# of `AbstractResource` we are to create and return.
resources_type = resource_json["type"]
if resources_type == "resource":
# This is a stop-gap measure to ensure to work with older versions of
# the "resource.json" file. These should be replaced with their
# respective specializations ASAP and this case removed.
if (
"additional_metadata" in resource_json
and "root_partition" in resource_json["additional_metadata"]
):
# In this case we should return a DiskImageResource.
root_partition = resource_json["additional_metadata"][
"root_partition"
]
return DiskImageResource(
local_path=to_path, root_partition=root_partition
)
return CustomResource(local_path=to_path)
assert resources_type in _get_resource_json_type_map
resource_class = _get_resource_json_type_map[resources_type]
# Once we know what AbstractResource subclass we are using, we create it.
# The fields in the JSON object are assumed to map like-for-like to the
# subclass contructor, so we can pass the resource_json map directly.
return resource_class(local_path=to_path, **resource_json)
def _get_default_resource_dir() -> str:
"""
Obtain the default gem5 resources directory on the host system. This
function will iterate through sensible targets until it finds one that
works on the host system.
:returns: The default gem5 resources directory.
"""
test_list = [
# First try `~/.cache/gem5`.
os.path.join(Path.home(), ".cache", "gem5"),
# Last resort, just put things in the cwd.
os.path.join(Path.cwd(), "resources"),
]
for path in test_list:
if os.path.exists(path): # If the path already exists...
if os.path.isdir(path): # Check to see the path is a directory.
return path # If so, the path is valid and can be used.
else: # If the path does not exist, try to create it.
try:
os.makedirs(path, exist_ok=False)
return path
except OSError:
continue # If the path cannot be created, then try another.
raise Exception("Cannot find a valid location to download resources")
# The following classes exist to preserve backwards functionality between the
# API for obtaining resources in v21.1.0 and prior.
class CustomResource(AbstractResource):
@@ -71,134 +429,101 @@ class CustomResource(AbstractResource):
A custom gem5 resource. This can be used to encapsulate a resource provided
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.
"""
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.
:param metadata: Add metadata for the custom resource. **Warning:**
As of v22.1.1, this parameter is not used.
"""
super().__init__(local_path=local_path, metadata=metadata)
warn(
"The `CustomResource` class is deprecated. Please use an "
"`AbstractResource` subclass instead."
)
if bool(metadata): # Empty dicts cast to False
warn(
"the `metadata` parameter was set via the `CustomResource` "
"constructor. This parameter is not used."
)
super().__init__(local_path=local_path)
class CustomDiskImageResource(CustomResource):
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.
"""
def __init__(
self,
local_path: str,
disk_root_partition: Optional[str] = None,
root_partition: Optional[str] = None,
metadata: Dict = {},
):
"""
:param local_path: The path of the disk image on the host system.
:param disk_root_partition: The root disk partition to use.
:param metadata: Metadata for the resource.
: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.
"""
# Behind the scenes, we set the the root partition via the metadata.
# For a traditional, non-custom, resource it is the metadata that is
# used to specify the disk image partition root. Therefore, when the
# root disk partition specified during the construction, we apply it as
# metadata.
if disk_root_partition:
disk_root_partition_dict = {
"additional_metadata": {"root_partition": disk_root_partition}
}
metadata.update(disk_root_partition_dict)
super().__init__(local_path=local_path, metadata=metadata)
class Resource(AbstractResource):
"""
An official gem5 resources as hosted within our gem5 resources repository
(<resources.gem5.org>).
A user need only specify the name of the resource during construction. The
resource will be downloaded if needed. A list of available resources can
be obtained via `downloader.list_resources()`.
"""
def __init__(
self,
resource_name: str,
resource_directory: Optional[str] = None,
download_md5_mismatch: bool = True,
):
"""
:param resource_name: The name of the gem5 resource.
: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.
: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.
"""
if resource_directory == None:
resource_directory = os.getenv(
"GEM5_RESOURCE_DIR", self._get_default_resource_dir()
warn(
"The `CustomDiskImageResource` class is deprecated. Please use "
"`DiskImageResource` instead."
)
if bool(metadata): # Empty dicts cast to False
warn(
"the `metadata` parameter was set via the "
"`CustomDiskImageResource` constructor. This parameter is not "
"used."
)
super().__init__(local_path=local_path, root_partition=root_partition)
if os.path.exists(resource_directory):
if not os.path.isdir(resource_directory):
raise Exception(
"gem5 resource directory, "
"'{}', exists but is not a directory".format(
resource_directory
)
)
else:
# `exist_ok=True` here as, occasionally, if multiple instance of
# gem5 are started simultaneously, a race condition can exist to
# create the resource directory. Without `exit_ok=True`, threads
# which lose this race will thrown a `FileExistsError` exception.
# `exit_ok=True` ensures no exception is thrown.
os.makedirs(resource_directory, exist_ok=True)
to_path = os.path.join(resource_directory, resource_name)
def Resource(
resource_name: str,
resource_directory: Optional[str] = None,
download_md5_mismatch: bool = True,
) -> AbstractResource:
"""
This function was created to maintain backwards compability for v21.1.0
and prior releases of gem5 where `Resource` was a class.
super().__init__(
local_path=to_path, metadata=get_resources_json_obj(resource_name)
)
get_resource(
resource_name=resource_name,
to_path=to_path,
download_md5_mismatch=download_md5_mismatch,
)
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.
This function (disguised as a class) wraps this function.
"""
def _get_default_resource_dir(cls) -> str:
"""
Obtain the default gem5 resources directory on the host system. This
function will iterate through sensible targets until it finds one that
works on the host system.
warn(
"`Resource` has been deprecated. Please use the `obtain_resource` "
"function instead."
)
:returns: The default gem5 resources directory.
"""
test_list = [
# First try `~/.cache/gem5`.
os.path.join(Path.home(), ".cache", "gem5"),
# Last resort, just put things in the cwd.
os.path.join(Path.cwd(), "resources"),
]
return obtain_resource(
resource_name=resource_name,
resource_directory=resource_directory,
download_md5_mismatch=download_md5_mismatch,
)
for path in test_list:
if os.path.exists(path): # If the path already exists...
if os.path.isdir(
path
): # Check to see the path is a directory.
return path # If so, the path is valid and can be used.
else: # If the path does not exist, try to create it.
try:
os.makedirs(path, exist_ok=False)
return path
except OSError:
continue # If the path cannot be created, then try another.
raise Exception("Cannot find a valid location to download resources")
_get_resource_json_type_map = {
"disk-image": DiskImageResource,
"binary": BinaryResource,
"kernel": KernelResource,
"checkpoint": CheckpointResource,
"git": GitResource,
"bootloader": BootloaderResource,
"file": FileResource,
"directory": DirectoryResource,
"simpoint": SimpointResource,
"resource": Resource,
}

View File

@@ -25,7 +25,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from .downloader import get_workload_json_obj
from .resource import Resource
from .resource import obtain_resource
from typing import Dict, Any, Optional
@@ -209,7 +209,7 @@ class Workload(AbstractWorkload):
assert isinstance(key, str)
value = workload_json["resources"][key]
assert isinstance(value, str)
params[key] = Resource(
params[key] = obtain_resource(
value, resource_directory=resource_directory
)

View File

@@ -94,44 +94,44 @@ gem5_verify_config(
length=constants.quick_tag,
)
gem5_verify_config(
name="test-simpoints-se-checkpoint",
fixtures=(),
verifiers=(),
config=joinpath(
config.base_dir,
"configs",
"example",
"gem5_library",
"checkpoints",
"simpoints-se-checkpoint.py",
),
config_args=[
"--checkpoint-path",
joinpath(resource_path, "se_checkpoint_folder-save"),
],
valid_isas=(constants.all_compiled_tag,),
valid_hosts=constants.supported_hosts,
length=constants.quick_tag,
)
# gem5_verify_config(
# name="test-simpoints-se-checkpoint",
# fixtures=(),
# verifiers=(),
# config=joinpath(
# config.base_dir,
# "configs",
# "example",
# "gem5_library",
# "checkpoints",
# "simpoints-se-checkpoint.py",
# ),
# config_args=[
# "--checkpoint-path",
# joinpath(resource_path, "se_checkpoint_folder-save"),
# ],
# valid_isas=(constants.all_compiled_tag,),
# valid_hosts=constants.supported_hosts,
# length=constants.quick_tag,
# )
gem5_verify_config(
name="test-simpoints-se-restore",
fixtures=(),
verifiers=(),
config=joinpath(
config.base_dir,
"configs",
"example",
"gem5_library",
"checkpoints",
"simpoints-se-restore.py",
),
config_args=[],
valid_isas=(constants.all_compiled_tag,),
valid_hosts=constants.supported_hosts,
length=constants.quick_tag,
)
# gem5_verify_config(
# name="test-simpoints-se-restore",
# fixtures=(),
# verifiers=(),
# config=joinpath(
# config.base_dir,
# "configs",
# "example",
# "gem5_library",
# "checkpoints",
# "simpoints-se-restore.py",
# ),
# config_args=[],
# valid_isas=(constants.all_compiled_tag,),
# valid_hosts=constants.supported_hosts,
# length=constants.quick_tag,
# )
if os.access("/dev/kvm", mode=os.R_OK | os.W_OK):
# The x86-ubuntu-run uses KVM cores, this test will therefore only be run

View File

@@ -0,0 +1,196 @@
# Copyright (c) 2023 The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import os
import unittest
from gem5.resources.resource import *
from gem5.isas import ISA
class ResourceSpecializationSuite(unittest.TestCase):
"""This suite tests that `gem5.resource.resource` casts to the correct
`AbstractResource` specialization when using the `obtain_resource`
function.
"""
@classmethod
def setUpClass(cls):
"""Prior to running the suite we set the resource directory to
"ref/resource-specialization.json"
"""
os.environ["GEM5_RESOURCE_JSON"] = os.path.join(
os.path.realpath(os.path.dirname(__file__)),
"refs",
"resource-specialization.json",
)
@classmethod
def tearDownClass(cls) -> None:
"""After running the suite we unset the gem5-resource JSON file, as to
not interfere with others tests.
"""
del os.environ["GEM5_RESOURCE_JSON"]
def get_resource_dir(cls) -> str:
"""To ensure the resources are cached to the same directory as all
other tests, this function returns the location of the testing
directories "resources" directory.
"""
return os.path.join(
os.path.realpath(os.path.dirname(__file__)),
os.pardir,
os.pardir,
os.pardir,
"gem5",
"resources",
)
def test_binary_resource(self) -> None:
"""Tests the loading of of a BinaryResource"""
resource = obtain_resource(
resource_name="binary-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, BinaryResource)
self.assertEquals(
"binary-example documentation.", resource.get_documentation()
)
self.assertEquals("src/simple", resource.get_source())
self.assertEquals(ISA.ARM, resource.get_architecture())
def test_kernel_resource(self) -> None:
"""Tests the loading of a KernelResource."""
resource = obtain_resource(
resource_name="kernel-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, KernelResource)
self.assertEquals(
"kernel-example documentation.", resource.get_documentation()
)
self.assertEquals("src/linux-kernel", resource.get_source())
self.assertEquals(ISA.RISCV, resource.get_architecture())
def test_bootloader_resource(self) -> None:
"""Tests the loading of a BootloaderResource."""
resource = obtain_resource(
resource_name="bootloader-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, BootloaderResource)
self.assertEquals(
"bootloader documentation.", resource.get_documentation()
)
self.assertIsNone(resource.get_source())
self.assertIsNone(resource.get_architecture())
def test_disk_image_resource(self) -> None:
"""Tests the loading of a DiskImageResource."""
resource = obtain_resource(
resource_name="disk-image-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, DiskImageResource)
self.assertEquals(
"disk-image documentation.", resource.get_documentation()
)
self.assertEquals("src/x86-ubuntu", resource.get_source())
self.assertEquals("1", resource.get_root_partition())
def test_checkpoint_resource(self) -> None:
"""Tests the loading of a CheckpointResource."""
resource = obtain_resource(
resource_name="checkpoint-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, CheckpointResource)
self.assertEquals(
"checkpoint-example documentation.", resource.get_documentation()
)
self.assertIsNone(resource.get_source())
def test_git_resource(self) -> None:
"""Tests the loading of a GitResource."""
resource = obtain_resource(
resource_name="git-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, GitResource)
self.assertIsNone(resource.get_documentation())
self.assertIsNone(resource.get_source())
def test_simpoint_resource(self) -> None:
"""Tests the loading of a Simpoint resource."""
resource = obtain_resource(
resource_name="simpoint-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, SimpointResource)
self.assertEquals(
"simpoint documentation.", resource.get_documentation()
)
self.assertIsNone(resource.get_source())
def test_file_resource(self) -> None:
"""Tests the loading of a FileResource."""
resource = obtain_resource(
resource_name="file-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, FileResource)
self.assertIsNone(resource.get_documentation())
self.assertIsNone(resource.get_source())
def test_directory_resource(self) -> None:
"""Tests the loading of a DirectoryResource."""
resource = obtain_resource(
resource_name="directory-example",
resource_directory=self.get_resource_dir(),
)
self.assertIsInstance(resource, DirectoryResource)
self.assertEquals(
"directory-example documentation.", resource.get_documentation()
)
self.assertIsNone(resource.get_source())

View File

@@ -29,7 +29,11 @@ import tempfile
import os
from gem5.resources.workload import Workload, CustomWorkload
from gem5.resources.resource import Resource
from gem5.resources.resource import (
BinaryResource,
DiskImageResource,
obtain_resource,
)
from gem5.resources.downloader import _resources_json_version_required
from typing import Dict
@@ -50,7 +54,7 @@ class CustomWorkloadTestSuite(unittest.TestCase):
"previous-versions" : {},
"resources": [
{
"type" : "resource",
"type" : "binary",
"name" : "x86-hello64-static",
"documentation" : "A 'Hello World!' binary.",
"architecture" : "X86",
@@ -73,7 +77,7 @@ class CustomWorkloadTestSuite(unittest.TestCase):
cls.custom_workload = CustomWorkload(
function="set_se_binary_workload",
parameters={
"binary": Resource("x86-hello64-static"),
"binary": obtain_resource("x86-hello64-static"),
"arguments": ["hello", 6],
},
)
@@ -100,7 +104,7 @@ class CustomWorkloadTestSuite(unittest.TestCase):
self.assertEquals(2, len(parameters))
self.assertTrue("binary" in parameters)
self.assertTrue(isinstance(parameters["binary"], Resource))
self.assertTrue(isinstance(parameters["binary"], BinaryResource))
self.assertTrue("arguments" in parameters)
self.assertTrue(isinstance(parameters["arguments"], list))
@@ -156,7 +160,7 @@ class WorkloadTestSuite(unittest.TestCase):
"previous-versions" : {},
"resources": [
{
"type" : "resource",
"type" : "kernel",
"name" : "x86-linux-kernel-5.2.3",
"documentation" : "The linux kernel (v5.2.3), compiled to X86.",
"architecture" : "X86",
@@ -166,7 +170,7 @@ class WorkloadTestSuite(unittest.TestCase):
"source" : "src/linux-kernel"
},
{
"type" : "resource",
"type" : "disk-image",
"name" : "x86-ubuntu-18.04-img",
"documentation" : "A disk image containing Ubuntu 18.04 for x86..",
"architecture" : "X86",
@@ -174,9 +178,7 @@ class WorkloadTestSuite(unittest.TestCase):
"md5sum" : "90e363abf0ddf22eefa2c7c5c9391c49",
"url" : "{url_base}/images/x86/ubuntu-18-04/x86-ubuntu.img.gz",
"source" : "src/x86-ubuntu",
"additional_metadata" : {
"root_partition": "1"
}
"root_partition": "1"
},
{
"type" : "workload",
@@ -226,10 +228,12 @@ class WorkloadTestSuite(unittest.TestCase):
self.assertEqual(3, len(parameters))
self.assertTrue("kernel" in parameters)
self.assertTrue(isinstance(parameters["kernel"], Resource))
self.assertTrue(isinstance(parameters["kernel"], BinaryResource))
self.assertTrue("disk_image" in parameters)
self.assertTrue(isinstance(parameters["disk_image"], Resource))
self.assertTrue(
isinstance(parameters["disk_image"], DiskImageResource)
)
self.assertTrue("readfile_contents" in parameters)
self.assertTrue(

View File

@@ -0,0 +1,99 @@
{
"version" : "develop",
"url_base" : "http://dist.gem5.org/dist/v22-1",
"previous-versions" : {
"develop" : "https://gem5.googlesource.com/public/gem5-resources/+/refs/heads/develop/resources.json?format=TEXT",
"21.2" : "http://resources.gem5.org/prev-resources-json/resources-21-2.json"
},
"resources": [
{
"type" : "kernel",
"name" : "kernel-example",
"documentation" : "kernel-example documentation.",
"architecture" : "RISCV",
"is_zipped" : false,
"md5sum" : "60a53c7d47d7057436bf4b9df707a841",
"url" : "{url_base}/kernels/x86/static/vmlinux-5.4.49",
"source" : "src/linux-kernel"
},
{
"type" : "disk-image",
"name" : "disk-image-example",
"documentation" : "disk-image documentation.",
"architecture" : "X86",
"is_zipped" : true,
"md5sum" : "90e363abf0ddf22eefa2c7c5c9391c49",
"url" : "{url_base}/images/x86/ubuntu-18-04/x86-ubuntu.img.gz",
"source" : "src/x86-ubuntu",
"root_partition": "1"
},
{
"type" : "binary",
"name" : "binary-example",
"documentation" : "binary-example documentation.",
"architecture" : "ARM",
"is_zipped" : false,
"md5sum" : "71b2cb004fe2cda4556f0b1a38638af6",
"url" : "{url_base}/test-progs/hello/bin/arm/linux/hello64-static",
"source" : "src/simple"
},
{
"type" : "bootloader",
"name" : "bootloader-example",
"documentation" : "bootloader documentation.",
"is_zipped" : false,
"md5sum" : "71b2cb004fe2cda4556f0b1a38638af6",
"url" : "{url_base}/test-progs/hello/bin/arm/linux/hello64-static"
},
{
"type" : "checkpoint",
"name" : "checkpoint-example",
"documentation" : "checkpoint-example documentation.",
"architecture": "RISCV",
"is_zipped" : false,
"md5sum" : "3a57c1bb1077176c4587b8a3bf4f8ace",
"source" : null,
"is_tar_archive" : true,
"url": "{url_base}/checkpoints/riscv-hello-example-checkpoint.tar"
},
{
"type" : "git",
"name" : "git-example",
"documentation" : null,
"is_zipped" : false,
"is_tar_archive" : true,
"md5sum" : "71b2cb004fe2cda4556f0b1a38638af6",
"url": "{url_base}/checkpoints/riscv-hello-example-checkpoint.tar"
},
{
"type" : "file",
"name" : "file-example",
"documentation" : null,
"is_zipped" : false,
"md5sum" : "71b2cb004fe2cda4556f0b1a38638af6",
"url": "{url_base}/checkpoints/riscv-hello-example-checkpoint.tar",
"source" : null
},
{
"type" : "directory",
"name" : "directory-example",
"documentation" : "directory-example documentation.",
"is_zipped" : false,
"md5sum" : "3a57c1bb1077176c4587b8a3bf4f8ace",
"source" : null,
"is_tar_archive" : true,
"url": "{url_base}/checkpoints/riscv-hello-example-checkpoint.tar"
},
{
"type" : "simpoint",
"name" : "simpoint-example",
"documentation" : "simpoint documentation.",
"is_zipped" : false,
"md5sum" : "3a57c1bb1077176c4587b8a3bf4f8ace",
"source" : null,
"is_tar_archive" : true,
"url": "{url_base}/checkpoints/riscv-hello-example-checkpoint.tar"
}
]
}