From a2b58afc4f5343413fa8de8861108d1e984705ce Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Mon, 20 May 2024 18:04:37 -0500 Subject: [PATCH 01/15] WIP --- smartsim/launchable/basejob.py | 52 +++++++++++++++++ smartsim/launchable/job.py | 84 +++++++++++++++++++++++++++ smartsim/launchable/launchable.py | 33 +++++++++++ smartsim/launchable/smartsimobject.py | 39 +++++++++++++ tests/test_launchable.py | 38 ++++++++++++ 5 files changed, 246 insertions(+) create mode 100644 smartsim/launchable/basejob.py create mode 100644 smartsim/launchable/job.py create mode 100644 smartsim/launchable/launchable.py create mode 100644 smartsim/launchable/smartsimobject.py create mode 100644 tests/test_launchable.py diff --git a/smartsim/launchable/basejob.py b/smartsim/launchable/basejob.py new file mode 100644 index 0000000000..689f25b6f8 --- /dev/null +++ b/smartsim/launchable/basejob.py @@ -0,0 +1,52 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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. + + +# Potentially suboptimal choices of abstract, static, and class methods. +# Incomplete/unclear documentation +# No table stakes class methods (e.g. str) +# Proper formatting +# Poor variable names +# An open design question is whether to deep copy or hold references to entities, launchsettings + +from abc import abstractmethod +from smartsim.launchable.launchable import Launchable + + +class BaseJob(Launchable): + """Highest level ABC of a single job that can be + launched + """ + + def __init__(self) -> None: + super().__init__() + + @abstractmethod + def get_launch_steps(self) -> LaunchSteps: + """Return the launch steps corresponding to the + internal data + """ + pass diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py new file mode 100644 index 0000000000..68bdb37c80 --- /dev/null +++ b/smartsim/launchable/job.py @@ -0,0 +1,84 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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. + +from smartsim.launchable.basejob import BaseJob + + +class Job(BaseJob): + + ## JOBS will have deep copies (not references) -- so when you change a job - it doesnt change other things + ## make sure to call this out in the docstring + + # combination of a single entity and launch settings + # build out Job with all its parents + + # these are all user level objects - that will be fed into exp.start() + + # UNIT Testing for the Job + # what does unit testing look like for a bunch of nested classes + + """A Job holds a reference to a SmartSimEntity and associated + LaunchSettings prior to launch. It is responsible for turning + the stored entity and launch settings into commands that can be + executed by a launcher. + """ + + def __init__(self, entity: SmartSimEntity, launch_settings: LaunchSettings) -> None: + + ## make sure these are all robust proper python classes + ## add all the dunder methods + # __string + # __ represents etc. + # and all the normal class things + super().__init__() + self.entity = entity # deepcopy(entity)? + self.launch_settings = launch_settings # deepcopy(entity)? + + # self.warehouse_runner = JobWarehouseRunner # omit for now + + # make sure everything that is suppose to be a abstract method, property, or static method is tagged appropriatelyt + + @abstractmethod + def get_launch_steps(self) -> LaunchCommands: + """Return the launch steps corresponding to the + internal data. + + # Examples of launch steps might be + # Application, Slurm + # -N 4 -n 80 /path/to/exe -i input_file -v + # Application, Dragon + # JSON of a single entry to launch + # MLWorker, Dragon (inherently uses colocated) + # 3 JSON entries for entites to launch embedded in colocated descriptor + # FeatureStore, Dragon + # JSON of one application to run + + """ + return JobWarehouseRunner.run(self) + + def __str__(self) -> str: ... + + def __repr__(self) -> str: ... diff --git a/smartsim/launchable/launchable.py b/smartsim/launchable/launchable.py new file mode 100644 index 0000000000..ad7454e7ae --- /dev/null +++ b/smartsim/launchable/launchable.py @@ -0,0 +1,33 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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. + +from .smartsimobject import SmartSimObject + + +class Launchable(SmartSimObject): + ... + + ## empty abstract class diff --git a/smartsim/launchable/smartsimobject.py b/smartsim/launchable/smartsimobject.py new file mode 100644 index 0000000000..0628a08f7a --- /dev/null +++ b/smartsim/launchable/smartsimobject.py @@ -0,0 +1,39 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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. + +from smartsim._core.utils import helpers as _helpers + + +class SmartSimObject: + """Generatic class with a global unique identifier attribute""" + + ## hold a GUUID for tracking and debugging + object_id = _helpers.create_short_id_str + + +@property +def get_id(self) -> str: + return self.object_id diff --git a/tests/test_launchable.py b/tests/test_launchable.py new file mode 100644 index 0000000000..49b063e093 --- /dev/null +++ b/tests/test_launchable.py @@ -0,0 +1,38 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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 pytest + +# from smartsim import Experiment +# from smartsim.status import SmartSimStatus +from smartsim.launchable import SmartSimObject + +pytestmark = pytest.mark.group_a + + +def test_smartsimobject(): + ss_object = SmartSimObject() + print(ss_object) From 6bcd4e54066f740cd545ca355e1194829a8ee4af Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Fri, 24 May 2024 19:19:35 -0500 Subject: [PATCH 02/15] job class and mpmd job in progress --- .../{smartsimobject.py => __init__.py} | 18 +- smartsim/launchable/basejob.py | 24 +-- smartsim/launchable/job.py | 63 +++---- smartsim/launchable/launchable.py | 11 +- smartsim/launchable/mpmdjob.py | 95 ++++++++++ smartsim/launchable/mpmdpair.py | 41 +++++ tests/test_launchable.py | 173 +++++++++++++++++- 7 files changed, 341 insertions(+), 84 deletions(-) rename smartsim/launchable/{smartsimobject.py => __init__.py} (82%) create mode 100644 smartsim/launchable/mpmdjob.py create mode 100644 smartsim/launchable/mpmdpair.py diff --git a/smartsim/launchable/smartsimobject.py b/smartsim/launchable/__init__.py similarity index 82% rename from smartsim/launchable/smartsimobject.py rename to smartsim/launchable/__init__.py index 0628a08f7a..e04fdddd14 100644 --- a/smartsim/launchable/smartsimobject.py +++ b/smartsim/launchable/__init__.py @@ -24,16 +24,8 @@ # 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. -from smartsim._core.utils import helpers as _helpers - - -class SmartSimObject: - """Generatic class with a global unique identifier attribute""" - - ## hold a GUUID for tracking and debugging - object_id = _helpers.create_short_id_str - - -@property -def get_id(self) -> str: - return self.object_id +from .basejob import BaseJob +from .job import Job +from .launchable import Launchable +from .mpmdjob import MPMDJob +from .mpmdpair import MPMDPair diff --git a/smartsim/launchable/basejob.py b/smartsim/launchable/basejob.py index 689f25b6f8..0f8ce77e7f 100644 --- a/smartsim/launchable/basejob.py +++ b/smartsim/launchable/basejob.py @@ -25,28 +25,14 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# Potentially suboptimal choices of abstract, static, and class methods. -# Incomplete/unclear documentation -# No table stakes class methods (e.g. str) -# Proper formatting -# Poor variable names -# An open design question is whether to deep copy or hold references to entities, launchsettings +from abc import ABC, abstractmethod -from abc import abstractmethod from smartsim.launchable.launchable import Launchable -class BaseJob(Launchable): - """Highest level ABC of a single job that can be - launched - """ - - def __init__(self) -> None: - super().__init__() +class BaseJob(ABC, Launchable): + """The highest level abstract base class for a single job that can be launched""" @abstractmethod - def get_launch_steps(self) -> LaunchSteps: - """Return the launch steps corresponding to the - internal data - """ - pass + def get_launch_steps(self) -> None: # -> LaunchSteps: + ... diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py index 68bdb37c80..d644a58f79 100644 --- a/smartsim/launchable/job.py +++ b/smartsim/launchable/job.py @@ -24,61 +24,40 @@ # 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. +from abc import abstractmethod + +from smartsim.entity.entity import SmartSimEntity from smartsim.launchable.basejob import BaseJob +from smartsim.settings import RunSettings class Job(BaseJob): - - ## JOBS will have deep copies (not references) -- so when you change a job - it doesnt change other things - ## make sure to call this out in the docstring - - # combination of a single entity and launch settings - # build out Job with all its parents - - # these are all user level objects - that will be fed into exp.start() - - # UNIT Testing for the Job - # what does unit testing look like for a bunch of nested classes - """A Job holds a reference to a SmartSimEntity and associated LaunchSettings prior to launch. It is responsible for turning the stored entity and launch settings into commands that can be executed by a launcher. - """ - def __init__(self, entity: SmartSimEntity, launch_settings: LaunchSettings) -> None: + Jobs will hold a deep copy of launch settings. + """ - ## make sure these are all robust proper python classes - ## add all the dunder methods - # __string - # __ represents etc. - # and all the normal class things + def __init__( + self, + entity: SmartSimEntity, + launch_settings: RunSettings, # rename to LaunchSettings + ) -> None: super().__init__() - self.entity = entity # deepcopy(entity)? - self.launch_settings = launch_settings # deepcopy(entity)? - - # self.warehouse_runner = JobWarehouseRunner # omit for now - - # make sure everything that is suppose to be a abstract method, property, or static method is tagged appropriatelyt + self.entity = entity + self.launch_settings = launch_settings + # self.warehouse_runner = JobWarehouseRunner - @abstractmethod - def get_launch_steps(self) -> LaunchCommands: + def get_launch_steps(self) -> None: # -> LaunchCommands: """Return the launch steps corresponding to the internal data. - - # Examples of launch steps might be - # Application, Slurm - # -N 4 -n 80 /path/to/exe -i input_file -v - # Application, Dragon - # JSON of a single entry to launch - # MLWorker, Dragon (inherently uses colocated) - # 3 JSON entries for entites to launch embedded in colocated descriptor - # FeatureStore, Dragon - # JSON of one application to run - """ - return JobWarehouseRunner.run(self) - - def __str__(self) -> str: ... + pass + # return JobWarehouseRunner.run(self) - def __repr__(self) -> str: ... + def __str__(self) -> str: + string = f"SmartSim Entity: {self.entity}" + string += f"Launch Settings: {self.launch_settings}" + return string diff --git a/smartsim/launchable/launchable.py b/smartsim/launchable/launchable.py index ad7454e7ae..7a8af2c19a 100644 --- a/smartsim/launchable/launchable.py +++ b/smartsim/launchable/launchable.py @@ -24,10 +24,15 @@ # 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. -from .smartsimobject import SmartSimObject +class SmartSimObject: + """Base Class for SmartSim Objects""" -class Launchable(SmartSimObject): ... - ## empty abstract class + +class Launchable(SmartSimObject): + """Base Class for anything than can be passed + into Experiment.start()""" + + ... diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py new file mode 100644 index 0000000000..300d062183 --- /dev/null +++ b/smartsim/launchable/mpmdjob.py @@ -0,0 +1,95 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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 typing as t + +from smartsim.entity.entity import SmartSimEntity +from smartsim.error.errors import SSUnsupportedError +from smartsim.launchable.basejob import BaseJob +from smartsim.launchable.mpmdpair import MPMDPair +from smartsim.settings.base import RunSettings + + +def _check_launcher(mpmd_pairs: t.List[MPMDPair]) -> None: + """Enforce all pairs have the same launcher""" + flag = 0 + ret = None + for mpmd_pair in mpmd_pairs: + if flag == 1: + if ret == mpmd_pair.launch_settings.run_command: + flag = 0 + else: + raise SSUnsupportedError("MPMD pairs must all share the same launcher.") + ret = mpmd_pair.launch_settings.run_command + flag = 1 + + +def _check_entity(mpmd_pairs: t.List[MPMDPair]) -> None: + """Enforce all pairs have the same entity types""" + flag = 0 + ret = None + for mpmd_pair in mpmd_pairs: + if flag == 1: + if type(ret) == type(mpmd_pair.entity): + flag = 0 + print(type(ret)) + print(type(mpmd_pair.entity)) + else: + raise SSUnsupportedError( + "MPMD pairs must all share the same entity type." + ) + ret = mpmd_pair.entity + flag = 1 + + +class MPMDJob(BaseJob): + """An MPMDJob holds references to SmartSimEntity and + LaunchSettings pairs. It is responsible for turning + The stored pairs into an MPMD command(s) + """ + + def __init__(self, mpmd_pairs: t.List[MPMDPair] = []) -> None: + super().__init__() + + self.mpmd_pairs = mpmd_pairs + _check_launcher(self.mpmd_pairs) + _check_entity(self.mpmd_pairs) + + # self.warehouse_runner = MPMDJobWarehouseRunner + + def add_mpmd_pair( + self, entity: SmartSimEntity, launch_settings: RunSettings + ) -> None: + """ + Add a mpmd pair to the mpmd job + """ + self.mpmd_pairs.append(MPMDPair(entity, launch_settings)) + _check_launcher(self.mpmd_pairs) + _check_entity(self.mpmd_pairs) + + def get_launch_steps(self) -> None: # -> LaunchSteps: + pass + # return MPMDJobWarehouseRunner.run(self) diff --git a/smartsim/launchable/mpmdpair.py b/smartsim/launchable/mpmdpair.py new file mode 100644 index 0000000000..2ab5905f80 --- /dev/null +++ b/smartsim/launchable/mpmdpair.py @@ -0,0 +1,41 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2024, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. 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. +# +# 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 HOLDER 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. + +from smartsim.entity.entity import SmartSimEntity +from smartsim.settings.base import RunSettings + + +class MPMDPair: + """Class to store MPMD Pairs""" + + def __init__( + self, entity: SmartSimEntity, launch_settings: RunSettings + ): # rename to LaunchSettings + self.entity = entity + self.launch_settings = launch_settings + + def __iter__(self): + return self diff --git a/tests/test_launchable.py b/tests/test_launchable.py index 49b063e093..98aaf437d8 100644 --- a/tests/test_launchable.py +++ b/tests/test_launchable.py @@ -26,13 +26,172 @@ import pytest -# from smartsim import Experiment -# from smartsim.status import SmartSimStatus -from smartsim.launchable import SmartSimObject +from smartsim.database.orchestrator import Orchestrator +from smartsim.entity.entity import SmartSimEntity +from smartsim.entity.model import Model +from smartsim.error.errors import SSUnsupportedError +from smartsim.launchable import Job, Launchable +from smartsim.launchable.launchable import SmartSimObject +from smartsim.launchable.mpmdjob import MPMDJob +from smartsim.launchable.mpmdpair import MPMDPair +from smartsim.settings.base import RunSettings -pytestmark = pytest.mark.group_a - -def test_smartsimobject(): +def test_smartsimobject_init(): ss_object = SmartSimObject() - print(ss_object) + assert isinstance(ss_object, SmartSimObject) + + +def test_launchable_init(): + launchable = Launchable() + assert isinstance(launchable, Launchable) + + +def test_job_init(): + entity = SmartSimEntity("test_name", None, None) + launch_settings = RunSettings("echo", ["spam", "eggs"]) + job = Job(entity, launch_settings) + assert isinstance(job, Job) + + +def test_add_mpmd_pair(): + """Test the creation of an MPMDJob and then adding an mpmd pair + using add_mpmd_pair""" + entity = SmartSimEntity("test_name", None, None) + launch_settings = RunSettings("echo", ["spam", "eggs"]) + + mpmd_job = MPMDJob() + mpmd_job.add_mpmd_pair(entity, launch_settings) + + mpmd_pair = MPMDPair(entity, launch_settings) + + assert len(mpmd_job.mpmd_pairs) > 0 + + assert mpmd_pair.entity == mpmd_job.mpmd_pairs[0].entity + assert mpmd_pair.launch_settings == mpmd_job.mpmd_pairs[0].launch_settings + + +def test_mpmdpair_init(): + """Test the creation of an MPMDPair""" + entity = SmartSimEntity("test_name", None, None) + launch_settings = RunSettings("echo", ["spam", "eggs"]) + mpmd_pair = MPMDPair(entity, launch_settings) + assert isinstance(mpmd_pair, MPMDPair) + + +def test_check_launcher(): + """Test that mpmd pairs that have the same launcher type can be added to an MPMD Job""" + + entity1 = SmartSimEntity("entity1", None, None) + launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="mpirun") + entity2 = SmartSimEntity("entity2", None, None) + launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="mpirun") + mpmd_pairs = [] + + pair1 = MPMDPair(entity1, launch_settings1) + mpmd_pairs.append(pair1) + mpmd_job = MPMDJob(mpmd_pairs) + # add a second mpmd pair to the mpmd job + mpmd_job.add_mpmd_pair(entity2, launch_settings2) + + assert str(mpmd_job.mpmd_pairs[0].entity) == "entity1" + assert str(mpmd_job.mpmd_pairs[1].entity) == "entity2" + + +def test_add_mpmd_pair_check_launcher_error(): + """Test that an error is raised when a pairs is added to an mpmd + job using add_mpmd_pair that does not have the same launcher type""" + mpmd_pairs = [] + entity1 = SmartSimEntity("entity1", None, None) + launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") + + entity2 = SmartSimEntity("entity2", None, None) + launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="mpirun") + + pair1 = MPMDPair(entity1, launch_settings1) + mpmd_pairs.append(pair1) + mpmd_job = MPMDJob(mpmd_pairs) + + # Add a second mpmd pair to the mpmd job with a different launcher + with pytest.raises(SSUnsupportedError): + mpmd_job.add_mpmd_pair(entity2, launch_settings2) + + +def test_add_mpmd_pair_check_entity(): + """Test that mpmd pairs that have the same entity type can be added to an MPMD Job""" + mpmd_pairs = [] + entity1 = Model("entity1", None, None) + launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") + + entity2 = Model("entity2", None, None) + launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="srun") + + pair1 = MPMDPair(entity1, launch_settings1) + mpmd_pairs.append(pair1) + mpmd_job = MPMDJob(mpmd_pairs) + + # Add a second mpmd pair to the mpmd job + mpmd_job.add_mpmd_pair(entity2, launch_settings2) + + assert isinstance(mpmd_job, MPMDJob) + + +def test_add_mpmd_pair_check_entity_error(): + """Test that an error is raised when a pairs is added to an mpmd job + using add_mpmd_pair that does not have the same entity type""" + mpmd_pairs = [] + entity1 = Model("entity1", None, None) + launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") + + entity2 = Orchestrator("entity2") + launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="srun") + + pair1 = MPMDPair(entity1, launch_settings1) + mpmd_pairs.append(pair1) + mpmd_job = MPMDJob(mpmd_pairs) + + with pytest.raises(SSUnsupportedError) as ex: + mpmd_job.add_mpmd_pair(entity2, launch_settings2) + + assert "MPMD pairs must all share the same entity type." in ex.value.args[0] + + +def test_create_mpmdjob_invalid_mpmdpairs(): + """Test that an error is raised when a pairs is added to an mpmd job that + does not have the same launcher type""" + + mpmd_pairs = [] + entity1 = Model("entity1", None, None) + launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") + + entity1 = Model("entity1", None, None) + launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="mpirun") + + pair1 = MPMDPair(entity1, launch_settings1) + pair2 = MPMDPair(entity1, launch_settings2) + + mpmd_pairs.append(pair1) + mpmd_pairs.append(pair2) + + with pytest.raises(SSUnsupportedError) as ex: + MPMDJob(mpmd_pairs) + assert "MPMD pairs must all share the same launcher." in ex.value.args[0] + + +def test_create_mpmdjob_valid_mpmdpairs(): + """Test that all pairs have the same entity type is enforced when creating an MPMDJob""" + + mpmd_pairs = [] + entity1 = Model("entity1", None, None) + launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") + entity1 = Model("entity1", None, None) + launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="srun") + + pair1 = MPMDPair(entity1, launch_settings1) + pair2 = MPMDPair(entity1, launch_settings2) + + mpmd_pairs.append(pair1) + mpmd_pairs.append(pair2) + mpmd_job = MPMDJob(mpmd_pairs) + + assert isinstance(mpmd_job, MPMDJob) From b3b1326b32da16622f63346b97c8f3981ac47200 Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Tue, 4 Jun 2024 14:21:56 -0500 Subject: [PATCH 03/15] addressing review comments --- smartsim/launchable/basejob.py | 3 +++ smartsim/launchable/job.py | 25 ++++++++++++++++++++---- smartsim/launchable/mpmdjob.py | 30 ++++++++++++++++++++++------- smartsim/launchable/mpmdpair.py | 3 --- tests/test_launchable.py | 34 ++++++++++++++++++++++++++------- 5 files changed, 74 insertions(+), 21 deletions(-) diff --git a/smartsim/launchable/basejob.py b/smartsim/launchable/basejob.py index 0f8ce77e7f..eb50412bbb 100644 --- a/smartsim/launchable/basejob.py +++ b/smartsim/launchable/basejob.py @@ -35,4 +35,7 @@ class BaseJob(ABC, Launchable): @abstractmethod def get_launch_steps(self) -> None: # -> LaunchSteps: + """Return the launch steps corresponding to the + internal data. + """ ... diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py index d644a58f79..6ba075fed7 100644 --- a/smartsim/launchable/job.py +++ b/smartsim/launchable/job.py @@ -25,6 +25,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from abc import abstractmethod +from copy import deepcopy from smartsim.entity.entity import SmartSimEntity from smartsim.launchable.basejob import BaseJob @@ -46,10 +47,26 @@ def __init__( launch_settings: RunSettings, # rename to LaunchSettings ) -> None: super().__init__() - self.entity = entity - self.launch_settings = launch_settings + self._entity = entity + self._launch_settings = launch_settings # self.warehouse_runner = JobWarehouseRunner + @property + def entity(self) -> SmartSimEntity: + return self._entity + + @entity.setter + def entity(self, value): + self._entity = deepcopy(value) + + @property + def launch_settings(self) -> RunSettings: + return self._launch_settings + + @launch_settings.setter + def launch_settings(self, value): + self._launch_settings = deepcopy(value) + def get_launch_steps(self) -> None: # -> LaunchCommands: """Return the launch steps corresponding to the internal data. @@ -57,7 +74,7 @@ def get_launch_steps(self) -> None: # -> LaunchCommands: pass # return JobWarehouseRunner.run(self) - def __str__(self) -> str: - string = f"SmartSim Entity: {self.entity}" + def __str__(self) -> str: # pragma: no cover + string = f"SmartSim Entity: {self.entity}\n" string += f"Launch Settings: {self.launch_settings}" return string diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py index 300d062183..d02ee5b9d2 100644 --- a/smartsim/launchable/mpmdjob.py +++ b/smartsim/launchable/mpmdjob.py @@ -25,6 +25,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import typing as t +from copy import deepcopy from smartsim.entity.entity import SmartSimEntity from smartsim.error.errors import SSUnsupportedError @@ -55,8 +56,6 @@ def _check_entity(mpmd_pairs: t.List[MPMDPair]) -> None: if flag == 1: if type(ret) == type(mpmd_pair.entity): flag = 0 - print(type(ret)) - print(type(mpmd_pair.entity)) else: raise SSUnsupportedError( "MPMD pairs must all share the same entity type." @@ -71,14 +70,21 @@ class MPMDJob(BaseJob): The stored pairs into an MPMD command(s) """ - def __init__(self, mpmd_pairs: t.List[MPMDPair] = []) -> None: + def __init__(self, mpmd_pairs: t.List[MPMDPair] = None) -> None: super().__init__() - self.mpmd_pairs = mpmd_pairs - _check_launcher(self.mpmd_pairs) - _check_entity(self.mpmd_pairs) + self._mpmd_pairs = mpmd_pairs or [] + _check_launcher(self._mpmd_pairs) + _check_entity(self._mpmd_pairs) + # self.warehouse_runner = MPMDJobWarehouseRunner + + @property + def mpmd_pairs(self) -> t.List[MPMDPair]: + return self._mpmd_pairs - # self.warehouse_runner = MPMDJobWarehouseRunner + @mpmd_pairs.setter + def mpmd_pair(self, value): + self._mpmd_pair = deepcopy(value) def add_mpmd_pair( self, entity: SmartSimEntity, launch_settings: RunSettings @@ -91,5 +97,15 @@ def add_mpmd_pair( _check_entity(self.mpmd_pairs) def get_launch_steps(self) -> None: # -> LaunchSteps: + """Return the launch steps corresponding to the + internal data. + """ pass # return MPMDJobWarehouseRunner.run(self) + + def __str__(self) -> str: # pragma: no cover + """returns A user-readable string of a MPMD Job""" + for mpmd_pair in self.mpmd_pairs: + string = "\n== MPMD Pair == \n{}\n{}\n" + return string.format(mpmd_pair.entity, mpmd_pair.launch_settings) + return string diff --git a/smartsim/launchable/mpmdpair.py b/smartsim/launchable/mpmdpair.py index 2ab5905f80..23c9efef49 100644 --- a/smartsim/launchable/mpmdpair.py +++ b/smartsim/launchable/mpmdpair.py @@ -36,6 +36,3 @@ def __init__( ): # rename to LaunchSettings self.entity = entity self.launch_settings = launch_settings - - def __iter__(self): - return self diff --git a/tests/test_launchable.py b/tests/test_launchable.py index 98aaf437d8..9b805253a3 100644 --- a/tests/test_launchable.py +++ b/tests/test_launchable.py @@ -52,21 +52,29 @@ def test_job_init(): launch_settings = RunSettings("echo", ["spam", "eggs"]) job = Job(entity, launch_settings) assert isinstance(job, Job) + assert job.entity.name == "test_name" + assert "echo" in job.launch_settings.exe[0] + assert "spam" in job.launch_settings.exe_args + assert "eggs" in job.launch_settings.exe_args + + +def test_job_init_deepcopy(): + entity = SmartSimEntity("test_name", None, None) + launch_settings = RunSettings("echo", ["spam", "eggs"]) + job = Job(entity, launch_settings) + RunSettings("echo", ["hello", "world"]) + assert "hello" not in job.launch_settings.exe_args def test_add_mpmd_pair(): - """Test the creation of an MPMDJob and then adding an mpmd pair - using add_mpmd_pair""" entity = SmartSimEntity("test_name", None, None) launch_settings = RunSettings("echo", ["spam", "eggs"]) mpmd_job = MPMDJob() mpmd_job.add_mpmd_pair(entity, launch_settings) - mpmd_pair = MPMDPair(entity, launch_settings) - assert len(mpmd_job.mpmd_pairs) > 0 - + assert len(mpmd_job.mpmd_pairs) == 1 assert mpmd_pair.entity == mpmd_job.mpmd_pairs[0].entity assert mpmd_pair.launch_settings == mpmd_job.mpmd_pairs[0].launch_settings @@ -77,6 +85,19 @@ def test_mpmdpair_init(): launch_settings = RunSettings("echo", ["spam", "eggs"]) mpmd_pair = MPMDPair(entity, launch_settings) assert isinstance(mpmd_pair, MPMDPair) + assert mpmd_pair.entity.name == "test_name" + assert "echo" in mpmd_pair.launch_settings.exe[0] + assert "spam" in mpmd_pair.launch_settings.exe_args + assert "eggs" in mpmd_pair.launch_settings.exe_args + + +def test_mpmdpair_init_deepcopy(): + """Test the creation of an MPMDPair""" + entity = SmartSimEntity("test_name", None, None) + launch_settings = RunSettings("echo", ["spam", "eggs"]) + mpmd_pair = MPMDPair(entity, launch_settings) + RunSettings("echo", ["hello", "world"]) + assert "hello" not in mpmd_pair.launch_settings.exe_args def test_check_launcher(): @@ -91,7 +112,7 @@ def test_check_launcher(): pair1 = MPMDPair(entity1, launch_settings1) mpmd_pairs.append(pair1) mpmd_job = MPMDJob(mpmd_pairs) - # add a second mpmd pair to the mpmd job + # Add a second mpmd pair to the mpmd job mpmd_job.add_mpmd_pair(entity2, launch_settings2) assert str(mpmd_job.mpmd_pairs[0].entity) == "entity1" @@ -152,7 +173,6 @@ def test_add_mpmd_pair_check_entity_error(): with pytest.raises(SSUnsupportedError) as ex: mpmd_job.add_mpmd_pair(entity2, launch_settings2) - assert "MPMD pairs must all share the same entity type." in ex.value.args[0] From 88a98cd0bd8f7cd1796f3f9af7e28fa38408574f Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:37:57 -0700 Subject: [PATCH 04/15] Update mpmdjob.py --- smartsim/launchable/mpmdjob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py index d02ee5b9d2..8d074fd303 100644 --- a/smartsim/launchable/mpmdjob.py +++ b/smartsim/launchable/mpmdjob.py @@ -73,7 +73,7 @@ class MPMDJob(BaseJob): def __init__(self, mpmd_pairs: t.List[MPMDPair] = None) -> None: super().__init__() - self._mpmd_pairs = mpmd_pairs or [] + self._mpmd_pairs = deepcopy(mpmd_pairs) if mpmd_pairs else [] _check_launcher(self._mpmd_pairs) _check_entity(self._mpmd_pairs) # self.warehouse_runner = MPMDJobWarehouseRunner From daee658b94c79ffcd7ad68dd91cf3c73bc19bb5f Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:40:59 -0700 Subject: [PATCH 05/15] Update mpmdjob.py --- smartsim/launchable/mpmdjob.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py index 8d074fd303..59b5bda13a 100644 --- a/smartsim/launchable/mpmdjob.py +++ b/smartsim/launchable/mpmdjob.py @@ -72,7 +72,6 @@ class MPMDJob(BaseJob): def __init__(self, mpmd_pairs: t.List[MPMDPair] = None) -> None: super().__init__() - self._mpmd_pairs = deepcopy(mpmd_pairs) if mpmd_pairs else [] _check_launcher(self._mpmd_pairs) _check_entity(self._mpmd_pairs) @@ -80,7 +79,7 @@ def __init__(self, mpmd_pairs: t.List[MPMDPair] = None) -> None: @property def mpmd_pairs(self) -> t.List[MPMDPair]: - return self._mpmd_pairs + return deepcopy(self._mpmd_pairs) @mpmd_pairs.setter def mpmd_pair(self, value): From c0998eba3e753d64ce4fff4c33db194fde476466 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:42:46 -0700 Subject: [PATCH 06/15] Update job.py --- smartsim/launchable/job.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py index 6ba075fed7..21ea5e8b98 100644 --- a/smartsim/launchable/job.py +++ b/smartsim/launchable/job.py @@ -53,7 +53,7 @@ def __init__( @property def entity(self) -> SmartSimEntity: - return self._entity + return deepcopy(self._entity) @entity.setter def entity(self, value): @@ -61,7 +61,7 @@ def entity(self, value): @property def launch_settings(self) -> RunSettings: - return self._launch_settings + return deepcopy(self._launch_settings) @launch_settings.setter def launch_settings(self, value): From 529b07248dd50ea9afa98dee3f63bbfc7c2103b1 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:43:34 -0700 Subject: [PATCH 07/15] Update job.py --- smartsim/launchable/job.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py index 21ea5e8b98..9515e5df25 100644 --- a/smartsim/launchable/job.py +++ b/smartsim/launchable/job.py @@ -47,8 +47,8 @@ def __init__( launch_settings: RunSettings, # rename to LaunchSettings ) -> None: super().__init__() - self._entity = entity - self._launch_settings = launch_settings + self._entity = deepcopy(entity) + self._launch_settings = deepcopy(launch_settings) # self.warehouse_runner = JobWarehouseRunner @property From 0d3a052bb4b7d667e8fcd7898b679c2dbfdea48d Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:45:24 -0700 Subject: [PATCH 08/15] Update job.py --- smartsim/launchable/job.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py index 9515e5df25..236ab1346a 100644 --- a/smartsim/launchable/job.py +++ b/smartsim/launchable/job.py @@ -49,7 +49,7 @@ def __init__( super().__init__() self._entity = deepcopy(entity) self._launch_settings = deepcopy(launch_settings) - # self.warehouse_runner = JobWarehouseRunner + # TODO: self.warehouse_runner = JobWarehouseRunner @property def entity(self) -> SmartSimEntity: @@ -72,7 +72,7 @@ def get_launch_steps(self) -> None: # -> LaunchCommands: internal data. """ pass - # return JobWarehouseRunner.run(self) + # TODO: return JobWarehouseRunner.run(self) def __str__(self) -> str: # pragma: no cover string = f"SmartSim Entity: {self.entity}\n" From 335500e2678650afdf4cac9044d66b7bd850222d Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:45:59 -0700 Subject: [PATCH 09/15] Update basejob.py --- smartsim/launchable/basejob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartsim/launchable/basejob.py b/smartsim/launchable/basejob.py index eb50412bbb..bcefd04880 100644 --- a/smartsim/launchable/basejob.py +++ b/smartsim/launchable/basejob.py @@ -34,7 +34,7 @@ class BaseJob(ABC, Launchable): """The highest level abstract base class for a single job that can be launched""" @abstractmethod - def get_launch_steps(self) -> None: # -> LaunchSteps: + def get_launch_steps(self) -> None: # TODO: -> LaunchSteps: """Return the launch steps corresponding to the internal data. """ From d7e89684b9932897dfae20271c78884739a93d72 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:47:42 -0700 Subject: [PATCH 10/15] Update job.py --- smartsim/launchable/job.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartsim/launchable/job.py b/smartsim/launchable/job.py index 236ab1346a..8bc7536ec1 100644 --- a/smartsim/launchable/job.py +++ b/smartsim/launchable/job.py @@ -44,7 +44,7 @@ class Job(BaseJob): def __init__( self, entity: SmartSimEntity, - launch_settings: RunSettings, # rename to LaunchSettings + launch_settings: RunSettings, # TODO: rename to LaunchSettings ) -> None: super().__init__() self._entity = deepcopy(entity) From 11d0f23549953a496dbf0f27515bdc9fbbac3302 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:48:48 -0700 Subject: [PATCH 11/15] Update mpmdjob.py --- smartsim/launchable/mpmdjob.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py index 59b5bda13a..2581ac74a9 100644 --- a/smartsim/launchable/mpmdjob.py +++ b/smartsim/launchable/mpmdjob.py @@ -75,7 +75,7 @@ def __init__(self, mpmd_pairs: t.List[MPMDPair] = None) -> None: self._mpmd_pairs = deepcopy(mpmd_pairs) if mpmd_pairs else [] _check_launcher(self._mpmd_pairs) _check_entity(self._mpmd_pairs) - # self.warehouse_runner = MPMDJobWarehouseRunner + # TODO: self.warehouse_runner = MPMDJobWarehouseRunner @property def mpmd_pairs(self) -> t.List[MPMDPair]: @@ -100,7 +100,7 @@ def get_launch_steps(self) -> None: # -> LaunchSteps: internal data. """ pass - # return MPMDJobWarehouseRunner.run(self) + # TODO: return MPMDJobWarehouseRunner.run(self) def __str__(self) -> str: # pragma: no cover """returns A user-readable string of a MPMD Job""" From e2d32315f1fc2e3562cdcecf97236034f871b484 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:49:28 -0700 Subject: [PATCH 12/15] Update mpmdjob.py --- smartsim/launchable/mpmdjob.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py index 2581ac74a9..01d83c4ee9 100644 --- a/smartsim/launchable/mpmdjob.py +++ b/smartsim/launchable/mpmdjob.py @@ -95,7 +95,7 @@ def add_mpmd_pair( _check_launcher(self.mpmd_pairs) _check_entity(self.mpmd_pairs) - def get_launch_steps(self) -> None: # -> LaunchSteps: + def get_launch_steps(self) -> None: # TODO: -> LaunchSteps: """Return the launch steps corresponding to the internal data. """ From 6610113dc16c486c52ce5ac71ddae29eaef95720 Mon Sep 17 00:00:00 2001 From: Julia Putko <81587103+juliaputko@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:50:18 -0700 Subject: [PATCH 13/15] Update mpmdpair.py --- smartsim/launchable/mpmdpair.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smartsim/launchable/mpmdpair.py b/smartsim/launchable/mpmdpair.py index 23c9efef49..ec9f2ffae7 100644 --- a/smartsim/launchable/mpmdpair.py +++ b/smartsim/launchable/mpmdpair.py @@ -33,6 +33,6 @@ class MPMDPair: def __init__( self, entity: SmartSimEntity, launch_settings: RunSettings - ): # rename to LaunchSettings + ): # TODO: rename to LaunchSettings self.entity = entity self.launch_settings = launch_settings From 01486067d953da3e367c6a1dbc977fd8e8216a0f Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Thu, 6 Jun 2024 15:25:54 -0500 Subject: [PATCH 14/15] changes to tests and mpmdjob.py --- smartsim/launchable/mpmdjob.py | 2 +- tests/test_launchable.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/smartsim/launchable/mpmdjob.py b/smartsim/launchable/mpmdjob.py index 01d83c4ee9..e9b238f5b6 100644 --- a/smartsim/launchable/mpmdjob.py +++ b/smartsim/launchable/mpmdjob.py @@ -91,7 +91,7 @@ def add_mpmd_pair( """ Add a mpmd pair to the mpmd job """ - self.mpmd_pairs.append(MPMDPair(entity, launch_settings)) + self._mpmd_pairs.append(MPMDPair(entity, launch_settings)) _check_launcher(self.mpmd_pairs) _check_entity(self.mpmd_pairs) diff --git a/tests/test_launchable.py b/tests/test_launchable.py index 9b805253a3..a897c5181a 100644 --- a/tests/test_launchable.py +++ b/tests/test_launchable.py @@ -75,8 +75,8 @@ def test_add_mpmd_pair(): mpmd_pair = MPMDPair(entity, launch_settings) assert len(mpmd_job.mpmd_pairs) == 1 - assert mpmd_pair.entity == mpmd_job.mpmd_pairs[0].entity - assert mpmd_pair.launch_settings == mpmd_job.mpmd_pairs[0].launch_settings + assert str(mpmd_pair.entity) == str(mpmd_job.mpmd_pairs[0].entity) + assert str(mpmd_pair.launch_settings) == str(mpmd_job.mpmd_pairs[0].launch_settings) def test_mpmdpair_init(): From 658795ad33dec204b1fe2f7031aa702bff0684a2 Mon Sep 17 00:00:00 2001 From: Julia Putko Date: Fri, 7 Jun 2024 13:41:18 -0500 Subject: [PATCH 15/15] orch-> fs and model-> appl --- tests/{ => _legacy}/test_launchable.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) rename tests/{ => _legacy}/test_launchable.py (94%) diff --git a/tests/test_launchable.py b/tests/_legacy/test_launchable.py similarity index 94% rename from tests/test_launchable.py rename to tests/_legacy/test_launchable.py index a897c5181a..24648e80d0 100644 --- a/tests/test_launchable.py +++ b/tests/_legacy/test_launchable.py @@ -26,9 +26,9 @@ import pytest -from smartsim.database.orchestrator import Orchestrator +from smartsim.database.orchestrator import FeatureStore from smartsim.entity.entity import SmartSimEntity -from smartsim.entity.model import Model +from smartsim.entity.model import Application from smartsim.error.errors import SSUnsupportedError from smartsim.launchable import Job, Launchable from smartsim.launchable.launchable import SmartSimObject @@ -141,10 +141,10 @@ def test_add_mpmd_pair_check_launcher_error(): def test_add_mpmd_pair_check_entity(): """Test that mpmd pairs that have the same entity type can be added to an MPMD Job""" mpmd_pairs = [] - entity1 = Model("entity1", None, None) + entity1 = Application("entity1", None, None) launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") - entity2 = Model("entity2", None, None) + entity2 = Application("entity2", None, None) launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="srun") pair1 = MPMDPair(entity1, launch_settings1) @@ -161,10 +161,10 @@ def test_add_mpmd_pair_check_entity_error(): """Test that an error is raised when a pairs is added to an mpmd job using add_mpmd_pair that does not have the same entity type""" mpmd_pairs = [] - entity1 = Model("entity1", None, None) + entity1 = Application("entity1", None, None) launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") - entity2 = Orchestrator("entity2") + entity2 = FeatureStore("entity2") launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="srun") pair1 = MPMDPair(entity1, launch_settings1) @@ -181,10 +181,10 @@ def test_create_mpmdjob_invalid_mpmdpairs(): does not have the same launcher type""" mpmd_pairs = [] - entity1 = Model("entity1", None, None) + entity1 = Application("entity1", None, None) launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") - entity1 = Model("entity1", None, None) + entity1 = Application("entity1", None, None) launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="mpirun") pair1 = MPMDPair(entity1, launch_settings1) @@ -202,9 +202,9 @@ def test_create_mpmdjob_valid_mpmdpairs(): """Test that all pairs have the same entity type is enforced when creating an MPMDJob""" mpmd_pairs = [] - entity1 = Model("entity1", None, None) + entity1 = Application("entity1", None, None) launch_settings1 = RunSettings("echo", ["hello", "world"], run_command="srun") - entity1 = Model("entity1", None, None) + entity1 = Application("entity1", None, None) launch_settings2 = RunSettings("echo", ["spam", "eggs"], run_command="srun") pair1 = MPMDPair(entity1, launch_settings1)