stdlib: Move setting of checkpoints to set_workload funcs

It never made much sense to set checkpoint via the Simulator module as
Checkpoints are very tightly coupled with the Workload being run. This
change therefore moves the checkpoint to the set_workload functions.

Setting checkpoints via the Simulator is deprecated and will be removed
in a future release.

Change-Id: I24d2133b38a86423d3553ec888c917c5fe47b93d
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/64571
Maintainer: Bobby Bruce <bbruce@ucdavis.edu>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
diff --git a/configs/example/gem5_library/checkpoints/riscv-hello-restore-checkpoint.py b/configs/example/gem5_library/checkpoints/riscv-hello-restore-checkpoint.py
index 4e9e8bf..e112b76 100644
--- a/configs/example/gem5_library/checkpoints/riscv-hello-restore-checkpoint.py
+++ b/configs/example/gem5_library/checkpoints/riscv-hello-restore-checkpoint.py
@@ -84,25 +84,18 @@
 # program compiled to the RISCV ISA. The `Resource` class will automatically
 # download the binary from the gem5 Resources cloud bucket if it's not already
 # present.
-board.set_se_binary_workload(
-    # the workload should be the same as the save-checkpoint script
-    Resource("riscv-hello")
-)
-
-# Getting the pre-taken checkpoint from gem5-resources. This checkpoint
+# We get the pre-taken checkpoint from gem5-resources. This checkpoint
 # was taken from running this gem5 configuration script,
 # configs/example/gem5_library/checkpoints/riscv-hello-save-checkpoint.py
-checkpoint_resource = Resource("riscv-hello-example-checkpoint-v22-1")
+board.set_se_binary_workload(
+    # the workload should be the same as the save-checkpoint script
+    Resource("riscv-hello"),
+    checkpoint=Resource("riscv-hello-example-checkpoint-v22-1"),
+)
 
-# Now we restore the checkpoint by passing the path to the checkpoint to
-# the Simulator object. The checkpoint_path could be a string containing
-# the path to the checkpoint folder. However, here, we use gem5 resources
-# to automatically download the checkpoint folder, and use .get_local_path()
-# to obtain the path to that folder.
-checkpoint_path = checkpoint_resource.get_local_path()
-print("Restore a checkpoint at", checkpoint_path)
 simulator = Simulator(
-    board=board, full_system=False, checkpoint_path=checkpoint_path
+    board=board,
+    full_system=False,
 )
 simulator.run()
 
diff --git a/configs/example/gem5_library/checkpoints/simpoints-se-restore.py b/configs/example/gem5_library/checkpoints/simpoints-se-restore.py
index decf9ea..b529672 100644
--- a/configs/example/gem5_library/checkpoints/simpoints-se-restore.py
+++ b/configs/example/gem5_library/checkpoints/simpoints-se-restore.py
@@ -96,16 +96,12 @@
     cache_hierarchy=cache_hierarchy,
 )
 
-board.set_workload(Workload("x86-print-this-15000-with-simpoints"))
-
-# Here we obtain the checkpoints from gem5 resources, but these are generated
-# from `configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py`.If
-# run prior to this script the `dir = Path("se_checkpoint_folder")` line may be
-# used. The resource is pulled so we may run this script as a test.
-# dir = Path("se_checkpoint_folder")
-dir = Path(Resource("simpoints-se-checkpoints-v22-1").get_local_path())
-subfolder = [int(str(name).rsplit(".", 1)[1]) for name in dir.iterdir()]
-dir = Path(dir / f"cpt.{min(subfolder)}").as_posix()
+# Here we obtain the workloadfrom gem5 resources, the checkpoint in this
+# workload was generated from
+# `configs/example/gem5_library/checkpoints/simpoints-se-checkpoint.py`.
+board.set_workload(
+    Workload("x86-print-this-15000-with-simpoints-and-checkpoint")
+)
 
 
 def max_inst():
@@ -128,7 +124,6 @@
 
 simulator = Simulator(
     board=board,
-    checkpoint_path=dir,
     on_exit_event={ExitEvent.MAX_INSTS: max_inst()},
 )
 
diff --git a/src/python/gem5/components/boards/abstract_board.py b/src/python/gem5/components/boards/abstract_board.py
index fef1db0..e22c9ef 100644
--- a/src/python/gem5/components/boards/abstract_board.py
+++ b/src/python/gem5/components/boards/abstract_board.py
@@ -100,6 +100,11 @@
         # determined by which kind of workload is set.
         self._is_fs = None
 
+        # This variable is used to record the checkpoint directory which is
+        # set when declaring the board's workload and then used by the
+        # Simulator module.
+        self._checkpoint = None
+
         # Setup the board and memory system's memory ranges.
         self._setup_memory_ranges()
 
diff --git a/src/python/gem5/components/boards/kernel_disk_workload.py b/src/python/gem5/components/boards/kernel_disk_workload.py
index ae3fedc..29d38ba 100644
--- a/src/python/gem5/components/boards/kernel_disk_workload.py
+++ b/src/python/gem5/components/boards/kernel_disk_workload.py
@@ -29,8 +29,9 @@
 from .abstract_board import AbstractBoard
 from ...resources.resource import AbstractResource
 
-from typing import List, Optional
+from typing import List, Optional, Union
 import os
+from pathlib import Path
 
 import m5
 
@@ -140,6 +141,7 @@
         readfile_contents: Optional[str] = None,
         kernel_args: Optional[List[str]] = None,
         exit_on_work_items: bool = True,
+        checkpoint: Optional[Union[Path, AbstractResource]] = None,
     ) -> None:
         """
         This function allows the setting of a full-system run with a Kernel
@@ -159,6 +161,8 @@
         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.
+        :param checkpoint: The checkpoint directory. Used to restore the
+        simulation to that checkpoint.
         """
 
         # We assume this this is in a multiple-inheritance setup with an
@@ -202,3 +206,17 @@
 
         # Set whether to exit on work items.
         self.exit_on_work_items = exit_on_work_items
+
+        # Here we set `self._checkpoint_dir`. This is then used by the
+        # Simulator module to setup checkpoints.
+        if checkpoint:
+            if isinstance(checkpoint, Path):
+                self._checkpoint = checkpoint
+            elif isinstance(checkpoint, AbstractResource):
+                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."
+                )
diff --git a/src/python/gem5/components/boards/se_binary_workload.py b/src/python/gem5/components/boards/se_binary_workload.py
index 7713b11..b9ecc7f 100644
--- a/src/python/gem5/components/boards/se_binary_workload.py
+++ b/src/python/gem5/components/boards/se_binary_workload.py
@@ -57,6 +57,7 @@
         stdout_file: Optional[Path] = None,
         stderr_file: Optional[Path] = None,
         arguments: List[str] = [],
+        checkpoint: Optional[Union[Path, AbstractResource]] = None,
     ) -> None:
         """Set up the system to run a specific binary.
 
@@ -70,6 +71,8 @@
         items. True by default.
         :param stdin_file: The input file for the binary
         :param arguments: The input arguments for the binary
+        :param checkpoint: The checkpoint directory. Used to restore the
+        simulation to that checkpoint.
         """
 
         # We assume this this is in a multiple-inheritance setup with an
@@ -99,11 +102,25 @@
         # Set whether to exit on work items for the se_workload
         self.exit_on_work_items = exit_on_work_items
 
+        # Here we set `self._checkpoint_dir`. This is then used by the
+        # Simulator module to setup checkpoints.
+        if checkpoint:
+            if isinstance(checkpoint, Path):
+                self._checkpoint = checkpoint
+            elif isinstance(checkpoint, AbstractResource):
+                self._checkpoint_dir = Path(checkpoint.get_local_path())
+            else:
+                raise Exception(
+                    "The checkpoint_dir must be None, Path, or "
+                    "AbstractResource."
+                )
+
     def set_se_simpoint_workload(
         self,
         binary: AbstractResource,
         arguments: List[str] = [],
         simpoint: Union[AbstractResource, SimPoint] = None,
+        checkpoint: Optional[Union[Path, AbstractResource]] = None,
     ) -> None:
         """Set up the system to run a SimPoint workload.
 
@@ -119,6 +136,8 @@
         :param simpoint: The SimPoint object or Resource 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
@@ -139,6 +158,7 @@
         self.set_se_binary_workload(
             binary=binary,
             arguments=arguments,
+            checkpoint=checkpoint,
         )
 
     def get_simpoint(self) -> SimPoint:
diff --git a/src/python/gem5/simulate/simulator.py b/src/python/gem5/simulate/simulator.py
index 34913b3..b45ff55 100644
--- a/src/python/gem5/simulate/simulator.py
+++ b/src/python/gem5/simulate/simulator.py
@@ -109,7 +109,9 @@
         events is valid.
         :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.
+        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
         ---------------------------
@@ -222,6 +224,16 @@
         self._last_exit_event = None
         self._exit_event_count = 0
 
+        if checkpoint_path:
+            warn(
+                "Setting the checkpoint path via the Simulator constructor is "
+                "deprecated and will be removed in future releases of gem5. "
+                "Please set this through via the appropriate workload "
+                "function (i.e., `set_se_binary_workload` or "
+                "`set_kernel_disk_workload`). If both are set the workload "
+                "function set takes precedence."
+            )
+
         self._checkpoint_path = checkpoint_path
 
     def schedule_simpoint(
@@ -402,7 +414,10 @@
             # m5.instantiate() takes a parameter specifying the path to the
             # checkpoint directory. If the parameter is None, no checkpoint
             # will be restored.
-            m5.instantiate(self._checkpoint_path)
+            if self._board._checkpoint:
+                m5.instantiate(self._board._checkpoint.as_posix())
+            else:
+                m5.instantiate(self._checkpoint_path)
             self._instantiated = True
 
             # Let the board know that instantiate has been called so it can do