From de3de0821a211d94a1b808b9e200ea48c0f24757 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Thu, 26 Jan 2023 10:10:46 -0800 Subject: [PATCH 01/57] CLI help for library options (#537) * remove compat cruft * print library options with help output --- legate/__init__.py | 2 ++ legate/args.py | 60 ++++++++++++++++++++++++++++++++++++++++++ legate/core/runtime.py | 46 ++------------------------------ legate/driver/args.py | 56 ++++++++++++++++++++++++++++++++++++++- legate/rc.py | 7 ----- 5 files changed, 119 insertions(+), 52 deletions(-) create mode 100644 legate/args.py diff --git a/legate/__init__.py b/legate/__init__.py index 2c9b706ce..e421b48d3 100644 --- a/legate/__init__.py +++ b/legate/__init__.py @@ -17,6 +17,8 @@ __path__ = extend_path(__path__, __name__) +from .args import ARGS + from . import _version __version__ = _version.get_versions()["version"] # type: ignore[no-untyped-call] diff --git a/legate/args.py b/legate/args.py new file mode 100644 index 000000000..2560d06d4 --- /dev/null +++ b/legate/args.py @@ -0,0 +1,60 @@ +# Copyright 2021-2022 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from __future__ import annotations + +from .util.args import ArgSpec, Argument + +ARGS = [ + Argument( + "consensus", + ArgSpec( + action="store_true", + default=False, + dest="consensus", + help="Turn on consensus match on single node (for testing).", + ), + ), + Argument( + "cycle-check", + ArgSpec( + action="store_true", + default=False, + dest="cycle_check", + help=( + "Check for reference cycles involving RegionField objects on " + "script exit (developer option). When such cycles arise " + "during execution, they stop used RegionFields from getting " + "collected and reused for new Stores, thus increasing memory " + "pressure. By default this check will miss any RegionField " + "cycles the garbage collector collected during execution; " + "run gc.disable() at the beginning of the program to avoid " + "this." + ), + ), + ), + Argument( + "future-leak-check", + ArgSpec( + action="store_true", + default=False, + dest="future_leak_check", + help=( + "Check for reference cycles keeping Future/FutureMap objects " + "alive after Legate runtime exit (developer option). Such " + "leaks can result in Legion runtime shutdown hangs." + ), + ), + ), +] diff --git a/legate/core/runtime.py b/legate/core/runtime.py index 637b09f72..aff0c1898 100644 --- a/legate/core/runtime.py +++ b/legate/core/runtime.py @@ -26,7 +26,8 @@ from legion_top import add_cleanup_item, top_level -from ..util.args import ArgSpec, Argument, parse_library_command_args +from ..args import ARGS +from ..util.args import parse_library_command_args from . import ffi # Make sure we only have one ffi instance from . import ( Fence, @@ -79,49 +80,6 @@ _LEGATE_FIELD_ID_BASE = 1000 -ARGS = [ - Argument( - "consensus", - ArgSpec( - action="store_true", - default=False, - dest="consensus", - help="Turn on consensus match on single node (for testing).", - ), - ), - Argument( - "cycle-check", - ArgSpec( - action="store_true", - default=False, - dest="cycle_check", - help=( - "Check for reference cycles involving RegionField objects on " - "script exit (developer option). When such cycles arise " - "during execution, they stop used RegionFields from getting " - "collected and reused for new Stores, thus increasing memory " - "pressure. By default this check will miss any RegionField " - "cycles the garbage collector collected during execution; " - "run gc.disable() at the beginning of the program to avoid " - "this." - ), - ), - ), - Argument( - "future-leak-check", - ArgSpec( - action="store_true", - default=False, - dest="future_leak_check", - help=( - "Check for reference cycles keeping Future/FutureMap objects " - "alive after Legate runtime exit (developer option). Such " - "leaks can result in Legion runtime shutdown hangs." - ), - ), - ), -] - # A helper class for doing field management with control replication @dataclass(frozen=True) diff --git a/legate/driver/args.py b/legate/driver/args.py index 92bce362b..00587c152 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -17,6 +17,7 @@ from __future__ import annotations from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser +from typing import IO, Optional from ..util.shared_args import ( CPUS, @@ -39,7 +40,60 @@ __all__ = ("parser",) -parser = ArgumentParser( + +# We want to provide information about library-specific command line options +# for legate and cunumeric, etc. if they are installed. But we want to avoid +# importing those packages under normal circumstances. This argument parser +# subclass overrides the standard print_help method to attempt to import +# specified packages *only* when printing help output. Additionally: +# +# - names of downstream packages must be configured on the packages class attr +# - downstream packages must expose a .ARGS attr with argparse args +# - .ARGS must be plain-python importable if the environment variable +# _LEGATE_PROJECT_HELP_ARGS_ is set to "1" +# +# All of this is somewhat clunky but the best option to provide a good UX. +class _LegateArgumentParser(ArgumentParser): + + packages = ("legate", "cunumeric") + + def print_help(self, file: Optional[IO[str]] = None) -> None: + import importlib + import os + from argparse import SUPPRESS + + os.environ["_LEGATE_PROJECT_HELP_ARGS_"] = "1" + + super().print_help(file) + + helps = [] + + for pkg_name in self.packages: + try: + ARGS = importlib.import_module(pkg_name).ARGS + parser = ArgumentParser( + prog=pkg_name, + add_help=False, + allow_abbrev=False, + usage=SUPPRESS, + ) + + for arg in ARGS: + argname = f"-{pkg_name}:{arg.name}" + parser.add_argument(argname, **arg.kwargs) + + helps.append((pkg_name, parser.format_help())) + + except Exception: + pass + + if helps: + print("\nLibrary-specific options\n------------------------\n") + for pkg_name, help in helps: + print(f"{pkg_name} library {help}") + + +parser = _LegateArgumentParser( description="Legate Driver", allow_abbrev=False, formatter_class=ArgumentDefaultsHelpFormatter, diff --git a/legate/rc.py b/legate/rc.py index bd4abca51..437eac146 100644 --- a/legate/rc.py +++ b/legate/rc.py @@ -27,13 +27,6 @@ legion_python directly. """ -# TODO (bv) temp transitive imports until cunumeric is updated -from .util.args import ( # noqa - ArgSpec, - Argument, - parse_library_command_args as parse_command_args, -) - def has_legion_context() -> bool: """Determine whether we are running in legion_python. From 27ef879496d1f2e04b43477e7aed4720fe20b653 Mon Sep 17 00:00:00 2001 From: Marcin Zalewski Date: Fri, 27 Jan 2023 10:17:33 -0800 Subject: [PATCH 02/57] Update the architectures built in conda package (#545) Co-authored-by: Marcin Zalewski --- conda/conda-build/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conda/conda-build/build.sh b/conda/conda-build/build.sh index 27b5aead1..317947dc4 100644 --- a/conda/conda-build/build.sh +++ b/conda/conda-build/build.sh @@ -16,7 +16,7 @@ CMAKE_ARGS+=" if [ -z "$CPU_ONLY" ]; then CMAKE_ARGS+=" -DLegion_USE_CUDA=ON --DCMAKE_CUDA_ARCHITECTURES:LIST=60-real;70-real;75-real;80-real;86 +-DCMAKE_CUDA_ARCHITECTURES:LIST=60-real;70-real;75-real;80-real;90 " fi From 76060f2509c1334ae016c0e406aa6d7c1e8f77a7 Mon Sep 17 00:00:00 2001 From: Wei Wu Date: Fri, 27 Jan 2023 19:35:33 -0700 Subject: [PATCH 03/57] Default python interpreter support for Legate (#539) * test * test * checkpoint * fixup * fixup * start the runtime explicitly * minor fix * fixup * use legate driver * fixup * split user_opts into user_script and user_opts * load env into os.environ * fixup * try fixing mypy * fix interactive mode * try fix mypy * fix mypy * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * fixup * fix unit tests * Update legate/driver/config.py Co-authored-by: Bryan Van de Ven * Update legate/driver/config.py Co-authored-by: Bryan Van de Ven * set the default value of user_script to None * Update legate/driver/driver.py Co-authored-by: Bryan Van de Ven * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * several fixes * rename Driver to LegateDriver * Update legate/driver/command.py Co-authored-by: Bryan Van de Ven * unify main and canonical_main * rename main to legate_main * more fixes * fix user_opts * Update legate/driver/main.py Co-authored-by: Bryan Van de Ven * Update legate/driver/config.py Co-authored-by: Bryan Van de Ven * fix cmd * support dry run and verbose for canonical python * fixup * fix pytest * try loading argv from env * fixup * Revert "fixup" This reverts commit 37a10baa7dc0772a1097edc66507569d74e50a69. * Revert "try loading argv from env" This reverts commit 16c0025fdd0a241daea05bba17670c8ffc9db74f. * clean up print * remove rc.py * Revert "remove rc.py" This reverts commit 19a8dcaaf286e3d096b4cdcb976934c06f2fe0df. * Revert "Revert "remove rc.py"" This reverts commit 1dc5ea8038271eae4d8e08f6e39fa8e906a221db. * several fixes * fix env * Update legate/driver/driver.py Co-authored-by: Manolis Papadakis --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bryan Van de Ven Co-authored-by: Manolis Papadakis --- legate/core/__init__.py | 25 +++++++- legate/driver/__init__.py | 4 +- legate/driver/args.py | 45 +++++++++----- legate/driver/command.py | 75 ++++++++++++++++++------ legate/driver/config.py | 12 +++- legate/driver/driver.py | 71 ++++++++++++++++++---- legate/driver/main.py | 46 +++++++++------ legate/jupyter/config.py | 2 + legate/jupyter/kernel.py | 4 +- legate/jupyter/main.py | 4 +- legate/rc.py | 49 ---------------- legate/util/shared_args.py | 6 +- tests/unit/legate/driver/test_command.py | 36 +++++++++--- tests/unit/legate/driver/test_config.py | 6 +- tests/unit/legate/driver/test_driver.py | 26 ++++---- tests/unit/legate/driver/test_main.py | 4 +- tests/unit/legate/jupyter/test_kernel.py | 10 ++-- tests/unit/legate/jupyter/test_main.py | 4 +- tests/unit/legate/test_rc.py | 66 --------------------- typings/legion_cffi/__init__.pyi | 2 + typings/legion_top/__init__.pyi | 6 +- 21 files changed, 280 insertions(+), 223 deletions(-) delete mode 100644 legate/rc.py delete mode 100644 tests/unit/legate/test_rc.py diff --git a/legate/core/__init__.py b/legate/core/__init__.py index 0c5eda106..f653a00fe 100644 --- a/legate/core/__init__.py +++ b/legate/core/__init__.py @@ -14,12 +14,31 @@ # from __future__ import annotations -from ..rc import check_legion from ..util.args import parse_library_command_args -check_legion() +from legion_cffi import is_legion_python, ffi, lib as legion -from legion_cffi import ffi, lib as legion +if is_legion_python == False: + from legion_top import ( + legion_canonical_python_main, + legion_canonical_python_cleanup, + ) + from ..driver.main import prepare_driver, CanonicalDriver + import atexit, sys, os + + # parse legate args into legion args + sys_argv = [ + "python", + ] + sys.argv + driver = prepare_driver(sys_argv, CanonicalDriver) + if driver.dry_run: + sys.exit(0) + legate_argv = driver.cmd + legate_env = driver.env + # set env + os.environ.update(legate_env) + legion_canonical_python_main(legate_argv) + atexit.register(legion_canonical_python_cleanup) from ._legion import ( LEGATE_MAX_DIM, diff --git a/legate/driver/__init__.py b/legate/driver/__init__.py index 67ce493b8..5ee41b8be 100644 --- a/legate/driver/__init__.py +++ b/legate/driver/__init__.py @@ -15,13 +15,13 @@ from __future__ import annotations from .config import Config -from .driver import Driver +from .driver import LegateDriver, CanonicalDriver from .launcher import Launcher def main() -> int: import sys - from .main import main as _main + from .main import legate_main as _main return _main(sys.argv) diff --git a/legate/driver/args.py b/legate/driver/args.py index 00587c152..8557601f6 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -116,7 +116,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: help="CPU cores to bind each rank to. Comma-separated core IDs as " "well as ranges are accepted, as reported by `numactl`. Binding " "instructions for all ranks should be listed in one string, separated " - "by `/`.", + "by `/`. " + "[legate-only, not supported with standard Python invocation]", ) @@ -124,7 +125,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: "--mem-bind", help="NUMA memories to bind each rank to. Use comma-separated integer " "IDs as reported by `numactl`. Binding instructions for all ranks " - "should be listed in one string, separated by `/`.", + "should be listed in one string, separated by `/`. " + "[legate-only, not supported with standard Python invocation]", ) @@ -132,7 +134,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: "--gpu-bind", help="GPUs to bind each rank to. Use comma-separated integer IDs as " "reported by `nvidia-smi`. Binding instructions for all ranks " - "should be listed in one string, separated by `/`.", + "should be listed in one string, separated by `/`. " + "[legate-only, not supported with standard Python invocation]", ) @@ -140,7 +143,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: "--nic-bind", help="NICs to bind each rank to. Use comma-separated device names as " "appropriate for the network in use. Binding instructions for all ranks " - "should be listed in one string, separated by `/`.", + "should be listed in one string, separated by `/`. " + "[legate-only, not supported with standard Python invocation]", ) @@ -188,7 +192,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="cprofile", action="store_true", required=False, - help="profile Python execution with the cprofile module", + help="profile Python execution with the cprofile module, " + "[legate-only, not supported with standard Python invocation]", ) @@ -197,7 +202,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="nvprof", action="store_true", required=False, - help="run Legate with nvprof", + help="run Legate with nvprof, " + "[legate-only, not supported with standard Python invocation]", ) @@ -206,7 +212,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="nsys", action="store_true", required=False, - help="run Legate with Nsight Systems", + help="run Legate with Nsight Systems, " + "[legate-only, not supported with standard Python invocation]", ) @@ -215,7 +222,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="nsys_targets", default="cublas,cuda,cudnn,nvtx,ucx", required=False, - help="Specify profiling targets for Nsight Systems", + help="Specify profiling targets for Nsight Systems, " + "[legate-only, not supported with standard Python invocation]", ) @@ -227,7 +235,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: required=False, help="Specify extra flags for Nsight Systems (can appear more than once). " "Multiple arguments may be provided together in a quoted string " - "(arguments with spaces inside must be additionally quoted)", + "(arguments with spaces inside must be additionally quoted), " + "[legate-only, not supported with standard Python invocation]", ) logging = parser.add_argument_group("Logging") @@ -277,7 +286,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="gdb", action="store_true", required=False, - help="run Legate inside gdb", + help="run Legate inside gdb, " + "[legate-only, not supported with standard Python invocation]", ) @@ -286,7 +296,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="cuda_gdb", action="store_true", required=False, - help="run Legate inside cuda-gdb", + help="run Legate inside cuda-gdb, " + "[legate-only, not supported with standard Python invocation]", ) @@ -295,7 +306,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="memcheck", action="store_true", required=False, - help="run Legate with cuda-memcheck", + help="run Legate with cuda-memcheck, " + "[legate-only, not supported with standard Python invocation]", ) @@ -372,7 +384,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="bind_detail", action="store_true", required=False, - help="print out the final invocation run by bind.sh", + help="print out the final invocation run by bind.sh, " + "[legate-only, not supported with standard Python invocation]", ) @@ -384,7 +397,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="module", default=None, required=False, - help="Specify a Python module to load before running", + help="Specify a Python module to load before running, " + "[legate-only, not supported with standard Python invocation]", ) @@ -402,7 +416,8 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: dest="rlwrap", action="store_true", required=False, - help="Whether to run with rlwrap to improve readline ability", + help="Whether to run with rlwrap to improve readline ability, " + "[legate-only, not supported with standard Python invocation]", ) other.add_argument( diff --git a/legate/driver/command.py b/legate/driver/command.py index 2fc8cc1ed..5b3816567 100644 --- a/legate/driver/command.py +++ b/legate/driver/command.py @@ -24,7 +24,7 @@ from .config import ConfigProtocol from .launcher import Launcher -__all__ = ("CMD_PARTS",) +__all__ = ("CMD_PARTS_LEGION", "CMD_PARTS_CANONICAL") # this will be replaced by bind.sh with the actual computed rank at runtime @@ -182,11 +182,18 @@ def cmd_legion( return (str(system.legion_paths.legion_python),) -def cmd_processor( +def cmd_python_processor( config: ConfigProtocol, system: System, launcher: Launcher ) -> CommandPart: - # We always need one python processor per rank and no local fields - return ("-ll:py", "1", "-lg:local", "0") + # We always need one python processor per rank + return ("-ll:py", "1") + + +def cmd_local_field( + config: ConfigProtocol, system: System, launcher: Launcher +) -> CommandPart: + # We always need no local fields + return ("-lg:local", "0") def cmd_kthreads( @@ -366,27 +373,22 @@ def cmd_ucx( return ("-ucx:tls_host", "^dc,ud") +def cmd_user_script( + config: ConfigProtocol, system: System, launcher: Launcher +) -> CommandPart: + return () if config.user_script is None else (config.user_script,) + + def cmd_user_opts( config: ConfigProtocol, system: System, launcher: Launcher ) -> CommandPart: return config.user_opts -CMD_PARTS = ( - cmd_bind, - cmd_rlwrap, - cmd_gdb, - cmd_cuda_gdb, - cmd_nvprof, - cmd_nsys, - # Add memcheck right before the binary - cmd_memcheck, - # Now we're ready to build the actual command to run - cmd_legion, +_CMD_PARTS_SHARED = ( # This has to go before script name cmd_nocr, - cmd_module, - cmd_processor, + cmd_local_field, cmd_kthreads, # Translate the requests to Realm command line parameters cmd_cpus, @@ -402,6 +404,41 @@ def cmd_user_opts( cmd_log_file, cmd_eager_alloc, cmd_ucx, - # Append user flags so they can override whatever we provided - cmd_user_opts, +) + +CMD_PARTS_LEGION = ( + ( + cmd_bind, + cmd_rlwrap, + cmd_gdb, + cmd_cuda_gdb, + cmd_nvprof, + cmd_nsys, + # Add memcheck right before the binary + cmd_memcheck, + # Now we're ready to build the actual command to run + cmd_legion, + # This has to go before script name + cmd_python_processor, + cmd_module, + ) + + _CMD_PARTS_SHARED + + ( + # User script + cmd_user_script, + # Append user flags so they can override whatever we provided + cmd_user_opts, + ) +) + +CMD_PARTS_CANONICAL = ( + ( + # User script + cmd_user_script, + ) + + _CMD_PARTS_SHARED + + ( + # Append user flags so they can override whatever we provided + cmd_user_opts, + ) ) diff --git a/legate/driver/config.py b/legate/driver/config.py index 0be36f959..996248c0f 100644 --- a/legate/driver/config.py +++ b/legate/driver/config.py @@ -22,7 +22,7 @@ from dataclasses import dataclass from functools import cached_property from pathlib import Path -from typing import Any, Protocol +from typing import Any, Optional, Protocol from ..util import colors from ..util.types import ( @@ -151,6 +151,7 @@ class ConfigProtocol(Protocol): argv: ArgList + user_script: Optional[str] user_opts: tuple[str, ...] multi_node: MultiNode binding: Binding @@ -184,7 +185,12 @@ def __init__(self, argv: ArgList) -> None: # only saving this for help with testing self._args = args - self.user_opts = tuple(extra) + self.user_script = next((x for x in extra if x.endswith(".py")), None) + + user_opts = list(extra) + if self.user_script in user_opts: + user_opts.remove(self.user_script) + self.user_opts = tuple(user_opts) # these may modify the args, so apply before dataclass conversions self._fixup_nocr(args) @@ -203,7 +209,7 @@ def __init__(self, argv: ArgList) -> None: @cached_property def console(self) -> bool: """Whether we are starting Legate as an interactive console.""" - return not any(opt.endswith(".py") for opt in self.user_opts) + return self.user_script is None def _fixup_nocr(self, args: Namespace) -> None: # this is slightly duplicative of MultiNode.ranks property, but fixup diff --git a/legate/driver/driver.py b/legate/driver/driver.py index 7f3e17d33..f4f12e0ef 100644 --- a/legate/driver/driver.py +++ b/legate/driver/driver.py @@ -21,15 +21,15 @@ from ..util.system import System from ..util.ui import kvtable, rule, section, value, warn -from .command import CMD_PARTS +from .command import CMD_PARTS_CANONICAL, CMD_PARTS_LEGION from .config import ConfigProtocol -from .launcher import Launcher +from .launcher import Launcher, SimpleLauncher from .logs import process_logs if TYPE_CHECKING: from ..util.types import Command, EnvDict -__all__ = ("Driver", "print_verbose") +__all__ = ("LegateDriver", "CanonicalDriver", "print_verbose") _DARWIN_GDB_WARN = """\ You must start the debugging session with the following command, @@ -41,7 +41,7 @@ """ -class Driver: +class LegateDriver: """Coordinate the system, user-configuration, and launcher to appropriately execute the Legate process. @@ -65,7 +65,7 @@ def cmd(self) -> Command: launcher = self.launcher system = self.system - parts = (part(config, system, launcher) for part in CMD_PARTS) + parts = (part(config, system, launcher) for part in CMD_PARTS_LEGION) return launcher.cmd + sum(parts, ()) @property @@ -83,12 +83,13 @@ def custom_env_vars(self) -> set[str]: # in case we want to augment the launcher env we could do it here return self.launcher.custom_env_vars - def run(self) -> int: - """Run the Legate process. + @property + def dry_run(self) -> bool: + """Check verbose and dry run. Returns ------- - int : process return code + bool : whether dry run is enabled """ if self.config.info.verbose: @@ -101,7 +102,17 @@ def run(self) -> int: self._darwin_gdb_warn() - if self.config.other.dry_run: + return self.config.other.dry_run + + def run(self) -> int: + """Run the Legate process. + + Returns + ------- + int : process return code + + """ + if self.dry_run: return 0 with process_logs(self.config, self.system, self.launcher): @@ -122,9 +133,49 @@ def _darwin_gdb_warn(self) -> None: ) +class CanonicalDriver(LegateDriver): + """Coordinate the system, user-configuration, and launcher to appropriately + execute the Legate process. + + Parameters + ---------- + config : Config + + system : System + + """ + + def __init__(self, config: ConfigProtocol, system: System) -> None: + self.config = config + self.system = system + self.launcher = SimpleLauncher(config, system) + + @property + def cmd(self) -> Command: + """The full command invocation that should be used to start Legate.""" + config = self.config + launcher = self.launcher + system = self.system + + parts = ( + part(config, system, launcher) for part in CMD_PARTS_CANONICAL + ) + return sum(parts, ()) + + def run(self) -> int: + """Run the Legate process. + + Returns + ------- + int : process return code + + """ + assert False, "This function should not be invoked." + + def print_verbose( system: System, - driver: Driver | None = None, + driver: LegateDriver | None = None, ) -> None: """Print system and driver configuration values. diff --git a/legate/driver/main.py b/legate/driver/main.py index 2ca3f04be..bb02c7cbb 100644 --- a/legate/driver/main.py +++ b/legate/driver/main.py @@ -17,32 +17,26 @@ """ from __future__ import annotations -__all__ = ("main",) +from typing import Type, Union +from . import CanonicalDriver, LegateDriver -def main(argv: list[str]) -> int: - """A main function for the Legate driver that can be used programmatically - or by entry-points. +__all__ = ("legate_main",) - Parameters - ---------- - argv : list[str] - Command-line arguments to start the Legate driver with - Returns - ------- - int, a process return code - - """ +def prepare_driver( + argv: list[str], + driver_type: Union[Type[CanonicalDriver], Type[LegateDriver]], +) -> Union[CanonicalDriver, LegateDriver]: from ..util.system import System from ..util.ui import error - from . import Config, Driver + from . import Config from .driver import print_verbose try: config = Config(argv) except Exception as e: - print(error("Could not configure Legate driver:\n")) + print(error("Could not configure driver:\n")) raise e try: @@ -52,11 +46,29 @@ def main(argv: list[str]) -> int: raise e try: - driver = Driver(config, system) + driver = driver_type(config, system) except Exception as e: - msg = "Could not initialize Legate driver, path config and exception follow:" # noqa + msg = "Could not initialize driver, path config and exception follow:" # noqa print(error(msg)) print_verbose(system) raise e + return driver + + +def legate_main(argv: list[str]) -> int: + """A main function for the Legate driver that can be used programmatically + or by entry-points. + + Parameters + ---------- + argv : list[str] + Command-line arguments to start the Legate driver with + + Returns + ------- + int, a process return code + + """ + driver = prepare_driver(argv, LegateDriver) return driver.run() diff --git a/legate/jupyter/config.py b/legate/jupyter/config.py index 2acbc6dcb..ebec279be 100644 --- a/legate/jupyter/config.py +++ b/legate/jupyter/config.py @@ -19,6 +19,7 @@ from dataclasses import dataclass from pathlib import Path +from typing import Optional import legate.util.colors as colors from legate.driver.config import ( @@ -79,6 +80,7 @@ def __init__(self, argv: ArgList) -> None: self.memory = object_to_dataclass(args, Memory) # turn everything else off + self.user_script: Optional[str] = None self.user_opts: tuple[str, ...] = () self.binding = Binding(None, None, None, None) self.profiling = Profiling(False, False, False, False, "", []) diff --git a/legate/jupyter/kernel.py b/legate/jupyter/kernel.py index daadae9ff..ae371e28f 100644 --- a/legate/jupyter/kernel.py +++ b/legate/jupyter/kernel.py @@ -31,7 +31,7 @@ NoSuchKernel, ) -from legate.driver import Driver +from legate.driver import LegateDriver from legate.jupyter.config import Config from legate.util.types import ArgList from legate.util.ui import error @@ -48,7 +48,7 @@ class LegateMetadata(TypedDict): LEGATE_JUPYTER_METADATA_KEY: Literal["legate"] = "legate" -def generate_kernel_spec(driver: Driver, config: Config) -> KernelSpec: +def generate_kernel_spec(driver: LegateDriver, config: Config) -> KernelSpec: legion_kernel = Path(__file__).parent / "_legion_kernel.py" argv = list(driver.cmd) + [str(legion_kernel), "-f", "{connection_file}"] diff --git a/legate/jupyter/main.py b/legate/jupyter/main.py index 494fdf421..d287022d3 100644 --- a/legate/jupyter/main.py +++ b/legate/jupyter/main.py @@ -16,7 +16,7 @@ # from __future__ import annotations -from legate.driver import Driver +from legate.driver import LegateDriver from legate.jupyter.config import Config from legate.jupyter.kernel import generate_kernel_spec, install_kernel_spec from legate.util.system import System @@ -28,7 +28,7 @@ def main(argv: list[str]) -> int: config = Config(argv) system = System() - driver = Driver(config, system) + driver = LegateDriver(config, system) spec = generate_kernel_spec(driver, config) diff --git a/legate/rc.py b/legate/rc.py deleted file mode 100644 index 437eac146..000000000 --- a/legate/rc.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2021-2022 NVIDIA Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from __future__ import annotations - -LEGION_WARNING = """ - -All Legate programs must be run with a legion_python interperter. We -recommend that you use the Legate driver script "bin/legate" found -in the installation directory to launch Legate programs as it -provides easy-to-use flags for invoking legion_python. You can see -options for using the driver script with "bin/legate --help". You -can also invoke legion_python directly. - -Use "bin/legate --verbose ..." to see some examples of how to call -legion_python directly. -""" - - -def has_legion_context() -> bool: - """Determine whether we are running in legion_python. - - Returns - bool : True if running in legion_python, otherwise False - - """ - try: - from legion_cffi import lib - - return lib.legion_runtime_has_context() - except (ModuleNotFoundError, AttributeError): - return False - - -def check_legion(msg: str = LEGION_WARNING) -> None: - """Raise an error if we are not running in legion_python.""" - if not has_legion_context(): - raise RuntimeError(msg) diff --git a/legate/util/shared_args.py b/legate/util/shared_args.py index 688c0bfa3..ac3a561f6 100644 --- a/legate/util/shared_args.py +++ b/legate/util/shared_args.py @@ -83,7 +83,8 @@ choices=LAUNCHERS, default="none", help='launcher program to use (set to "none" for local runs, or if ' - "the launch has already happened by the time legate is invoked)", + "the launch has already happened by the time legate is invoked), " + "[legate-only, not supported with standard Python invocation]", ), ) @@ -97,7 +98,8 @@ required=False, help="additional argument to pass to the launcher (can appear more " "than once). Multiple arguments may be provided together in a quoted " - "string (arguments with spaces inside must be additionally quoted)", + "string (arguments with spaces inside must be additionally quoted), " + "[legate-only, not supported with standard Python invocation]", ), ) diff --git a/tests/unit/legate/driver/test_command.py b/tests/unit/legate/driver/test_command.py index 436d53bbf..28ace41fc 100644 --- a/tests/unit/legate/driver/test_command.py +++ b/tests/unit/legate/driver/test_command.py @@ -29,7 +29,10 @@ def test___all__() -> None: - assert m.__all__ == ("CMD_PARTS",) + assert m.__all__ == ( + "CMD_PARTS_LEGION", + "CMD_PARTS_CANONICAL", + ) def test_LEGATE_GLOBAL_RANK_SUBSTITUTION() -> None: @@ -37,7 +40,7 @@ def test_LEGATE_GLOBAL_RANK_SUBSTITUTION() -> None: def test_CMD_PARTS() -> None: - assert m.CMD_PARTS == ( + assert m.CMD_PARTS_LEGION == ( m.cmd_bind, m.cmd_rlwrap, m.cmd_gdb, @@ -46,9 +49,10 @@ def test_CMD_PARTS() -> None: m.cmd_nsys, m.cmd_memcheck, m.cmd_legion, - m.cmd_nocr, + m.cmd_python_processor, m.cmd_module, - m.cmd_processor, + m.cmd_nocr, + m.cmd_local_field, m.cmd_kthreads, m.cmd_cpus, m.cmd_gpus, @@ -63,6 +67,7 @@ def test_CMD_PARTS() -> None: m.cmd_log_file, m.cmd_eager_alloc, m.cmd_ucx, + m.cmd_user_script, m.cmd_user_opts, ) @@ -629,13 +634,22 @@ def test_default(self, genobjs: GenObjs) -> None: assert result == (str(system.legion_paths.legion_python),) -class Test_cmd_processor: +class Test_cmd_python_processor: + def test_default(self, genobjs: GenObjs) -> None: + config, system, launcher = genobjs([]) + + result = m.cmd_python_processor(config, system, launcher) + + assert result == ("-ll:py", "1") + + +class Test_cmd_local_field: def test_default(self, genobjs: GenObjs) -> None: config, system, launcher = genobjs([]) - result = m.cmd_processor(config, system, launcher) + result = m.cmd_local_field(config, system, launcher) - assert result == ("-ll:py", "1", "-lg:local", "0") + assert result == ("-lg:local", "0") class Test_cmd_kthreads: @@ -1210,7 +1224,9 @@ class Test_cmd_user_opts: def test_basic(self, genobjs: GenObjs, opts: list[str]) -> None: config, system, launcher = genobjs(opts, fake_module=None) - result = m.cmd_user_opts(config, system, launcher) + user_opts = m.cmd_user_opts(config, system, launcher) + user_script = m.cmd_user_script(config, system, launcher) + result = user_script + user_opts assert result == tuple(opts) @@ -1219,7 +1235,9 @@ def test_with_legate_opts(self, genobjs: GenObjs, opts: list[str]) -> None: args = ["--verbose", "--rlwrap", "--gpus", "2"] + opts config, system, launcher = genobjs(args, fake_module=None) - result = m.cmd_user_opts(config, system, launcher) + user_opts = m.cmd_user_opts(config, system, launcher) + user_script = m.cmd_user_script(config, system, launcher) + result = user_script + user_opts assert result == tuple(opts) diff --git a/tests/unit/legate/driver/test_config.py b/tests/unit/legate/driver/test_config.py index 91b6f5056..168d248f0 100644 --- a/tests/unit/legate/driver/test_config.py +++ b/tests/unit/legate/driver/test_config.py @@ -447,7 +447,8 @@ def test_log_to_file_fixup( def test_user_opts(self, args: tuple[str, ...]) -> None: c = m.Config(["legate"] + list(args) + ["foo.py", "-a", "1"]) - assert c.user_opts == ("foo.py", "-a", "1") + assert c.user_opts == ("-a", "1") + assert c.user_script == "foo.py" def test_console_true(self) -> None: c = m.Config(["legate"]) @@ -458,5 +459,6 @@ def test_console_true(self) -> None: def test_console_false(self) -> None: c = m.Config(["legate", "--rlwrap", "--gpus", "2", "foo.py", "-a"]) - assert c.user_opts == ("foo.py", "-a") + assert c.user_opts == ("-a",) + assert c.user_script == "foo.py" assert not c.console diff --git a/tests/unit/legate/driver/test_driver.py b/tests/unit/legate/driver/test_driver.py index 652f73627..3bb417ffb 100644 --- a/tests/unit/legate/driver/test_driver.py +++ b/tests/unit/legate/driver/test_driver.py @@ -21,7 +21,7 @@ from pytest_mock import MockerFixture import legate.driver.driver as m -from legate.driver.command import CMD_PARTS +from legate.driver.command import CMD_PARTS_LEGION from legate.driver.config import Config from legate.driver.launcher import RANK_ENV_VARS, Launcher from legate.util.colors import scrub @@ -48,7 +48,7 @@ class TestDriver: def test_init(self, genconfig: GenConfig, launch: LauncherType) -> None: config = genconfig(["--launcher", launch]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) assert driver.config is config assert driver.system is SYSTEM @@ -58,9 +58,11 @@ def test_init(self, genconfig: GenConfig, launch: LauncherType) -> None: def test_cmd(self, genconfig: GenConfig, launch: LauncherType) -> None: config = genconfig(["--launcher", launch]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) - parts = (part(config, SYSTEM, driver.launcher) for part in CMD_PARTS) + parts = ( + part(config, SYSTEM, driver.launcher) for part in CMD_PARTS_LEGION + ) expected_cmd = driver.launcher.cmd + sum(parts, ()) assert driver.cmd == expected_cmd @@ -69,7 +71,7 @@ def test_cmd(self, genconfig: GenConfig, launch: LauncherType) -> None: def test_env(self, genconfig: GenConfig, launch: LauncherType) -> None: config = genconfig(["--launcher", launch]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) assert driver.env == driver.launcher.env @@ -79,7 +81,7 @@ def test_custom_env_vars( ) -> None: config = genconfig(["--launcher", launch]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) assert driver.custom_env_vars == driver.launcher.custom_env_vars @@ -88,7 +90,7 @@ def test_dry_run( self, genconfig: GenConfig, mocker: MockerFixture, launch: LauncherType ) -> None: config = genconfig(["--launcher", launch, "--dry-run"]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) mocker.patch.object(m, "process_logs") mock_run = mocker.patch.object(m, "run") @@ -102,7 +104,7 @@ def test_run( self, genconfig: GenConfig, mocker: MockerFixture, launch: LauncherType ) -> None: config = genconfig(["--launcher", launch]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) mocker.patch.object(m, "process_logs") mock_run = mocker.patch.object(m, "run") @@ -120,7 +122,7 @@ def test_verbose( ) -> None: # set --dry-run to avoid needing to mock anything config = genconfig(["--launcher", launch, "--verbose", "--dry-run"]) - driver = m.Driver(config, SYSTEM) + driver = m.LegateDriver(config, SYSTEM) driver.run() @@ -149,7 +151,7 @@ def test_verbose_nonero_rank_id( ["--launcher", "none", "--verbose", "--dry-run"], multi_rank=(2, 2) ) system = System() - driver = m.Driver(config, system) + driver = m.LegateDriver(config, system) driver.run() @@ -176,7 +178,7 @@ def test_darwin_gdb_warning( # set --dry-run to avoid needing to mock anything config = genconfig(["--launcher", launch, "--gdb", "--dry-run"]) - driver = m.Driver(config, system) + driver = m.LegateDriver(config, system) driver.run() @@ -205,7 +207,7 @@ def test_system_only(self, capsys: Capsys) -> None: def test_system_and_driver(self, capsys: Capsys) -> None: config = Config(["legate", "--no-replicate"]) system = System() - driver = m.Driver(config, system) + driver = m.LegateDriver(config, system) m.print_verbose(system, driver) diff --git a/tests/unit/legate/driver/test_main.py b/tests/unit/legate/driver/test_main.py index c0dfd07d5..77d29953c 100644 --- a/tests/unit/legate/driver/test_main.py +++ b/tests/unit/legate/driver/test_main.py @@ -38,8 +38,8 @@ def test_main(mocker: MockerFixture) -> None: config_spy = mocker.spy(legate.driver.config.Config, "__init__") system_spy = mocker.spy(legate.util.system.System, "__init__") - driver_spy = mocker.spy(legate.driver.driver.Driver, "__init__") - mocker.patch("legate.driver.driver.Driver.run", return_value=123) + driver_spy = mocker.spy(legate.driver.driver.LegateDriver, "__init__") + mocker.patch("legate.driver.driver.LegateDriver.run", return_value=123) mocker.patch.object(sys, "argv", ["/some/path/foo", "bar"]) result = m.main() diff --git a/tests/unit/legate/jupyter/test_kernel.py b/tests/unit/legate/jupyter/test_kernel.py index d176ba23d..105451b93 100644 --- a/tests/unit/legate/jupyter/test_kernel.py +++ b/tests/unit/legate/jupyter/test_kernel.py @@ -20,7 +20,7 @@ from pytest_mock import MockerFixture import legate.jupyter.kernel as m -from legate.driver import Driver +from legate.driver import LegateDriver from legate.jupyter.config import Config from legate.util.system import System @@ -41,7 +41,7 @@ def test_LEGATE_JUPYTER_METADATA_KEY() -> None: class Test_generate_kernel_spec: def test_defatul(self) -> None: config = Config([]) - driver = Driver(config, system) + driver = LegateDriver(config, system) spec = m.generate_kernel_spec(driver, config) @@ -77,7 +77,7 @@ def test_install(self, mocker: MockerFixture, capsys: Capsys) -> None: config = Config( ["legate-jupyter", "--name", "____fake_test_kernel_123abc_____"] ) - driver = Driver(config, system) + driver = LegateDriver(config, system) spec = m.generate_kernel_spec(driver, config) @@ -112,7 +112,7 @@ def test_install_verbose( "____fake_test_kernel_123abc_____", ] ) - driver = Driver(config, system) + driver = LegateDriver(config, system) spec = m.generate_kernel_spec(driver, config) @@ -148,7 +148,7 @@ def test_install_verbose2( "____fake_test_kernel_123abc_____", ] ) - driver = Driver(config, system) + driver = LegateDriver(config, system) spec = m.generate_kernel_spec(driver, config) diff --git a/tests/unit/legate/jupyter/test_main.py b/tests/unit/legate/jupyter/test_main.py index a92b071c7..c25c2c5b3 100644 --- a/tests/unit/legate/jupyter/test_main.py +++ b/tests/unit/legate/jupyter/test_main.py @@ -38,7 +38,7 @@ def test_main(mocker: MockerFixture) -> None: config_spy = mocker.spy(legate.jupyter.config.Config, "__init__") system_spy = mocker.spy(legate.util.system.System, "__init__") - driver_spy = mocker.spy(legate.driver.driver.Driver, "__init__") + driver_spy = mocker.spy(legate.driver.driver.LegateDriver, "__init__") generate_spy = mocker.spy(legate.jupyter.kernel, "generate_kernel_spec") install_mock = mocker.patch("legate.jupyter.kernel.install_kernel_spec") mocker.patch.object( @@ -64,7 +64,7 @@ def test_main(mocker: MockerFixture) -> None: assert generate_spy.call_count == 1 assert len(generate_spy.call_args[0]) == 2 assert isinstance( - generate_spy.call_args[0][0], legate.driver.driver.Driver + generate_spy.call_args[0][0], legate.driver.driver.LegateDriver ) assert isinstance( generate_spy.call_args[0][1], legate.jupyter.config.Config diff --git a/tests/unit/legate/test_rc.py b/tests/unit/legate/test_rc.py deleted file mode 100644 index 74cea3092..000000000 --- a/tests/unit/legate/test_rc.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2021-2022 NVIDIA Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -import sys -from unittest.mock import MagicMock - -import pytest - -import legate.rc as m - - -@pytest.fixture -def mock_has_legion_context(monkeypatch: pytest.MonkeyPatch) -> MagicMock: - stub = MagicMock() - monkeypatch.setattr("legate.rc.has_legion_context", stub) - return stub - - -class Test_check_legion: - def test_True(self, mock_has_legion_context: MagicMock) -> None: - mock_has_legion_context.return_value = True - assert m.check_legion() is None # type: ignore[func-returns-value] - - def test_True_with_msg(self, mock_has_legion_context: MagicMock) -> None: - mock_has_legion_context.return_value = True - assert m.check_legion(msg="custom") is None # type: ignore[func-returns-value] # noqa - - def test_False(self, mock_has_legion_context: MagicMock) -> None: - mock_has_legion_context.return_value = False - with pytest.raises(RuntimeError) as e: - m.check_legion() - assert str(e) == m.LEGION_WARNING - - def test_False_with_msg(self, mock_has_legion_context: MagicMock) -> None: - mock_has_legion_context.return_value = False - with pytest.raises(RuntimeError) as e: - m.check_legion(msg="custom") - assert str(e) == "custom" - - -@pytest.mark.skip -class Test_has_legion_context: - def test_True(self) -> None: - assert m.has_legion_context() is True - - # It does not seem possible to patch CFFI libs, so testing - # the "False" branch is not really feasible - @pytest.mark.skip - def test_False(self) -> None: - pass - - -if __name__ == "__main__": - sys.exit(pytest.main(sys.argv)) diff --git a/typings/legion_cffi/__init__.pyi b/typings/legion_cffi/__init__.pyi index 66acac230..50d84df5b 100644 --- a/typings/legion_cffi/__init__.pyi +++ b/typings/legion_cffi/__init__.pyi @@ -42,3 +42,5 @@ class FFI: ) -> CData: ... ffi: FFI + +is_legion_python: bool diff --git a/typings/legion_top/__init__.pyi b/typings/legion_top/__init__.pyi index da8b37606..2ee59f46f 100644 --- a/typings/legion_top/__init__.pyi +++ b/typings/legion_top/__init__.pyi @@ -13,11 +13,13 @@ # limitations under the License. # -from typing import Any, Callable +from typing import Any, Callable, Tuple from legion_cffi.lib import legion_context_t, legion_runtime_t def add_cleanup_item(callback: Callable[[], None]) -> None: ... +def legion_canonical_python_main(sys_argv: Tuple[str, ...]) -> None: ... +def legion_canonical_python_cleanup() -> None: ... class top_level: runtime: list[legion_runtime_t] @@ -25,5 +27,7 @@ class top_level: __all__ = ( "add_cleanup_item", + "legion_canonical_python_main", + "legion_canonical_python_cleanup", "top_level", ) From c41b692b0a50470f08a2b699191e68b0ee2a79f2 Mon Sep 17 00:00:00 2001 From: Marcin Zalewski Date: Mon, 30 Jan 2023 15:31:23 -0800 Subject: [PATCH 04/57] pre-commit autoupdate (#553) Co-authored-by: Marcin Zalewski --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c6003f5fc..1bc88456f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/PyCQA/isort - rev: 5.11.4 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/psf/black From 561ad4c3749691b7ee978409802ac64cd5be36ae Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 30 Jan 2023 17:14:58 -0800 Subject: [PATCH 05/57] Use @loader_path instead of $ORIGIN on MacOS (#543) * Use @loader_path instead of $ORIGIN on MacOS * Cleaner setting --- legate_core_cpp.cmake | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index ef714345f..d9bbd10b7 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -231,11 +231,17 @@ endif() add_library(legate_core ${legate_core_SOURCES}) add_library(legate::core ALIAS legate_core) +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(platform_rpath_origin "\$ORIGIN") +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(platform_rpath_origin "@loader_path") +endif () + set_target_properties(legate_core PROPERTIES EXPORT_NAME core LIBRARY_OUTPUT_NAME lgcore - BUILD_RPATH "\$ORIGIN" - INSTALL_RPATH "\$ORIGIN" + BUILD_RPATH "${platform_rpath_origin}" + INSTALL_RPATH "${platform_rpath_origin}" CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON CUDA_STANDARD 17 From 7d162218139a97c6430c20501969fb22a8775071 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 31 Jan 2023 13:55:57 -0800 Subject: [PATCH 06/57] Report version info in --verbose outupt (#549) * prefer f-strings in install.py * report version info in --verbose outupt * kick ci --- install.py | 24 ++++++++++++------------ legate/driver/driver.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/install.py b/install.py index e2506a68d..a2b8738c5 100755 --- a/install.py +++ b/install.py @@ -413,7 +413,7 @@ def validate_path(path): cmake_flags = cmd_env.get("CMAKE_ARGS", "").split(" ") if debug or verbose: - cmake_flags += ["--log-level=%s" % ("DEBUG" if debug else "VERBOSE")] + cmake_flags += [f"--log-level={'DEBUG' if debug else 'VERBOSE'}"] cmake_flags += f"""\ -DCMAKE_BUILD_TYPE={( @@ -441,27 +441,27 @@ def validate_path(path): """.splitlines() if nccl_dir: - cmake_flags += ["-DNCCL_DIR=%s" % nccl_dir] + cmake_flags += [f"-DNCCL_DIR={nccl_dir}"] if gasnet_dir: - cmake_flags += ["-DGASNet_ROOT_DIR=%s" % gasnet_dir] + cmake_flags += [f"-DGASNet_ROOT_DIR={gasnet_dir}"] if ucx_dir: - cmake_flags += ["-DUCX_ROOT=%s" % ucx_dir] + cmake_flags += [f"-DUCX_ROOT={ucx_dir}"] if conduit: - cmake_flags += ["-DGASNet_CONDUIT=%s" % conduit] + cmake_flags += [f"-DGASNet_CONDUIT={conduit}"] if cuda_dir: - cmake_flags += ["-DCUDA_TOOLKIT_ROOT_DIR=%s" % cuda_dir] + cmake_flags += [f"-DCUDA_TOOLKIT_ROOT_DIR={cuda_dir}"] if thrust_dir: - cmake_flags += ["-DThrust_ROOT=%s" % thrust_dir] + cmake_flags += [f"-DThrust_ROOT={thrust_dir}"] if legion_dir: - cmake_flags += ["-DLegion_ROOT=%s" % legion_dir] + cmake_flags += [f"-DLegion_ROOT={legion_dir}"] elif legion_src_dir: - cmake_flags += ["-DCPM_Legion_SOURCE=%s" % legion_src_dir] + cmake_flags += [f"-DCPM_Legion_SOURCE={legion_src_dir}"] else: cmake_flags += ["-DCPM_DOWNLOAD_Legion=ON"] if legion_url: - cmake_flags += ["-Dlegate_core_LEGION_REPOSITORY=%s" % legion_url] + cmake_flags += [f"-Dlegate_core_LEGION_REPOSITORY={legion_url}"] if legion_branch: - cmake_flags += ["-Dlegate_core_LEGION_BRANCH=%s" % legion_branch] + cmake_flags += [f"-Dlegate_core_LEGION_BRANCH={legion_branch}"] cmake_flags += extra_flags build_flags = [f"-j{str(thread_count)}"] @@ -761,7 +761,7 @@ def driver(): ) print("to specify the CMake executable if it is not on PATH.") print() - print("Attempted to execute: %s" % args.cmake_exe) + print(f"Attempted to execute: {args.cmake_exe}") sys.exit(1) install(unknown=unknown, **vars(args)) diff --git a/legate/driver/driver.py b/legate/driver/driver.py index f4f12e0ef..f01ada82d 100644 --- a/legate/driver/driver.py +++ b/legate/driver/driver.py @@ -14,12 +14,15 @@ # from __future__ import annotations +import os +from dataclasses import dataclass from shlex import quote from subprocess import run from textwrap import indent from typing import TYPE_CHECKING from ..util.system import System +from ..util.types import DataclassMixin from ..util.ui import kvtable, rule, section, value, warn from .command import CMD_PARTS_CANONICAL, CMD_PARTS_LEGION from .config import ConfigProtocol @@ -41,6 +44,14 @@ """ +@dataclass(frozen=True) +class LegateVersions(DataclassMixin): + """Collect package versions relevant to Legate.""" + + legate_version: str + cunumeric_version: str | None + + class LegateDriver: """Coordinate the system, user-configuration, and launcher to appropriately execute the Legate process. @@ -173,6 +184,23 @@ def run(self) -> int: assert False, "This function should not be invoked." +def get_versions() -> LegateVersions: + from legate import __version__ as lg_version + + os.environ["_LEGATE_PROJECT_HELP_ARGS_"] = "1" + try: + import cunumeric # type: ignore [import] + + cn_version = cunumeric.__version__ + except ModuleNotFoundError: + cn_version = None + del os.environ["_LEGATE_PROJECT_HELP_ARGS_"] + + return LegateVersions( + legate_version=lg_version, cunumeric_version=cn_version + ) + + def print_verbose( system: System, driver: LegateDriver | None = None, @@ -202,6 +230,9 @@ def print_verbose( print(section("\nLegion paths:")) print(indent(str(system.legion_paths), prefix=" ")) + print(section("\nVersions:")) + print(indent(str(get_versions()), prefix=" ")) + if driver: print(section("\nCommand:")) cmd = " ".join(quote(t) for t in driver.cmd) From 1db1434dc075da269d61ba2910c3d939a1c9772b Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Wed, 1 Feb 2023 13:04:21 -0800 Subject: [PATCH 07/57] don't report cn version for now (#555) --- legate/driver/driver.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/legate/driver/driver.py b/legate/driver/driver.py index f01ada82d..a534bf09f 100644 --- a/legate/driver/driver.py +++ b/legate/driver/driver.py @@ -14,7 +14,6 @@ # from __future__ import annotations -import os from dataclasses import dataclass from shlex import quote from subprocess import run @@ -49,7 +48,6 @@ class LegateVersions(DataclassMixin): """Collect package versions relevant to Legate.""" legate_version: str - cunumeric_version: str | None class LegateDriver: @@ -187,18 +185,7 @@ def run(self) -> int: def get_versions() -> LegateVersions: from legate import __version__ as lg_version - os.environ["_LEGATE_PROJECT_HELP_ARGS_"] = "1" - try: - import cunumeric # type: ignore [import] - - cn_version = cunumeric.__version__ - except ModuleNotFoundError: - cn_version = None - del os.environ["_LEGATE_PROJECT_HELP_ARGS_"] - - return LegateVersions( - legate_version=lg_version, cunumeric_version=cn_version - ) + return LegateVersions(legate_version=lg_version) def print_verbose( From c3f46931d436b1d9c5ff73b7a3b6300eb79e81b6 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Wed, 1 Feb 2023 14:35:11 -0800 Subject: [PATCH 08/57] Update information about conda packages --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 040142e6f..ba08b815b 100644 --- a/README.md +++ b/README.md @@ -223,8 +223,12 @@ Legate Core is available [on conda](https://anaconda.org/legate/legate-core): conda install -c nvidia -c conda-forge -c legate legate-core ``` -The conda package is compatible with CUDA >= 11.4 (CUDA driver version >= r470), -and Volta or later GPU architectures. +Only linux-64 packages are available at the moment. + +The default package contains GPU support, and is compatible with CUDA >= 11.4 +(CUDA driver version >= r470), and Volta or later GPU architectures. There are +also CPU-only packages available, and will be automatically selected by `conda` +when installing on a machine without GPUs. See [BUILD.md](BUILD.md) for instructions on building Legate Core from source. From 07e86edaa2d4e609faa3a40e626936eef1556174 Mon Sep 17 00:00:00 2001 From: Evan Ramos Date: Thu, 2 Feb 2023 13:08:38 -0600 Subject: [PATCH 09/57] NVTX: Use RangePush and Domain (#293) * NVTX: Use RangePush instead of RangeStart * NVTX: Use Domain --- src/core/runtime/runtime.cc | 13 ++++++++++++- src/core/utilities/nvtx_help.h | 18 +++++++++++++++--- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/core/runtime/runtime.cc b/src/core/runtime/runtime.cc index 27e14a7da..e43236b60 100644 --- a/src/core/runtime/runtime.cc +++ b/src/core/runtime/runtime.cc @@ -45,6 +45,11 @@ static const char* const core_library_name = "legate.core"; /*static*/ bool Core::has_socket_mem = false; +#ifdef LEGATE_USE_CUDA +/*static*/ const char* const nvtx::Range::domainName = "Legate"; +/*static*/ nvtxDomainHandle_t nvtx::Range::domain; +#endif + /*static*/ void Core::parse_config(void) { #ifndef LEGATE_USE_CUDA @@ -83,6 +88,10 @@ static const char* const core_library_name = "legate.core"; parse_variable("LEGATE_EMPTY_TASK", use_empty_task); parse_variable("LEGATE_SYNC_STREAM_VIEW", synchronize_stream_view); parse_variable("LEGATE_LOG_MAPPING", log_mapping_decisions); + +#ifdef LEGATE_USE_CUDA + nvtx::Range::initialize(); +#endif } static void extract_scalar_task( @@ -107,7 +116,9 @@ static void extract_scalar_task( /*static*/ void Core::shutdown(void) { - // Nothing to do here yet... +#ifdef LEGATE_USE_CUDA + nvtx::Range::shutdown(); +#endif } /*static*/ void Core::show_progress(const Legion::Task* task, diff --git a/src/core/utilities/nvtx_help.h b/src/core/utilities/nvtx_help.h index 9b5c6270c..4d967993e 100644 --- a/src/core/utilities/nvtx_help.h +++ b/src/core/utilities/nvtx_help.h @@ -27,11 +27,23 @@ namespace nvtx { class Range { public: - Range(const char* message) { range_ = nvtxRangeStartA(message); } - ~Range() { nvtxRangeEnd(range_); } + Range(const char* message) + { + nvtxEventAttributes_t eventAttrib = {0}; + eventAttrib.version = NVTX_VERSION; + eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; + eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; + eventAttrib.message.ascii = message; + nvtxDomainRangePushEx(domain, &eventAttrib); + } + ~Range() { nvtxDomainRangePop(domain); } + + static void initialize() { domain = nvtxDomainCreateA(domainName); } + static void shutdown() { nvtxDomainDestroy(domain); } private: - nvtxRangeId_t range_; + static const char* const domainName; + static nvtxDomainHandle_t domain; }; } // namespace nvtx From 8b4317258343a511c3270460427563ddfe312286 Mon Sep 17 00:00:00 2001 From: Marcin Zalewski Date: Thu, 2 Feb 2023 11:42:15 -0800 Subject: [PATCH 10/57] Update label action to v3 (#557) Co-authored-by: Marcin Zalewski --- .github/workflows/require-labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/require-labels.yml b/.github/workflows/require-labels.yml index d6634be4f..d7090f59b 100644 --- a/.github/workflows/require-labels.yml +++ b/.github/workflows/require-labels.yml @@ -11,7 +11,7 @@ jobs: run: sleep 300s shell: bash - name: Check Labels - uses: mheap/github-action-required-labels@v2 + uses: mheap/github-action-required-labels@v3 with: mode: exactly count: 1 From 34917dfe36717a4f5a883689f007d29277f42e92 Mon Sep 17 00:00:00 2001 From: Marcin Zalewski Date: Thu, 2 Feb 2023 11:44:54 -0800 Subject: [PATCH 11/57] Remove unsuccessful label delay (#558) Co-authored-by: Marcin Zalewski --- .github/workflows/require-labels.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/require-labels.yml b/.github/workflows/require-labels.yml index d7090f59b..4a6fc3b6e 100644 --- a/.github/workflows/require-labels.yml +++ b/.github/workflows/require-labels.yml @@ -6,10 +6,6 @@ jobs: label: runs-on: ubuntu-latest steps: - - name: Delay checking labels if PR is just created - if: ${{ github.event.action == 'opened' }} - run: sleep 300s - shell: bash - name: Check Labels uses: mheap/github-action-required-labels@v3 with: From 733cdd40d5a1906dac27f486dd331f25ff2461d3 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Thu, 9 Feb 2023 07:41:55 -0800 Subject: [PATCH 12/57] Args and Config (#562) * use REMAINDER to determine script to run * put coverage in the correct relative position * Update legate/driver/args.py Co-authored-by: Manolis Papadakis * add LEGATE_CONFIG --------- Co-authored-by: Manolis Papadakis --- legate/core/__init__.py | 30 +++++++++++-------- legate/driver/__init__.py | 14 +++++++-- legate/driver/args.py | 9 +++++- legate/driver/config.py | 10 ++----- legate/tester/stages/_linux/cpu.py | 4 ++- legate/tester/stages/_linux/eager.py | 2 ++ legate/tester/stages/_linux/gpu.py | 4 ++- legate/tester/stages/_linux/omp.py | 4 ++- legate/tester/stages/_osx/cpu.py | 4 ++- legate/tester/stages/_osx/eager.py | 2 ++ legate/tester/stages/_osx/gpu.py | 4 ++- legate/tester/stages/_osx/omp.py | 4 ++- legate/tester/stages/test_stage.py | 18 +++++++++-- .../legate/tester/stages/_linux/test_cpu.py | 9 ++++-- .../legate/tester/stages/_linux/test_gpu.py | 3 +- .../legate/tester/stages/_linux/test_omp.py | 9 ++++-- .../legate/tester/stages/test_test_stage.py | 2 ++ 17 files changed, 93 insertions(+), 39 deletions(-) diff --git a/legate/core/__init__.py b/legate/core/__init__.py index f653a00fe..7ca864b6c 100644 --- a/legate/core/__init__.py +++ b/legate/core/__init__.py @@ -14,8 +14,6 @@ # from __future__ import annotations -from ..util.args import parse_library_command_args - from legion_cffi import is_legion_python, ffi, lib as legion if is_legion_python == False: @@ -24,20 +22,26 @@ legion_canonical_python_cleanup, ) from ..driver.main import prepare_driver, CanonicalDriver - import atexit, sys, os + import atexit, os, shlex, sys + + # A little explanation. We want to encourage configuration options be + # passed via LEGATE_CONFIG, in order to be considerate to user scripts. + # But we still need to accept actual command line args for comaptibility, + # and those should also take precedences. Here we splice the options from + # LEGATE_CONFIG in before sys.argv, and take advantage of the fact that if + # there are any options repeated in both places, argparse will use the + # latter (i.e. the actual command line provided ones). + env_args = shlex.split(os.environ.get("LEGATE_CONFIG", "")) + argv = ["legate"] + env_args + sys.argv + + driver = prepare_driver(argv, CanonicalDriver) - # parse legate args into legion args - sys_argv = [ - "python", - ] + sys.argv - driver = prepare_driver(sys_argv, CanonicalDriver) if driver.dry_run: sys.exit(0) - legate_argv = driver.cmd - legate_env = driver.env - # set env - os.environ.update(legate_env) - legion_canonical_python_main(legate_argv) + + os.environ.update(driver.env) + + legion_canonical_python_main(driver.cmd) atexit.register(legion_canonical_python_cleanup) from ._legion import ( diff --git a/legate/driver/__init__.py b/legate/driver/__init__.py index 5ee41b8be..786b0f069 100644 --- a/legate/driver/__init__.py +++ b/legate/driver/__init__.py @@ -20,8 +20,18 @@ def main() -> int: - import sys + import os, shlex, sys from .main import legate_main as _main - return _main(sys.argv) + # A little explanation. We want to encourage configuration options be + # passed via LEGATE_CONFIG, in order to be considerate to user scripts. + # But we still need to accept actual command line args for comaptibility, + # and those should also take precedences. Here we splice the options from + # LEGATE_CONFIG in before sys.argv, and take advantage of the fact that if + # there are any options repeated in both places, argparse will use the + # latter (i.e. the actual command line provided ones). + env_args = shlex.split(os.environ.get("LEGATE_CONFIG", "")) + argv = sys.argv[:1] + env_args + sys.argv[1:] + + return _main(argv) diff --git a/legate/driver/args.py b/legate/driver/args.py index 8557601f6..3747bbaac 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -16,7 +16,7 @@ # from __future__ import annotations -from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser +from argparse import REMAINDER, ArgumentDefaultsHelpFormatter, ArgumentParser from typing import IO, Optional from ..util.shared_args import ( @@ -99,6 +99,13 @@ def print_help(self, file: Optional[IO[str]] = None) -> None: formatter_class=ArgumentDefaultsHelpFormatter, ) +parser.add_argument( + "command", + nargs=REMAINDER, + help="A python script to run, plus any arguments for the script. " + "Any arguments after the script will be passed to the script, i.e. " + "NOT used as arguments to legate itself.", +) multi_node = parser.add_argument_group("Multi-node configuration") multi_node.add_argument(NODES.name, **NODES.kwargs) diff --git a/legate/driver/config.py b/legate/driver/config.py index 996248c0f..7e7ceb9ae 100644 --- a/legate/driver/config.py +++ b/legate/driver/config.py @@ -178,19 +178,15 @@ class Config: def __init__(self, argv: ArgList) -> None: self.argv = argv - args, extra = parser.parse_known_args(self.argv[1:]) + args = parser.parse_args(self.argv[1:]) colors.ENABLED = args.color # only saving this for help with testing self._args = args - self.user_script = next((x for x in extra if x.endswith(".py")), None) - - user_opts = list(extra) - if self.user_script in user_opts: - user_opts.remove(self.user_script) - self.user_opts = tuple(user_opts) + self.user_script = args.command[0] if args.command else None + self.user_opts = tuple(args.command[1:]) if self.user_script else () # these may modify the args, so apply before dataclass conversions self._fixup_nocr(args) diff --git a/legate/tester/stages/_linux/cpu.py b/legate/tester/stages/_linux/cpu.py index deb5610a6..ef5b2c0f4 100644 --- a/legate/tester/stages/_linux/cpu.py +++ b/legate/tester/stages/_linux/cpu.py @@ -48,7 +48,9 @@ class CPU(TestStage): kind: FeatureType = "cpus" - args = [CUNUMERIC_TEST_ARG] + args: ArgList = [] + + _tmp_args = [CUNUMERIC_TEST_ARG] def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/_linux/eager.py b/legate/tester/stages/_linux/eager.py index cc9a08d5a..cd11567aa 100644 --- a/legate/tester/stages/_linux/eager.py +++ b/legate/tester/stages/_linux/eager.py @@ -43,6 +43,8 @@ class Eager(TestStage): args: ArgList = [] + _tmp_args: ArgList = [] + def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/_linux/gpu.py b/legate/tester/stages/_linux/gpu.py index 64f625c00..a54db7299 100644 --- a/legate/tester/stages/_linux/gpu.py +++ b/legate/tester/stages/_linux/gpu.py @@ -44,7 +44,9 @@ class GPU(TestStage): kind: FeatureType = "cuda" - args = [CUNUMERIC_TEST_ARG] + args: ArgList = [] + + _tmp_args = [CUNUMERIC_TEST_ARG] def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/_linux/omp.py b/legate/tester/stages/_linux/omp.py index f7af3e9d0..fb54c3b12 100644 --- a/legate/tester/stages/_linux/omp.py +++ b/legate/tester/stages/_linux/omp.py @@ -48,7 +48,9 @@ class OMP(TestStage): kind: FeatureType = "openmp" - args = [CUNUMERIC_TEST_ARG] + args: ArgList = [] + + _tmp_args = [CUNUMERIC_TEST_ARG] def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/_osx/cpu.py b/legate/tester/stages/_osx/cpu.py index 182a6d76b..7e4b015a0 100644 --- a/legate/tester/stages/_osx/cpu.py +++ b/legate/tester/stages/_osx/cpu.py @@ -47,7 +47,9 @@ class CPU(TestStage): kind: FeatureType = "cpus" - args = [CUNUMERIC_TEST_ARG] + args: ArgList = [] + + _tmp_args = [CUNUMERIC_TEST_ARG] def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/_osx/eager.py b/legate/tester/stages/_osx/eager.py index b32feb17d..7b3f2d963 100644 --- a/legate/tester/stages/_osx/eager.py +++ b/legate/tester/stages/_osx/eager.py @@ -43,6 +43,8 @@ class Eager(TestStage): args: ArgList = [] + _tmp_args = [] + def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/_osx/gpu.py b/legate/tester/stages/_osx/gpu.py index 2a1597494..cbe678330 100644 --- a/legate/tester/stages/_osx/gpu.py +++ b/legate/tester/stages/_osx/gpu.py @@ -42,7 +42,9 @@ class GPU(TestStage): kind: FeatureType = "cuda" - args: ArgList = [CUNUMERIC_TEST_ARG] + args: ArgList = [] + + _tmp_args = [CUNUMERIC_TEST_ARG] def __init__(self, config: Config, system: TestSystem) -> None: raise RuntimeError("GPU test are not supported on OSX") diff --git a/legate/tester/stages/_osx/omp.py b/legate/tester/stages/_osx/omp.py index eb279791a..ca8d19e2c 100644 --- a/legate/tester/stages/_osx/omp.py +++ b/legate/tester/stages/_osx/omp.py @@ -47,7 +47,9 @@ class OMP(TestStage): kind: FeatureType = "openmp" - args = [CUNUMERIC_TEST_ARG] + args: ArgList = [] + + _tmp_args = [CUNUMERIC_TEST_ARG] def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) diff --git a/legate/tester/stages/test_stage.py b/legate/tester/stages/test_stage.py index ed24ae461..c1c0beb3c 100644 --- a/legate/tester/stages/test_stage.py +++ b/legate/tester/stages/test_stage.py @@ -57,6 +57,12 @@ class TestStage(Protocol): #: Any fixed stage-specific command-line args to pass args: ArgList + # This can go away when/if "-cunumeric:test" is replaced by an env var. + # The issue is that currently the args above are all otherwise legate + # args that must appear before the script path, but "-cunumeric:test" is + # not a legate arg, so it cannot go there. + _tmp_args: ArgList + # --- Protocol methods def __init__(self, config: Config, system: TestSystem) -> None: @@ -252,12 +258,18 @@ def run( cov_args = self.cov_args(config) - cmd = [str(config.legate_path)] + cov_args + [str(test_path)] - stage_args = self.args + self.shard_args(shard, config) file_args = self.file_args(test_file, config) - cmd += stage_args + file_args + config.extra_args + cmd = ( + [str(config.legate_path)] + + stage_args + + cov_args + + [str(test_path)] + + file_args + + config.extra_args + + self._tmp_args + ) if custom_args: cmd += custom_args diff --git a/tests/unit/legate/tester/stages/_linux/test_cpu.py b/tests/unit/legate/tester/stages/_linux/test_cpu.py index 24a4eef3d..66b73105b 100644 --- a/tests/unit/legate/tester/stages/_linux/test_cpu.py +++ b/tests/unit/legate/tester/stages/_linux/test_cpu.py @@ -31,7 +31,8 @@ def test_default() -> None: s = FakeSystem(cpus=12) stage = m.CPU(c, s) assert stage.kind == "cpus" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == UNPIN_ENV assert stage.spec.workers > 0 @@ -44,7 +45,8 @@ def test_cpu_pin_strict() -> None: s = FakeSystem(cpus=12) stage = m.CPU(c, s) assert stage.kind == "cpus" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == {} assert stage.spec.workers > 0 @@ -57,7 +59,8 @@ def test_cpu_pin_none() -> None: s = FakeSystem(cpus=12) stage = m.CPU(c, s) assert stage.kind == "cpus" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == UNPIN_ENV assert stage.spec.workers > 0 diff --git a/tests/unit/legate/tester/stages/_linux/test_gpu.py b/tests/unit/legate/tester/stages/_linux/test_gpu.py index 8d792b7b3..2946bb7dc 100644 --- a/tests/unit/legate/tester/stages/_linux/test_gpu.py +++ b/tests/unit/legate/tester/stages/_linux/test_gpu.py @@ -30,7 +30,8 @@ def test_default() -> None: s = FakeSystem() stage = m.GPU(c, s) assert stage.kind == "cuda" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == {} assert stage.spec.workers > 0 diff --git a/tests/unit/legate/tester/stages/_linux/test_omp.py b/tests/unit/legate/tester/stages/_linux/test_omp.py index a4d319fc0..3e4ffdc4d 100644 --- a/tests/unit/legate/tester/stages/_linux/test_omp.py +++ b/tests/unit/legate/tester/stages/_linux/test_omp.py @@ -31,7 +31,8 @@ def test_default() -> None: s = FakeSystem(cpus=12) stage = m.OMP(c, s) assert stage.kind == "openmp" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == UNPIN_ENV assert stage.spec.workers > 0 @@ -44,7 +45,8 @@ def test_cpu_pin_strict() -> None: s = FakeSystem(cpus=12) stage = m.OMP(c, s) assert stage.kind == "openmp" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == {} assert stage.spec.workers > 0 @@ -57,7 +59,8 @@ def test_cpu_pin_none() -> None: s = FakeSystem(cpus=12) stage = m.OMP(c, s) assert stage.kind == "openmp" - assert stage.args == ["-cunumeric:test"] + assert stage.args == [] + assert stage._tmp_args == ["-cunumeric:test"] assert stage.env(c, s) == UNPIN_ENV assert stage.spec.workers > 0 diff --git a/tests/unit/legate/tester/stages/test_test_stage.py b/tests/unit/legate/tester/stages/test_test_stage.py index fcdc7a934..fe075c685 100644 --- a/tests/unit/legate/tester/stages/test_test_stage.py +++ b/tests/unit/legate/tester/stages/test_test_stage.py @@ -40,6 +40,8 @@ class MockTestStage(m.TestStage): args = ["-foo", "-bar"] + _tmp_args = [] + def __init__(self, config: Config, system: _TestSystem) -> None: self._init(config, system) From b2fe6a54eb651c4e61a5d07e788972aa2145cf5b Mon Sep 17 00:00:00 2001 From: Marcin Zalewski Date: Thu, 9 Feb 2023 14:15:29 -0800 Subject: [PATCH 13/57] Add the missing documentation category to PR label check (#564) Co-authored-by: Marcin Zalewski --- .github/workflows/require-labels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/require-labels.yml b/.github/workflows/require-labels.yml index 4a6fc3b6e..6f1f751d2 100644 --- a/.github/workflows/require-labels.yml +++ b/.github/workflows/require-labels.yml @@ -11,4 +11,4 @@ jobs: with: mode: exactly count: 1 - labels: "category:new-feature, category:improvement, category:bug-fix, category:task" \ No newline at end of file + labels: "category:new-feature, category:improvement, category:bug-fix, category:task, category:documentation" \ No newline at end of file From 659fa8c17350280082febd2c9791fa861adc0ee4 Mon Sep 17 00:00:00 2001 From: OTABI Tomoya Date: Fri, 10 Feb 2023 14:14:44 +0900 Subject: [PATCH 14/57] Update Build.md to add the missing dependency, rust (#565) Signed-off-by: OTABI Tomoya --- BUILD.md | 1 + 1 file changed, 1 insertion(+) diff --git a/BUILD.md b/BUILD.md index 406953fa7..4329cdefa 100644 --- a/BUILD.md +++ b/BUILD.md @@ -189,6 +189,7 @@ in the environment file: - `git` - `make` - `ninja` (this is optional, but produces more informative build output) +- `rust` - `scikit-build` ### OpenBLAS From 64334f005efd54e9293d54ac09b8374d8978af99 Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Mon, 13 Feb 2023 20:04:46 -0800 Subject: [PATCH 15/57] Mappers should skip collective views with no suitable instance (#559) * Mappers should skip collective views with no suitable instance * Assert collect sources contain at least one instance on the requested memory --- src/core/mapping/base_mapper.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/mapping/base_mapper.cc b/src/core/mapping/base_mapper.cc index 0fe6075e9..b692ee9c0 100644 --- a/src/core/mapping/base_mapper.cc +++ b/src/core/mapping/base_mapper.cc @@ -980,6 +980,10 @@ void BaseMapper::legate_select_sources(const MapperContext ctx, for (uint32_t idx = 0; idx < collective_sources.size(); idx++) { std::vector col_instances; collective_sources[idx].find_instances_nearest_memory(destination_memory, col_instances); +#ifdef DEBUG_LEGATE + // there must exist at least one instance in the collective view + assert(!col_instances.empty()); +#endif // we need only first instance if there are several const PhysicalInstance& instance = col_instances[0]; add_instance_to_band_ranking( From 4cd044c2c188401509263122d9ff545b89ee98ea Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Mon, 13 Feb 2023 20:05:43 -0800 Subject: [PATCH 16/57] Bump up the thrust version to 1.17 (#560) --- cmake/versions.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/versions.json b/cmake/versions.json index 02d16cf16..aae9a7ffe 100644 --- a/cmake/versions.json +++ b/cmake/versions.json @@ -1,9 +1,9 @@ { "packages" : { "Thrust" : { - "version" : "1.15.0.0", + "version" : "1.17.0.0", "git_url" : "https://github.com/NVIDIA/thrust.git", - "git_tag" : "1.15.0" + "git_tag" : "1.17.0" } } } From 6d107efd8ca7e84628116e14743ada0247585fca Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 14 Feb 2023 08:48:17 -0800 Subject: [PATCH 17/57] Move RC command line args to env var / settings (#567) * Move legate RC args to env var / settings * review * review --- legate/__init__.py | 2 - legate/args.py | 60 ----- legate/core/runtime.py | 11 +- legate/settings.py | 63 +++++ legate/util/settings.py | 310 ++++++++++++++++++++++++ tests/unit/legate/test_cycle_check.py | 13 +- tests/unit/legate/test_settings.py | 62 +++++ tests/unit/legate/util/test_settings.py | 182 ++++++++++++++ 8 files changed, 632 insertions(+), 71 deletions(-) delete mode 100644 legate/args.py create mode 100644 legate/settings.py create mode 100644 legate/util/settings.py create mode 100644 tests/unit/legate/test_settings.py create mode 100644 tests/unit/legate/util/test_settings.py diff --git a/legate/__init__.py b/legate/__init__.py index e421b48d3..2c9b706ce 100644 --- a/legate/__init__.py +++ b/legate/__init__.py @@ -17,8 +17,6 @@ __path__ = extend_path(__path__, __name__) -from .args import ARGS - from . import _version __version__ = _version.get_versions()["version"] # type: ignore[no-untyped-call] diff --git a/legate/args.py b/legate/args.py deleted file mode 100644 index 2560d06d4..000000000 --- a/legate/args.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2021-2022 NVIDIA Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from __future__ import annotations - -from .util.args import ArgSpec, Argument - -ARGS = [ - Argument( - "consensus", - ArgSpec( - action="store_true", - default=False, - dest="consensus", - help="Turn on consensus match on single node (for testing).", - ), - ), - Argument( - "cycle-check", - ArgSpec( - action="store_true", - default=False, - dest="cycle_check", - help=( - "Check for reference cycles involving RegionField objects on " - "script exit (developer option). When such cycles arise " - "during execution, they stop used RegionFields from getting " - "collected and reused for new Stores, thus increasing memory " - "pressure. By default this check will miss any RegionField " - "cycles the garbage collector collected during execution; " - "run gc.disable() at the beginning of the program to avoid " - "this." - ), - ), - ), - Argument( - "future-leak-check", - ArgSpec( - action="store_true", - default=False, - dest="future_leak_check", - help=( - "Check for reference cycles keeping Future/FutureMap objects " - "alive after Legate runtime exit (developer option). Such " - "leaks can result in Legion runtime shutdown hangs." - ), - ), - ), -] diff --git a/legate/core/runtime.py b/legate/core/runtime.py index aff0c1898..093464a63 100644 --- a/legate/core/runtime.py +++ b/legate/core/runtime.py @@ -26,8 +26,7 @@ from legion_top import add_cleanup_item, top_level -from ..args import ARGS -from ..util.args import parse_library_command_args +from ..settings import settings from . import ffi # Make sure we only have one ffi instance from . import ( Fence, @@ -919,8 +918,6 @@ def __init__(self, core_library: CoreLib) -> None: focus on implementing their domain logic. """ - self._args = parse_library_command_args("legate", ARGS) - # Record whether we need to run finalize tasks # Key off whether we are being loaded in a context or not try: @@ -1005,7 +1002,7 @@ def __init__(self, core_library: CoreLib) -> None: ) self._field_manager_class = ( ConsensusMatchingFieldManager - if self._num_nodes > 1 or self._args.consensus + if self._num_nodes > 1 or settings.consensus() else FieldManager ) self._max_lru_length = int( @@ -1649,7 +1646,7 @@ def raise_exceptions(self) -> None: def _cleanup_legate_runtime() -> None: global runtime - future_leak_check = runtime._args.future_leak_check + future_leak_check = settings.future_leak_check() runtime.destroy() del runtime gc.collect() @@ -1679,7 +1676,7 @@ def __del__(self) -> None: find_cycles(False) -if runtime._args.cycle_check: +if settings.cycle_check(): # The first thing that legion_top does after executing the user script # is to remove the newly created "__main__" module. We intercept this # deletion operation to perform our check. diff --git a/legate/settings.py b/legate/settings.py new file mode 100644 index 000000000..589d3db38 --- /dev/null +++ b/legate/settings.py @@ -0,0 +1,63 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from __future__ import annotations + +from .util.settings import PrioritizedSetting, Settings, convert_bool + +__all__ = ("settings",) + + +class LegateRuntimeSettings(Settings): + + consensus: PrioritizedSetting[bool] = PrioritizedSetting( + "consensus", + "LEGATE_CONSENSUS", + default=False, + convert=convert_bool, + help=""" + Whether to enable consensus match on single node (for testing). + """, + ) + + cycle_check: PrioritizedSetting[bool] = PrioritizedSetting( + "cycle_check", + "LEGATE_CYCLE_CHECK", + default=False, + convert=convert_bool, + help=""" + Whether to check for reference cycles involving RegionField objects on + exit (developer option). When such cycles arise during execution they + stop used RegionFields from being collected and reused for new Stores, + thus increasing memory pressure. By default this check will miss any + RegionField cycles the garbage collector collected during execution. + + Run gc.disable() at the beginning of the program to avoid this. + """, + ) + + future_leak_check: PrioritizedSetting[bool] = PrioritizedSetting( + "future_leak_check", + "LEGATE_FUTURE_LEAK_CHECK", + default=False, + convert=convert_bool, + help=""" + Whether to check for reference cycles keeping Future/FutureMap objects + alive after Legate runtime exit (developer option). Such leaks can + result in Legion runtime shutdown hangs. + """, + ) + + +settings = LegateRuntimeSettings() diff --git a/legate/util/settings.py b/legate/util/settings.py new file mode 100644 index 000000000..c4ef60899 --- /dev/null +++ b/legate/util/settings.py @@ -0,0 +1,310 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +""" Control global configuration options with environment variables. + +Precedence +~~~~~~~~~~ + +Setting values are always looked up in the following prescribed order: + +immediately supplied values + These are values that are passed to the setting: + + .. code-block:: python + + settings.consensus(value) + + If ``value`` is not None, then it will be returned, as-is. Otherwise, if + None is passed, then the setting will continue to look down the search + order for a value. This is useful for passing optional function paramters + that are None by default. If the parameter is passed to the function, then + it will take precedence. + +previously user-set values + If the value is set explicity in code: + + .. code-block:: python + + settings.minified = False + + Then this value will take precedence over other sources. Applications + may use this ability to set values supplied on the command line, so that + they take precedence over environment variables. + +environment variable + Values found in the associated environment variables: + + .. code-block:: sh + + LEGATE_CONSENSUS=yes legate script.py + +local defaults + These are default values defined when accessing the setting: + + .. code-block:: python + + settings.concensus(default=True) + + Local defaults have lower precendence than every other setting mechanism + except global defaults. + +global defaults + These are default values defined by the setting declarations. They have + lower precedence than every other setting mechanism. + +If no value is obtained after searching all of these locations, then a +RuntimeError will be raised. + +""" +from __future__ import annotations + +import os +from typing import Any, Generic, Type, TypeVar, Union + +from typing_extensions import TypeAlias + +__all__ = ( + "convert_str", + "convert_bool", + "convert_str_seq", + "PrioritizedSetting", + "Settings", +) + + +class _Unset: + pass + + +T = TypeVar("T") + + +Unset: TypeAlias = Union[T, Type[_Unset]] + + +def convert_str(value: str) -> str: + """Return a string as-is.""" + return value + + +def convert_bool(value: bool | str) -> bool: + """Convert a string to True or False. + + If a boolean is passed in, it is returned as-is. Otherwise the function + maps the following strings, ignoring case: + + * "yes", "1", "on", "true" -> True + * "no", "0", "off", "false" -> False + + Args: + value (str): + A string value to convert to bool + + Returns: + bool + + Raises: + ValueError + + """ + if isinstance(value, bool): + return value + + val = value.lower() + if val in ("yes", "1", "on", "true"): + return True + if val in ("no", "0", "off", "false"): + return False + + raise ValueError(f"Cannot convert {value} to boolean value") + + +def convert_str_seq( + value: list[str] | tuple[str, ...] | str +) -> tuple[str, ...]: + """Convert a string to a list of strings. + + If a list or tuple is passed in, it is returned as-is. + + Args: + value (seq[str] or str) : + A string to convert to a list of strings + + Returns + list[str] + + Raises: + ValueError + + """ + if isinstance(value, (list, tuple)): + return tuple(value) + + try: + return tuple(value.split(",")) + except Exception: + raise ValueError(f"Cannot convert {value} to list value") + + +class PrioritizedSetting(Generic[T]): + """Return a value for a global setting according to configuration + precedence. + + The following methods are searched in order for the setting: + + 4. immediately supplied values + 3. previously user-set values (e.g. set from command line) + 2. environment variable + 1. local defaults + 0. global defaults + + If a value cannot be determined, a RuntimeError is raised. + + The ``env_var`` argument specifies the name of an environment to check for + setting values, e.g. ``"LEGATE_CHECK_CYCLE"``. + + The optional ``default`` argument specified an implicit default value for + the setting that is returned if no other methods provide a value. + + A ``convert`` agument may be provided to convert values before they are + returned. + """ + + _parent: Settings | None + _user_value: Unset[str | T] + + def __init__( + self, + name: str, + env_var: str | None = None, + default: Unset[T] = _Unset, + convert: Any | None = None, + help: str = "", + ) -> None: + self._convert = convert if convert else convert_str + self._default = default + self._env_var = env_var + self._help = help + self._name = name + self._parent = None + self._user_value = _Unset + + def __call__( + self, value: T | str | None = None, default: Unset[T] = _Unset + ) -> T: + """Return the setting value according to the standard precedence. + + Args: + value (any, optional): + An optional immediate value. If not None, the value will + be converted, then returned. + + default (any, optional): + An optional default value that only takes precendence over + implicit default values specified on the property itself. + + Returns: + str or int or float + + Raises: + RuntimeError + """ + + # 4. immediate values + if value is not None: + return self._convert(value) + + # 3. previously user-set value + if self._user_value is not _Unset: + return self._convert(self._user_value) + + # 2. environment variable + if self._env_var and self._env_var in os.environ: + return self._convert(os.environ[self._env_var]) + + # 1. local defaults + if default is not _Unset: + return self._convert(default) + + # 0. global defaults + if self._default is not _Unset: + return self._convert(self._default) + + raise RuntimeError( + f"No configured value found for setting {self._name!r}" + ) + + def __get__( + self, instance: Any, owner: type[Any] + ) -> PrioritizedSetting[T]: + return self + + def __set__(self, instance: Any, value: str | T) -> None: + self.set_value(value) + + def set_value(self, value: str | T) -> None: + """Specify a value for this setting programmatically. + + A value set this way takes precedence over all other methods except + immediate values. + + Args: + value (str or int or float): + A user-set value for this setting + + Returns: + None + """ + # It is usually not advised to store any data directly on descriptors, + # since they are shared by all instances. But in our case we only ever + # have a single instance of a given settings object. + self._user_value = value + + def unset_value(self) -> None: + """Unset the previous user value such that the priority is reset.""" + self._user_value = _Unset + + @property + def env_var(self) -> str | None: + return self._env_var + + @property + def default(self) -> Unset[T]: + return self._default + + @property + def name(self) -> str: + return self._name + + @property + def help(self) -> str: + return self._help + + @property + def convert_type(self) -> str: + if self._convert is convert_str: + return "str" + if self._convert is convert_bool: + return "bool" + if self._convert is convert_str_seq: + return "tuple[str, ...]" + raise RuntimeError("unreachable") + + +class Settings: + def __init__(self) -> None: + for x in self.__class__.__dict__.values(): + if isinstance(x, PrioritizedSetting): + x._parent = self diff --git a/tests/unit/legate/test_cycle_check.py b/tests/unit/legate/test_cycle_check.py index 5839bd917..5f5961b49 100644 --- a/tests/unit/legate/test_cycle_check.py +++ b/tests/unit/legate/test_cycle_check.py @@ -1,4 +1,4 @@ -# Copyright 2022 NVIDIA Corporation +# Copyright 2022-2023 NVIDIA Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ # limitations under the License. # +import os import subprocess from pathlib import Path @@ -35,8 +36,16 @@ def test_cycle_check(tmp_path: Path) -> None: prog_file = tmp_path / "prog.py" prog_file.write_text(PROG_TEXT) + env = os.environ.copy() + env["LEGATE_CYCLE_CHECK"] = "yes" output = subprocess.check_output( - ["legate", prog_file, "--cpus", "1", "-legate:cycle-check"] + [ + "legate", + prog_file, + "--cpus", + "1", + ], + env=env, ) assert "found cycle!" in output.decode("utf-8") diff --git a/tests/unit/legate/test_settings.py b/tests/unit/legate/test_settings.py new file mode 100644 index 000000000..092229e28 --- /dev/null +++ b/tests/unit/legate/test_settings.py @@ -0,0 +1,62 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from __future__ import annotations + +import pytest + +import legate.settings as m +from legate.util.settings import PrioritizedSetting + +_expected_settings = ( + "consensus", + "cycle_check", + "future_leak_check", +) + + +class TestSettings: + def test_standard_settings(self) -> None: + settings = [ + k + for k, v in m.settings.__class__.__dict__.items() + if isinstance(v, PrioritizedSetting) + ] + assert set(settings) == set(_expected_settings) + + @pytest.mark.parametrize("name", _expected_settings) + def test_prefix(self, name: str) -> None: + ps = getattr(m.settings, name) + assert ps.env_var.startswith("LEGATE_") + + @pytest.mark.parametrize("name", _expected_settings) + def test_parent(self, name: str) -> None: + ps = getattr(m.settings, name) + assert ps._parent == m.settings + + def test_types(self) -> None: + assert m.settings.consensus.convert_type == "bool" + assert m.settings.cycle_check.convert_type == "bool" + assert m.settings.future_leak_check.convert_type == "bool" + + +class TestDefaults: + def test_consensus(self) -> None: + assert m.settings.consensus.default is False + + def test_cycle_check(self) -> None: + assert m.settings.cycle_check.default is False + + def test_future_leak_check(self) -> None: + assert m.settings.future_leak_check.default is False diff --git a/tests/unit/legate/util/test_settings.py b/tests/unit/legate/util/test_settings.py new file mode 100644 index 000000000..071c4df2d --- /dev/null +++ b/tests/unit/legate/util/test_settings.py @@ -0,0 +1,182 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from __future__ import annotations + +import os +from contextlib import contextmanager +from typing import Any, Iterator, Mapping + +import pytest + +import legate.util.settings as m + + +@contextmanager +def envset( + value: Mapping[str, str] | None = None, **kw: Any +) -> Iterator[None]: + old = os.environ.copy() + if value: + os.environ.update(value) + os.environ.update(**kw) + yield + # take care to keep the same actual dict object + os.environ.clear() + os.environ.update(old) + + +class TestConverters: + @pytest.mark.parametrize( + "value", ["Yes", "YES", "yes", "1", "ON", "on", "true", "True", True] + ) + def test_convert_bool(self, value: str) -> None: + assert m.convert_bool(value) + + @pytest.mark.parametrize( + "value", ["No", "NO", "no", "0", "OFF", "off", "false", "False", False] + ) + def test_convert_bool_false(self, value: str) -> None: + assert not m.convert_bool(value) + + @pytest.mark.parametrize("value", [True, False]) + def test_convert_bool_identity(self, value: bool) -> None: + assert m.convert_bool(value) == value + + def test_convert_bool_bad(self) -> None: + with pytest.raises(ValueError): + m.convert_bool("junk") + + +class TestPrioritizedSetting: + def test_env_var_property(self) -> None: + ps: Any = m.PrioritizedSetting("foo", env_var="LEGATE_FOO") + assert ps.env_var == "LEGATE_FOO" + + def test_everything_unset_raises(self) -> None: + ps: Any = m.PrioritizedSetting("foo") + with pytest.raises(RuntimeError): + ps() + + def test_implict_default(self) -> None: + ps: Any = m.PrioritizedSetting("foo", default=10) + assert ps() == 10 + + def test_implict_default_converts(self) -> None: + ps: Any = m.PrioritizedSetting("foo", convert=int, default="10") + assert ps() == 10 + + def test_help(self) -> None: + ps: Any = m.PrioritizedSetting( + "foo", env_var="LEGATE_FOO", default=10, help="bar" + ) + assert ps.help == "bar" + + def test_name(self) -> None: + ps: Any = m.PrioritizedSetting("foo", env_var="LEGATE_FOO", default=10) + assert ps.name == "foo" + + def test_global_default(self) -> None: + ps: Any = m.PrioritizedSetting("foo", env_var="LEGATE_FOO", default=10) + assert ps.default == 10 + assert ps() == 10 + + def test_local_default(self) -> None: + ps: Any = m.PrioritizedSetting("foo", env_var="LEGATE_FOO", default=10) + assert ps.default == 10 + assert ps(default=20) == 20 + + def test_env_var(self) -> None: + with envset(LEGATE_FOO="30"): + ps: Any = m.PrioritizedSetting("foo", env_var="LEGATE_FOO") + assert ps.env_var == "LEGATE_FOO" + assert ps() == "30" + assert ps(default=20) == "30" + + def test_env_var_converts(self) -> None: + with envset(LEGATE_FOO="30"): + ps: Any = m.PrioritizedSetting( + "foo", convert=int, env_var="LEGATE_FOO" + ) + assert ps() == 30 + + def test_user_set(self) -> None: + ps: Any = m.PrioritizedSetting("foo") + ps.set_value(40) + assert ps() == 40 + assert ps(default=20) == 40 + + def test_user_unset(self) -> None: + ps: Any = m.PrioritizedSetting("foo", default=2) + ps.set_value(40) + assert ps() == 40 + ps.unset_value() + assert ps() == 2 + + def test_user_set_converts(self) -> None: + ps: Any = m.PrioritizedSetting("foo", convert=int) + ps.set_value("40") + assert ps() == 40 + + def test_immediate(self) -> None: + ps: Any = m.PrioritizedSetting("foo") + assert ps(50) == 50 + assert ps(50, default=20) == 50 + + def test_immediate_converts(self) -> None: + ps: Any = m.PrioritizedSetting("foo", convert=int) + assert ps("50") == 50 + + def test_precedence(self) -> None: + class FakeSettings: + pass + + ps: Any = m.PrioritizedSetting( + "foo", env_var="LEGATE_FOO", convert=int, default=0 + ) + ps._parent = FakeSettings + + # 0. global default + assert ps() == 0 + + # 1. local default + assert ps(default=10) == 10 + + # 2. environment variable + with envset(LEGATE_FOO="40"): + assert ps() == 40 + assert ps(default=10) == 40 + + # 3. previously user-set value + ps.set_value(60) + assert ps() == 60 + assert ps(default=10) == 60 + + # 4. immediate values + assert ps(70) == 70 + assert ps(70, default=10) == 70 + + def test_descriptors(self) -> None: + class FakeSettings: + foo: Any = m.PrioritizedSetting("foo", env_var="LEGATE_FOO") + bar: Any = m.PrioritizedSetting( + "bar", env_var="LEGATE_BAR", default=10 + ) + + s = FakeSettings() + assert s.foo is FakeSettings.foo + + assert s.bar() == 10 + s.bar = 20 + assert s.bar() == 20 # type: ignore From 2fe300f3d6ca1787027308c8ddb2d1b08820b11a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Feb 2023 09:55:40 -0800 Subject: [PATCH 18/57] [pre-commit.ci] pre-commit autoupdate (#561) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 22.12.0 → 23.1.0](https://github.com/psf/black/compare/22.12.0...23.1.0) - [github.com/pre-commit/mirrors-mypy: v0.991 → v1.0.0](https://github.com/pre-commit/mirrors-mypy/compare/v0.991...v1.0.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- legate/core/_legion/future.py | 2 +- legate/core/_legion/operation.py | 2 +- legate/core/_legion/partition_functor.py | 2 +- legate/core/_legion/region.py | 1 - legate/core/_legion/task.py | 1 - legate/core/context.py | 2 +- legate/core/launcher.py | 12 ++++++------ legate/core/operation.py | 8 ++++---- legate/core/store.py | 2 +- legate/driver/args.py | 1 - legate/driver/config.py | 1 - legate/tester/stages/test_stage.py | 1 - legate/tester/test_system.py | 1 - legate/util/colors.py | 1 - legate/util/fs.py | 1 - scripts/generate-conda-envs.py | 1 - tests/unit/legate/driver/test_command.py | 4 ---- tests/unit/legate/driver/test_config.py | 2 -- tests/unit/legate/driver/test_launcher.py | 3 --- tests/unit/legate/jupyter/test_config.py | 2 -- tests/unit/legate/tester/stages/test_test_stage.py | 1 - tests/unit/legate/tester/test_config.py | 1 - 23 files changed, 17 insertions(+), 39 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1bc88456f..0ffedcd82 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 23.1.0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 @@ -18,7 +18,7 @@ repos: files: \.(cu|cuh|h|cc|inl)$ types_or: [] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v0.991' + rev: 'v1.0.0' hooks: - id: mypy pass_filenames: false diff --git a/legate/core/_legion/future.py b/legate/core/_legion/future.py index f4d98c882..470af4dd0 100644 --- a/legate/core/_legion/future.py +++ b/legate/core/_legion/future.py @@ -386,7 +386,7 @@ def from_dict( num_futures = len(futures) points = ffi.new("legion_domain_point_t[%d]" % num_futures) futures_ = ffi.new("legion_future_t[%d]" % num_futures) - for (i, (point, future)) in enumerate(futures.items()): + for i, (point, future) in enumerate(futures.items()): points[i] = point.raw() futures_[i] = future.handle handle = legion.legion_future_map_construct_from_futures( diff --git a/legate/core/_legion/operation.py b/legate/core/_legion/operation.py index cf13a7bff..95cf96fbb 100644 --- a/legate/core/_legion/operation.py +++ b/legate/core/_legion/operation.py @@ -1309,7 +1309,7 @@ def __init__( mem = legion.legion_memory_query_next(query, mem) legion.legion_memory_query_destroy(query) legion.legion_machine_destroy(machine) - for (sub_region, buf) in shard_local_data.items(): + for sub_region, buf in shard_local_data.items(): if sub_region.parent is not None: assert sub_region.parent.parent is parent legion.legion_index_attach_launcher_attach_array_soa( diff --git a/legate/core/_legion/partition_functor.py b/legate/core/_legion/partition_functor.py index 47eec302d..2f9822441 100644 --- a/legate/core/_legion/partition_functor.py +++ b/legate/core/_legion/partition_functor.py @@ -379,7 +379,7 @@ def partition( assert num_domains <= color_space.get_volume() colors = ffi.new("legion_domain_point_t[%d]" % num_domains) domains = ffi.new("legion_domain_t[%d]" % num_domains) - for (i, (point, rect)) in enumerate(self.domains.items()): + for i, (point, rect) in enumerate(self.domains.items()): colors[i] = point.raw() domains[i] = rect.raw() return legion.legion_index_partition_create_by_domain( diff --git a/legate/core/_legion/region.py b/legate/core/_legion/region.py index a1eaf3cfb..60577ad1d 100644 --- a/legate/core/_legion/region.py +++ b/legate/core/_legion/region.py @@ -28,7 +28,6 @@ class Region: - handle: Any def __init__( diff --git a/legate/core/_legion/task.py b/legate/core/_legion/task.py index 670b2796c..b086523fd 100644 --- a/legate/core/_legion/task.py +++ b/legate/core/_legion/task.py @@ -471,7 +471,6 @@ def launch( class IndexTask(Dispatchable[Union[Future, FutureMap]]): - point_args: Union[list[Any], None] def __init__( diff --git a/legate/core/context.py b/legate/core/context.py index e1aac4536..ca226a647 100644 --- a/legate/core/context.py +++ b/legate/core/context.py @@ -54,7 +54,7 @@ def __call__(self, *args: Any, **kwargs: Any) -> Any: def find_last_user_frame(libname: str) -> str: - for (frame, _) in traceback.walk_stack(None): + for frame, _ in traceback.walk_stack(None): if "__name__" not in frame.f_globals: continue if not any( diff --git a/legate/core/launcher.py b/legate/core/launcher.py index 69d6833c7..5dc8bb34b 100644 --- a/legate/core/launcher.py +++ b/legate/core/launcher.py @@ -928,7 +928,7 @@ def build_task( if self._sharding_space is not None: task.set_sharding_space(self._sharding_space) - for (req, fields) in self._req_analyzer.requirements: + for req, fields in self._req_analyzer.requirements: req.proj.add(task, req, fields, _index_task_calls) for future in self._future_args: task.add_future(future) @@ -937,7 +937,7 @@ def build_task( arrival, wait = runtime.get_barriers(volume) task.add_future(arrival) task.add_future(wait) - for (out_req, fields) in self._out_analyzer.requirements: + for out_req, fields in self._out_analyzer.requirements: out_req.add(task, fields) for comm in self._comms: task.add_point_future(ArgumentMap(future_map=comm)) @@ -966,11 +966,11 @@ def build_single_task(self, argbuf: BufferBuilder) -> SingleTask: tag=self._tag, provenance=self._provenance, ) - for (req, fields) in self._req_analyzer.requirements: + for req, fields in self._req_analyzer.requirements: req.proj.add_single(task, req, fields, _single_task_calls) for future in self._future_args: task.add_future(future) - for (out_req, fields) in self._out_analyzer.requirements: + for out_req, fields in self._out_analyzer.requirements: out_req.add_single(task, fields) if ( not self._has_side_effect @@ -1178,7 +1178,7 @@ def build_copy(self, launch_domain: Rect) -> IndexCopy: def add_requirements( requirements: list[tuple[RegionReq, int]] ) -> None: - for (req, field) in requirements: + for req, field in requirements: req.proj.add(copy, req, field, _index_copy_calls) add_requirements(self._input_reqs.requirements) @@ -1209,7 +1209,7 @@ def build_single_copy(self) -> SingleCopy: def add_requirements( requirements: list[tuple[RegionReq, int]] ) -> None: - for (req, field) in requirements: + for req, field in requirements: req.proj.add_single(copy, req, field, _single_copy_calls) add_requirements(self._input_reqs.requirements) diff --git a/legate/core/operation.py b/legate/core/operation.py index 07738aa51..c5bac7b62 100644 --- a/legate/core/operation.py +++ b/legate/core/operation.py @@ -289,7 +289,7 @@ def capture_traceback(self) -> None: self._tb_repr = capture_traceback_repr() def _add_scalar_args_to_launcher(self, launcher: TaskLauncher) -> None: - for (arg, dtype) in self._scalar_args: + for arg, dtype in self._scalar_args: launcher.add_scalar_arg(arg, dtype) def _demux_scalar_stores_future(self, result: Future) -> None: @@ -604,7 +604,7 @@ def launch(self, strategy: Strategy) -> None: # We update the key partition of a store only when it gets updated store.set_key_partition(store_part.partition) - for ((store, redop), part_symb) in zip( + for (store, redop), part_symb in zip( self._reductions, self._reduction_parts ): req, tag, store_part = self.get_requirement( @@ -618,7 +618,7 @@ def launch(self, strategy: Strategy) -> None: store, req, tag=tag, read_write=can_read_write ) - for (store, part_symb) in zip(self._outputs, self._output_parts): + for store, part_symb in zip(self._outputs, self._output_parts): if not store.unbound: continue fspace = strategy.get_field_space(part_symb) @@ -964,7 +964,7 @@ def launch(self, strategy: Strategy) -> None: else: launcher.add_output(store, req, tag=tag) - for ((store, redop), part_symb) in zip( + for (store, redop), part_symb in zip( self._reductions, self._reduction_parts ): req, tag, store_part = self.get_requirement( diff --git a/legate/core/store.py b/legate/core/store.py index 0d55cbf62..086418503 100644 --- a/legate/core/store.py +++ b/legate/core/store.py @@ -209,7 +209,7 @@ def record_detach(detach: Union[Detach, IndexDetach]) -> None: else field_type ) shard_local_data = {} - for (c, buf) in alloc.shard_local_buffers.items(): + for c, buf in alloc.shard_local_buffers.items(): subregion = alloc.partition.get_child(c) bounds = subregion.index_space.get_bounds() if buf.shape != tuple( diff --git a/legate/driver/args.py b/legate/driver/args.py index 3747bbaac..633439d50 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -54,7 +54,6 @@ # # All of this is somewhat clunky but the best option to provide a good UX. class _LegateArgumentParser(ArgumentParser): - packages = ("legate", "cunumeric") def print_help(self, file: Optional[IO[str]] = None) -> None: diff --git a/legate/driver/config.py b/legate/driver/config.py index 7e7ceb9ae..de0394a7d 100644 --- a/legate/driver/config.py +++ b/legate/driver/config.py @@ -146,7 +146,6 @@ class Other(DataclassMixin): class ConfigProtocol(Protocol): - _args: Namespace argv: ArgList diff --git a/legate/tester/stages/test_stage.py b/legate/tester/stages/test_stage.py index c1c0beb3c..b5a8254ea 100644 --- a/legate/tester/stages/test_stage.py +++ b/legate/tester/stages/test_stage.py @@ -297,7 +297,6 @@ def _init(self, config: Config, system: TestSystem) -> None: def _launch( self, config: Config, system: TestSystem ) -> list[ProcessResult]: - pool = multiprocessing.pool.ThreadPool(self.spec.workers) jobs = [ diff --git a/legate/tester/test_system.py b/legate/tester/test_system.py index 2c4e9949f..9f416782b 100644 --- a/legate/tester/test_system.py +++ b/legate/tester/test_system.py @@ -33,7 +33,6 @@ @dataclass class ProcessResult: - #: The command invovation, including relevant environment vars invocation: str diff --git a/legate/util/colors.py b/legate/util/colors.py index 6c417c221..547f0e015 100644 --- a/legate/util/colors.py +++ b/legate/util/colors.py @@ -94,7 +94,6 @@ def yellow(text: str) -> str: colorama.init() except ImportError: - bright = dim = white = cyan = red = magenta = green = yellow = _text # ref: https://stackoverflow.com/a/14693789 diff --git a/legate/util/fs.py b/legate/util/fs.py index 4b7465799..ffc5f5ab8 100644 --- a/legate/util/fs.py +++ b/legate/util/fs.py @@ -114,7 +114,6 @@ def get_legate_build_dir(legate_dir: Path) -> Path | None: return None for f in skbuild_dir.iterdir(): - # If using a local scikit-build dir at _skbuild//cmake-build, # read Legion_BINARY_DIR and Legion_SOURCE_DIR from CMakeCache.txt diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 361f35149..4f6954ffe 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -314,7 +314,6 @@ def __call__(self, parser, namespace, values, option_string): if __name__ == "__main__": - import sys parser = ArgumentParser() diff --git a/tests/unit/legate/driver/test_command.py b/tests/unit/legate/driver/test_command.py index 28ace41fc..6f05a44f1 100644 --- a/tests/unit/legate/driver/test_command.py +++ b/tests/unit/legate/driver/test_command.py @@ -193,7 +193,6 @@ def test_ranks_bad( class Test_cmd_gdb: - MULTI_RANK_WARN = ( "WARNING: Legate does not support gdb for multi-rank runs" ) @@ -231,7 +230,6 @@ def test_with_option_multi_rank( class Test_cmd_cuda_gdb: - MULTI_RANK_WARN = ( "WARNING: Legate does not support cuda-gdb for multi-rank runs" ) @@ -653,7 +651,6 @@ def test_default(self, genobjs: GenObjs) -> None: class Test_cmd_kthreads: - DBG_OPTS = ("--gdb", "--cuda-gdb", "--freeze-on-error") def test_default(self, genobjs: GenObjs) -> None: @@ -1211,7 +1208,6 @@ def test_basic(self, genobjs: GenObjs, value: str) -> None: class Test_cmd_user_opts: - USER_OPTS: tuple[list[str], ...] = ( [], ["foo"], diff --git a/tests/unit/legate/driver/test_config.py b/tests/unit/legate/driver/test_config.py index 168d248f0..ec0f7d48d 100644 --- a/tests/unit/legate/driver/test_config.py +++ b/tests/unit/legate/driver/test_config.py @@ -272,7 +272,6 @@ def test_mixin(self) -> None: class TestConfig: def test_default_init(self) -> None: - # Note this test does not clear the environment. Default values from # the defaults module can depend on the environment, but what matters # is that the generated config matches those values, whatever they are. @@ -349,7 +348,6 @@ def test_color_arg(self) -> None: assert colors.ENABLED is True def test_arg_conversions(self, mocker: MockerFixture) -> None: - # This is kind of a dumb short-cut test, but if we believe that # object_to_dataclass works as advertised, then this test ensures that # it is being used for all the sub-configs that it should be used for diff --git a/tests/unit/legate/driver/test_launcher.py b/tests/unit/legate/driver/test_launcher.py index f9a1b9d1a..d2a183d27 100644 --- a/tests/unit/legate/driver/test_launcher.py +++ b/tests/unit/legate/driver/test_launcher.py @@ -421,7 +421,6 @@ def test_multi_rank_launcher_extra_ignored( class TestMPILauncher: - XARGS1 = ( () + ("-x", "DEFAULTS_PATH") @@ -536,7 +535,6 @@ def test_multi_rank_launcher_extra( genconfig: GenConfig, rank_var: str, ) -> None: - for name in m.RANK_ENV_VARS: monkeypatch.delenv(name, raising=False) monkeypatch.setenv(name, "123") @@ -633,7 +631,6 @@ def test_multi_rank_launcher_extra( genconfig: GenConfig, rank_var: str, ) -> None: - for name in m.RANK_ENV_VARS: monkeypatch.delenv(name, raising=False) monkeypatch.setenv(name, "123") diff --git a/tests/unit/legate/jupyter/test_config.py b/tests/unit/legate/jupyter/test_config.py index d1c425237..d0e44aa33 100644 --- a/tests/unit/legate/jupyter/test_config.py +++ b/tests/unit/legate/jupyter/test_config.py @@ -41,7 +41,6 @@ def test_mixin(self) -> None: class TestConfig: def test_default_init(self) -> None: - # Note this test does not clear the environment. Default values from # the defaults module can depend on the environment, but what matters # is that the generated config matches those values, whatever they are. @@ -120,7 +119,6 @@ def test_color_arg(self) -> None: assert colors.ENABLED is True def test_arg_conversions(self, mocker: MockerFixture) -> None: - # This is kind of a dumb short-cut test, but if we believe that # object_to_dataclass works as advertised, then this test ensures that # it is being used for all the sub-configs that it should be used for diff --git a/tests/unit/legate/tester/stages/test_test_stage.py b/tests/unit/legate/tester/stages/test_test_stage.py index fe075c685..a8831ce61 100644 --- a/tests/unit/legate/tester/stages/test_test_stage.py +++ b/tests/unit/legate/tester/stages/test_test_stage.py @@ -33,7 +33,6 @@ class MockTestStage(m.TestStage): - kind: FeatureType = "eager" name = "mock" diff --git a/tests/unit/legate/tester/test_config.py b/tests/unit/legate/tester/test_config.py index ac7b30f07..e4016f5d8 100644 --- a/tests/unit/legate/tester/test_config.py +++ b/tests/unit/legate/tester/test_config.py @@ -100,7 +100,6 @@ def test_env_features( @pytest.mark.parametrize("feature", FEATURES) def test_cmd_features(self, feature: str) -> None: - # test a single value c = m.Config(["test.py", "--use", feature]) assert set(c.features) == {feature} From ef5363c579132499c20ebc8e30fab9bc1a105e37 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 14 Feb 2023 10:59:49 -0800 Subject: [PATCH 19/57] don't use sys.argv for plain python init (#569) --- legate/core/__init__.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/legate/core/__init__.py b/legate/core/__init__.py index 7ca864b6c..8a278ed92 100644 --- a/legate/core/__init__.py +++ b/legate/core/__init__.py @@ -24,15 +24,7 @@ from ..driver.main import prepare_driver, CanonicalDriver import atexit, os, shlex, sys - # A little explanation. We want to encourage configuration options be - # passed via LEGATE_CONFIG, in order to be considerate to user scripts. - # But we still need to accept actual command line args for comaptibility, - # and those should also take precedences. Here we splice the options from - # LEGATE_CONFIG in before sys.argv, and take advantage of the fact that if - # there are any options repeated in both places, argparse will use the - # latter (i.e. the actual command line provided ones). - env_args = shlex.split(os.environ.get("LEGATE_CONFIG", "")) - argv = ["legate"] + env_args + sys.argv + argv = ["legate"] + shlex.split(os.environ.get("LEGATE_CONFIG", "")) driver = prepare_driver(argv, CanonicalDriver) From 0f45d3a11b8657068fab5e6216835ea840500fbe Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 14 Feb 2023 15:46:15 -0800 Subject: [PATCH 20/57] Document DeferredBuffer.destroy() lifetime issues in CUDA tasks (#566) --- src/core/cuda/stream_pool.h | 2 ++ src/core/data/buffer.h | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/core/cuda/stream_pool.h b/src/core/cuda/stream_pool.h index e2eeb86ee..937556577 100644 --- a/src/core/cuda/stream_pool.h +++ b/src/core/cuda/stream_pool.h @@ -58,6 +58,8 @@ struct StreamPool { private: // For now we keep only one stream in the pool + // TODO: If this ever changes, the use of non-stream-ordered `DeferredBuffer`s + // in `core/data/buffer.h` will no longer be safe. std::unique_ptr cached_stream_{nullptr}; }; diff --git a/src/core/data/buffer.h b/src/core/data/buffer.h index 91550f69d..8c5a01b6c 100644 --- a/src/core/data/buffer.h +++ b/src/core/data/buffer.h @@ -25,6 +25,23 @@ namespace legate { template using Buffer = Legion::DeferredBuffer; +// Note on using temporary buffers in CUDA tasks: +// We use Legion `DeferredBuffer`s, whose lifetime is not connected with the CUDA stream(s) used to +// launch kernels. The buffer is allocated immediately at the point when `create_buffer` called, +// whereas the kernel that uses it is placed on a stream, and may run at a later point. Normally +// `DeferredBuffer`s are deallocated automatically by Legion once all the kernels launched in the +// task are complete. However, `DeferredBuffer`s can also be deallocated immediately using +// `destroy()`, which is useful for operations that want to deallocate intermediate memory as soon +// as possible. This deallocation is not synchronized with the task stream, i.e. it may happen +// before a kernel which uses the buffer has actually completed. This is safe as long as we use the +// same stream on all GPU tasks running on the same device (which is guaranteed by the current +// implementation of `get_cached_stream()`), because then all the actual uses of the buffer are done +// in order on the one stream. It is important that all library CUDA code uses +// `get_cached_stream()`, and all CUDA operations (including library calls) are enqueued on that +// stream exclusively. This analysis additionally assumes that no code outside of Legate is +// concurrently allocating from the eager pool, and that it's OK for kernels to access a buffer even +// after it's technically been deallocated. + template Buffer create_buffer(const Legion::Point& extents, Legion::Memory::Kind kind = Legion::Memory::Kind::NO_MEMKIND, From 0083721816c617e6e486516bee3bac35bfac473c Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Wed, 15 Feb 2023 14:50:57 -0800 Subject: [PATCH 21/57] Updates for cmd opts -> env vars (#572) * remove cmd help for libraries * switch to use CUNUMERIC_TEST env var * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * remove unused parse_library_command_args * explicit CUNUMERIC_TEST=0 for eager stage --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- legate/driver/args.py | 54 +------- legate/settings.py | 1 - legate/tester/stages/_linux/cpu.py | 8 +- legate/tester/stages/_linux/eager.py | 11 +- legate/tester/stages/_linux/gpu.py | 6 +- legate/tester/stages/_linux/omp.py | 8 +- legate/tester/stages/_osx/cpu.py | 8 +- legate/tester/stages/_osx/eager.py | 11 +- legate/tester/stages/_osx/gpu.py | 8 +- legate/tester/stages/_osx/omp.py | 8 +- legate/tester/stages/test_stage.py | 7 -- legate/tester/stages/util.py | 13 +- legate/util/args.py | 67 ---------- .../legate/tester/stages/_linux/test_cpu.py | 14 +-- .../legate/tester/stages/_linux/test_eager.py | 1 + .../legate/tester/stages/_linux/test_gpu.py | 4 +- .../legate/tester/stages/_linux/test_omp.py | 14 +-- .../legate/tester/stages/test_test_stage.py | 2 - tests/unit/legate/util/test_args.py | 118 +----------------- 19 files changed, 56 insertions(+), 307 deletions(-) diff --git a/legate/driver/args.py b/legate/driver/args.py index 633439d50..58a9bf5cc 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -17,7 +17,6 @@ from __future__ import annotations from argparse import REMAINDER, ArgumentDefaultsHelpFormatter, ArgumentParser -from typing import IO, Optional from ..util.shared_args import ( CPUS, @@ -41,58 +40,7 @@ __all__ = ("parser",) -# We want to provide information about library-specific command line options -# for legate and cunumeric, etc. if they are installed. But we want to avoid -# importing those packages under normal circumstances. This argument parser -# subclass overrides the standard print_help method to attempt to import -# specified packages *only* when printing help output. Additionally: -# -# - names of downstream packages must be configured on the packages class attr -# - downstream packages must expose a .ARGS attr with argparse args -# - .ARGS must be plain-python importable if the environment variable -# _LEGATE_PROJECT_HELP_ARGS_ is set to "1" -# -# All of this is somewhat clunky but the best option to provide a good UX. -class _LegateArgumentParser(ArgumentParser): - packages = ("legate", "cunumeric") - - def print_help(self, file: Optional[IO[str]] = None) -> None: - import importlib - import os - from argparse import SUPPRESS - - os.environ["_LEGATE_PROJECT_HELP_ARGS_"] = "1" - - super().print_help(file) - - helps = [] - - for pkg_name in self.packages: - try: - ARGS = importlib.import_module(pkg_name).ARGS - parser = ArgumentParser( - prog=pkg_name, - add_help=False, - allow_abbrev=False, - usage=SUPPRESS, - ) - - for arg in ARGS: - argname = f"-{pkg_name}:{arg.name}" - parser.add_argument(argname, **arg.kwargs) - - helps.append((pkg_name, parser.format_help())) - - except Exception: - pass - - if helps: - print("\nLibrary-specific options\n------------------------\n") - for pkg_name, help in helps: - print(f"{pkg_name} library {help}") - - -parser = _LegateArgumentParser( +parser = ArgumentParser( description="Legate Driver", allow_abbrev=False, formatter_class=ArgumentDefaultsHelpFormatter, diff --git a/legate/settings.py b/legate/settings.py index 589d3db38..c3b89ece0 100644 --- a/legate/settings.py +++ b/legate/settings.py @@ -20,7 +20,6 @@ class LegateRuntimeSettings(Settings): - consensus: PrioritizedSetting[bool] = PrioritizedSetting( "consensus", "LEGATE_CONSENSUS", diff --git a/legate/tester/stages/_linux/cpu.py b/legate/tester/stages/_linux/cpu.py index ef5b2c0f4..8c17343c7 100644 --- a/legate/tester/stages/_linux/cpu.py +++ b/legate/tester/stages/_linux/cpu.py @@ -19,7 +19,7 @@ from ..test_stage import TestStage from ..util import ( - CUNUMERIC_TEST_ARG, + CUNUMERIC_TEST_ENV, UNPIN_ENV, Shard, StageSpec, @@ -50,13 +50,13 @@ class CPU(TestStage): args: ArgList = [] - _tmp_args = [CUNUMERIC_TEST_ARG] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - return {} if config.cpu_pin == "strict" else dict(UNPIN_ENV) + env = {} if config.cpu_pin == "strict" else dict(UNPIN_ENV) + env.update(CUNUMERIC_TEST_ENV) + return env def shard_args(self, shard: Shard, config: Config) -> ArgList: args = [ diff --git a/legate/tester/stages/_linux/eager.py b/legate/tester/stages/_linux/eager.py index cd11567aa..12a19c24b 100644 --- a/legate/tester/stages/_linux/eager.py +++ b/legate/tester/stages/_linux/eager.py @@ -17,7 +17,7 @@ from typing import TYPE_CHECKING from ..test_stage import TestStage -from ..util import Shard, StageSpec, adjust_workers +from ..util import EAGER_ENV, Shard, StageSpec, adjust_workers if TYPE_CHECKING: from ....util.types import ArgList, EnvDict @@ -43,18 +43,11 @@ class Eager(TestStage): args: ArgList = [] - _tmp_args: ArgList = [] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - # Raise min chunk sizes for deferred codepaths to force eager execution - env = { - "CUNUMERIC_MIN_CPU_CHUNK": "2000000000", - "CUNUMERIC_MIN_OMP_CHUNK": "2000000000", - "CUNUMERIC_MIN_GPU_CHUNK": "2000000000", - } + env = dict(EAGER_ENV) return env def shard_args(self, shard: Shard, config: Config) -> ArgList: diff --git a/legate/tester/stages/_linux/gpu.py b/legate/tester/stages/_linux/gpu.py index a54db7299..751118dcf 100644 --- a/legate/tester/stages/_linux/gpu.py +++ b/legate/tester/stages/_linux/gpu.py @@ -18,7 +18,7 @@ from typing import TYPE_CHECKING from ..test_stage import TestStage -from ..util import CUNUMERIC_TEST_ARG, Shard, StageSpec, adjust_workers +from ..util import CUNUMERIC_TEST_ENV, Shard, StageSpec, adjust_workers if TYPE_CHECKING: from ....util.types import ArgList, EnvDict @@ -46,13 +46,11 @@ class GPU(TestStage): args: ArgList = [] - _tmp_args = [CUNUMERIC_TEST_ARG] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - return {} + return dict(CUNUMERIC_TEST_ENV) def delay(self, shard: Shard, config: Config, system: TestSystem) -> None: time.sleep(config.gpu_delay / 1000) diff --git a/legate/tester/stages/_linux/omp.py b/legate/tester/stages/_linux/omp.py index fb54c3b12..b5ee8a1a7 100644 --- a/legate/tester/stages/_linux/omp.py +++ b/legate/tester/stages/_linux/omp.py @@ -19,7 +19,7 @@ from ..test_stage import TestStage from ..util import ( - CUNUMERIC_TEST_ARG, + CUNUMERIC_TEST_ENV, UNPIN_ENV, Shard, StageSpec, @@ -50,13 +50,13 @@ class OMP(TestStage): args: ArgList = [] - _tmp_args = [CUNUMERIC_TEST_ARG] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - return {} if config.cpu_pin == "strict" else dict(UNPIN_ENV) + env = {} if config.cpu_pin == "strict" else dict(UNPIN_ENV) + env.update(CUNUMERIC_TEST_ENV) + return env def shard_args(self, shard: Shard, config: Config) -> ArgList: args = [ diff --git a/legate/tester/stages/_osx/cpu.py b/legate/tester/stages/_osx/cpu.py index 7e4b015a0..e911892de 100644 --- a/legate/tester/stages/_osx/cpu.py +++ b/legate/tester/stages/_osx/cpu.py @@ -18,7 +18,7 @@ from ..test_stage import TestStage from ..util import ( - CUNUMERIC_TEST_ARG, + CUNUMERIC_TEST_ENV, UNPIN_ENV, Shard, StageSpec, @@ -49,13 +49,13 @@ class CPU(TestStage): args: ArgList = [] - _tmp_args = [CUNUMERIC_TEST_ARG] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - return UNPIN_ENV + env = dict(UNPIN_ENV) + env.update(CUNUMERIC_TEST_ENV) + return env def shard_args(self, shard: Shard, config: Config) -> ArgList: return ["--cpus", str(config.cpus)] diff --git a/legate/tester/stages/_osx/eager.py b/legate/tester/stages/_osx/eager.py index 7b3f2d963..4cb0be16b 100644 --- a/legate/tester/stages/_osx/eager.py +++ b/legate/tester/stages/_osx/eager.py @@ -17,7 +17,7 @@ from typing import TYPE_CHECKING from ..test_stage import TestStage -from ..util import UNPIN_ENV, Shard, StageSpec, adjust_workers +from ..util import EAGER_ENV, UNPIN_ENV, Shard, StageSpec, adjust_workers if TYPE_CHECKING: from ....util.types import ArgList, EnvDict @@ -43,18 +43,11 @@ class Eager(TestStage): args: ArgList = [] - _tmp_args = [] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - # Raise min chunk sizes for deferred codepaths to force eager execution - env = { - "CUNUMERIC_MIN_CPU_CHUNK": "2000000000", - "CUNUMERIC_MIN_OMP_CHUNK": "2000000000", - "CUNUMERIC_MIN_GPU_CHUNK": "2000000000", - } + env = dict(EAGER_ENV) env.update(UNPIN_ENV) return env diff --git a/legate/tester/stages/_osx/gpu.py b/legate/tester/stages/_osx/gpu.py index cbe678330..1e54ba737 100644 --- a/legate/tester/stages/_osx/gpu.py +++ b/legate/tester/stages/_osx/gpu.py @@ -18,7 +18,7 @@ from typing import TYPE_CHECKING from ..test_stage import TestStage -from ..util import CUNUMERIC_TEST_ARG, UNPIN_ENV, Shard +from ..util import CUNUMERIC_TEST_ENV, UNPIN_ENV, Shard if TYPE_CHECKING: from ....util.types import ArgList, EnvDict @@ -44,13 +44,13 @@ class GPU(TestStage): args: ArgList = [] - _tmp_args = [CUNUMERIC_TEST_ARG] - def __init__(self, config: Config, system: TestSystem) -> None: raise RuntimeError("GPU test are not supported on OSX") def env(self, config: Config, system: TestSystem) -> EnvDict: - return UNPIN_ENV + env = dict(UNPIN_ENV) + env.update(CUNUMERIC_TEST_ENV) + return env def delay(self, shard: Shard, config: Config, system: TestSystem) -> None: time.sleep(config.gpu_delay / 1000) diff --git a/legate/tester/stages/_osx/omp.py b/legate/tester/stages/_osx/omp.py index ca8d19e2c..1d1a8d24b 100644 --- a/legate/tester/stages/_osx/omp.py +++ b/legate/tester/stages/_osx/omp.py @@ -18,7 +18,7 @@ from ..test_stage import TestStage from ..util import ( - CUNUMERIC_TEST_ARG, + CUNUMERIC_TEST_ENV, UNPIN_ENV, Shard, StageSpec, @@ -49,13 +49,13 @@ class OMP(TestStage): args: ArgList = [] - _tmp_args = [CUNUMERIC_TEST_ARG] - def __init__(self, config: Config, system: TestSystem) -> None: self._init(config, system) def env(self, config: Config, system: TestSystem) -> EnvDict: - return UNPIN_ENV + env = dict(UNPIN_ENV) + env.update(CUNUMERIC_TEST_ENV) + return env def shard_args(self, shard: Shard, config: Config) -> ArgList: return [ diff --git a/legate/tester/stages/test_stage.py b/legate/tester/stages/test_stage.py index b5a8254ea..e9080394c 100644 --- a/legate/tester/stages/test_stage.py +++ b/legate/tester/stages/test_stage.py @@ -57,12 +57,6 @@ class TestStage(Protocol): #: Any fixed stage-specific command-line args to pass args: ArgList - # This can go away when/if "-cunumeric:test" is replaced by an env var. - # The issue is that currently the args above are all otherwise legate - # args that must appear before the script path, but "-cunumeric:test" is - # not a legate arg, so it cannot go there. - _tmp_args: ArgList - # --- Protocol methods def __init__(self, config: Config, system: TestSystem) -> None: @@ -268,7 +262,6 @@ def run( + [str(test_path)] + file_args + config.extra_args - + self._tmp_args ) if custom_args: diff --git a/legate/tester/stages/util.py b/legate/tester/stages/util.py index 27d53bbd1..fb38d77c1 100644 --- a/legate/tester/stages/util.py +++ b/legate/tester/stages/util.py @@ -25,10 +25,19 @@ from ..logger import LOG from ..test_system import ProcessResult -CUNUMERIC_TEST_ARG = "-cunumeric:test" - UNPIN_ENV = {"REALM_SYNTHETIC_CORE_MAP": ""} +CUNUMERIC_TEST_ENV = {"CUNUMERIC_TEST": "1"} + +# Raise min chunk sizes for deferred codepaths to force eager execution +EAGER_ENV = { + "CUNUMERIC_TEST": "0", + "CUNUMERIC_MIN_CPU_CHUNK": "2000000000", + "CUNUMERIC_MIN_OMP_CHUNK": "2000000000", + "CUNUMERIC_MIN_GPU_CHUNK": "2000000000", +} + + Shard: TypeAlias = Tuple[int, ...] diff --git a/legate/util/args.py b/legate/util/args.py index 4485d6db2..d23dda932 100644 --- a/legate/util/args.py +++ b/legate/util/args.py @@ -14,9 +14,6 @@ # from __future__ import annotations -import re -import sys -import warnings from argparse import Action, ArgumentParser, Namespace from dataclasses import dataclass, fields from typing import ( @@ -144,67 +141,3 @@ def __call__( items.append(values) # removing any duplicates before storing setattr(namespace, self.dest, list(set(items))) - - -def parse_library_command_args( - libname: str, args: Iterable[Argument] -) -> Namespace: - """ """ - if not libname.isidentifier(): - raise ValueError( - f"Invalid library {libname!r} for command line arguments" - ) - - parser = ArgumentParser( - prog=f"<{libname} program>", add_help=False, allow_abbrev=False - ) - - # Some explanation is in order. Argparse treats arguments with a single - # dash differently, e.g. "-xyz" is interpreted as "-x -y -z". This can - # cause confusion and clashes when there are multiple single-dash args - # with identical prefixes. TLDR; we want "-legate:foo" to behave just - # as if it was "--legate:foo". In order to do this, we configure a parser - # for "long argumens" and then munge the values in sys.argv to update - # any "short prefix" arguments to be "long prefix" arguments first, before - # parsing. We also take care to update any output. The alternative here - # would be to abandon argparse entirely, and parse sys.argv manually. - # - # ref: https://github.com/nv-legate/legate.core/issues/415 - - short_prefix = f"-{libname}:" - long_prefix = f"-{short_prefix}" - - argnames = [arg.name for arg in args] - - for arg in args: - argname = f"{long_prefix}{arg.name}" - parser.add_argument(argname, **arg.kwargs) - - has_custom_help = "help" in argnames - - if f"{short_prefix}help" in sys.argv and not has_custom_help: - help_string = parser.format_help() - - # this is a little sloppy but should suffice in practice - print(help_string.replace(long_prefix, short_prefix)) - - sys.exit() - - # convert any short-prefix args to be long-prefix - sys.argv = [re.sub(f"^{short_prefix}", long_prefix, x) for x in sys.argv] - - args, extra = parser.parse_known_args() - - # put any unconsumed args back they way they were - extra = [re.sub(f"^{long_prefix}", short_prefix, x) for x in extra] - - for item in extra: - if item.startswith(short_prefix): - warnings.warn( - f"Unrecognized argument {item!r} for {libname} (passed on as-is)" # noqa: E501 - ) - break - - sys.argv = sys.argv[:1] + extra - - return args diff --git a/tests/unit/legate/tester/stages/_linux/test_cpu.py b/tests/unit/legate/tester/stages/_linux/test_cpu.py index 66b73105b..c4394af14 100644 --- a/tests/unit/legate/tester/stages/_linux/test_cpu.py +++ b/tests/unit/legate/tester/stages/_linux/test_cpu.py @@ -21,10 +21,13 @@ from legate.tester.config import Config from legate.tester.stages._linux import cpu as m -from legate.tester.stages.util import UNPIN_ENV +from legate.tester.stages.util import CUNUMERIC_TEST_ENV, UNPIN_ENV from .. import FakeSystem +unpin_and_test = dict(UNPIN_ENV) +unpin_and_test.update(CUNUMERIC_TEST_ENV) + def test_default() -> None: c = Config([]) @@ -32,8 +35,7 @@ def test_default() -> None: stage = m.CPU(c, s) assert stage.kind == "cpus" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == UNPIN_ENV + assert stage.env(c, s) == unpin_and_test assert stage.spec.workers > 0 shard = (1, 2, 3) @@ -46,8 +48,7 @@ def test_cpu_pin_strict() -> None: stage = m.CPU(c, s) assert stage.kind == "cpus" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == {} + assert stage.env(c, s) == CUNUMERIC_TEST_ENV assert stage.spec.workers > 0 shard = (1, 2, 3) @@ -60,8 +61,7 @@ def test_cpu_pin_none() -> None: stage = m.CPU(c, s) assert stage.kind == "cpus" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == UNPIN_ENV + assert stage.env(c, s) == unpin_and_test assert stage.spec.workers > 0 shard = (1, 2, 3) diff --git a/tests/unit/legate/tester/stages/_linux/test_eager.py b/tests/unit/legate/tester/stages/_linux/test_eager.py index eb8c48629..477a4e54d 100644 --- a/tests/unit/legate/tester/stages/_linux/test_eager.py +++ b/tests/unit/legate/tester/stages/_linux/test_eager.py @@ -32,6 +32,7 @@ def test_default() -> None: assert stage.kind == "eager" assert stage.args == [] assert stage.env(c, s) == { + "CUNUMERIC_TEST": "0", "CUNUMERIC_MIN_CPU_CHUNK": "2000000000", "CUNUMERIC_MIN_OMP_CHUNK": "2000000000", "CUNUMERIC_MIN_GPU_CHUNK": "2000000000", diff --git a/tests/unit/legate/tester/stages/_linux/test_gpu.py b/tests/unit/legate/tester/stages/_linux/test_gpu.py index 2946bb7dc..8e7d7e234 100644 --- a/tests/unit/legate/tester/stages/_linux/test_gpu.py +++ b/tests/unit/legate/tester/stages/_linux/test_gpu.py @@ -21,6 +21,7 @@ from legate.tester.config import Config from legate.tester.stages._linux import gpu as m +from legate.tester.stages.util import CUNUMERIC_TEST_ENV from .. import FakeSystem @@ -31,8 +32,7 @@ def test_default() -> None: stage = m.GPU(c, s) assert stage.kind == "cuda" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == {} + assert stage.env(c, s) == CUNUMERIC_TEST_ENV assert stage.spec.workers > 0 diff --git a/tests/unit/legate/tester/stages/_linux/test_omp.py b/tests/unit/legate/tester/stages/_linux/test_omp.py index 3e4ffdc4d..66cdca5c9 100644 --- a/tests/unit/legate/tester/stages/_linux/test_omp.py +++ b/tests/unit/legate/tester/stages/_linux/test_omp.py @@ -21,10 +21,13 @@ from legate.tester.config import Config from legate.tester.stages._linux import omp as m -from legate.tester.stages.util import UNPIN_ENV +from legate.tester.stages.util import CUNUMERIC_TEST_ENV, UNPIN_ENV from .. import FakeSystem +unpin_and_test = dict(UNPIN_ENV) +unpin_and_test.update(CUNUMERIC_TEST_ENV) + def test_default() -> None: c = Config([]) @@ -32,8 +35,7 @@ def test_default() -> None: stage = m.OMP(c, s) assert stage.kind == "openmp" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == UNPIN_ENV + assert stage.env(c, s) == unpin_and_test assert stage.spec.workers > 0 shard = (1, 2, 3) @@ -46,8 +48,7 @@ def test_cpu_pin_strict() -> None: stage = m.OMP(c, s) assert stage.kind == "openmp" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == {} + assert stage.env(c, s) == CUNUMERIC_TEST_ENV assert stage.spec.workers > 0 shard = (1, 2, 3) @@ -60,8 +61,7 @@ def test_cpu_pin_none() -> None: stage = m.OMP(c, s) assert stage.kind == "openmp" assert stage.args == [] - assert stage._tmp_args == ["-cunumeric:test"] - assert stage.env(c, s) == UNPIN_ENV + assert stage.env(c, s) == unpin_and_test assert stage.spec.workers > 0 shard = (1, 2, 3) diff --git a/tests/unit/legate/tester/stages/test_test_stage.py b/tests/unit/legate/tester/stages/test_test_stage.py index a8831ce61..d37363abb 100644 --- a/tests/unit/legate/tester/stages/test_test_stage.py +++ b/tests/unit/legate/tester/stages/test_test_stage.py @@ -39,8 +39,6 @@ class MockTestStage(m.TestStage): args = ["-foo", "-bar"] - _tmp_args = [] - def __init__(self, config: Config, system: _TestSystem) -> None: self._init(config, system) diff --git a/tests/unit/legate/util/test_args.py b/tests/unit/legate/util/test_args.py index 190ff3c6b..77de6ed11 100644 --- a/tests/unit/legate/util/test_args.py +++ b/tests/unit/legate/util/test_args.py @@ -22,7 +22,7 @@ import legate.util.args as m -from ...util import Capsys, powerset +from ...util import powerset T = TypeVar("T") @@ -101,121 +101,5 @@ def test_entries() -> None: assert set(m.entries(_TestObj())) == {("a", 10), ("c", "foo")} -class Test_parse_library_command_args: - @pytest.mark.parametrize("name", ("1foo", "a.b", "a/b", "a[", "a(")) - def test_bad_libname(self, name: str) -> None: - with pytest.raises(ValueError): - m.parse_library_command_args(name, []) - - def test_default_help( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:help"]) - with pytest.raises(SystemExit) as e: - m.parse_library_command_args("foo", []) - assert e.value.code is None - out, err = capsys.readouterr() - assert out.startswith("usage: ") - - def test_default_help_precedence( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:help", "-foo:bar"]) - args = [m.Argument("bar", m.ArgSpec(dest="bar"))] - with pytest.raises(SystemExit) as e: - m.parse_library_command_args("foo", args) - assert e.value.code is None - out, err = capsys.readouterr() - assert out.startswith("usage: ") - - def test_default_help_patches_short_args( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:help", "-foo:bar"]) - args = [m.Argument("bar", m.ArgSpec(dest="bar"))] - with pytest.raises(SystemExit) as e: - m.parse_library_command_args("foo", args) - assert e.value.code is None - out, err = capsys.readouterr() - assert out.startswith("usage: ") - assert "-foo:bar" in out - assert "--foo:bar" not in out - - def test_help_override( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:help"]) - args = [ - m.Argument("help", m.ArgSpec(action="store_true", dest="help")) - ] - ns = m.parse_library_command_args("foo", args) - out, err = capsys.readouterr() - assert out == "" - assert vars(ns) == {"help": True} - assert sys.argv == ["app"] - - def test_basic( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:bar", "-foo:quux", "1"]) - args = [ - m.Argument("bar", m.ArgSpec(action="store_true", dest="bar")), - m.Argument( - "quux", m.ArgSpec(dest="quux", action="store", type=int) - ), - ] - ns = m.parse_library_command_args("foo", args) - out, err = capsys.readouterr() - assert out == "" - assert vars(ns) == {"bar": True, "quux": 1} - assert sys.argv == ["app"] - - def test_extra_args_passed_on( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:bar", "--extra", "1"]) - args = [m.Argument("bar", m.ArgSpec(action="store_true", dest="bar"))] - ns = m.parse_library_command_args("foo", args) - out, err = capsys.readouterr() - assert out == "" - assert vars(ns) == {"bar": True} - assert sys.argv == ["app", "--extra", "1"] - - def test_unrecognized_libname_arg( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr("sys.argv", ["app", "-foo:bar", "-foo:baz"]) - with pytest.warns(UserWarning) as record: - ns = m.parse_library_command_args("foo", []) - out, err = capsys.readouterr() - assert out == "" - assert vars(ns) == {} - assert sys.argv == ["app", "-foo:bar", "-foo:baz"] - - # issues one warning for the first encountered - assert len(record) == 1 - assert isinstance(record[0].message, Warning) - assert ( - record[0].message.args[0] - == "Unrecognized argument '-foo:bar' for foo (passed on as-is)" - ) - assert out == "" - assert vars(ns) == {} - assert sys.argv == ["app", "-foo:bar", "-foo:baz"] - - def test_no_prefix_conflict( - self, monkeypatch: pytest.MonkeyPatch, capsys: Capsys - ) -> None: - monkeypatch.setattr( - "sys.argv", ["app", "-foo:bar", "--foo", "-f", "1", "-ff"] - ) - args = [m.Argument("bar", m.ArgSpec(action="store_true", dest="bar"))] - ns = m.parse_library_command_args("foo", args) - out, err = capsys.readouterr() - assert out == "" - assert vars(ns) == {"bar": True} - assert sys.argv == ["app", "--foo", "-f", "1", "-ff"] - - if __name__ == "__main__": sys.exit(pytest.main(sys.argv)) From c6b8e1078b8bcdd80e44ef28a41b8de0e0620041 Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Wed, 15 Feb 2023 15:26:29 -0800 Subject: [PATCH 22/57] Change the legion branch back to control_replication (#573) * Change the legion branch back to control_replication * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update the default legion branch in cmake files --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Manolis Papadakis --- cmake/thirdparty/get_legion.cmake | 2 +- install.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/thirdparty/get_legion.cmake b/cmake/thirdparty/get_legion.cmake index e158391cc..cb87c4f82 100644 --- a/cmake/thirdparty/get_legion.cmake +++ b/cmake/thirdparty/get_legion.cmake @@ -176,7 +176,7 @@ function(find_or_configure_legion) endfunction() if(NOT DEFINED legate_core_LEGION_BRANCH) - set(legate_core_LEGION_BRANCH collective) + set(legate_core_LEGION_BRANCH control_replication) endif() if(NOT DEFINED legate_core_LEGION_REPOSITORY) diff --git a/install.py b/install.py index a2b8738c5..82cfd6ee2 100755 --- a/install.py +++ b/install.py @@ -743,7 +743,7 @@ def driver(): "--legion-branch", dest="legion_branch", required=False, - default="collective", + default="control_replication", help="Legion branch to build Legate with.", ) args, unknown = parser.parse_known_args() From 1c163d36e14d3b549ad82819a4fbb8ebfafd4254 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Wed, 15 Feb 2023 16:53:31 -0800 Subject: [PATCH 23/57] Fix a minor compiler warning (#574) --- src/core/utilities/machine.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/utilities/machine.cc b/src/core/utilities/machine.cc index 9d7e31cdd..a6c5e7e5e 100644 --- a/src/core/utilities/machine.cc +++ b/src/core/utilities/machine.cc @@ -36,6 +36,7 @@ Memory::Kind find_memory_kind_for_executing_processor(bool host_accessible) case Processor::Kind::OMP_PROC: { return Core::has_socket_mem ? Memory::Kind::SOCKET_MEM : Memory::Kind::SYSTEM_MEM; } + default: break; } LEGATE_ABORT; return Memory::Kind::SYSTEM_MEM; From 7ddfece6fbd2cc019f675c08ad01404d4a2b7a0d Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Thu, 16 Feb 2023 13:41:13 -0800 Subject: [PATCH 24/57] Add `--numamem` to the tester (#576) * Add `--numamem` to the tester * Add more tests for the new tester flag and also fix the existing ones --- legate/tester/__init__.py | 3 +++ legate/tester/args.py | 10 ++++++++++ legate/tester/config.py | 1 + legate/tester/stages/_linux/omp.py | 2 ++ tests/unit/legate/tester/stages/_linux/test_omp.py | 2 ++ tests/unit/legate/tester/test___init__.py | 4 ++++ tests/unit/legate/tester/test_args.py | 4 ++++ 7 files changed, 26 insertions(+) diff --git a/legate/tester/__init__.py b/legate/tester/__init__.py index 045eca19d..9ba89aa88 100644 --- a/legate/tester/__init__.py +++ b/legate/tester/__init__.py @@ -46,6 +46,9 @@ #: Value to use if --ompthreads is not specified. DEFAULT_OMPTHREADS = 4 +#: Value to use if --numamem is not specified. +DEFAULT_NUMAMEM = 0 + #: Default values to apply to normalize the testing environment. DEFAULT_PROCESS_ENV = { "LEGATE_TEST": "1", diff --git a/legate/tester/args.py b/legate/tester/args.py index 4b24077a0..5119a1994 100644 --- a/legate/tester/args.py +++ b/legate/tester/args.py @@ -28,6 +28,7 @@ DEFAULT_GPU_DELAY, DEFAULT_GPU_MEMORY_BUDGET, DEFAULT_GPUS_PER_NODE, + DEFAULT_NUMAMEM, DEFAULT_OMPS_PER_NODE, DEFAULT_OMPTHREADS, FEATURES, @@ -161,6 +162,15 @@ ) +feature_opts.add_argument( + "--numamem", + dest="numamem", + type=int, + default=DEFAULT_NUMAMEM, + help="NUMA memory for OpenMP processors (MB)", +) + + test_opts = parser.add_argument_group("Test run configuration options") diff --git a/legate/tester/config.py b/legate/tester/config.py index 39441e433..d943b4b14 100644 --- a/legate/tester/config.py +++ b/legate/tester/config.py @@ -63,6 +63,7 @@ def __init__(self, argv: ArgList) -> None: self.fbmem = args.fbmem self.gpu_delay = args.gpu_delay self.ompthreads = args.ompthreads + self.numamem = args.numamem # test run configuration self.debug = args.debug diff --git a/legate/tester/stages/_linux/omp.py b/legate/tester/stages/_linux/omp.py index b5ee8a1a7..09101bafd 100644 --- a/legate/tester/stages/_linux/omp.py +++ b/legate/tester/stages/_linux/omp.py @@ -64,6 +64,8 @@ def shard_args(self, shard: Shard, config: Config) -> ArgList: str(config.omps), "--ompthreads", str(config.ompthreads), + "--numamem", + str(config.numamem), ] if config.cpu_pin != "none": args += [ diff --git a/tests/unit/legate/tester/stages/_linux/test_omp.py b/tests/unit/legate/tester/stages/_linux/test_omp.py index 66cdca5c9..cb926d295 100644 --- a/tests/unit/legate/tester/stages/_linux/test_omp.py +++ b/tests/unit/legate/tester/stages/_linux/test_omp.py @@ -79,6 +79,8 @@ def test_shard_args(shard: tuple[int, ...], expected: str) -> None: f"{c.omps}", "--ompthreads", f"{c.ompthreads}", + "--numamem", + f"{c.numamem}", "--cpu-bind", expected, ] diff --git a/tests/unit/legate/tester/test___init__.py b/tests/unit/legate/tester/test___init__.py index 6431469ff..26e330ece 100644 --- a/tests/unit/legate/tester/test___init__.py +++ b/tests/unit/legate/tester/test___init__.py @@ -22,6 +22,7 @@ DEFAULT_GPU_DELAY, DEFAULT_GPU_MEMORY_BUDGET, DEFAULT_GPUS_PER_NODE, + DEFAULT_NUMAMEM, DEFAULT_OMPS_PER_NODE, DEFAULT_OMPTHREADS, DEFAULT_PROCESS_ENV, @@ -50,6 +51,9 @@ def test_DEFAULT_OMPS_PER_NODE(self) -> None: def test_DEFAULT_OMPTHREADS(self) -> None: assert DEFAULT_OMPTHREADS == 4 + def test_DEFAULT_NUMAMEM(self) -> None: + assert DEFAULT_NUMAMEM == 0 + def test_DEFAULT_PROCESS_ENV(self) -> None: assert DEFAULT_PROCESS_ENV == { "LEGATE_TEST": "1", diff --git a/tests/unit/legate/tester/test_args.py b/tests/unit/legate/tester/test_args.py index c307a7080..ad87c536f 100644 --- a/tests/unit/legate/tester/test_args.py +++ b/tests/unit/legate/tester/test_args.py @@ -22,6 +22,7 @@ DEFAULT_GPU_DELAY, DEFAULT_GPU_MEMORY_BUDGET, DEFAULT_GPUS_PER_NODE, + DEFAULT_NUMAMEM, DEFAULT_OMPS_PER_NODE, DEFAULT_OMPTHREADS, args as m, @@ -59,6 +60,9 @@ def test_omps(self) -> None: def test_ompthreads(self) -> None: assert m.parser.get_default("ompthreads") == DEFAULT_OMPTHREADS + def test_numamem(self) -> None: + assert m.parser.get_default("numamem") == DEFAULT_NUMAMEM + def test_legate_dir(self) -> None: assert m.parser.get_default("legate_dir") is None From e6eff78c27206ecced34e4dd17e3a338b3fe62f2 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Thu, 16 Feb 2023 14:21:27 -0800 Subject: [PATCH 25/57] Change default --cpus value to 2 (#575) --- legate/tester/__init__.py | 2 +- tests/unit/legate/tester/test___init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/legate/tester/__init__.py b/legate/tester/__init__.py index 9ba89aa88..29f8d0b20 100644 --- a/legate/tester/__init__.py +++ b/legate/tester/__init__.py @@ -29,7 +29,7 @@ ] #: Value to use if --cpus is not specified. -DEFAULT_CPUS_PER_NODE = 4 +DEFAULT_CPUS_PER_NODE = 2 #: Value to use if --gpus is not specified. DEFAULT_GPUS_PER_NODE = 1 diff --git a/tests/unit/legate/tester/test___init__.py b/tests/unit/legate/tester/test___init__.py index 26e330ece..e28217082 100644 --- a/tests/unit/legate/tester/test___init__.py +++ b/tests/unit/legate/tester/test___init__.py @@ -34,7 +34,7 @@ class TestConsts: def test_DEFAULT_CPUS_PER_NODE(self) -> None: - assert DEFAULT_CPUS_PER_NODE == 4 + assert DEFAULT_CPUS_PER_NODE == 2 def test_DEFAULT_GPUS_PER_NODE(self) -> None: assert DEFAULT_GPUS_PER_NODE == 1 From 1244d9608299ad4eb7f24980889a1745c6025ef3 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Fri, 17 Feb 2023 10:17:42 -0800 Subject: [PATCH 26/57] Skip python 3.9.7 to work around python issue45121 (#577) --- conda/conda-build/conda_build_config.yaml | 2 +- scripts/generate-conda-envs.py | 2 +- setup.cfg | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/conda/conda-build/conda_build_config.yaml b/conda/conda-build/conda_build_config.yaml index e970f469e..b5ebf7fa5 100644 --- a/conda/conda-build/conda_build_config.yaml +++ b/conda/conda-build/conda_build_config.yaml @@ -4,7 +4,7 @@ gpu_enabled: python: - 3.8 - - 3.9 + - "3.9,!=3.9.7" - 3.10 numpy_version: diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 4f6954ffe..d6ae24ee4 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -239,7 +239,7 @@ def filename(self) -> str: - conda-forge dependencies: - - python={python} + - python={python},!=3.9.7 # avoid https://bugs.python.org/issue45121 {conda_sections}{pip} """ diff --git a/setup.cfg b/setup.cfg index ce00187b8..71b5eaf9b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,4 +61,4 @@ packages = find: install_requires = numpy>=1.22 # TODO: Add rest of install dependencies -python_requires = >=3.8 +python_requires = >=3.8,!=3.9.7 From bfa43594b8df1d4a940614dcff26b39de819cfc6 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 21 Feb 2023 09:45:26 -0800 Subject: [PATCH 27/57] Deps for cunumeric docs updates (#579) * nbsphinx and deps * add directive for settings --- legate/_sphinxext/__init__.py | 14 +++++ legate/_sphinxext/settings.py | 108 +++++++++++++++++++++++++++++++++ pyproject.toml | 1 + scripts/generate-conda-envs.py | 6 ++ 4 files changed, 129 insertions(+) create mode 100644 legate/_sphinxext/__init__.py create mode 100644 legate/_sphinxext/settings.py diff --git a/legate/_sphinxext/__init__.py b/legate/_sphinxext/__init__.py new file mode 100644 index 000000000..dca0f1315 --- /dev/null +++ b/legate/_sphinxext/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/legate/_sphinxext/settings.py b/legate/_sphinxext/settings.py new file mode 100644 index 000000000..0cba5d1b1 --- /dev/null +++ b/legate/_sphinxext/settings.py @@ -0,0 +1,108 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from __future__ import annotations + +import importlib +import textwrap + +from docutils import nodes +from docutils.parsers.rst.directives import unchanged +from docutils.statemachine import ViewList +from jinja2 import Template +from sphinx.errors import SphinxError +from sphinx.util.docutils import SphinxDirective +from sphinx.util.nodes import nested_parse_with_titles + +from legate.util.settings import PrioritizedSetting, _Unset + +SETTINGS_DETAIL = Template( + """ +{% for setting in settings %} + +``{{ setting['name'] }}`` +{{ "''''" + "'" * setting['name']|length }} + +:**Type**: {{ setting['type'] }} +:**Env var**: ``{{ setting['env_var'] }}`` +:**Default**: {{ setting['default'] }} + +{{ setting['help'] }} + +{% endfor %} +""" +) + + +class SettingsDirective(SphinxDirective): + has_content = True + required_arguments = 1 + optional_arguments = 1 + option_spec = {"module": unchanged} + + def run(self): + obj_name = " ".join(self.arguments) + module_name = self.options["module"] + + try: + module = importlib.import_module(module_name) + except ImportError: + raise SphinxError( + f"Unable to generate reference docs for {obj_name}: " + f"couldn't import module {module_name}" + ) + + obj = getattr(module, obj_name, None) + if obj is None: + raise SphinxError( + f"Unable to generate reference docs for {obj_name}: " + f"no model {obj_name} in module {module_name}" + ) + + settings = [] + for x in obj.__class__.__dict__.values(): + if not isinstance(x, PrioritizedSetting): + continue + # help = [line.strip() for line in x.help.strip().split("\n")] + setting = { + "name": x.name, + "env_var": x.env_var, + "type": x.convert_type, + "help": textwrap.dedent(x.help), + "default": "(Unset)" + if x.default is _Unset + else repr(x.default), + } + settings.append(setting) + + rst_text = SETTINGS_DETAIL.render( + name=obj_name, module_name=module_name, settings=settings + ) + return self.parse(rst_text, "") + + def parse(self, rst_text, annotation): + result = ViewList() + for line in rst_text.split("\n"): + result.append(line, annotation) + node = nodes.paragraph() + node.document = self.state.document + nested_parse_with_titles(self.state, result, node) + return node.children + + +def setup(app): + """Required Sphinx extension setup function.""" + app.add_directive_to_domain("py", "settings", SettingsDirective) + + return dict(parallel_read_safe=True, parallel_write_safe=True) diff --git a/pyproject.toml b/pyproject.toml index 8f82a0d13..181f16d26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,5 +94,6 @@ module = [ "legate._version", "legate.__main__", "legate.install_info", + "legate._sphinxext.*", ] ignore_errors = true diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index d6ae24ee4..f5a354b6a 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -155,13 +155,19 @@ def pip(self) -> Reqs: class DocsConfig(SectionConfig): header = "docs" + @property + def conda(self) -> Reqs: + return ("pandoc",) + @property def pip(self) -> Reqs: return ( + "ipython", "jinja2", "markdown<3.4.0", "pydata-sphinx-theme", "myst-parser", + "nbsphinx", "sphinx-copybutton", "sphinx>=4.4.0", ) From 74f3c69ceb103c72dcb49f224f045cd0481424c9 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 21 Feb 2023 09:46:30 -0800 Subject: [PATCH 28/57] Add hopper to CUDA architectures (#583) Co-authored-by: Manolis Papadakis --- cmake/Modules/cuda_arch_helpers.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/Modules/cuda_arch_helpers.cmake b/cmake/Modules/cuda_arch_helpers.cmake index c70235f68..9a2206f69 100644 --- a/cmake/Modules/cuda_arch_helpers.cmake +++ b/cmake/Modules/cuda_arch_helpers.cmake @@ -44,6 +44,9 @@ function(set_cuda_arch_from_names) if(CMAKE_CUDA_ARCHITECTURES MATCHES "ampere") list(APPEND cuda_archs 80) endif() + if(CMAKE_CUDA_ARCHITECTURES MATCHES "hopper") + list(APPEND cuda_archs 90) + endif() if(cuda_archs) list(LENGTH cuda_archs num_archs) @@ -83,6 +86,7 @@ function(add_cuda_architecture_defines defs) add_def_if_arch_enabled("70" "VOLTA_ARCH") add_def_if_arch_enabled("75" "TURING_ARCH") add_def_if_arch_enabled("80" "AMPERE_ARCH") + add_def_if_arch_enabled("90" "HOPPER_ARCH") set(${defs} ${_defs} PARENT_SCOPE) endfunction() From 5f806db3242e9b3a29bc4f9f670269d99ca666da Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Feb 2023 09:54:00 -0800 Subject: [PATCH 29/57] [pre-commit.ci] pre-commit autoupdate (#582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v1.0.0 → v1.0.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.0...v1.0.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0ffedcd82..a8ac54762 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: files: \.(cu|cuh|h|cc|inl)$ types_or: [] - repo: https://github.com/pre-commit/mirrors-mypy - rev: 'v1.0.0' + rev: 'v1.0.1' hooks: - id: mypy pass_filenames: false From ec74153346546338109fb1da1ca973462c9d3288 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 21 Feb 2023 11:54:37 -0800 Subject: [PATCH 30/57] Don't silently ignore non-existing user-supplied dirs (#580) Co-authored-by: Manolis Papadakis --- install.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/install.py b/install.py index 82cfd6ee2..149910f54 100755 --- a/install.py +++ b/install.py @@ -324,12 +324,14 @@ def install( print("Using python lib and version: {}, {}".format(pylib_name, pyversion)) def validate_path(path): - if path is not None and (path := str(path)) != "": - if not os.path.isabs(path): - path = join(legate_core_dir, path) - if exists(path := realpath(path)): - return path - return None + if path is None or (path := str(path)) == "": + return None + if not os.path.isabs(path): + path = join(legate_core_dir, path) + if not exists(path := realpath(path)): + print(f"Error: path does not exist: {path}") + sys.exit(1) + return path cuda_dir = validate_path(cuda_dir) nccl_dir = validate_path(nccl_dir) From f26889f2efd6fb519fe45db400729a4f5b5e9353 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 21 Feb 2023 14:20:43 -0800 Subject: [PATCH 31/57] Fix driver help typos (#584) --- legate/driver/args.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/legate/driver/args.py b/legate/driver/args.py index 58a9bf5cc..55c382e3b 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -102,7 +102,7 @@ ) -core = parser.add_argument_group("Core alloction") +core = parser.add_argument_group("Core allocation") core.add_argument(CPUS.name, **CPUS.kwargs) core.add_argument(GPUS.name, **GPUS.kwargs) core.add_argument(OMPS.name, **OMPS.kwargs) @@ -110,7 +110,7 @@ core.add_argument(UTILITY.name, **UTILITY.kwargs) -memory = parser.add_argument_group("Memory alloction") +memory = parser.add_argument_group("Memory allocation") memory.add_argument(SYSMEM.name, **SYSMEM.kwargs) memory.add_argument(NUMAMEM.name, **NUMAMEM.kwargs) memory.add_argument(FBMEM.name, **FBMEM.kwargs) From 7efd229ec515ab75559fd1b7d77aac6bfd8b31e4 Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Tue, 21 Feb 2023 14:26:48 -0800 Subject: [PATCH 32/57] Revert "NVTX: Use RangePush and Domain (#293)" (#578) This reverts commit 07e86edaa2d4e609faa3a40e626936eef1556174. --- src/core/runtime/runtime.cc | 13 +------------ src/core/utilities/nvtx_help.h | 18 +++--------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/src/core/runtime/runtime.cc b/src/core/runtime/runtime.cc index e43236b60..27e14a7da 100644 --- a/src/core/runtime/runtime.cc +++ b/src/core/runtime/runtime.cc @@ -45,11 +45,6 @@ static const char* const core_library_name = "legate.core"; /*static*/ bool Core::has_socket_mem = false; -#ifdef LEGATE_USE_CUDA -/*static*/ const char* const nvtx::Range::domainName = "Legate"; -/*static*/ nvtxDomainHandle_t nvtx::Range::domain; -#endif - /*static*/ void Core::parse_config(void) { #ifndef LEGATE_USE_CUDA @@ -88,10 +83,6 @@ static const char* const core_library_name = "legate.core"; parse_variable("LEGATE_EMPTY_TASK", use_empty_task); parse_variable("LEGATE_SYNC_STREAM_VIEW", synchronize_stream_view); parse_variable("LEGATE_LOG_MAPPING", log_mapping_decisions); - -#ifdef LEGATE_USE_CUDA - nvtx::Range::initialize(); -#endif } static void extract_scalar_task( @@ -116,9 +107,7 @@ static void extract_scalar_task( /*static*/ void Core::shutdown(void) { -#ifdef LEGATE_USE_CUDA - nvtx::Range::shutdown(); -#endif + // Nothing to do here yet... } /*static*/ void Core::show_progress(const Legion::Task* task, diff --git a/src/core/utilities/nvtx_help.h b/src/core/utilities/nvtx_help.h index 4d967993e..9b5c6270c 100644 --- a/src/core/utilities/nvtx_help.h +++ b/src/core/utilities/nvtx_help.h @@ -27,23 +27,11 @@ namespace nvtx { class Range { public: - Range(const char* message) - { - nvtxEventAttributes_t eventAttrib = {0}; - eventAttrib.version = NVTX_VERSION; - eventAttrib.size = NVTX_EVENT_ATTRIB_STRUCT_SIZE; - eventAttrib.messageType = NVTX_MESSAGE_TYPE_ASCII; - eventAttrib.message.ascii = message; - nvtxDomainRangePushEx(domain, &eventAttrib); - } - ~Range() { nvtxDomainRangePop(domain); } - - static void initialize() { domain = nvtxDomainCreateA(domainName); } - static void shutdown() { nvtxDomainDestroy(domain); } + Range(const char* message) { range_ = nvtxRangeStartA(message); } + ~Range() { nvtxRangeEnd(range_); } private: - static const char* const domainName; - static nvtxDomainHandle_t domain; + nvtxRangeId_t range_; }; } // namespace nvtx From 8fc44403a04788db8654e86ed9ec98829983d6fd Mon Sep 17 00:00:00 2001 From: Mark Vaz Date: Thu, 23 Feb 2023 09:17:23 -0800 Subject: [PATCH 33/57] add nvml dependency to get the headers for realm (#586) Co-authored-by: mavaz --- conda/conda-build/meta.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/conda/conda-build/meta.yaml b/conda/conda-build/meta.yaml index 77722cab1..ace526e84 100644 --- a/conda/conda-build/meta.yaml +++ b/conda/conda-build/meta.yaml @@ -112,6 +112,7 @@ requirements: - cuda-nvtx ={{ cuda_version }} - cuda-cccl ={{ cuda_version }} - cuda-cudart ={{ cuda_version }} + - cuda-nvml-dev ={{ cuda_version }} - cuda-driver-dev ={{ cuda_version }} - cuda-cudart-dev ={{ cuda_version }} {% endif %} From cb65d91c5713f9b210897da3b025ddb306d2806e Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Fri, 24 Feb 2023 21:23:29 -0800 Subject: [PATCH 34/57] Refactoring changes (#581) * Move the Legate task implemention out from the header * Fix the bug in task name extraction introduced by refactoring * Factor out variant detection code from the base task class * Move task details to an inline file * Refactoring to get rid of Legion references in registration * Hide variant registration details with a friend class * Take over reduction operator registrations from Legion * Re-export necessary Legion names and use fully qualified names for all other Legion references * Use the right copyright year --- legate_core_cpp.cmake | 5 + src/core/comm/coll.cc | 1 - src/core/comm/comm_cpu.cc | 25 +- src/core/comm/comm_nccl.cu | 29 +- src/core/comm/local_comm.cc | 3 +- src/core/comm/mpi_comm.cc | 3 +- src/core/data/allocator.cc | 4 +- src/core/data/allocator.h | 6 +- src/core/data/buffer.h | 14 +- src/core/data/store.cc | 37 +-- src/core/data/store.h | 67 +++-- src/core/data/store.inl | 60 ++--- src/core/data/transform.cc | 39 ++- src/core/data/transform.h | 16 +- src/core/mapping/base_mapper.cc | 383 ++++++++++++++------------- src/core/mapping/base_mapper.h | 73 ++--- src/core/mapping/core_mapper.cc | 134 +++++----- src/core/mapping/instance_manager.cc | 23 +- src/core/mapping/instance_manager.h | 7 +- src/core/mapping/mapping.cc | 27 +- src/core/mapping/mapping.h | 16 +- src/core/mapping/operation.cc | 26 +- src/core/mapping/operation.h | 26 +- src/core/runtime/context.cc | 34 +-- src/core/runtime/context.h | 22 +- src/core/runtime/context.inl | 76 ++++++ src/core/runtime/projection.cc | 62 ++--- src/core/runtime/projection.h | 9 +- src/core/runtime/runtime.cc | 65 +++-- src/core/runtime/runtime.h | 11 +- src/core/runtime/shard.cc | 40 +-- src/core/task/registrar.cc | 99 +++++++ src/core/task/registrar.h | 49 ++++ src/core/task/return.cc | 23 +- src/core/task/return.h | 3 +- src/core/task/task.cc | 99 ++++--- src/core/task/task.h | 293 ++------------------ src/core/task/task.inl | 79 ++++++ src/core/task/variant.cc | 51 ++++ src/core/task/variant.h | 106 ++++++++ src/core/utilities/debug.h | 3 +- src/core/utilities/deserializer.cc | 28 +- src/core/utilities/dispatch.h | 70 ++--- src/core/utilities/linearize.cc | 2 - src/core/utilities/linearize.h | 10 +- src/core/utilities/machine.cc | 2 - src/core/utilities/machine.h | 4 +- src/core/utilities/typedefs.h | 80 ++++-- src/legate.h | 1 + src/legate_defines.h | 6 + 50 files changed, 1345 insertions(+), 1006 deletions(-) create mode 100644 src/core/runtime/context.inl create mode 100644 src/core/task/registrar.cc create mode 100644 src/core/task/registrar.h create mode 100644 src/core/task/task.inl create mode 100644 src/core/task/variant.cc create mode 100644 src/core/task/variant.h diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index d9bbd10b7..6191cf2cf 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -205,8 +205,10 @@ list(APPEND legate_core_SOURCES src/core/runtime/projection.cc src/core/runtime/runtime.cc src/core/runtime/shard.cc + src/core/task/registrar.cc src/core/task/return.cc src/core/task/task.cc + src/core/task/variant.cc src/core/utilities/debug.cc src/core/utilities/deserializer.cc src/core/utilities/machine.cc @@ -355,6 +357,7 @@ install( install( FILES src/core/runtime/context.h + src/core/runtime/context.inl src/core/runtime/runtime.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/legate/core/runtime) @@ -362,6 +365,8 @@ install( FILES src/core/task/exception.h src/core/task/return.h src/core/task/task.h + src/core/task/task.inl + src/core/task/variant.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/legate/core/task) install( diff --git a/src/core/comm/coll.cc b/src/core/comm/coll.cc index 5f1a1f4e9..4bd76a758 100644 --- a/src/core/comm/coll.cc +++ b/src/core/comm/coll.cc @@ -35,7 +35,6 @@ namespace legate { namespace comm { namespace coll { -using namespace Legion; Logger log_coll("coll"); BackendNetwork* backend_network = nullptr; diff --git a/src/core/comm/comm_cpu.cc b/src/core/comm/comm_cpu.cc index 05c2f6283..7b0393f91 100644 --- a/src/core/comm/comm_cpu.cc +++ b/src/core/comm/comm_cpu.cc @@ -19,8 +19,6 @@ #include "core/comm/coll.h" -using namespace Legion; - namespace legate { namespace comm { namespace cpu { @@ -30,7 +28,7 @@ static int init_cpucoll_mapping(const Legion::Task* task, Legion::Context context, Legion::Runtime* runtime) { - Core::show_progress(task, context, runtime, task->get_task_name()); + Core::show_progress(task, context, runtime); int mpi_rank = 0; #if defined(LEGATE_USE_NETWORK) if (coll::backend_network->comm_type == coll::CollCommType::CollMPI) { @@ -46,7 +44,7 @@ static coll::CollComm init_cpucoll(const Legion::Task* task, Legion::Context context, Legion::Runtime* runtime) { - Core::show_progress(task, context, runtime, task->get_task_name()); + Core::show_progress(task, context, runtime); const int point = task->index_point[0]; int num_ranks = task->index_domain.get_volume(); @@ -80,7 +78,7 @@ static void finalize_cpucoll(const Legion::Task* task, Legion::Context context, Legion::Runtime* runtime) { - Core::show_progress(task, context, runtime, task->get_task_name()); + Core::show_progress(task, context, runtime); assert(task->futures.size() == 1); coll::CollComm comm = task->futures[0].get_result(); @@ -95,32 +93,29 @@ void register_tasks(Legion::Machine machine, Legion::Runtime* runtime, const LibraryContext& context) { - const InputArgs& command_args = Legion::Runtime::get_input_args(); - int argc = command_args.argc; - char** argv = command_args.argv; - coll::collInit(argc, argv); + const auto& command_args = Legion::Runtime::get_input_args(); + coll::collInit(command_args.argc, command_args.argv); - const TaskID init_cpucoll_mapping_task_id = - context.get_task_id(LEGATE_CORE_INIT_CPUCOLL_MAPPING_TASK_ID); + auto init_cpucoll_mapping_task_id = context.get_task_id(LEGATE_CORE_INIT_CPUCOLL_MAPPING_TASK_ID); const char* init_cpucoll_mapping_task_name = "core::comm::cpu::init_mapping"; runtime->attach_name(init_cpucoll_mapping_task_id, init_cpucoll_mapping_task_name, false /*mutable*/, true /*local only*/); - const TaskID init_cpucoll_task_id = context.get_task_id(LEGATE_CORE_INIT_CPUCOLL_TASK_ID); + auto init_cpucoll_task_id = context.get_task_id(LEGATE_CORE_INIT_CPUCOLL_TASK_ID); const char* init_cpucoll_task_name = "core::comm::cpu::init"; runtime->attach_name( init_cpucoll_task_id, init_cpucoll_task_name, false /*mutable*/, true /*local only*/); - const TaskID finalize_cpucoll_task_id = context.get_task_id(LEGATE_CORE_FINALIZE_CPUCOLL_TASK_ID); + auto finalize_cpucoll_task_id = context.get_task_id(LEGATE_CORE_FINALIZE_CPUCOLL_TASK_ID); const char* finalize_cpucoll_task_name = "core::comm::cpu::finalize"; runtime->attach_name( finalize_cpucoll_task_id, finalize_cpucoll_task_name, false /*mutable*/, true /*local only*/); auto make_registrar = [&](auto task_id, auto* task_name, auto proc_kind) { - TaskVariantRegistrar registrar(task_id, task_name); - registrar.add_constraint(ProcessorConstraint(proc_kind)); + Legion::TaskVariantRegistrar registrar(task_id, task_name); + registrar.add_constraint(Legion::ProcessorConstraint(proc_kind)); registrar.set_leaf(true); registrar.global_registration = false; return registrar; diff --git a/src/core/comm/comm_nccl.cu b/src/core/comm/comm_nccl.cu index 2e22b6e92..0f95fe74e 100644 --- a/src/core/comm/comm_nccl.cu +++ b/src/core/comm/comm_nccl.cu @@ -17,14 +17,14 @@ #include "core/comm/comm_nccl.h" #include "core/cuda/cuda_help.h" #include "core/cuda/stream_pool.h" +#include "core/data/buffer.h" #include "core/utilities/nvtx_help.h" +#include "core/utilities/typedefs.h" #include "legate.h" #include #include -using namespace Legion; - namespace legate { namespace comm { namespace nccl { @@ -59,7 +59,7 @@ static ncclUniqueId init_nccl_id(const Legion::Task* task, { legate::nvtx::Range auto_range("core::comm::nccl::init_id"); - Core::show_progress(task, context, runtime, task->get_task_name()); + Core::show_progress(task, context, runtime); ncclUniqueId id; CHECK_NCCL(ncclGetUniqueId(&id)); @@ -74,7 +74,7 @@ static ncclComm_t* init_nccl(const Legion::Task* task, { legate::nvtx::Range auto_range("core::comm::nccl::init"); - Core::show_progress(task, context, runtime, task->get_task_name()); + Core::show_progress(task, context, runtime); assert(task->futures.size() == 1); @@ -92,13 +92,8 @@ static ncclComm_t* init_nccl(const Legion::Task* task, // Perform a warm-up all-to-all - using namespace Legion; - - DeferredBuffer<_Payload, 1> src_buffer(Memory::GPU_FB_MEM, - Domain(Rect<1>{Point<1>{0}, Point<1>{num_ranks - 1}})); - - DeferredBuffer<_Payload, 1> tgt_buffer(Memory::GPU_FB_MEM, - Domain(Rect<1>{Point<1>{0}, Point<1>{num_ranks - 1}})); + auto src_buffer = create_buffer<_Payload>(num_ranks, Memory::Kind::GPU_FB_MEM); + auto tgt_buffer = create_buffer<_Payload>(num_ranks, Memory::Kind::GPU_FB_MEM); CHECK_NCCL(ncclGroupStart()); for (auto idx = 0; idx < num_ranks; ++idx) { @@ -119,7 +114,7 @@ static void finalize_nccl(const Legion::Task* task, { legate::nvtx::Range auto_range("core::comm::nccl::finalize"); - Core::show_progress(task, context, runtime, task->get_task_name()); + Core::show_progress(task, context, runtime); assert(task->futures.size() == 1); auto comm = task->futures[0].get_result(); @@ -131,24 +126,24 @@ void register_tasks(Legion::Machine machine, Legion::Runtime* runtime, const LibraryContext& context) { - const TaskID init_nccl_id_task_id = context.get_task_id(LEGATE_CORE_INIT_NCCL_ID_TASK_ID); + auto init_nccl_id_task_id = context.get_task_id(LEGATE_CORE_INIT_NCCL_ID_TASK_ID); const char* init_nccl_id_task_name = "core::comm::nccl::init_id"; runtime->attach_name( init_nccl_id_task_id, init_nccl_id_task_name, false /*mutable*/, true /*local only*/); - const TaskID init_nccl_task_id = context.get_task_id(LEGATE_CORE_INIT_NCCL_TASK_ID); + auto init_nccl_task_id = context.get_task_id(LEGATE_CORE_INIT_NCCL_TASK_ID); const char* init_nccl_task_name = "core::comm::nccl::init"; runtime->attach_name( init_nccl_task_id, init_nccl_task_name, false /*mutable*/, true /*local only*/); - const TaskID finalize_nccl_task_id = context.get_task_id(LEGATE_CORE_FINALIZE_NCCL_TASK_ID); + auto finalize_nccl_task_id = context.get_task_id(LEGATE_CORE_FINALIZE_NCCL_TASK_ID); const char* finalize_nccl_task_name = "core::comm::nccl::finalize"; runtime->attach_name( finalize_nccl_task_id, finalize_nccl_task_name, false /*mutable*/, true /*local only*/); auto make_registrar = [&](auto task_id, auto* task_name, auto proc_kind) { - TaskVariantRegistrar registrar(task_id, task_name); - registrar.add_constraint(ProcessorConstraint(proc_kind)); + Legion::TaskVariantRegistrar registrar(task_id, task_name); + registrar.add_constraint(Legion::ProcessorConstraint(proc_kind)); registrar.set_leaf(true); registrar.global_registration = false; return registrar; diff --git a/src/core/comm/local_comm.cc b/src/core/comm/local_comm.cc index 8adc4a2f3..29d317c38 100644 --- a/src/core/comm/local_comm.cc +++ b/src/core/comm/local_comm.cc @@ -27,7 +27,6 @@ namespace legate { namespace comm { namespace coll { -using namespace Legion; extern Logger log_coll; // public functions start from here @@ -348,4 +347,4 @@ void LocalNetwork::barrierLocal(CollComm global_comm) } // namespace coll } // namespace comm -} // namespace legate \ No newline at end of file +} // namespace legate diff --git a/src/core/comm/mpi_comm.cc b/src/core/comm/mpi_comm.cc index 1761701ff..114c82171 100644 --- a/src/core/comm/mpi_comm.cc +++ b/src/core/comm/mpi_comm.cc @@ -27,7 +27,6 @@ namespace legate { namespace comm { namespace coll { -using namespace Legion; extern Logger log_coll; enum CollTag : int { @@ -572,4 +571,4 @@ int MPINetwork::generateGatherTag(int rank, CollComm global_comm) } // namespace coll } // namespace comm -} // namespace legate \ No newline at end of file +} // namespace legate diff --git a/src/core/data/allocator.cc b/src/core/data/allocator.cc index 62051d05e..7f4512064 100644 --- a/src/core/data/allocator.cc +++ b/src/core/data/allocator.cc @@ -19,7 +19,7 @@ namespace legate { -ScopedAllocator::ScopedAllocator(Legion::Memory::Kind kind, bool scoped, size_t alignment) +ScopedAllocator::ScopedAllocator(Memory::Kind kind, bool scoped, size_t alignment) : target_kind_(kind), scoped_(scoped), alignment_(alignment) { } @@ -59,4 +59,4 @@ void ScopedAllocator::deallocate(void* ptr) buffer.destroy(); } -} // namespace legate \ No newline at end of file +} // namespace legate diff --git a/src/core/data/allocator.h b/src/core/data/allocator.h index 47d3c1a32..f6f057f7d 100644 --- a/src/core/data/allocator.h +++ b/src/core/data/allocator.h @@ -31,7 +31,7 @@ class ScopedAllocator { // Iff 'scoped', all allocations will be released upon destruction. // Otherwise this is up to the runtime after the task has finished. - ScopedAllocator(Legion::Memory::Kind kind, bool scoped = true, size_t alignment = 16); + ScopedAllocator(Memory::Kind kind, bool scoped = true, size_t alignment = 16); ~ScopedAllocator(); public: @@ -39,10 +39,10 @@ class ScopedAllocator { void deallocate(void* ptr); private: - Legion::Memory::Kind target_kind_{Legion::Memory::Kind::SYSTEM_MEM}; + Memory::Kind target_kind_{Memory::Kind::SYSTEM_MEM}; bool scoped_; size_t alignment_; std::unordered_map buffers_{}; }; -} // namespace legate \ No newline at end of file +} // namespace legate diff --git a/src/core/data/buffer.h b/src/core/data/buffer.h index 8c5a01b6c..90ec8d5c9 100644 --- a/src/core/data/buffer.h +++ b/src/core/data/buffer.h @@ -19,6 +19,7 @@ #include "legion.h" #include "core/utilities/machine.h" +#include "core/utilities/typedefs.h" namespace legate { @@ -43,11 +44,10 @@ using Buffer = Legion::DeferredBuffer; // after it's technically been deallocated. template -Buffer create_buffer(const Legion::Point& extents, - Legion::Memory::Kind kind = Legion::Memory::Kind::NO_MEMKIND, - size_t alignment = 16) +Buffer create_buffer(const Point& extents, + Memory::Kind kind = Memory::Kind::NO_MEMKIND, + size_t alignment = 16) { - using namespace Legion; if (Memory::Kind::NO_MEMKIND == kind) kind = find_memory_kind_for_executing_processor(false); auto hi = extents - Point::ONES(); // We just avoid creating empty buffers, as they cause all sorts of headaches. @@ -58,10 +58,10 @@ Buffer create_buffer(const Legion::Point& extents, template Buffer create_buffer(size_t size, - Legion::Memory::Kind kind = Legion::Memory::Kind::NO_MEMKIND, - size_t alignment = 16) + Memory::Kind kind = Memory::Kind::NO_MEMKIND, + size_t alignment = 16) { - return create_buffer(Legion::Point<1>(size), kind, alignment); + return create_buffer(Point<1>(size), kind, alignment); } } // namespace legate diff --git a/src/core/data/store.cc b/src/core/data/store.cc index c185ab602..bc7592c33 100644 --- a/src/core/data/store.cc +++ b/src/core/data/store.cc @@ -28,9 +28,7 @@ namespace legate { -using namespace Legion; - -RegionField::RegionField(int32_t dim, const PhysicalRegion& pr, FieldID fid) +RegionField::RegionField(int32_t dim, const Legion::PhysicalRegion& pr, Legion::FieldID fid) : dim_(dim), pr_(pr), fid_(fid) { auto priv = pr.get_privilege(); @@ -60,14 +58,18 @@ RegionField& RegionField::operator=(RegionField&& other) noexcept return *this; } -bool RegionField::valid() const { return pr_.get_logical_region() != LogicalRegion::NO_REGION; } +bool RegionField::valid() const +{ + return pr_.get_logical_region() != Legion::LogicalRegion::NO_REGION; +} Domain RegionField::domain() const { return dim_dispatch(dim_, get_domain_fn{}, pr_); } -OutputRegionField::OutputRegionField(const OutputRegion& out, FieldID fid) +OutputRegionField::OutputRegionField(const Legion::OutputRegion& out, Legion::FieldID fid) : out_(out), fid_(fid), - num_elements_(UntypedDeferredValue(sizeof(size_t), find_memory_kind_for_executing_processor())) + num_elements_( + Legion::UntypedDeferredValue(sizeof(size_t), find_memory_kind_for_executing_processor())) { } @@ -75,9 +77,9 @@ OutputRegionField::OutputRegionField(OutputRegionField&& other) noexcept : bound_(other.bound_), out_(other.out_), fid_(other.fid_), num_elements_(other.num_elements_) { other.bound_ = false; - other.out_ = OutputRegion(); + other.out_ = Legion::OutputRegion(); other.fid_ = -1; - other.num_elements_ = UntypedDeferredValue(); + other.num_elements_ = Legion::UntypedDeferredValue(); } OutputRegionField& OutputRegionField::operator=(OutputRegionField&& other) noexcept @@ -88,9 +90,9 @@ OutputRegionField& OutputRegionField::operator=(OutputRegionField&& other) noexc num_elements_ = other.num_elements_; other.bound_ = false; - other.out_ = OutputRegion(); + other.out_ = Legion::OutputRegion(); other.fid_ = -1; - other.num_elements_ = UntypedDeferredValue(); + other.num_elements_ = Legion::UntypedDeferredValue(); return *this; } @@ -125,8 +127,11 @@ void OutputRegionField::update_num_elements(size_t num_elements) acc[0] = num_elements; } -FutureWrapper::FutureWrapper( - bool read_only, int32_t field_size, Domain domain, Future future, bool initialize /*= false*/) +FutureWrapper::FutureWrapper(bool read_only, + int32_t field_size, + Domain domain, + Legion::Future future, + bool initialize /*= false*/) : read_only_(read_only), field_size_(field_size), domain_(domain), future_(future) { #ifdef DEBUG_LEGATE @@ -148,16 +153,16 @@ FutureWrapper::FutureWrapper( #ifdef LEGATE_USE_CUDA if (mem_kind == Memory::Kind::GPU_FB_MEM) { // TODO: This should be done by Legion - buffer_ = UntypedDeferredValue(field_size, mem_kind); + buffer_ = Legion::UntypedDeferredValue(field_size, mem_kind); AccessorWO acc(buffer_, field_size, false); auto stream = cuda::StreamPool::get_stream_pool().get_stream(); CHECK_CUDA( cudaMemcpyAsync(acc.ptr(0), p_init_value, field_size, cudaMemcpyDeviceToDevice, stream)); } else #endif - buffer_ = UntypedDeferredValue(field_size, mem_kind, p_init_value); + buffer_ = Legion::UntypedDeferredValue(field_size, mem_kind, p_init_value); } else - buffer_ = UntypedDeferredValue(field_size, mem_kind); + buffer_ = Legion::UntypedDeferredValue(field_size, mem_kind); } } @@ -187,7 +192,7 @@ void FutureWrapper::initialize_with_identity(int32_t redop_id) auto untyped_acc = AccessorWO(buffer_, field_size_); auto ptr = untyped_acc.ptr(0); - auto redop = Runtime::get_reduction_op(redop_id); + auto redop = Legion::Runtime::get_reduction_op(redop_id); #ifdef DEBUG_LEGATE assert(redop->sizeof_lhs == field_size_); #endif diff --git a/src/core/data/store.h b/src/core/data/store.h index f21c820fc..0ae7231bc 100644 --- a/src/core/data/store.h +++ b/src/core/data/store.h @@ -59,7 +59,7 @@ class RegionField { ACC operator()(const Legion::PhysicalRegion& pr, Legion::FieldID fid, const Legion::AffineTransform& transform, - const Legion::Rect& bounds) + const Rect& bounds) { return ACC(pr, fid, transform, bounds); } @@ -76,7 +76,7 @@ class RegionField { Legion::FieldID fid, int32_t redop_id, const Legion::AffineTransform& transform, - const Legion::Rect& bounds) + const Rect& bounds) { return ACC(pr, fid, redop_id, transform, bounds); } @@ -84,9 +84,9 @@ class RegionField { struct get_domain_fn { template - Legion::Domain operator()(const Legion::PhysicalRegion& pr) + Domain operator()(const Legion::PhysicalRegion& pr) { - return Legion::Domain(pr.get_bounds()); + return Domain(pr.get_bounds()); } }; @@ -113,35 +113,34 @@ class RegionField { public: template - AccessorRO read_accessor(const Legion::Rect& bounds) const; + AccessorRO read_accessor(const Rect& bounds) const; template - AccessorWO write_accessor(const Legion::Rect& bounds) const; + AccessorWO write_accessor(const Rect& bounds) const; template - AccessorRW read_write_accessor(const Legion::Rect& bounds) const; + AccessorRW read_write_accessor(const Rect& bounds) const; template - AccessorRD reduce_accessor(int32_t redop_id, - const Legion::Rect& bounds) const; + AccessorRD reduce_accessor(int32_t redop_id, const Rect& bounds) const; public: template - AccessorRO read_accessor(const Legion::Rect& bounds, + AccessorRO read_accessor(const Rect& bounds, const Legion::DomainAffineTransform& transform) const; template - AccessorWO write_accessor(const Legion::Rect& bounds, + AccessorWO write_accessor(const Rect& bounds, const Legion::DomainAffineTransform& transform) const; template - AccessorRW read_write_accessor(const Legion::Rect& bounds, + AccessorRW read_write_accessor(const Rect& bounds, const Legion::DomainAffineTransform& transform) const; template AccessorRD reduce_accessor( int32_t redop_id, - const Legion::Rect& bounds, + const Rect& bounds, const Legion::DomainAffineTransform& transform) const; public: template - Legion::Rect shape() const; - Legion::Domain domain() const; + Rect shape() const; + Domain domain() const; public: bool is_readable() const { return readable_; } @@ -177,11 +176,11 @@ class OutputRegionField { public: template - Buffer create_output_buffer(const Legion::Point& extents, bool return_buffer); + Buffer create_output_buffer(const Point& extents, bool return_buffer); public: template - void return_data(Buffer& buffer, const Legion::Point& extents); + void return_data(Buffer& buffer, const Point& extents); void make_empty(int32_t dim); public: @@ -202,7 +201,7 @@ class FutureWrapper { FutureWrapper() {} FutureWrapper(bool read_only, int32_t field_size, - Legion::Domain domain, + Domain domain, Legion::Future future, bool initialize = false); @@ -225,14 +224,13 @@ class FutureWrapper { public: template - AccessorRO read_accessor(const Legion::Rect& bounds) const; + AccessorRO read_accessor(const Rect& bounds) const; template - AccessorWO write_accessor(const Legion::Rect& bounds) const; + AccessorWO write_accessor(const Rect& bounds) const; template - AccessorRW read_write_accessor(const Legion::Rect& bounds) const; + AccessorRW read_write_accessor(const Rect& bounds) const; template - AccessorRD reduce_accessor(int32_t redop_id, - const Legion::Rect& bounds) const; + AccessorRD reduce_accessor(int32_t redop_id, const Rect& bounds) const; public: template @@ -240,8 +238,8 @@ class FutureWrapper { public: template - Legion::Rect shape() const; - Legion::Domain domain() const; + Rect shape() const; + Domain domain() const; public: void initialize_with_identity(int32_t redop_id); @@ -252,7 +250,7 @@ class FutureWrapper { private: bool read_only_{true}; size_t field_size_{0}; - Legion::Domain domain_{}; + Domain domain_{}; Legion::Future future_{}; Legion::UntypedDeferredValue buffer_{}; }; @@ -307,23 +305,22 @@ class Store { public: template - AccessorRO read_accessor(const Legion::Rect& bounds) const; + AccessorRO read_accessor(const Rect& bounds) const; template - AccessorWO write_accessor(const Legion::Rect& bounds) const; + AccessorWO write_accessor(const Rect& bounds) const; template - AccessorRW read_write_accessor(const Legion::Rect& bounds) const; + AccessorRW read_write_accessor(const Rect& bounds) const; template - AccessorRD reduce_accessor(const Legion::Rect& bounds) const; + AccessorRD reduce_accessor(const Rect& bounds) const; public: template - Buffer create_output_buffer(const Legion::Point& extents, - bool return_buffer = false); + Buffer create_output_buffer(const Point& extents, bool return_buffer = false); public: template - Legion::Rect shape() const; - Legion::Domain domain() const; + Rect shape() const; + Domain domain() const; public: bool is_readable() const { return readable_; } @@ -336,7 +333,7 @@ class Store { public: template - void return_data(Buffer& buffer, const Legion::Point& extents); + void return_data(Buffer& buffer, const Point& extents); void make_empty(); public: diff --git a/src/core/data/store.inl b/src/core/data/store.inl index 7dc1d38db..d3cd6e594 100644 --- a/src/core/data/store.inl +++ b/src/core/data/store.inl @@ -72,32 +72,32 @@ AccessorRD RegionField::reduce_accessor( } template -AccessorRO RegionField::read_accessor(const Legion::Rect& bounds) const +AccessorRO RegionField::read_accessor(const Rect& bounds) const { return AccessorRO(pr_, fid_, bounds); } template -AccessorWO RegionField::write_accessor(const Legion::Rect& bounds) const +AccessorWO RegionField::write_accessor(const Rect& bounds) const { return AccessorWO(pr_, fid_, bounds); } template -AccessorRW RegionField::read_write_accessor(const Legion::Rect& bounds) const +AccessorRW RegionField::read_write_accessor(const Rect& bounds) const { return AccessorRW(pr_, fid_, bounds); } template AccessorRD RegionField::reduce_accessor(int32_t redop_id, - const Legion::Rect& bounds) const + const Rect& bounds) const { return AccessorRD(pr_, fid_, redop_id, bounds); } template -AccessorRO RegionField::read_accessor(const Legion::Rect& bounds, +AccessorRO RegionField::read_accessor(const Rect& bounds, const Legion::DomainAffineTransform& transform) const { using ACC = AccessorRO; @@ -106,7 +106,7 @@ AccessorRO RegionField::read_accessor(const Legion::Rect& bounds, } template -AccessorWO RegionField::write_accessor(const Legion::Rect& bounds, +AccessorWO RegionField::write_accessor(const Rect& bounds, const Legion::DomainAffineTransform& transform) const { using ACC = AccessorWO; @@ -116,7 +116,7 @@ AccessorWO RegionField::write_accessor(const Legion::Rect& bounds, template AccessorRW RegionField::read_write_accessor( - const Legion::Rect& bounds, const Legion::DomainAffineTransform& transform) const + const Rect& bounds, const Legion::DomainAffineTransform& transform) const { using ACC = AccessorRW; return dim_dispatch( @@ -125,9 +125,7 @@ AccessorRW RegionField::read_write_accessor( template AccessorRD RegionField::reduce_accessor( - int32_t redop_id, - const Legion::Rect& bounds, - const Legion::DomainAffineTransform& transform) const + int32_t redop_id, const Rect& bounds, const Legion::DomainAffineTransform& transform) const { using ACC = AccessorRD; return dim_dispatch( @@ -135,9 +133,9 @@ AccessorRD RegionField::reduce_accessor( } template -Legion::Rect RegionField::shape() const +Rect RegionField::shape() const { - return Legion::Rect(pr_); + return Rect(pr_); } template @@ -147,7 +145,7 @@ AccessorRO FutureWrapper::read_accessor() const assert(sizeof(T) == field_size_); #endif if (read_only_) { - auto memkind = Legion::Memory::Kind::NO_MEMKIND; + auto memkind = Memory::Kind::NO_MEMKIND; return AccessorRO(future_, memkind); } else return AccessorRO(buffer_); @@ -184,20 +182,20 @@ AccessorRD FutureWrapper::reduce_accessor(int32_t redop_id) } template -AccessorRO FutureWrapper::read_accessor(const Legion::Rect& bounds) const +AccessorRO FutureWrapper::read_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE assert(sizeof(T) == field_size_); #endif if (read_only_) { - auto memkind = Legion::Memory::Kind::NO_MEMKIND; + auto memkind = Memory::Kind::NO_MEMKIND; return AccessorRO(future_, bounds, memkind); } else return AccessorRO(buffer_, bounds); } template -AccessorWO FutureWrapper::write_accessor(const Legion::Rect& bounds) const +AccessorWO FutureWrapper::write_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE assert(sizeof(T) == field_size_); @@ -207,7 +205,7 @@ AccessorWO FutureWrapper::write_accessor(const Legion::Rect& bounds } template -AccessorRW FutureWrapper::read_write_accessor(const Legion::Rect& bounds) const +AccessorRW FutureWrapper::read_write_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE assert(sizeof(T) == field_size_); @@ -218,7 +216,7 @@ AccessorRW FutureWrapper::read_write_accessor(const Legion::Rect& b template AccessorRD FutureWrapper::reduce_accessor(int32_t redop_id, - const Legion::Rect& bounds) const + const Rect& bounds) const { #ifdef DEBUG_LEGATE assert(sizeof(typename OP::LHS) == field_size_); @@ -228,9 +226,9 @@ AccessorRD FutureWrapper::reduce_accessor(int32_t redop_id, } template -Legion::Rect FutureWrapper::shape() const +Rect FutureWrapper::shape() const { - return Legion::Rect(domain()); + return Rect(domain()); } template @@ -246,7 +244,7 @@ VAL FutureWrapper::scalar() const } template -Buffer OutputRegionField::create_output_buffer(const Legion::Point& extents, +Buffer OutputRegionField::create_output_buffer(const Point& extents, bool return_buffer) { if (return_buffer) { @@ -261,7 +259,7 @@ Buffer OutputRegionField::create_output_buffer(const Legion::Point& } template -void OutputRegionField::return_data(Buffer& buffer, const Legion::Point& extents) +void OutputRegionField::return_data(Buffer& buffer, const Point& extents) { #ifdef DEBUG_LEGATE assert(!bound_); @@ -337,7 +335,7 @@ AccessorRD Store::reduce_accessor() const } template -AccessorRO Store::read_accessor(const Legion::Rect& bounds) const +AccessorRO Store::read_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE check_accessor_dimension(DIM); @@ -353,7 +351,7 @@ AccessorRO Store::read_accessor(const Legion::Rect& bounds) const } template -AccessorWO Store::write_accessor(const Legion::Rect& bounds) const +AccessorWO Store::write_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE check_accessor_dimension(DIM); @@ -369,7 +367,7 @@ AccessorWO Store::write_accessor(const Legion::Rect& bounds) const } template -AccessorRW Store::read_write_accessor(const Legion::Rect& bounds) const +AccessorRW Store::read_write_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE check_accessor_dimension(DIM); @@ -385,7 +383,7 @@ AccessorRW Store::read_write_accessor(const Legion::Rect& bounds) c } template -AccessorRD Store::reduce_accessor(const Legion::Rect& bounds) const +AccessorRD Store::reduce_accessor(const Rect& bounds) const { #ifdef DEBUG_LEGATE check_accessor_dimension(DIM); @@ -401,7 +399,7 @@ AccessorRD Store::reduce_accessor(const Legion::Rect& b } template -Buffer Store::create_output_buffer(const Legion::Point& extents, +Buffer Store::create_output_buffer(const Point& extents, bool return_buffer /*= false*/) { #ifdef DEBUG_LEGATE @@ -412,7 +410,7 @@ Buffer Store::create_output_buffer(const Legion::Point& extents, } template -Legion::Rect Store::shape() const +Rect Store::shape() const { #ifdef DEBUG_LEGATE if (!(DIM == dim_ || (dim_ == 0 && DIM == 1))) { @@ -426,8 +424,8 @@ Legion::Rect Store::shape() const if (dom.dim > 0) return dom.bounds(); else { - auto p = Legion::Point::ZEROES(); - return Legion::Rect(p, p); + auto p = Point::ZEROES(); + return Rect(p, p); } } @@ -441,7 +439,7 @@ VAL Store::scalar() const } template -void Store::return_data(Buffer& buffer, const Legion::Point& extents) +void Store::return_data(Buffer& buffer, const Point& extents) { #ifdef DEBUG_LEGATE check_valid_return(); diff --git a/src/core/data/transform.cc b/src/core/data/transform.cc index 07ab5f7ef..93d8e6956 100644 --- a/src/core/data/transform.cc +++ b/src/core/data/transform.cc @@ -18,11 +18,10 @@ namespace legate { -using namespace Legion; - -DomainAffineTransform combine(const DomainAffineTransform& lhs, const DomainAffineTransform& rhs) +Legion::DomainAffineTransform combine(const Legion::DomainAffineTransform& lhs, + const Legion::DomainAffineTransform& rhs) { - DomainAffineTransform result; + Legion::DomainAffineTransform result; auto transform = lhs.transform * rhs.transform; auto offset = lhs.transform * rhs.offset + lhs.offset; result.transform = transform; @@ -37,7 +36,7 @@ TransformStack::TransformStack(std::unique_ptr&& transform, { } -Legion::Domain TransformStack::transform(const Legion::Domain& input) const +Domain TransformStack::transform(const Domain& input) const { #ifdef DEBUG_LEGATE assert(transform_ != nullptr); @@ -100,12 +99,12 @@ Domain Shift::transform(const Domain& input) const return result; } -DomainAffineTransform Shift::inverse_transform(int32_t in_dim) const +Legion::DomainAffineTransform Shift::inverse_transform(int32_t in_dim) const { assert(dim_ < in_dim); auto out_dim = in_dim; - DomainTransform transform; + Legion::DomainTransform transform; transform.m = out_dim; transform.n = in_dim; for (int32_t i = 0; i < out_dim; ++i) @@ -116,7 +115,7 @@ DomainAffineTransform Shift::inverse_transform(int32_t in_dim) const offset.dim = out_dim; for (int32_t i = 0; i < out_dim; ++i) offset[i] = i == dim_ ? -offset_ : 0; - DomainAffineTransform result; + Legion::DomainAffineTransform result; result.transform = transform; result.offset = offset; return result; @@ -152,12 +151,12 @@ Domain Promote::transform(const Domain& input) const return output; } -DomainAffineTransform Promote::inverse_transform(int32_t in_dim) const +Legion::DomainAffineTransform Promote::inverse_transform(int32_t in_dim) const { assert(extra_dim_ < in_dim); auto out_dim = in_dim - 1; - DomainTransform transform; + Legion::DomainTransform transform; transform.m = std::max(out_dim, 1); transform.n = in_dim; for (int32_t i = 0; i < transform.m; ++i) @@ -171,7 +170,7 @@ DomainAffineTransform Promote::inverse_transform(int32_t in_dim) const offset.dim = std::max(out_dim, 1); for (int32_t i = 0; i < transform.m; ++i) offset[i] = 0; - DomainAffineTransform result; + Legion::DomainAffineTransform result; result.transform = transform; result.offset = offset; return result; @@ -202,12 +201,12 @@ Domain Project::transform(const Domain& input) const return output; } -DomainAffineTransform Project::inverse_transform(int32_t in_dim) const +Legion::DomainAffineTransform Project::inverse_transform(int32_t in_dim) const { auto out_dim = in_dim + 1; assert(dim_ < out_dim); - DomainTransform transform; + Legion::DomainTransform transform; transform.m = out_dim; if (in_dim == 0) { transform.n = out_dim; @@ -225,7 +224,7 @@ DomainAffineTransform Project::inverse_transform(int32_t in_dim) const offset.dim = out_dim; for (int32_t i = 0; i < out_dim; ++i) offset[i] = i == dim_ ? coord_ : 0; - DomainAffineTransform result; + Legion::DomainAffineTransform result; result.transform = transform; result.offset = offset; return result; @@ -254,9 +253,9 @@ Domain Transpose::transform(const Domain& input) const return output; } -DomainAffineTransform Transpose::inverse_transform(int32_t in_dim) const +Legion::DomainAffineTransform Transpose::inverse_transform(int32_t in_dim) const { - DomainTransform transform; + Legion::DomainTransform transform; transform.m = in_dim; transform.n = in_dim; for (int32_t i = 0; i < in_dim; ++i) @@ -268,7 +267,7 @@ DomainAffineTransform Transpose::inverse_transform(int32_t in_dim) const offset.dim = in_dim; for (int32_t i = 0; i < in_dim; ++i) offset[i] = 0; - DomainAffineTransform result; + Legion::DomainAffineTransform result; result.transform = transform; result.offset = offset; return result; @@ -338,9 +337,9 @@ Domain Delinearize::transform(const Domain& input) const return delinearize(dim_, sizes_.size(), strides_, input); } -DomainAffineTransform Delinearize::inverse_transform(int32_t in_dim) const +Legion::DomainAffineTransform Delinearize::inverse_transform(int32_t in_dim) const { - DomainTransform transform; + Legion::DomainTransform transform; int32_t out_dim = in_dim - strides_.size() + 1; transform.m = out_dim; transform.n = in_dim; @@ -357,7 +356,7 @@ DomainAffineTransform Delinearize::inverse_transform(int32_t in_dim) const offset.dim = out_dim; for (int32_t i = 0; i < out_dim; ++i) offset[i] = 0; - DomainAffineTransform result; + Legion::DomainAffineTransform result; result.transform = transform; result.offset = offset; return result; diff --git a/src/core/data/transform.h b/src/core/data/transform.h index fbdd2e4a8..a925b6bf0 100644 --- a/src/core/data/transform.h +++ b/src/core/data/transform.h @@ -18,12 +18,12 @@ #include -#include "legion.h" +#include "core/utilities/typedefs.h" namespace legate { struct Transform { - virtual Legion::Domain transform(const Legion::Domain& input) const = 0; + virtual Domain transform(const Domain& input) const = 0; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const = 0; virtual void print(std::ostream& out) const = 0; }; @@ -40,7 +40,7 @@ struct TransformStack : public Transform { std::shared_ptr&& parent); public: - virtual Legion::Domain transform(const Legion::Domain& input) const override; + virtual Domain transform(const Domain& input) const override; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const override; virtual void print(std::ostream& out) const override; @@ -61,7 +61,7 @@ class Shift : public StoreTransform { Shift(int32_t dim, int64_t offset); public: - virtual Legion::Domain transform(const Legion::Domain& input) const override; + virtual Domain transform(const Domain& input) const override; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const override; virtual void print(std::ostream& out) const override; @@ -78,7 +78,7 @@ class Promote : public StoreTransform { Promote(int32_t extra_dim, int64_t dim_size); public: - virtual Legion::Domain transform(const Legion::Domain& input) const override; + virtual Domain transform(const Domain& input) const override; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const override; virtual void print(std::ostream& out) const override; @@ -96,7 +96,7 @@ class Project : public StoreTransform { virtual ~Project() {} public: - virtual Legion::Domain transform(const Legion::Domain& domain) const override; + virtual Domain transform(const Domain& domain) const override; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const override; virtual void print(std::ostream& out) const override; @@ -113,7 +113,7 @@ class Transpose : public StoreTransform { Transpose(std::vector&& axes); public: - virtual Legion::Domain transform(const Legion::Domain& domain) const override; + virtual Domain transform(const Domain& domain) const override; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const override; virtual void print(std::ostream& out) const override; @@ -129,7 +129,7 @@ class Delinearize : public StoreTransform { Delinearize(int32_t dim, std::vector&& sizes); public: - virtual Legion::Domain transform(const Legion::Domain& domain) const override; + virtual Domain transform(const Domain& domain) const override; virtual Legion::DomainAffineTransform inverse_transform(int32_t in_dim) const override; virtual void print(std::ostream& out) const override; diff --git a/src/core/mapping/base_mapper.cc b/src/core/mapping/base_mapper.cc index b692ee9c0..85a2c7427 100644 --- a/src/core/mapping/base_mapper.cc +++ b/src/core/mapping/base_mapper.cc @@ -30,12 +30,6 @@ #include "core/utilities/linearize.h" #include "legate_defines.h" -using LegionTask = Legion::Task; -using LegionCopy = Legion::Copy; - -using namespace Legion; -using namespace Legion::Mapping; - namespace legate { namespace mapping { @@ -54,9 +48,9 @@ const std::vector& default_store_targets(Processor::Kind kind) return finder->second; } -std::string log_mappable(const Mappable& mappable, bool prefix_only = false) +std::string log_mappable(const Legion::Mappable& mappable, bool prefix_only = false) { - static const std::map prefixes = { + static const std::map prefixes = { {LEGION_TASK_MAPPABLE, "Task "}, {LEGION_COPY_MAPPABLE, "Copy "}, {LEGION_INLINE_MAPPABLE, "Inline mapping "}, @@ -75,20 +69,24 @@ std::string log_mappable(const Mappable& mappable, bool prefix_only = false) } // namespace -BaseMapper::BaseMapper(Runtime* rt, Machine m, const LibraryContext& ctx) +BaseMapper::BaseMapper(std::unique_ptr legate_mapper, + Legion::Runtime* rt, + Legion::Machine m, + const LibraryContext& ctx) : Mapper(rt->get_mapper_runtime()), + legate_mapper_(std::move(legate_mapper)), legion_runtime(rt), machine(m), context(ctx), local_node(get_local_node()), - total_nodes(get_total_nodes(m)), + total_nodes_(get_total_nodes(m)), mapper_name(std::move(create_name(local_node))), logger(create_logger_name().c_str()), local_instances(InstanceManager::get_instance_manager()), reduction_instances(ReductionInstanceManager::get_instance_manager()) { // Query to find all our local processors - Machine::ProcessorQuery local_procs(machine); + Legion::Machine::ProcessorQuery local_procs(machine); local_procs.local_address_space(); for (auto local_proc : local_procs) { switch (local_proc.kind()) { @@ -108,20 +106,20 @@ BaseMapper::BaseMapper(Runtime* rt, Machine m, const LibraryContext& ctx) } } // Now do queries to find all our local memories - Machine::MemoryQuery local_sysmem(machine); + Legion::Machine::MemoryQuery local_sysmem(machine); local_sysmem.local_address_space(); local_sysmem.only_kind(Memory::SYSTEM_MEM); assert(local_sysmem.count() > 0); local_system_memory = local_sysmem.first(); if (!local_gpus.empty()) { - Machine::MemoryQuery local_zcmem(machine); + Legion::Machine::MemoryQuery local_zcmem(machine); local_zcmem.local_address_space(); local_zcmem.only_kind(Memory::Z_COPY_MEM); assert(local_zcmem.count() > 0); local_zerocopy_memory = local_zcmem.first(); } for (auto& local_gpu : local_gpus) { - Machine::MemoryQuery local_framebuffer(machine); + Legion::Machine::MemoryQuery local_framebuffer(machine); local_framebuffer.local_address_space(); local_framebuffer.only_kind(Memory::GPU_FB_MEM); local_framebuffer.best_affinity_to(local_gpu); @@ -129,7 +127,7 @@ BaseMapper::BaseMapper(Runtime* rt, Machine m, const LibraryContext& ctx) local_frame_buffers[local_gpu] = local_framebuffer.first(); } for (auto& local_omp : local_omps) { - Machine::MemoryQuery local_numa(machine); + Legion::Machine::MemoryQuery local_numa(machine); local_numa.local_address_space(); local_numa.only_kind(Memory::SOCKET_MEM); local_numa.best_affinity_to(local_omp); @@ -139,9 +137,11 @@ BaseMapper::BaseMapper(Runtime* rt, Machine m, const LibraryContext& ctx) local_numa_domains[local_omp] = local_system_memory; } generate_prime_factors(); + + legate_mapper_->set_machine(this); } -BaseMapper::~BaseMapper(void) +BaseMapper::~BaseMapper() { // Compute the size of all our remaining instances in each memory const char* show_usage = getenv("LEGATE_SHOW_USAGE"); @@ -168,22 +168,22 @@ BaseMapper::~BaseMapper(void) } } -/*static*/ AddressSpace BaseMapper::get_local_node(void) +/*static*/ Legion::AddressSpace BaseMapper::get_local_node() { Processor p = Processor::get_executing_processor(); return p.address_space(); } -/*static*/ size_t BaseMapper::get_total_nodes(Machine m) +/*static*/ size_t BaseMapper::get_total_nodes(Legion::Machine m) { - Machine::ProcessorQuery query(m); + Legion::Machine::ProcessorQuery query(m); query.only_kind(Processor::LOC_PROC); - std::set spaces; + std::set spaces; for (auto proc : query) spaces.insert(proc.address_space()); return spaces.size(); } -std::string BaseMapper::create_name(AddressSpace node) const +std::string BaseMapper::create_name(Legion::AddressSpace node) const { std::stringstream ss; ss << context.get_library_name() << " on Node " << node; @@ -197,15 +197,15 @@ std::string BaseMapper::create_logger_name() const return ss.str(); } -const char* BaseMapper::get_mapper_name(void) const { return mapper_name.c_str(); } +const char* BaseMapper::get_mapper_name() const { return mapper_name.c_str(); } -Mapper::MapperSyncModel BaseMapper::get_mapper_sync_model(void) const +Legion::Mapping::Mapper::MapperSyncModel BaseMapper::get_mapper_sync_model() const { return SERIALIZED_REENTRANT_MAPPER_MODEL; } -void BaseMapper::select_task_options(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::select_task_options(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, TaskOptions& output) { #ifdef LEGATE_USE_COLLECTIVE @@ -232,27 +232,27 @@ void BaseMapper::select_task_options(const MapperContext ctx, options.push_back(TaskTarget::CPU); Task legate_task(&task, context, runtime, ctx); - auto target = task_target(legate_task, options); + auto target = legate_mapper_->task_target(legate_task, options); dispatch(target, [&output](auto& procs) { output.initial_proc = procs.front(); }); // We never want valid instances output.valid_instances = false; } -void BaseMapper::premap_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::premap_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const PremapTaskInput& input, PremapTaskOutput& output) { // NO-op since we know that all our futures should be mapped in the system memory } -void BaseMapper::slice_auto_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::slice_auto_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SliceTaskInput& input, SliceTaskOutput& output) { - ProjectionID projection = 0; + Legion::ProjectionID projection = 0; for (auto& req : task.regions) if (req.tag == LEGATE_CORE_KEY_STORE_TAG) { projection = req.projection; @@ -310,8 +310,7 @@ void BaseMapper::generate_prime_factors() if (local_cpus.size() > 0) generate_prime_factor(local_cpus, Processor::LOC_PROC); } -const std::vector BaseMapper::get_processor_grid(Legion::Processor::Kind kind, - int32_t ndim) +const std::vector BaseMapper::get_processor_grid(Processor::Kind kind, int32_t ndim) { auto key = std::make_pair(kind, ndim); auto finder = proc_grids.find(key); @@ -337,8 +336,8 @@ const std::vector BaseMapper::get_processor_grid(Legion::Processor::Kin return pitches; } -void BaseMapper::slice_manual_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::slice_manual_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SliceTaskInput& input, SliceTaskOutput& output) { @@ -358,8 +357,8 @@ void BaseMapper::slice_manual_task(const MapperContext ctx, dispatch(task.target_proc.kind(), distribute); } -void BaseMapper::slice_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::slice_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SliceTaskInput& input, SliceTaskOutput& output) { @@ -369,23 +368,25 @@ void BaseMapper::slice_task(const MapperContext ctx, slice_auto_task(ctx, task, input, output); } -bool BaseMapper::has_variant(const MapperContext ctx, const LegionTask& task, Processor::Kind kind) +bool BaseMapper::has_variant(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + Processor::Kind kind) { return find_variant(ctx, task, kind).has_value(); } -std::optional BaseMapper::find_variant(const MapperContext ctx, - const LegionTask& task, - Processor::Kind kind) +std::optional BaseMapper::find_variant(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + Processor::Kind kind) { const VariantCacheKey key(task.task_id, kind); auto finder = variants.find(key); if (finder != variants.end()) return finder->second; // Haven't seen it before so let's look it up to make sure it exists - std::vector avail_variants; + std::vector avail_variants; runtime->find_valid_variants(ctx, key.first, avail_variants, key.second); - std::optional result; + std::optional result; for (auto vid : avail_variants) { #ifdef DEBUG_LEGATE assert(vid > 0); @@ -404,13 +405,14 @@ std::optional BaseMapper::find_variant(const MapperContext ctx, return result; } -void BaseMapper::map_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::map_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const MapTaskInput& input, MapTaskOutput& output) { #ifdef DEBUG_LEGATE - logger.debug() << "Entering map_task for " << Utilities::to_string(runtime, ctx, task); + logger.debug() << "Entering map_task for " + << Legion::Mapping::Utilities::to_string(runtime, ctx, task); #endif // Should never be mapping the top-level task here @@ -429,7 +431,7 @@ void BaseMapper::map_task(const MapperContext ctx, const auto& options = default_store_targets(task.target_proc.kind()); - auto mappings = store_mappings(legate_task, options); + auto mappings = legate_mapper_->store_mappings(legate_task, options); auto validate_colocation = [this](const auto& mapping) { if (mapping.stores.empty()) { @@ -533,27 +535,28 @@ void BaseMapper::map_task(const MapperContext ctx, output.output_targets[req_idx] = get_target_memory(task.target_proc, mapping.policy.target); auto ndim = mapping.store().dim(); // FIXME: Unbound stores can have more than one dimension later - std::vector dimension_ordering; + std::vector dimension_ordering; for (int32_t dim = ndim - 1; dim >= 0; --dim) - dimension_ordering.push_back( - static_cast(static_cast(DimensionKind::LEGION_DIM_X) + dim)); - dimension_ordering.push_back(DimensionKind::LEGION_DIM_F); + dimension_ordering.push_back(static_cast( + static_cast(Legion::DimensionKind::LEGION_DIM_X) + dim)); + dimension_ordering.push_back(Legion::DimensionKind::LEGION_DIM_F); output.output_constraints[req_idx].ordering_constraint = - OrderingConstraint(dimension_ordering, false); + Legion::OrderingConstraint(dimension_ordering, false); } }; map_unbound_stores(for_unbound_stores); output.chosen_instances.resize(task.regions.size()); - std::map*> output_map; + std::map*> + output_map; for (uint32_t idx = 0; idx < task.regions.size(); ++idx) output_map[&task.regions[idx]] = &output.chosen_instances[idx]; map_legate_stores(ctx, task, for_stores, task.target_proc, output_map); } -void BaseMapper::map_replicate_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::map_replicate_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const MapTaskInput& input, const MapTaskOutput& def_output, MapReplicateTaskOutput& output) @@ -574,18 +577,18 @@ Memory BaseMapper::get_target_memory(Processor proc, StoreTarget target) return Memory::NO_MEMORY; } -void BaseMapper::map_legate_stores(const MapperContext ctx, - const Mappable& mappable, +void BaseMapper::map_legate_stores(const Legion::Mapping::MapperContext ctx, + const Legion::Mappable& mappable, std::vector& mappings, Processor target_proc, OutputMap& output_map) { auto try_mapping = [&](bool can_fail) { - const PhysicalInstance NO_INST{}; - std::vector instances; + const Legion::Mapping::PhysicalInstance NO_INST{}; + std::vector instances; for (auto& mapping : mappings) { - PhysicalInstance result = NO_INST; - auto reqs = mapping.requirements(); + Legion::Mapping::PhysicalInstance result = NO_INST; + auto reqs = mapping.requirements(); while (map_legate_store(ctx, mappable, mapping, reqs, target_proc, result, can_fail)) { if (NO_INST == result) { #ifdef DEBUG_LEGATE @@ -610,10 +613,10 @@ void BaseMapper::map_legate_stores(const MapperContext ctx, << " for reqs:" << reqs_ss.str(); #endif if ((*reqs.begin())->redop != 0) { - AutoLock lock(ctx, reduction_instances->manager_lock()); + Legion::Mapping::AutoLock lock(ctx, reduction_instances->manager_lock()); reduction_instances->erase(result); } else { - AutoLock lock(ctx, local_instances->manager_lock()); + Legion::Mapping::AutoLock lock(ctx, local_instances->manager_lock()); local_instances->erase(result); } result = NO_INST; @@ -649,14 +652,14 @@ void BaseMapper::map_legate_stores(const MapperContext ctx, } } -void BaseMapper::tighten_write_policies(const Mappable& mappable, +void BaseMapper::tighten_write_policies(const Legion::Mappable& mappable, std::vector& mappings) { for (auto& mapping : mappings) { // If the policy is exact, there's nothing we can tighten if (mapping.policy.exact) continue; - PrivilegeMode priv = LEGION_NO_ACCESS; + int32_t priv = LEGION_NO_ACCESS; for (auto* req : mapping.requirements()) priv |= req->privilege; // We tighten only write requirements if (!(priv & LEGION_WRITE_PRIV)) continue; @@ -671,22 +674,22 @@ void BaseMapper::tighten_write_policies(const Mappable& mappable, } } -bool BaseMapper::map_legate_store(const MapperContext ctx, - const Mappable& mappable, +bool BaseMapper::map_legate_store(const Legion::Mapping::MapperContext ctx, + const Legion::Mappable& mappable, const StoreMapping& mapping, - const std::set& reqs, + const std::set& reqs, Processor target_proc, - PhysicalInstance& result, + Legion::Mapping::PhysicalInstance& result, bool can_fail) { if (reqs.empty()) return false; const auto& policy = mapping.policy; - std::vector regions; + std::vector regions; for (auto* req : reqs) regions.push_back(req->region); auto target_memory = get_target_memory(target_proc, policy.target); - ReductionOpID redop = (*reqs.begin())->redop; + auto redop = (*reqs.begin())->redop; #ifdef DEBUG_LEGATE for (auto* req : reqs) { if (redop != req->redop) { @@ -699,7 +702,7 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, #endif // Generate layout constraints from the store mapping - LayoutConstraintSet layout_constraints; + Legion::LayoutConstraintSet layout_constraints; mapping.populate_layout_constraints(layout_constraints); auto& fields = layout_constraints.field_constraint.field_set; @@ -707,7 +710,7 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, if (redop != 0) { // We need to hold the instance manager lock as we're about to try // to find an instance - AutoLock reduction_lock(ctx, reduction_instances->manager_lock()); + Legion::Mapping::AutoLock reduction_lock(ctx, reduction_instances->manager_lock()); // This whole process has to appear atomic runtime->disable_reentrant(ctx); @@ -730,7 +733,8 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, } // if we didn't find it, create one - layout_constraints.add_constraint(SpecializedConstraint(REDUCTION_FOLD_SPECIALIZE, redop)); + layout_constraints.add_constraint( + Legion::SpecializedConstraint(REDUCTION_FOLD_SPECIALIZE, redop)); size_t footprint = 0; if (runtime->create_physical_instance(ctx, target_memory, @@ -745,7 +749,7 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, Realm::LoggerMessage msg = logger.debug(); msg << "Operation " << mappable.get_unique_id() << ": created reduction instance " << result << " for"; - for (LogicalRegion r : regions) msg << " " << r; + for (auto& r : regions) msg << " " << r; msg << " (size: " << footprint << " bytes, memory: " << target_memory << ")"; #endif if (target_proc.kind() == Processor::TOC_PROC) { @@ -764,7 +768,7 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, return true; } - AutoLock lock(ctx, local_instances->manager_lock()); + Legion::Mapping::AutoLock lock(ctx, local_instances->manager_lock()); runtime->disable_reentrant(ctx); // See if we already have it in our local instances if (fields.size() == 1 && regions.size() == 1 && @@ -790,7 +794,7 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, // that instance for all the tasks for the different regions. // First we have to see if there is anything we overlap with auto fid = fields.front(); - const IndexSpace is = regions.front().get_index_space(); + auto is = regions.front().get_index_space(); const Domain domain = runtime->get_index_space_domain(ctx, is); group = local_instances->find_region_group(regions.front(), domain, fid, target_memory, policy.exact); @@ -864,10 +868,10 @@ bool BaseMapper::map_legate_store(const MapperContext ctx, return true; } -void BaseMapper::report_failed_mapping(const Mappable& mappable, +void BaseMapper::report_failed_mapping(const Legion::Mappable& mappable, uint32_t index, Memory target_memory, - ReductionOpID redop) + Legion::ReductionOpID redop) { static const char* memory_kinds[] = { #define MEM_NAMES(name, desc) desc, @@ -876,7 +880,7 @@ void BaseMapper::report_failed_mapping(const Mappable& mappable, }; std::string opname = ""; - if (mappable.get_mappable_type() == Mappable::TASK_MAPPABLE) { + if (mappable.get_mappable_type() == Legion::Mappable::TASK_MAPPABLE) { const auto task = mappable.as_task(); opname = task->get_task_name(); } @@ -902,8 +906,8 @@ void BaseMapper::report_failed_mapping(const Mappable& mappable, LEGATE_ABORT; } -void BaseMapper::select_task_variant(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::select_task_variant(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectVariantInput& input, SelectVariantOutput& output) { @@ -914,8 +918,8 @@ void BaseMapper::select_task_variant(const MapperContext ctx, output.chosen_variant = *variant; } -void BaseMapper::postmap_task(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::postmap_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const PostMapInput& input, PostMapOutput& output) { @@ -923,8 +927,8 @@ void BaseMapper::postmap_task(const MapperContext ctx, LEGATE_ABORT; } -void BaseMapper::select_task_sources(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::select_task_sources(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectTaskSrcInput& input, SelectTaskSrcOutput& output) { @@ -932,17 +936,18 @@ void BaseMapper::select_task_sources(const MapperContext ctx, ctx, input.target, input.source_instances, input.collective_views, output.chosen_ranking); } -void add_instance_to_band_ranking(const PhysicalInstance& instance, - const Legion::AddressSpace& local_node, - std::map& source_memories, - std::vector>& band_ranking, - const Memory& destination_memory, - const Legion::Machine& machine) +void add_instance_to_band_ranking( + const Legion::Mapping::PhysicalInstance& instance, + const Legion::AddressSpace& local_node, + std::map& source_memories, + std::vector>& band_ranking, + const Memory& destination_memory, + const Legion::Machine& machine) { Memory location = instance.get_location(); auto finder = source_memories.find(location); if (finder == source_memories.end()) { - std::vector affinity; + std::vector affinity; machine.get_mem_mem_affinity( affinity, location, destination_memory, false /*not just local affinities*/); uint32_t memory_bandwidth = 0; @@ -953,16 +958,19 @@ void add_instance_to_band_ranking(const PhysicalInstance& instance, memory_bandwidth = affinity[0].bandwidth; } source_memories[location] = memory_bandwidth; - band_ranking.push_back(std::pair(instance, memory_bandwidth)); + band_ranking.push_back( + std::pair(instance, memory_bandwidth)); } else - band_ranking.push_back(std::pair(instance, finder->second)); + band_ranking.push_back( + std::pair(instance, finder->second)); } -void BaseMapper::legate_select_sources(const MapperContext ctx, - const PhysicalInstance& target, - const std::vector& sources, - const std::vector& collective_sources, - std::deque& ranking) +void BaseMapper::legate_select_sources( + const Legion::Mapping::MapperContext ctx, + const Legion::Mapping::PhysicalInstance& target, + const std::vector& sources, + const std::vector& collective_sources, + std::deque& ranking) { std::map source_memories; // For right now we'll rank instances by the bandwidth of the memory @@ -970,22 +978,22 @@ void BaseMapper::legate_select_sources(const MapperContext ctx, // TODO: consider layouts when ranking source to help out the DMA system Memory destination_memory = target.get_location(); // fill in a vector of the sources with their bandwidths and sort them - std::vector> band_ranking; + std::vector> band_ranking; for (uint32_t idx = 0; idx < sources.size(); idx++) { - const PhysicalInstance& instance = sources[idx]; + const Legion::Mapping::PhysicalInstance& instance = sources[idx]; add_instance_to_band_ranking( instance, local_node, source_memories, band_ranking, destination_memory, machine); } for (uint32_t idx = 0; idx < collective_sources.size(); idx++) { - std::vector col_instances; + std::vector col_instances; collective_sources[idx].find_instances_nearest_memory(destination_memory, col_instances); #ifdef DEBUG_LEGATE // there must exist at least one instance in the collective view assert(!col_instances.empty()); #endif // we need only first instance if there are several - const PhysicalInstance& instance = col_instances[0]; + const Legion::Mapping::PhysicalInstance& instance = col_instances[0]; add_instance_to_band_ranking( instance, local_node, source_memories, band_ranking, destination_memory, machine); } @@ -1004,25 +1012,25 @@ void BaseMapper::legate_select_sources(const MapperContext ctx, ranking.push_back(it->first); } -void BaseMapper::speculate(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::speculate(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, SpeculativeOutput& output) { output.speculate = false; } -void BaseMapper::report_profiling(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const TaskProfilingInfo& input) { // Shouldn't get any profiling feedback currently LEGATE_ABORT; } -ShardingID BaseMapper::find_sharding_functor_by_key_store_projection( - const std::vector& requirements) +Legion::ShardingID BaseMapper::find_sharding_functor_by_key_store_projection( + const std::vector& requirements) { - ProjectionID proj_id = 0; + Legion::ProjectionID proj_id = 0; for (auto& requirement : requirements) if (LEGATE_CORE_KEY_STORE_TAG == requirement.tag) { proj_id = requirement.projection; @@ -1031,8 +1039,8 @@ ShardingID BaseMapper::find_sharding_functor_by_key_store_projection( return find_sharding_functor_by_projection_functor(proj_id); } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { @@ -1041,8 +1049,8 @@ void BaseMapper::select_sharding_functor(const MapperContext ctx, : find_sharding_functor_by_projection_functor(0); } -void BaseMapper::map_inline(const MapperContext ctx, - const InlineMapping& inline_op, +void BaseMapper::map_inline(const Legion::Mapping::MapperContext ctx, + const Legion::InlineMapping& inline_op, const MapInlineInput& input, MapInlineOutput& output) { @@ -1062,14 +1070,15 @@ void BaseMapper::map_inline(const MapperContext ctx, std::vector mappings; mappings.push_back(StoreMapping::default_mapping(store, store_target, false)); - std::map*> output_map; + std::map*> + output_map; for (auto* req : mappings.front().requirements()) output_map[req] = &output.chosen_instances; map_legate_stores(ctx, inline_op, mappings, target_proc, output_map); } -void BaseMapper::select_inline_sources(const MapperContext ctx, - const InlineMapping& inline_op, +void BaseMapper::select_inline_sources(const Legion::Mapping::MapperContext ctx, + const Legion::InlineMapping& inline_op, const SelectInlineSrcInput& input, SelectInlineSrcOutput& output) { @@ -1077,16 +1086,16 @@ void BaseMapper::select_inline_sources(const MapperContext ctx, ctx, input.target, input.source_instances, input.collective_views, output.chosen_ranking); } -void BaseMapper::report_profiling(const MapperContext ctx, - const InlineMapping& inline_op, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::InlineMapping& inline_op, const InlineProfilingInfo& input) { // No profiling yet for inline mappings LEGATE_ABORT; } -void BaseMapper::map_copy(const MapperContext ctx, - const LegionCopy& copy, +void BaseMapper::map_copy(const Legion::Mapping::MapperContext ctx, + const Legion::Copy& copy, const MapCopyInput& input, MapCopyOutput& output) { @@ -1128,7 +1137,8 @@ void BaseMapper::map_copy(const MapperContext ctx, Copy legate_copy(©, runtime, ctx); - std::map*> output_map; + std::map*> + output_map; auto add_to_output_map = [&output_map](auto& reqs, auto& instances) { instances.resize(reqs.size()); for (uint32_t idx = 0; idx < reqs.size(); ++idx) output_map[&reqs[idx]] = &instances[idx]; @@ -1165,8 +1175,8 @@ void BaseMapper::map_copy(const MapperContext ctx, map_legate_stores(ctx, copy, mappings, target_proc, output_map); } -void BaseMapper::select_copy_sources(const MapperContext ctx, - const LegionCopy& copy, +void BaseMapper::select_copy_sources(const Legion::Mapping::MapperContext ctx, + const Legion::Copy& copy, const SelectCopySrcInput& input, SelectCopySrcOutput& output) { @@ -1174,23 +1184,23 @@ void BaseMapper::select_copy_sources(const MapperContext ctx, ctx, input.target, input.source_instances, input.collective_views, output.chosen_ranking); } -void BaseMapper::speculate(const MapperContext ctx, - const LegionCopy& copy, +void BaseMapper::speculate(const Legion::Mapping::MapperContext ctx, + const Legion::Copy& copy, SpeculativeOutput& output) { output.speculate = false; } -void BaseMapper::report_profiling(const MapperContext ctx, - const LegionCopy& copy, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::Copy& copy, const CopyProfilingInfo& input) { // No profiling for copies yet LEGATE_ABORT; } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const LegionCopy& copy, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Copy& copy, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { @@ -1198,8 +1208,8 @@ void BaseMapper::select_sharding_functor(const MapperContext ctx, output.chosen_functor = find_sharding_functor_by_projection_functor(0); } -void BaseMapper::select_close_sources(const MapperContext ctx, - const Close& close, +void BaseMapper::select_close_sources(const Legion::Mapping::MapperContext ctx, + const Legion::Close& close, const SelectCloseSrcInput& input, SelectCloseSrcOutput& output) { @@ -1207,63 +1217,63 @@ void BaseMapper::select_close_sources(const MapperContext ctx, ctx, input.target, input.source_instances, input.collective_views, output.chosen_ranking); } -void BaseMapper::report_profiling(const MapperContext ctx, - const Close& close, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::Close& close, const CloseProfilingInfo& input) { // No profiling yet for legate LEGATE_ABORT; } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const Close& close, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Close& close, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { LEGATE_ABORT; } -void BaseMapper::map_acquire(const MapperContext ctx, - const Acquire& acquire, +void BaseMapper::map_acquire(const Legion::Mapping::MapperContext ctx, + const Legion::Acquire& acquire, const MapAcquireInput& input, MapAcquireOutput& output) { // Nothing to do } -void BaseMapper::speculate(const MapperContext ctx, - const Acquire& acquire, +void BaseMapper::speculate(const Legion::Mapping::MapperContext ctx, + const Legion::Acquire& acquire, SpeculativeOutput& output) { output.speculate = false; } -void BaseMapper::report_profiling(const MapperContext ctx, - const Acquire& acquire, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::Acquire& acquire, const AcquireProfilingInfo& input) { // No profiling for legate yet LEGATE_ABORT; } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const Acquire& acquire, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Acquire& acquire, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { LEGATE_ABORT; } -void BaseMapper::map_release(const MapperContext ctx, - const Release& release, +void BaseMapper::map_release(const Legion::Mapping::MapperContext ctx, + const Legion::Release& release, const MapReleaseInput& input, MapReleaseOutput& output) { // Nothing to do } -void BaseMapper::select_release_sources(const MapperContext ctx, - const Release& release, +void BaseMapper::select_release_sources(const Legion::Mapping::MapperContext ctx, + const Legion::Release& release, const SelectReleaseSrcInput& input, SelectReleaseSrcOutput& output) { @@ -1271,31 +1281,31 @@ void BaseMapper::select_release_sources(const MapperContext ctx, ctx, input.target, input.source_instances, input.collective_views, output.chosen_ranking); } -void BaseMapper::speculate(const MapperContext ctx, - const Release& release, +void BaseMapper::speculate(const Legion::Mapping::MapperContext ctx, + const Legion::Release& release, SpeculativeOutput& output) { output.speculate = false; } -void BaseMapper::report_profiling(const MapperContext ctx, - const Release& release, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::Release& release, const ReleaseProfilingInfo& input) { // No profiling for legate yet LEGATE_ABORT; } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const Release& release, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Release& release, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { LEGATE_ABORT; } -void BaseMapper::select_partition_projection(const MapperContext ctx, - const Partition& partition, +void BaseMapper::select_partition_projection(const Legion::Mapping::MapperContext ctx, + const Legion::Partition& partition, const SelectPartitionProjectionInput& input, SelectPartitionProjectionOutput& output) { @@ -1303,11 +1313,11 @@ void BaseMapper::select_partition_projection(const MapperContext ctx, if (!input.open_complete_partitions.empty()) output.chosen_partition = input.open_complete_partitions[0]; else - output.chosen_partition = LogicalPartition::NO_PART; + output.chosen_partition = Legion::LogicalPartition::NO_PART; } -void BaseMapper::map_partition(const MapperContext ctx, - const Partition& partition, +void BaseMapper::map_partition(const Legion::Mapping::MapperContext ctx, + const Legion::Partition& partition, const MapPartitionInput& input, MapPartitionOutput& output) { @@ -1327,14 +1337,15 @@ void BaseMapper::map_partition(const MapperContext ctx, std::vector mappings; mappings.push_back(StoreMapping::default_mapping(store, store_target, false)); - std::map*> output_map; + std::map*> + output_map; for (auto* req : mappings.front().requirements()) output_map[req] = &output.chosen_instances; map_legate_stores(ctx, partition, mappings, target_proc, output_map); } -void BaseMapper::select_partition_sources(const MapperContext ctx, - const Partition& partition, +void BaseMapper::select_partition_sources(const Legion::Mapping::MapperContext ctx, + const Legion::Partition& partition, const SelectPartitionSrcInput& input, SelectPartitionSrcOutput& output) { @@ -1342,24 +1353,24 @@ void BaseMapper::select_partition_sources(const MapperContext ctx, ctx, input.target, input.source_instances, input.collective_views, output.chosen_ranking); } -void BaseMapper::report_profiling(const MapperContext ctx, - const Partition& partition, +void BaseMapper::report_profiling(const Legion::Mapping::MapperContext ctx, + const Legion::Partition& partition, const PartitionProfilingInfo& input) { // No profiling yet LEGATE_ABORT; } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const Partition& partition, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Partition& partition, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { output.chosen_functor = find_sharding_functor_by_projection_functor(0); } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const Fill& fill, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Fill& fill, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { @@ -1368,26 +1379,26 @@ void BaseMapper::select_sharding_functor(const MapperContext ctx, : find_sharding_functor_by_projection_functor(0); } -void BaseMapper::configure_context(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::configure_context(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, ContextConfigOutput& output) { // Use the defaults currently } -void BaseMapper::select_tunable_value(const MapperContext ctx, - const LegionTask& task, +void BaseMapper::select_tunable_value(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectTunableInput& input, SelectTunableOutput& output) { - auto value = tunable_value(input.tunable_id); + auto value = legate_mapper_->tunable_value(input.tunable_id); output.size = value.size(); output.value = malloc(output.size); memcpy(output.value, value.ptr(), output.size); } -void BaseMapper::select_sharding_functor(const MapperContext ctx, - const MustEpoch& epoch, +void BaseMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::MustEpoch& epoch, const SelectShardingFunctorInput& input, MustEpochShardingFunctorOutput& output) { @@ -1395,15 +1406,15 @@ void BaseMapper::select_sharding_functor(const MapperContext ctx, LEGATE_ABORT; } -void BaseMapper::memoize_operation(const MapperContext ctx, - const Mappable& mappable, +void BaseMapper::memoize_operation(const Legion::Mapping::MapperContext ctx, + const Legion::Mappable& mappable, const MemoizeInput& input, MemoizeOutput& output) { LEGATE_ABORT; } -void BaseMapper::map_must_epoch(const MapperContext ctx, +void BaseMapper::map_must_epoch(const Legion::Mapping::MapperContext ctx, const MapMustEpochInput& input, MapMustEpochOutput& output) { @@ -1411,7 +1422,7 @@ void BaseMapper::map_must_epoch(const MapperContext ctx, LEGATE_ABORT; } -void BaseMapper::map_dataflow_graph(const MapperContext ctx, +void BaseMapper::map_dataflow_graph(const Legion::Mapping::MapperContext ctx, const MapDataflowGraphInput& input, MapDataflowGraphOutput& output) { @@ -1419,7 +1430,7 @@ void BaseMapper::map_dataflow_graph(const MapperContext ctx, LEGATE_ABORT; } -void BaseMapper::select_tasks_to_map(const MapperContext ctx, +void BaseMapper::select_tasks_to_map(const Legion::Mapping::MapperContext ctx, const SelectMappingInput& input, SelectMappingOutput& output) { @@ -1427,14 +1438,14 @@ void BaseMapper::select_tasks_to_map(const MapperContext ctx, for (auto task : input.ready_tasks) output.map_tasks.insert(task); } -void BaseMapper::select_steal_targets(const MapperContext ctx, +void BaseMapper::select_steal_targets(const Legion::Mapping::MapperContext ctx, const SelectStealingInput& input, SelectStealingOutput& output) { // Nothing to do, no stealing in the leagte mapper currently } -void BaseMapper::permit_steal_request(const MapperContext ctx, +void BaseMapper::permit_steal_request(const Legion::Mapping::MapperContext ctx, const StealRequestInput& input, StealRequestOutput& output) { @@ -1442,13 +1453,15 @@ void BaseMapper::permit_steal_request(const MapperContext ctx, LEGATE_ABORT; } -void BaseMapper::handle_message(const MapperContext ctx, const MapperMessage& message) +void BaseMapper::handle_message(const Legion::Mapping::MapperContext ctx, + const MapperMessage& message) { // We shouldn't be receiving any messages currently LEGATE_ABORT; } -void BaseMapper::handle_task_result(const MapperContext ctx, const MapperTaskResult& result) +void BaseMapper::handle_task_result(const Legion::Mapping::MapperContext ctx, + const MapperTaskResult& result) { // Nothing to do since we should never get one of these LEGATE_ABORT; diff --git a/src/core/mapping/base_mapper.h b/src/core/mapping/base_mapper.h index 86e558e0b..32d6ca2cb 100644 --- a/src/core/mapping/base_mapper.h +++ b/src/core/mapping/base_mapper.h @@ -38,10 +38,13 @@ enum class Strictness : bool { hint = false, }; -class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { +class BaseMapper : public Legion::Mapping::Mapper, public MachineQueryInterface { public: - BaseMapper(Legion::Runtime* rt, Legion::Machine machine, const LibraryContext& context); - virtual ~BaseMapper(void); + BaseMapper(std::unique_ptr legate_mapper, + Legion::Runtime* rt, + Legion::Machine machine, + const LibraryContext& context); + virtual ~BaseMapper(); private: BaseMapper(const BaseMapper& rhs) = delete; @@ -49,15 +52,22 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { protected: // Start-up methods - static Legion::AddressSpaceID get_local_node(void); + static Legion::AddressSpaceID get_local_node(); static size_t get_total_nodes(Legion::Machine m); std::string create_name(Legion::AddressSpace node) const; std::string create_logger_name() const; public: - virtual const char* get_mapper_name(void) const override; - virtual Legion::Mapping::Mapper::MapperSyncModel get_mapper_sync_model(void) const override; - virtual bool request_valid_instances(void) const override { return false; } + // MachineQueryInterface + virtual const std::vector& cpus() const override { return local_cpus; } + virtual const std::vector& gpus() const override { return local_gpus; } + virtual const std::vector& omps() const override { return local_omps; } + virtual uint32_t total_nodes() const override { return total_nodes_; } + + public: + virtual const char* get_mapper_name() const override; + virtual Legion::Mapping::Mapper::MapperSyncModel get_mapper_sync_model() const override; + virtual bool request_valid_instances() const override { return false; } public: // Task mapping calls virtual void select_task_options(const Legion::Mapping::MapperContext ctx, @@ -257,13 +267,13 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { const MapperTaskResult& result) override; protected: - Legion::Memory get_target_memory(Legion::Processor proc, StoreTarget target); + Memory get_target_memory(Processor proc, StoreTarget target); using OutputMap = std::map*>; void map_legate_stores(const Legion::Mapping::MapperContext ctx, const Legion::Mappable& mappable, std::vector& mappings, - Legion::Processor target_proc, + Processor target_proc, OutputMap& output_map); void tighten_write_policies(const Legion::Mappable& mappable, std::vector& mappings); @@ -271,12 +281,12 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { const Legion::Mappable& mappable, const StoreMapping& mapping, const std::set& reqs, - Legion::Processor target_proc, + Processor target_proc, Legion::Mapping::PhysicalInstance& result, bool can_fail); void report_failed_mapping(const Legion::Mappable& mappable, unsigned index, - Legion::Memory target_memory, + Memory target_memory, Legion::ReductionOpID redop); void legate_select_sources(const Legion::Mapping::MapperContext ctx, const Legion::Mapping::PhysicalInstance& target, @@ -287,15 +297,14 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { protected: bool has_variant(const Legion::Mapping::MapperContext ctx, const Legion::Task& task, - Legion::Processor::Kind kind); + Processor::Kind kind); std::optional find_variant(const Legion::Mapping::MapperContext ctx, const Legion::Task& task, - Legion::Processor::Kind kind); + Processor::Kind kind); private: void generate_prime_factors(); - void generate_prime_factor(const std::vector& processors, - Legion::Processor::Kind kind); + void generate_prime_factor(const std::vector& processors, Processor::Kind kind); protected: template @@ -310,12 +319,12 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { return functor(local_cpus); } template - decltype(auto) dispatch(Legion::Processor::Kind kind, Functor functor) + decltype(auto) dispatch(Processor::Kind kind, Functor functor) { switch (kind) { - case Legion::Processor::LOC_PROC: return functor(local_cpus); - case Legion::Processor::TOC_PROC: return functor(local_gpus); - case Legion::Processor::OMP_PROC: return functor(local_omps); + case Processor::LOC_PROC: return functor(local_cpus); + case Processor::TOC_PROC: return functor(local_gpus); + case Processor::OMP_PROC: return functor(local_omps); default: LEGATE_ABORT; } assert(false); @@ -323,7 +332,7 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { } protected: - const std::vector get_processor_grid(Legion::Processor::Kind kind, int32_t ndim); + const std::vector get_processor_grid(Processor::Kind kind, int32_t ndim); void slice_auto_task(const Legion::Mapping::MapperContext ctx, const Legion::Task& task, const SliceTaskInput& input, @@ -344,28 +353,30 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { { return (left.second < right.second); } - // NumPyOpCode decode_task_id(Legion::TaskID tid); + + private: + std::unique_ptr legate_mapper_; public: Legion::Runtime* const legion_runtime; const Legion::Machine machine; const LibraryContext context; const Legion::AddressSpace local_node; - const size_t total_nodes; const std::string mapper_name; Legion::Logger logger; protected: - std::vector local_cpus; - std::vector local_gpus; - std::vector local_omps; // OpenMP processors + const size_t total_nodes_; + std::vector local_cpus; + std::vector local_gpus; + std::vector local_omps; // OpenMP processors protected: - Legion::Memory local_system_memory, local_zerocopy_memory; - std::map local_frame_buffers; - std::map local_numa_domains; + Memory local_system_memory, local_zerocopy_memory; + std::map local_frame_buffers; + std::map local_numa_domains; protected: - using VariantCacheKey = std::pair; + using VariantCacheKey = std::pair; std::map> variants; protected: @@ -374,8 +385,8 @@ class BaseMapper : public Legion::Mapping::Mapper, public LegateMapper { protected: // Used for n-D cyclic distribution - std::map> all_factors; - std::map, std::vector> proc_grids; + std::map> all_factors; + std::map, std::vector> proc_grids; protected: // These are used for computing sharding functions diff --git a/src/core/mapping/core_mapper.cc b/src/core/mapping/core_mapper.cc index bb9389108..0d09e3c7d 100644 --- a/src/core/mapping/core_mapper.cc +++ b/src/core/mapping/core_mapper.cc @@ -24,12 +24,10 @@ #endif #include "core/task/task.h" #include "core/utilities/linearize.h" +#include "core/utilities/typedefs.h" namespace legate { -using namespace Legion; -using namespace Legion::Mapping; - uint32_t extract_env(const char* env_name, const uint32_t default_value, const uint32_t test_value) { const char* env_value = getenv(env_name); @@ -48,61 +46,65 @@ uint32_t extract_env(const char* env_name, const uint32_t default_value, const u // should be overriding this mapper so we burry it in here class CoreMapper : public Legion::Mapping::NullMapper { public: - CoreMapper(MapperRuntime* runtime, Machine machine, const LibraryContext& context); - virtual ~CoreMapper(void); + CoreMapper(Legion::Mapping::MapperRuntime* runtime, + Legion::Machine machine, + const LibraryContext& context); + virtual ~CoreMapper(); public: // Start-up methods - static AddressSpaceID get_local_node(void); - static size_t get_total_nodes(Machine m); - static const char* create_name(AddressSpace node); + static Legion::AddressSpaceID get_local_node(); + static size_t get_total_nodes(Legion::Machine m); + static const char* create_name(Legion::AddressSpace node); public: - virtual const char* get_mapper_name(void) const; - virtual MapperSyncModel get_mapper_sync_model(void) const; - virtual bool request_valid_instances(void) const { return false; } + virtual const char* get_mapper_name() const override; + virtual Legion::Mapping::Mapper::MapperSyncModel get_mapper_sync_model() const override; + virtual bool request_valid_instances() const { return false; } public: // Task mapping calls - virtual void select_task_options(const MapperContext ctx, const Task& task, TaskOptions& output); - virtual void slice_task(const MapperContext ctx, - const Task& task, + virtual void select_task_options(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + TaskOptions& output); + virtual void slice_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SliceTaskInput& input, SliceTaskOutput& output); - virtual void map_task(const MapperContext ctx, - const Task& task, + virtual void map_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const MapTaskInput& input, MapTaskOutput& output); - virtual void select_sharding_functor(const MapperContext ctx, - const Task& task, + virtual void select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output); - virtual void select_steal_targets(const MapperContext ctx, + virtual void select_steal_targets(const Legion::Mapping::MapperContext ctx, const SelectStealingInput& input, SelectStealingOutput& output); - virtual void select_tasks_to_map(const MapperContext ctx, + virtual void select_tasks_to_map(const Legion::Mapping::MapperContext ctx, const SelectMappingInput& input, SelectMappingOutput& output); public: - virtual void configure_context(const MapperContext ctx, - const Task& task, + virtual void configure_context(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, ContextConfigOutput& output); - void map_future_map_reduction(const MapperContext ctx, + void map_future_map_reduction(const Legion::Mapping::MapperContext ctx, const FutureMapReductionInput& input, FutureMapReductionOutput& output); - virtual void select_tunable_value(const MapperContext ctx, - const Task& task, + virtual void select_tunable_value(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectTunableInput& input, SelectTunableOutput& output); protected: template - decltype(auto) dispatch(Legion::Processor::Kind kind, Functor functor) + decltype(auto) dispatch(Processor::Kind kind, Functor functor) { switch (kind) { - case Legion::Processor::LOC_PROC: return functor(local_cpus); - case Legion::Processor::TOC_PROC: return functor(local_gpus); - case Legion::Processor::OMP_PROC: return functor(local_omps); + case Processor::LOC_PROC: return functor(local_cpus); + case Processor::TOC_PROC: return functor(local_gpus); + case Processor::OMP_PROC: return functor(local_omps); default: LEGATE_ABORT; } assert(false); @@ -110,7 +112,7 @@ class CoreMapper : public Legion::Mapping::NullMapper { } public: - const AddressSpace local_node; + const Legion::AddressSpace local_node; const size_t total_nodes; const char* const mapper_name; LibraryContext context; @@ -138,7 +140,9 @@ class CoreMapper : public Legion::Mapping::NullMapper { std::map local_numa_domains; }; -CoreMapper::CoreMapper(MapperRuntime* rt, Machine m, const LibraryContext& c) +CoreMapper::CoreMapper(Legion::Mapping::MapperRuntime* rt, + Legion::Machine m, + const LibraryContext& c) : NullMapper(rt, m), local_node(get_local_node()), total_nodes(get_total_nodes(m)), @@ -164,9 +168,10 @@ CoreMapper::CoreMapper(MapperRuntime* rt, Machine m, const LibraryContext& c) has_socket_mem(false) { // Query to find all our local processors - Machine::ProcessorQuery local_procs(machine); + Legion::Machine::ProcessorQuery local_procs(machine); local_procs.local_address_space(); - for (Machine::ProcessorQuery::iterator it = local_procs.begin(); it != local_procs.end(); it++) { + for (Legion::Machine::ProcessorQuery::iterator it = local_procs.begin(); it != local_procs.end(); + it++) { switch (it->kind()) { case Processor::LOC_PROC: { local_cpus.push_back(*it); @@ -184,20 +189,20 @@ CoreMapper::CoreMapper(MapperRuntime* rt, Machine m, const LibraryContext& c) } } // Now do queries to find all our local memories - Machine::MemoryQuery local_sysmem(machine); + Legion::Machine::MemoryQuery local_sysmem(machine); local_sysmem.local_address_space(); local_sysmem.only_kind(Memory::SYSTEM_MEM); assert(local_sysmem.count() > 0); local_system_memory = local_sysmem.first(); if (!local_gpus.empty()) { - Machine::MemoryQuery local_zcmem(machine); + Legion::Machine::MemoryQuery local_zcmem(machine); local_zcmem.local_address_space(); local_zcmem.only_kind(Memory::Z_COPY_MEM); assert(local_zcmem.count() > 0); local_zerocopy_memory = local_zcmem.first(); } for (auto local_gpu : local_gpus) { - Machine::MemoryQuery local_framebuffer(machine); + Legion::Machine::MemoryQuery local_framebuffer(machine); local_framebuffer.local_address_space(); local_framebuffer.only_kind(Memory::GPU_FB_MEM); local_framebuffer.best_affinity_to(local_gpu); @@ -205,7 +210,7 @@ CoreMapper::CoreMapper(MapperRuntime* rt, Machine m, const LibraryContext& c) local_frame_buffers[local_gpu] = local_framebuffer.first(); } for (auto local_omp : local_omps) { - Machine::MemoryQuery local_numa(machine); + Legion::Machine::MemoryQuery local_numa(machine); local_numa.local_address_space(); local_numa.only_kind(Memory::SOCKET_MEM); local_numa.best_affinity_to(local_omp); @@ -218,39 +223,40 @@ CoreMapper::CoreMapper(MapperRuntime* rt, Machine m, const LibraryContext& c) } } -CoreMapper::~CoreMapper(void) { free(const_cast(mapper_name)); } +CoreMapper::~CoreMapper() { free(const_cast(mapper_name)); } -/*static*/ AddressSpace CoreMapper::get_local_node(void) +/*static*/ Legion::AddressSpace CoreMapper::get_local_node() { Processor p = Processor::get_executing_processor(); return p.address_space(); } -/*static*/ size_t CoreMapper::get_total_nodes(Machine m) +/*static*/ size_t CoreMapper::get_total_nodes(Legion::Machine m) { - Machine::ProcessorQuery query(m); + Legion::Machine::ProcessorQuery query(m); query.only_kind(Processor::LOC_PROC); - std::set spaces; - for (Machine::ProcessorQuery::iterator it = query.begin(); it != query.end(); it++) - spaces.insert(it->address_space()); + std::set spaces; + for (auto it = query.begin(); it != query.end(); it++) spaces.insert(it->address_space()); return spaces.size(); } -/*static*/ const char* CoreMapper::create_name(AddressSpace node) +/*static*/ const char* CoreMapper::create_name(Legion::AddressSpace node) { char buffer[128]; snprintf(buffer, 127, "Legate Mapper on Node %d", node); return strdup(buffer); } -const char* CoreMapper::get_mapper_name(void) const { return mapper_name; } +const char* CoreMapper::get_mapper_name() const { return mapper_name; } -Mapper::MapperSyncModel CoreMapper::get_mapper_sync_model(void) const +Legion::Mapping::Mapper::MapperSyncModel CoreMapper::get_mapper_sync_model() const { return SERIALIZED_REENTRANT_MAPPER_MODEL; } -void CoreMapper::select_task_options(const MapperContext ctx, const Task& task, TaskOptions& output) +void CoreMapper::select_task_options(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + TaskOptions& output) { assert(context.valid_task_id(task.task_id)); if (task.tag == LEGATE_CPU_VARIANT) { @@ -266,8 +272,8 @@ void CoreMapper::select_task_options(const MapperContext ctx, const Task& task, } } -void CoreMapper::slice_task(const MapperContext ctx, - const Task& task, +void CoreMapper::slice_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SliceTaskInput& input, SliceTaskOutput& output) { @@ -291,8 +297,8 @@ void CoreMapper::slice_task(const MapperContext ctx, dispatch(task.target_proc.kind(), round_robin); } -void CoreMapper::map_task(const MapperContext ctx, - const Task& task, +void CoreMapper::map_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const MapTaskInput& input, MapTaskOutput& output) { @@ -302,8 +308,8 @@ void CoreMapper::map_task(const MapperContext ctx, output.chosen_variant = task.tag; } -void CoreMapper::select_sharding_functor(const MapperContext ctx, - const Task& task, +void CoreMapper::select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectShardingFunctorInput& input, SelectShardingFunctorOutput& output) { @@ -314,29 +320,29 @@ void CoreMapper::select_sharding_functor(const MapperContext ctx, output.chosen_functor = context.get_sharding_id(LEGATE_CORE_TOPLEVEL_TASK_SHARD_ID); } -void CoreMapper::select_steal_targets(const MapperContext ctx, +void CoreMapper::select_steal_targets(const Legion::Mapping::MapperContext ctx, const SelectStealingInput& input, SelectStealingOutput& output) { // Do nothing } -void CoreMapper::select_tasks_to_map(const MapperContext ctx, +void CoreMapper::select_tasks_to_map(const Legion::Mapping::MapperContext ctx, const SelectMappingInput& input, SelectMappingOutput& output) { output.map_tasks.insert(input.ready_tasks.begin(), input.ready_tasks.end()); } -void CoreMapper::configure_context(const MapperContext ctx, - const Task& task, +void CoreMapper::configure_context(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, ContextConfigOutput& output) { // Use the defaults currently } template -void pack_tunable(const T value, Mapper::SelectTunableOutput& output) +void pack_tunable(const T value, Legion::Mapping::Mapper::SelectTunableOutput& output) { T* result = static_cast(malloc(sizeof(value))); *result = value; @@ -344,7 +350,7 @@ void pack_tunable(const T value, Mapper::SelectTunableOutput& output) output.size = sizeof(value); } -void CoreMapper::map_future_map_reduction(const MapperContext ctx, +void CoreMapper::map_future_map_reduction(const Legion::Mapping::MapperContext ctx, const FutureMapReductionInput& input, FutureMapReductionOutput& output) { @@ -368,8 +374,8 @@ void CoreMapper::map_future_map_reduction(const MapperContext ctx, for (auto& pair : local_numa_domains) output.destination_memories.push_back(pair.second); } -void CoreMapper::select_tunable_value(const MapperContext ctx, - const Task& task, +void CoreMapper::select_tunable_value(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, const SelectTunableInput& input, SelectTunableOutput& output) { @@ -468,7 +474,9 @@ void CoreMapper::select_tunable_value(const MapperContext ctx, LEGATE_ABORT; } -void register_legate_core_mapper(Machine machine, Runtime* runtime, const LibraryContext& context) +void register_legate_core_mapper(Legion::Machine machine, + Legion::Runtime* runtime, + const LibraryContext& context) { // Replace all the default mappers with our custom mapper for the Legate // top-level task and init task diff --git a/src/core/mapping/instance_manager.cc b/src/core/mapping/instance_manager.cc index f732b0b79..c4416cd83 100644 --- a/src/core/mapping/instance_manager.cc +++ b/src/core/mapping/instance_manager.cc @@ -20,9 +20,6 @@ namespace legate { namespace mapping { -using namespace Legion; -using namespace Legion::Mapping; - using RegionGroupP = std::shared_ptr; static Legion::Logger log_instmgr("instmgr"); @@ -37,9 +34,9 @@ RegionGroup::RegionGroup(std::set&& rs, const Domain bound) { } -std::vector RegionGroup::get_regions() const +std::vector RegionGroup::get_regions() const { - std::vector result; + std::vector result; result.insert(result.end(), regions.begin(), regions.end()); return std::move(result); } @@ -106,7 +103,7 @@ static inline bool too_big(size_t union_volume, struct construct_overlapping_region_group_fn { template RegionGroupP operator()(const InstanceSet::Region& region, - const InstanceSet::Domain& domain, + const Domain& domain, const std::map& instances) { auto bound = domain.bounds(); @@ -159,7 +156,7 @@ struct construct_overlapping_region_group_fn { bound_vol = union_vol; } - return std::make_shared(std::move(regions), InstanceSet::Domain(bound)); + return std::make_shared(std::move(regions), Domain(bound)); } }; @@ -241,7 +238,7 @@ std::set InstanceSet::record_instance(RegionGroupP group, return std::move(replaced); } -bool InstanceSet::erase(PhysicalInstance inst) +bool InstanceSet::erase(Instance inst) { std::set filtered_groups; #ifdef DEBUG_LEGATE @@ -333,7 +330,7 @@ void ReductionInstanceSet::record_instance(ReductionOpID& redop, } } -bool ReductionInstanceSet::erase(PhysicalInstance inst) +bool ReductionInstanceSet::erase(Instance inst) { for (auto it = instances_.begin(); it != instances_.end(); /*nothing*/) { if (it->second.instance == inst) { @@ -390,7 +387,7 @@ std::set InstanceManager::record_instance( return instance_sets_[key].record_instance(group, instance, policy); } -void InstanceManager::erase(PhysicalInstance inst) +void InstanceManager::erase(Instance inst) { const auto mem = inst.get_location(); const auto tid = inst.get_tree_id(); @@ -408,9 +405,9 @@ void InstanceManager::erase(PhysicalInstance inst) } } -std::map InstanceManager::aggregate_instance_sizes() const +std::map InstanceManager::aggregate_instance_sizes() const { - std::map result; + std::map result; for (auto& pair : instance_sets_) { auto& memory = pair.first.memory; if (result.find(memory) == result.end()) result[memory] = 0; @@ -459,7 +456,7 @@ void ReductionInstanceManager::record_instance(ReductionOpID& redop, } } -void ReductionInstanceManager::erase(PhysicalInstance inst) +void ReductionInstanceManager::erase(Instance inst) { const auto mem = inst.get_location(); const auto tid = inst.get_tree_id(); diff --git a/src/core/mapping/instance_manager.h b/src/core/mapping/instance_manager.h index c42df3119..35a49befb 100644 --- a/src/core/mapping/instance_manager.h +++ b/src/core/mapping/instance_manager.h @@ -30,7 +30,6 @@ namespace mapping { struct RegionGroup { public: using Region = Legion::LogicalRegion; - using Domain = Legion::Domain; public: RegionGroup(const std::set& regions, const Domain bounding_box); @@ -56,7 +55,6 @@ struct InstanceSet { public: using Region = Legion::LogicalRegion; using Instance = Legion::Mapping::PhysicalInstance; - using Domain = Legion::Domain; using RegionGroupP = std::shared_ptr; public: @@ -99,7 +97,6 @@ class ReductionInstanceSet { public: using Region = Legion::LogicalRegion; using Instance = Legion::Mapping::PhysicalInstance; - using Domain = Legion::Domain; using ReductionOpID = Legion::ReductionOpID; public: @@ -141,9 +138,7 @@ class BaseInstanceManager { using Region = Legion::LogicalRegion; using RegionTreeID = Legion::RegionTreeID; using Instance = Legion::Mapping::PhysicalInstance; - using Domain = Legion::Domain; using FieldID = Legion::FieldID; - using Memory = Legion::Memory; public: struct FieldMemInfo { @@ -206,7 +201,7 @@ class InstanceManager : public BaseInstanceManager { static InstanceManager* get_instance_manager(); public: - std::map aggregate_instance_sizes() const; + std::map aggregate_instance_sizes() const; private: std::map instance_sets_{}; diff --git a/src/core/mapping/mapping.cc b/src/core/mapping/mapping.cc index 5d1aa971c..3e092708d 100644 --- a/src/core/mapping/mapping.cc +++ b/src/core/mapping/mapping.cc @@ -20,8 +20,6 @@ #include "core/mapping/mapping.h" -using namespace Legion; - namespace legate { namespace mapping { @@ -44,7 +42,7 @@ bool DimOrdering::operator==(const DimOrdering& other) const } void DimOrdering::populate_dimension_ordering(const Store& store, - std::vector& ordering) const + std::vector& ordering) const { // TODO: We need to implement the relative dimension ordering assert(!relative); @@ -52,17 +50,17 @@ void DimOrdering::populate_dimension_ordering(const Store& store, case Kind::C: { auto dim = store.region_field().dim(); for (int32_t idx = dim - 1; idx >= 0; --idx) - ordering.push_back(static_cast(DIM_X + idx)); + ordering.push_back(static_cast(DIM_X + idx)); break; } case Kind::FORTRAN: { auto dim = store.region_field().dim(); for (int32_t idx = 0; idx < dim; ++idx) - ordering.push_back(static_cast(DIM_X + idx)); + ordering.push_back(static_cast(DIM_X + idx)); break; } case Kind::CUSTOM: { - for (auto idx : dims) ordering.push_back(static_cast(DIM_X + idx)); + for (auto idx : dims) ordering.push_back(static_cast(DIM_X + idx)); break; } } @@ -92,15 +90,16 @@ bool InstanceMappingPolicy::operator!=(const InstanceMappingPolicy& other) const void InstanceMappingPolicy::populate_layout_constraints( const Store& store, Legion::LayoutConstraintSet& layout_constraints) const { - std::vector dimension_ordering{}; + std::vector dimension_ordering{}; if (layout == InstLayout::AOS) dimension_ordering.push_back(DIM_F); ordering.populate_dimension_ordering(store, dimension_ordering); if (layout == InstLayout::SOA) dimension_ordering.push_back(DIM_F); - layout_constraints.add_constraint(OrderingConstraint(dimension_ordering, false /*contiguous*/)); + layout_constraints.add_constraint( + Legion::OrderingConstraint(dimension_ordering, false /*contiguous*/)); - layout_constraints.add_constraint(MemoryConstraint(get_memory_kind(target))); + layout_constraints.add_constraint(Legion::MemoryConstraint(get_memory_kind(target))); } /*static*/ InstanceMappingPolicy InstanceMappingPolicy::default_policy(StoreTarget target, @@ -160,9 +159,9 @@ std::set StoreMapping::requirement_indices() const return std::move(indices); } -std::set StoreMapping::requirements() const +std::set StoreMapping::requirements() const { - std::set reqs; + std::set reqs; for (auto& store : stores) { if (store.is_future()) continue; auto* req = store.region_field().get_requirement(); @@ -177,9 +176,9 @@ void StoreMapping::populate_layout_constraints( { policy.populate_layout_constraints(stores.front(), layout_constraints); - std::vector fields{}; + std::vector fields{}; if (stores.size() > 1) { - std::set field_set{}; + std::set field_set{}; for (auto& store : stores) { auto field_id = store.region_field().field_id(); if (field_set.find(field_id) == field_set.end()) { @@ -189,7 +188,7 @@ void StoreMapping::populate_layout_constraints( } } else fields.push_back(stores.front().region_field().field_id()); - layout_constraints.add_constraint(FieldConstraint(fields, true /*contiguous*/)); + layout_constraints.add_constraint(Legion::FieldConstraint(fields, true /*contiguous*/)); } /*static*/ StoreMapping StoreMapping::default_mapping(const Store& store, diff --git a/src/core/mapping/mapping.h b/src/core/mapping/mapping.h index 2d56d1a67..bb1b92b3c 100644 --- a/src/core/mapping/mapping.h +++ b/src/core/mapping/mapping.h @@ -17,6 +17,7 @@ #pragma once #include "core/mapping/operation.h" +#include "core/utilities/typedefs.h" namespace legate { namespace mapping { @@ -108,7 +109,8 @@ struct InstanceMappingPolicy { bool operator==(const InstanceMappingPolicy&) const; bool operator!=(const InstanceMappingPolicy&) const; - public: + private: + friend class StoreMapping; void populate_layout_constraints(const Store& store, Legion::LayoutConstraintSet& layout_constraints) const; @@ -142,15 +144,23 @@ struct StoreMapping { std::set requirement_indices() const; std::set requirements() const; - public: + private: + friend class BaseMapper; void populate_layout_constraints(Legion::LayoutConstraintSet& layout_constraints) const; public: static StoreMapping default_mapping(const Store& store, StoreTarget target, bool exact = false); }; +struct MachineQueryInterface { + virtual const std::vector& cpus() const = 0; + virtual const std::vector& gpus() const = 0; + virtual const std::vector& omps() const = 0; + virtual uint32_t total_nodes() const = 0; +}; + struct LegateMapper { - virtual bool is_pure() const = 0; + virtual void set_machine(const MachineQueryInterface* machine) = 0; virtual TaskTarget task_target(const Task& task, const std::vector& options) = 0; virtual std::vector store_mappings(const Task& task, const std::vector& options) = 0; diff --git a/src/core/mapping/operation.cc b/src/core/mapping/operation.cc index 03f34d5b2..fb6826ac6 100644 --- a/src/core/mapping/operation.cc +++ b/src/core/mapping/operation.cc @@ -20,13 +20,10 @@ namespace legate { namespace mapping { -using LegionTask = Legion::Task; -using LegionCopy = Legion::Copy; - -using namespace Legion; -using namespace Legion::Mapping; - -RegionField::RegionField(const RegionRequirement* req, int32_t dim, uint32_t idx, FieldID fid) +RegionField::RegionField(const Legion::RegionRequirement* req, + int32_t dim, + uint32_t idx, + Legion::FieldID fid) : req_(req), dim_(dim), idx_(idx), fid_(fid) { } @@ -38,12 +35,13 @@ bool RegionField::can_colocate_with(const RegionField& other) const return my_req->region.get_tree_id() == other_req->region.get_tree_id(); } -Domain RegionField::domain(MapperRuntime* runtime, const MapperContext context) const +Domain RegionField::domain(Legion::Mapping::MapperRuntime* runtime, + const Legion::Mapping::MapperContext context) const { return runtime->get_index_space_domain(context, get_index_space()); } -IndexSpace RegionField::get_index_space() const { return req_->region.get_index_space(); } +Legion::IndexSpace RegionField::get_index_space() const { return req_->region.get_index_space(); } FutureWrapper::FutureWrapper(uint32_t idx, const Domain& domain) : idx_(idx), domain_(domain) {} @@ -139,10 +137,10 @@ Domain Store::domain() const return result; } -Task::Task(const LegionTask* task, +Task::Task(const Legion::Task* task, const LibraryContext& library, - MapperRuntime* runtime, - const MapperContext context) + Legion::Mapping::MapperRuntime* runtime, + const Legion::Mapping::MapperContext context) : task_(task), library_(library) { TaskDeserializer dez(task, runtime, context); @@ -154,7 +152,9 @@ Task::Task(const LegionTask* task, int64_t Task::task_id() const { return library_.get_local_task_id(task_->task_id); } -Copy::Copy(const LegionCopy* copy, MapperRuntime* runtime, const MapperContext context) +Copy::Copy(const Legion::Copy* copy, + Legion::Mapping::MapperRuntime* runtime, + const Legion::Mapping::MapperContext context) : copy_(copy) { CopyDeserializer dez(copy->mapper_data, diff --git a/src/core/mapping/operation.h b/src/core/mapping/operation.h index 0cc5dc267..fb84fe27c 100644 --- a/src/core/mapping/operation.h +++ b/src/core/mapping/operation.h @@ -43,12 +43,12 @@ class RegionField { public: template - Legion::Rect shape(Legion::Mapping::MapperRuntime* runtime, - const Legion::Mapping::MapperContext context) const; + Rect shape(Legion::Mapping::MapperRuntime* runtime, + const Legion::Mapping::MapperContext context) const; public: - Legion::Domain domain(Legion::Mapping::MapperRuntime* runtime, - const Legion::Mapping::MapperContext context) const; + Domain domain(Legion::Mapping::MapperRuntime* runtime, + const Legion::Mapping::MapperContext context) const; public: bool operator==(const RegionField& other) const; @@ -76,7 +76,7 @@ class RegionField { class FutureWrapper { public: FutureWrapper() {} - FutureWrapper(uint32_t idx, const Legion::Domain& domain); + FutureWrapper(uint32_t idx, const Domain& domain); public: FutureWrapper(const FutureWrapper& other) = default; @@ -88,12 +88,12 @@ class FutureWrapper { public: template - Legion::Rect shape() const; - Legion::Domain domain() const; + Rect shape() const; + Domain domain() const; private: uint32_t idx_{-1U}; - Legion::Domain domain_{}; + Domain domain_{}; }; class Store { @@ -131,7 +131,7 @@ class Store { public: bool is_reduction() const { return redop_id_ > 0; } - Legion::ReductionOpID redop() const { return redop_id_; } + int32_t redop() const { return redop_id_; } public: bool can_colocate_with(const Store& other) const; @@ -145,10 +145,10 @@ class Store { public: template - Legion::Rect shape() const; + Rect shape() const; public: - Legion::Domain domain() const; + Domain domain() const; private: bool is_future_{false}; @@ -186,7 +186,7 @@ class Task { const std::vector& scalars() const { return scalars_; } public: - Legion::DomainPoint point() const { return task_->index_point; } + DomainPoint point() const { return task_->index_point; } private: const LibraryContext& library_; @@ -210,7 +210,7 @@ class Copy { const std::vector& output_indirections() const { return output_indirections_; } public: - Legion::DomainPoint point() const { return copy_->index_point; } + DomainPoint point() const { return copy_->index_point; } private: const Legion::Copy* copy_; diff --git a/src/core/runtime/context.cc b/src/core/runtime/context.cc index c482ae3aa..f696c101b 100644 --- a/src/core/runtime/context.cc +++ b/src/core/runtime/context.cc @@ -32,24 +32,22 @@ namespace legate { -LibraryContext::LibraryContext(Legion::Runtime* runtime, - const std::string& library_name, - const ResourceConfig& config) - : runtime_(runtime), library_name_(library_name) +LibraryContext::LibraryContext(const std::string& library_name, const ResourceConfig& config) + : runtime_(Legion::Runtime::get_runtime()), library_name_(library_name) { task_scope_ = ResourceScope( - runtime->generate_library_task_ids(library_name.c_str(), config.max_tasks), config.max_tasks); + runtime_->generate_library_task_ids(library_name.c_str(), config.max_tasks), config.max_tasks); mapper_scope_ = - ResourceScope(runtime->generate_library_mapper_ids(library_name.c_str(), config.max_mappers), + ResourceScope(runtime_->generate_library_mapper_ids(library_name.c_str(), config.max_mappers), config.max_mappers); redop_scope_ = ResourceScope( - runtime->generate_library_reduction_ids(library_name.c_str(), config.max_reduction_ops), + runtime_->generate_library_reduction_ids(library_name.c_str(), config.max_reduction_ops), config.max_reduction_ops); proj_scope_ = ResourceScope( - runtime->generate_library_projection_ids(library_name.c_str(), config.max_projections), + runtime_->generate_library_projection_ids(library_name.c_str(), config.max_projections), config.max_projections); shard_scope_ = ResourceScope( - runtime->generate_library_sharding_ids(library_name.c_str(), config.max_shardings), + runtime_->generate_library_sharding_ids(library_name.c_str(), config.max_shardings), config.max_shardings); } @@ -148,13 +146,15 @@ bool LibraryContext::valid_sharding_id(Legion::ShardingID shard_id) const return shard_scope_.in_scope(shard_id); } -void LibraryContext::register_mapper(mapping::BaseMapper* mapper, int64_t local_mapper_id) const +void LibraryContext::register_mapper(std::unique_ptr mapper, + int64_t local_mapper_id) const { - auto mapper_id = get_mapper_id(local_mapper_id); + auto base_mapper = new legate::mapping::BaseMapper( + std::move(mapper), runtime_, Realm::Machine::get_machine(), *this); + Legion::Mapping::Mapper* legion_mapper = base_mapper; if (Core::log_mapping_decisions) - runtime_->add_mapper(mapper_id, new Legion::Mapping::LoggingWrapper(mapper, &mapper->logger)); - else - runtime_->add_mapper(mapper_id, mapper); + legion_mapper = new Legion::Mapping::LoggingWrapper(base_mapper, &base_mapper->logger); + runtime_->add_mapper(get_mapper_id(local_mapper_id), legion_mapper); } TaskContext::TaskContext(const Legion::Task* task, @@ -203,7 +203,7 @@ TaskContext::TaskContext(const Legion::Task* task, #ifdef LEGATE_USE_CUDA // If the task is running on a GPU and there is at least one scalar store for reduction, // we need to wait for all the host-to-device copies for initialization to finish - if (Legion::Processor::get_executing_processor().kind() == Legion::Processor::Kind::TOC_PROC) + if (Processor::get_executing_processor().kind() == Processor::Kind::TOC_PROC) for (auto& reduction : reductions_) if (reduction.is_future()) { CHECK_CUDA(cudaDeviceSynchronize()); @@ -214,9 +214,9 @@ TaskContext::TaskContext(const Legion::Task* task, bool TaskContext::is_single_task() const { return !task_->is_index_space; } -Legion::DomainPoint TaskContext::get_task_index() const { return task_->index_point; } +DomainPoint TaskContext::get_task_index() const { return task_->index_point; } -Legion::Domain TaskContext::get_launch_domain() const { return task_->index_domain; } +Domain TaskContext::get_launch_domain() const { return task_->index_domain; } void TaskContext::make_all_unbound_stores_empty() { diff --git a/src/core/runtime/context.h b/src/core/runtime/context.h index b387b4979..2a0c7624a 100644 --- a/src/core/runtime/context.h +++ b/src/core/runtime/context.h @@ -16,16 +16,21 @@ #pragma once +#include + #include "legion.h" +// Must be included after legion.h +#include "legate_defines.h" #include "core/comm/communicator.h" #include "core/task/return.h" +#include "core/utilities/typedefs.h" namespace legate { namespace mapping { -class BaseMapper; +class LegateMapper; } // namespace mapping @@ -70,9 +75,7 @@ class ResourceScope { class LibraryContext { public: - LibraryContext(Legion::Runtime* runtime, - const std::string& library_name, - const ResourceConfig& config); + LibraryContext(const std::string& library_name, const ResourceConfig& config); public: LibraryContext(const LibraryContext&) = default; @@ -102,7 +105,10 @@ class LibraryContext { bool valid_sharding_id(Legion::ShardingID shard_id) const; public: - void register_mapper(mapping::BaseMapper* mapper, int64_t local_mapper_id = 0) const; + template + void register_reduction_operator(); + void register_mapper(std::unique_ptr mapper, + int64_t local_mapper_id = 0) const; private: Legion::Runtime* runtime_; @@ -133,8 +139,8 @@ class TaskContext { public: bool is_single_task() const; bool can_raise_exception() const { return can_raise_exception_; } - Legion::DomainPoint get_task_index() const; - Legion::Domain get_launch_domain() const; + DomainPoint get_task_index() const; + Domain get_launch_domain() const; public: void make_all_unbound_stores_empty(); @@ -159,3 +165,5 @@ class TaskContext { }; } // namespace legate + +#include "core/runtime/context.inl" diff --git a/src/core/runtime/context.inl b/src/core/runtime/context.inl new file mode 100644 index 000000000..e847b5bf1 --- /dev/null +++ b/src/core/runtime/context.inl @@ -0,0 +1,76 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "core/runtime/context.h" + +namespace legate { + +#ifndef REALM_COMPILER_IS_NVCC + +#ifdef LEGATE_USE_CUDA +extern Legion::Logger log_legate; +#endif + +template +void LibraryContext::register_reduction_operator() +{ +#ifdef LEGATE_USE_CUDA + log_legate.error("Reduction operators must be registered in a .cu file when CUDA is enabled"); + LEGATE_ABORT; +#endif + Legion::Runtime::register_reduction_op(get_reduction_op_id(REDOP::REDOP_ID)); +} + +#else // ifndef REALM_COMPILER_IS_NVCC + +namespace detail { + +template +class CUDAReductionOpWrapper : public T { + public: + static const bool has_cuda_reductions = true; + + template + __device__ static void apply_cuda(typename T::LHS& lhs, typename T::RHS rhs) + { + T::template apply(lhs, rhs); + } + + template + __device__ static void fold_cuda(typename T::LHS& lhs, typename T::RHS rhs) + { + T::template fold(lhs, rhs); + } +}; + +} // namespace detail + +template +void LibraryContext::register_reduction_operator() +{ + Legion::Runtime::register_reduction_op( + get_reduction_op_id(REDOP::REDOP_ID), + Realm::ReductionOpUntyped::create_reduction_op>(), + nullptr, + nullptr, + false); +} + +#endif // ifndef REALM_COMPILER_IS_NVCC + +} // namespace legate diff --git a/src/core/runtime/projection.cc b/src/core/runtime/projection.cc index 9392cd051..c45794d68 100644 --- a/src/core/runtime/projection.cc +++ b/src/core/runtime/projection.cc @@ -22,36 +22,33 @@ #include "core/runtime/projection.h" #include "core/utilities/dispatch.h" +#include "core/utilities/typedefs.h" #include "legate_defines.h" -using namespace Legion; - namespace legate { -extern Logger log_legate; - // This special functor overrides the default projection implementation because it needs // to know the the target color space for delinearization. Also note that this functor's // project_point passes through input points, as we already know they are always 1D points // and the output will be linearized back to integers. class DelinearizationFunctor : public LegateProjectionFunctor { public: - DelinearizationFunctor(Runtime* runtime); + DelinearizationFunctor(Legion::Runtime* runtime); public: virtual Legion::LogicalRegion project(Legion::LogicalPartition upper_bound, - const Legion::DomainPoint& point, - const Legion::Domain& launch_domain) override; + const DomainPoint& point, + const Domain& launch_domain) override; public: - virtual Legion::DomainPoint project_point(const Legion::DomainPoint& point, - const Legion::Domain& launch_domain) const override; + virtual DomainPoint project_point(const DomainPoint& point, + const Domain& launch_domain) const override; }; template class AffineFunctor : public LegateProjectionFunctor { public: - AffineFunctor(Runtime* runtime, int32_t* dims, int32_t* weights, int32_t* offsets); + AffineFunctor(Legion::Runtime* runtime, int32_t* dims, int32_t* weights, int32_t* offsets); public: DomainPoint project_point(const DomainPoint& point, const Domain& launch_domain) const override; @@ -64,26 +61,27 @@ class AffineFunctor : public LegateProjectionFunctor { Point offsets_; }; -LegateProjectionFunctor::LegateProjectionFunctor(Runtime* rt) : ProjectionFunctor(rt) {} +LegateProjectionFunctor::LegateProjectionFunctor(Legion::Runtime* rt) : ProjectionFunctor(rt) {} -LogicalRegion LegateProjectionFunctor::project(LogicalPartition upper_bound, - const DomainPoint& point, - const Domain& launch_domain) +Legion::LogicalRegion LegateProjectionFunctor::project(Legion::LogicalPartition upper_bound, + const DomainPoint& point, + const Domain& launch_domain) { const DomainPoint dp = project_point(point, launch_domain); if (runtime->has_logical_subregion_by_color(upper_bound, dp)) return runtime->get_logical_subregion_by_color(upper_bound, dp); else - return LogicalRegion::NO_REGION; + return Legion::LogicalRegion::NO_REGION; } -DelinearizationFunctor::DelinearizationFunctor(Runtime* runtime) : LegateProjectionFunctor(runtime) +DelinearizationFunctor::DelinearizationFunctor(Legion::Runtime* runtime) + : LegateProjectionFunctor(runtime) { } -LogicalRegion DelinearizationFunctor::project(LogicalPartition upper_bound, - const DomainPoint& point, - const Domain& launch_domain) +Legion::LogicalRegion DelinearizationFunctor::project(Legion::LogicalPartition upper_bound, + const DomainPoint& point, + const Domain& launch_domain) { const auto color_space = runtime->get_index_partition_color_space(upper_bound.get_index_partition()); @@ -108,17 +106,17 @@ LogicalRegion DelinearizationFunctor::project(LogicalPartition upper_bound, if (runtime->has_logical_subregion_by_color(upper_bound, delinearized)) return runtime->get_logical_subregion_by_color(upper_bound, delinearized); else - return LogicalRegion::NO_REGION; + return Legion::LogicalRegion::NO_REGION; } -Legion::DomainPoint DelinearizationFunctor::project_point(const Legion::DomainPoint& point, - const Legion::Domain& launch_domain) const +DomainPoint DelinearizationFunctor::project_point(const DomainPoint& point, + const Domain& launch_domain) const { return point; } template -AffineFunctor::AffineFunctor(Runtime* runtime, +AffineFunctor::AffineFunctor(Legion::Runtime* runtime, int32_t* dims, int32_t* weights, int32_t* offsets) @@ -170,7 +168,7 @@ template } struct IdentityFunctor : public LegateProjectionFunctor { - IdentityFunctor(Runtime* runtime) : LegateProjectionFunctor(runtime) {} + IdentityFunctor(Legion::Runtime* runtime) : LegateProjectionFunctor(runtime) {} DomainPoint project_point(const DomainPoint& point, const Domain&) const override { return point; @@ -178,7 +176,7 @@ struct IdentityFunctor : public LegateProjectionFunctor { }; static LegateProjectionFunctor* identity_functor{nullptr}; -static std::unordered_map functor_table{}; +static std::unordered_map functor_table{}; static std::mutex functor_table_lock{}; struct create_affine_functor_fn { @@ -218,8 +216,11 @@ struct create_affine_functor_fn { } template - void operator()( - Runtime* runtime, int32_t* dims, int32_t* weights, int32_t* offsets, ProjectionID proj_id) + void operator()(Legion::Runtime* runtime, + int32_t* dims, + int32_t* weights, + int32_t* offsets, + Legion::ProjectionID proj_id) { auto functor = new AffineFunctor(runtime, dims, weights, offsets); #ifdef DEBUG_LEGATE @@ -251,7 +252,8 @@ void register_legate_core_projection_functors(Legion::Runtime* runtime, identity_functor = new IdentityFunctor(runtime); } -LegateProjectionFunctor* find_legate_projection_functor(ProjectionID proj_id, bool allow_missing) +LegateProjectionFunctor* find_legate_projection_functor(Legion::ProjectionID proj_id, + bool allow_missing) { if (0 == proj_id) return identity_functor; const std::lock_guard lock(functor_table_lock); @@ -264,7 +266,7 @@ LegateProjectionFunctor* find_legate_projection_functor(ProjectionID proj_id, bo return result; } -struct LinearizingPointTransformFunctor : public PointTransformFunctor { +struct LinearizingPointTransformFunctor : public Legion::PointTransformFunctor { // This is actually an invertible functor, but we will not use this for inversion virtual bool is_invertible(void) const { return false; } @@ -300,7 +302,7 @@ void legate_register_affine_projection_functor(int32_t src_ndim, int32_t* offsets, legion_projection_id_t proj_id) { - auto runtime = Runtime::get_runtime(); + auto runtime = Legion::Runtime::get_runtime(); legate::double_dispatch(src_ndim, tgt_ndim, legate::create_affine_functor_fn{}, diff --git a/src/core/runtime/projection.h b/src/core/runtime/projection.h index cf74d1689..4eb2bb1ad 100644 --- a/src/core/runtime/projection.h +++ b/src/core/runtime/projection.h @@ -19,6 +19,7 @@ #include "legion.h" #include "core/runtime/context.h" +#include "core/utilities/typedefs.h" namespace legate { @@ -30,8 +31,8 @@ class LegateProjectionFunctor : public Legion::ProjectionFunctor { public: using Legion::ProjectionFunctor::project; virtual Legion::LogicalRegion project(Legion::LogicalPartition upper_bound, - const Legion::DomainPoint& point, - const Legion::Domain& launch_domain); + const DomainPoint& point, + const Domain& launch_domain); public: // legate projection functors are almost always functional and don't traverse the region tree @@ -42,8 +43,8 @@ class LegateProjectionFunctor : public Legion::ProjectionFunctor { void set_collective() { is_collective_ = true; } public: - virtual Legion::DomainPoint project_point(const Legion::DomainPoint& point, - const Legion::Domain& launch_domain) const = 0; + virtual DomainPoint project_point(const DomainPoint& point, + const Domain& launch_domain) const = 0; private: bool is_collective_ = false; diff --git a/src/core/runtime/runtime.cc b/src/core/runtime/runtime.cc index 27e14a7da..dbc34030b 100644 --- a/src/core/runtime/runtime.cc +++ b/src/core/runtime/runtime.cc @@ -23,12 +23,11 @@ #include "core/task/task.h" #include "core/utilities/deserializer.h" #include "core/utilities/machine.h" +#include "core/utilities/nvtx_help.h" #include "legate.h" namespace legate { -using namespace Legion; - Logger log_legate("legate"); // This is the unique string name for our library which can be used @@ -95,7 +94,7 @@ static void extract_scalar_task( Legion::Runtime* runtime; Legion::Runtime::legion_task_preamble(args, arglen, p, task, regions, legion_context, runtime); - Core::show_progress(task, legion_context, runtime, task->get_task_name()); + Core::show_progress(task, legion_context, runtime); TaskContext context(task, *regions, legion_context, runtime); auto idx = context.scalars()[0].value(); @@ -112,50 +111,73 @@ static void extract_scalar_task( /*static*/ void Core::show_progress(const Legion::Task* task, Legion::Context ctx, - Legion::Runtime* runtime, - const char* task_name) + Legion::Runtime* runtime) { if (!Core::show_progress_requested) return; const auto exec_proc = runtime->get_executing_processor(ctx); - const auto proc_kind_str = (exec_proc.kind() == Legion::Processor::LOC_PROC) ? "CPU" - : (exec_proc.kind() == Legion::Processor::TOC_PROC) ? "GPU" - : "OpenMP"; + const auto proc_kind_str = (exec_proc.kind() == Processor::LOC_PROC) ? "CPU" + : (exec_proc.kind() == Processor::TOC_PROC) ? "GPU" + : "OpenMP"; std::stringstream point_str; const auto& point = task->index_point; point_str << point[0]; - for (int32_t dim = 1; dim < task->index_point.dim; ++dim) point_str << "," << point[dim]; + for (int32_t dim = 1; dim < point.dim; ++dim) point_str << "," << point[dim]; log_legate.print("%s %s task [%s], pt = (%s), proc = " IDFMT, - task_name, + task->get_task_name(), proc_kind_str, task->get_provenance_string().c_str(), point_str.str().c_str(), exec_proc.id); } -/*static*/ void Core::report_unexpected_exception(const char* task_name, +/*static*/ void Core::report_unexpected_exception(const Legion::Task* task, const legate::TaskException& e) { log_legate.error( "Task %s threw an exception \"%s\", but the task did not declare any exception. " "Please specify a Python exception that you want this exception to be re-thrown with " "using 'throws_exception'.", - task_name, + task->get_task_name(), e.error_message().c_str()); LEGATE_ABORT; } -void register_legate_core_tasks(Machine machine, Runtime* runtime, const LibraryContext& context) +namespace detail { + +struct RegistrationCallbackArgs { + Core::RegistrationCallback callback; +}; + +static void invoke_legate_registration_callback(const Legion::RegistrationCallbackArgs& args) +{ + auto p_args = static_cast(args.buffer.get_ptr()); + p_args->callback(); +}; + +} // namespace detail + +/*static*/ void Core::perform_registration(RegistrationCallback callback) +{ + legate::detail::RegistrationCallbackArgs args{callback}; + Legion::UntypedBuffer buffer(&args, sizeof(args)); + Legion::Runtime::perform_registration_callback( + detail::invoke_legate_registration_callback, buffer, true /*global*/); +} + +void register_legate_core_tasks(Legion::Machine machine, + Legion::Runtime* runtime, + const LibraryContext& context) { - const TaskID extract_scalar_task_id = context.get_task_id(LEGATE_CORE_EXTRACT_SCALAR_TASK_ID); + auto extract_scalar_task_id = context.get_task_id(LEGATE_CORE_EXTRACT_SCALAR_TASK_ID); const char* extract_scalar_task_name = "core::extract_scalar"; runtime->attach_name( extract_scalar_task_id, extract_scalar_task_name, false /*mutable*/, true /*local only*/); auto make_registrar = [&](auto task_id, auto* task_name, auto proc_kind) { - TaskVariantRegistrar registrar(task_id, task_name); - registrar.add_constraint(ProcessorConstraint(proc_kind)); + Legion::TaskVariantRegistrar registrar(task_id, task_name); + registrar.add_constraint(Legion::ProcessorConstraint(proc_kind)); registrar.set_leaf(true); registrar.global_registration = false; return registrar; @@ -178,10 +200,11 @@ void register_legate_core_tasks(Machine machine, Runtime* runtime, const Library comm::register_tasks(machine, runtime, context); } -extern void register_exception_reduction_op(Runtime* runtime, const LibraryContext& context); +extern void register_exception_reduction_op(Legion::Runtime* runtime, + const LibraryContext& context); -/*static*/ void core_registration_callback(Machine machine, - Runtime* runtime, +/*static*/ void core_registration_callback(Legion::Machine machine, + Legion::Runtime* runtime, const std::set& local_procs) { ResourceConfig config; @@ -190,7 +213,7 @@ extern void register_exception_reduction_op(Runtime* runtime, const LibraryConte // We register one sharding functor for each new projection functor config.max_shardings = LEGATE_CORE_MAX_FUNCTOR_ID; config.max_reduction_ops = LEGATE_CORE_MAX_REDUCTION_OP_ID; - LibraryContext context(runtime, core_library_name, config); + LibraryContext context(core_library_name, config); register_legate_core_tasks(machine, runtime, context); @@ -203,7 +226,7 @@ extern void register_exception_reduction_op(Runtime* runtime, const LibraryConte register_legate_core_sharding_functors(runtime, context); auto fut = runtime->select_tunable_value( - Runtime::get_context(), LEGATE_CORE_TUNABLE_HAS_SOCKET_MEM, context.get_mapper_id(0)); + Legion::Runtime::get_context(), LEGATE_CORE_TUNABLE_HAS_SOCKET_MEM, context.get_mapper_id(0)); Core::has_socket_mem = fut.get_result(); } diff --git a/src/core/runtime/runtime.h b/src/core/runtime/runtime.h index b7b86c836..723582cc6 100644 --- a/src/core/runtime/runtime.h +++ b/src/core/runtime/runtime.h @@ -27,15 +27,18 @@ extern uint32_t extract_env(const char* env_name, const uint32_t default_value, const uint32_t test_value); -class Core { +struct Core { public: static void parse_config(void); static void shutdown(void); static void show_progress(const Legion::Task* task, Legion::Context ctx, - Legion::Runtime* runtime, - const char* task_name); - static void report_unexpected_exception(const char* task_name, const legate::TaskException& e); + Legion::Runtime* runtime); + static void report_unexpected_exception(const Legion::Task* task, const legate::TaskException& e); + + public: + using RegistrationCallback = void (*)(); + static void perform_registration(RegistrationCallback callback); public: // Configuration settings diff --git a/src/core/runtime/shard.cc b/src/core/runtime/shard.cc index eca6a7775..db2e74434 100644 --- a/src/core/runtime/shard.cc +++ b/src/core/runtime/shard.cc @@ -23,16 +23,16 @@ #include "core/runtime/shard.h" #include "core/utilities/linearize.h" -using namespace Legion; - namespace legate { -static std::unordered_map functor_id_table; +static std::unordered_map functor_id_table; static std::mutex functor_table_lock; -class ToplevelTaskShardingFunctor : public ShardingFunctor { +class ToplevelTaskShardingFunctor : public Legion::ShardingFunctor { public: - virtual ShardID shard(const DomainPoint& p, const Domain& launch_space, const size_t total_shards) + virtual Legion::ShardID shard(const DomainPoint& p, + const Domain& launch_space, + const size_t total_shards) { // Just tile this space in 1D const Point<1> point = p; @@ -43,9 +43,11 @@ class ToplevelTaskShardingFunctor : public ShardingFunctor { } }; -class LinearizingShardingFunctor : public ShardingFunctor { +class LinearizingShardingFunctor : public Legion::ShardingFunctor { public: - virtual ShardID shard(const DomainPoint& p, const Domain& launch_space, const size_t total_shards) + virtual Legion::ShardID shard(const DomainPoint& p, + const Domain& launch_space, + const size_t total_shards) { const size_t size = launch_space.get_volume(); const size_t chunk = (size + total_shards - 1) / total_shards; @@ -54,7 +56,7 @@ class LinearizingShardingFunctor : public ShardingFunctor { virtual bool is_invertible(void) const { return true; } - virtual void invert(ShardID shard, + virtual void invert(Legion::ShardID shard, const Domain& shard_domain, const Domain& full_domain, const size_t total_shards, @@ -95,14 +97,14 @@ void register_legate_core_sharding_functors(Legion::Runtime* runtime, const Libr functor_id_table[context.get_projection_id(LEGATE_CORE_DELINEARIZE_PROJ_ID)] = sharding_id; } -class LegateShardingFunctor : public ShardingFunctor { +class LegateShardingFunctor : public Legion::ShardingFunctor { public: LegateShardingFunctor(LegateProjectionFunctor* proj_functor) : proj_functor_(proj_functor) {} public: - virtual ShardID shard(const DomainPoint& p, - const Domain& launch_space, - const size_t total_shards) override + virtual Legion::ShardID shard(const DomainPoint& p, + const Domain& launch_space, + const size_t total_shards) override { auto lo = proj_functor_->project_point(launch_space.lo(), launch_space); auto hi = proj_functor_->project_point(launch_space.hi(), launch_space); @@ -117,25 +119,25 @@ class LegateShardingFunctor : public ShardingFunctor { LegateProjectionFunctor* proj_functor_; }; -ShardingID find_sharding_functor_by_projection_functor(Legion::ProjectionID proj_id) +Legion::ShardingID find_sharding_functor_by_projection_functor(Legion::ProjectionID proj_id) { const std::lock_guard lock(legate::functor_table_lock); assert(functor_id_table.find(proj_id) != functor_id_table.end()); return functor_id_table[proj_id]; } -struct callback_args_t { +struct ShardingCallbackArgs { Legion::ShardID shard_id; Legion::ProjectionID proj_id; }; static void sharding_functor_registration_callback(const Legion::RegistrationCallbackArgs& args) { - auto p_args = static_cast(args.buffer.get_ptr()); + auto p_args = static_cast(args.buffer.get_ptr()); auto shard_id = p_args->shard_id; auto proj_id = p_args->proj_id; - auto runtime = Runtime::get_runtime(); + auto runtime = Legion::Runtime::get_runtime(); auto sharding_functor = new legate::LegateShardingFunctor(legate::find_legate_projection_functor(proj_id)); runtime->register_sharding_functor(shard_id, sharding_functor, true /*silence warnings*/); @@ -148,13 +150,13 @@ extern "C" { void legate_create_sharding_functor_using_projection(Legion::ShardID shard_id, Legion::ProjectionID proj_id) { - auto runtime = Runtime::get_runtime(); - legate::callback_args_t args{shard_id, proj_id}; + auto runtime = Legion::Runtime::get_runtime(); + legate::ShardingCallbackArgs args{shard_id, proj_id}; { const std::lock_guard lock(legate::functor_table_lock); legate::functor_id_table[proj_id] = shard_id; } - UntypedBuffer buffer(&args, sizeof(args)); + Legion::UntypedBuffer buffer(&args, sizeof(args)); Legion::Runtime::perform_registration_callback( legate::sharding_functor_registration_callback, buffer, false /*global*/, false /*dedup*/); } diff --git a/src/core/task/registrar.cc b/src/core/task/registrar.cc new file mode 100644 index 000000000..3386d2010 --- /dev/null +++ b/src/core/task/registrar.cc @@ -0,0 +1,99 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "core/task/registrar.h" + +#include "core/runtime/context.h" +#include "core/utilities/typedefs.h" + +namespace legate { + +struct PendingTaskVariant : public Legion::TaskVariantRegistrar { + PendingTaskVariant(void) + : Legion::TaskVariantRegistrar(), task_name(nullptr), var(LEGATE_NO_VARIANT) + { + } + PendingTaskVariant(Legion::TaskID tid, + bool global, + const char* var_name, + const char* t_name, + const Legion::CodeDescriptor& desc, + LegateVariantCode v, + size_t ret) + : Legion::TaskVariantRegistrar(tid, global, var_name), + task_name(t_name), + descriptor(desc), + var(v), + ret_size(ret) + { + } + + const char* task_name; + Legion::CodeDescriptor descriptor; + LegateVariantCode var; + size_t ret_size; +}; + +void TaskRegistrar::record_variant(Legion::TaskID tid, + const char* task_name, + const Legion::CodeDescriptor& desc, + Legion::ExecutionConstraintSet& execution_constraints, + Legion::TaskLayoutConstraintSet& layout_constraints, + LegateVariantCode var, + Processor::Kind kind, + const VariantOptions& options) +{ + assert((kind == Processor::LOC_PROC) || (kind == Processor::TOC_PROC) || + (kind == Processor::OMP_PROC)); + + // Buffer these up until we can do our actual registration with the runtime + auto registrar = new PendingTaskVariant(tid, + false /*global*/, + (kind == Processor::LOC_PROC) ? "CPU" + : (kind == Processor::TOC_PROC) ? "GPU" + : "OpenMP", + task_name, + desc, + var, + options.return_size); + + registrar->execution_constraints.swap(execution_constraints); + registrar->layout_constraints.swap(layout_constraints); + registrar->add_constraint(Legion::ProcessorConstraint(kind)); + registrar->set_leaf(options.leaf); + registrar->set_inner(options.inner); + registrar->set_idempotent(options.idempotent); + registrar->set_concurrent(options.concurrent); + + pending_task_variants_.push_back(registrar); +} + +void TaskRegistrar::register_all_tasks(const LibraryContext& context) +{ + auto runtime = Legion::Runtime::get_runtime(); + // Do all our registrations + for (auto& task : pending_task_variants_) { + task->task_id = + context.get_task_id(task->task_id); // Convert a task local task id to a global id + // Attach the task name too for debugging + runtime->attach_name(task->task_id, task->task_name, false /*mutable*/, true /*local only*/); + runtime->register_task_variant(*task, task->descriptor, nullptr, 0, task->ret_size, task->var); + delete task; + } + pending_task_variants_.clear(); +} + +} // namespace legate diff --git a/src/core/task/registrar.h b/src/core/task/registrar.h new file mode 100644 index 000000000..ad7e3ddb3 --- /dev/null +++ b/src/core/task/registrar.h @@ -0,0 +1,49 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include + +#include "legion.h" + +#include "core/task/variant.h" +#include "core/utilities/typedefs.h" + +namespace legate { + +class LibraryContext; +class PendingTaskVariant; + +class TaskRegistrar { + public: + void record_variant(Legion::TaskID tid, + const char* task_name, + const Legion::CodeDescriptor& desc, + Legion::ExecutionConstraintSet& execution_constraints, + Legion::TaskLayoutConstraintSet& layout_constraints, + LegateVariantCode var, + Processor::Kind kind, + const VariantOptions& options); + + public: + void register_all_tasks(const LibraryContext& context); + + private: + std::vector pending_task_variants_; +}; + +} // namespace legate diff --git a/src/core/task/return.cc b/src/core/task/return.cc index 98c70419a..10d69d079 100644 --- a/src/core/task/return.cc +++ b/src/core/task/return.cc @@ -31,8 +31,6 @@ #include "core/cuda/stream_pool.h" #endif -using namespace Legion; - namespace legate { ReturnValue::ReturnValue(Legion::UntypedDeferredValue value, size_t size) @@ -43,7 +41,7 @@ ReturnValue::ReturnValue(Legion::UntypedDeferredValue value, size_t size) /*static*/ ReturnValue ReturnValue::unpack(const void* ptr, size_t size, Memory::Kind memory_kind) { - ReturnValue result(UntypedDeferredValue(size, memory_kind), size); + ReturnValue result(Legion::UntypedDeferredValue(size, memory_kind), size); #ifdef DEBUG_LEGATE assert(!result.is_device_value()); #endif @@ -108,12 +106,14 @@ static void pack_returned_exception(const ReturnedException& value, void*& ptr, value.legion_serialize(ptr); } -static void returned_exception_init(const ReductionOp* reduction_op, void*& ptr, size_t& size) +static void returned_exception_init(const Legion::ReductionOp* reduction_op, + void*& ptr, + size_t& size) { pack_returned_exception(JoinReturnedException::identity, ptr, size); } -static void returned_exception_fold(const ReductionOp* reduction_op, +static void returned_exception_fold(const Legion::ReductionOp* reduction_op, void*& lhs_ptr, size_t& lhs_size, const void* rhs_ptr) @@ -171,7 +171,7 @@ ReturnValue ReturnedException::pack() const { auto buffer_size = legion_buffer_size(); auto mem_kind = find_memory_kind_for_executing_processor(); - auto buffer = UntypedDeferredValue(buffer_size, mem_kind); + auto buffer = Legion::UntypedDeferredValue(buffer_size, mem_kind); AccessorWO acc(buffer, buffer_size, false); legion_serialize(acc.ptr(0)); @@ -296,10 +296,10 @@ void ReturnValues::legion_deserialize(const void* buffer) return ReturnValue::unpack(values + offset, size, kind); } -void ReturnValues::finalize(Context legion_context) const +void ReturnValues::finalize(Legion::Context legion_context) const { if (return_values_.empty()) { - Runtime::legion_task_postamble(legion_context); + Legion::Runtime::legion_task_postamble(legion_context); return; } else if (return_values_.size() == 1) { return_values_.front().finalize(legion_context); @@ -317,17 +317,18 @@ void ReturnValues::finalize(Context legion_context) const size_t return_size = legion_buffer_size(); auto return_buffer = - UntypedDeferredValue(return_size, find_memory_kind_for_executing_processor()); + Legion::UntypedDeferredValue(return_size, find_memory_kind_for_executing_processor()); AccessorWO acc(return_buffer, return_size, false); legion_serialize(acc.ptr(0)); return_buffer.finalize(legion_context); } -void register_exception_reduction_op(Runtime* runtime, const LibraryContext& context) +void register_exception_reduction_op(Legion::Runtime* runtime, const LibraryContext& context) { auto redop_id = context.get_reduction_op_id(LEGATE_CORE_JOIN_EXCEPTION_OP); auto* redop = Realm::ReductionOpUntyped::create_reduction_op(); - Runtime::register_reduction_op(redop_id, redop, returned_exception_init, returned_exception_fold); + Legion::Runtime::register_reduction_op( + redop_id, redop, returned_exception_init, returned_exception_fold); } } // namespace legate diff --git a/src/core/task/return.h b/src/core/task/return.h index 031bb71f2..6b7b9935f 100644 --- a/src/core/task/return.h +++ b/src/core/task/return.h @@ -17,6 +17,7 @@ #pragma once #include +#include "core/utilities/typedefs.h" namespace legate { @@ -29,7 +30,7 @@ struct ReturnValue { ReturnValue& operator=(const ReturnValue&) = default; public: - static ReturnValue unpack(const void* ptr, size_t size, Legion::Memory::Kind memory_kind); + static ReturnValue unpack(const void* ptr, size_t size, Memory::Kind memory_kind); public: void* ptr(); diff --git a/src/core/task/task.cc b/src/core/task/task.cc index 51ac3e1c1..26366c64b 100644 --- a/src/core/task/task.cc +++ b/src/core/task/task.cc @@ -16,54 +16,73 @@ #include "core/task/task.h" -namespace legate { +#include -using namespace Legion; +#include "realm/faults.h" -void LegateTaskRegistrar::record_variant(TaskID tid, - const char* task_name, - const CodeDescriptor& descriptor, - ExecutionConstraintSet& execution_constraints, - TaskLayoutConstraintSet& layout_constraints, - LegateVariantCode var, - Processor::Kind kind, - const VariantOptions& options) -{ - assert((kind == Processor::LOC_PROC) || (kind == Processor::TOC_PROC) || - (kind == Processor::OMP_PROC)); +#include "core/runtime/context.h" +#include "core/runtime/runtime.h" +#include "core/task/exception.h" +#include "core/task/registrar.h" +#include "core/task/return.h" +#include "core/utilities/deserializer.h" +#include "core/utilities/nvtx_help.h" +#include "core/utilities/typedefs.h" - // Buffer these up until we can do our actual registration with the runtime - pending_task_variants_.push_back(PendingTaskVariant(tid, - false /*global*/, - (kind == Processor::LOC_PROC) ? "CPU" - : (kind == Processor::TOC_PROC) ? "GPU" - : "OpenMP", - task_name, - descriptor, - var, - options.return_size)); +namespace legate { +namespace detail { - auto& registrar = pending_task_variants_.back(); - registrar.execution_constraints.swap(execution_constraints); - registrar.layout_constraints.swap(layout_constraints); - registrar.add_constraint(ProcessorConstraint(kind)); - registrar.set_leaf(options.leaf); - registrar.set_inner(options.inner); - registrar.set_idempotent(options.idempotent); - registrar.set_concurrent(options.concurrent); +std::string generate_task_name(const std::type_info& ti) +{ + std::string result; + int status = 0; + char* demangled = abi::__cxa_demangle(ti.name(), 0, 0, &status); + result = demangled; + free(demangled); + return std::move(result); } -void LegateTaskRegistrar::register_all_tasks(Runtime* runtime, LibraryContext& context) +void task_wrapper(VariantImpl variant_impl, + const char* task_name, + const void* args, + size_t arglen, + const void* userdata, + size_t userlen, + Processor p) + { - // Do all our registrations - for (auto& task : pending_task_variants_) { - task.task_id = - context.get_task_id(task.task_id); // Convert a task local task id to a global id - // Attach the task name too for debugging - runtime->attach_name(task.task_id, task.task_name, false /*mutable*/, true /*local only*/); - runtime->register_task_variant(task, task.descriptor, nullptr, 0, task.ret_size, task.var); + // Legion preamble + const Legion::Task* task; + const std::vector* regions; + Legion::Context legion_context; + Legion::Runtime* runtime; + Legion::Runtime::legion_task_preamble(args, arglen, p, task, regions, legion_context, runtime); + +#ifdef LEGATE_USE_CUDA + nvtx::Range auto_range(task_name); +#endif + + Core::show_progress(task, legion_context, runtime); + + TaskContext context(task, *regions, legion_context, runtime); + + ReturnValues return_values{}; + try { + if (!Core::use_empty_task) (*variant_impl)(context); + return_values = context.pack_return_values(); + } catch (legate::TaskException& e) { + if (context.can_raise_exception()) { + context.make_all_unbound_stores_empty(); + return_values = context.pack_return_values_with_exception(e.index(), e.error_message()); + } else + // If a Legate exception is thrown by a task that does not declare any exception, + // this is a bug in the library that needs to be reported to the developer + Core::report_unexpected_exception(task, e); } - pending_task_variants_.clear(); + + // Legion postamble + return_values.finalize(legion_context); } +} // namespace detail } // namespace legate diff --git a/src/core/task/task.h b/src/core/task/task.h index b90a4e86b..76a9d6eb3 100644 --- a/src/core/task/task.h +++ b/src/core/task/task.h @@ -16,293 +16,44 @@ #pragma once -#include -#include - -#include "legion.h" -#include "realm/faults.h" - -#include "core/runtime/context.h" -#include "core/runtime/runtime.h" -#include "core/task/exception.h" -#include "core/task/return.h" -#include "core/utilities/deserializer.h" -#include "core/utilities/nvtx_help.h" +#include "core/task/variant.h" #include "core/utilities/typedefs.h" namespace legate { -// We're going to allow for each task to use only up to 341 scalar output stores -constexpr size_t LEGATE_MAX_SIZE_SCALAR_RETURN = 4096; - -struct VariantOptions { - bool leaf{true}; - bool inner{false}; - bool idempotent{false}; - bool concurrent{false}; - size_t return_size{LEGATE_MAX_SIZE_SCALAR_RETURN}; - - VariantOptions& with_leaf(bool _leaf) - { - leaf = _leaf; - return *this; - } - VariantOptions& with_inner(bool _inner) - { - inner = _inner; - return *this; - } - VariantOptions& with_idempotent(bool _idempotent) - { - idempotent = _idempotent; - return *this; - } - VariantOptions& with_concurrent(bool _concurrent) - { - concurrent = _concurrent; - return *this; - } - VariantOptions& with_return_size(size_t _return_size) - { - return_size = _return_size; - return *this; - } -}; +class TaskContext; -using LegateVariantImpl = void (*)(TaskContext&); +using VariantImpl = void (*)(TaskContext&); template -class LegateTask { - protected: - // Helper class for checking for various kinds of variants - using __no = int8_t[1]; - using __yes = int8_t[2]; - struct HasCPUVariant { - template - static __yes& test(decltype(&U::cpu_variant)); - template - static __no& test(...); - static const bool value = (sizeof(test(0)) == sizeof(__yes)); - }; - struct HasOMPVariant { - template - static __yes& test(decltype(&U::omp_variant)); - template - static __no& test(...); - static const bool value = (sizeof(test(0)) == sizeof(__yes)); - }; - struct HasGPUVariant { - template - static __yes& test(decltype(&U::gpu_variant)); - template - static __no& test(...); - static const bool value = (sizeof(test(0)) == sizeof(__yes)); - }; +struct LegateTask { + // Exports the base class so we can access it via subclass T + using BASE = LegateTask; - public: - static const char* task_name() - { - static std::string result; - if (result.empty()) { - int status = 0; - char* demangled = abi::__cxa_demangle(typeid(T).name(), 0, 0, &status); - result = demangled; - free(demangled); - } + static void register_variants( + const std::map& all_options = {}); - return result.c_str(); - } + private: + template typename, bool> + friend struct detail::RegisterVariantImpl; - // Task wrappers so we can instrument all Legate tasks if we want - template + // A wrapper that wraps all Legate task variant implementations. Provides + // common functionalities and instrumentations + template static void legate_task_wrapper( - const void* args, size_t arglen, const void* userdata, size_t userlen, Legion::Processor p) - { - // Legion preamble - const Legion::Task* task; - const std::vector* regions; - Legion::Context legion_context; - Legion::Runtime* runtime; - Legion::Runtime::legion_task_preamble(args, arglen, p, task, regions, legion_context, runtime); - -#ifdef LEGATE_USE_CUDA - nvtx::Range auto_range(task_name()); -#endif - - Core::show_progress(task, legion_context, runtime, task_name()); + const void* args, size_t arglen, const void* userdata, size_t userlen, Processor p); - TaskContext context(task, *regions, legion_context, runtime); - - ReturnValues return_values{}; - try { - if (!Core::use_empty_task) (*TASK_PTR)(context); - return_values = context.pack_return_values(); - } catch (legate::TaskException& e) { - if (context.can_raise_exception()) { - context.make_all_unbound_stores_empty(); - return_values = context.pack_return_values_with_exception(e.index(), e.error_message()); - } else - // If a Legate exception is thrown by a task that does not declare any exception, - // this is a bug in the library that needs to be reported to the developer - Core::report_unexpected_exception(task_name(), e); - } - - // Legion postamble - return_values.finalize(legion_context); - } - - public: - // Methods for registering variants - template + // A helper to register a single task variant + template static void register_variant(Legion::ExecutionConstraintSet& execution_constraints, Legion::TaskLayoutConstraintSet& layout_constraints, LegateVariantCode var, - Legion::Processor::Kind kind, - const VariantOptions& options) - { - // Construct the code descriptor for this task so that the library - // can register it later when it is ready - Legion::CodeDescriptor desc(legate_task_wrapper); - auto task_id = T::TASK_ID; - - T::Registrar::record_variant( - task_id, T::task_name(), desc, execution_constraints, layout_constraints, var, kind, options); - } - static void register_variants( - const std::map& all_options = {}); -}; - -template -class RegisterCPUVariant { - public: - static void register_variant(const VariantOptions& options) - { - Legion::ExecutionConstraintSet execution_constraints; - Legion::TaskLayoutConstraintSet layout_constraints; - BASE::template register_variant(execution_constraints, - layout_constraints, - LEGATE_CPU_VARIANT, - Legion::Processor::LOC_PROC, - options); - } -}; + Processor::Kind kind, + const VariantOptions& options); -template -class RegisterCPUVariant { - public: - static void register_variant(const VariantOptions& options) - { - // Do nothing - } -}; - -template -class RegisterOMPVariant { - public: - static void register_variant(const VariantOptions& options) - { - Legion::ExecutionConstraintSet execution_constraints; - Legion::TaskLayoutConstraintSet layout_constraints; - BASE::template register_variant(execution_constraints, - layout_constraints, - LEGATE_OMP_VARIANT, - Legion::Processor::OMP_PROC, - options); - } -}; - -template -class RegisterOMPVariant { - public: - static void register_variant(const VariantOptions& options) - { - // Do nothing - } -}; - -template -class RegisterGPUVariant { - public: - static void register_variant(const VariantOptions& options) - { - Legion::ExecutionConstraintSet execution_constraints; - Legion::TaskLayoutConstraintSet layout_constraints; - BASE::template register_variant(execution_constraints, - layout_constraints, - LEGATE_GPU_VARIANT, - Legion::Processor::TOC_PROC, - options); - } -}; - -template -class RegisterGPUVariant { - public: - static void register_variant(const VariantOptions& options) - { - // Do nothing - } -}; - -template -/*static*/ void LegateTask::register_variants( - const std::map& all_options) -{ - // Make a copy of the map of options so that we can do find-or-create on it - auto all_options_copy = all_options; - RegisterCPUVariant, HasCPUVariant::value>::register_variant( - all_options_copy[LEGATE_CPU_VARIANT]); - RegisterOMPVariant, HasOMPVariant::value>::register_variant( - all_options_copy[LEGATE_OMP_VARIANT]); - RegisterGPUVariant, HasGPUVariant::value>::register_variant( - all_options_copy[LEGATE_GPU_VARIANT]); -} - -class LegateTaskRegistrar { - public: - void record_variant(Legion::TaskID tid, - const char* task_name, - const Legion::CodeDescriptor& desc, - Legion::ExecutionConstraintSet& execution_constraints, - Legion::TaskLayoutConstraintSet& layout_constraints, - LegateVariantCode var, - Legion::Processor::Kind kind, - const VariantOptions& options); - - public: - void register_all_tasks(Legion::Runtime* runtime, LibraryContext& context); - - private: - struct PendingTaskVariant : public Legion::TaskVariantRegistrar { - public: - PendingTaskVariant(void) - : Legion::TaskVariantRegistrar(), task_name(nullptr), var(LEGATE_NO_VARIANT) - { - } - PendingTaskVariant(Legion::TaskID tid, - bool global, - const char* var_name, - const char* t_name, - const Legion::CodeDescriptor& desc, - LegateVariantCode v, - size_t ret) - : Legion::TaskVariantRegistrar(tid, global, var_name), - task_name(t_name), - descriptor(desc), - var(v), - ret_size(ret) - { - } - - public: - const char* task_name; - Legion::CodeDescriptor descriptor; - LegateVariantCode var; - size_t ret_size; - }; - - private: - std::vector pending_task_variants_; + static const char* task_name(); }; } // namespace legate + +#include "core/task/task.inl" diff --git a/src/core/task/task.inl b/src/core/task/task.inl new file mode 100644 index 000000000..713cc3efd --- /dev/null +++ b/src/core/task/task.inl @@ -0,0 +1,79 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "core/task/task.h" + +namespace legate { + +namespace detail { + +std::string generate_task_name(const std::type_info&); + +void task_wrapper( + VariantImpl, const char*, const void*, size_t, const void*, size_t, Legion::Processor); + +}; // namespace detail + +template +template +/*static*/ void LegateTask::legate_task_wrapper( + const void* args, size_t arglen, const void* userdata, size_t userlen, Legion::Processor p) +{ + detail::task_wrapper(VARIANT_IMPL, task_name(), args, arglen, userdata, userlen, p); +} + +template +template +/*static*/ void LegateTask::register_variant( + Legion::ExecutionConstraintSet& execution_constraints, + Legion::TaskLayoutConstraintSet& layout_constraints, + LegateVariantCode var, + Legion::Processor::Kind kind, + const VariantOptions& options) +{ + // Construct the code descriptor for this task so that the library + // can register it later when it is ready + Legion::CodeDescriptor desc(legate_task_wrapper); + auto task_id = T::TASK_ID; + + T::Registrar::record_variant( + task_id, task_name(), desc, execution_constraints, layout_constraints, var, kind, options); +} + +template +/*static*/ void LegateTask::register_variants( + const std::map& all_options) +{ + // Make a copy of the map of options so that we can do find-or-create on it + auto all_options_copy = all_options; + detail::RegisterVariant::register_variant( + all_options_copy[LEGATE_CPU_VARIANT]); + detail::RegisterVariant::register_variant( + all_options_copy[LEGATE_OMP_VARIANT]); + detail::RegisterVariant::register_variant( + all_options_copy[LEGATE_GPU_VARIANT]); +} + +template +/*static*/ const char* LegateTask::task_name() +{ + static std::string result = detail::generate_task_name(typeid(T)); + return result.c_str(); +} + +} // namespace legate diff --git a/src/core/task/variant.cc b/src/core/task/variant.cc new file mode 100644 index 000000000..ea54b414e --- /dev/null +++ b/src/core/task/variant.cc @@ -0,0 +1,51 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "core/task/variant.h" + +namespace legate { + +VariantOptions& VariantOptions::with_leaf(bool _leaf) +{ + leaf = _leaf; + return *this; +} + +VariantOptions& VariantOptions::with_inner(bool _inner) +{ + inner = _inner; + return *this; +} + +VariantOptions& VariantOptions::with_idempotent(bool _idempotent) +{ + idempotent = _idempotent; + return *this; +} + +VariantOptions& VariantOptions::with_concurrent(bool _concurrent) +{ + concurrent = _concurrent; + return *this; +} + +VariantOptions& VariantOptions::with_return_size(size_t _return_size) +{ + return_size = _return_size; + return *this; +} + +} // namespace legate diff --git a/src/core/task/variant.h b/src/core/task/variant.h new file mode 100644 index 000000000..53c350302 --- /dev/null +++ b/src/core/task/variant.h @@ -0,0 +1,106 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "legion.h" + +#include "core/utilities/typedefs.h" + +namespace legate { + +// We're going to allow for each task to use only up to 341 scalar output stores +constexpr size_t LEGATE_MAX_SIZE_SCALAR_RETURN = 4096; + +struct VariantOptions { + bool leaf{true}; + bool inner{false}; + bool idempotent{false}; + bool concurrent{false}; + size_t return_size{LEGATE_MAX_SIZE_SCALAR_RETURN}; + + VariantOptions& with_leaf(bool leaf); + VariantOptions& with_inner(bool inner); + VariantOptions& with_idempotent(bool idempotent); + VariantOptions& with_concurrent(bool concurrent); + VariantOptions& with_return_size(size_t return_size); +}; + +namespace detail { + +template +using void_t = void; + +template +struct CPUVariant : std::false_type {}; + +template +struct OMPVariant : std::false_type {}; + +template +struct GPUVariant : std::false_type {}; + +template +struct CPUVariant> : std::true_type { + static constexpr auto variant = T::cpu_variant; + static constexpr auto id = LEGATE_CPU_VARIANT; + static constexpr auto proc_kind = Processor::LOC_PROC; +}; + +template +struct OMPVariant> : std::true_type { + static constexpr auto variant = T::omp_variant; + static constexpr auto id = LEGATE_OMP_VARIANT; + static constexpr auto proc_kind = Processor::OMP_PROC; +}; + +template +struct GPUVariant> : std::true_type { + static constexpr auto variant = T::gpu_variant; + static constexpr auto id = LEGATE_GPU_VARIANT; + static constexpr auto proc_kind = Processor::TOC_PROC; +}; + +template typename SELECTOR, bool HAS_VARIANT> +struct RegisterVariantImpl { + static void register_variant(const VariantOptions& options) + { + Legion::ExecutionConstraintSet execution_constraints; + Legion::TaskLayoutConstraintSet layout_constraints; + T::BASE::template register_variant::variant>( + execution_constraints, layout_constraints, SELECTOR::id, SELECTOR::proc_kind, options); + } +}; + +template typename SELECTOR> +struct RegisterVariantImpl { + static void register_variant(const VariantOptions& options) + { + // Do nothing + } +}; + +template typename SELECTOR> +struct RegisterVariant { + static void register_variant(const VariantOptions& options) + { + RegisterVariantImpl::value>::register_variant(options); + } +}; + +} // namespace detail + +} // namespace legate diff --git a/src/core/utilities/debug.h b/src/core/utilities/debug.h index e6f52897f..d0f803fe5 100644 --- a/src/core/utilities/debug.h +++ b/src/core/utilities/debug.h @@ -17,6 +17,7 @@ #pragma once #include "core/data/store.h" +#include "core/utilities/typedefs.h" #ifdef LEGATE_USE_CUDA #include @@ -26,8 +27,6 @@ namespace legate { -using namespace Legion; - #ifdef LEGATE_USE_CUDA #ifndef MAX diff --git a/src/core/utilities/deserializer.cc b/src/core/utilities/deserializer.cc index f62f5b50a..325b0d2d4 100644 --- a/src/core/utilities/deserializer.cc +++ b/src/core/utilities/deserializer.cc @@ -18,26 +18,22 @@ #include "core/data/scalar.h" #include "core/data/store.h" #include "core/utilities/machine.h" +#include "core/utilities/typedefs.h" #include "legion/legion_c.h" #include "legion/legion_c_util.h" -using LegionTask = Legion::Task; - -using namespace Legion; -using namespace Legion::Mapping; - namespace legate { -TaskDeserializer::TaskDeserializer(const LegionTask* task, - const std::vector& regions) +TaskDeserializer::TaskDeserializer(const Legion::Task* task, + const std::vector& regions) : BaseDeserializer(static_cast(task->args), task->arglen), futures_{task->futures.data(), task->futures.size()}, regions_{regions.data(), regions.size()}, outputs_() { - auto runtime = Runtime::get_runtime(); - auto ctx = Runtime::get_context(); + auto runtime = Legion::Runtime::get_runtime(); + auto ctx = Legion::Runtime::get_context(); runtime->get_output_regions(ctx, outputs_); first_task_ = !task->is_index_space || (task->index_point == task->index_domain.lo()); @@ -76,7 +72,7 @@ void TaskDeserializer::_unpack(FutureWrapper& value) auto field_size = unpack(); auto point = unpack>(); - Legion::Domain domain; + Domain domain; domain.dim = static_cast(point.size()); for (int32_t idx = 0; idx < domain.dim; ++idx) { domain.rect_data[idx] = 0; @@ -122,14 +118,14 @@ void TaskDeserializer::_unpack(Legion::PhaseBarrier& barrier) auto future = futures_[0]; futures_ = futures_.subspan(1); auto barrier_ = future.get_result(); - barrier = CObjectWrapper::unwrap(barrier_); + barrier = Legion::CObjectWrapper::unwrap(barrier_); } namespace mapping { TaskDeserializer::TaskDeserializer(const Legion::Task* task, - MapperRuntime* runtime, - MapperContext context) + Legion::Mapping::MapperRuntime* runtime, + Legion::Mapping::MapperContext context) : BaseDeserializer(static_cast(task->args), task->arglen), task_(task), runtime_(runtime), @@ -170,7 +166,7 @@ void TaskDeserializer::_unpack(FutureWrapper& value) unpack(); auto point = unpack>(); - Legion::Domain domain; + Domain domain; domain.dim = static_cast(point.size()); for (int32_t idx = 0; idx < domain.dim; ++idx) { domain.rect_data[idx] = 0; @@ -193,8 +189,8 @@ void TaskDeserializer::_unpack(RegionField& value, bool is_output_region) CopyDeserializer::CopyDeserializer(const void* args, size_t arglen, std::vector&& all_requirements, - MapperRuntime* runtime, - MapperContext context) + Legion::Mapping::MapperRuntime* runtime, + Legion::Mapping::MapperContext context) : BaseDeserializer(static_cast(args), arglen), all_reqs_(std::forward>(all_requirements)), curr_reqs_(all_reqs_.begin()), diff --git a/src/core/utilities/dispatch.h b/src/core/utilities/dispatch.h index c2e849f24..8d3d2f302 100644 --- a/src/core/utilities/dispatch.h +++ b/src/core/utilities/dispatch.h @@ -86,42 +86,42 @@ struct inner_dim_dispatch_fn { case 1: { return f.template operator()(std::forward(args)...); } -#if LEGION_MAX_DIM >= 2 +#if LEGATE_MAX_DIM >= 2 case 2: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 3 +#if LEGATE_MAX_DIM >= 3 case 3: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 4 +#if LEGATE_MAX_DIM >= 4 case 4: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 5 +#if LEGATE_MAX_DIM >= 5 case 5: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 6 +#if LEGATE_MAX_DIM >= 6 case 6: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 7 +#if LEGATE_MAX_DIM >= 7 case 7: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 8 +#if LEGATE_MAX_DIM >= 8 case 8: { return f.template operator()(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 9 +#if LEGATE_MAX_DIM >= 9 case 9: { return f.template operator()(std::forward(args)...); } @@ -136,47 +136,47 @@ template constexpr decltype(auto) double_dispatch(int dim, LegateTypeCode code, Functor f, Fnargs&&... args) { switch (dim) { -#if LEGION_MAX_DIM >= 1 +#if LEGATE_MAX_DIM >= 1 case 1: { return inner_type_dispatch_fn<1>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 2 +#if LEGATE_MAX_DIM >= 2 case 2: { return inner_type_dispatch_fn<2>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 3 +#if LEGATE_MAX_DIM >= 3 case 3: { return inner_type_dispatch_fn<3>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 4 +#if LEGATE_MAX_DIM >= 4 case 4: { return inner_type_dispatch_fn<4>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 5 +#if LEGATE_MAX_DIM >= 5 case 5: { return inner_type_dispatch_fn<5>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 6 +#if LEGATE_MAX_DIM >= 6 case 6: { return inner_type_dispatch_fn<6>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 7 +#if LEGATE_MAX_DIM >= 7 case 7: { return inner_type_dispatch_fn<7>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 8 +#if LEGATE_MAX_DIM >= 8 case 8: { return inner_type_dispatch_fn<8>{}(code, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 9 +#if LEGATE_MAX_DIM >= 9 case 9: { return inner_type_dispatch_fn<9>{}(code, f, std::forward(args)...); } @@ -190,47 +190,47 @@ template constexpr decltype(auto) double_dispatch(int dim1, int dim2, Functor f, Fnargs&&... args) { switch (dim1) { -#if LEGION_MAX_DIM >= 1 +#if LEGATE_MAX_DIM >= 1 case 1: { return inner_dim_dispatch_fn<1>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 2 +#if LEGATE_MAX_DIM >= 2 case 2: { return inner_dim_dispatch_fn<2>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 3 +#if LEGATE_MAX_DIM >= 3 case 3: { return inner_dim_dispatch_fn<3>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 4 +#if LEGATE_MAX_DIM >= 4 case 4: { return inner_dim_dispatch_fn<4>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 5 +#if LEGATE_MAX_DIM >= 5 case 5: { return inner_dim_dispatch_fn<5>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 6 +#if LEGATE_MAX_DIM >= 6 case 6: { return inner_dim_dispatch_fn<6>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 7 +#if LEGATE_MAX_DIM >= 7 case 7: { return inner_dim_dispatch_fn<7>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 8 +#if LEGATE_MAX_DIM >= 8 case 8: { return inner_dim_dispatch_fn<8>{}(dim2, f, std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 9 +#if LEGATE_MAX_DIM >= 9 case 9: { return inner_dim_dispatch_fn<9>{}(dim2, f, std::forward(args)...); } @@ -244,47 +244,47 @@ template constexpr decltype(auto) dim_dispatch(int dim, Functor f, Fnargs&&... args) { switch (dim) { -#if LEGION_MAX_DIM >= 1 +#if LEGATE_MAX_DIM >= 1 case 1: { return f.template operator()<1>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 2 +#if LEGATE_MAX_DIM >= 2 case 2: { return f.template operator()<2>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 3 +#if LEGATE_MAX_DIM >= 3 case 3: { return f.template operator()<3>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 4 +#if LEGATE_MAX_DIM >= 4 case 4: { return f.template operator()<4>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 5 +#if LEGATE_MAX_DIM >= 5 case 5: { return f.template operator()<5>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 6 +#if LEGATE_MAX_DIM >= 6 case 6: { return f.template operator()<6>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 7 +#if LEGATE_MAX_DIM >= 7 case 7: { return f.template operator()<7>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 8 +#if LEGATE_MAX_DIM >= 8 case 8: { return f.template operator()<8>(std::forward(args)...); } #endif -#if LEGION_MAX_DIM >= 9 +#if LEGATE_MAX_DIM >= 9 case 9: { return f.template operator()<9>(std::forward(args)...); } diff --git a/src/core/utilities/linearize.cc b/src/core/utilities/linearize.cc index 5223fd2fb..02ed39ac2 100644 --- a/src/core/utilities/linearize.cc +++ b/src/core/utilities/linearize.cc @@ -19,8 +19,6 @@ namespace legate { -using namespace Legion; - struct linearize_fn { template size_t operator()(const DomainPoint& lo_dp, const DomainPoint& hi_dp, const DomainPoint& point_dp) diff --git a/src/core/utilities/linearize.h b/src/core/utilities/linearize.h index 70a016521..a8d1720ac 100644 --- a/src/core/utilities/linearize.h +++ b/src/core/utilities/linearize.h @@ -16,16 +16,12 @@ #pragma once -#include "legion.h" +#include "core/utilities/typedefs.h" namespace legate { -size_t linearize(const Legion::DomainPoint& lo, - const Legion::DomainPoint& hi, - const Legion::DomainPoint& point); +size_t linearize(const DomainPoint& lo, const DomainPoint& hi, const DomainPoint& point); -Legion::DomainPoint delinearize(const Legion::DomainPoint& lo, - const Legion::DomainPoint& hi, - size_t idx); +DomainPoint delinearize(const DomainPoint& lo, const DomainPoint& hi, size_t idx); } // namespace legate diff --git a/src/core/utilities/machine.cc b/src/core/utilities/machine.cc index a6c5e7e5e..ca79637e9 100644 --- a/src/core/utilities/machine.cc +++ b/src/core/utilities/machine.cc @@ -19,8 +19,6 @@ #include "core/runtime/runtime.h" #include "legate_defines.h" -using namespace Legion; - namespace legate { Memory::Kind find_memory_kind_for_executing_processor(bool host_accessible) diff --git a/src/core/utilities/machine.h b/src/core/utilities/machine.h index b61824542..5e0cd9d60 100644 --- a/src/core/utilities/machine.h +++ b/src/core/utilities/machine.h @@ -18,8 +18,10 @@ #include "legion.h" +#include "core/utilities/typedefs.h" + namespace legate { -Legion::Memory::Kind find_memory_kind_for_executing_processor(bool host_accessible = true); +Memory::Kind find_memory_kind_for_executing_processor(bool host_accessible = true); } // namespace legate diff --git a/src/core/utilities/typedefs.h b/src/core/utilities/typedefs.h index f33bcff79..7ab90cb75 100644 --- a/src/core/utilities/typedefs.h +++ b/src/core/utilities/typedefs.h @@ -19,32 +19,80 @@ #include "legion.h" #include "core/legate_c.h" +#include "legate_defines.h" namespace legate { -extern Legion::Logger log_legate; +// C enum typedefs +using LegateVariantCode = legate_core_variant_t; +using LegateTypeCode = legate_core_type_code_t; +using LegateMappingTag = legate_core_mapping_tag_t; + +using Logger = Legion::Logger; + +extern Logger log_legate; + +// Re-export Legion types + +using TunableID = Legion::TunableID; + +// Geometry types + +using coord_t = Legion::coord_t; + +template +using Point = Legion::Point; +template +using Rect = Legion::Rect; -template +using Domain = Legion::Domain; +using DomainPoint = Legion::DomainPoint; + +// Accessor types + +template using AccessorRO = Legion::FieldAccessor>; -template +template using AccessorWO = Legion::FieldAccessor>; -template +template using AccessorRW = Legion::FieldAccessor>; -template +template using AccessorRD = Legion:: ReductionAccessor>; -template -using GenericAccessorRO = Legion::FieldAccessor; -template -using GenericAccessorWO = Legion::FieldAccessor; -template -using GenericAccessorRW = Legion::FieldAccessor; -using TunableID = Legion::TunableID; +// Iterators -// C enum typedefs -using LegateVariantCode = legate_core_variant_t; -using LegateTypeCode = legate_core_type_code_t; -using LegateMappingTag = legate_core_mapping_tag_t; +template +using PointInRectIterator = Legion::PointInRectIterator; +template +using RectInDomainIterator = Legion::RectInDomainIterator; +template +using PointInDomainIterator = Legion::PointInDomainIterator; + +// Machine + +using Processor = Legion::Processor; +using Memory = Legion::Memory; + +// Reduction operators + +template +using SumReduction = Legion::SumReduction; +template +using DiffReduction = Legion::DiffReduction; +template +using ProdReduction = Legion::ProdReduction; +template +using DivReduction = Legion::DivReduction; +template +using MaxReduction = Legion::MaxReduction; +template +using MinReduction = Legion::MinReduction; +template +using OrReduction = Legion::OrReduction; +template +using AndReduction = Legion::AndReduction; +template +using XorReduction = Legion::XorReduction; } // namespace legate diff --git a/src/legate.h b/src/legate.h index 14171e1c1..7e53e9a45 100644 --- a/src/legate.h +++ b/src/legate.h @@ -23,6 +23,7 @@ #include "core/data/store.h" #include "core/legate_c.h" #include "core/runtime/runtime.h" +#include "core/task/registrar.h" #include "core/task/task.h" #include "core/utilities/deserializer.h" #include "core/utilities/dispatch.h" diff --git a/src/legate_defines.h b/src/legate_defines.h index de272dde0..7c08bc3b1 100644 --- a/src/legate_defines.h +++ b/src/legate_defines.h @@ -52,5 +52,11 @@ #endif #endif +#ifdef LEGION_BOUNDS_CHECKS +#define LEGATE_BOUNDS_CHECKS +#endif + +#define LEGATE_MAX_DIM LEGION_MAX_DIM + // TODO: 2022-10-04: Work around a Legion bug, by not instantiating futures on framebuffer. #define LEGATE_NO_FUTURES_ON_FB From 04b51e694846c38fbcbd94bdccc92f44428cbf01 Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Sun, 26 Feb 2023 20:42:56 -0800 Subject: [PATCH 35/57] Fix non-editable build (#589) --- legate_core_cpp.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index 6191cf2cf..d7e1047f5 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -363,6 +363,7 @@ install( install( FILES src/core/task/exception.h + src/core/task/registrar.h src/core/task/return.h src/core/task/task.h src/core/task/task.inl From 6782f2129ac4a63bd10b7dde1368a46fab904b5e Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Mon, 27 Feb 2023 16:34:34 -0800 Subject: [PATCH 36/57] Runtime network detection and UCX options (#590) * report networks in install_info * factor bgwork / ucx opts * Update legate/driver/command.py Co-authored-by: Manolis Papadakis * add tests --------- Co-authored-by: Manolis Papadakis --- legate/driver/command.py | 27 ++- legate/install_info.py.in | 2 + legate_core_python.cmake | 2 +- tests/unit/legate/driver/test_command.py | 202 ++++++++++++++++++++++- 4 files changed, 222 insertions(+), 11 deletions(-) diff --git a/legate/driver/command.py b/legate/driver/command.py index 5b3816567..3a27f7818 100644 --- a/legate/driver/command.py +++ b/legate/driver/command.py @@ -16,6 +16,7 @@ from typing import TYPE_CHECKING +from .. import install_info from ..util.ui import warn if TYPE_CHECKING: @@ -258,26 +259,37 @@ def cmd_openmp( ) -def cmd_utility( +def cmd_bgwork( config: ConfigProtocol, system: System, launcher: Launcher ) -> CommandPart: - utility = config.core.utility ranks = config.multi_node.ranks + utility = config.core.utility - if utility == 1: - return () - - opts: CommandPart = ("-ll:util", str(utility)) + opts: CommandPart = () # If we are running multi-rank then make the number of active # message handler threads equal to our number of utility # processors in order to prevent head-of-line blocking if ranks > 1: - opts += ("-ll:bgwork", str(utility)) + opts += ("-ll:bgwork", str(max(utility, 2))) + + if ranks > 1 and "ucx" in install_info.networks: + opts += ("-ll:bgworkpin", "1") return opts +def cmd_utility( + config: ConfigProtocol, system: System, launcher: Launcher +) -> CommandPart: + utility = config.core.utility + + if utility == 1: + return () + + return ("-ll:util", str(utility)) + + def cmd_mem( config: ConfigProtocol, system: System, launcher: Launcher ) -> CommandPart: @@ -395,6 +407,7 @@ def cmd_user_opts( cmd_gpus, cmd_openmp, cmd_utility, + cmd_bgwork, cmd_mem, cmd_numamem, cmd_fbmem, diff --git a/legate/install_info.py.in b/legate/install_info.py.in index 4f0416979..bc38c4083 100644 --- a/legate/install_info.py.in +++ b/legate/install_info.py.in @@ -42,3 +42,5 @@ def get_libpath(): libpath: str = get_libpath() header: str = """@header@""" + +networks: list[str] = "@Legion_NETWORKS@".split() diff --git a/legate_core_python.cmake b/legate_core_python.cmake index 05d92853e..c3db1b60e 100644 --- a/legate_core_python.cmake +++ b/legate_core_python.cmake @@ -45,10 +45,10 @@ endif() add_custom_target("generate_install_info_py" ALL COMMAND ${CMAKE_COMMAND} + -DLegion_NETWORKS="${Legion_NETWORKS}" -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/generate_install_info_py.cmake" COMMENT "Generate install_info.py" - VERBATIM ) add_library(legate_core_python INTERFACE) diff --git a/tests/unit/legate/driver/test_command.py b/tests/unit/legate/driver/test_command.py index 6f05a44f1..b95fcbfba 100644 --- a/tests/unit/legate/driver/test_command.py +++ b/tests/unit/legate/driver/test_command.py @@ -20,6 +20,7 @@ import pytest import legate.driver.command as m +from legate import install_info from legate.driver.launcher import RANK_ENV_VARS from legate.util.colors import scrub from legate.util.types import LauncherType @@ -58,6 +59,7 @@ def test_CMD_PARTS() -> None: m.cmd_gpus, m.cmd_openmp, m.cmd_utility, + m.cmd_bgwork, m.cmd_mem, m.cmd_numamem, m.cmd_fbmem, @@ -826,7 +828,7 @@ def test_default_multi_rank( result = m.cmd_utility(config, system, launcher) - assert result == ("-ll:util", "2", "-ll:bgwork", "2") + assert result == ("-ll:util", "2") @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) @pytest.mark.parametrize("rank", ("0", "1", "2")) @@ -865,7 +867,7 @@ def test_utility_n_multi_rank_no_launcher( result = m.cmd_utility(config, system, launcher) - assert result == ("-ll:util", value, "-ll:bgwork", value) + assert result == ("-ll:util", value) @pytest.mark.parametrize("launch", ("mpirun", "jsrun", "srun")) @pytest.mark.parametrize("value", ("2", "3", "10")) @@ -878,7 +880,201 @@ def test_utility_n_multi_rank_with_launcher( result = m.cmd_utility(config, system, launcher) - assert result == ("-ll:util", value, "-ll:bgwork", value) + assert result == ("-ll:util", value) + + +class Test_cmd_bgwork: + def test_default_single_rank(self, genobjs: GenObjs) -> None: + config, system, launcher = genobjs([]) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == () + + def test_utility_1_single_rank(self, genobjs: GenObjs) -> None: + config, system, launcher = genobjs(["--utility", "1"]) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == () + + def test_utility_1_single_rank_and_ucx(self, genobjs: GenObjs) -> None: + config, system, launcher = genobjs(["--utility", "1"]) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == () + + @pytest.mark.parametrize("value", ("2", "3", "10")) + def test_utiltity_n_single_rank( + self, genobjs: GenObjs, value: str + ) -> None: + config, system, launcher = genobjs(["--utility", value]) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == () + + @pytest.mark.parametrize("value", ("2", "3", "10")) + def test_utiltity_n_single_rank_and_ucx( + self, genobjs: GenObjs, value: str + ) -> None: + config, system, launcher = genobjs(["--utility", value]) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == () + + @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) + @pytest.mark.parametrize("rank", ("0", "1", "2")) + def test_default_multi_rank( + self, genobjs: GenObjs, rank: str, rank_var: dict[str, str] + ) -> None: + config, system, launcher = genobjs( + [], multi_rank=(2, 2), rank_env={rank_var: rank} + ) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == ("-ll:bgwork", "2") + + @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) + @pytest.mark.parametrize("rank", ("0", "1", "2")) + def test_default_multi_rank_and_ucx( + self, genobjs: GenObjs, rank: str, rank_var: dict[str, str] + ) -> None: + config, system, launcher = genobjs( + [], multi_rank=(2, 2), rank_env={rank_var: rank} + ) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == ("-ll:bgwork", "2", "-ll:bgworkpin", "1") + + @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) + @pytest.mark.parametrize("rank", ("0", "1", "2")) + def test_utility_1_multi_rank_no_launcher( + self, genobjs: GenObjs, rank: str, rank_var: dict[str, str] + ) -> None: + config, system, launcher = genobjs( + ["--utility", "1"], multi_rank=(2, 2), rank_env={rank_var: rank} + ) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == ("-ll:bgwork", "2") + + @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) + @pytest.mark.parametrize("rank", ("0", "1", "2")) + def test_utility_1_multi_rank_no_launcher_and_ucx( + self, genobjs: GenObjs, rank: str, rank_var: dict[str, str] + ) -> None: + config, system, launcher = genobjs( + ["--utility", "1"], multi_rank=(2, 2), rank_env={rank_var: rank} + ) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == ("-ll:bgwork", "2", "-ll:bgworkpin", "1") + + @pytest.mark.parametrize("launch", ("mpirun", "jsrun", "srun")) + def test_utility_1_multi_rank_with_launcher( + self, genobjs: GenObjs, launch: str + ) -> None: + config, system, launcher = genobjs( + ["--utility", "1", "--launcher", launch], multi_rank=(2, 2) + ) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == ("-ll:bgwork", "2") + + @pytest.mark.parametrize("launch", ("mpirun", "jsrun", "srun")) + def test_utility_1_multi_rank_with_launcher_and_ucx( + self, genobjs: GenObjs, launch: str + ) -> None: + config, system, launcher = genobjs( + ["--utility", "1", "--launcher", launch], multi_rank=(2, 2) + ) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == ("-ll:bgwork", "2", "-ll:bgworkpin", "1") + + @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) + @pytest.mark.parametrize("rank", ("0", "1", "2")) + @pytest.mark.parametrize("value", ("2", "3", "10")) + def test_utility_n_multi_rank_no_launcher( + self, genobjs: GenObjs, value: str, rank: str, rank_var: dict[str, str] + ) -> None: + config, system, launcher = genobjs( + ["--utility", value], multi_rank=(2, 2), rank_env={rank_var: rank} + ) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == ("-ll:bgwork", value) + + @pytest.mark.parametrize("rank_var", RANK_ENV_VARS) + @pytest.mark.parametrize("rank", ("0", "1", "2")) + @pytest.mark.parametrize("value", ("2", "3", "10")) + def test_utility_n_multi_rank_no_launcher_and_ucx( + self, genobjs: GenObjs, value: str, rank: str, rank_var: dict[str, str] + ) -> None: + config, system, launcher = genobjs( + ["--utility", value], multi_rank=(2, 2), rank_env={rank_var: rank} + ) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == ("-ll:bgwork", value, "-ll:bgworkpin", "1") + + @pytest.mark.parametrize("launch", ("mpirun", "jsrun", "srun")) + @pytest.mark.parametrize("value", ("2", "3", "10")) + def test_utility_n_multi_rank_with_launcher( + self, genobjs: GenObjs, value: str, launch: str + ) -> None: + config, system, launcher = genobjs( + ["--utility", value, "--launcher", launch], multi_rank=(2, 2) + ) + + result = m.cmd_bgwork(config, system, launcher) + + assert result == ("-ll:bgwork", value) + + @pytest.mark.parametrize("launch", ("mpirun", "jsrun", "srun")) + @pytest.mark.parametrize("value", ("2", "3", "10")) + def test_utility_n_multi_rank_with_launcher_and_ucx( + self, genobjs: GenObjs, value: str, launch: str + ) -> None: + config, system, launcher = genobjs( + ["--utility", value, "--launcher", launch], multi_rank=(2, 2) + ) + + networks_orig = list(install_info.networks) + install_info.networks.append("ucx") + result = m.cmd_bgwork(config, system, launcher) + install_info.networks[:] = networks_orig[:] + + assert result == ("-ll:bgwork", value, "-ll:bgworkpin", "1") class Test_cmd_sysmem: From 33ce363e91069accbc22105f5f9d95122a8fcce1 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 27 Feb 2023 17:44:25 -0800 Subject: [PATCH 37/57] Fix is_complete_for check (#587) * Fix is_complete_for check * Fix another use of inequality on Shape * Return a bool tuple from Shape comparisons --------- Co-authored-by: Manolis Papadakis --- legate/core/partition.py | 6 +++--- legate/core/shape.py | 25 +++++++++++++++++-------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/legate/core/partition.py b/legate/core/partition.py index d5904c319..c0eb24ad6 100644 --- a/legate/core/partition.py +++ b/legate/core/partition.py @@ -227,7 +227,7 @@ def is_complete_for(self, extents: Shape, offsets: Shape) -> bool: my_lo = self._offset my_hi = self._offset + self.tile_shape * self._color_shape - return my_lo <= offsets and offsets + extents <= my_hi + return all(my_lo <= offsets) and all(offsets + extents <= my_hi) def is_disjoint_for(self, launch_domain: Optional[Rect]) -> bool: return ( @@ -236,7 +236,7 @@ def is_disjoint_for(self, launch_domain: Optional[Rect]) -> bool: ) def has_color(self, color: Shape) -> bool: - return color >= 0 and color < self._color_shape + return all(color >= 0) and all(color < self._color_shape) @lru_cache def get_subregion_size(self, extents: Shape, color: Shape) -> Shape: @@ -396,7 +396,7 @@ def is_disjoint_for(self, launch_domain: Optional[Rect]) -> bool: return True def has_color(self, color: Shape) -> bool: - return color >= 0 and color < self._color_shape + return all(color >= 0) and all(color < self._color_shape) def translate(self, offset: Shape) -> None: raise NotImplementedError("This method shouldn't be invoked") diff --git a/legate/core/shape.py b/legate/core/shape.py index 98207191f..cd6c44ee5 100644 --- a/legate/core/shape.py +++ b/legate/core/shape.py @@ -32,6 +32,11 @@ def _cast_tuple(value: int | Iterable[int], ndim: int) -> tuple[int, ...]: return tuple(value) +class _ShapeComparisonResult(tuple[bool, ...]): + def __bool__(self) -> bool: + assert False, "use any() or all()" + + class Shape: _extents: Union[tuple[int, ...], None] _ispace: Union[IndexSpace, None] @@ -154,41 +159,45 @@ def __eq__(self, other: object) -> bool: else: return False - def __le__(self, other: ExtentLike) -> bool: + def __le__(self, other: ExtentLike) -> _ShapeComparisonResult: lh = self.extents rh = ( other.extents if isinstance(other, Shape) else _cast_tuple(other, self.ndim) ) - return len(lh) == len(rh) and lh <= rh + assert len(lh) == len(rh) + return _ShapeComparisonResult(l <= r for (l, r) in zip(lh, rh)) - def __lt__(self, other: ExtentLike) -> bool: + def __lt__(self, other: ExtentLike) -> _ShapeComparisonResult: lh = self.extents rh = ( other.extents if isinstance(other, Shape) else _cast_tuple(other, self.ndim) ) - return len(lh) == len(rh) and lh < rh + assert len(lh) == len(rh) + return _ShapeComparisonResult(l < r for (l, r) in zip(lh, rh)) - def __ge__(self, other: ExtentLike) -> bool: + def __ge__(self, other: ExtentLike) -> _ShapeComparisonResult: lh = self.extents rh = ( other.extents if isinstance(other, Shape) else _cast_tuple(other, self.ndim) ) - return len(lh) == len(rh) and lh >= rh + assert len(lh) == len(rh) + return _ShapeComparisonResult(l >= r for (l, r) in zip(lh, rh)) - def __gt__(self, other: ExtentLike) -> bool: + def __gt__(self, other: ExtentLike) -> _ShapeComparisonResult: lh = self.extents rh = ( other.extents if isinstance(other, Shape) else _cast_tuple(other, self.ndim) ) - return len(lh) == len(rh) and lh > rh + assert len(lh) == len(rh) + return _ShapeComparisonResult(l > r for (l, r) in zip(lh, rh)) def __add__(self, other: ExtentLike) -> Shape: lh = self.extents From 333e8288605bd8189f6173058fc3986c48ead170 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 27 Feb 2023 17:50:21 -0800 Subject: [PATCH 38/57] Copy warnings on stderr even if logging to file (#588) * Copy warnings on stderr even if logging to file * Fix unit test --- legate/driver/command.py | 2 +- tests/unit/legate/driver/test_command.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/legate/driver/command.py b/legate/driver/command.py index 3a27f7818..92a5ea3d4 100644 --- a/legate/driver/command.py +++ b/legate/driver/command.py @@ -366,7 +366,7 @@ def cmd_log_file( log_to_file = config.logging.log_to_file if log_to_file: - return ("-logfile", str(log_dir / "legate_%.log")) + return ("-logfile", str(log_dir / "legate_%.log"), "-errlevel", "4") return () diff --git a/tests/unit/legate/driver/test_command.py b/tests/unit/legate/driver/test_command.py index b95fcbfba..2ea0b7c53 100644 --- a/tests/unit/legate/driver/test_command.py +++ b/tests/unit/legate/driver/test_command.py @@ -1380,7 +1380,7 @@ def test_flag_without_dir(self, genobjs: GenObjs) -> None: result = m.cmd_log_file(config, system, launcher) logfile = str(config.logging.logdir / "legate_%.log") - assert result == ("-logfile", logfile) + assert result == ("-logfile", logfile, "-errlevel", "4") def test_flag_with_dir(self, genobjs: GenObjs) -> None: config, system, launcher = genobjs( @@ -1390,7 +1390,7 @@ def test_flag_with_dir(self, genobjs: GenObjs) -> None: result = m.cmd_log_file(config, system, launcher) logfile = str(Path("foo") / "legate_%.log") - assert result == ("-logfile", logfile) + assert result == ("-logfile", logfile, "-errlevel", "4") class Test_cmd_eager_alloc: From 02bb2be53381910a9341a3b6bfc5ff2f8eec2b9d Mon Sep 17 00:00:00 2001 From: Jeremy Date: Mon, 27 Feb 2023 20:24:44 -0800 Subject: [PATCH 39/57] Fix C++ warnings, virtual destructor bugs, and style issues (#591) * fix C++ warnings, virtual destructor bugs, and style issues * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/core/mapping/core_mapper.cc | 65 +++++++++++++++++---------------- src/core/mapping/mapping.h | 8 +++- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/src/core/mapping/core_mapper.cc b/src/core/mapping/core_mapper.cc index 0d09e3c7d..0e42875a1 100644 --- a/src/core/mapping/core_mapper.cc +++ b/src/core/mapping/core_mapper.cc @@ -49,6 +49,7 @@ class CoreMapper : public Legion::Mapping::NullMapper { CoreMapper(Legion::Mapping::MapperRuntime* runtime, Legion::Machine machine, const LibraryContext& context); + virtual ~CoreMapper(); public: @@ -58,44 +59,44 @@ class CoreMapper : public Legion::Mapping::NullMapper { static const char* create_name(Legion::AddressSpace node); public: - virtual const char* get_mapper_name() const override; - virtual Legion::Mapping::Mapper::MapperSyncModel get_mapper_sync_model() const override; - virtual bool request_valid_instances() const { return false; } + const char* get_mapper_name() const override; + Legion::Mapping::Mapper::MapperSyncModel get_mapper_sync_model() const override; + bool request_valid_instances() const override { return false; } public: // Task mapping calls - virtual void select_task_options(const Legion::Mapping::MapperContext ctx, - const Legion::Task& task, - TaskOptions& output); - virtual void slice_task(const Legion::Mapping::MapperContext ctx, - const Legion::Task& task, - const SliceTaskInput& input, - SliceTaskOutput& output); - virtual void map_task(const Legion::Mapping::MapperContext ctx, - const Legion::Task& task, - const MapTaskInput& input, - MapTaskOutput& output); - virtual void select_sharding_functor(const Legion::Mapping::MapperContext ctx, - const Legion::Task& task, - const SelectShardingFunctorInput& input, - SelectShardingFunctorOutput& output); - virtual void select_steal_targets(const Legion::Mapping::MapperContext ctx, - const SelectStealingInput& input, - SelectStealingOutput& output); - virtual void select_tasks_to_map(const Legion::Mapping::MapperContext ctx, - const SelectMappingInput& input, - SelectMappingOutput& output); + void select_task_options(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + TaskOptions& output) override; + void slice_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + const SliceTaskInput& input, + SliceTaskOutput& output) override; + void map_task(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + const MapTaskInput& input, + MapTaskOutput& output) override; + void select_sharding_functor(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + const SelectShardingFunctorInput& input, + SelectShardingFunctorOutput& output) override; + void select_steal_targets(const Legion::Mapping::MapperContext ctx, + const SelectStealingInput& input, + SelectStealingOutput& output) override; + void select_tasks_to_map(const Legion::Mapping::MapperContext ctx, + const SelectMappingInput& input, + SelectMappingOutput& output) override; public: - virtual void configure_context(const Legion::Mapping::MapperContext ctx, - const Legion::Task& task, - ContextConfigOutput& output); + void configure_context(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + ContextConfigOutput& output) override; void map_future_map_reduction(const Legion::Mapping::MapperContext ctx, const FutureMapReductionInput& input, - FutureMapReductionOutput& output); - virtual void select_tunable_value(const Legion::Mapping::MapperContext ctx, - const Legion::Task& task, - const SelectTunableInput& input, - SelectTunableOutput& output); + FutureMapReductionOutput& output) override; + void select_tunable_value(const Legion::Mapping::MapperContext ctx, + const Legion::Task& task, + const SelectTunableInput& input, + SelectTunableOutput& output) override; protected: template diff --git a/src/core/mapping/mapping.h b/src/core/mapping/mapping.h index bb1b92b3c..247b283be 100644 --- a/src/core/mapping/mapping.h +++ b/src/core/mapping/mapping.h @@ -152,14 +152,18 @@ struct StoreMapping { static StoreMapping default_mapping(const Store& store, StoreTarget target, bool exact = false); }; -struct MachineQueryInterface { +class MachineQueryInterface { + public: + virtual ~MachineQueryInterface() {} virtual const std::vector& cpus() const = 0; virtual const std::vector& gpus() const = 0; virtual const std::vector& omps() const = 0; virtual uint32_t total_nodes() const = 0; }; -struct LegateMapper { +class LegateMapper { + public: + virtual ~LegateMapper() {} virtual void set_machine(const MachineQueryInterface* machine) = 0; virtual TaskTarget task_target(const Task& task, const std::vector& options) = 0; virtual std::vector store_mappings(const Task& task, From f85ec7bfbb10acc334d1f70fe12726cca2cab600 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 28 Feb 2023 20:45:24 -0800 Subject: [PATCH 40/57] Re-enable collectives (#598) Co-authored-by: Manolis Papadakis --- cmake/Modules/legate_core_options.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/legate_core_options.cmake b/cmake/Modules/legate_core_options.cmake index 7e4b80261..158eae120 100644 --- a/cmake/Modules/legate_core_options.cmake +++ b/cmake/Modules/legate_core_options.cmake @@ -78,7 +78,7 @@ endif() option(legate_core_STATIC_CUDA_RUNTIME "Statically link the cuda runtime library" OFF) option(legate_core_EXCLUDE_LEGION_FROM_ALL "Exclude Legion targets from legate.core's 'all' target" OFF) -option(legate_core_COLLECTIVE "Use of collective instances" OFF) +option(legate_core_COLLECTIVE "Use of collective instances" ON) set_or_default(NCCL_DIR NCCL_PATH) From ab0a15f7bc6cac9deccab8e911c6454289f735e3 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 28 Feb 2023 20:49:35 -0800 Subject: [PATCH 41/57] Fixes for running cuNumeric CI multi-node (#597) * Global callbacks must have external linkage * Restricted attachment is disallowed in replicated contexts --------- Co-authored-by: Manolis Papadakis --- legate/core/store.py | 9 +++------ src/core/runtime/runtime.cc | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/legate/core/store.py b/legate/core/store.py index 086418503..107339ddc 100644 --- a/legate/core/store.py +++ b/legate/core/store.py @@ -178,10 +178,9 @@ def record_detach(detach: Union[Detach, IndexDetach]) -> None: mapper=context.mapper_id, provenance=context.provenance, ) - # If we're not sharing then there is no need to map or restrict the - # attachment + attach.set_restricted(False) + # If we're not sharing then there is no need to map the attachment if not share: - attach.set_restricted(False) attach.set_mapped(False) else: self.physical_region_mapped = True @@ -231,9 +230,7 @@ def record_detach(detach: Union[Detach, IndexDetach]) -> None: provenance=context.provenance, ) index_attach.set_deduplicate_across_shards(True) - # If we're not sharing there is no need to restrict the attachment - if not share: - index_attach.set_restricted(False) + index_attach.set_restricted(False) external_resources = runtime.dispatch(index_attach) # We don't need to flush the contents back to the attached memory # if this is an internal temporary allocation. diff --git a/src/core/runtime/runtime.cc b/src/core/runtime/runtime.cc index dbc34030b..020ff02cb 100644 --- a/src/core/runtime/runtime.cc +++ b/src/core/runtime/runtime.cc @@ -150,7 +150,7 @@ struct RegistrationCallbackArgs { Core::RegistrationCallback callback; }; -static void invoke_legate_registration_callback(const Legion::RegistrationCallbackArgs& args) +void invoke_legate_registration_callback(const Legion::RegistrationCallbackArgs& args) { auto p_args = static_cast(args.buffer.get_ptr()); p_args->callback(); From c00fcc003a22e21c9a39ba4568296287de7a519a Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 28 Feb 2023 20:52:40 -0800 Subject: [PATCH 42/57] Remove support for python 3.8 (#595) --- BUILD.md | 2 +- conda/conda-build/conda_build_config.yaml | 1 - scripts/generate-conda-envs.py | 2 +- setup.cfg | 2 +- setup.py | 1 - 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/BUILD.md b/BUILD.md index 4329cdefa..43c054fe9 100644 --- a/BUILD.md +++ b/BUILD.md @@ -125,7 +125,7 @@ Legate has been tested on Linux and MacOS, although only a few flavors of Linux such as Ubuntu have been thoroughly tested. There is currently no support for Windows. -### Python >= 3.8 (`--python` flag) +### Python >= 3.9 (`--python` flag) In terms of Python compatibility, Legate *roughly* follows the timeline outlined in [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html). diff --git a/conda/conda-build/conda_build_config.yaml b/conda/conda-build/conda_build_config.yaml index b5ebf7fa5..00fe47139 100644 --- a/conda/conda-build/conda_build_config.yaml +++ b/conda/conda-build/conda_build_config.yaml @@ -3,7 +3,6 @@ gpu_enabled: - false python: - - 3.8 - "3.9,!=3.9.7" - 3.10 diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index f5a354b6a..698dedaac 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -220,7 +220,7 @@ def filename(self) -> str: # --- Setup ------------------------------------------------------------------- -PYTHON_VERSIONS = ("3.8", "3.9", "3.10") +PYTHON_VERSIONS = ("3.9", "3.10") CTK_VERSIONS = ( "none", diff --git a/setup.cfg b/setup.cfg index 71b5eaf9b..65a47048c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -61,4 +61,4 @@ packages = find: install_requires = numpy>=1.22 # TODO: Add rest of install dependencies -python_requires = >=3.8,!=3.9.7 +python_requires = >=3.9,!=3.9.7 diff --git a/setup.py b/setup.py index 89583411a..f03a05cc4 100755 --- a/setup.py +++ b/setup.py @@ -33,7 +33,6 @@ "Topic :: Scientific/Engineering", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", ], From f5ec849f521a481892a64f0448a08a75532e4f41 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Wed, 1 Mar 2023 09:35:40 -0800 Subject: [PATCH 43/57] set sphinx theme minver to 0.13 (#594) --- scripts/generate-conda-envs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 698dedaac..a43a84aff 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -165,7 +165,7 @@ def pip(self) -> Reqs: "ipython", "jinja2", "markdown<3.4.0", - "pydata-sphinx-theme", + "pydata-sphinx-theme>=0.13", "myst-parser", "nbsphinx", "sphinx-copybutton", From 668e617b24f81243074e1a7a2fbaf4dae5bf7586 Mon Sep 17 00:00:00 2001 From: Seyed Mirsadeghi Date: Wed, 1 Mar 2023 13:46:03 -0500 Subject: [PATCH 44/57] Fix ucx:tls_host default value (#592) "^dc,ud" will NOT work properly in UCX until 1.14.1 is released. --- legate/driver/command.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/legate/driver/command.py b/legate/driver/command.py index 92a5ea3d4..b4ab348fe 100644 --- a/legate/driver/command.py +++ b/legate/driver/command.py @@ -382,7 +382,7 @@ def cmd_eager_alloc( def cmd_ucx( config: ConfigProtocol, system: System, launcher: Launcher ) -> CommandPart: - return ("-ucx:tls_host", "^dc,ud") + return ("-ucx:tls_host", "rc,tcp,cuda_copy,cuda_ipc,sm,self") def cmd_user_script( From 90224a148547fe5e33097e9b30bfe78eab0ebdb3 Mon Sep 17 00:00:00 2001 From: Paul Taylor Date: Wed, 1 Mar 2023 12:01:47 -0800 Subject: [PATCH 45/57] append CTK stubs dir to implicit link directories so stubs don't end up in library consumers' rpaths (#599) --- cmake/thirdparty/get_legion.cmake | 63 +++++++++++++++++-------------- legate_core_cpp.cmake | 7 ++++ 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/cmake/thirdparty/get_legion.cmake b/cmake/thirdparty/get_legion.cmake index cb87c4f82..f7b1bb5de 100644 --- a/cmake/thirdparty/get_legion.cmake +++ b/cmake/thirdparty/get_legion.cmake @@ -86,38 +86,41 @@ function(find_or_configure_legion) endif() # Get the `stubs/libcuda.so` path so we can set CMAKE_LIBRARY_PATH for FindCUDA.cmake + set(_libdir "lib64") + if(CMAKE_SIZEOF_VOID_P LESS 8) + set(_libdir "lib") + endif() - # Prefer users' CUDA_PATH envvar (if set) - set(_cuda_stubs "$ENV{CUDA_PATH}") - if(NOT _cuda_stubs) - if(DEFINED ENV{CUDA_LIB_PATH}) - # Prefer users' CUDA_LIB_PATH envvar (if set) - list(APPEND _cuda_stubs "$ENV{CUDA_LIB_PATH}") - message(VERBOSE "legate.core: Path(s) to CUDA stubs: ${_cuda_stubs}") - elseif(EXISTS "${CUDAToolkit_LIBRARY_DIR}/stubs/libcuda.so") - # This might be the path to the `$CONDA_PREFIX/lib` - # If it is (and it has the libcuda.so driver stub), - # then we know we're using the cuda-toolkit package - # and should link to that driver stub instead of the - # one potentially in `/usr/local/cuda/lib[64]/stubs` - list(APPEND _cuda_stubs "${CUDAToolkit_LIBRARY_DIR}/stubs") - message(VERBOSE "legate.core: Path(s) to CUDA stubs: ${_cuda_stubs}") - elseif(DEFINED ENV{LIBRARY_PATH}) - # LIBRARY_PATH is set automatically in the `nvidia/cuda` containers. - # Only use it if the conda env doesn't have the `stubs/libcuda.so` lib. - list(APPEND _cuda_stubs "$ENV{LIBRARY_PATH}") - message(VERBOSE "legate.core: Path(s) to CUDA stubs: ${_cuda_stubs}") - elseif(CMAKE_SIZEOF_VOID_P LESS 8) - # Otherwise assume stubs are relative to the CUDA toolkit root dir - list(APPEND _cuda_stubs "${CUDAToolkit_LIBRARY_ROOT}/lib/stubs") - message(VERBOSE "legate.core: Path(s) to CUDA stubs: ${_cuda_stubs}") - else() - # Otherwise assume stubs are relative to the CUDA toolkit root dir - list(APPEND _cuda_stubs "${CUDAToolkit_LIBRARY_ROOT}/lib64/stubs") - message(VERBOSE "legate.core: Path(s) to CUDA stubs: ${_cuda_stubs}") - endif() + if(EXISTS "${CUDAToolkit_LIBRARY_DIR}/stubs/libcuda.so") + # This might be the path to the `$CONDA_PREFIX/lib` + # If it is (and it has the libcuda.so driver stub), + # then we know we're using the cuda-toolkit package + # and should link to that driver stub instead of the + # one potentially in `/usr/local/cuda/lib[64]/stubs` + list(APPEND _cuda_stubs "${CUDAToolkit_LIBRARY_DIR}/stubs") + elseif(EXISTS "${CUDAToolkit_TARGET_DIR}/${_libdir}/stubs/libcuda.so") + # Otherwise assume stubs are relative to the CUDA toolkit root dir + list(APPEND _cuda_stubs "${CUDAToolkit_TARGET_DIR}/${_libdir}/stubs") + elseif(EXISTS "${CUDAToolkit_LIBRARY_ROOT}/${_libdir}/stubs/libcuda.so") + list(APPEND _cuda_stubs "${CUDAToolkit_LIBRARY_ROOT}/${_libdir}/stubs") + elseif(DEFINED ENV{CUDA_PATH} AND EXISTS "$ENV{CUDA_PATH}/${_libdir}/stubs/libcuda.so") + # Use CUDA_PATH envvar (if set) + list(APPEND _cuda_stubs "$ENV{CUDA_PATH}/${_libdir}/stubs/libcuda.so") + elseif(DEFINED ENV{CUDA_LIB_PATH} AND EXISTS "$ENV{CUDA_LIB_PATH}/stubs/libcuda.so") + # Use CUDA_LIB_PATH envvar (if set) + list(APPEND _cuda_stubs "$ENV{CUDA_LIB_PATH}/stubs/libcuda.so") + elseif(DEFINED ENV{LIBRARY_PATH} AND + ("$ENV{LIBRARY_PATH}" STREQUAL "/usr/local/cuda/${_libdir}/stubs")) + # LIBRARY_PATH is set in the `nvidia/cuda` containers to /usr/local/cuda/lib64/stubs + list(APPEND _cuda_stubs "$ENV{LIBRARY_PATH}") + else() + message(FATAL_ERROR "Could not find the libcuda.so driver stub. " + "Please reconfigure with -DCUDAToolkit_ROOT= " + "set to a valid CUDA Toolkit installation.") endif() + message(VERBOSE "legate.core: Path(s) to CUDA stubs: ${_cuda_stubs}") + list(APPEND _legion_cuda_options "CUDA_NVCC_FLAGS ${_nvcc_flags}") list(APPEND _legion_cuda_options "CMAKE_CUDA_STANDARD ${_cuda_std}") # Set this so Legion correctly finds the CUDA toolkit. @@ -131,6 +134,8 @@ function(find_or_configure_legion) list(APPEND CMAKE_C_IMPLICIT_LINK_DIRECTORIES "${_cuda_stubs}") list(APPEND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "${_cuda_stubs}") list(APPEND CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES "${_cuda_stubs}") + set(legate_core_cuda_stubs_path "${_cuda_stubs}" PARENT_SCOPE) + set(legate_core_cuda_stubs_path "${_cuda_stubs}" CACHE STRING "" FORCE) endif() # Because legion sets these as cache variables, we need to force set this as a cache variable here diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index d7e1047f5..5d6e80715 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -412,6 +412,13 @@ endif() ]=] ) +if(DEFINED legate_core_cuda_stubs_path) + string(JOIN "\n" code_string "${code_string}" + "list(APPEND CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${legate_core_cuda_stubs_path})" + "list(APPEND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES ${legate_core_cuda_stubs_path})" + "list(APPEND CMAKE_CUDA_IMPLICIT_LINK_DIRECTORIES ${legate_core_cuda_stubs_path})") +endif() + rapids_export( INSTALL legate_core EXPORT_SET legate-core-exports From 6c7f61dd37f39d7f06bbf43d287eec13d8d7fe4f Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Wed, 1 Mar 2023 13:36:32 -0800 Subject: [PATCH 46/57] API reference (#563) * Initial work on API reference * Add Doxygen build to CMake * Add a doxygen dependency * Strip out the right prefix of header paths * More docstrings for C++ code * Docstrings for remaning C++ files * Parallel build for Sphinx doc * Docstrings for Store * API reference for operations * API reference for context and runtime * Document top-level routines * Documentation on shape and inline allocation * Put back a docstring missed by the merge * Put a brief description on the new variant.h * Put a missing @param * Docstrings for machine query interface * Docstrings for legate::Core * More docstrings for task, task registrar, and library context * Docstrings for all imported classes * Put module boundaries and add more docstrings to utilities * Minor tunning for the main page * Doxygen needs to be installed via conda * Address review comments --- cmake/Modules/legate_core_options.cmake | 1 + docs/legate/core/Makefile | 3 +- docs/legate/core/source/api/allocation.rst | 20 + docs/legate/core/source/api/classes.rst | 14 + docs/legate/core/source/api/index.rst | 42 +- docs/legate/core/source/api/operation.rst | 120 ++++++ docs/legate/core/source/api/routines.rst | 11 + docs/legate/core/source/api/runtime.rst | 101 +++++ docs/legate/core/source/api/shape.rst | 62 +++ docs/legate/core/source/api/store.rst | 125 ++++++ install.py | 12 + legate/core/allocation.py | 17 + legate/core/context.py | 310 +++++++++++++- legate/core/legate.py | 37 +- legate/core/operation.py | 444 ++++++++++++++++++--- legate/core/resource.py | 19 +- legate/core/runtime.py | 61 +++ legate/core/shape.py | 348 ++++++++++++++++ legate/core/store.py | 387 +++++++++++++++++- legate_core_cpp.cmake | 52 +++ scripts/generate-conda-envs.py | 2 +- src/core/comm/communicator.h | 31 +- src/core/cuda/stream_pool.h | 38 ++ src/core/data/allocator.h | 39 ++ src/core/data/buffer.h | 72 +++- src/core/data/scalar.cc | 2 +- src/core/data/scalar.h | 70 ++++ src/core/data/store.h | 185 +++++++++ src/core/mapping/mapping.cc | 2 + src/core/mapping/mapping.h | 238 ++++++++++- src/core/mapping/operation.h | 94 ++++- src/core/runtime/context.h | 153 ++++++- src/core/runtime/runtime.h | 16 + src/core/task/exception.h | 42 +- src/core/task/registrar.h | 59 +++ src/core/task/task.h | 37 ++ src/core/task/variant.h | 35 +- src/core/utilities/debug.h | 34 ++ src/core/utilities/dispatch.h | 58 +++ src/core/utilities/span.h | 47 +++ src/core/utilities/type_traits.h | 37 ++ src/core/utilities/typedefs.h | 244 ++++++++++- src/legate.h | 6 + 43 files changed, 3555 insertions(+), 172 deletions(-) create mode 100644 docs/legate/core/source/api/allocation.rst create mode 100644 docs/legate/core/source/api/classes.rst create mode 100644 docs/legate/core/source/api/operation.rst create mode 100644 docs/legate/core/source/api/routines.rst create mode 100644 docs/legate/core/source/api/runtime.rst create mode 100644 docs/legate/core/source/api/shape.rst create mode 100644 docs/legate/core/source/api/store.rst diff --git a/cmake/Modules/legate_core_options.cmake b/cmake/Modules/legate_core_options.cmake index 158eae120..62fd1e759 100644 --- a/cmake/Modules/legate_core_options.cmake +++ b/cmake/Modules/legate_core_options.cmake @@ -79,6 +79,7 @@ endif() option(legate_core_STATIC_CUDA_RUNTIME "Statically link the cuda runtime library" OFF) option(legate_core_EXCLUDE_LEGION_FROM_ALL "Exclude Legion targets from legate.core's 'all' target" OFF) option(legate_core_COLLECTIVE "Use of collective instances" ON) +option(legate_core_BUILD_DOCS "Build doxygen docs" OFF) set_or_default(NCCL_DIR NCCL_PATH) diff --git a/docs/legate/core/Makefile b/docs/legate/core/Makefile index bff64057f..72ea3d7ea 100644 --- a/docs/legate/core/Makefile +++ b/docs/legate/core/Makefile @@ -19,6 +19,7 @@ # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= -v -W +PARALLEL_BUILD ?= 1 SPHINXBUILD ?= legate $(shell which sphinx-build) SOURCEDIR = source BUILDDIR = build @@ -32,7 +33,7 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -j $(PARALLEL_BUILD) rm -rf build/html/docs mkdir -p build/html/docs cp -r ../../figures build/html/docs/ diff --git a/docs/legate/core/source/api/allocation.rst b/docs/legate/core/source/api/allocation.rst new file mode 100644 index 000000000..5f71df89c --- /dev/null +++ b/docs/legate/core/source/api/allocation.rst @@ -0,0 +1,20 @@ +.. _label_allocation: + +.. currentmodule:: legate.core.allocation + +Inline mapping +============== + +When a client requests an immediate allocation of a store with +:meth:`legate.core.store.Store.get_inline_allocation`, the runtime gives you +back an ``InlineMappedAllocation`` object, which is a thin wrapper around the +allocation. Since the runtime needs to keep track of lifetimes of Python +objects using the allocation, the wrapper reveals the allocation to a callback +and not directly. Doing it this way allows the runtime to capture the object +constructed from the allocation and tie their lifetimes. + + +.. autosummary:: + :toctree: generated/ + + InlineMappedAllocation.consume diff --git a/docs/legate/core/source/api/classes.rst b/docs/legate/core/source/api/classes.rst new file mode 100644 index 000000000..f46811a82 --- /dev/null +++ b/docs/legate/core/source/api/classes.rst @@ -0,0 +1,14 @@ +------- +Classes +------- + +.. toctree:: + :maxdepth: 2 + + runtime + operation + store + allocation + shape +.. partition +.. legion diff --git a/docs/legate/core/source/api/index.rst b/docs/legate/core/source/api/index.rst index d5516f6dc..abe6a5ab9 100644 --- a/docs/legate/core/source/api/index.rst +++ b/docs/legate/core/source/api/index.rst @@ -5,43 +5,7 @@ API Reference .. currentmodule:: legate.core .. toctree:: - :maxdepth: 1 + :maxdepth: 2 -.. autosummary:: - :toctree: generated/ - - Point - Rect - Domain - Transform - AffineTransform - IndexSpace - PartitionFunctor - PartitionByRestriction - PartitionByImage - PartitionByImageRange - EqualPartition - PartitionByWeights - IndexPartition - FieldSpace - FieldID - Region - Partition - Fill - IndexFill - Copy - IndexCopy - Attach - Detach - Acquire - Release - Future - OutputRegion - PhysicalRegion - InlineMapping - Task - FutureMap - IndexTask - Fence - ArgumentMap - BufferBuilder + routines + classes diff --git a/docs/legate/core/source/api/operation.rst b/docs/legate/core/source/api/operation.rst new file mode 100644 index 000000000..f84a1bced --- /dev/null +++ b/docs/legate/core/source/api/operation.rst @@ -0,0 +1,120 @@ +.. _label_operation: + +.. currentmodule:: legate.core.operation + +Operations +========== + +Operations in Legate are by default automatically parallelized. Legate extracts +parallelism from an operation by partitioning its store arguments. Operations +usually require the partitions to be aligned in some way; e.g., partitioning +vectors across multiple addition tasks requires the vectors to be partitioned +in the same way. Legate provides APIs for developers to control how stores are +partitioned via `partitioning constraints`. + +When an operation needs a store to be partitioned more than one way, the +operation can create `partition symbols` and use them in partitioning +constraints. In that case, a partition symbol must be passed along with the +store when the store is added. Stores can be partitioned in multiple ways when +they are used only for read accesses or reductions. + +AutoTask +-------- + +``AutoTask`` is a type of tasks that are automatically parallelized. Each +Legate task is associated with a task id that uniquely names a task to invoke. +The actual task implementation resides on the C++ side. + +.. autosummary:: + :toctree: generated/ + + AutoTask.add_input + AutoTask.add_output + AutoTask.add_reduction + AutoTask.add_scalar_arg + AutoTask.declare_partition + AutoTask.add_constraint + AutoTask.add_alignment + AutoTask.add_broadcast + AutoTask.throws_exception + AutoTask.can_raise_exception + AutoTask.add_nccl_communicator + AutoTask.add_cpu_communicator + AutoTask.side_effect + AutoTask.set_concurrent + AutoTask.set_side_effect + AutoTask.execute + + +Copy +---- + +``Copy`` is a special kind of operation for copying data from one store to +another. Unlike tasks that are mapped to and run on application processors, +copies are performed by the DMA engine in the runtime. Also, unlike tasks that +are user-defined, copies have well-defined semantics and come with predefined +partitioning assumptions on stores. Hence, copies need not take partitioning +constraints from developers. + +A copy can optionally take a store for indices that need to be used in +accessing the source or target. With an `indirection` store on the source, the +copy performs a gather operation, and with an indirection on the target, the +copy does a scatter; when indirections exist for both the source and target, +the copy turns into a full gather-scatter copy. Out-of-bounds indices are not +checked and can produce undefined behavior. The caller therefore is responsible +for making sure the indices are within bounds. + +.. autosummary:: + :toctree: generated/ + + Copy.add_input + Copy.add_output + Copy.add_reduction + Copy.add_source_indirect + Copy.add_target_indirect + Copy.execute + +Fill +---- + +``Fill`` is a special kind of operation for filling a store with constant values. +Like coipes, fills are performed by the DMA engine and their partitioning +constraints are predefined. + +.. autosummary:: + :toctree: generated/ + + Fill.execute + + +Manually Parallelized Tasks +--------------------------- + +In some occassions, tasks are unnatural or even impossible to write in the +auto-parallelized style. For those occassions, Legate provides explicit control +on how tasks are parallelized via ``ManualTask``. Each manual task requires the +caller to provide a `launch domain` that determines the degree of parallelism +and also names task instances initiaed by the task. Direct store arguments to a +manual task are assumed to be replicated across task instances, and it's the +developer's responsibility to partition stores. Mapping between points in the +launch domain and colors in the color space of a store partition is assumed to +be an identity mapping by default, but it can be configured with a `projection +function`, a Python function on tuples of coordinates. (See +:ref:`StorePartition ` for definitions of color, +color space, and store partition.) + +.. autosummary:: + :toctree: generated/ + + ManualTask.side_effect + ManualTask.set_concurrent + ManualTask.set_side_effect + ManualTask.add_input + ManualTask.add_output + ManualTask.add_reduction + ManualTask.add_scalar_arg + ManualTask.throws_exception + ManualTask.can_raise_exception + ManualTask.add_nccl_communicator + ManualTask.add_cpu_communicator + ManualTask.execute diff --git a/docs/legate/core/source/api/routines.rst b/docs/legate/core/source/api/routines.rst new file mode 100644 index 000000000..78dd1609a --- /dev/null +++ b/docs/legate/core/source/api/routines.rst @@ -0,0 +1,11 @@ +.. currentmodule:: legate.core + +-------- +Routines +-------- + +.. autosummary:: + :toctree: generated/ + + get_legate_runtime + track_provenance diff --git a/docs/legate/core/source/api/runtime.rst b/docs/legate/core/source/api/runtime.rst new file mode 100644 index 000000000..8a4033e43 --- /dev/null +++ b/docs/legate/core/source/api/runtime.rst @@ -0,0 +1,101 @@ +.. _label_runtime: + +.. currentmodule:: legate.core + +Runtime and Library Contexts +============================ + +Library +------- + +A ``Library`` class is an interface that every library descriptor needs to +implement. Each library should tell the Legate runtime how to initialize and +configure the library, and this class provides a common way to reveal that +information to the runtime. Each library should register to the runtime a +library descriptor object that implements ``Library`` directly or via duck +typing. (See :meth:`legate.core.runtime.Runtime.register_library`.) + +.. autosummary:: + :toctree: generated/ + + Library.get_name + Library.get_shared_library + Library.get_c_header + Library.get_registration_callback + Library.get_resource_configuration + + +Resource configuration +---------------------- + +A ``ResourceConfig`` object describes the maximum number of handles that a +library uses. + +.. autosummary:: + :toctree: generated/ + + ResourceConfig.max_tasks + ResourceConfig.max_reduction_ops + ResourceConfig.max_mappers + + +Context +------- + +A ``Context`` object provides APIs for creating stores and issuing tasks and +other kinds of operations. When a library registers itself to the Legate +runtime, the runtime gives back a context object unique to the library. + +.. autosummary:: + :toctree: generated/ + + context.Context.create_store + context.Context.create_task + context.Context.create_manual_task + context.Context.create_auto_task + context.Context.create_copy + context.Context.create_fill + context.Context.issue_execution_fence + context.Context.tree_reduce + context.Context.get_tunable + context.Context.provenance + context.Context.annotation + context.Context.set_provenance + context.Context.reset_provenance + context.Context.push_provenance + context.Context.pop_provenance + context.Context.track_provenance + + +Legate Runtime +-------------- + +.. autosummary:: + :toctree: generated/ + + runtime.Runtime.num_cpus + runtime.Runtime.num_omps + runtime.Runtime.num_gpus + runtime.Runtime.register_library + runtime.Runtime.create_future + + +Annotation +---------- + +An ``Annotation`` is a context manager to set library specific annotations that +are to be attached to operations issued within a scope. A typical usage of +``Annotation`` would look like this: + +:: + + with Annotation(lib_context, { "key1" : "value1", "key2" : "value2", ... }: + ... + +Then each operation in the scope is annotated with the key-value pairs, +which are later rendered in execution profiles. + +.. autosummary:: + :toctree: generated/ + + context.Annotation.__init__ diff --git a/docs/legate/core/source/api/shape.rst b/docs/legate/core/source/api/shape.rst new file mode 100644 index 000000000..46b4aeba1 --- /dev/null +++ b/docs/legate/core/source/api/shape.rst @@ -0,0 +1,62 @@ +.. currentmodule:: legate.core.shape + +Shape +===== + +A ``Shape`` is used in expressing the shape of a certain entity in Legate. The +reason Legate introduces this indirection to the shape metadata is that stores +in Legate can have unknown shapes at creation time; the shape of an unbound +store is determined only when the producer task finishes. The shape object can +help the runtime query the store's metadata or construct another store +isomorphic to the store without getting blocked. + +Shape objects should behave just like an array of integers, but operations that +introspect the values implicitly block on completion of the producer task. + + +.. autosummary:: + :toctree: generated/ + + Shape.__init__ + + +Properties +---------- +.. autosummary:: + :toctree: generated/ + + Shape.extents + Shape.fixed + Shape.ndim + Shape.volume + Shape.sum + Shape.strides + + +Manipulation Methods +-------------------- +.. autosummary:: + :toctree: generated/ + + Shape.drop + Shape.update + Shape.replace + Shape.insert + Shape.map + + +Arithmetic and comparison +------------------------- +.. autosummary:: + :toctree: generated/ + + Shape.__eq__ + Shape.__le__ + Shape.__lt__ + Shape.__ge__ + Shape.__gt__ + Shape.__add__ + Shape.__sub__ + Shape.__mul__ + Shape.__mod__ + Shape.__floordiv__ diff --git a/docs/legate/core/source/api/store.rst b/docs/legate/core/source/api/store.rst new file mode 100644 index 000000000..0b95ca443 --- /dev/null +++ b/docs/legate/core/source/api/store.rst @@ -0,0 +1,125 @@ +.. currentmodule:: legate.core.store + +Store +===== + +`Store` is a multi-dimensional data container for fixed-size elements. Stores +are internally partitioned and distributed across the system. By default, +Legate clients need not create nor maintain the partitions explicitly, and the +Legate runtime is responsible for managing them. Legate clients can control how +stores should be partitioned for a given task by attaching partitioning +constraints to the task (see section :ref:`label_operation` for partitioning +constraint APIs). + +Each Store object is a logical handle to the data and is not immediately +associated with a physical allocation. To access the data, a client must +`map` the store to a physical instance. A client can map a store by passing +it to a task, in which case the task body can see the allocation, or calling +``get_inline_allocation``, which gives the client a linear handle to the +physical allocation (see section :ref:`label_allocation` for details about +inline allocations). + +Normally, a store gets a fixed shape upon creation. However, there is a special +type of stores called `unbound` stores whose shapes are unknown at creation +time. (see section :ref:`label_runtime` for the store creation API.) The shape +of an unbound store is determined by a task that first updates the store; upon +the submission of the task, the store becomes a normal store. Passing an +unbound store as a read-only argument or requesting an inline allocation of an +unbound store are invalid. + +One consequence due to the nature of unbound stores is that querying the shape +of a previously unbound store can block the client's control flow for an +obvious reason; to know the shape of the store whose shape was unknown at +creation time, the client must wait until the updater task to finish. However, +passing a previously unbound store to a downstream operation can be +non-blocking, as long as the operation requires no changes in the partitioning +and mapping for the store. + + +Basic Properties +---------------- + +.. autosummary:: + :toctree: generated/ + + Store.shape + Store.ndim + Store.size + Store.type + Store.kind + Store.unbound + Store.scalar +.. Store.extents + + +Transformation +-------------- + +Legate provides several API calls to transform stores. A store after a +transformation is a view to the original store; i.e., any changes made to the +transformed store are visible via the original one and vice versa. + +.. autosummary:: + :toctree: generated/ + + Store.transform + Store.transformed + Store.promote + Store.project + Store.slice + Store.transpose + Store.delinearize + + +Storage management +------------------ + +.. autosummary:: + :toctree: generated/ + + Store.get_inline_allocation +.. Store.storage +.. Store.has_storage + + +Partition management +-------------------- + +In most cases, Legate clients need not create nor manage partitions manually by +themselves. However, there are occasions where the clients need to parallelize +tasks manually, for which stores need to be partitioned manually as well. For +those occasions, clients may want to query and update the `key` partition of +each store, i.e., the partition used for updating the store for the last time. +The following are the API calls for manual partition management. + +.. autosummary:: + :toctree: generated/ + + Store.get_key_partition + Store.set_key_partition + Store.reset_key_partition + Store.partition_by_tiling + + +.. _label_store_partition: + +StorePartition +============== + +A ``StorePartition`` is an object that represents a partitioned state of a +store. A store partition is a name of a collection of `sub-stores`, each of +which contains to a subset of elements in the store. Sub-stores in a store +partition are uniquely identified by their `colors`, and a set of all colors +of a given store partition is called a `color space`. + +It is recommended that store partitions and their sub-stores be used as +arguments to ``ManualTask`` (see section :ref:`label_operation` for APIs for +manual parallelization). + + +.. autosummary:: + :toctree: generated/ + + StorePartition.store + StorePartition.partition + StorePartition.get_child_store diff --git a/install.py b/install.py index 149910f54..57bcc692b 100755 --- a/install.py +++ b/install.py @@ -241,6 +241,7 @@ def install( hdf, llvm, spy, + build_docs, conduit, nccl_dir, cmake_exe, @@ -288,6 +289,7 @@ def install( print("hdf:", hdf) print("llvm:", llvm) print("spy:", spy) + print("build_docs:", build_docs) print("conduit:", conduit) print("nccl_dir:", nccl_dir) print("cmake_exe:", cmake_exe) @@ -464,6 +466,8 @@ def validate_path(path): cmake_flags += [f"-Dlegate_core_LEGION_REPOSITORY={legion_url}"] if legion_branch: cmake_flags += [f"-Dlegate_core_LEGION_BRANCH={legion_branch}"] + if build_docs: + cmake_flags += ["-Dlegate_core_BUILD_DOCS=ON"] cmake_flags += extra_flags build_flags = [f"-j{str(thread_count)}"] @@ -620,6 +624,14 @@ def driver(): default=os.environ.get("USE_SPY", "0") == "1", help="Build Legate with detailed Legion Spy enabled.", ) + parser.add_argument( + "--docs", + dest="build_docs", + action="store_true", + required=False, + default=False, + help="Build Doxygen docs.", + ) parser.add_argument( "--conduit", dest="conduit", diff --git a/legate/core/allocation.py b/legate/core/allocation.py index 4f7354e42..b2b86f6c2 100644 --- a/legate/core/allocation.py +++ b/legate/core/allocation.py @@ -49,6 +49,23 @@ def __del__(self) -> None: def consume( self, ctor: Callable[[tuple[int, ...], int, tuple[int, ...]], Any] ) -> Any: + """ + Consumes the allocation. Each allocation can be consumed only once. + + Parameters + ---------- + ctor : Callback + Callback that constructs a Python object from the allocation. + Each callback gets the shape, the physical address, and the strides + of the allocation, and is supposed to return a Python object + using the allocation. Leaking the three arguments in some other way + will lead to an undefined behavior. + + Returns + ------- + Any + Python object the callback constructs from the allocation + """ if self._consumed: raise RuntimeError("Each inline mapping can be consumed only once") self._consumed = True diff --git a/legate/core/context.py b/legate/core/context.py index ca226a647..e044271ae 100644 --- a/legate/core/context.py +++ b/legate/core/context.py @@ -160,6 +160,14 @@ def destroy(self) -> None: @property def runtime(self) -> Runtime: + """ + Returns the runtime + + Returns + ------- + Runtime + The runtime object + """ return self._runtime @property @@ -192,6 +200,15 @@ def type_system(self) -> TypeSystem: @property def annotation(self) -> LibraryAnnotations: + """ + Returns the current set of annotations. Provenance string is one + entry in the set. + + Returns + ------- + LibraryAnnotations + Library annotations + """ return self._annotations[-1] def get_all_annotations(self) -> str: @@ -199,6 +216,15 @@ def get_all_annotations(self) -> str: @property def provenance(self) -> Optional[str]: + """ + Returns the current provenance string. Attached to every operation + issued with the context. + + Returns + ------- + str or None + Provenance string + """ return self.annotation.provenance def get_task_id(self, task_id: int) -> int: @@ -226,6 +252,25 @@ def get_sharding_id(self, shard_id: int) -> int: def get_tunable( self, tunable_id: int, dtype: DataType, mapper_id: int = 0 ) -> npt.NDArray[Any]: + """ + Queries a tunable parameter to the mapper. + + Parameters + ---------- + tunable_id : int + Tunable id. Local to each mapper. + + dtype : DataType + Value type + + mapper_id : int + Id of the mapper that should handle the tunable query + + Returns + ------- + np.ndarray + A NumPy array holding the value of the tunable parameter + """ dt = np.dtype(dtype.to_pandas_dtype()) mapper_id = self.get_mapper_id(mapper_id) fut = Future( @@ -244,16 +289,38 @@ def get_unique_op_id(self) -> int: return self._runtime.get_unique_op_id() def set_provenance(self, provenance: str) -> None: + """ + Sets a new provenance string + + Parameters + ---------- + provenance : str + Provenance string + """ self._annotations[-1].set_provenance(provenance) def reset_provenance(self) -> None: + """ + Clears the provenance string that is currently set + """ self._annotations[-1].reset_provenance() def push_provenance(self, provenance: str) -> None: + """ + Pushes a provenance string to the stack + + Parameters + ---------- + provenance : str + Provenance string + """ self._annotations.append(LibraryAnnotations()) self.set_provenance(provenance) def pop_provenance(self) -> None: + """ + Pops the provenance string on top the stack + """ if len(self._annotations) == 1: raise ValueError("Provenance stack underflow") self._annotations.pop(-1) @@ -261,6 +328,25 @@ def pop_provenance(self) -> None: def track_provenance( self, func: AnyCallable, nested: bool = False ) -> AnyCallable: + """ + Wraps a function with provenance tracking. Provenance of each operation + issued within the wrapped function will be tracked automatically. + + Parameters + ---------- + func : AnyCallable + Function to wrap + + nested : bool + If ``True``, each invocation to a wrapped function within another + wrapped function updates the provenance string. Otherwise, the + provenance is tracked only for the outermost wrapped function. + + Returns + ------- + AnyCallable + Wrapped function + """ if nested: def wrapper(*args: Any, **kwargs: Any) -> Any: @@ -286,9 +372,37 @@ def create_task( self, task_id: int, mapper_id: int = 0, - manual: Optional[bool] = False, + manual: bool = False, launch_domain: Optional[Rect] = None, ) -> Union[AutoTask, ManualTask]: + """ + Creates a task. The type of the returned task is determined by the + value of ``manual``. + + Parameters + ---------- + task_id : int + Task id. Scoped locally within the context; i.e., different + libraries can use the same task id. There must be a task + implementation corresponding to the task id. + + mapper_id : int, optional + Id of the mapper that should determine mapping policies for the + task. Used only when the library has more than one mapper. + + manual : bool + Indicates whether the task should be manually parallelized; + if ``True``, the task is parallelized manually by the caller. + + launch_domain : Rect, optional + Launch domain of the task. Ignored if the task is automatically + parallelized, mandatory otherwise. + + Returns + ------- + AutoTask or ManualTask + A new task + """ from .operation import AutoTask, ManualTask unique_op_id = self.get_unique_op_id() @@ -314,6 +428,30 @@ def create_manual_task( mapper_id: int = 0, launch_domain: Optional[Rect] = None, ) -> ManualTask: + """ + Type safe version of ``Context.create_task``. Always returns a + `ManualTask`. + + Parameters + ---------- + task_id : int + Task id + + mapper_id : int, optional + Mapper id + + launch_domain : Rect, optional + Launch domain of the task. + + Returns + ------- + AutoTask + A new auto-parallelized task + + See Also + -------- + Context.create_task + """ from .operation import ManualTask return cast( @@ -330,8 +468,32 @@ def create_auto_task( self, task_id: int, mapper_id: int = 0, - launch_domain: Optional[Rect] = None, ) -> AutoTask: + """ + Type safe version of ``Context.create_task``. Always returns an + `AutoTask`. + + Parameters + ---------- + task_id : int + Task id + + mapper_id : int, optional + Mapper id + + launch_domain : Rect, optional + Launch domain of the task. + + Returns + ------- + AutoTask + A new manually parallelized task + + See Also + -------- + Context.create_task + """ + from .operation import AutoTask return cast( @@ -340,11 +502,25 @@ def create_auto_task( task_id=task_id, mapper_id=mapper_id, manual=False, - launch_domain=launch_domain, ), ) def create_copy(self, mapper_id: int = 0) -> Copy: + """ + Creates a copy operation. + + Parameters + ---------- + mapper_id : int, optional + Id of the mapper that should determine mapping policies for the + copy. Used only when the library has more than one mapper. + + Returns + ------- + Copy + A new copy operation + """ + from .operation import Copy return Copy(self, mapper_id, self.get_unique_op_id()) @@ -352,6 +528,32 @@ def create_copy(self, mapper_id: int = 0) -> Copy: def create_fill( self, lhs: Store, value: Store, mapper_id: int = 0 ) -> Fill: + """ + Creates a fill operation. + + Parameters + ---------- + lhs : Store + Store to fill + + value : Store + Store holding the constant value to fill the ``lhs`` with + + mapper_id : int, optional + Id of the mapper that should determine mapping policies for the + fill. Used only when the library has more than one mapper. + + Returns + ------- + Copy + A new fill operation + + Raises + ------ + ValueError + If the ``value`` is not scalar or the ``lhs`` is either unbound or + scalar + """ from .operation import Fill return Fill(self, lhs, value, mapper_id, self.get_unique_op_id()) @@ -370,6 +572,34 @@ def create_store( optimize_scalar: bool = False, ndim: Optional[int] = None, ) -> Store: + """ + Creates a fresh store. + + Parameters + ---------- + ty : Dtype + Type of the elements + + shape : Shape or tuple[int], optional + Shape of the store. The store becomes unbound if no shape is + given. + + storage : RegionField or Future, optional + Optional storage to initialize the store with. Used only when the + store is constructed from a future holding a scalar value. + + optimize_scalar : bool + If ``True``, the runtime will use a ``Future`` when the store's + size is 1 + + ndim : int, optional + Dimension of the store. Must be passed if the store is unbound. + + Returns + ------- + Store + A new store + """ dtype = self.type_system[ty] return self._runtime.create_store( dtype, @@ -386,11 +616,50 @@ def get_cpu_communicator(self) -> Communicator: return self._runtime.get_cpu_communicator() def issue_execution_fence(self, block: bool = False) -> None: + """ + Issues an execution fence. A fence is a special operation that + guarantees that all upstream operations finish before any of the + downstream operations start. The caller can optionally block on + completion of all upstream operations. + + Parameters + ---------- + block : bool + If ``True``, the call blocks until all upstream operations finish. + """ self._runtime.issue_execution_fence(block=block) def tree_reduce( self, task_id: int, store: Store, mapper_id: int = 0, radix: int = 4 ) -> Store: + """ + Performs a user-defined reduction by building a tree of reduction + tasks. At each step, the reducer task gets up to ``radix`` input stores + and is supposed to produce outputs in a single unbound store. + + Parameters + ---------- + task_id : int + Id of the reducer task + + store : Store + Store to perform reductions on + + mapper_id : int + Id of the mapper that should decide mapping policies for reducer + tasks + + radix : int + Fan-in of each reducer task. If the store is partitioned into + :math:`N` sub-stores by the runtime, then the first level of + reduction tree has :math:`\\ceil{N / \\mathtt{radix}}` reducer + tasks. + + Returns + ------- + Store + Store that contains reduction results + """ from .operation import Reduce result = self.create_store(store.type) @@ -412,6 +681,31 @@ def track_provenance( context: Context, nested: bool = False, ) -> Callable[[AnyCallable], AnyCallable]: + """ + Decorator that adds provenance tracking to functions. Provenance of each + operation issued within the wrapped function will be tracked automatically. + + Parameters + ---------- + context : Context + Context that the function uses to issue operations + + nested : bool + If ``True``, each invocation to a wrapped function within another + wrapped function updates the provenance string. Otherwise, the + provenance is tracked only for the outermost wrapped function. + + Returns + ------- + Decorator + Function that takes a function and returns a one with provenance + tracking + + See Also + -------- + legate.core.context.Context.track_provenance + """ + def decorator(func: AnyCallable) -> AnyCallable: return context.track_provenance(func, nested=nested) @@ -420,6 +714,16 @@ def decorator(func: AnyCallable) -> AnyCallable: class Annotation: def __init__(self, context: Context, pairs: dict[str, str]) -> None: + """ + Constructs a new annotation object + + Parameters + ---------- + context : Context + Context to which the annotations should be added + pairs : dict[str, str] + Annotations as key-value pairs + """ self._annotation = context.annotation self._pairs = pairs diff --git a/legate/core/legate.py b/legate/core/legate.py index 044a41c7e..48b5c3de7 100644 --- a/legate/core/legate.py +++ b/legate/core/legate.py @@ -520,31 +520,56 @@ def __init__(self) -> None: def get_name(self) -> str: """ - Return a string name describing this library + Returns a name of the library + + Returns + ------- + str + Library name """ raise NotImplementedError("Implement in derived classes") - def get_shared_library(self) -> Any: + def get_shared_library(self) -> Optional[str]: """ - Return the name of the shared library + Returns the path to the shared library + + Returns + ------- + str or ``None`` + Path to the shared library """ raise NotImplementedError("Implement in derived classes") def get_c_header(self) -> str: """ - Return a compiled C string header for this library + Returns a compiled C header string for the library + + Returns + ------- + str + C header string """ raise NotImplementedError("Implement in derived classes") def get_registration_callback(self) -> str: """ - Return the name of a C registration callback for this library + Returns the name of a C registration callback for the library + + Returns + ------- + str + The name of the C registration callback """ raise NotImplementedError("Implement in derived classes") def get_resource_configuration(self) -> ResourceConfig: """ - Return a ResourceConfig object that configures the library + Returns a ResourceConfig object that configures the library + + Returns + ------- + ResourceConfig + A ``ResourceConfig`` object """ # Return the default configuration return ResourceConfig() diff --git a/legate/core/operation.py b/legate/core/operation.py index c5bac7b62..bdc282809 100644 --- a/legate/core/operation.py +++ b/legate/core/operation.py @@ -158,6 +158,26 @@ def get_all_stores(self) -> OrderedSet[Store]: return result def add_alignment(self, store1: Store, store2: Store) -> None: + """ + Sets an alignment between stores. Equivalent to the following code: + + :: + + symb1 = op.declare_partition(store1) + symb2 = op.declare_partition(store2) + op.add_constraint(symb1 == symb2) + + Parameters + ---------- + store1, store2 : Store + Stores to align + + Raises + ------ + ValueError + If the stores don't have the same shape or only one of them is + unbound + """ self._check_store(store1, allow_unbound=True) self._check_store(store2, allow_unbound=True) if not ( @@ -175,14 +195,44 @@ def add_alignment(self, store1: Store, store2: Store) -> None: def add_broadcast( self, store: Store, axes: Optional[Union[int, Iterable[int]]] = None ) -> None: + """ + Sets a broadcasting constraint on the store. Equivalent to the + following code: + + :: + + symb = op.declare_partition(store) + op.add_constraint(symb.broadcast(axes)) + + Parameters + ---------- + store : Store + Store to set a broadcasting constraint on + axes : int or Iterable[int], optional + Axes to broadcast. The entire store is replicated if no axes are + given. + """ self._check_store(store) part = self._get_unique_partition(store) self.add_constraint(part.broadcast(axes=axes)) def add_constraint(self, constraint: Constraint) -> None: + """ + Adds a partitioning constraint to the operation + + Parameters + ---------- + constraint : Constraint + Partitioning constraint + """ self._constraints.append(constraint) def execute(self) -> None: + """ + Submits the operation to the runtime. There is no guarantee that the + operation will start the execution right upon the return of this + method. + """ self._context.runtime.submit(self) @staticmethod @@ -220,6 +270,23 @@ def get_name(self) -> str: def declare_partition( self, store: Store, disjoint: bool = True, complete: bool = True ) -> PartSym: + """ + Creates a partition symbol for the store + + Parameters + ---------- + store : Store + Store to associate the partition symbol with + disjoint : bool, optional + ``True`` (by default) means the partition must be disjoint + complete : bool, optional + ``True`` (by default) means the partition must be complete + + Returns + ------- + PartSym + A partition symbol + """ sym = PartSym( self._op_id, self.get_name(), @@ -253,16 +320,62 @@ def __init__( @property def side_effect(self) -> bool: + """ + Indicates whether the task has side effects + + Returns + ------- + bool + ``True`` if the task has side efects + """ return self._side_effect def set_side_effect(self, side_effect: bool) -> None: + """ + Sets whether the task has side effects or not. A task is assumed to be + free of side effects by default if the task only has scalar arguments. + + Parameters + ---------- + side_effect : bool + A new boolean value indicating whether the task has side effects + """ self._side_effect = side_effect @property def concurrent(self) -> bool: + """ + Indicates whether the task needs a concurrent task launch. + + A concurrent task launch guarantees that all tasks will be active at + the same time and make progress concurrently. This means that the tasks + will and should be mapped to distinct processors and that no other + tasks will be interleaved at any given point in time during execution + of the concurrent tasks. This operational guarantee is useful + when the tasks need to perform collective operations or explicit + communication outside Legate, but comes with performance overhead + due to distributed rendezvous used in the launch. + + Returns + ------- + bool + ``True`` if the task needs a concurrent task launch + """ return self._concurrent def set_concurrent(self, concurrent: bool) -> None: + """ + Sets whether the task needs a concurrent task launch. Any task with at + least one communicator will implicitly use concurrent task launch, so + this method is to be used when the task needs a concurrent task launch + for a reason unknown to Legate. + + Parameters + ---------- + concurrent : bool + A new boolean value indicating whether the task needs a concurrent + task launch + """ self._concurrent = concurrent def get_name(self) -> str: @@ -272,6 +385,18 @@ def get_name(self) -> str: def add_scalar_arg( self, value: Any, dtype: Union[DTType, tuple[DTType]] ) -> None: + """ + Adds a by-value argument to the task + + Parameters + ---------- + value : Any + Scalar value or a tuple of scalars (but no nested tuples) + dtype : DType + Data type descriptor for the scalar value. A descriptor ``(T,)`` + means that the value is a tuple of elements of type ``T``. + """ + self._scalar_args.append((value, dtype)) def add_dtype_arg(self, dtype: DTType) -> None: @@ -279,10 +404,29 @@ def add_dtype_arg(self, dtype: DTType) -> None: self._scalar_args.append((code, ty.int32)) def throws_exception(self, exn_type: type) -> None: + """ + Declares that the task can raise an exception. If more than one + exception is added to the task, they are numbered by the order in which + they are added, and those numbers are used to refer to them in the C++ + task. + + Parameters + ---------- + exn_type : Type + Type of exception + """ self._exn_types.append(exn_type) @property def can_raise_exception(self) -> bool: + """ + Indicates whether the task can raise an exception + + Returns + ------- + bool + ``True`` if the task can raise an exception + """ return len(self._exn_types) > 0 def capture_traceback(self) -> None: @@ -427,10 +571,16 @@ def _demux_scalar_stores( self._demux_scalar_stores_future_map(result, launch_domain) def add_nccl_communicator(self) -> None: + """ + Adds a NCCL communicator to the task + """ comm = self._context.get_nccl_communicator() self._comm_args.append(comm) def add_cpu_communicator(self) -> None: + """ + Adds a CPU communicator to the task + """ comm = self._context.get_cpu_communicator() self._comm_args.append(comm) @@ -470,9 +620,42 @@ def get_requirement( tag = self.get_tag(strategy, part_symb) return req, tag, store_part + +class AutoTask(AutoOperation, Task): + """ + A type of tasks that are automatically parallelized + """ + + def __init__( + self, + context: Context, + task_id: int, + mapper_id: int, + op_id: int, + ) -> None: + super().__init__( + context=context, + task_id=task_id, + mapper_id=mapper_id, + op_id=op_id, + ) + self._reusable_stores: list[Tuple[Store, PartSym]] = [] + self._reuse_map: dict[int, Store] = {} + def add_input( self, store: Store, partition: Optional[PartSym] = None ) -> None: + """ + Adds a store as input to the task + + Parameters + ---------- + store : Store + Store to pass as input + partition : PartSym, optional + Partition to associate with the store. The default partition is + picked if none is given. + """ self._check_store(store) if partition is None: partition = self._get_unique_partition(store) @@ -482,6 +665,17 @@ def add_input( def add_output( self, store: Store, partition: Optional[PartSym] = None ) -> None: + """ + Adds a store as output to the task + + Parameters + ---------- + store : Store + Store to pass as output + partition : PartSym, optional + Partition to associate with the store. The default partition is + picked if none is given. + """ self._check_store(store, allow_unbound=True) if store.kind is Future: self._scalar_outputs.append(len(self._outputs)) @@ -495,6 +689,19 @@ def add_output( def add_reduction( self, store: Store, redop: int, partition: Optional[PartSym] = None ) -> None: + """ + Adds a store to the task for reduction + + Parameters + ---------- + store : Store + Store to pass for reduction + redop : int + Reduction operator ID + partition : PartSym, optional + Partition to associate with the store. The default partition is + picked if none is given. + """ self._check_store(store) if store.kind is Future: self._scalar_reductions.append(len(self._reductions)) @@ -503,24 +710,6 @@ def add_reduction( self._reductions.append((store, redop)) self._reduction_parts.append(partition) - -class AutoTask(AutoOperation, Task): - def __init__( - self, - context: Context, - task_id: int, - mapper_id: int, - op_id: int, - ) -> None: - super().__init__( - context=context, - task_id=task_id, - mapper_id=mapper_id, - op_id=op_id, - ) - self._reusable_stores: list[Tuple[Store, PartSym]] = [] - self._reuse_map: dict[int, Store] = {} - def record_reuse( self, strategy: Strategy, @@ -643,6 +832,10 @@ def launch(self, strategy: Strategy) -> None: class ManualTask(Operation, Task): + """ + A type of tasks that need explicit parallelization + """ + def __init__( self, context: Context, @@ -685,6 +878,16 @@ def add_input( arg: Union[Store, StorePartition], proj: Optional[ProjFn] = None, ) -> None: + """ + Adds a store as input to the task + + Parameters + ---------- + arg : Store or StorePartition + Store or store partition to pass as input + proj : ProjFn, optional + Projection function + """ self._check_arg(arg) if isinstance(arg, Store): self._input_parts.append(arg.partition(REPLICATE)) @@ -697,10 +900,25 @@ def add_output( arg: Union[Store, StorePartition], proj: Optional[ProjFn] = None, ) -> None: + """ + Adds a store as output to the task + + Parameters + ---------- + arg : Store or StorePartition + Store or store partition to pass as output + proj : ProjFn, optional + Projection function + + Raises + ------ + NotImplementedError + If the store is unbound + """ self._check_arg(arg) if isinstance(arg, Store): if arg.unbound: - raise ValueError( + raise NotImplementedError( "Unbound store cannot be used with " "manually parallelized task" ) @@ -718,6 +936,16 @@ def add_reduction( redop: int, proj: Optional[ProjFn] = None, ) -> None: + """ + Adds a store to the task for reduction + + Parameters + ---------- + arg : Store or StorePartition + Store or store partition to pass for reduction + proj : ProjFn, optional + Projection function + """ self._check_arg(arg) if isinstance(arg, Store): if arg.kind is Future: @@ -791,6 +1019,10 @@ def launch(self, strategy: Strategy) -> None: class Copy(AutoOperation): + """ + A special kind of operation for copying data from one store to another. + """ + def __init__( self, context: Context, @@ -813,49 +1045,141 @@ def get_name(self) -> str: def inputs(self) -> list[Store]: return super().inputs + self._source_indirects + self._target_indirects - def add_output( - self, store: Store, partition: Optional[PartSym] = None - ) -> None: + def add_input(self, store: Store) -> None: + """ + Adds a store as a source of the copy + + Parameters + ---------- + store : Store + Source store + + Raises + ------ + ValueError + If the store is scalar or unbound + """ + if store.kind is Future or store.unbound: + raise ValueError( + "Copy input must be a normal, region-backed store" + ) + self._check_store(store) + partition = self._get_unique_partition(store) + self._inputs.append(store) + self._input_parts.append(partition) + + def add_output(self, store: Store) -> None: + """ + Adds a store as a target of the copy. To avoid ambiguity in matching + sources and targets, one copy cannot have both normal targets and + reduction targets. + + Parameters + ---------- + store : Store + Target store + + Raises + ------ + RuntimeError + If the copy already has a reduction target + ValueError + If the store is scalar or unbound + """ if len(self._reductions) > 0: raise RuntimeError( "Copy targets must be either all normal outputs or reductions" ) - super().add_output(store, partition) + if store.kind is Future or store.unbound: + raise ValueError( + "Copy target must be a normal, region-backed store" + ) - def add_reduction( - self, store: Store, redop: int, partition: Optional[PartSym] = None - ) -> None: + self._check_store(store) + partition = self._get_unique_partition(store) + self._outputs.append(store) + self._output_parts.append(partition) + + def add_reduction(self, store: Store, redop: int) -> None: + """ + Adds a store as a reduction target of the copy. To avoid ambiguity in + matching sources and targets, one copy cannot have both normal targets + and reduction targets. + + Parameters + ---------- + store : Store + Reduction target store + redop : int + Reduction operator ID + + Raises + ------ + RuntimeError + If the copy already has a normal target + ValueError + If the store is scalar or unbound + """ if len(self._outputs) > 0: raise RuntimeError( "Copy targets must be either all normal outputs or reductions" ) - super().add_reduction(store, redop, partition) + if store.kind is Future or store.unbound: + raise ValueError( + "Copy target must be a normal, region-backed store" + ) + self._check_store(store) + partition = self._get_unique_partition(store) + self._reductions.append((store, redop)) + self._reduction_parts.append(partition) - def add_source_indirect( - self, store: Store, partition: Optional[PartSym] = None - ) -> None: + def add_source_indirect(self, store: Store) -> None: + """ + Adds an indirection for sources. A copy can have only up to one source + indirection. + + Parameters + ---------- + store : Store + Source indirection store + + Raises + ------ + RuntimeError + If the copy already has a source indirection + """ if len(self._source_indirects) != 0: raise RuntimeError( "There can be only up to one source indirection store for " "a Copy operation" ) self._check_store(store) - if partition is None: - partition = self._get_unique_partition(store) + partition = self._get_unique_partition(store) self._source_indirects.append(store) self._source_indirect_parts.append(partition) - def add_target_indirect( - self, store: Store, partition: Optional[PartSym] = None - ) -> None: + def add_target_indirect(self, store: Store) -> None: + """ + Adds an indirection for targets. A copy can have only up to one target + indirection. + + Parameters + ---------- + store : Store + Target indirection store + + Raises + ------ + RuntimeError + If the copy already has a target indirection + """ if len(self._target_indirects) != 0: raise RuntimeError( "There can be only up to one target indirection store for " "a Copy operation" ) self._check_store(store) - if partition is None: - partition = self._get_unique_partition(store) + partition = self._get_unique_partition(store) self._target_indirects.append(store) self._target_indirect_parts.append(partition) @@ -994,6 +1318,10 @@ def launch(self, strategy: Strategy) -> None: class Fill(AutoOperation): + """ + A special kind of operation for filling a store with constant values + """ + def __init__( self, context: Context, @@ -1009,8 +1337,18 @@ def __init__( raise ValueError("Fill lhs must be a bound Store") if lhs.kind is Future: raise ValueError("Fill lhs must be a RegionField-backed Store") - super().add_input(value) - super().add_output(lhs) + self._add_value(value) + self._add_lhs(lhs) + + def _add_value(self, value: Store) -> None: + partition = self._get_unique_partition(value) + self._inputs.append(value) + self._input_parts.append(partition) + + def _add_lhs(self, lhs: Store) -> None: + partition = self._get_unique_partition(lhs) + self._outputs.append(lhs) + self._output_parts.append(partition) def get_name(self) -> str: libname = self.context.library.get_name() @@ -1033,21 +1371,6 @@ def add_constraint(self, constraint: Constraint) -> None: "User partitioning constraints are not allowed for fills" ) - def add_input( - self, store: Store, partition: Optional[PartSym] = None - ) -> None: - raise TypeError("No further inputs can be added to fills") - - def add_output( - self, store: Store, partition: Optional[PartSym] = None - ) -> None: - raise TypeError("No further outputs can be added to fills") - - def add_reduction( - self, store: Store, redop: int, partition: Optional[PartSym] = None - ) -> None: - raise TypeError("No reductions can be added to fills") - def launch(self, strategy: Strategy) -> None: lhs = self._outputs[0] lhs_part_sym = self._output_parts[0] @@ -1096,6 +1419,19 @@ def __init__( self._radix = radix self._task_id = task_id + def add_input(self, store: Store) -> None: + self._check_store(store) + partition = self._get_unique_partition(store) + self._inputs.append(store) + self._input_parts.append(partition) + + def add_output(self, store: Store) -> None: + assert store.unbound + partition = self._get_unique_partition(store) + self._unbound_outputs.append(len(self._outputs)) + self._outputs.append(store) + self._output_parts.append(partition) + def launch(self, strategy: Strategy) -> None: assert len(self._inputs) == 1 and len(self._outputs) == 1 diff --git a/legate/core/resource.py b/legate/core/resource.py index 240c7b6b8..e3d85e43e 100644 --- a/legate/core/resource.py +++ b/legate/core/resource.py @@ -22,20 +22,11 @@ class ResourceConfig: - __slots__ = ( - "max_tasks", - "max_mappers", - "max_reduction_ops", - "max_projections", - "max_shardings", - ) - - def __init__(self) -> None: - self.max_tasks = 1_000_000 - self.max_mappers = 1 - self.max_reduction_ops = 0 - self.max_projections = 0 - self.max_shardings = 0 + max_tasks = 1_000_000 + max_reduction_ops = 0 + max_mappers = 1 + max_projections = 0 + max_shardings = 0 class ResourceScope: diff --git a/legate/core/runtime.py b/legate/core/runtime.py index 093464a63..00b48510f 100644 --- a/legate/core/runtime.py +++ b/legate/core/runtime.py @@ -1087,14 +1087,38 @@ def empty_argmap(self) -> ArgumentMap: @property def num_cpus(self) -> int: + """ + Returns the total number of CPUs in the system + + Returns + ------- + int + Number of CPUs + """ return self._num_cpus @property def num_omps(self) -> int: + """ + Returns the total number of OpenMP processors in the system + + Returns + ------- + int + Number of OpenMP processors + """ return self._num_omps @property def num_gpus(self) -> int: + """ + Returns the total number of GPUs in the system + + Returns + ------- + int + Number of GPUs + """ return self._num_gpus @property @@ -1119,6 +1143,19 @@ def field_match_manager(self) -> FieldMatchManager: return self._field_match_manager def register_library(self, library: Library) -> Context: + """ + Registers a library to the runtime. + + Parameters + ---------- + library : Library + Library object + + Returns + ------- + Context + A new context for the library + """ from .context import Context libname = library.get_name() @@ -1311,6 +1348,23 @@ def get_transform_code(self, name: str) -> int: ) def create_future(self, data: Any, size: int) -> Future: + """ + Creates a future from a buffer holding a scalar value. The value is + copied to the future. + + Parameters + ---------- + data : buffer + Buffer that holds a scalar value + + size : int + Size of the value + + Returns + ------- + Future + A new future + """ future = Future() future.set_value(self.legion_runtime, data, size) return future @@ -1696,4 +1750,11 @@ def legate_add_library(library: Library) -> None: def get_legate_runtime() -> Runtime: + """ + Returns the Legate runtime + + Returns + ------- + Legate runtime object + """ return runtime diff --git a/legate/core/shape.py b/legate/core/shape.py index cd6c44ee5..af84a6132 100644 --- a/legate/core/shape.py +++ b/legate/core/shape.py @@ -46,6 +46,19 @@ def __init__( extents: Optional[ExtentLike] = None, ispace: Optional[IndexSpace] = None, ) -> None: + """ + Constructs a new shape object + + Parameters + ---------- + extents: int, Iterable[int], or Shape + Extents to construct the shape object with. Must be passed unless an + ``ispace`` is given. + ispace : IndexSpace, optional + A Legion index space handle to construct the shape object with. + Must not be used by clients explicitly, as they don't have access + to index spaces. + """ if isinstance(extents, int): self._extents = (extents,) self._ispace = None @@ -59,6 +72,18 @@ def __init__( @property def extents(self) -> tuple[int, ...]: + """ + Returns the extents of the shape in a tuple + + Returns + ------- + tuple[int] + Extents of the shape + + Notes + ----- + Can block on the producer task + """ if self._extents is None: assert self._ispace is not None bounds = self._ispace.get_bounds() @@ -100,6 +125,14 @@ def __contains__(self, value: object) -> bool: @property def fixed(self) -> bool: + """ + Indicates whether the shape's extents are already computed + + Returns + ------ + bool + If ``True``, the shape has fixed extents + """ return self._extents is not None @property @@ -108,6 +141,15 @@ def ispace(self) -> Union[IndexSpace, None]: @property def ndim(self) -> int: + """ + Dimension of the shape. Unlike the ``extents`` property, this is + non-blocking. + + Returns + ------ + int + Dimension of the shape + """ if self._extents is None: assert self._ispace is not None return self._ispace.get_dim() @@ -127,9 +169,33 @@ def get_index_space(self, runtime: Runtime) -> IndexSpace: return self._ispace def volume(self) -> int: + """ + Returns the shape's volume + + Returns + ------ + int + Volume of the shape + + Notes + ----- + Can block on the producer task + """ return reduce(lambda x, y: x * y, self.extents, 1) def sum(self) -> int: + """ + Returns a sum of the extents + + Returns + ------ + int + Sum of the extents + + Notes + ----- + Can block on the producer task + """ return reduce(lambda x, y: x + y, self.extents, 0) def __hash__(self) -> int: @@ -139,6 +205,23 @@ def __hash__(self) -> int: return hash((self.__class__, True, self._extents)) def __eq__(self, other: object) -> bool: + """ + Checks whether the shape is identical to a given shape + + Parameters + ---------- + other : Shape or Iterable[int] + Shape to compare with + + Returns + ------ + bool + ``True`` if the shapes are identical + + Notes + ----- + Can block on the producer task + """ if isinstance(other, Shape): if ( self._ispace is not None @@ -160,6 +243,23 @@ def __eq__(self, other: object) -> bool: return False def __le__(self, other: ExtentLike) -> _ShapeComparisonResult: + """ + Returns the result of element-wise ``<=``. + + Parameters + ---------- + other : Shape or Iterable[int] + Shape to compare with + + Returns + ------ + tuple[bool] + Result of element-wise ``<=``. + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -170,6 +270,23 @@ def __le__(self, other: ExtentLike) -> _ShapeComparisonResult: return _ShapeComparisonResult(l <= r for (l, r) in zip(lh, rh)) def __lt__(self, other: ExtentLike) -> _ShapeComparisonResult: + """ + Returns the result of element-wise ``<``. + + Parameters + ---------- + other : Shape or Iterable[int] + Shape to compare with + + Returns + ------ + tuple[bool] + Result of element-wise ``<``. + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -180,6 +297,23 @@ def __lt__(self, other: ExtentLike) -> _ShapeComparisonResult: return _ShapeComparisonResult(l < r for (l, r) in zip(lh, rh)) def __ge__(self, other: ExtentLike) -> _ShapeComparisonResult: + """ + Returns the result of element-wise ``<=``. + + Parameters + ---------- + other : Shape or Iterable[int] + Shape to compare with + + Returns + ------ + tuple[bool] + Result of element-wise ``<=``. + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -190,6 +324,23 @@ def __ge__(self, other: ExtentLike) -> _ShapeComparisonResult: return _ShapeComparisonResult(l >= r for (l, r) in zip(lh, rh)) def __gt__(self, other: ExtentLike) -> _ShapeComparisonResult: + """ + Returns the result of element-wise ``<=``. + + Parameters + ---------- + other : Shape or Iterable[int] + Shape to compare with + + Returns + ------ + tuple[bool] + Result of element-wise ``<=``. + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -200,6 +351,23 @@ def __gt__(self, other: ExtentLike) -> _ShapeComparisonResult: return _ShapeComparisonResult(l > r for (l, r) in zip(lh, rh)) def __add__(self, other: ExtentLike) -> Shape: + """ + Returns an element-wise addition of the shapes + + Parameters + ---------- + other : Shape or Iterable[int] + A shape to add to this shape + + Returns + ------ + bool + Result of element-wise addition + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -209,6 +377,23 @@ def __add__(self, other: ExtentLike) -> Shape: return Shape(tuple(a + b for (a, b) in zip(lh, rh))) def __sub__(self, other: ExtentLike) -> Shape: + """ + Returns an element-wise subtraction between the shapes + + Parameters + ---------- + other : Shape or Iterable[int] + A shape to subtract from this shape + + Returns + ------ + bool + Result of element-wise subtraction + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -218,6 +403,23 @@ def __sub__(self, other: ExtentLike) -> Shape: return Shape(tuple(a - b for (a, b) in zip(lh, rh))) def __mul__(self, other: ExtentLike) -> Shape: + """ + Returns an element-wise multiplication of the shapes + + Parameters + ---------- + other : Shape or Iterable[int] + A shape to multiply with this shape + + Returns + ------ + bool + Result of element-wise multiplication + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -227,6 +429,23 @@ def __mul__(self, other: ExtentLike) -> Shape: return Shape(tuple(a * b for (a, b) in zip(lh, rh))) def __mod__(self, other: ExtentLike) -> Shape: + """ + Returns the result of element-wise modulo operation + + Parameters + ---------- + other : Shape or Iterable[int] + Shape to compare with + + Returns + ------ + bool + Result of element-wise modulo operation + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -236,6 +455,23 @@ def __mod__(self, other: ExtentLike) -> Shape: return Shape(tuple(a % b for (a, b) in zip(lh, rh))) def __floordiv__(self, other: ExtentLike) -> Shape: + """ + Returns the result of element-wise integer division + + Parameters + ---------- + other : Shape or Iterable[int] + A shape to divide this shape by + + Returns + ------ + bool + Result of element-wise integer division + + Notes + ----- + Can block on the producer task + """ lh = self.extents rh = ( other.extents @@ -245,26 +481,138 @@ def __floordiv__(self, other: ExtentLike) -> Shape: return Shape(tuple(a // b for (a, b) in zip(lh, rh))) def drop(self, dim: int) -> Shape: + """ + Removes a dimension from the shape + + Parameters + ---------- + dim : int + Dimension to remove + + Returns + ------ + Shape + Shape with one less dimension + + Notes + ----- + Can block on the producer task + """ extents = self.extents return Shape(extents[:dim] + extents[dim + 1 :]) def update(self, dim: int, new_value: int) -> Shape: + """ + Replaces the extent of a dimension with a new extent + + Parameters + ---------- + dim : int + Dimension to replace + + new_value : int + New extent + + Returns + ------ + Shape + Shape with the chosen dimension updated + + Notes + ----- + Can block on the producer task + """ return self.replace(dim, (new_value,)) def replace(self, dim: int, new_values: Iterable[int]) -> Shape: + """ + Replaces a dimension with multiple dimensions + + Parameters + ---------- + dim : int + Dimension to replace + + new_values : Iterable[int] + Extents of the new dimensions + + Returns + ------ + Shape + Shape with the chosen dimension replaced + + Notes + ----- + Can block on the producer task + """ if not isinstance(new_values, tuple): new_values = tuple(new_values) extents = self.extents return Shape(extents[:dim] + new_values + extents[dim + 1 :]) def insert(self, dim: int, new_value: int) -> Shape: + """ + Inserts a new dimension + + Parameters + ---------- + dim : int + Location to insert the new dimension + + new_value : int + Extent of the new dimension + + Returns + ------ + Shape + Shape with one more dimension + + Notes + ----- + Can block on the producer task + """ extents = self.extents return Shape(extents[:dim] + (new_value,) + extents[dim:]) def map(self, mapping: tuple[int, ...]) -> Shape: + """ + Applies a mapping to each extent in the shape + + Parameters + ---------- + maping : tuple[int] + New values for dimensions + + Returns + ------ + Shape + Shape with the extents replaced + + Notes + ----- + Can block on the producer task + """ return Shape(tuple(self[mapping[dim]] for dim in range(self.ndim))) def strides(self) -> Shape: + """ + Computes strides of the shape. The last dimension is considered the + most rapidly changing one. For example, if the shape is ``(3, 4, 5)``, + the strides are + + :: + + (20, 5, 1) + + Returns + ------ + Shape + Strides of the shape + + Notes + ----- + Can block on the producer task + """ strides: tuple[int, ...] = () stride = 1 for size in reversed(self.extents): diff --git a/legate/core/store.py b/legate/core/store.py index 107339ddc..309585999 100644 --- a/legate/core/store.py +++ b/legate/core/store.py @@ -783,10 +783,26 @@ def __init__( @property def store(self) -> Store: + """ + Returns the store of the store partition + + Returns + ------- + Store + A ``Store`` object wrapped in the store partition + """ return self._store @property def partition(self) -> PartitionBase: + """ + Returns the partition descriptor of the store partition + + Returns + ------- + PartitionBase + A ``PartitionBase`` object wrapped in the store partition + """ return self._partition @property @@ -794,6 +810,19 @@ def transform(self) -> TransformStackBase: return self._store.transform def get_child_store(self, *indices: int) -> Store: + """ + Returns the sub-store of a given color + + Parameters + ---------- + indices : tuple[int] + Color of the sub-store + + Returns + ------- + Store + The sub-store of the chosen color + """ color = self.transform.invert_color(Shape(indices)) child_storage = self._storage_partition.get_child(color) child_transform = self.transform @@ -892,6 +921,15 @@ def move_data(self, other: Store) -> None: @property def shape(self) -> Shape: + """ + Returns the shape of the store. Flushes the scheduling window if the + store is unbound and has no shape assigned. + + Returns + ------- + Shape + The store's shape + """ if self._shape is None: # If someone wants to access the shape of an unbound # store before it is set, that means the producer task is @@ -912,6 +950,14 @@ def shape(self) -> Shape: @property def ndim(self) -> int: + """ + Returns the number of dimensions of the store. + + Returns + ------- + int + The number of dimensions + """ if self._shape is None: assert self._ndim is not None return self._ndim @@ -920,12 +966,25 @@ def ndim(self) -> int: @property def size(self) -> int: + """ + Returns the number of elements in the store. + + Returns + ------- + int + The store's size + """ return prod(self.shape) if self.ndim > 0 else 1 @property def type(self) -> _Dtype: """ - Return the type of the data in this storage primitive + Returns the element type of the store. + + Returns + ------- + _Dtype + Type of elements in the store """ return self._dtype @@ -935,24 +994,42 @@ def get_dtype(self) -> _Dtype: @property def kind(self) -> Union[Type[RegionField], Type[Future]]: """ - Return the type of the Legion storage object backing the data in this - storage object: either Future, or RegionField. + Returns the kind of backing storage + + Returns + ------- + Type + `RegionField` or `Future` """ return self._storage.kind @property def unbound(self) -> bool: + """ + Indicates whether the store is unbound + + Returns + ------- + bool + ``True`` if the store is unbound + """ return self._shape is None @property def scalar(self) -> bool: + """ + Indicates whether the store is scalar (i.e., backed by a `Future` and + of size 1) + + Returns + ------- + bool + ``True`` if the store is scalar + """ return self.kind is Future and self.shape.volume() == 1 @property def storage(self) -> Union[RegionField, Future]: - """ - Return the Legion container backing this Store. - """ if self.unbound: raise RuntimeError( "Storage of a variable size store cannot be retrieved " @@ -973,10 +1050,26 @@ def extents(self) -> Shape: @property def transform(self) -> TransformStackBase: + """ + Returns a transformation attached to the store + + Returns + ------- + TransformStackBase + Transformation attached to the store + """ return self._transform @property def transformed(self) -> bool: + """ + Indicates whether the store is transformed + + Returns + ------- + bool + If ``True``, the store is transformed + """ return not self._transform.bottom def attach_external_allocation( @@ -1035,6 +1128,46 @@ def __repr__(self) -> str: # Convert a store in N-D space to that in (N+1)-D space. # The extra_dim specifies the added dimension def promote(self, extra_dim: int, dim_size: int = 1) -> Store: + """ + Adds an extra dimension to the store. Value of ``extra_dim`` decides + where a new dimension should be added, and each dimension `i`, where + `i` >= ``extra_dim``, is mapped to dimension `i+1` in a returned store. + A returned store provides a view to the input store where the values + are broadcasted along the new dimension. + + For example, for a 1D store ``A`` contains ``[1, 2, 3]``, + ``A.promote(0, 2)`` yields a store equivalent to: + + :: + + [[1, 2, 3], + [1, 2, 3]] + + whereas ``A.promote(1, 2)`` yields: + + :: + + [[1, 1], + [2, 2], + [3, 3]] + + Parameters + ---------- + extra_dim : int + Position for a new dimension + dim_size : int, optional + Extent of the new dimension + + Returns + ------- + Store + A new store with an extra dimension + + Raises + ------ + ValueError + If ``extra_dim`` is not a valid dimension name + """ extra_dim = extra_dim + self.ndim if extra_dim < 0 else extra_dim if extra_dim < 0 or extra_dim > self.ndim: raise ValueError( @@ -1057,6 +1190,34 @@ def promote(self, extra_dim: int, dim_size: int = 1) -> Store: # Take a hyperplane of an N-D store for a given index # to create an (N-1)-D store def project(self, dim: int, index: int) -> Store: + """ + Projects out a dimension of the store. Each dimension `i`, where + `i` > ``dim``, is mapped to dimension `i-1` in a returned store. + A returned store provides a view to the input store where the values + are on hyperplane :math:`x_\\mathtt{dim} = \\mathtt{index}`. + + For example, if a 2D store ``A`` contains ``[[1, 2], [3, 4]]``, + ``A.project(0, 1)`` yields a store equivalent to ``[3, 4]``, whereas + ``A.project(1, 0)`` yields ``[1, 3]``. + + Parameters + ---------- + dim : int + Dimension to project out + index : int + Index on the chosen dimension + + Returns + ------- + Store + A new store with one fewer dimension + + Raises + ------ + ValueError + If ``dim`` is not a valid dimension name or ``index`` is + out of bounds + """ dim = dim + self.ndim if dim < 0 else dim if dim < 0 or dim >= self.ndim: raise ValueError( @@ -1094,6 +1255,68 @@ def project(self, dim: int, index: int) -> Store: ) def slice(self, dim: int, sl: slice) -> Store: + """ + Slices a contiguous sub-section of the store. + + For example, consider a 2D store ``A`` + + :: + + [[1, 2, 3], + [4, 5, 6], + [7, 8, 9]] + + A slicing ``A.slice(0, slice(1, None))`` yields: + + :: + + [[4, 5, 6], + [7, 8, 9]] + + The result store will look like this on a different slicing call + ``A.slice(1, slice(None, 2))``: + + :: + + [[1, 2], + [4, 5], + [7, 8]] + + Finally, chained slicing calls + + :: + + A.slice(0, slice(1, None)).slice(1, slice(None, 2)) + + results in: + + :: + + [[4, 5], + [7, 8]] + + + Parameters + ---------- + dim : int + Dimension to slice + sl : slice + Slice that expresses a sub-section + + Returns + ------- + Store + A new store that correponds to the sliced section + + Notes + ----- + Slicing with a non-unit step is currently not supported. + + Raises + ------ + ValueError + If ``sl.step`` is not a unit or ``sl`` is out of bounds + """ dim = dim + self.ndim if dim < 0 else dim if dim < 0 or dim >= self.ndim: raise ValueError( @@ -1143,6 +1366,60 @@ def slice(self, dim: int, sl: slice) -> Store: ) def transpose(self, axes: tuple[int, ...]) -> Store: + """ + Reorders dimensions of the store. Dimension ``i`` of the resulting + store is mapped to dimension ``axes[i]`` of the input store. + + For example, for a 3D store ``A`` + + :: + + [[[1, 2], + [3, 4]], + + [[5, 6], + [7, 8]]] + + transpose calls ``A.transpose([1, 2, 0])`` and ``A.transpose([2, 1, + 0])`` yield the following stores, respectively: + + :: + + [[[1, 5], + [2, 6]], + + [[3, 7], + [4, 8]]] + + + :: + + [[[1, 5], + [3, 7]], + + [[2, 6], + [4, 8]]] + + + Parameters + ---------- + axes : tuple[int] + Mapping from dimensions of the resulting store to those of the + input + + Returns + ------- + Store + A new store with the dimensions transposed + + Raises + ------ + ValueError + If any of the following happens: 1) The length of ``axes`` doesn't + match the store's dimension; 2) ``axes`` has duplicates; 3) Any + value in ``axes`` is negative, or greater than or equal to the + store's dimension + """ if len(axes) != self.ndim: raise ValueError( f"dimension mismatch: expected {self.ndim} axes, " @@ -1170,6 +1447,54 @@ def transpose(self, axes: tuple[int, ...]) -> Store: ) def delinearize(self, dim: int, shape: tuple[int, ...]) -> Store: + """ + Delinearizes a dimension into multiple dimensions. Each dimension + `i` of the store, where `i` > ``dim``, will be mapped to dimension + `i+N` of the resulting store, where `N` is the length of ``shape``. + A delinearization that does not preserve the size of the store is + invalid. + + For example, consider a 2D store ``A`` + + :: + + [[1, 2, 3, 4], + [5, 6, 7, 8]] + + A delinearizing call `A.delinearize(1, [2, 2]))` yields: + + :: + + [[[1, 2], + [3, 4]], + + [[5, 6], + [7, 8]]] + + Parameters + ---------- + dim : int + Dimension to delinearize + shape : tuple[int] + New shape for the chosen dimension + + Returns + ------- + Store + A new store with the chosen dimension delinearized + + Notes + ----- + Unlike other transformations, delinearization is not an affine + transformation. Due to this nature, delinearized stores can raise + `NonInvertibleError` in places where they cannot be used. + + Raises + ------ + ValueError + If ``dim`` is invalid for the store or ``shape`` does not preserve + the size of the chosen dimenison + """ dim = dim + self.ndim if dim < 0 else dim if dim < 0 or dim >= self.ndim: raise ValueError( @@ -1198,6 +1523,24 @@ def delinearize(self, dim: int, shape: tuple[int, ...]) -> Store: def get_inline_allocation( self, context: Optional[Context] = None ) -> InlineMappedAllocation: + """ + Creates an inline allocation for the store. + + Parameters + ---------- + context : Context, optional + Library context within which the allocation is created + + Notes + ------- + This call blocks the client's control flow. And it fetches the data for + the whole store on a single node. + + Returns + ------- + InlineMappedAllocation + A helper object wrapping the allocation + """ assert self.kind is RegionField return self._storage.get_inline_allocation( self.shape, @@ -1216,6 +1559,14 @@ def serialize(self, buf: BufferBuilder) -> None: self._transform.serialize(buf) def get_key_partition(self) -> Optional[PartitionBase]: + """ + Returns the current key partition of the store + + Returns + ------- + PartitionBase + The store's key partition + """ # Flush outstanding operations to have the key partition of this store # registered correctly runtime.flush_scheduling_window() @@ -1235,6 +1586,14 @@ def has_key_partition(self, restrictions: tuple[Restriction, ...]) -> bool: return (part is not None) and (part.even or self._transform.bottom) def set_key_partition(self, partition: PartitionBase) -> None: + """ + Sets a new key partition for the store + + Parameters + ---------- + partition : PartitionBase + A new key partition + """ runtime.partition_manager.record_store_key_partition( self._unique_id, partition ) @@ -1245,6 +1604,9 @@ def set_key_partition(self, partition: PartitionBase) -> None: ) def reset_key_partition(self) -> None: + """ + Clears the store's key partition + """ runtime.partition_manager.reset_store_key_partition(self._unique_id) # Also reset the storage's key partition. self._storage.reset_key_partition() @@ -1343,6 +1705,19 @@ def partition(self, partition: PartitionBase) -> StorePartition: def partition_by_tiling( self, tile_shape: Union[Shape, Sequence[int]] ) -> StorePartition: + """ + Creates a tiled partition of the store + + Parameters + ---------- + tile_shape : Shape or Sequence[int] + Shape of tiles + + Returns + ------- + StorePartition + A ``StorePartition`` object + """ if self.unbound: raise TypeError("Unbound store cannot be manually partitioned") if not isinstance(tile_shape, Shape): diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index 5d6e80715..d18ebdb22 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -305,6 +305,58 @@ SECTIONS target_link_options(legate_core PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/fatbin.ld") endif() +############################################################################## +# - Doxygen target------------------------------------------------------------ + +if (legate_core_BUILD_DOCS) + find_package(Doxygen) + if(Doxygen_FOUND) + set(legate_core_DOC_SOURCES "") + list(APPEND legate_core_DOC_SOURCES + # task + src/core/task/task.h + src/core/task/registrar.h + src/core/task/variant.h + src/core/task/exception.h + src/core/cuda/stream_pool.h + # data + src/core/data/store.h + src/core/data/scalar.h + src/core/data/buffer.h + src/core/utilities/span.h + src/core/data/allocator.h + # runtime + src/core/runtime/runtime.h + src/core/runtime/context.h + # mapping + src/core/mapping/mapping.h + src/core/mapping/operation.h + # aliases + src/core/utilities/typedefs.h + # utilities + src/core/utilities/debug.h + src/core/utilities/dispatch.h + src/core/utilities/type_traits.h + # main page + src/legate.h + ) + set(DOXYGEN_PROJECT_NAME "Legate") + set(DOXYGEN_FULL_PATH_NAMES NO) + set(DOXYGEN_GENERATE_HTML YES) + set(DOXYGEN_GENERATE_LATEX NO) + set(DOXYGEN_EXTENSION_MAPPING cu=C++ cuh=C++) + set(DOXYGEN_HIDE_UNDOC_MEMBERS YES) + set(DOXYGEN_HIDE_UNDOC_CLASSES YES) + set(DOXYGEN_STRIP_FROM_INC_PATH ${CMAKE_SOURCE_DIR}/src) + doxygen_add_docs("doxygen_legate" ALL + ${legate_core_DOC_SOURCES} + COMMENT "Custom command for building Doxygen docs." + ) + else() + message(STATUS "cannot find Doxygen. not generating docs.") + endif() +endif() + ############################################################################## # - install targets----------------------------------------------------------- diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index a43a84aff..7743914f4 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -157,7 +157,7 @@ class DocsConfig(SectionConfig): @property def conda(self) -> Reqs: - return ("pandoc",) + return ("pandoc", "doxygen") @property def pip(self) -> Reqs: diff --git a/src/core/comm/communicator.h b/src/core/comm/communicator.h index ed75aeb66..4da3cf7b4 100644 --- a/src/core/comm/communicator.h +++ b/src/core/comm/communicator.h @@ -18,17 +18,25 @@ #include "legion.h" +/** + * @file + * @brief Class definition for legate::comm::Communicator + */ + namespace legate { namespace comm { -// This is a thin class wrapping a future that contains a communicator. -// This class only provides a template member function for retrieving the handle -// and the client is expected to use a correct type for the communicators that it uses. -// -// The following is the list of handle types for supported communicators: -// -// - NCCL: ncclComm_t* -// +/** + * @ingroup task + * @brief A thin wrapper class for communicators stored in futures. This class only provides + * a tempalte method to retrieve the communicator handle and the client is expected to pass + * the right handle type. + * + * The following is the list of handle types for communicators supported in Legate: + * + * - NCCL: ncclComm_t* + * - CPU communicator in Legate: legate::comm::coll::CollComm* + */ class Communicator { public: Communicator() {} @@ -39,6 +47,13 @@ class Communicator { Communicator& operator=(const Communicator&) = default; public: + /** + * @brief Returns the communicator stored in the wrapper + * + * @tparam T The type of communicator handle to get (see valid types above) + * + * @return A communicator + */ template T get() const { diff --git a/src/core/cuda/stream_pool.h b/src/core/cuda/stream_pool.h index 937556577..27c55fa90 100644 --- a/src/core/cuda/stream_pool.h +++ b/src/core/cuda/stream_pool.h @@ -21,11 +21,28 @@ #include #include "legion.h" +/** + * @file + * @brief Class definition for legate::cuda::StreamPool + */ + namespace legate { namespace cuda { +/** + * @ingroup task + * @brief A simple wrapper around CUDA streams to inject auxiliary features + * + * When `LEGATE_SYNC_STREAM_VIEW` is set to 1, every `StreamView` synchronizes the CUDA stream + * that it wraps when it is destroyed. + */ struct StreamView { public: + /** + * @brief Creates a `StreamView` with a raw CUDA stream + * + * @param stream Raw CUDA stream to wrap + */ StreamView(cudaStream_t stream) : valid_(true), stream_(stream) {} ~StreamView(); @@ -38,6 +55,11 @@ struct StreamView { StreamView& operator=(StreamView&&); public: + /** + * @brief Unwraps the raw CUDA stream + * + * @return Raw CUDA stream wrapped by the `StreamView` + */ operator cudaStream_t() const { return stream_; } private: @@ -45,15 +67,31 @@ struct StreamView { cudaStream_t stream_; }; +/** + * @brief A stream pool + */ struct StreamPool { public: StreamPool() {} ~StreamPool(); public: + /** + * @brief Returns a `StreamView` in the pool + * + * @return A `StreamView` object. Currently, all stream views returned from this pool are backed + * by the same CUDA stream. + */ StreamView get_stream(); public: + /** + * @brief Returns a singleton stream pool + * + * The stream pool is alive throughout the program execution. + * + * @return A `StreamPool` object + */ static StreamPool& get_stream_pool(); private: diff --git a/src/core/data/allocator.h b/src/core/data/allocator.h index f6f057f7d..f9c80a64f 100644 --- a/src/core/data/allocator.h +++ b/src/core/data/allocator.h @@ -20,8 +20,22 @@ #include +/** + * @file + * @brief Class definition for legate::ScopedAllocator + */ + namespace legate { +/** + * @ingroup data + * @brief A simple allocator backed by `Buffer` objects + * + * For each allocation request, this allocator creates a 1D `Buffer` of `int8_t` and returns + * the raw pointer to it. By default, all allocations are deallocated when the allocator is + * destroyed, and can optionally be made alive until the task finishes by making the allocator + * unscoped. + */ class ScopedAllocator { public: using ByteBuffer = Buffer; @@ -31,11 +45,36 @@ class ScopedAllocator { // Iff 'scoped', all allocations will be released upon destruction. // Otherwise this is up to the runtime after the task has finished. + /** + * @brief Create a `ScopedAllocator` for a specific memory kind + * + * @param kind Kind of the memory on which the `Buffer`s should be created + * @param scoped If true, the allocator is scoped; i.e., lifetimes of allocations are tied to + * the allocator's lifetime. Otherwise, the allocations are alive until the task finishes + * (and unless explicitly deallocated). + * @param alignment Alignment for the allocations + */ ScopedAllocator(Memory::Kind kind, bool scoped = true, size_t alignment = 16); ~ScopedAllocator(); public: + /** + * @brief Allocates a contiguous buffer of the given Memory::Kind + * + * When the allocator runs out of memory, the runtime will fail with an error message. + * Otherwise, the function returns a valid pointer. + * + * @param bytes Size of the allocation in bytes + * + * @return A raw pointer to the allocation + */ void* allocate(size_t bytes); + /** + * @brief Deallocates an allocation. The input pointer must be one that was previously + * returned by an `allocate` call, otherwise the code will fail with an error message. + * + * @param ptr Pointer to the allocation to deallocate + */ void deallocate(void* ptr); private: diff --git a/src/core/data/buffer.h b/src/core/data/buffer.h index 90ec8d5c9..f706c232c 100644 --- a/src/core/data/buffer.h +++ b/src/core/data/buffer.h @@ -21,28 +21,55 @@ #include "core/utilities/machine.h" #include "core/utilities/typedefs.h" +/** + * @file + * @brief Type alias definition for legate::Buffer and utility functions for it + */ + namespace legate { +/** + * @ingroup data + * @brief A typed buffer class for intra-task temporary allocations + * + * Values in a buffer can be accessed by index expressions with legate::Point objects, + * or via a raw pointer to the underlying allocation, which can be queried with the `ptr` method. + * + * `legate::Buffer` is an alias to + * [`Legion::DeferredBuffer`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion.h#L3509-L3609). + * + * Note on using temporary buffers in CUDA tasks: + * + * We use Legion `DeferredBuffer`, whose lifetime is not connected with the CUDA stream(s) used to + * launch kernels. The buffer is allocated immediately at the point when `create_buffer` is called, + * whereas the kernel that uses it is placed on a stream, and may run at a later point. Normally + * a `DeferredBuffer` is deallocated automatically by Legion once all the kernels launched in the + * task are complete. However, a `DeferredBuffer` can also be deallocated immediately using + * `destroy()`, which is useful for operations that want to deallocate intermediate memory as soon + * as possible. This deallocation is not synchronized with the task stream, i.e. it may happen + * before a kernel which uses the buffer has actually completed. This is safe as long as we use the + * same stream on all GPU tasks running on the same device (which is guaranteed by the current + * implementation of `get_cached_stream`), because then all the actual uses of the buffer are done + * in order on the one stream. It is important that all library CUDA code uses + * `get_cached_stream()`, and all CUDA operations (including library calls) are enqueued on that + * stream exclusively. This analysis additionally assumes that no code outside of Legate is + * concurrently allocating from the eager pool, and that it's OK for kernels to access a buffer even + * after it's technically been deallocated. + */ template using Buffer = Legion::DeferredBuffer; -// Note on using temporary buffers in CUDA tasks: -// We use Legion `DeferredBuffer`s, whose lifetime is not connected with the CUDA stream(s) used to -// launch kernels. The buffer is allocated immediately at the point when `create_buffer` called, -// whereas the kernel that uses it is placed on a stream, and may run at a later point. Normally -// `DeferredBuffer`s are deallocated automatically by Legion once all the kernels launched in the -// task are complete. However, `DeferredBuffer`s can also be deallocated immediately using -// `destroy()`, which is useful for operations that want to deallocate intermediate memory as soon -// as possible. This deallocation is not synchronized with the task stream, i.e. it may happen -// before a kernel which uses the buffer has actually completed. This is safe as long as we use the -// same stream on all GPU tasks running on the same device (which is guaranteed by the current -// implementation of `get_cached_stream()`), because then all the actual uses of the buffer are done -// in order on the one stream. It is important that all library CUDA code uses -// `get_cached_stream()`, and all CUDA operations (including library calls) are enqueued on that -// stream exclusively. This analysis additionally assumes that no code outside of Legate is -// concurrently allocating from the eager pool, and that it's OK for kernels to access a buffer even -// after it's technically been deallocated. - +/** + * @ingroup data + * @brief Creates a `Buffer` of specific extents + * + * @param extents Extents of the buffer + * @param kind Kind of the target memory (optional). If not given, the runtime will pick + * automatically based on the executing processor + * @param alignment Alignment for the memory allocation (optional) + * + * @return A `Buffer` object + */ template Buffer create_buffer(const Point& extents, Memory::Kind kind = Memory::Kind::NO_MEMKIND, @@ -56,6 +83,17 @@ Buffer create_buffer(const Point& extents, return Buffer(bounds, kind, nullptr, alignment); } +/** + * @ingroup data + * @brief Creates a `Buffer` of a specific size. Always returns a 1D buffer. + * + * @param size Size of the buffdr + * @param kind Kind of the target memory (optional). If not given, the runtime will pick + * automatically based on the executing processor + * @param alignment Alignment for the memory allocation (optional) + * + * @return A 1D `Buffer` object + */ template Buffer create_buffer(size_t size, Memory::Kind kind = Memory::Kind::NO_MEMKIND, diff --git a/src/core/data/scalar.cc b/src/core/data/scalar.cc index 2282c2f8a..13300e60e 100644 --- a/src/core/data/scalar.cc +++ b/src/core/data/scalar.cc @@ -71,7 +71,7 @@ size_t Scalar::size() const auto elem_size = type_dispatch(code_, elem_size_fn{}); if (tuple_) { auto num_elements = *static_cast(data_); - return sizeof(int32_t) + num_elements * elem_size; + return sizeof(uint32_t) + num_elements * elem_size; } else return elem_size; } diff --git a/src/core/data/scalar.h b/src/core/data/scalar.h index 5fc782271..63db09fbd 100644 --- a/src/core/data/scalar.h +++ b/src/core/data/scalar.h @@ -20,18 +20,58 @@ #include "core/utilities/type_traits.h" #include "core/utilities/typedefs.h" +/** + * @file + * @brief Class definition for legate::Scalar + */ + namespace legate { +/** + * @ingroup data + * @brief A type-erased container for scalars and tuples of scalars. + * + * A Scalar can be owned or shared, depending on whether it owns the backing allocation: + * If a `Scalar` is shared, it does not own the allocation and any of its copies are also + * shared. If a `Scalar` is owned, it owns the backing allocation and releases it upon + * destruction. Any copy of an owned `Scalar` is owned as well. + * + * A `Scalar` that stores a tuple of scalars has an allocation big enough to contain both + * the number of elements and the elements themselves. The number of elements should be + * stored in the first four bytes of the allocation. + * + */ class Scalar { public: Scalar() = default; Scalar(const Scalar& other); + /** + * @brief Creates a shared `Scalar` with an existing allocation. The caller is responsible + * for passing in a sufficiently big allocation. + * + * @param tuple If true, the allocation contains a tuple of scalars. + * @param code Type code of the scalar(s) + * @param data Allocation containing the data. + */ Scalar(bool tuple, LegateTypeCode code, const void* data); ~Scalar(); public: + /** + * @brief Creates an owned scalar from a scalar value + * + * @tparam T The scalar type to wrap + * + * @param value A scalar value to create a `Scalar` with + */ template Scalar(T value); + /** + * @brief Creates an owned scalar from a tuple of scalars. The values in the input vector + * will be copied. + * + * @param values A vector that contains elements of a tuple + */ template Scalar(const std::vector& values); @@ -42,14 +82,44 @@ class Scalar { void copy(const Scalar& other); public: + /** + * @brief Indicates if the `Scalar` object represents a tuple + * + * @return true The `Scalar` is a tuple + * @return false The `Scalar` is a scalar + */ bool is_tuple() const { return tuple_; } + /** + * @brief Returns the size of allocation for the `Scalar`. + * + * @return The size of allocation + */ size_t size() const; public: + /** + * @brief Returns the value stored in the `Scalar`. The call does no type checking; + * i.e., passing a wrong type parameter will not be caught by the call. + * + * @tparam VAL Type of the value to unwrap + * + * @return The value stored in the `Scalar` + */ template VAL value() const; + /** + * @brief Returns values stored in the `Scalar`. If the `Scalar` contains a scalar, + * a unit span will be returned. + * + * @return Values stored in the `Scalar` + */ template Span values() const; + /** + * @brief Returns a raw pointer to the backing allocation + * + * @return A raw pointer to the `Scalar`'s data + */ const void* ptr() const { return data_; } private: diff --git a/src/core/data/store.h b/src/core/data/store.h index 0ae7231bc..a66617b71 100644 --- a/src/core/data/store.h +++ b/src/core/data/store.h @@ -24,6 +24,14 @@ #include "legate_defines.h" #include "legion.h" +/** @defgroup data Data abstractions and allocators + */ + +/** + * @file + * @brief Class definition for legate::Store + */ + namespace legate { class RegionField { @@ -255,6 +263,10 @@ class FutureWrapper { Legion::UntypedDeferredValue buffer_{}; }; +/** + * @ingroup data + * @brief A multi-dimensional data container storing task data + */ class Store { public: Store() {} @@ -282,11 +294,34 @@ class Store { Store& operator=(const Store& other) = delete; public: + /** + * @brief Indicates whether the store is valid. A store passed to a task can be invalid + * only for reducer tasks for tree reduction. + * + * @return true The store is valid + * @return false The store is invalid and cannot be used in any data access + */ bool valid() const; + /** + * @brief Indicates whether the store is transformed in any way. + * + * @return true The store is transformed + * @return false The store is not transformed + */ bool transformed() const { return !transform_->identity(); } public: + /** + * @brief Returns the dimension of the store + * + * @return The store's dimension + */ int32_t dim() const { return dim_; } + /** + * @brief Returns the type code of the store + * + * @return The store's type code + */ template TYPE_CODE code() const { @@ -294,50 +329,200 @@ class Store { } public: + /** + * @brief Returns a read-only accessor to the store for the entire domain + * + * @return A read-only accessor to the store + */ template AccessorRO read_accessor() const; + /** + * @brief Returns a write-only accessor to the store for the entire domain + * + * @return A write-only accessor to the store + */ template AccessorWO write_accessor() const; + /** + * @brief Returns a read-write accessor to the store for the entire domain + * + * @return A read-write accessor to the store + */ template AccessorRW read_write_accessor() const; + /** + * @brief Returns a reduction accessor to the store for the entire domain + * + * @tparam OP Reduction operator class. For details about reduction operators, See + * LibraryContext::register_reduction_operator. + * + * @tparam EXCLUSIVE Indicates whether reductions can be performed in exclusive mode. If + * `EXCLUSIVE` is `false`, every reduction via the acecssor is performed atomically. + * + * @return A reduction accessor to the store + */ template AccessorRD reduce_accessor() const; public: + /** + * @brief Returns a read-only accessor to the store for specific bounds. + * + * @param bounds Domain within which accesses should be allowed. + * The actual bounds for valid access are determined by an intersection between + * the store's domain and the bounds. + * + * @return A read-only accessor to the store + */ template AccessorRO read_accessor(const Rect& bounds) const; + /** + * @brief Returns a write-only accessor to the store for the entire domain + * + * @param bounds Domain within which accesses should be allowed. + * The actual bounds for valid access are determined by an intersection between + * the store's domain and the bounds. + * + * @return A write-only accessor to the store + */ template AccessorWO write_accessor(const Rect& bounds) const; + /** + * @brief Returns a read-write accessor to the store for the entire domain + * + * @param bounds Domain within which accesses should be allowed. + * The actual bounds for valid access are determined by an intersection between + * the store's domain and the bounds. + * + * @return A read-write accessor to the store + */ template AccessorRW read_write_accessor(const Rect& bounds) const; + /** + * @brief Returns a reduction accessor to the store for the entire domain + * + * @param bounds Domain within which accesses should be allowed. + * The actual bounds for valid access are determined by an intersection between + * the store's domain and the bounds. + * + * @tparam OP Reduction operator class. For details about reduction operators, See + * LibraryContext::register_reduction_operator. + * + * @tparam EXCLUSIVE Indicates whether reductions can be performed in exclusive mode. If + * `EXCLUSIVE` is `false`, every reduction via the acecssor is performed atomically. + * + * @return A reduction accessor to the store + */ template AccessorRD reduce_accessor(const Rect& bounds) const; public: + /** + * @brief Creates a buffer of specified extents for the unbound store. The returned + * buffer is always consistent with the mapping policy for the store. Can be invoked + * multiple times unless `return_buffer` is true. + * + * @param extents Extents of the buffer + * + * @param return_buffer If the value is true, the created buffer will be bound + * to the store upon return + * + * @return A reduction accessor to the store + */ template Buffer create_output_buffer(const Point& extents, bool return_buffer = false); public: + /** + * @brief Returns the store's domain + * + * @return Store's domain + */ template Rect shape() const; + /** + * @brief Returns the store's domain in a dimension-erased domain type + * + * @return Store's domain in a dimension-erased domain type + */ Domain domain() const; public: + /** + * @brief Indicates whether the store can have a read accessor + * + * @return true The store can have a read accessor + * @return false The store cannot have a read accesor + */ bool is_readable() const { return readable_; } + /** + * @brief Indicates whether the store can have a write accessor + * + * @return true The store can have a write accessor + * @return false The store cannot have a write accesor + */ bool is_writable() const { return writable_; } + /** + * @brief Indicates whether the store can have a reduction accessor + * + * @return true The store can have a reduction accessor + * @return false The store cannot have a reduction accesor + */ bool is_reducible() const { return reducible_; } public: + /** + * @brief Returns the scalar value stored in the store. + * + * The requested type must match with the store's data type. If the store is not + * backed by the future, the runtime will fail with an error message. + * + * @tparam VAL Type of the scalar value + * + * @return The scalar value stored in the store + */ template VAL scalar() const; public: + /** + * @brief Binds a buffer to the store. Valid only when the store is unbound and + * has not yet been bound to another buffer. The buffer must be consistent with + * the mapping policy for the store. Recommend that the buffer be created by + * a `create_output_buffer` call. + * + * @param buffer Buffer to bind to the store + * + * @param extents Extents of the buffer. Passing extents smaller than the actual + * extents of the buffer is legal; the runtime uses the passed extents as the + * extents of this store. + * + */ template void return_data(Buffer& buffer, const Point& extents); + /** + * @brief Makes the unbound store empty. Valid only when the store is unbound and + * has not yet been bound to another buffer. + */ void make_empty(); public: + /** + * @brief Indicates whether the store is backed by a future + * (i.e., a container for scalar value) + * + * @return true The store is backed by a future + * @return false The store is backed by a region field + */ bool is_future() const { return is_future_; } + /** + * @brief Indicates whether the store is an unbound store. The value DOES NOT indicate + * that the store has already assigned to a buffer; i.e., the store may have been assigned + * to a buffer even when this function returns `true`. + * + * @return true The store is an unbound store + * @return false The store is a normal store + */ bool is_output_store() const { return is_output_store_; } ReturnValue pack() const { return future_.pack(); } ReturnValue pack_weight() const { return output_field_.pack_weight(); } diff --git a/src/core/mapping/mapping.cc b/src/core/mapping/mapping.cc index 3e092708d..960cbfbc0 100644 --- a/src/core/mapping/mapping.cc +++ b/src/core/mapping/mapping.cc @@ -145,6 +145,8 @@ uint32_t StoreMapping::requirement_index() const } return result; #else + static constexpr uint32_t invalid = -1U; + if (stores.empty()) return invalid; return stores.front().requirement_index(); #endif } diff --git a/src/core/mapping/mapping.h b/src/core/mapping/mapping.h index 247b283be..bed1247ee 100644 --- a/src/core/mapping/mapping.h +++ b/src/core/mapping/mapping.h @@ -19,38 +19,114 @@ #include "core/mapping/operation.h" #include "core/utilities/typedefs.h" +/** @defgroup mapping Mapping API + */ + +/** + * @file + * @brief Legate Mapping API + */ + namespace legate { namespace mapping { +/** + * @ingroup mapping + * @brief An enum class for task targets + */ enum class TaskTarget : int32_t { + /** + * @brief Indicates the task be mapped to a CPU + */ CPU = 1, + /** + * @brief Indicates the task be mapped to a GPU + */ GPU = 2, + /** + * @brief Indicates the task be mapped to an OpenMP processor + */ OMP = 3, }; +/** + * @ingroup mapping + * @brief An enum class for store targets + */ enum class StoreTarget : int32_t { - SYSMEM = 1, - FBMEM = 2, - ZCMEM = 3, + /** + * @brief Indicates the store be mapped to the system memory (host memory) + */ + SYSMEM = 1, + /** + * @brief Indicates the store be mapped to the GPU framebuffer + */ + FBMEM = 2, + /** + * @brief Indicates the store be mapped to the pinned memory for zero-copy GPU accesses + */ + ZCMEM = 3, + /** + * @brief Indicates the store be mapped to the host memory closest to the target CPU + */ SOCKETMEM = 4, }; +/** + * @ingroup mapping + * @brief An enum class for instance allocation policies + */ enum class AllocPolicy : int32_t { - MAY_ALLOC = 1, + /** + * @brief Indicates the store can reuse an existing instance + */ + MAY_ALLOC = 1, + /** + * @brief Indicates the store must be mapped to a fresh instance + */ MUST_ALLOC = 2, }; +/** + * @ingroup mapping + * @brief An enum class for instant layouts + */ enum class InstLayout : int32_t { + /** + * @brief Indicates the store must be mapped to an SOA instance + */ SOA = 1, + /** + * @brief Indicates the store must be mapped to an AOS instance. No different than `SOA` in a + * store mapping for a single store + */ AOS = 2, }; +/** + * @ingroup mapping + * @brief A descriptor for dimension ordering + */ struct DimOrdering { public: + /** + * @brief An enum class for kinds of dimension ordering + */ enum class Kind : int32_t { - C = 1, + /** + * @brief Indicates the instance have C layout (i.e., the last dimension is the leading + * dimension in the instance) + */ + C = 1, + /** + * @brief Indicates the instance have Fortran layout (i.e., the first dimension is the leading + * dimension instance) + */ FORTRAN = 2, - CUSTOM = 3, + /** + * @brief Indicates the order of dimensions of the instance is manually specified + */ + CUSTOM = 3, }; public: @@ -72,26 +148,67 @@ struct DimOrdering { std::vector& ordering) const; public: + /** + * @brief Sets the dimension ordering to C + */ void c_order(); + /** + * @brief Sets the dimension ordering to Fortran + */ void fortran_order(); + /** + * @brief Sets a custom dimension ordering + * + * @param dims A vector that stores the order of dimensions. + */ void custom_order(std::vector&& dims); public: + /** + * @brief Dimension ordering type + */ Kind kind{Kind::C}; // When relative is true, 'dims' specifies the order of dimensions // for the store's local coordinate space, which will be mapped // back to the root store's original coordinate space. + /** + * @brief If true, the dimension ordering specifies the order of dimensions + * for the store's current domain, which will be transformed back to the root + * store's domain. + */ bool relative{false}; - // Used only when the kind is CUSTOM + /** + * @brief Dimension list. Used only when the `kind` is `CUSTOM`. + */ std::vector dims{}; }; +/** + * @ingroup mapping + * @brief A descriptor for instance mapping policy + */ struct InstanceMappingPolicy { public: + /** + * @brief Target memory type for the instance + */ StoreTarget target{StoreTarget::SYSMEM}; + /** + * @brief Allocation policy + */ AllocPolicy allocation{AllocPolicy::MAY_ALLOC}; + /** + * @brief Instance layout for the instance + */ InstLayout layout{InstLayout::SOA}; + /** + * @brief Dimension ordering for the instance + */ DimOrdering ordering{}; + /** + * @brief If true, the instance must be tight to the store(s); i.e., the instance + * must not have any extra elements not included in the store(s). + */ bool exact{false}; public: @@ -118,9 +235,19 @@ struct InstanceMappingPolicy { static InstanceMappingPolicy default_policy(StoreTarget target, bool exact = false); }; +/** + * @ingroup mapping + * @brief A mapping policy for stores + */ struct StoreMapping { public: + /** + * @brief Stores to which the `policy` should be applied + */ std::vector stores{}; + /** + * @brief Instance mapping policy + */ InstanceMappingPolicy policy; public: @@ -140,8 +267,26 @@ struct StoreMapping { const Store& store() const; public: + /** + * @brief Returns a region requirement index for the stores. + * + * Returns an undefined value if the store mapping has more than one store and the stores are + * mapped to different region requirements. + * + * @return Region requirement index + */ uint32_t requirement_index() const; + /** + * @brief Returns a set of region requirement indices for the stores. + * + * @return A set of region requirement indices + */ std::set requirement_indices() const; + /** + * @brief Returns the stores' region requirements + * + * @return A set of region requirements + */ std::set requirements() const; private: @@ -149,26 +294,97 @@ struct StoreMapping { void populate_layout_constraints(Legion::LayoutConstraintSet& layout_constraints) const; public: + /** + * @brief Creates a `StoreMapping` object following the default mapping poicy + * + * @param store Target store for the mapping policy + * @param target Target memory type for the store + * @param exact Indicates whether the policy should request an exact instance + * + * @return A `StoreMapping` object + */ static StoreMapping default_mapping(const Store& store, StoreTarget target, bool exact = false); }; +/** + * @ingroup mapping + * @brief An abstract class that defines machine query APIs + */ class MachineQueryInterface { public: virtual ~MachineQueryInterface() {} + /** + * @brief Returns local CPUs + * + * @return A vector of processors + */ virtual const std::vector& cpus() const = 0; + /** + * @brief Returns local GPUs + * + * @return A vector of processors + */ virtual const std::vector& gpus() const = 0; + /** + * @brief Returns local OpenMP processors + * + * @return A vector of processors + */ virtual const std::vector& omps() const = 0; - virtual uint32_t total_nodes() const = 0; + /** + * @brief Returns the total number of nodes + * + * @return Total number of nodes + */ + virtual uint32_t total_nodes() const = 0; }; +/** + * @ingroup mapping + * @brief An abstract class that defines Legate mapping APIs + * + * The APIs give Legate libraries high-level control on task and store mappings + */ class LegateMapper { public: virtual ~LegateMapper() {} - virtual void set_machine(const MachineQueryInterface* machine) = 0; - virtual TaskTarget task_target(const Task& task, const std::vector& options) = 0; + /** + * @brief Sets a machine query interface. This call gives the mapper a chance + * to cache the machine query interface. + * + * @param machine Machine query interface + */ + virtual void set_machine(const MachineQueryInterface* machine) = 0; + /** + * @brief Picks the target processor type for the task + * + * @param task Task to map + * @param options Processor types for which the task has variants + * + * @return A target processor type + */ + virtual TaskTarget task_target(const Task& task, const std::vector& options) = 0; + /** + * @brief Chooses mapping policies for the task's stores. + * + * Store mappings can be underspecified; any store of the task that doesn't have a mapping policy + * will fall back to the default one. + * + * @param task Task to map + * @param options Types of memories to which the stores can be mapped + * + * @return A vector of store mappings + */ virtual std::vector store_mappings(const Task& task, const std::vector& options) = 0; - virtual Scalar tunable_value(TunableID tunable_id) = 0; + /** + * @brief Returns a tunable value + * + * @param tunable_id a tunable value id + * + * @return A tunable value in a `Scalar` object + */ + virtual Scalar tunable_value(TunableID tunable_id) = 0; }; } // namespace mapping diff --git a/src/core/mapping/operation.h b/src/core/mapping/operation.h index fb84fe27c..47ef686e3 100644 --- a/src/core/mapping/operation.h +++ b/src/core/mapping/operation.h @@ -23,6 +23,11 @@ #include "core/data/transform.h" #include "core/runtime/context.h" +/** + * @file + * @brief Class definitions for operations and stores used in mapping + */ + namespace legate { namespace mapping { @@ -96,6 +101,11 @@ class FutureWrapper { Domain domain_{}; }; +/** + * @ingroup mapping + * @brief A metadata class that mirrors the structure of legate::Store but contains + * only the data relevant to mapping + */ class Store { public: Store() {} @@ -125,15 +135,51 @@ class Store { Store& operator=(Store&& other) = default; public: + /** + * @brief Indicates whether the store is backed by a future + * + * @return true The store is backed by a future + * @return false The store is backed by a region field + */ bool is_future() const { return is_future_; } + /** + * @brief Indicates whether the store is unbound + * + * @return true The store is unbound + * @return false The store is a normal store + */ bool unbound() const { return is_output_store_; } + /** + * @brief Returns the store's dimension + * + * @return Store's dimension + */ int32_t dim() const { return dim_; } public: + /** + * @brief Indicates whether the store is a reduction store + * + * @return true The store is a reduction store + * @return false The store is either an input or output store + */ bool is_reduction() const { return redop_id_ > 0; } + /** + * @brief Returns the reduction operator id for the store + * + * @return Reduction oeprator id + */ int32_t redop() const { return redop_id_; } public: + /** + * @brief Indicates whether the store can colocate in an instance with a given store + * + * @param other Store against which the colocation is checked + * + * @return true The store can colocate with the input + * @return false The store cannot colocate with the input + */ bool can_colocate_with(const Store& other) const; const RegionField& region_field() const; const FutureWrapper& future() const; @@ -144,10 +190,18 @@ class Store { uint32_t future_index() const; public: + /** + * @brief Returns the store's domain + * + * @return Store's domain + */ template Rect shape() const; - - public: + /** + * @brief Returns the store's domain in a dimension-erased domain type + * + * @return Store's domain in a dimension-erased domain type + */ Domain domain() const; private: @@ -169,6 +223,10 @@ class Store { Legion::Mapping::MapperContext context_{nullptr}; }; +/** + * @ingroup mapping + * @brief A metadata class for tasks + */ class Task { public: Task(const Legion::Task* task, @@ -177,15 +235,47 @@ class Task { const Legion::Mapping::MapperContext context); public: + /** + * @brief Returns the task id + * + * @return Task id + */ int64_t task_id() const; public: + /** + * @brief Returns metadata for the task's input stores + * + * @return Vector of store metadata objects + */ const std::vector& inputs() const { return inputs_; } + /** + * @brief Returns metadata for the task's output stores + * + * @return Vector of store metadata objects + */ const std::vector& outputs() const { return outputs_; } + /** + * @brief Returns metadata for the task's reduction stores + * + * @return Vector of store metadata objects + */ const std::vector& reductions() const { return reductions_; } + /** + * @brief Returns the vector of the task's by-value arguments. Unlike `mapping::Store` + * objects that have no access to data in the stores, the returned `Scalar` objects + * contain valid arguments to the task + * + * @return Vector of `Scalar` objects + */ const std::vector& scalars() const { return scalars_; } public: + /** + * @brief Returns the point of the task + * + * @return The point of the task + */ DomainPoint point() const { return task_->index_point; } private: diff --git a/src/core/runtime/context.h b/src/core/runtime/context.h index 2a0c7624a..dac640a3f 100644 --- a/src/core/runtime/context.h +++ b/src/core/runtime/context.h @@ -26,6 +26,11 @@ #include "core/task/return.h" #include "core/utilities/typedefs.h" +/** + * @file + * @brief Class definitions for legate::LibraryContext and legate::TaskContext + */ + namespace legate { namespace mapping { @@ -37,9 +42,22 @@ class LegateMapper; class Store; class Scalar; +/** + * @ingroup runtime + * @brief POD for library configuration. + */ struct ResourceConfig { + /** + * @brief Maximum number of tasks that the library can register + */ int64_t max_tasks{1000000}; + /** + * @brief Maximum number of mappers that the library can register + */ int64_t max_mappers{1}; + /** + * @brief Maximum number of custom reduction operators that the library can register + */ int64_t max_reduction_ops{0}; int64_t max_projections{0}; int64_t max_shardings{0}; @@ -73,14 +91,35 @@ class ResourceScope { int64_t max_{-1}; }; +/** + * @ingroup runtime + * @brief A library context that provides APIs for registering components + */ class LibraryContext { public: + /** + * @brief Creates a library context from a library name and a configuration. + * + * A library is registered to the runtime only upon the first construction + * and the `config` object is referred to only when the registration happens. + * All the following constructions of `LibraryContext` only retrieve the + * metadata from the runtime without registration and ignore the `config`. + * + * @param library_name Library name + * @param config Resource configuration for the library. If the library is already + * registered, the value will be ignored. + */ LibraryContext(const std::string& library_name, const ResourceConfig& config); public: LibraryContext(const LibraryContext&) = default; public: + /** + * @brief Returns the name of the library + * + * @return Library name + */ const std::string& get_library_name() const; public: @@ -105,8 +144,66 @@ class LibraryContext { bool valid_sharding_id(Legion::ShardingID shard_id) const; public: + /** + * @brief Registers a library specific reduction operator. + * + * The type parameter `REDOP` points to a class that implements a reduction operator. + * Each reduction operator class has the following structure: + * + * @code{.cpp} + * struct RedOp { + * using LHS = ...; // Type of the LHS values + * using RHS = ...; // Type of the RHS values + * + * static const RHS identity = ...; // Identity of the reduction operator + * static const int32_t REDOP_ID = ... // Reduction operator id + * + * template + * __CUDA_HD__ inline static void apply(LHS& lhs, RHS rhs) + * { + * ... + * } + * template + * __CUDA_HD__ inline static void fold(RHS& rhs1, RHS rhs2) + * { + * ... + * } + * }; + * @endcode + * + * Semantically, Legate performs reductions of values `V0`, ..., `Vn` to element `E` in the + * following way: + * + * @code{.cpp} + * RHS T = RedOp::identity; + * RedOp::fold(T, V0) + * ... + * RedOp::fold(T, Vn) + * RedOp::apply(E, T) + * @endcode + * I.e., Legate gathers all reduction contributions using `fold` and applies the accumulator + * to the element using `apply`. + * + * Oftentimes, the LHS and RHS of a reduction operator are the same type and `fold` and `apply` + * perform the same computation, but that's not mandatory. For example, one may implement + * a reduction operator for subtraction, where the `fold` would sum up all RHS values whereas + * the `apply` would subtract the aggregate value from the LHS. + * + * The reduction operator id (`REDOP_ID`) can be local to the library but should be unique + * for each opeartor within the library. + * + * Finally, the contract for `apply` and `fold` is that they must update the + * reference atomically when the `EXCLUSIVE` is `false`. + */ template void register_reduction_operator(); + /** + * @brief Registers a library specific mapper. Transfers the ownership of the mapper to + * the runtime. + * + * @param mapper Mapper object + * @param local_mapper_id Id for the mapper. Used only when there is more than one mapper. + */ void register_mapper(std::unique_ptr mapper, int64_t local_mapper_id = 0) const; @@ -120,8 +217,10 @@ class LibraryContext { ResourceScope shard_scope_; }; -// A thin context layer on top of the Legion runtime, primarily designed to hide verbosity -// of the Legion API. +/** + * @ingroup task + * @brief A task context that contains task arguments and communicators + */ class TaskContext { public: TaskContext(const Legion::Task* task, @@ -130,19 +229,69 @@ class TaskContext { Legion::Runtime* runtime); public: + /** + * @brief Returns input stores of the task + * + * @return Vector of input stores + */ std::vector& inputs() { return inputs_; } + /** + * @brief Returns output stores of the task + * + * @return Vector of output stores + */ std::vector& outputs() { return outputs_; } + /** + * @brief Returns reduction stores of the task + * + * @return Vector of reduction stores + */ std::vector& reductions() { return reductions_; } + /** + * @brief Returns by-value arguments of the task + * + * @return Vector of scalar objects + */ std::vector& scalars() { return scalars_; } + /** + * @brief Returns communicators of the task + * + * @return Vector of communicator objects + */ std::vector& communicators() { return comms_; } public: + /** + * @brief Indicates whether the task is parallelized + * + * @return true The task is a single task + * @return false The task is one in a set of multiple parallel tasks + */ bool is_single_task() const; + /** + * @brief Indicates whether the task is allowed to raise an exception + * + * @return true The task can raise an exception + * @return false The task must not raise an exception + */ bool can_raise_exception() const { return can_raise_exception_; } + /** + * @brief Returns the point of the task. A 0D point will be returned for a single task. + * + * @return The point of the task + */ DomainPoint get_task_index() const; + /** + * @brief Returns the task group's launch domain. A single task returns an empty domain + * + * @return The task group's launch domain + */ Domain get_launch_domain() const; public: + /** + * @brief Makes all of unbound output stores of this task empty + */ void make_all_unbound_stores_empty(); ReturnValues pack_return_values() const; ReturnValues pack_return_values_with_exception(int32_t index, diff --git a/src/core/runtime/runtime.h b/src/core/runtime/runtime.h index 723582cc6..ccd1f861d 100644 --- a/src/core/runtime/runtime.h +++ b/src/core/runtime/runtime.h @@ -21,12 +21,19 @@ #include "core/task/exception.h" #include "core/utilities/typedefs.h" +/** @defgroup runtime Runtime and library contexts + */ + namespace legate { extern uint32_t extract_env(const char* env_name, const uint32_t default_value, const uint32_t test_value); +/** + * @ingroup runtime + * @brief A utility class that collects static members shared by all Legate libraries + */ struct Core { public: static void parse_config(void); @@ -37,7 +44,16 @@ struct Core { static void report_unexpected_exception(const Legion::Task* task, const legate::TaskException& e); public: + /** + * @brief Type signature for registration callbacks + */ using RegistrationCallback = void (*)(); + /** + * @brief Performs a registration callback. Libraries must perform + * registration of tasks and other components through this function. + * + * @param callback Registration callback to perform + */ static void perform_registration(RegistrationCallback callback); public: diff --git a/src/core/task/exception.h b/src/core/task/exception.h index ec0c147ab..9f34f8b76 100644 --- a/src/core/task/exception.h +++ b/src/core/task/exception.h @@ -18,22 +18,60 @@ #include +/** + * @file + * @brief Class definition for legate::TaskException + */ + namespace legate { +/** + * @ingroup task + * @brief An exception class used in cross language exception handling + * + * Any client that needs to catch a C++ exception during task execution and have it rethrown + * on the launcher side should wrap that C++ exception with a `TaskException`. In case the + * task can raise more than one type of exception, they are distinguished by integer ids; + * the launcher is responsible for enumerating a list of all exceptions that can be raised + * and the integer ids are positions in that list. + */ class TaskException : public std::exception { public: - TaskException(const std::string& error_message) : index_(0), error_message_(error_message) {} - + /** + * @brief Constructs a `TaskException` object with an exception id and an error message. + * The id must be a valid index for the list of exceptions declared by the launcher. + * + * @param index Exception id + * @param error_message Error message + */ TaskException(int32_t index, const std::string& error_message) : index_(index), error_message_(error_message) { } + /** + * @brief Constructs a `TaskException` object with an error message. The exception id + * is set to 0. + * + * @param error_message Error message + */ + TaskException(const std::string& error_message) : index_(0), error_message_(error_message) {} + public: virtual const char* what() const throw() { return error_message_.c_str(); } public: + /** + * @brief Returns the exception id + * + * @return The exception id + */ int32_t index() const { return index_; } + /** + * @brief Returns the error message + * + * @return The error message + */ const std::string& error_message() const { return error_message_; } private: diff --git a/src/core/task/registrar.h b/src/core/task/registrar.h index ad7e3ddb3..67c8c0d81 100644 --- a/src/core/task/registrar.h +++ b/src/core/task/registrar.h @@ -23,11 +23,64 @@ #include "core/task/variant.h" #include "core/utilities/typedefs.h" +/** + * @file + * @brief Class definition fo legate::TaskRegistrar + */ + namespace legate { class LibraryContext; class PendingTaskVariant; +/** + * @ingroup task + * @brief A helper class for task variant registration. + * + * The `legate::TaskRegistrar` class is designed to simplify the boilerplate that client libraries + * need to register all its task variants. The following is a boilerplate that each library + * needs to write: + * + * @code{.cpp} + * struct MyLibrary { + * public: + * template + * static void record_variant(Args&&... args) + * { + * get_registrar().record_variant(std::forward(args)...); + * } + * static legate::TaskRegistrar& get_registrar(); + * }; + * + * template + * struct MyLibraryTaskBase : public legate::LegateTask { + * using Registrar = MyLibrary; + * + * ... + * }; + * @endcode + * + * In the code above, the `MyLibrary` has a static member that returns a singleton + * `legate::TaskRegistrar` object, and another member `record_variant` that simply forwards all + * arguments to the registrar. Then, the `MyLibraryTaskBase` points to the class so Legate can find + * where task variants are registered. + * + * Once this registrar is set up in a library, each library task can simply register itself + * with the `LegateTask::register_variants` method like the following: + * + * @code{.cpp} + * // In a header + * struct MyLibraryTask : public MyLibraryTaskBase { + * ... + * }; + * + * // In a C++ file + * static void __attribute__((constructor)) register_tasks() + * { + * MyLibraryTask::register_variants(); + * } + * @endcode + */ class TaskRegistrar { public: void record_variant(Legion::TaskID tid, @@ -40,6 +93,12 @@ class TaskRegistrar { const VariantOptions& options); public: + /** + * @brief Registers all tasks recorded in this registrar. Typically invoked in a registration + * callback of a library. + * + * @param context Context of the library that owns this registrar + */ void register_all_tasks(const LibraryContext& context); private: diff --git a/src/core/task/task.h b/src/core/task/task.h index 76a9d6eb3..50577bce2 100644 --- a/src/core/task/task.h +++ b/src/core/task/task.h @@ -19,17 +19,54 @@ #include "core/task/variant.h" #include "core/utilities/typedefs.h" +/** @defgroup task Task + */ + +/** + * @file + * @brief Class definition fo legate::LegateTask + */ namespace legate { class TaskContext; +/** + * @brief Function signature for task variants. Each task variant must be a function of this type. + */ using VariantImpl = void (*)(TaskContext&); +/** + * @ingroup task + * @brief A base class template for Legate task implementations. + * + * Any Legate task class must inherit legate::LegateTask directly or transitively. The type + * parameter `T` needs to be bound to a child Legate task class that inherits legate::LegateTask. + * + * Curently, each task can have up to three variants and the variants need to be static member + * functions of the class under the following names: + * + * - `cpu_variant`: CPU implementation of the task + * - `gpu_variant`: GPU implementation of the task + * - `omp_variant`: OpenMP implementation of the task + * + * Tasks must have at least one variant, and all task variants must be semantically equivalent + * (modulo some minor rounding errors due to floating point imprecision). + * + * Each task class must also have a type alias `Registrar` that points to a library specific + * registrar class. (See legate::TaskRegistrar for details.) + */ template struct LegateTask { // Exports the base class so we can access it via subclass T using BASE = LegateTask; + /** + * @brief Registers all task variants of the task. The client can optionally specify + * variant options. + * + * @param all_options Options for task variants. Variants with no entires in `all_options` will + * use the default set of options + */ static void register_variants( const std::map& all_options = {}); diff --git a/src/core/task/variant.h b/src/core/task/variant.h index 53c350302..1ec6007ec 100644 --- a/src/core/task/variant.h +++ b/src/core/task/variant.h @@ -20,22 +20,55 @@ #include "core/utilities/typedefs.h" +/** + * @file + * @brief Class definition fo legate::VariantOptions + */ namespace legate { -// We're going to allow for each task to use only up to 341 scalar output stores +// Each scalar output store can take up to 12 bytes, so in the worst case there can be only up to +// 341 scalar output stores. constexpr size_t LEGATE_MAX_SIZE_SCALAR_RETURN = 4096; +/** + * @ingroup task + * @brief A helper class for specifying variant options + */ struct VariantOptions { + /** + * @brief If the flag is `true`, the variant launches no subtasks. `true` by default. + */ bool leaf{true}; bool inner{false}; bool idempotent{false}; + /** + * @brief If the flag is `true`, the variant needs a concurrent task launch. `false` by default. + */ bool concurrent{false}; + /** + * @brief Maximum aggregate size for scalar output values. 4096 by default. + */ size_t return_size{LEGATE_MAX_SIZE_SCALAR_RETURN}; + /** + * @brief Changes the value of the `leaf` flag + * + * @param `leaf` A new value for the `leaf` flag + */ VariantOptions& with_leaf(bool leaf); VariantOptions& with_inner(bool inner); VariantOptions& with_idempotent(bool idempotent); + /** + * @brief Changes the value of the `concurrent` flag + * + * @param `concurrent` A new value for the `concurrent` flag + */ VariantOptions& with_concurrent(bool concurrent); + /** + * @brief Sets a maximum aggregate size for scalar output values + * + * @param `return_size` A new maximum aggregate size for scalar output values + */ VariantOptions& with_return_size(size_t return_size); }; diff --git a/src/core/utilities/debug.h b/src/core/utilities/debug.h index d0f803fe5..d5e86cac4 100644 --- a/src/core/utilities/debug.h +++ b/src/core/utilities/debug.h @@ -25,6 +25,13 @@ #include +/** @defgroup util Utilities + */ + +/** + * @file + * @brief Debugging utilities + */ namespace legate { #ifdef LEGATE_USE_CUDA @@ -42,6 +49,16 @@ inline bool is_device_only_ptr(const void* ptr) #endif // LEGATE_USE_CUDA +/** + * @ingroup util + * @brief Converts the dense array into a string + * + * @param base Array to convert + * @param extents Extents of the array + * @param strides Strides for dimensions + * + * @return A string expressing the contents of the array + */ template std::string print_dense_array(const T* base, const Point& extents, size_t strides[DIM]) { @@ -93,6 +110,15 @@ std::string print_dense_array(const T* base, const Point& extents, size_t s return ss.str(); } +/** + * @ingroup util + * @brief Converts the dense array into a string using an accessor + * + * @param accessor Accessor to an array + * @param rect Sub-rectangle within which the elements should be retrieved + * + * @return A string expressing the contents of the array + */ template std::string print_dense_array(ACC accessor, const Rect& rect) { @@ -102,6 +128,14 @@ std::string print_dense_array(ACC accessor, const Rect& rect) return print_dense_array(base, extents, strides); } +/** + * @ingroup util + * @brief Converts the store to a string + * + * @param store Store to convert + * + * @return A string expressing the contents of the store + */ std::string print_dense_array(const Store& store); } // namespace legate diff --git a/src/core/utilities/dispatch.h b/src/core/utilities/dispatch.h index 8d3d2f302..f7c808005 100644 --- a/src/core/utilities/dispatch.h +++ b/src/core/utilities/dispatch.h @@ -18,6 +18,10 @@ #include "core/utilities/typedefs.h" +/** + * @file + * @brief Definitions for dispatch routines + */ namespace legate { template @@ -132,6 +136,20 @@ struct inner_dim_dispatch_fn { } }; +/** + * @ingroup util + * @brief Converts the runtime dimension and type code into compile time constants and + * invokes the functor with them + * + * The functor's `operator()` should take a dimension and a type code as template parameters. + * + * @param dim Dimension + * @param code Type code + * @param f Functor to dispatch + * @param args Extra arguments to the functor + * + * @return The functor's return value + */ template constexpr decltype(auto) double_dispatch(int dim, LegateTypeCode code, Functor f, Fnargs&&... args) { @@ -186,6 +204,20 @@ constexpr decltype(auto) double_dispatch(int dim, LegateTypeCode code, Functor f return inner_type_dispatch_fn<1>{}(code, f, std::forward(args)...); } +/** + * @ingroup util + * @brief Converts the runtime dimensions into compile time constants and invokes + * the functor with them + * + * The functor's `operator()` should take exactly two integers as template parameters. + * + * @param dim1 First dimension + * @param dim2 Second dimension + * @param f Functor to dispatch + * @param args Extra arguments to the functor + * + * @return The functor's return value + */ template constexpr decltype(auto) double_dispatch(int dim1, int dim2, Functor f, Fnargs&&... args) { @@ -240,6 +272,19 @@ constexpr decltype(auto) double_dispatch(int dim1, int dim2, Functor f, Fnargs&& return inner_dim_dispatch_fn<1>{}(dim2, f, std::forward(args)...); } +/** + * @ingroup util + * @brief Converts the runtime dimension into a compile time constant and invokes + * the functor with it + * + * The functor's `operator()` should take an integer as its sole template parameter. + * + * @param dim Dimension + * @param f Functor to dispatch + * @param args Extra arguments to the functor + * + * @return The functor's return value + */ template constexpr decltype(auto) dim_dispatch(int dim, Functor f, Fnargs&&... args) { @@ -294,6 +339,19 @@ constexpr decltype(auto) dim_dispatch(int dim, Functor f, Fnargs&&... args) return f.template operator()<1>(std::forward(args)...); } +/** + * @ingroup util + * @brief Converts the runtime type code into a compile time constant and invokes + * the functor with it + * + * The functor's `operator()` should take a type code as its sole template parameter. + * + * @param code Type code + * @param f Functor to dispatch + * @param args Extra arguments to the functor + * + * @return The functor's return value + */ template constexpr decltype(auto) type_dispatch(LegateTypeCode code, Functor f, Fnargs&&... args) { diff --git a/src/core/utilities/span.h b/src/core/utilities/span.h index a4fd12a8c..4f34c172d 100644 --- a/src/core/utilities/span.h +++ b/src/core/utilities/span.h @@ -19,8 +19,18 @@ #include #include +/** + * @file + * @brief Class definition for legate::Span + */ + namespace legate { +/** + * @ingroup data + * @brief A simple span implementation used in Legate. Should eventually be replaced with + * std::span once we bump up the C++ standard version to C++20 + */ template struct Span { public: @@ -28,9 +38,23 @@ struct Span { Span(const Span&) = default; public: + /** + * @brief Creates a span with an existing pointer and a size. + * + * The caller must guarantee that the allocation is big enough (i.e., bigger than or + * equal to `sizeof(T) * size`) and that the allocation is alive while the span is alive. + * + * @param data Pointer to the data + * @param size Number of elements + */ Span(T* data, size_t size) : data_(data), size_(size) {} public: + /** + * @brief Returns the number of elements + * + * @return The number of elements + */ size_t size() const { return size_; } public: @@ -39,10 +63,28 @@ struct Span { assert(pos < size_); return data_[pos]; } + /** + * @brief Returns the pointer to the first element + * + * @return Pointer to the first element + */ const T* begin() const { return &data_[0]; } + /** + * @brief Returns the pointer to the end of allocation + * + * @return Pointer to the end of allocation + */ const T* end() const { return &data_[size_]; } public: + /** + * @brief Slices off the first `off` elements. Passing an `off` greater than + * the size will fail with an assertion failure. + * + * @param off Number of elements to skip + * + * @return A span for range `[off, size())` + */ decltype(auto) subspan(size_t off) { assert(off <= size_); @@ -50,6 +92,11 @@ struct Span { } public: + /** + * @brief Returns a `const` pointer to the data + * + * @return Pointer to the data + */ const T* ptr() const { return data_; } private: diff --git a/src/core/utilities/type_traits.h b/src/core/utilities/type_traits.h index 84197f528..9ac4d8929 100644 --- a/src/core/utilities/type_traits.h +++ b/src/core/utilities/type_traits.h @@ -18,6 +18,11 @@ #include "core/utilities/typedefs.h" +/** + * @file + * @brief Definitions for type traits in Legate + */ + namespace legate { // This maps a type to its LegateTypeCode @@ -54,6 +59,10 @@ static constexpr LegateTypeCode legate_type_code_of> = COMPLEX64_ template <> static constexpr LegateTypeCode legate_type_code_of> = COMPLEX128_LT; #else // not clang +/** + * @ingroup util + * @brief A template constexpr that converts types to type codes + */ template constexpr LegateTypeCode legate_type_code_of = MAX_TYPE_NUMBER; @@ -148,29 +157,53 @@ struct LegateTypeOf { using type = complex; }; +/** + * @ingroup util + * @brief A template that converts type codes to types + */ template using legate_type_of = typename LegateTypeOf::type; +/** + * @ingroup util + * @brief A predicate that holds if the type code is of an integral type + */ template struct is_integral { static constexpr bool value = std::is_integral>::value; }; +/** + * @ingroup util + * @brief A predicate that holds if the type code is of a signed integral type + */ template struct is_signed { static constexpr bool value = std::is_signed>::value; }; +/** + * @ingroup util + * @brief A predicate that holds if the type code is of an unsigned integral type + */ template struct is_unsigned { static constexpr bool value = std::is_unsigned>::value; }; +/** + * @ingroup util + * @brief A predicate that holds if the type code is of a floating point type + */ template struct is_floating_point { static constexpr bool value = std::is_floating_point>::value; }; +/** + * @ingroup util + * @brief A predicate that holds if the type code is of a complex type + */ template struct is_complex : std::false_type {}; @@ -180,6 +213,10 @@ struct is_complex : std::true_type {}; template <> struct is_complex : std::true_type {}; +/** + * @ingroup util + * @brief A predicate that holds if the type is one of the supported complex types + */ template struct is_complex_type : std::false_type {}; diff --git a/src/core/utilities/typedefs.h b/src/core/utilities/typedefs.h index 7ab90cb75..b9ca9b38e 100644 --- a/src/core/utilities/typedefs.h +++ b/src/core/utilities/typedefs.h @@ -21,6 +21,11 @@ #include "core/legate_c.h" #include "legate_defines.h" +/** + * @file + * @brief Type aliases to Legion components + */ + namespace legate { // C enum typedefs @@ -38,61 +43,292 @@ using TunableID = Legion::TunableID; // Geometry types +/** @defgroup geometry Geometry types + * + * @{ + */ + +/** + * @brief Coordinate type. + */ using coord_t = Legion::coord_t; +/** + * @brief Type for multi-dimensional points. + * + * Point objects support index expressions; they can be accessed like a statically-sized array. + * Point objects also support usual arithmetic operators and a dot opreator. + * + * For a complete definition, see + * [`Realm::Point`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/point.h#L46-L124). + */ template using Point = Legion::Point; + +/** + * @brief Type for multi-dimensional rectangles. + * + * Each rectangle consists of two legate::Point objects, one for the lower + * bounds (`.lo`) and one for the upper bounds (`.hi`). + * + * For a complete definition, see + * [`Realm::Rect`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/point.h#L126-L212). + */ template using Rect = Legion::Rect; -using Domain = Legion::Domain; +/** + * @brief Dimension-erased type for multi-dimensional points. + * + * For a complete definition, see + * [`Legion::DomainPoint`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_domain.h#L127-L253). + */ using DomainPoint = Legion::DomainPoint; +/** + * @brief Dimension-erased type for multi-dimensional rectangles. + * + * For a complete definition, see + * [`Legion::Domain`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_domain.h#L255-L543). + */ +using Domain = Legion::Domain; + +/** @} */ // end of geometry + // Accessor types +/** @defgroup accessor Accessor types + * + * Accessors provide an interface to access values in stores. Access modes are encoded + * in the accessor types so that the compiler can catch invalid accesses. Accessors also + * provide bounds checks (which can be turned on with a compile flag). + * + * All accessors have a `ptr` method that returns a raw pointer to the underlying allocation. + * The caller can optionally pass an array to query strides of dimensions, necessary for correct + * accesse. Unlike the accesses mediated by accessors, raw pointer accesses are not protected by + * Legate, and thus the developer should make sure of safety of the accesses. + * + * The most common mistake with raw pointers from reduction accessors are that the code overwrites + * values to the elements, instead of reducing them. The key contract with reduction is that + * the values must be reduced to the elements in the store. So, any client code that uses a raw + * pointer to a reduction store should make sure that it makes updates to the effect of reducing + * its contributions to the original elements. Not abiding by this contract can lead to + * non-deterministic conrrectness issues. + * + * @{ + */ + +/** + * @brief Read-only accessor + * + * See + * [legion.h](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion.h#L2555-L2562) + * for a complete list of supported operators. + */ template using AccessorRO = Legion::FieldAccessor>; + +/** + * @brief Write-only accessor + * + * See + * [legion.h](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion.h#L2575-L2581) + * for a complete list of supported operators. + */ template using AccessorWO = Legion::FieldAccessor>; + +/** + * @brief Read-write accessor + * + * See + * [legion.h](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion.h#L2564-L2573) + * for a complete list of supported operators. + */ template using AccessorRW = Legion::FieldAccessor>; + +/** + * @brief Reduction accessor + * + * Unlike the other accessors, an index expression on a reduction accessor allows the client to + * perform only two operations, `<<=` and `reduce`, both of which reduce a value to the chosen + * element. + * + * See + * [legion.h](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion.h#L2837-L2848) + * for details about the reduction accessor. + */ template using AccessorRD = Legion:: ReductionAccessor>; +/** @} */ // end of accessor + // Iterators +/** @defgroup iterator Iterator types + * + * @{ + */ + +/** + * @brief Iterator that iterates all points in a given `legate::Rect`. + * + * See + * [Realm::PointInRectIterator](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/point.h#L239-L255) + * for a complete definition. + */ template using PointInRectIterator = Legion::PointInRectIterator; -template -using RectInDomainIterator = Legion::RectInDomainIterator; + +/** + * @brief Iterator that iterates all points in a given `legate::Domain`. + * + * See + * [Legion::PointInDomainIterator](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_domain.h#L599-L622) + * for a complete definition. + */ template using PointInDomainIterator = Legion::PointInDomainIterator; +/** @} */ // end of iterator + // Machine +/** @defgroup machine Machine objects + * + * @{ + */ + +/** + * @brief Logical processor handle + * + * Legate libraries rarely use processor handles directly and there are no Legate APIs that take + * a processor handle. However, the libraries may want to query the processor that runs the + * current task to perform some processor- or processor kind-specific operations. In that case, + * `legate::Processor::get_executing_processor` can be used. Other useful memobers of + * `legate::Processor` are the `kind` method, which returns the processor kind, and + * `legate::Processor::Kind`, an enum for all processor types. + * + * See + * [`Realm::Processor`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/processor.h#L35-L141) + * for a complete definition. The list of processor types can be found + * [here](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/realm_c.h#L45-L54). + * + */ using Processor = Legion::Processor; -using Memory = Legion::Memory; + +/** + * @brief Logical memory handle + * + * In Legate, libraries will never have to use memory handles directly. However, some Legate + * APIs (e.g., legate::create_buffer) take a memory kind as an argument; `legate::Memory::Kind` + * is an enum for all memory types. + * + * See + * [`Realm::Memory`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/memory.h#L30-L65) + * for a complete definition. The list of memory types can be found + * [here](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/realm/realm_c.h#L63-L78). + */ +using Memory = Legion::Memory; + +/** @} */ // end of machine // Reduction operators +/** @defgroup reduction Built-in reduction operators + * + * All built-in operators are defined for signed and unsigned integer types. Floating point + * types (`__half`, `float`, and `double`) are supported by all but bitwise operators. Arithmetic + * operators also cover complex types `complex<__half>` and `complex`. + * + * For details about reduction operators, See LibraryContext::register_reduction_operator. + * + * @{ + */ + +/** + * @brief Reduction with addition + * + * See + * [`Legion::SumReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L46-L285). + */ template using SumReduction = Legion::SumReduction; + +/** + * @brief Reduction with subtraction + * + * See + * [`Legion::DiffReduction`](https://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L287-L492). + */ template using DiffReduction = Legion::DiffReduction; + +/** + * @brief Reduction with multiplication + * + * See + * [`Legion::ProdReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L494-L714). + */ template using ProdReduction = Legion::ProdReduction; + +/** + * @brief Reduction with division + * + * See + * [`Legion::DivReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L716-L921). + */ template using DivReduction = Legion::DivReduction; + +/** + * @brief Reduction with the binary max operator + * + * See + * [`Legion::MaxReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L923-L1109). + */ template using MaxReduction = Legion::MaxReduction; + +/** + * @brief Reduction with the binary min operator + * + * See + * [`Legion::MinReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L1111-L1297). + */ template using MinReduction = Legion::MinReduction; + +/** + * @brief Reduction with bitwise or + * + * See + * [`Legion::OrReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L1299-L1423). + */ template using OrReduction = Legion::OrReduction; + +/** + * @brief Reduction with bitwise and + * + * See + * [`Legion::AndReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L1425-L1549). + */ template using AndReduction = Legion::AndReduction; + +/** + * @brief Reduction with bitwise xor + * + * See + * [`Legion::XorReduction`](http://github.com/StanfordLegion/legion/blob/9ed6f4d6b579c4f17e0298462e89548a4f0ed6e5/runtime/legion/legion_redop.h#L1551-L1690). + */ template using XorReduction = Legion::XorReduction; +/** @} */ // end of reduction + } // namespace legate diff --git a/src/legate.h b/src/legate.h index 7e53e9a45..76e4b6d36 100644 --- a/src/legate.h +++ b/src/legate.h @@ -16,6 +16,12 @@ #pragma once +/** + * @mainpage Legate C++ API reference + * + * This is an API reference for Legate's C++ components. + */ + #include "legion.h" // legion.h has to go before these #include "core/data/allocator.h" From bab96c0ce400c9fa981d82f652ad5864f2e13e1b Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Wed, 1 Mar 2023 13:54:29 -0800 Subject: [PATCH 47/57] Add a link to the C++ API reference in the Python doc (#601) --- docs/legate/core/source/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/legate/core/source/index.rst b/docs/legate/core/source/index.rst index 5475b6fa6..b968d3738 100644 --- a/docs/legate/core/source/index.rst +++ b/docs/legate/core/source/index.rst @@ -6,7 +6,8 @@ Welcome to Legate Core's documentation! Overview Build instructions - API Reference + Python API Reference + C++ API Reference Contributing Versions From 58d434f67e30fd252be59a98b175e0d092c5b1e3 Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Wed, 1 Mar 2023 14:00:25 -0800 Subject: [PATCH 48/57] Fix the url to the documentation in README (#602) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ba08b815b..325e5f88f 100644 --- a/README.md +++ b/README.md @@ -465,8 +465,8 @@ See the discussion of contributing in [CONTRIBUTING.md](CONTRIBUTING.md). ## Documentation -A complete list of available features can is provided in the [API -reference](https://nv-legate.github.io/legate.core/api.html). +A complete list of available features can is found in the [Legate Core +documentation](https://nv-legate.github.io/legate.core). ## Next Steps From 3daa0647e02cd2352b08a89bfa588e3d363bad1f Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Wed, 1 Mar 2023 16:08:44 -0800 Subject: [PATCH 49/57] add support for --version (#600) --- legate/driver/args.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/legate/driver/args.py b/legate/driver/args.py index 55c382e3b..daee26ab0 100644 --- a/legate/driver/args.py +++ b/legate/driver/args.py @@ -18,6 +18,7 @@ from argparse import REMAINDER, ArgumentDefaultsHelpFormatter, ArgumentParser +from .. import __version__ from ..util.shared_args import ( CPUS, FBMEM, @@ -381,3 +382,9 @@ required=False, help="Whether to use color terminal output (if colorama is installed)", ) + +other.add_argument( + "--version", + action="version", + version=__version__, +) From 37596159b1f8f06439fdc95d6090bbc4315c302c Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Wed, 1 Mar 2023 21:19:46 -0800 Subject: [PATCH 50/57] Map each Legate callback to a unique Legion callback (#603) --- legate_core_cpp.cmake | 1 + src/core/runtime/runtime.cc | 22 ------------------- src/core/runtime/runtime.h | 7 ++++-- src/core/runtime/runtime.inl | 42 ++++++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 24 deletions(-) create mode 100644 src/core/runtime/runtime.inl diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index d18ebdb22..4caab4973 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -327,6 +327,7 @@ if (legate_core_BUILD_DOCS) src/core/data/allocator.h # runtime src/core/runtime/runtime.h + src/core/runtime/runtime.inl src/core/runtime/context.h # mapping src/core/mapping/mapping.h diff --git a/src/core/runtime/runtime.cc b/src/core/runtime/runtime.cc index 020ff02cb..2b17a830b 100644 --- a/src/core/runtime/runtime.cc +++ b/src/core/runtime/runtime.cc @@ -144,28 +144,6 @@ static void extract_scalar_task( LEGATE_ABORT; } -namespace detail { - -struct RegistrationCallbackArgs { - Core::RegistrationCallback callback; -}; - -void invoke_legate_registration_callback(const Legion::RegistrationCallbackArgs& args) -{ - auto p_args = static_cast(args.buffer.get_ptr()); - p_args->callback(); -}; - -} // namespace detail - -/*static*/ void Core::perform_registration(RegistrationCallback callback) -{ - legate::detail::RegistrationCallbackArgs args{callback}; - Legion::UntypedBuffer buffer(&args, sizeof(args)); - Legion::Runtime::perform_registration_callback( - detail::invoke_legate_registration_callback, buffer, true /*global*/); -} - void register_legate_core_tasks(Legion::Machine machine, Legion::Runtime* runtime, const LibraryContext& context) diff --git a/src/core/runtime/runtime.h b/src/core/runtime/runtime.h index ccd1f861d..8a78be56c 100644 --- a/src/core/runtime/runtime.h +++ b/src/core/runtime/runtime.h @@ -52,9 +52,10 @@ struct Core { * @brief Performs a registration callback. Libraries must perform * registration of tasks and other components through this function. * - * @param callback Registration callback to perform + * @tparam CALLBACK Registration callback to perform */ - static void perform_registration(RegistrationCallback callback); + template + static void perform_registration(); public: // Configuration settings @@ -66,3 +67,5 @@ struct Core { }; } // namespace legate + +#include "core/runtime/runtime.inl" diff --git a/src/core/runtime/runtime.inl b/src/core/runtime/runtime.inl new file mode 100644 index 000000000..0c98e9c7f --- /dev/null +++ b/src/core/runtime/runtime.inl @@ -0,0 +1,42 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "core/runtime/runtime.h" + +namespace legate { + +namespace detail { + +template +void invoke_legate_registration_callback(Legion::Machine, + Legion::Runtime*, + const std::set&) +{ + CALLBACK(); +}; + +} // namespace detail + +template +/*static*/ void Core::perform_registration() +{ + Legion::Runtime::perform_registration_callback( + detail::invoke_legate_registration_callback, true /*global*/); +} + +} // namespace legate From 44250a6ea549d7c8ea808358c01919cac04613cc Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 2 Mar 2023 10:19:44 -0800 Subject: [PATCH 51/57] add missing install file (#605) --- legate_core_cpp.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index 4caab4973..1ad9d1919 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -412,6 +412,7 @@ install( FILES src/core/runtime/context.h src/core/runtime/context.inl src/core/runtime/runtime.h + src/core/runtime/runtime.inl DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/legate/core/runtime) install( From a65d4af81b68ff9861d827e8c38f23581797db6b Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Thu, 2 Mar 2023 10:55:44 -0800 Subject: [PATCH 52/57] More informative OOM message (#604) * More informative OOM message * Reformat message * No need for numbers anymore --- src/core/mapping/base_mapper.cc | 33 ++++++++++++++++++++++++++------- src/core/mapping/base_mapper.h | 3 ++- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/core/mapping/base_mapper.cc b/src/core/mapping/base_mapper.cc index 85a2c7427..65c9f1537 100644 --- a/src/core/mapping/base_mapper.cc +++ b/src/core/mapping/base_mapper.cc @@ -764,7 +764,7 @@ bool BaseMapper::map_legate_store(const Legion::Mapping::MapperContext ctx, return false; } if (!can_fail) - report_failed_mapping(mappable, mapping.requirement_index(), target_memory, redop); + report_failed_mapping(mappable, mapping.requirement_index(), target_memory, redop, footprint); return true; } @@ -863,7 +863,8 @@ bool BaseMapper::map_legate_store(const Legion::Mapping::MapperContext ctx, // If we make it here then we failed entirely if (!can_fail) { auto req_indices = mapping.requirement_indices(); - for (auto req_idx : req_indices) report_failed_mapping(mappable, req_idx, target_memory, redop); + for (auto req_idx : req_indices) + report_failed_mapping(mappable, req_idx, target_memory, redop, footprint); } return true; } @@ -871,7 +872,8 @@ bool BaseMapper::map_legate_store(const Legion::Mapping::MapperContext ctx, void BaseMapper::report_failed_mapping(const Legion::Mappable& mappable, uint32_t index, Memory target_memory, - Legion::ReductionOpID redop) + Legion::ReductionOpID redop, + size_t footprint) { static const char* memory_kinds[] = { #define MEM_NAMES(name, desc) desc, @@ -894,15 +896,32 @@ void BaseMapper::report_failed_mapping(const Legion::Mappable& mappable, else req_ss << "region requirement " << index; - logger.error("Mapper %s failed to map %s of %s%s[%s] (UID %lld) into %s memory " IDFMT, + logger.error("Mapper %s failed to allocate %zd bytes on memory " IDFMT + " (of kind %s: %s) for %s of %s%s[%s] (UID %lld).\n" + "This means Legate was unable to reserve ouf of its memory pool the full amount " + "required for the above operation. Here are some things to try:\n" + "* Make sure your code is not impeding the garbage collection of Legate-backed " + "objects, e.g. by storing references in caches, or creating reference cycles.\n" + "* Ask Legate to reserve more space on the above memory, using the appropriate " + "--*mem legate flag.\n" + "* Assign less memory to the eager pool, by reducing --eager-alloc-percentage.\n" + "* If running on multiple nodes, increase how often distributed garbage collection " + "runs, by reducing LEGATE_FIELD_REUSE_FREQ (default: 32, warning: may " + "incur overhead).\n" + "* Adapt your code to reduce temporary storage requirements, e.g. by breaking up " + "larger operations into batches.\n" + "* If the previous steps don't help, and you are confident Legate should be able to " + "handle your code's working set, please open an issue on Legate's bug tracker.", get_mapper_name(), + footprint, + target_memory.id, + Legion::Mapping::Utilities::to_string(target_memory.kind()), + memory_kinds[target_memory.kind()], req_ss.str().c_str(), log_mappable(mappable, true /*prefix_only*/).c_str(), opname.c_str(), provenance.c_str(), - mappable.get_unique_id(), - memory_kinds[target_memory.kind()], - target_memory.id); + mappable.get_unique_id()); LEGATE_ABORT; } diff --git a/src/core/mapping/base_mapper.h b/src/core/mapping/base_mapper.h index 32d6ca2cb..b4c6dcfd7 100644 --- a/src/core/mapping/base_mapper.h +++ b/src/core/mapping/base_mapper.h @@ -287,7 +287,8 @@ class BaseMapper : public Legion::Mapping::Mapper, public MachineQueryInterface void report_failed_mapping(const Legion::Mappable& mappable, unsigned index, Memory target_memory, - Legion::ReductionOpID redop); + Legion::ReductionOpID redop, + size_t footprint); void legate_select_sources(const Legion::Mapping::MapperContext ctx, const Legion::Mapping::PhysicalInstance& target, const std::vector& sources, From 847ef92a4fb21ff8bc82e4b6677644e7873b8494 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 2 Mar 2023 15:31:50 -0800 Subject: [PATCH 53/57] Build helper functions for legate projects, legate-hello example (#571) * Add helper functions to reduce build boilerplate for legate projects * add hello world into repo and add build tests for external projects * separate cunumeric example for easier running and fill out doc files --- CMakeLists.txt | 5 + cmake/legate_helper_functions.cmake | 427 ++++++++++++++++++ examples/CMakeLists.txt | 5 + examples/hello/CMakeLists.txt | 14 + examples/hello/README.md | 218 +++++++++ examples/hello/editable-install.sh | 5 + examples/hello/examples/cunumeric-variance.py | 26 ++ examples/hello/examples/hello-world.md | 37 ++ examples/hello/examples/hello-world.py | 5 + examples/hello/examples/variance.md | 67 +++ examples/hello/examples/variance.py | 23 + examples/hello/hello/__init__.py | 2 + examples/hello/hello/hello.py | 169 +++++++ examples/hello/install.sh | 1 + examples/hello/setup.py | 56 +++ examples/hello/src/CMakeLists.txt | 22 + examples/hello/src/hello_cffi.h | 7 + examples/hello/src/hello_world.cc | 25 + examples/hello/src/hello_world.h | 10 + examples/hello/src/iota.cc | 33 ++ examples/hello/src/square.cc | 44 ++ examples/hello/src/sum.cc | 49 ++ legate_core_cpp.cmake | 11 +- pyproject.toml | 2 + src/core/runtime/runtime.h | 1 + 25 files changed, 1262 insertions(+), 2 deletions(-) create mode 100644 cmake/legate_helper_functions.cmake create mode 100644 examples/CMakeLists.txt create mode 100644 examples/hello/CMakeLists.txt create mode 100644 examples/hello/README.md create mode 100755 examples/hello/editable-install.sh create mode 100644 examples/hello/examples/cunumeric-variance.py create mode 100644 examples/hello/examples/hello-world.md create mode 100644 examples/hello/examples/hello-world.py create mode 100644 examples/hello/examples/variance.md create mode 100644 examples/hello/examples/variance.py create mode 100644 examples/hello/hello/__init__.py create mode 100644 examples/hello/hello/hello.py create mode 100755 examples/hello/install.sh create mode 100644 examples/hello/setup.py create mode 100644 examples/hello/src/CMakeLists.txt create mode 100644 examples/hello/src/hello_cffi.h create mode 100644 examples/hello/src/hello_world.cc create mode 100644 examples/hello/src/hello_world.h create mode 100644 examples/hello/src/iota.cc create mode 100644 examples/hello/src/square.cc create mode 100644 examples/hello/src/sum.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index c83e6b7c1..cd9522297 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,3 +123,8 @@ if(CMAKE_GENERATOR STREQUAL "Ninja") endfunction() add_touch_legate_core_ninja_build_target() endif() + +option(legate_core_EXAMPLE_BUILD_TESTS OFF) +if (legate_core_EXAMPLE_BUILD_TESTS) + add_subdirectory(examples) +endif() diff --git a/cmake/legate_helper_functions.cmake b/cmake/legate_helper_functions.cmake new file mode 100644 index 000000000..79f2d1c1f --- /dev/null +++ b/cmake/legate_helper_functions.cmake @@ -0,0 +1,427 @@ +macro(legate_include_rapids) + if (NOT _LEGATE_HAS_RAPIDS) + if(NOT EXISTS ${CMAKE_BINARY_DIR}/LEGATE_RAPIDS.cmake) + file(DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-23.02/RAPIDS.cmake + ${CMAKE_BINARY_DIR}/LEGATE_RAPIDS.cmake) + endif() + include(${CMAKE_BINARY_DIR}/LEGATE_RAPIDS.cmake) + include(rapids-cmake) + include(rapids-cpm) + include(rapids-cuda) + include(rapids-export) + include(rapids-find) + set(_LEGATE_HAS_RAPIDS ON) + endif() +endmacro() + +function(legate_default_cpp_install target) + set(options) + set(one_value_args EXPORT) + set(multi_value_args) + cmake_parse_arguments( + LEGATE_OPT + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN} + ) + + if (NOT LEGATE_OPT_EXPORT) + message(FATAL_ERROR "Need EXPORT name for legate_default_install") + endif() + + legate_include_rapids() + + rapids_cmake_install_lib_dir(lib_dir) + + install(TARGETS ${target} + DESTINATION ${lib_dir} + EXPORT ${LEGATE_OPT_EXPORT}) + + rapids_export( + INSTALL ${target} + EXPORT_SET ${LEGATE_OPT_EXPORT} + GLOBAL_TARGETS ${target} + NAMESPACE legate:: + ) + + # build export targets + rapids_export( + BUILD ${target} + EXPORT_SET ${LEGATE_OPT_EXPORT} + GLOBAL_TARGETS ${target} + NAMESPACE legate:: + ) +endfunction() + +function(legate_add_cffi header) + if (NOT DEFINED CMAKE_C_COMPILER) + message(FATAL_ERROR "Must enable C language to build Legate projects") + endif() + + set(options) + set(one_value_args TARGET) + set(multi_value_args) + cmake_parse_arguments( + LEGATE_OPT + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN} + ) + # abbreviate for the function below + set(target ${LEGATE_OPT_TARGET}) + set(install_info_in +[=[ +from pathlib import Path + +def get_libpath(): + import os, sys, platform + join = os.path.join + exists = os.path.exists + dirname = os.path.dirname + cn_path = dirname(dirname(__file__)) + so_ext = { + "": "", + "Java": ".jar", + "Linux": ".so", + "Darwin": ".dylib", + "Windows": ".dll" + }[platform.system()] + + def find_lib(libdir): + target = f"libhello{so_ext}*" + search_path = Path(libdir) + matches = [m for m in search_path.rglob(target)] + if matches: + return matches[0].parent + return None + + return ( + find_lib("@libdir@") or + find_lib(join(dirname(dirname(dirname(cn_path))), "lib")) or + find_lib(join(dirname(dirname(sys.executable)), "lib")) or + "" + ) + +libpath: str = get_libpath() + +header: str = """ + @header@ + void @target@_perform_registration(); +""" +]=]) + set(install_info_py_in ${CMAKE_BINARY_DIR}/legate_${target}/install_info.py.in) + set(install_info_py ${CMAKE_SOURCE_DIR}/${target}/install_info.py) + file(WRITE ${install_info_py_in} "${install_info_in}") + + set(generate_script_content + [=[ + execute_process( + COMMAND ${CMAKE_C_COMPILER} + -E + -P @header@ + ECHO_ERROR_VARIABLE + OUTPUT_VARIABLE header + COMMAND_ERROR_IS_FATAL ANY + ) + configure_file( + @install_info_py_in@ + @install_info_py@ + @ONLY) + ]=]) + + set(generate_script ${CMAKE_BINARY_DIR}/gen_install_info.cmake) + file(CONFIGURE + OUTPUT ${generate_script} + CONTENT "${generate_script_content}" + @ONLY + ) + + # cmake doesn't let you pipe the output of a + # custom command so you have to generate a script + # that writes to a file and THEN run that in a + # custom command + add_custom_target("generate_install_info_py" ALL + COMMAND ${CMAKE_COMMAND} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -Dtarget=${target} + -P ${generate_script} + OUTPUT ${install_info_py} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating install_info.py" + DEPENDS ${header} + ) +endfunction() + +function(legate_default_python_install target) + set(options) + set(one_value_args EXPORT) + set(multi_value_args) + cmake_parse_arguments( + LEGATE_OPT + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN} + ) + + if (NOT LEGATE_OPT_EXPORT) + message(FATAL_ERROR "Need EXPORT name for legate_default_python_install") + endif() + + if (SKBUILD) + add_library(${target}_python INTERFACE) + add_library(legate::${target}_python ALIAS ${target}_python) + target_link_libraries(${target}_python INTERFACE legate::core legate::${target}) + + install(TARGETS ${target}_python + DESTINATION ${lib_dir} + EXPORT ${LEGATE_OPT_EXPORT}) + + legate_include_rapids() + rapids_export( + INSTALL ${target}_python + EXPORT_SET ${LEGATE_OPT_EXPORT} + GLOBAL_TARGETS ${target}_python + NAMESPACE legate:: + ) + endif() +endfunction() + +function(legate_add_cpp_subdirectory dir) + set(options) + set(one_value_args EXPORT TARGET) + set(multi_value_args) + cmake_parse_arguments( + LEGATE_OPT + "${options}" + "${one_value_args}" + "${multi_value_args}" + ${ARGN} + ) + + if (NOT LEGATE_OPT_EXPORT) + message(FATAL_ERROR "Need EXPORT name for legate_default_install") + endif() + + if (NOT LEGATE_OPT_TARGET) + message(FATAL_ERROR "Need TARGET name for Legate package") + endif() + # abbreviate for the function + set(target ${LEGATE_OPT_TARGET}) + + legate_include_rapids() + + rapids_find_package(legate_core CONFIG + GLOBAL_TARGETS legate::core + BUILD_EXPORT_SET ${LEGATE_OPT_EXPORT} + INSTALL_EXPORT_SET ${LEGATE_OPT_EXPORT}) + + if (SKBUILD) + if (NOT DEFINED ${target}_ROOT) + set(${target}_ROOT ${CMAKE_SOURCE_DIR}/build) + endif() + rapids_find_package(${target} CONFIG + GLOBAL_TARGETS legate::${target} + BUILD_EXPORT_SET ${LEGATE_OPT_EXPORT} + INSTALL_EXPORT_SET ${LEGATE_OPT_EXPORT}) + if (NOT ${target}_FOUND) + add_subdirectory(${dir} ${CMAKE_BINARY_DIR}/legate_${target}) + legate_default_cpp_install(${target} EXPORT ${LEGATE_OPT_EXPORT}) + endif() + else() + add_subdirectory(${dir} ${CMAKE_BINARY_DIR}/legate_${target}) + legate_default_cpp_install(${target} EXPORT ${LEGATE_OPT_EXPORT}) + endif() + +endfunction() + +function(legate_cpp_library_template target output_sources_variable) + set(file_template +[=[ +#pragma once + +#include "legate.h" + +namespace @target@ { + +struct Registry { + public: + template + static void record_variant(Args&&... args) + { + get_registrar().record_variant(std::forward(args)...); + } + static legate::TaskRegistrar& get_registrar(); +}; + +template +struct Task : public legate::LegateTask { + using Registrar = Registry; + static constexpr int TASK_ID = ID; +}; + +} +]=]) + string(CONFIGURE "${file_template}" file_content @ONLY) + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/legate_library.h "${file_content}") + + set(file_template +[=[ +#include "legate_library.h" +#include "core/mapping/mapping.h" + +namespace @target@ { + +class Mapper : public legate::mapping::LegateMapper { + public: + Mapper(){} + + private: + Mapper(const Mapper& rhs) = delete; + Mapper& operator=(const Mapper& rhs) = delete; + + // Legate mapping functions + public: + void set_machine(const legate::mapping::MachineQueryInterface* machine) override { + machine_ = machine; + } + + legate::mapping::TaskTarget task_target( + const legate::mapping::Task& task, + const std::vector& options) override { + return *options.begin(); + } + + std::vector store_mappings( + const legate::mapping::Task& task, + const std::vector& options) override { + using legate::mapping::StoreMapping; + std::vector mappings; + auto& inputs = task.inputs(); + auto& outputs = task.outputs(); + for (auto& input : inputs) { + mappings.push_back(StoreMapping::default_mapping(input, options.front())); + mappings.back().policy.exact = true; + } + for (auto& output : outputs) { + mappings.push_back(StoreMapping::default_mapping(output, options.front())); + mappings.back().policy.exact = true; + } + return std::move(mappings); + } + + legate::Scalar tunable_value(legate::TunableID tunable_id) override { + return 0; + } + + private: + const legate::mapping::MachineQueryInterface* machine_; +}; + +static const char* const library_name = "hello"; + +Legion::Logger log_hello("hello"); + +/*static*/ legate::TaskRegistrar& Registry::get_registrar() +{ + static legate::TaskRegistrar registrar; + return registrar; +} + +void registration_callback() +{ + legate::ResourceConfig config; + config.max_mappers = 1; + config.max_tasks = 1024; + config.max_reduction_ops = 8; + legate::LibraryContext context(library_name, config); + + Registry::get_registrar().register_all_tasks(context); + + // Now we can register our mapper with the runtime + context.register_mapper(std::make_unique(), 0); +} + +} // namespace @target@ + +extern "C" { + +void @target@_perform_registration(void) +{ + // Tell the runtime about our registration callback so we hook it + // in before the runtime starts and make it global so that we know + // that this call back is invoked everywhere across all nodes + legate::Core::perform_registration<@target@::registration_callback>(); +} + +} +]=]) + string(CONFIGURE "${file_template}" file_content @ONLY) + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/legate_library.cc "${file_content}") + + set(${output_sources_variable} + legate_library.h + legate_library.cc + PARENT_SCOPE + ) +endfunction() + +function(legate_python_library_template target) +set(file_template +[=[ +from legate.core import ( + Library, + ResourceConfig, + get_legate_runtime, +) +import os +from typing import Any + +class UserLibrary(Library): + def __init__(self, name: str) -> None: + self.name = name + self.shared_object: Any = None + + @property + def cffi(self) -> Any: + return self.shared_object + + def get_name(self) -> str: + return self.name + + def get_shared_library(self) -> str: + from hello.install_info import libpath + return os.path.join(libpath, f"lib@target@{self.get_library_extension()}") + + def get_c_header(self) -> str: + from hello.install_info import header + + return header + + def get_registration_callback(self) -> str: + return "hello_perform_registration" + + def get_resource_configuration(self) -> ResourceConfig: + assert self.shared_object is not None + config = ResourceConfig() + config.max_tasks = 1024 + config.max_mappers = 1 + config.max_reduction_ops = 8 + config.max_projections = 0 + config.max_shardings = 0 + return config + + def initialize(self, shared_object: Any) -> None: + self.shared_object = shared_object + + def destroy(self) -> None: + pass + +user_lib = UserLibrary("@target@") +user_context = get_legate_runtime().register_library(user_lib) +]=]) + string(CONFIGURE "${file_template}" file_content @ONLY) + file(WRITE ${CMAKE_SOURCE_DIR}/${target}/library.py "${file_content}") +endfunction() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 000000000..fdee93f24 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,5 @@ +# We abuse find package for testing purposes here to +# 'find' the current build tree to test package builds +set(legate_core_ROOT ${CMAKE_BINARY_DIR}) + +add_subdirectory(hello) diff --git a/examples/hello/CMakeLists.txt b/examples/hello/CMakeLists.txt new file mode 100644 index 000000000..f163cfc7c --- /dev/null +++ b/examples/hello/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.22.1 FATAL_ERROR) + +project(hello VERSION 1.0 LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 17) +set(BUILD_SHARED_LIBS ON) + +find_package(legate_core REQUIRED) + +legate_add_cpp_subdirectory(src TARGET hello EXPORT hello-export) + +legate_add_cffi(${CMAKE_CURRENT_SOURCE_DIR}/src/hello_cffi.h TARGET hello) +legate_python_library_template(hello) +legate_default_python_install(hello EXPORT hello-export) diff --git a/examples/hello/README.md b/examples/hello/README.md new file mode 100644 index 000000000..d2a26a40e --- /dev/null +++ b/examples/hello/README.md @@ -0,0 +1,218 @@ +# Legate Hello World Application + +Here we illustrate a minimal example to get a Legate library up and running. +The example here shows how to get started with the minimum amount of boilerplate. +For advanced use cases, the boilerplate generated can be customized as needed. +In general, a Legate application will need to implement three pieces. + +1. Build system +1. C++ tasks +1. Python library + +Please refer to the README in the [Legate repo](https://github.com/nv-legate/legate.core/blob/HEAD/README.md) +for first installing `legate.core`. We strongly recommend creating a Conda environment for development and testing. + +# Build System + +## Build Steps + +To build the project, the user can do the following: + +``` +$ cmake -S . -B build +$ cmake --build build +$ python -m pip install -e . +``` + +This performs an editable install of the project, which we recommend for development. +If `cmake` fails to find Legate, the path to the installed Legate can be manually +specific as `-Dlegate_core_ROOT=<...>` to the `cmake` configuration. +Alternatively, the user can just do a regular pip installation: + +``` +$ python -m pip install . +``` + +These approaches are illustrated in the `editable-install.sh` and `install.sh` scripts. +In particular, `editable-install.sh` shows how to use Legate install info to +point CMake to the correct installation root. + +## CMake +CMake is the officially supported mechanism for building Legate libraries. +Legate exports a CMake target and helper functions for building libraries and provides by-far the easiest onboarding. +There are only a few main steps in setting up a build system. +First, the user should initialize a CMake project. + +```cmake +cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) + +project(hello VERSION 1.0 LANGUAGES C CXX) +``` + +Next the user needs to find an existing Legate core: + +```cmake +find_package(legate_core REQUIRED) +``` + +Once the `legate_core` package is located, a number of helper functions will be available. +In a source folder, the user can define a library that will implement the C++ tasks: + +```cmake +legate_cpp_library_template(hello TEMPLATE_SOURCES) + +add_library( + hello + hello_world.cc + hello_world.h + ${TEMPLATE_SOURCES} +) +target_link_libraries(hello PRIVATE legate::core) +``` + +First, a helper function is invoked to generate the Legate C++ boilerplate files. +The list of generated files is returned in the `TEMPLATE_SOURCES` variable. +Second, the CMake library is linked against the imported `legate::core` target. + +Two helper functions are provided to generate the Python boilerplate. +In the top-level CMakeLists.txt, the Python-C bindings can be generated using CFFI: + +```cmake +legate_add_cffi(${CMAKE_SOURCE_DIR}/src/hello_world.h TARGET hello) +``` + +The header file is implemented by the user and contains all the enums required +to implement a Legate library. The necessary Python file is generated in the `hello` +subdirectory. Additionally, the user may want to generate a standard `library.py` +in the Python `hello` folder: + +```cmake +legate_python_library_template(hello) +``` + +Finally, default pip installation hooks (via scikit-build) can be added: + +```cmake +legate_default_python_install(hello EXPORT hello-export) +``` + +## Editable Builds + +Although the final user Python library will likely be installed with `pip`, +the user will usually need to iterate on the C++ implementation of tasks +for debugging and optmization. The user will therefore want to be able +to first build the C++ pieces of the project and then install the Python. +To support this workflow, legate provides a helper function: + +```cmake +legate_add_cpp_subdirectory(src hello EXPORT hello-export) +``` +This encapsulates the build target `hello` so that the C++ library can +be first built with CMake and then pip-installed in a separate step. +This is optional, though, and the entire build can always be executed by +doing a regular pip install: + +``` +$ python -m pip install . +``` + +# C++ tasks + +First, a `hello_world.h` header is needed to define all enums. In this case, +we have enums identifying the different task types: + +```cpp +enum HelloOpCode { + _OP_CODE_BASE = 0, + HELLO_WORLD_TASK = 1, +}; +``` + +We implement this CPU-only task in a `hello_world.cc`. + +```cpp +#include "legate_library.h" +#include "hello_world.h" + +namespace hello { +``` + +The source file should include the library header and the generated file `legate_library.h`. +Because the target was named `hello` in the build files, all generated files create types +in the `hello` namespace. + +The task implementation is simple: + +```cpp +class HelloWorldTask : public Task { + public: + static void cpu_variant(legate::TaskContext& context){ + std::string message = context.scalars()[0].value(); + std::cout << message << std::endl; + } +}; +``` +Here we define a CPU variant. The task is given the unique enum ID from `hello_world.h`. +The task unpacks a string from the input context and prints it. +Task types needed to be statically registered, which requires a bit of extra boilerplate: + +```cpp +namespace +{ + +static void __attribute__((constructor)) register_tasks(void) +{ + hello::HelloWorldTask::register_variants(); +} + +} +``` + +Any tasks instantiated in the Python library will ultimately invoke this C++ task. + +# Python library + +The example uses two generated files `library.py` and `install_info.py`. +The implementation of tasks is provided in the `hello.py` file. +First, we have to import a few types and a context object for creating tasks. +The context object is automatically created in the generated boilerplate. + +```python +from .library import user_context, user_lib +from enum import IntEnum +from legate.core import Rect +import legate.core.types as types +``` + +The C++ enums can be mapped into Python: + +```python +class HelloOpCode(IntEnum): + HELLO_WORLD = user_lib.cffi.HELLO_WORLD_TASK +``` + +The example here provides two library functions. The first prints a single message. +The second prints a fixed number of of messages. For `print_hello`, +a new task is created in `user_context`. The message string is added as a scalar argument. +In the second example, a launch domain for a fixed `n` is provided. + +These library functions can now be imported and used in python. +This is shown in `examples/hello.py`: + +``` +from hello import print_hello + +print_hello("Hello, world") +``` + + +# Examples + +The tutorial contains a few examples that illustate key Legate concepts: + +1. [Hello World](examples/hello-world.md): Shows the basics of creating tasks and adding task arguments. +1. [Variance](examples/variance.md): Shows how to create input arrays and tasks operating on partitioned data. +Also shows how to perform reduction tasks like summation. + + + diff --git a/examples/hello/editable-install.sh b/examples/hello/editable-install.sh new file mode 100755 index 000000000..5c5774ece --- /dev/null +++ b/examples/hello/editable-install.sh @@ -0,0 +1,5 @@ +legate_root=`python -c 'import legate.install_info as i; from pathlib import Path; print(Path(i.libpath).parent.resolve())'` +echo "Using Legate at $legate_root" +cmake -S . -B build -D legate_core_ROOT=$legate_root +cmake --build build +python -m pip install -e . diff --git a/examples/hello/examples/cunumeric-variance.py b/examples/hello/examples/cunumeric-variance.py new file mode 100644 index 000000000..cfaed064d --- /dev/null +++ b/examples/hello/examples/cunumeric-variance.py @@ -0,0 +1,26 @@ +from typing import Any + +import cunumeric +import numpy as np +from hello import square, sum, to_scalar + +from legate.core import Store + + +def mean_and_variance(a: Any, n: int) -> float: + a_sq: Store = square(a) # A 1-D array of shape (4,) + sum_sq: Store = sum(a_sq) # A scalar sum + sum_a: Store = sum(a) # A scalar sum + + # Extract scalar values from the Legate stores + mean_a: float = to_scalar(sum_a) / n + mean_sum_sq: float = to_scalar(sum_sq) / n + variance = mean_sum_sq - mean_a * mean_a + return mean_a, variance + + +# Example: Use a random array from cunumeric +n = 4 +a = cunumeric.random.randn(n).astype(np.float32) +print(a) +print(mean_and_variance(a, n)) diff --git a/examples/hello/examples/hello-world.md b/examples/hello/examples/hello-world.md new file mode 100644 index 000000000..5df75a854 --- /dev/null +++ b/examples/hello/examples/hello-world.md @@ -0,0 +1,37 @@ +# Basic Hello, World Application + +The code for this example can be found in the [library file](../hello/hello.py) and [example](hello-world.py). + +## Single, auto task + +Generally auto tasks should be preferred that automatically +partition and parallelize task launches. +In the hello world example, only a single scalar argument +is added and the task is enqueued with `execute`: + +``` +task = user_context.create_auto_task(HelloOpCode.HELLO_WORLD) +task.add_scalar_arg(message, types.string) +task.execute() +``` + +In this case, the cost heuristic in the runtime will notice +that the task is inexpensive and launch a single instance. + +## Manual task with explicit launch domain + +It is possibly to manually specify the launch domain for a task, +overriding the internal heuristics. + +``` +launch_domain = Rect(lo=[0], hi=[n], exclusive=True) +task = user_context.create_manual_task( + HelloOpCode.HELLO_WORLD, launch_domain=launch_domain +) +task.add_scalar_arg(message, types.string) +task.execute() +``` + +Now `n` replica tasks will be launched. In this case, +the `Rect` launch domain is linear, but multi-dimensional domains +are also possible. diff --git a/examples/hello/examples/hello-world.py b/examples/hello/examples/hello-world.py new file mode 100644 index 000000000..15728fb48 --- /dev/null +++ b/examples/hello/examples/hello-world.py @@ -0,0 +1,5 @@ +from hello import print_hello, print_hellos + +print_hello("Hello, world") + +print_hellos(message="Romanes eunt domus", n=2) diff --git a/examples/hello/examples/variance.md b/examples/hello/examples/variance.md new file mode 100644 index 000000000..c11042823 --- /dev/null +++ b/examples/hello/examples/variance.md @@ -0,0 +1,67 @@ +# Variance Example + +The code for this example can be found in the [library file](../hello/hello.py) and [example](variance.py). + +## Creating a store + +As seen in the `iota` task, a store can be created from a context as, e.g. + +``` +output = user_context.create_store( + types.float32, + shape=(size,), + optimize_scalar=True, +) +``` + +At this point, the store may not be allocated or contain data, +but can still be passed to tasks as a valid output handle. + +## Elementwise task with aligned partitions + +Tasks are also created on a context: + +``` +task = user_context.create_auto_task(HelloOpCode.SQUARE) + +task.add_input(input) +task.add_output(output) +task.add_alignment(input, output) +task.execute() +``` + +An auto task indicates Legate should auto-partition based +on cost heuristics and partitioning constraints. +An input and output array are added. +The most critical step here, though, is the alignment of +the input and output. Since we want to do elementwise operations, +we need the input and output partitions to be aligned. +This expresses an auto-partitioning constraint. +Finally, the task is enqueued by calling its `execute` method. + +## Reduction (Summation) + +We similarly set up a task, but now add the output +as a reduction. + +``` +task = user_context.create_auto_task(HelloOpCode.SUM) + +task.add_input(input) +task.add_reduction(output, types.ReductionOp.ADD) +task.execute() +``` + +The output is a scalar, which means there is no partitioning +alignment constraint with input and output. + +## Using data from other Legate libraries + +Data structures from other libraries (e.g. cunumeric) +can be passed into functions from other Legate libraries, +even if the libraries are unaware of each other. +Legate provides a common interface for data structures +to provide a schema and access to its underlying stores. +This is shown in the `_get_legate_store` function via +the `__legate_data_interface__`. + diff --git a/examples/hello/examples/variance.py b/examples/hello/examples/variance.py new file mode 100644 index 000000000..a8272eec9 --- /dev/null +++ b/examples/hello/examples/variance.py @@ -0,0 +1,23 @@ +from typing import Any + +from hello import iota, square, sum, to_scalar + +from legate.core import Store + + +def mean_and_variance(a: Any, n: int) -> float: + a_sq: Store = square(a) # A 1-D array of shape (4,) + sum_sq: Store = sum(a_sq) # A scalar sum + sum_a: Store = sum(a) # A scalar sum + + # Extract scalar values from the Legate stores + mean_a: float = to_scalar(sum_a) / n + mean_sum_sq: float = to_scalar(sum_sq) / n + variance = mean_sum_sq - mean_a * mean_a + return mean_a, variance + + +# Example: Use a basic 1,2,3,4 array +n = 4 +a = iota(n) +print(mean_and_variance(a, n)) diff --git a/examples/hello/hello/__init__.py b/examples/hello/hello/__init__.py new file mode 100644 index 000000000..6e38a3cde --- /dev/null +++ b/examples/hello/hello/__init__.py @@ -0,0 +1,2 @@ +from .library import user_lib +from .hello import iota, print_hello, print_hellos, square, sum, to_scalar diff --git a/examples/hello/hello/hello.py b/examples/hello/hello/hello.py new file mode 100644 index 000000000..6548806b2 --- /dev/null +++ b/examples/hello/hello/hello.py @@ -0,0 +1,169 @@ +import struct +from enum import IntEnum +from typing import Any + +import numpy as np + +import legate.core.types as types +from legate.core import Rect, Store, get_legate_runtime + +from .library import user_context, user_lib + + +class HelloOpCode(IntEnum): + HELLO_WORLD = user_lib.cffi.HELLO_WORLD + SUM = user_lib.cffi.SUM + SQUARE = user_lib.cffi.SQUARE + IOTA = user_lib.cffi.IOTA + + +def print_hello(message: str) -> None: + """Create a Legate task launch to print a message + + Args: + message (str): The message to print + """ + task = user_context.create_auto_task(HelloOpCode.HELLO_WORLD) + task.add_scalar_arg(message, types.string) + task.execute() + + +def print_hellos(message: str, n: int) -> None: + """Create a Legate task launch to print a message n times, + using n replicas of the task + + Args: + message (str): The message to print + n (int): The number of times to print + """ + launch_domain = Rect(lo=[0], hi=[n]) + task = user_context.create_manual_task( + HelloOpCode.HELLO_WORLD, launch_domain=launch_domain + ) + task.add_scalar_arg(message, types.string) + task.execute() + + +def _get_legate_store(input: Any) -> Store: + """Extracts a Legate store from any object + implementing the legete data interface + + Args: + input (Any): The input object + + Returns: + Store: The extracted Legate store + """ + if isinstance(input, Store): + return input + data = input.__legate_data_interface__["data"] + field = next(iter(data)) + array = data[field] + _, store = array.stores() + return store + + +def to_scalar(input: Store) -> float: + """Extracts a Python scalar value from a Legate store + encapsulating a single scalar + + Args: + input (Store): The Legate store encapsulating a scalar + + Returns: + float: A Python scalar + """ + # This operation blocks until the data in the Store + # is available and correct + buf = input.storage.get_buffer(np.float32().itemsize) + result = np.frombuffer(buf, dtype=np.float32, count=1) + return float(result[0]) + + +def zero() -> Store: + """Creates a Legate store representing a single zero scalar + + Returns: + Store: A Legate store representing a scalar zero + """ + data = bytearray(4) + buf = struct.pack(f"{len(data)}s", data) + future = get_legate_runtime().create_future(buf, len(buf)) + return user_context.create_store( + types.float32, + shape=(1,), + storage=future, + optimize_scalar=True, + ) + + +def iota(size: int) -> Store: + """Enqueues a task that will generate a 1-D array + 1,2,...size. + + Args: + size (int): The number of elements to generate + + Returns: + Store: The Legate store that will hold the iota values + """ + output = user_context.create_store( + types.float32, + shape=(size,), + optimize_scalar=True, + ) + task = user_context.create_auto_task( + HelloOpCode.IOTA, + ) + task.add_output(output) + task.execute() + return output + + +def sum(input: Any) -> Store: + """Sums a 1-D array into a single scalar + + Args: + input (Any): A Legate store or any object implementing + the Legate data interface. + + Returns: + Store: A Legate store encapsulating the array sum + """ + input_store = _get_legate_store(input) + + task = user_context.create_auto_task(HelloOpCode.SUM) + + # zero-initialize the output for the summation + output = zero() + + task.add_input(input_store) + task.add_reduction(output, types.ReductionOp.ADD) + task.execute() + return output + + +def square(input: Any) -> Store: + """Computes the elementwise square of a 1-D array + + Args: + input (Any): A Legate store or any object implementing + the Legate data interface. + + Returns: + Store: A Legate store encapsulating a 1-D array + holding the elementwise square values + """ + input_store = _get_legate_store(input) + + output = user_context.create_store( + types.float32, shape=input_store.shape, optimize_scalar=True + ) + task = user_context.create_auto_task(HelloOpCode.SQUARE) + + task.add_input(input_store) + task.add_output(output) + task.add_alignment(input_store, output) + task.execute() + + return output diff --git a/examples/hello/install.sh b/examples/hello/install.sh new file mode 100755 index 000000000..b4d1f47d4 --- /dev/null +++ b/examples/hello/install.sh @@ -0,0 +1 @@ +python -m pip install . diff --git a/examples/hello/setup.py b/examples/hello/setup.py new file mode 100644 index 000000000..fc918c843 --- /dev/null +++ b/examples/hello/setup.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +# Copyright 2021-2022 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +from pathlib import Path + +from setuptools import find_packages +from skbuild import setup + +import legate.install_info as lg_install_info + +legate_dir = Path(lg_install_info.libpath).parent.as_posix() + +cmake_flags = [ + f"-Dlegate_core_ROOT:STRING={legate_dir}", +] + +os.environ["SKBUILD_CONFIGURE_OPTIONS"] = " ".join(cmake_flags) + + +setup( + name="Legate Hello", + version="0.1", + description="A Hello World for Legate", + author="NVIDIA Corporation", + license="Apache 2.0", + classifiers=[ + "Intended Audience :: Developers", + "Topic :: Database", + "Topic :: Scientific/Engineering", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + ], + packages=find_packages( + where=".", + include=["hello", "hello.*"], + ), + include_package_data=True, + zip_safe=False, +) diff --git a/examples/hello/src/CMakeLists.txt b/examples/hello/src/CMakeLists.txt new file mode 100644 index 000000000..dfe343722 --- /dev/null +++ b/examples/hello/src/CMakeLists.txt @@ -0,0 +1,22 @@ + +legate_cpp_library_template(hello TEMPLATE_SOURCES) + +add_library( + hello + hello_world.cc + hello_world.h + iota.cc + sum.cc + square.cc + ${TEMPLATE_SOURCES} +) + +target_include_directories(hello + PRIVATE + $ + INTERFACE + $ +) + +target_link_libraries(hello PRIVATE legate::core) + diff --git a/examples/hello/src/hello_cffi.h b/examples/hello/src/hello_cffi.h new file mode 100644 index 000000000..c9b8a2c33 --- /dev/null +++ b/examples/hello/src/hello_cffi.h @@ -0,0 +1,7 @@ +enum HelloOpCode { + _OP_CODE_BASE = 0, + HELLO_WORLD = 1, + SUM = 2, + SQUARE = 3, + IOTA = 4, +}; diff --git a/examples/hello/src/hello_world.cc b/examples/hello/src/hello_world.cc new file mode 100644 index 000000000..9cea64c42 --- /dev/null +++ b/examples/hello/src/hello_world.cc @@ -0,0 +1,25 @@ +#include "hello_world.h" +#include "legate_library.h" + +namespace hello { + +Legion::Logger logger("legate.hello"); + +class HelloWorldTask : public Task { +public: + static void cpu_variant(legate::TaskContext &context) { + std::string message = context.scalars()[0].value(); + std::cout << message << std::endl; + } +}; + +} // namespace hello + +namespace // unnamed +{ + +static void __attribute__((constructor)) register_tasks(void) { + hello::HelloWorldTask::register_variants(); +} + +} // namespace diff --git a/examples/hello/src/hello_world.h b/examples/hello/src/hello_world.h new file mode 100644 index 000000000..8b1c7fb8e --- /dev/null +++ b/examples/hello/src/hello_world.h @@ -0,0 +1,10 @@ +#pragma once + +#include "hello_cffi.h" +#include "legate_library.h" + +namespace hello { + +extern Legion::Logger logger; + +} \ No newline at end of file diff --git a/examples/hello/src/iota.cc b/examples/hello/src/iota.cc new file mode 100644 index 000000000..4f408008b --- /dev/null +++ b/examples/hello/src/iota.cc @@ -0,0 +1,33 @@ +#include "hello_world.h" +#include "legate_library.h" + +namespace hello { + +class IotaTask : public Task { +public: + static void cpu_variant(legate::TaskContext &context) { + + legate::Store &output = context.outputs()[0]; + legate::Rect<1> output_shape = output.shape<1>(); + auto out = output.write_accessor(); + + logger.info() << "Iota task [" << output_shape.lo << "," << output_shape.hi + << "]"; + + // i is a global index for the complete array + for (size_t i = output_shape.lo; i <= output_shape.hi; ++i) { + out[i] = i + 1; + } + } +}; + +} // namespace hello + +namespace // unnamed +{ + +static void __attribute__((constructor)) register_tasks(void) { + hello::IotaTask::register_variants(); +} + +} // namespace diff --git a/examples/hello/src/square.cc b/examples/hello/src/square.cc new file mode 100644 index 000000000..eb44365dc --- /dev/null +++ b/examples/hello/src/square.cc @@ -0,0 +1,44 @@ +#include "hello_world.h" +#include "legate_library.h" + +namespace hello { + +class SquareTask : public Task { +public: + static void cpu_variant(legate::TaskContext &context) { + legate::Store &output = context.outputs()[0]; + // Best-practice to validate the store types + assert(output.code() == FLOAT_LT); + assert(output.dim() == 1); + legate::Rect<1> output_shape = output.shape<1>(); + auto out = output.write_accessor(); + + legate::Store &input = context.inputs()[0]; + // Best-practice to validate the store types + assert(input.code() == FLOAT_LT); + assert(input.dim() == 1); + legate::Rect<1> input_shape = input.shape<1>(); // should be a 1-Dim array + auto in = input.read_accessor(); + + assert(input_shape == output_shape); + + logger.info() << "Elementwise square [" << output_shape.lo << "," + << output_shape.hi << "]"; + + // i is a global index for the complete array + for (size_t i = input_shape.lo; i <= input_shape.hi; ++i) { + out[i] = in[i] * in[i]; + } + } +}; + +} // namespace hello + +namespace // unnamed +{ + +static void __attribute__((constructor)) register_tasks(void) { + hello::SquareTask::register_variants(); +} + +} // namespace diff --git a/examples/hello/src/sum.cc b/examples/hello/src/sum.cc new file mode 100644 index 000000000..e736600f2 --- /dev/null +++ b/examples/hello/src/sum.cc @@ -0,0 +1,49 @@ +#include "hello_world.h" +#include "legate_library.h" + +namespace hello { + +class SumTask : public Task { +public: + static void cpu_variant(legate::TaskContext &context) { + legate::Store &input = context.inputs()[0]; + legate::Rect<1> input_shape = input.shape<1>(); // should be a 1-Dim array + auto in = input.read_accessor(); + + logger.info() << "Sum [" << input_shape.lo << "," << input_shape.hi << "]"; + + float total = 0; + // i is a global index for the complete array + for (size_t i = input_shape.lo; i <= input_shape.hi; ++i) { + total += in[i]; + } + + /** + The task launch as a whole will return a single value (Store of size 1) + to the caller. However, each point task gets a separate Store of the + same size as the result, to reduce into. This "local accumulator" will + be initialized by the runtime, and all we need to do is call .reduce() + to add our local contribution. After all point tasks return, the runtime + will make sure to combine all their buffers into the single final result. + */ + using Reduce = Legion::SumReduction; + legate::Store &output = context.reductions()[0]; + auto sum = output.reduce_accessor(); + // Best-practice is to validate types + assert(output.code() == FLOAT_LT); + assert(output.dim() == 1); + assert(output.shape<1>() == legate::Rect<1>(0, 0)); + sum.reduce(0, total); + } +}; + +} // namespace hello + +namespace // unnamed +{ + +static void __attribute__((constructor)) register_tasks(void) { + hello::SumTask::register_variants(); +} + +} // namespace diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index 1ad9d1919..499db234f 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -448,6 +448,8 @@ Imported Targets: ]=]) +file(READ ${CMAKE_SOURCE_DIR}/cmake/legate_helper_functions.cmake helper_functions) + string(JOIN "\n" code_string [=[ if(NOT TARGET legate::Thrust) @@ -464,6 +466,7 @@ if(Legion_NETWORKS) find_package(MPI REQUIRED COMPONENTS CXX) endif() ]=] +"${helper_functions}" ) if(DEFINED legate_core_cuda_stubs_path) @@ -479,7 +482,9 @@ rapids_export( GLOBAL_TARGETS core NAMESPACE legate:: DOCUMENTATION doc_string - FINAL_CODE_BLOCK code_string) + FINAL_CODE_BLOCK code_string + LANGUAGES ${ENABLED_LANGUAGES} +) # build export targets rapids_export( @@ -488,4 +493,6 @@ rapids_export( GLOBAL_TARGETS core NAMESPACE legate:: DOCUMENTATION doc_string - FINAL_CODE_BLOCK code_string) + FINAL_CODE_BLOCK code_string + LANGUAGES ${ENABLED_LANGUAES} +) diff --git a/pyproject.toml b/pyproject.toml index 181f16d26..c186fc785 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,6 +88,8 @@ strict_equality = true warn_unused_configs = true +exclude = ['tests/examples'] + [[tool.mypy.overrides]] # ignore certain auto-generated and utility files module = [ diff --git a/src/core/runtime/runtime.h b/src/core/runtime/runtime.h index 8a78be56c..a6143f44e 100644 --- a/src/core/runtime/runtime.h +++ b/src/core/runtime/runtime.h @@ -48,6 +48,7 @@ struct Core { * @brief Type signature for registration callbacks */ using RegistrationCallback = void (*)(); + /** * @brief Performs a registration callback. Libraries must perform * registration of tasks and other components through this function. From 21f1416c13db147d3808b75e3cc6d6ef7af84d35 Mon Sep 17 00:00:00 2001 From: Paul Taylor Date: Mon, 6 Mar 2023 11:30:26 -0800 Subject: [PATCH 54/57] Pin Legion to specific commit sha by default (#593) * pin legion to a specific commit * ignore cached legate_core_LEGION_REPOSITORY value and revert to default if unset * update rapids-cmake and legate_core package versions * define legion branch and repository in versions.json * fix typo * clarify comment * update Legion hash * parse leading zeroes from version legion version components --- CMakeLists.txt | 4 +- cmake/thirdparty/get_legion.cmake | 69 ++++++++++++++++++++++++------- cmake/versions.json | 12 ++++-- install.py | 6 +-- 4 files changed, 67 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd9522297..62f4f3cba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ endif() # - Download and initialize RAPIDS CMake helpers ----------------------------- if(NOT EXISTS ${CMAKE_BINARY_DIR}/RAPIDS.cmake) - file(DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-22.08/RAPIDS.cmake + file(DOWNLOAD https://raw.githubusercontent.com/rapidsai/rapids-cmake/branch-23.02/RAPIDS.cmake ${CMAKE_BINARY_DIR}/RAPIDS.cmake) endif() include(${CMAKE_BINARY_DIR}/RAPIDS.cmake) @@ -72,7 +72,7 @@ include(rapids-cuda) include(rapids-export) include(rapids-find) -set(legate_core_version 22.12.00) +set(legate_core_version 23.03.00) # For now we want the optimization flags to match on both normal make and cmake # builds so we override the cmake defaults here for release, this changes diff --git a/cmake/thirdparty/get_legion.cmake b/cmake/thirdparty/get_legion.cmake index f7b1bb5de..71ce33fb1 100644 --- a/cmake/thirdparty/get_legion.cmake +++ b/cmake/thirdparty/get_legion.cmake @@ -1,5 +1,5 @@ #============================================================================= -# Copyright 2022 NVIDIA Corporation +# Copyright 2022-2023 NVIDIA Corporation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,6 +14,8 @@ # limitations under the License. #============================================================================= +include_guard(GLOBAL) + function(find_or_configure_legion) set(oneValueArgs VERSION REPOSITORY BRANCH EXCLUDE_FROM_ALL) cmake_parse_arguments(PKG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) @@ -21,6 +23,22 @@ function(find_or_configure_legion) include("${rapids-cmake-dir}/export/detail/parse_version.cmake") rapids_export_parse_version(${PKG_VERSION} Legion PKG_VERSION) + string(REGEX REPLACE "^0([0-9]+)?$" "\\1" Legion_major_version "${Legion_major_version}") + string(REGEX REPLACE "^0([0-9]+)?$" "\\1" Legion_minor_version "${Legion_minor_version}") + string(REGEX REPLACE "^0([0-9]+)?$" "\\1" Legion_patch_version "${Legion_patch_version}") + + include("${rapids-cmake-dir}/cpm/detail/package_details.cmake") + rapids_cpm_package_details(Legion version git_repo git_branch shallow exclude_from_all) + + set(version "${Legion_major_version}.${Legion_minor_version}.${Legion_patch_version}") + set(exclude_from_all ${PKG_EXCLUDE_FROM_ALL}) + if(PKG_BRANCH) + set(git_branch "${PKG_BRANCH}") + endif() + if(PKG_REPOSITORY) + set(git_repo "${PKG_REPOSITORY}") + endif() + set(Legion_CUDA_ARCH "") if(Legion_USE_CUDA) set(Legion_CUDA_ARCH ${CMAKE_CUDA_ARCHITECTURES}) @@ -47,14 +65,15 @@ function(find_or_configure_legion) if(Legion_DIR OR Legion_ROOT) set(_find_mode REQUIRED) endif() - rapids_find_package(Legion ${PKG_VERSION} EXACT CONFIG ${_find_mode} ${FIND_PKG_ARGS}) + rapids_find_package(Legion ${version} EXACT CONFIG ${_find_mode} ${FIND_PKG_ARGS}) endif() if(Legion_FOUND) - message(STATUS "CPM: using local package Legion@${PKG_VERSION}") + message(STATUS "CPM: using local package Legion@${version}") else() + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/cpm_helpers.cmake) - get_cpm_git_args(legion_cpm_git_args REPOSITORY ${PKG_REPOSITORY} BRANCH ${PKG_BRANCH}) + get_cpm_git_args(legion_cpm_git_args REPOSITORY ${git_repo} BRANCH ${git_branch}) if(NOT DEFINED Legion_PYTHON_EXTRA_INSTALL_ARGS) set(Legion_PYTHON_EXTRA_INSTALL_ARGS "--single-version-externally-managed --root=/") endif() @@ -149,14 +168,19 @@ function(find_or_configure_legion) set(Legion_CUDA_ARCH ${Legion_CUDA_ARCH} CACHE STRING "Comma-separated list of CUDA architectures to build for (e.g. 60,70)" FORCE) - rapids_cpm_find(Legion ${PKG_VERSION} ${FIND_PKG_ARGS} + message(VERBOSE "legate.core: Legion version: ${version}") + message(VERBOSE "legate.core: Legion git_repo: ${git_repo}") + message(VERBOSE "legate.core: Legion git_branch: ${git_branch}") + message(VERBOSE "legate.core: Legion exclude_from_all: ${exclude_from_all}") + + rapids_cpm_find(Legion ${version} ${FIND_PKG_ARGS} CPM_ARGS ${legion_cpm_git_args} FIND_PACKAGE_ARGUMENTS EXACT - EXCLUDE_FROM_ALL ${PKG_EXCLUDE_FROM_ALL} + EXCLUDE_FROM_ALL ${exclude_from_all} OPTIONS ${_legion_cuda_options} "CMAKE_CXX_STANDARD ${_cxx_std}" - "Legion_VERSION ${PKG_VERSION}" + "Legion_VERSION ${version}" "Legion_BUILD_BINDINGS ON" "Legion_BUILD_APPS OFF" "Legion_BUILD_TESTS OFF" @@ -165,6 +189,14 @@ function(find_or_configure_legion) "Legion_REDOP_COMPLEX ON" "Legion_GPU_REDUCTIONS OFF" "Legion_BUILD_RUST_PROFILER ON" + "Legion_SPY ${Legion_SPY}" + "Legion_USE_LLVM ${Legion_USE_LLVM}" + "Legion_USE_HDF5 ${Legion_USE_HDF5}" + "Legion_USE_CUDA ${Legion_USE_CUDA}" + "Legion_NETWORKS ${Legion_NETWORKS}" + "Legion_USE_OpenMP ${Legion_USE_OpenMP}" + "Legion_USE_Python ${Legion_USE_Python}" + "Legion_BOUNDS_CHECKS ${Legion_BOUNDS_CHECKS}" ) endif() @@ -180,16 +212,23 @@ function(find_or_configure_legion) endfunction() -if(NOT DEFINED legate_core_LEGION_BRANCH) - set(legate_core_LEGION_BRANCH control_replication) -endif() - -if(NOT DEFINED legate_core_LEGION_REPOSITORY) - set(legate_core_LEGION_REPOSITORY https://gitlab.com/StanfordLegion/legion.git) -endif() +foreach(_var IN ITEMS "legate_core_LEGION_VERSION" + "legate_core_LEGION_BRANCH" + "legate_core_LEGION_REPOSITORY" + "legate_core_EXCLUDE_LEGION_FROM_ALL") + if(DEFINED ${_var}) + # Create a legate_core_LEGION_BRANCH variable in the current scope either from the existing + # current-scope variable, or the cache variable. + set(${_var} "${${_var}}") + # Remove legate_core_LEGION_BRANCH from the CMakeCache.txt. This ensures reconfiguring the same + # build dir without passing `-Dlegate_core_LEGION_BRANCH=` reverts to the value in versions.json + # instead of reusing the previous `-Dlegate_core_LEGION_BRANCH=` value. + unset(${_var} CACHE) + endif() +endforeach() if(NOT DEFINED legate_core_LEGION_VERSION) - set(legate_core_LEGION_VERSION "${legate_core_VERSION_MAJOR}.${legate_core_VERSION_MINOR}.0") + set(legate_core_LEGION_VERSION "${legate_core_VERSION}") endif() find_or_configure_legion(VERSION ${legate_core_LEGION_VERSION} diff --git a/cmake/versions.json b/cmake/versions.json index aae9a7ffe..c5bf2d31a 100644 --- a/cmake/versions.json +++ b/cmake/versions.json @@ -1,9 +1,13 @@ { "packages" : { - "Thrust" : { - "version" : "1.17.0.0", - "git_url" : "https://github.com/NVIDIA/thrust.git", - "git_tag" : "1.17.0" + "Thrust" : { + "version" : "1.17.0.0", + "git_url" : "https://github.com/NVIDIA/thrust.git", + "git_tag" : "1.17.0" + }, + "Legion": { + "git_url" : "https://gitlab.com/StanfordLegion/legion.git", + "git_tag" : "e1f1ef61e29c3160419d0cd528950b2d565c2a0d" } } } diff --git a/install.py b/install.py index 57bcc692b..4c94b3b32 100755 --- a/install.py +++ b/install.py @@ -453,7 +453,7 @@ def validate_path(path): if conduit: cmake_flags += [f"-DGASNet_CONDUIT={conduit}"] if cuda_dir: - cmake_flags += [f"-DCUDA_TOOLKIT_ROOT_DIR={cuda_dir}"] + cmake_flags += [f"-DCUDAToolkit_ROOT={cuda_dir}"] if thrust_dir: cmake_flags += [f"-DThrust_ROOT={thrust_dir}"] if legion_dir: @@ -750,14 +750,14 @@ def driver(): "--legion-url", dest="legion_url", required=False, - default="https://gitlab.com/StanfordLegion/legion.git", + default=None, help="Legion git URL to build Legate with.", ) parser.add_argument( "--legion-branch", dest="legion_branch", required=False, - default="control_replication", + default=None, help="Legion branch to build Legate with.", ) args, unknown = parser.parse_known_args() From 918b4a2d7c1c67a228d7afc8de3dc66877855394 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 6 Mar 2023 13:54:28 -0800 Subject: [PATCH 55/57] Small fixes to README (#606) * Remove figure that used old "legate.numpy" name * Update link to Hello World Library --- README.md | 11 ++++------- docs/figures/vision.png | Bin 877228 -> 0 bytes 2 files changed, 4 insertions(+), 7 deletions(-) delete mode 100644 docs/figures/vision.png diff --git a/README.md b/README.md index 325e5f88f..576222033 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,7 @@ by running the same code that runs on a desktop or a laptop at scale. Using this technology, computational and data scientists can develop and test programs on moderately sized data sets on local machines and then immediately scale up to larger data sets deployed on many nodes in the cloud or on a -supercomputer without any code modifications. In visual terms: - -drawing +supercomputer without any code modifications. The Legate project is built upon two foundational principles: @@ -473,7 +471,6 @@ documentation](https://nv-legate.github.io/legate.core). We recommend starting by experimenting with at least one Legate application library to test out performance and see how Legate works. If you are interested in building your own Legate application library, we recommend that you -investigate our [Legate Hello World application -library](https://github.com/nv-legate/legate.hello) that provides a small -example of how to get started developing your own drop-in replacement library -on top of Legion using the Legate Core library. +investigate our [Legate Hello World application library](examples/hello) that +provides a small example of how to get started developing your own drop-in +replacement library on top of Legion using the Legate Core library. diff --git a/docs/figures/vision.png b/docs/figures/vision.png deleted file mode 100644 index 6cd072bacaf4968549ce22f9629dc5a6683c787c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 877228 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

a}R@bqgo1X%k$W56;t( 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 z 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

XKM*MqAmMP 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 ya^>*M`xE&&+l1DPnYI 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

    *NwTRr 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�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%0A`eH4#O|0QpN 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

    ebP@6WIz|I=Z{wtg4^4tNp*{fC$(P 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 z zh7|aM%F_s;vaXt%f*TG0OI6#T_q$3+$@a5gh{0Q!WCCJLm1ed8a0^af9KLqDDj=|B z*zjb^7DW3RqXtnNxl!2N$y}|X?J`i<&X)JsKBsg#GBX`1+D?Z(1Pjlx;hkc2+N5h~ z@jTPUJeS>n)y!=_WCzw2^ltZzxqdGob4U3MpL+fD$B$*am_^8wRtofKAI?nrLaWIA zIQ+ZJ2bJ{t{&7cJj`sV6Gk?8i$9W!J;E_EuxBQAvGM(`|C7Pz&#j6(rLF~YBn0>Rp z_vuC`0F0vB^WbB6pyXJ44w>NEer0fWP`4LM<*~VSN{=#*jk1eLd4JX(e>}z46;~O& z`62FnoD_dc*Beu|wA%HF!MZ^t@2%J-T@GLtx26?Ph_Hytbb%UUnmGu&UF_V2!rl*u zJJ8|H-YrPwW@Dd=!zFgI_LH4}xlF4S*<8pkzx@cGAA5}mHi*p#|6Ue7+Tv5I+xd@>6N^77zC8Xg5)nB=|)MU{5=Ax z9>!4bbkj>Jf~QN6bg-q!c4StGtHs1Ee@|+YW9m6&p*~Vi29{tp^s2 z+=_=r!GfsfuA3$cA4JVy2e~>o+IMK`8zIN<5M{powm&=6F&n)o|Ke86La~DyyM;vgA z6U&Pr=hr2N@;`lPPWWw|9y)}I(~=nE^Uo;f75@d|f6WD){1!deHVf>4%ocBFVBeB| zxj{jCRsA|Ik~=TEPR)$;kDe_aqmL!0rPJX4LdsXO+(<>X%zE`r31AE>aVYx&0Yz9u zQZ85rjZMgx{*5B=fl=(fuh)P6a_$V1YtZ#wJrxQ+I$r$1B1G06ctNDE7H|k95FR)L zH(XJ(LHVkr6rH(SSnkF$VO_6rKk^Lq@(gRJuiOQMvwJQTPc!#L-M&$t;3+H1yX&eO zR9K*CUXfA6Ua}FY4dtb(Y)1QljZE{@*H}qPShVL+_`&9+^yvo6z`6bs!B=99dFvoP zC((ff@dWrG{Nl5!-QwZSXBgmYr$<`O*&!8007eXTHwh~)9_M@NfYtG>Zs7LdYW&*j z#SJ^>@_-war2dNa!HO^~4WfW=QhxDDB8=l#qeKD_S1xD8{X!r-oo9+^-B*GBzO$eN z3G9zaOA2=}Ty;BT5CkQ|5qeMrQgmohhx1nzC*?cVi3xPc6^l(BAf8KnfeCznLj!QG zR)KQS`dP? zaCJJ}eottj&b5{yJbpTA3K{5sIzIOo%P4bCub(c-^`uIWPr|t4LfsAgMc8687`yJc zjY3e?C$i0&8mtDz>X?cmnzpDfw}rV44)hakv7jf+lseh(@Gw`ki_3Pvm~hi4`@2Wk zn?ZF8pV3yGlpW{aZ}xB9&siZhb`tM6E@=>1MN8Z;mmeL%Utms z{4>33J9X{ZYr+`FHE}xkDld<+v_ri_j_o=2A^zJ&*lP(zXFNFfb{G&LG}hU=V+FsI zk^tgL+@2Q@C@%1Ks`ft|%eqGh-2Qq!{QYM;&Sj*V{6D9lM*D30{}l=6NBw$%+}~ED z#bm>EQT@+?5Y!O0kKlyP=c3w`Ru_j~0un@lM|Zzx6EQ^hWESfkUT&|g5B4kCa$JX6 z5^jb^WW|UL(1Z}DBUj}Ed&hqDe_$?oD{md4P?|DYrX`~x3ugKn^$AZ=HyKzyfD$Fx zs;DOZE?7q86j&66>+a^D<42>RzCTYzbb0&qz|FFnfWtf+&wbVYviJA?9$mdxb>+=z zS3)SEPPux$0Mp?xu|Weux%rtU?9E|MR&q(~dY9i|Gi7Ko7ZMI?9YOQ(&R4Jt#^5M; zXDY}qT-D(9T}@oKYH2uGLu~hyd3FnGR8m;Uv4fsm0DS55$g5E}V$Q_^u#Cazi*)$& z9^6MWi?^eVq=068)Go|9QX}+$B3AhQV;(gqqo8&0`%k_kCb{)D=?&+;zv{9zJ}-%+ zg#Og|ejVcCZ%~+vHJ&lI&GY^8g+VOd#MEp4`^)WA-oxqHmD*3R6W85%3hPu9B!=DF z_|Nfb3S>TcTRqo?wIre)y-BHdmXC&MJH1eLcvb|@tMSvndQi58iZ+-j>iNXG*ebmi z*r9VpdSK*dkvJ8?BaNaMX_WjC1dCF?Z{6SIa+!IVHk`OG!(4soaYz+#{gHc;Gtb49 zi`4o_xXM2KR@x9G3#s*QpnOdr08|d^CCsl%JZ;-UP6lO)Wsqt*L@oZcU#Yix zspZ20U>QVBW=oV$%}kRKz%(Z3-wUr;1w?eaTe}b<^T`0;>sRlMos|`ZyYiMMVfi{c z9dUe8=!=#^`_M)e4?R=7A{zCzREt)rQ1}u8%Jwj`HH#H!*tf0e_vzEO7F-|L+@ITb zH>g3>De5E`I81!vna~8PET-AaHL?v^m6!Nc(mf#EI3llG*l?@jW1X(SMg_P9S+uzZ%o zwt(t(+?%rVnpx*p*{28Stu7TWoa0-K$&%>&=fpTf1gdwI)?eC; z6}=}T7Ley1QdpUo=cfSQH*|Da_;$KS3TOtwdW5(VLg8K+}qxl@>+XX!vzX}3kP`=1ELFg#S-nq>g>h& zOzJ3fMRoaj#a%qQrSE3wO5co;!qboQwMr?9qM|mXW>I_7+C=Ofp|#bBt!nSRg4on3v3EkOsx4wCHn;2gT=(@m_wRdu z|9PEv-X}RH|2)s@`FuPdV`P;ssiPv}x(^G~RIYMb zoC?$z7Cm+0qwGChu~83#DfO2u9zj_*Xj#?hM%Iufg0m+x5rDLk@=1F~hv{Kt2x#+R zhj|trlO##1PMY7@42uj?C40{lvXZj;VTqNY;sJd^c{wymhhaFd`@ty*c@l6_dbm91 zQu>E8EY1G!h`RH9wafTS{6?D73%Bx(X_uAKd~H~@0r$sw{oIR&xp;a<^x3x&@5K*% zuxfJD9uhMba-gC;CS39c+9tuZL!!`9iS42dvRY7|N7V>+*rkL_tr6z}L3 zo5x1JkSctbo2CObvbljM^Lj$8msceW`h*+TC)XFG^c5;CnEd2MT9zdVWg?ntdHq)h z;O``2705D%*(Z(L8*FpSv{-08`djZJb3I*>zU~U;%iSMedfz55@-9#jHz@v*Yr$A` z)QoNeQl~ddwAiu=5I^}te0&!(TuHY>PDqzuI^aq3vj0fzW#Z*3H5sv@s zV)q-PQb=w$xXgSoDeCQ(B`%NKqeat`%;YjxH)ETw{E;KU)PS`PXp`yZ=kOT|F*r7g zcs9*pc6hD8c&^1pbfUQK*re88CUksFo37gHK4LgEjwVW;L68U8=)Lk0NyMthNVFb< zta(;c5IC&IORUp*-$U0K_a>;(?|F3v6I8KF^x`88DDZ1RJj-xH$>bcpVH+-HI3OEo zG8#;|4THKXgB__-of1pkPDaM`#u z<>E}AnP}dsRKggZ<%sr#tB+S>3bn=zB3e$vd=AJYWlI1CIEdy$VT zHp|`8??Z}gS6wm9W69t~F?h*z(nkl(ZE?8-$)3c@)xt;M5KhOH>sYs{ibsZ1V3@U4 z;DgpUb;#6kIh!4m`DY1aqOWqTYz~7C+zd*@>HYY{-g8{ zE1za`227Cm{P2)L%D!>zd4w?PtHBGltD7~*+m0(M8eiFs@(>Q zG`GwA_p;gPI>2%Ke=pTLFvm#`Oud64GO~>Ro-k=Q1wQQH^j9vM_fcU5iO2)S13z(& z6*5D;w)h!*XgxQbplTQ$aj0K9x2_v`BT)#kIx_7~e%@jmwg&!`}ZD2os4c#;NHYb+*Go1)WAWw4fv@6Sz=Cag~Mm<1+-gXmHlH5hYbM5 zli0T{H%%to6V!GS<4x&0&r{BT0)WlzX52uAfw8MB3U67s0EV*-%#y1%A!VdcwpwL!R5qw{=uJt=`wSIW*Y0WLlASY-=KPF{0wtpynd?djBf;@q6r&QNNj_s&N2=4&AU2 zq9{Am`6y_`pzThXx`InYNv+Ed{RxmUdsazGy>^aT#cGD#;#m_RAFq56J5U@?d|+45 z)(56BA5*Icw1Aw1l*^MEfLKnS@TcoHa+*87Qva3a#k(>^dQa}Csx5Z+SbDos&+{ml z+mFZYn?;0psT@`Q{kV$$qI(rdHAV;HiV|{9FP}gv<6c`QXUljb1*+8Ne)b1m_&H>a zq;68NN=S;j0-qhTwlj;PDF_>k55m#a4o=ZsvwHzh)+mIp`sdd{) zC3QXh86k0qvwel2Edn$1)ILLiBff#=>~Rs zljcQkK_12uBP_!I{ZNd_=brOpvJVcmJZ0m+E3+?-SA~v-jVJ^CpeNr09&J7^MXEyO!9@%g0Oy~`rsDzi(r$W-yE zl8xd1h@#vPGnua4ToT|WF%+pLW`&I*5(ymbq~<@h(xRU|!|$T^`U|%|&&VD9O7CYl zZ;a5{DJy3v2Z=Bs2FHJ<9GRr*WoQF79&F|b)^jU}{mR|^!oIxoVCn6P1srYoLG<%w z@5!Rp1J#}EBr`%mlhOlK|C1t?>jqlH>zL9eVJRLhv{_><>~%9&2v_N4(-OKefbBi) zp)0NJ_T10C$;4w|cQ!jR7)oRMRO1;&-qJy=>v+5fYcEOfczk8DVJV%7(eeOkGCCM5OI=fm~U8H4(PfA;}yR&&$0kl zDexipjMb>84LLro5jLw5Eu3yV$g5wVGI2I2H7jS#cWm*qkdNr+F`2H58dAv=&6^92 z)?;+|_T866o5~!z?kzd`dad8EArg8sT4LPAf4HlXwBFf8R6kQBcZDo`Y|kN8QYRzz z!<{eoo{`9AK5Zu9eRu>GRp=&Twd7izYAZiBt+qR4fv?b-3=vqo^X>hSXU%e7M5_Bz8_qClKq)hqAfkDw@xJsKAL3Xzd0 zB_wwih0CXs%Rg@56gqw?!LGq!txy}`nsORe^HL#rT(I2|w^AZ9DqZ4n=^J|tgik%t zKXYnsI_-&_$*MMcGbZhAKVabTc=?gJTp;hpVlN^sL_;X$RXAqKnCnobn8v48u793% ze&)k%by>_*Y&pR!Qi{uyf@>h4ox5n}*>XAq!I_%m=`1hXMy)*^ZusUaAC30j{YE>9!7DnZCY?mMQ?F ze$vQW28AeR;{&@|^U}?`aI{bVGdi`Ijy-2lo62d$a>qcNEKD;Bq=^*(Uy>ZA{J%Gw zfAK#nxeJQmi1t&era95W|F4ggY#AV z7g{i{5K}TZp3G%Yf{2=>S(}F~TAO3S_4BNZ<)cJg;+Sw`9ZhmaySq-`0~m{*G9o#Y zBT6G$(}VohOGjq+1L~*`C*xl+e~(%T1SSg|sb=278q2S!BR%KtKB3CJFm_KE3-S3? z;8bm*s&pGs&9wpW7gEa~M#gUC6{&K41=taaI(~-mQ zwWmIv1k&$`AL_1s-(>!CxbfjY(oe&Y;mbHsKVE^HlGh?OYxrd|fAWWipXs?G+A=KU zGPDvC6H620JAOpO;vHhG0nhD*=1)t?tw{C6=W3OJ59bHt`y^MgUDl zT1cJA4=Zg|p(eSzV@{K+!+(GpK1Ni#>G%9P&m}x1+UoF=zu0Pu%c(r=KWrYwQ36Eh zc{Xx|0uJ-K#%#9FqgsH-uFJpPzAt#~$W9w#$isY75_=sD1zQk`Q4bxSvUDC&E4qDn zdMdxmM@nc{A?O&`QuXn?$i!}*N>rzmH0Q7}Z2PG6_srP%fXU~@XMwThr7T>t*@C~H zVy4ud-cr?uRRR35B|_=FTnJbi zZ}%gu#X)9SoO@e-i<^xaa!O-SlT0)P2q|>Zc9Os)PFsj9TV`gq24-8hC86r#&)@lp zp;-=Q6aX&Vry;TxdZONwKlgLt)P4y3Y^g`pbF_2HtXUm?_nTmzOjO~Nr*e{F<+c~* zGsopW6?e=#eB~bh55H0Em4;Tw|F{7ewIg{RbIh_HvHXzmyvBMffd-j_T*Q*aDGK7yd`9?1LF`lFm9Ge6ZSc=ud68JxydUU-0e3ffCH4o^+0NmaN_h1~5c} z^6ni!NqwXMh>U`s-6FH?l@OD7Xt^BLrRb{GOEYwN1N)zs}14%BM) zP^y@vxRkxacV`v1lO)VhA%GWmvhycMj+8!fv}4Fq#Jv^`C!vbvnqNPfpZR@46AFWw z9)@4q?XqYYm-F4@2e0B#+e3!+Vo(xC(pUr&0m=5a2u=3}4Q{`wx%7I?Cb4v`1HPvA zk*GvKVWlyH%hQJgHoG_&7tp>MaTC0-Yl~IcKErX*%50j!3(B{wVU&n`Gru3g29==AEKzJ-v4o4><{nAm+J7 z)`tht+A)n0#524c#gY2D8nF`DWuBpWTq63dRQ-^Bc?5SQS^KCYpzjVYU3Jr*o5W#q#JH zkVC$&=K7Y*qH*HZSfd^D6$!|aO055nU4wZe=Kdah~$ zJX(SXyu)nIq;kHUzn@i2oK>{oR(f?<8i$K)<52gumdqOL?b&5 zB2UKZeN?%RfT@4!Qnxb1g6Mcmg}^IR*v~4gHTm-Fff>t;k7FKvEF{XY90FLu8ylBm zPtP2@Kl8G_Uy$p{My;mw$jC`viYb(Hxhh4W_wpDoFcMnUOSilK&fI;W_3GAqn){2w z?iW#GxiAjx7}4;8myMn=S4TUt!!|yT`pp@-P^`%;?%sqlEBcac9%991@xm(e1Sg^e zZOvWBx6Lv{PTQc=-qQ%9_gbv6@<>I;4Avf6P0{43AK<-cwL5o3r$ynF5bOsOl+>7^ zm3XA5!gRj+MPT<+^B5`CvZYPGLYaOaw~%8?o{7H9&~6{aO8H1r+F!}0ZI+41&by>W zo~a70QLQG&iq-?g42kL_E$JB7--VZBdB8RP%La4biT4X6|j2D#P zX_m5BErD3zh3X^fqiGUh(>I9RqX*tS}kD<$+ZNa zt2pKOlFtu+G1@B@MiH6z9YNE%+mdV&v72|j0iEGzj227An^r{^g%N0C@M+0^dLgQVSpJ{ z`qA8YrhCiRKG*_9>t8p#y6imIdS(aXHcy5dnWou(9EXbPoJQAHls_+8)$_*bKTB1j zvcI+f5tJH@^grv}svl!Q$x5wUu(@QdJ#Z-`HCYXA6Me)1QXRy%TdH9<{?lhNF3+_; z_`gUj|3_iw7gK}^7L=tJRB|W^a#^}Z8t2OAJF-9I zR5pE>|O6K zAX#3TvG<4ZY=k?zH>p=j3vU(xQO8s9rMCp#pcPddzs~i{gTHD$ZIrhP{Ij9^WZ<~# zOSZ6PCc*>$ZgT__@f6RI4o2~^FS(0*GMYJp?@g5oxb(Hx^&u7{+7mm zX~wXzcsM_CDP5SM%j;up4A_d5IOocoALm)b>{{ME5vZwz;6B{!SklNVSo4|&XN?=* zO!BQ#>}VqC;VWmoLm~91tkoK~*TO#!wC2I$z$(0Dje4HeL7(0J9@lsu zT+QKQZd*4BG;nX_Nt!ZUWFK2d2nCRnQ^tgO%*#6uY>TeT1$Ju^HvcK4l%Xja$0>xr3T@?JLOD=1Yz7NUs z=tC~J4WB&WUDP(N-x}jZ8rYC@1&EZKROX=^St=rQ&ThL+}BdFG=@aGSwOUL7dB0$OHQFaE&BFhg%M_K`qof6vy~ z2h)7lP2hKK@m{!)kmwI6!MwJRQ!YQ^MqV7>Z9=QM{b9T>FFevbxPhV1Lsu8gD#VB!&F89SkF z<-;A(w9(`YU_O!gP!m~{*i`0e^gk)Jl$RydD$ZC5=h;BXqhQdck^^?sV-)MD*^u^V zZ7g|vh3@Kxp3suv3fPQ+WQ9YZS`Om5yd`nBaL3}=U$^IM${5ezMU zzX4W;Ka&k!ka<`(ZxiOE!lq>mO+OoFo~_On??!ME>i3i1k5ij|aXL(?06WUjALMJ| zQ&G-Rwqa5XIo(CxV(d?GKWd72leN2eT$*tys_pxO;w)=$9X8ROlgw~2;!D}}Z3w^y zc&;|M1CcQq^+Ef5gctXg?fH;!dj_MQcE#eOhS|5OBOaj!Wn7e0UnNAv*!1ScR`SI` z70o1GP8VF+syw2H>HEx3M8r2@@Q9!8mZiGUuSI>7&lOIGdhOrHJvTGjxOWnPOFV59 zu3A#Ce&m|#64jY`^jmnP?Kep)h480Phrx6hcHa;g&0{D&o$wg=A}7U#%|#Wbn|4ln zI4S+8QE6HcHI+SVmQK_)04T~eMFds%ALTi!jaTkQy@=0D3e_NLbozUheCPB%Ua|W) z3Qe*yYhP!L8T-KTnsr^^`RF^B(^mcBT{EGz`Adq!$%Jz_t^KPJJCuz+kVqnEo{R9cI+1 zOj~WN@9=RnnoRIhID-L%z%qt*m22RoKn!x#5MbD13k5OEGG6CfW6c@;Ui2jVgT7=2 z_&5J=glN_avY4ru-N6EVI@#3QL8OGVRZ0N`cQ)^65V2B+X+QY(AcrWAmheg3Q1Jj) zsY%-G)%9+)V5tsFc8bX5Gv9ON*Q7H6fNXX`nS?lYr39B4!xkb!(Yx>btdyswO5$x1 z560Ny{5s_nUSCxNki=jId++AwMR`sgU&={dbd=QP(9G=XQsK9**Y6uv9x#=-H9Z^1 zA6jRJ8w{71B*U{VvFqHa?Uwj#Q#{5*KF;x>`2%&u;@v=YfRG@oNQJ1l+L|p$I}!d` zcY$C73$-T8uF9WSlaxIs;_K;jT$5?PLBd%d%HobLRisNC;` z$MLMFc(>e__!v_COs?J6e}DtMu3`&S~Cw-bY}PTt%Z=IsA_w*R$K;P$y( zZk>u;@Jycy@L8x1Nc@Y4Tp0}j8Ch$UUi&c_2sK!bJ+Fn+F9mm$IZE+X{!V6g=*T3o{FMrvT@ zmZsU#48Y0wW8Cxa?pFvdml|-v=))aMF6LxRf>n960m}o~VjleaK3-!ZVL!ylE>E8@ zT~{O%AlF!+w1|bhtNhuKXH)g7-=k0C!uS9@6?i%yr27$I|d)B%_7qY*a= z*SfZCB)Bd^c+=OIr`!m5zqqnQq}s*ZEW+MyfCbTRz)xZFcw&p z+^O;XEAh=}Ff05WkuWU%JwgIDG=+g1x7kvK_QIQ|yxtBh9l@Yt|IBuN9}0L+PCTXF zzwbQ0Z_lT3&FFV^eXES~+Ml~Zhs%&B*~7`{b7k9E$$;eL(Zm_)boe?2d7G)%pUMk$ zIxHj?eC{!K9_~L8opI?ppE`rwy?RNvcmbL{Su@2b9W5qOWx(pMR{ZB%A#aX+LXO+^ zL6^CeO(zNSr@{X9T&I5;E`+Xdp3`{n?Mp`gqfGDKh7QkzsXhu*A2o2h?sXg8;_j*R z)nCV};2rE^Na}HF;o``1h~$1|>j~*LZ|mMMHaKwBxKDI{DV+ z#yej69OJQBLzVuUrke}@?YI3t{b`SFzrt05uVUpHs?*cyuN_xvfG2-R1Fk|5udfI_ z@u3a>U{C&H``zt(4N>2#SKImOVZkTX9=i(}+-s#w-qf-+Xb+xk^lzf%$XBXNIo)+0 z>kHzk6wJJgdevp+UUsv{VExnbyR&FCT%OT)G*^xCbb3b#UcyBu_0%5ecYnPVOyJ?= zwxWB1|8rjF!0F1btNgUQ6Ro}@n+VrxM898d^jR%YX#$EhZvDWxM11*@XrWV@-+rh< z+);p}mSd?PCV4;Gw_lAdHGT2&%sm&2w!?wFF(r|b)w$A^-VERmDjpSt+?Z|=Op%XN`>BQ!6ZIPn^!2rGW@qNplf|=hfAE{Tk-)Zh_=8QiXR)-FnrdlB5^s?(yX_M% zhXI#jkMgzbJsX=Np%hhLi5pjF*E7fG{k9Qmeq+gS~eoT zX=YZ@wchtmv{4t3kTT6MBzO{TmW(3xmsxV;P&JwmJ>4K6r)?z*2iZyDi>Ze0KSdSq*&G;rMf~i+^?@LDHV%$DxU(0jp(YB`U3t z{(KZ0+61w0lWf#XAaXWpn-y4g|Lvcbbk_%JGuODqYf^0e)zxDCP&u)7cav0GvA+M+ z-?m@S?byIe@l;z$X{(&U@WL?!>fxpNOUs=kF$JHiiv4%O1LxTp!dD(gm+p?)y^D#S zAvp${(!wzIUUs-%g)c*hL2k|FWO&cTO;P(~tDS3tKj&TUM2!{77mFJib8h1g9jCW4 z+{ADr=)I+p+12_hfz-9*w{3H4^>|<7&;BNn_S!dye1ZI(sf9d$B-|9t)9xyMa{D(1+E}!i>SE4Fhb$oQ6#|i5+D}4? zA7Z!?rkg(r0JR(>yL+The>Sn}lNw|hXTOxXm^dwl6=wL3k4U`m{IISP{At&D($Ux#Ljuq+dNU0U41S271L=X&f>u?3 z2@m%w-gD0Mm##y#fnA(Cc{oA2i7U z>1G5)m|eWulG<^DFHYReg~0c3;> z-Nyu8XdR9>Xwx@Tg{Rl^>5ANNPwdq!pQ9VU7NBHjrdD`Tu^LvMo-Ka9P2u5fZKlgB zVRqefy}x)+{ht*vG|d0@Kg(jFuUg0H3O4KCwsZaWY1k86Q^P_@wqi~lzIu6>jDT@! zH0}uLgxn#54#ssH=e;?!DHNlHT3?A#Yz^Z0x1U`ue3pfOw35yZ7JAi|3a` ze;DWdmLZA(UzIJzZ4WTdr#8-xw$w*`rOj!h#Z{C7vS5 z(Yde<1ITWCS8#h{%tR&qT!f|Y7Q3f3IwcbHZprSG4L_&uZ1!0%3Bp+RuB(e073JV; zPU?O`1=A~BUcJJP2i1jjJzXE_bY{bc2%=0MikQB}uB>$Dex>xoxmdB_gp(=(y)3Dq z9dyx+ejujB=jgESX`UwCSk2Nm4X5)>7<5 zfXr`?OHzBMEnDi21gC=1yjLgbN%GGceyR3^MksFcp=({wLt9d?*e@w4Dw{kK>2tOKmZb?i|Ch=MyP zO)eX+*7xadw|UmR&9v+Mz!{k?NmLc?2|Z&sJ__PBt4Kthjz80+o9u;~%+=Umd__wQ zBfVfEzVgk(a=K{oGrzgYxQQNW;q=3OBDf?nY;x0TY~NB_1T+^q5}9 zPB^(W{NRT7T4!acBAo1yo^PWWJUb$flO-|QEUSQp(}qOd$Qp}XmDhFKY-!fx?B(WZ z`Ej4+58Jbozu7kcEvxed9Jj{4q^`ya&O{3)4p%9y&;AKm`MV8_AO;Rl07JJ*4fFs_ zOtVQ=T`H$RT#>>x!v2B*eMzem+_MY`aO2&XwF}DGK0HWk(gWKc4Z+ti)(|DbS0jq2 zU@ZUX#pKS|{vCRH0+9L<_!uuu=!IxWjr3q3>u;mr!?xaHjsi$3S=2JVypSFq@jjCM zMS91=Uu$ih3+(9G_tyQ!h~?bG!@`W1ACBG6Ak-pq8O~S# z{>n<4A^Yp1ti4^>QT{#QJZ<57t>fu zHJ8QqSM`MpBph4FB-(y<9&#W%p$0FSUdu9mN*Xr4f3`WWuH-_-v)>U@h`fDB>OGFS zqpPfm`oQTH5Vtk2(~3zxrue?evF&u;0Mj+bue=Zjtcm5N+aI-lomyJqHBhEH9Q;Mt zu#RFEW!AzYTxDAiTV_M30bk^6k3Ap9eq>anFrKuNTRn=Uf3AZcN?x37&}P$D(0+xO z+{@;wX*fuf424a{WEb-Sjv5bkHXoe%q|b=OSH}vUo^t}Ubo4&D3YyJ`M;$$09V4k^fbLL6Zh@1 z_eMR7C!LAo`l_4QJYQ+Omdg&`csDxv3@~;2;Ybrtc3Jfd3WcV>711yzGoNDg01}FG zP`zig+@b54iwdv4pUsPBk1DZZzKaBmnZQm#Gj28!GokiwHaftzu%mUqeaKVUr6rr~ zJduiT$zdZ81ipI4PE~r@k;2XGOO7gBxl3Q>-p*{XE!`)k+qf8Z8u)qfFsq^3ZOo?C@?*I!Gl`TG+KgMxCAA)2>P_Zzer-07v33iww*)KGk#Ka4 zT~#^c9o(h$2=Nsoa`-B9Mx=txghZQ{9&?}|u`H^5sL6nkY)+a2i}ZTb^&HXbNWIsh zLk2e?*bEPn*HlKrk$u59@!8_VDqF||phuR>7>yec#cz&?0cTSUX&1XgmWcyJ|3j&i z?7F^8`Zr>E{S|25_#Q91G#|UtM%R#oZ@m?}4W4pmU<``HOZOZ~cT9Dy?}NuK&+FFD z#U+jO2NV1J$$mwXD!sq(3jhW;a-N7Tjrik}n~nZ7_gz<$iUY3~sQmu_F7Ge<7vC%$ z6Ft7P*e<^~M)=1_iv?tCF^5S%&h`ZYCn^_$_SU;!`LPZVynmhtwJNMy(g7WI32oc> z&AJ4Tz+;BPj!++1f~45erCEtwp6#lZeS_S=gfO;B#n2EFvA>E=y9k|<4sxD-FfGQP zL!sJ3F>)-+%0BRl5r4p5JeVnMB~uU|IG4YL%c>hgcK7JQ%aZ0N#<~mQi!mWj-Dnk| zTIJ;?m9OdQX_q^{>-x=qFO_t_1^3!#H684XC!I%a1<2CeOWjM1XKp?AM9XaD)&!Tw zxlow5hzA7aMf#2PC~Ejs)CW-(4aapF*>ckv|-&w9|o929iL;93o3ag4;_*sHHD zXgn6&E|(#=*4Ty=bu+wY&!YAhjg$zW8+Q;Qyvt(QI0gD*3Rxm9rFBzRq@SrXZmcb? z8z2IHJ)77f*4B=eLgdNWzMy zQTipmdBZ9hq(MRFF@nm@x>K{>oTUVfdZ`uNiz9B|ZsY-fAU%ds+S~5kt;9J#?5>=l zXda?Hj+`=eJR9m><{%Wiw=s&xAKUvoE-FPCbA5_Kv#e&9lbXPnmn=nVxd$wJov2Z< zn!DiJ*S6y8M$8gpjdy{gms2x&?B`~K+MAp?@BAK0v_wBH0x%3E1m>5@g+>sznbt~j zV&mN(aOhu_kqkxeqJ8kUdW$K40`w^%T-B%_M8jRwkds;V3eCCmL`_Ws2PrekS@%_2x_cWM#*Qo(Jv$9tYJ;noRwf7jc$eVu^+FSswg z7d$ip?rUdMJR%5}JYOlqqS}ut-_h(fKe^RTXLCKCc`C^o_xa!ArT-qCq>n+uwPml% z7)aBn`3E0V$%<%v!UU1(QOEa9!r^d`t7{iauXNJV<_hO4W^Z7wyX{1%5NJIfW&du# zKBgSx=koW-DbwEl+flF7rIlRnC`~A|O7z#0Wt>UeXU{KkFc#9`NkWqURJ&m{GL<^r zx8}Ra3tY=1b30yvXN-1I9KQIgmmu?8Hu`&*9y|Dmy1sGhSao}2sF`g@mCT;GX{wHU z>e{YRV>})hjG+K3)vTiInvXq6%Nveob#^aV=*028phUGYABZicRR>aR+QW4z>q|7t zwBxoMk6nTenSOvRa0bqBu3TW5$|_U&%ePpE@x*cRfQf}db5@*6a}CNXIciaAgd zOAkZ5YhkRvy4#UkxxankzMwgFu6Cp~fqsi0s0ls?7RV`|yRgZeNHbI)rvoigdp3r#~@h1`M)epI0dS9NCPH z#8_M&!6wt?qGY3wc_O-J&WK|?Pb?CL1Qdp*7e!kQ5_;g^DqnQ!AkBGNZMzr@l4@vJ36gy)z8PLKtUAJP|Cu^1)gqvb z23!(5LhoQ5IqPb&Xy^Z=b<|gq>_eqiY8f{OauHV-k3mNAkR6U=b6d|fC3<*e1@5&C z^U-IPbgnNM1q}M0uNl+T-i4khy2-Y)dHE@?qx+G81W|h5Q-(!eJbDj2a&2Ft3fmtQ z`pk1Dp>j}lXU4}@X7)=rVe1G}HXh5TX04&hs#M4AC~WKc;jPp~#V&yyDxN-epCRcS zri=kBX0cDz$O{ayJbO>rQr<+*P62zDvK(2{)B;q2=bz3eJY9Sk7ef6iwPfr=lzN*9 zCURmLW2TD@fo)ct(e^KK zI+JZ|+y9Z{`ga`r z|GOAFJ?{naA%NnsBsnwQ_U3{&bDzLn5BVS)hCO2>F4GIvh7 zh`I1(AKkfJ3x|1*jDTaM{q;5;2JU`%c2Vz-L1F(jmQNkFU!bnc!ApPO>mz|4wQB!o zKL7XAiL}`}dY`u(?A=a+wn@Uwq;a}rpP9^LCnX3;$y&~Umf`$_!uL|l(r4|&YS&K9 zXRmh`s!BNR`R8Gq_FaAS^78U5yaJcE8+neYDFsu4GkLPos~NLVWAin>D*JXx}G{$lXV< zghz$4q>}XNe4M&wt?6^JOZ2V3TJr~DEv&GCl8!^L>akB}kzh90`rGtIy<#aJRTYI! z?ur((pKi>tMUl?ha+?N=Sv;R=v_JWESQ5U-Gv3!tokms=z+{7SiM=ac80wNkD3{O^ z{ipD1fBn-kRx#sf6Yte27Zw>QO?wnMY@BTkX-gB6t(49Qc>aj*i5aE412jW#BU2Us zcx9wL^V^N1#=2ilE0-|PRdq02=1pYIZboegG-p?!8!Ric9cFS>sIsd_`to#pSlV{+ zWQ}eokU>@}&DPNv{nN{^qTS>4Fyvj%ZcWo6u9eS6V-DK)(3W$fL|@QkVZesL#0O$J zk}d9pE0LFX6Lxe#zaoEWx4fLI)YoUCRr>8b#OG|=LZ9p8M(q0)ua4>%$R+MO-;>Ct z&l;4L^xeQ5(cs2J7A{w$lH7Z1;>}4x4i4yGBC4iZplEY5ys^#_m=0vvbeVUGnen+c zOiGl8r%Bl7CWoh?21(24$%)_8YaGNBP9ac96c)y$9=#bK3eVG9 zch=+j*N^RujpCw|U;Po4wpFO+}V; z6r6>W4PGdYj<9nWFC@yq6FgW)8iTL%D#dDj#3$!Kjp<}}XRUVBZ;!3YcEDi;V(_L< zhC8<^p!tUJ#OhUS=q%q)gJLF?uRI90IIFF=7yl;`<=(Gd47hYlrFlw=_ z`C_}=he#@=0Iw}G)>&sjdcKdzfN2HrCMSK+ER{Kd-?x1&zIC9|L&iw}46iOe>jpg_`0M}HMdR6}^t(-kH{IapwnQdTYH^Y|d0uCr*K?UkVH%hy_JIX)X8 z8tX{P0OFWXRz^$UP&~z?R@lg`)vITfcesxXcV$g5m#dZs^%UnKL5{7H7FWAWbZos@nB{+rf3r@sj@HNwQjQ({xxU)WlwQGv~A+k~nx^I3Hm>{=@d zb@$rtEv>6-$!xd_{hU=tZ*GD37|&NnvF;zRIgb9{z!_6UTPrart47gV%@9sV zCrS#E935Zc&PlVv@kYiBm_+ynp{3r6nwt_zs*Q7x7kk9K!;0za(|b+(t+W%m=34xI zT?$i!-=98+t_yXXw!4TC?23^1Yh`S}?XCKC+8wr0RegaS$K|s0n?IiDLqJ^oOue+k zZbDD1DwX4Y#Q;}rWwhEkz^3b|vn=}TF}CIKclZ@}c_}2F5qgrc?kA&CbkIt=R0*mg zn(Ycvh{4tJ3NALp!u>cZ&nzkkD6Ipu%5{-9oEewHCJTUe59OxJZtp|ipFh7LZP&m; zJ_Q7>^7p?Ouy#;eBlPG`ZzzKeCSULr-jmPx;sIP4 z*Lb6Teklnxmbn?{U7V!Nf7)f2y%k0;$_kgcn{<_>87EahAe0}=r(5h#|NdgrWvC)9 z=Ou)u&Zx{X1?(JXw`OiMe|726omrQ>eh6O6g<{f>KVwXWH5Bj%KhGT8d$x=hBmP5H z7x-%m{O57^J!Ae3_%}GVCrsq{M!U6kx6qSST4*-Dx`HI?mq0az^KyT;pbBtgY6PSCXR{s1n+QeR~0Wd$^t zCnpI(k~Q-bemNInd>W2PBJBmxMBD$M0wip^iMWe1B&wbZ)#F*7X$ z-Xi?+L{4#1eMfhupXY$=9ouraTZnP_P5M(d@5|{|Pacx;D_wYhXSa+2kKT5*6gMyw z7_jH3MI)`Ko~XM_-{dZJXVsPK91KygG+#_4a|hOIeB^FEmo)TnnS~Wz6*WB9);A5d=%kzRi zxRZzs6OHB#M4yn6ld}pTzB(rYH!O@Bte)=Y7REDH8(Zs;W9n%mE3`IBgDGxQPwL4lD@{o^r4fe zMI+JkPT=u&b||B>StX#zGN>>9HCu?JnRo+|=*{;c* z9MC{0AuE(fVqtF5)vSesUB!UDd`O7T$+;0fz=z{SnV+GwSG!FrhSvJG{UU$m-mh?% zD^Er)fMNx4Z@RDjUZHZDVYdb2+V_wmFe>og9=k}*58kj}CovM!T$A+! z%>WzKG8$8qsH`<^d1ys=bu(JnYW{PLc}HD`W+@YOiS}Zqa=&U%p<*>|>lbHKJ2wC% z#+lGFK9P=Ht*%qy5GT8{3}!~n*bjB0w?_LrDv;%>Cb-fk3RlrnGts7&gCu&q$8#a@ z>AkQ(tR1tYeScCvG9rIwZQ0;3@!mQdg3A>_anTVAfdEG6Y1&jk=qpv8cG3yK_F0L6y}?kjDJiF)1bEH4fV42V5M7UXs(h?qOHb_ zUvGdi6=M!Gy}UMPJ5L~HI14akM3cOTGgB)IVhE%!T<&>{>-Z7ttdU1y-2f7J;Vs?Z z9LTCHTJH}jkiTC+N5hVFfAVZI0!oq5LhJ2If8fW>Mbk=t`W^Snh*B2v`uhY|VK`c$ z8_sli&$f*Hp7-_m!g&JX3t7EFg{ftmgT*e*w>|=ptkR12RhM4+Uzx=AcFCMwDM<;0 ze&B0`Y>0T8lsNq*!D##Uq7zD-@{MP0j#!eWSZ;7RmN!i@<&KRBRPFf6Xh zKPDOQIchCmw)wQ>Zn350;&~bD1-8=N%TG`Z`vzWYskH25qAwda><3e`S3OU~Y#R|GYxNC1&v-#$&3anpyUf54 z>8RM&Eke_7tWb)SNJz#ZMTgC7cY~O*7?o?RKj5G0M1-~e`{A`OnXu~_PmYZs2mC%+ zt87N0=!lIcX=3IBelw+5M_m&gS?U{>GA6-{-M-;CQjkAw2{zHAw}FIe3aqJ*=t&%g ze|h_7IK_`o2l+g_ZqIzL>k@BZdmt4aG8aeL0v#(aeR^8PXo{&4$Gt6{#}p*bO%?lZ z)EWD*`PDjMG#wmG7pgt|b&s;$>YG5_SPvwL!_bNEDyU{|7Apbg&G+L|9Ic&=W)2oS z?IzXU`}uis3)Qd^&tvDhBPH?WCPt0Lx)s8OA?WawZA8-`In+^h#qF;xe%~_v0wn(L z$#*5|#d#xDK*1nHl8xr^|5dk`8R9Xa*dd|OS^mpE{PUydzekasu~L7u%h|f3!Z-nv z@22OAVX(wRIzXub8LkJsutnb$KLnnd5;>N=SW6KG!3R8FG9o`OFsH>7YNc>?EaSp` zsnyeOBC6HdT(>d+*4mG_?(^5psIgDo$mXSb6$K9ZMeoS*_J_*R4#$V_m_ilQ+eSKz zWBaLqF>^tty3folE>`ts4cvt3R|=6^-rvenG=Dpft{tmC*cXT z)1YV)otGyD+WR;*pub0wN{yUmARPJ-BD7d}?L+ihhSb}T;XWF1if^SiSqG`D1fKM; zpw1b!`)?dlg~(ovI)A4|Yq+-Z3!A9$qb2;d@=rBP72I#-XiqBHloT5kRT=I6D3Wwd zqQ%5jN|CapcNgzKSiVKC;dRTT)}4ZpTI?vUTq=}AyEl~F8|h}@{q+<4hvrFECiT|p zWUuuCP)gWkQMN7mbh7GTvXy+R0`2yM-fInTD`of>^pwfD(NopUtoY(1t|N2?a-Zvo z^Wyfw7IfjEU-B!1=P#U{=s9jai7lfXFde9_`ZUU;-ELu5(Lz#AMC+pG-mThcHH&j& ziURce%`CFBXEv_{>6G$xNfpWOB|EhxdqIlxl&lVgM-OB~#;M#!?DBs(-u2?)gyW;q zV<@B-=C^WK)sIc(3OF+pCfg9@ht)PDee2^RD@4Rd#z*blcv<#+-0evj5YVh1d|6QT z7y*t)UytzW(%ph24Sx+lpl?WV%BOR$1b^DoZbSLAcvN?zm%-vR=ngoE6_1e78+@ zx;)L!-qQ2)x}$MwZ(XL0MRfE<`Zaed#@aGT)@uNAjnFo2VA6o6>9;a$X+OV#^e@1| z6$#1nX^p8AHw~N~#<1+js-XlOFJ{d4V#CC*+%5KJNMBj1*Ba~gqkZphS#J0>YBysX z$OGXp%p79SGjKAnxUlmpW$tSv+M1smrUNNwzeic`vA<);VzgVQq8}OT?Qm04Jbny%IS>1c1w+WK$XH1iB1x-@9m^wS%bMiuUkR1MJmdVjbt^r%B!RV>axqIrw6T$B>CX7_SSRly`eyt3E{Tx(LK z={Q$e8J$YZ)XnXg4};s?z{=?z@#O;H7=zI92Z}QIkLs_P1hsfwXsIoOR3ExVr3yao z==~!nY6VbMyM2~s75~M5h~3#K)|EO!Pf??kowrurGw4NrY+^@?x&Ki5$(uK@u;MB!nx59MhM*-j$-0~j%N*L^{1N=~q-_h(!@TPC zO1sA>r8KioXQVns7Qbs^&w7iyH2a{4IFas;S~vDYTa=&NAK#iWqNDc`b+jxHfsqGT z$N>jP1pB5Gxl}L0Pg|&IfrjsCPhW;Jx&Ox`4P{wBf(FvO#uGQ81pk2O_vvdeh%&D( z;MgbvNEfqnwQA}12~D^ug+IZ`>}G1mqQ9zO?}9=F-pKn|Z38jts?B$R0pv-CYx)Mg z=(fvqDXazSk63BVE)7!mmij7AX ztI|#C{KY(i0QyI-mN|1+m+r=3GGCkRzHa;JiAj`s_=53{DL}E;wK88uhW?Y4R z_&e%C?hxzM{w`VXE$*uSP6V`B{p(Tc0#XF-NuD;^ioah zQj_H_%+pm(Q?bdST#SZWRiuToWhmDaCz(fktTr>peSYhfpw=$Ju0xjn%fn<^kGJZ& z$yy_l+`8lDbRmq^8Q!Zjd&lgfvuxEqQ)OB`bNmBxl#CyhtaOZHuC6yKyEcCH^DBQD z`lDC4e06)OAWaC#=~4zzP8Vpp;-Q@lC9MU^1L1 zOvN;hf3B#@h#^+xauKN3CP8J;v$z*~zsKU#v2=)={loR_D?iN#86H36+Vh z%mmS!cCEk*DQYbbLbFw6;jSbY(QjW}*%i+Ld8VBN=0J*;${9ux(kU#l5Ukap{l3siyPb zSo&iTPP)}Da)&|jWs&L_4z!htyB@#>AX@fa#;#$y&GR+T<4y1HO z>VY(=$e73VHlNs~5@zhsWf)Ug%U+q&VsjKy4x%5-e4=mA-mqf{+T{d=rj`u@983&n zNCq_51rg5*!xE8Qus!Z9!L+e5yFv)XToy4rT@P-?7u4wKRh&8s4wg-MbvU?yvk1Qn z_jI!S^=#L>c8X`rKvIHh4!U#cyIZkZ=lILkW`gJDh;*}`?WogYi(>`+vT30Wg6#c! zx_*QQ1$_Bip>`ga({k`Gl>+R4RPir|ef~Z#`wAiQl=GJB^g$MJkKfA~t;j*~SC0Nq zqUOBvmv9El`pOpXv9kpnHn+vD9Myj+HvI zRxheoEIxD_NRT%&@1c=t&TZTAL^j{Elg^#N3PQ+7PO)#JYESV8kK&d|1#N@rdCF6w zs(f*JKeER7t$K!sHB;q9u_!c3GLV|XGVU;^9I#eYbV`?Z?^l}76uget(S^HyC!r_3 zUZkB|$!qv0Qro~(Sc{B3XzI}6eQ=mf-NkrGIhE#CF|x-~=Hyd!8o#m2WASB@$ybym*d6{*uv!8cqe4ErtOM>nUlZWm@ecgB=Ht5HeXbV&@fmXSWbfAN7Rjp0 z#C&E%+N+vUhjNB;scA-l;zP{Pifdz3Nd!0g>G!Y;b@`wWY6ckqjbQ@ru|q!HKM*s^ zkwZo!lT^Cy^I=)rt*CRhxF??8bxZ-XjFuq{8y+zBoe{bwHU)Mj!P1gNbLp3sc-{-c zZ0tBNBqKOaxTd1zAaq{t$}#JtNaZfQNbQpu48^6VytLXtVnh9WL~xBhLo{?O1vOh$CkGn65b%!nPGuI;M%nndTHHIesAp2#unHuC$;D1 zc*69TMKck_zDc$LJTy1TWA2mz#UW@MH>@SE=OOc;))Lys(TTTmbd|>2GtFJsrUtS9 zL;EdhnjIV40LHV)5ZmH>lN}!UcHo3SaGD zy}M$)>bq2nCFha{fHhK2i(<3x?)l`LB-dXw{dv5p4xXDs>0@br8*>~QLOy7ESghM2 z=L0w1tQKBa{Dg$49M~n_wIN?5D zKFClFf?wtbbYJczW_iNc&}ilVyQN<&=RM%S%3s>Chbe|szaEt@C`>d64_9$=jFrL1 zK`@h};@i8)&aEFh-;V|94NlCI%s-QkXsU4+WWFv`zQ&u;MT^jTRXK1cX8Ng59%s4O zq4NBBnf)|bj$T}?iL$KL?W8irtw^3vjTW>R_1%z{;lbkLH1Uc1GE2daT9RaflIarO z^-O1L3cwcl{k!;xE2G9$gv#|vW~QhfmUyrsFSzZQa6!+5lFurP={(G>5R1rq%7t<^ zF-q`<#swVGdH$Tqd2V^DAe!x_gc{(ckd}WJWjz32Na<(wJb3CLST4~xTYvt+O|`de zZz#$mLt!EzQk;#M;8m-aMe@2^M<1j)+|->EC{_`_Pd`z6x8427^b$d>w%`dkcgeSL zG1|wCkeyyb9lu`;FDI)Sizql@XutiI4F_%gM^%k^bA&E0f6~SON+qq|RgNNO#3pcX z<>NT7&={qE295IFSd669TGC?xFjJl-tUphDrEwp!4dj;23fOj(6nk<}jGF1!v_bGY z8rGTNSPniqE(RZ4utc~Hmn7cM{gI+Q&cG;>qdB_`tU$lbQXz*GdTrQX@x}nX*Zd6; zr5?%;dCEbqGWWXs<^-SeOdgKHrih+#TIsL(2JS-}$jLq?f6#N7hHpjKCE|>6_IO+%2)s zD{7rdF?z$@H`wX!l<7{*X$7;Sr8n8O#`Y%bRlG+Ui!+GFAxN8YoCM6~*Y_+>x1z`E zn#S7@x6@)x>(sLSpRA}A{}1%_wsqM)PqtOAEj@+XRAUSLbA)q`oZLVTN4SWY(O*!k zZNNyT|ISmK%4$LcwF)j~WoOO*MNO1fS-$_vn)sOku;mA1W2Q_`FA>yyt%fHKQ;z(1 zjup<)mhtb6f5l~!{&K;Ylt^Zyc-0XscWU;jR3)bkFn6+jsvyXfv*LF$clsF$W{Q2h#V&FLm<)AAfg61F8)S~JTMCLA;yT7BZ2OK-x4w?bZe zuMd#^SX6!D6eXG>*VxD7w<1A_twFxlOc9i2mAEB*@xmpNI2KwRDFWRRNBW-imd;*$ z)txRc+nGo?$*#>e)Ky4-Rw|bA{o)-ypLb|$)@XXC~|w`vBo~!5Y!G0U}wA0 z$k(TpWXqhbT=2Ox;31FI*O*GTFENkSEMMtUulxR?M)|(wDjVDMaJq(Sc2%QAIqcEE zI1;$7%hdy}GspEB@N=oYGZ8jPwpL^Xzw42h5Gv2`U`(x_eAz^0l4bna4BWN&6~JGx z;h*JuEU`#|t{moGb<-O-JB-eRq3-M?u20|ZPBgE2Oz_yUYSj60-}uD6!@{;+0asdS z?DYUUtnZAp_=zcf>tiEYZa&7y$!Bu5I4&wlH3dRhkl^Z7=|?ILk*$(R=*Ty*{R@Q4 zcN1?UZv2+x=po8oB5c8}HI%I~r z%1zw~))zFqDR@s0JCUVor8aA80lf%Hk%8og#>9+YkMN7~fvbDz_6UdSrl+i{e1W(}%)06Jw4p@HRpvJ$PvxnTTC#3o#QRbRJFZqIXQB9%C2fu~2~djQ z>DYij(&0o?5?xVNX3C_*-E{bgPHIoR<8NkA0#0LRqlL=G2Vy5#7$So{H{X{=-$b1+-9(f$w$G@{b6w zA1ZsOw%&i+H*L3;cngWeBnQ=*%r9baJ5ipMC_hL9Rlqqcx{05vP3GI%16%PsC49u= zNg&dSmiSRi^$dC?#|#)wXuV3iY#e}r?=LPgQE#v-Iu(UvxrX3^TKqc zrXP5-1dLfWozf8tn57AuP4&O1K0w=yS!-l3w`7kfkq-&~3Tu&q)vY~8!B@K4h&#q` zWGhJlzkW&5!h3E7NiXtamVH{%EdB$yIJh7uMxUQl1S}lIN@2oLdwXXAoC+daM7u2- zx3k7#$eGtAKN0Ztk=EnD^Qw(}$BZ`}tRK_C1ycdUL%8S>Tu32FOhy7m zZ;o$TXmUer98H7<|5jem?ePzI#m3da#`QG=#Z0mn*37xv9IgLWo{U$?#D~EzB(>PS zsb&((<}0vk0fU}ocObj(qlIs9#m&t8ON6g0N#&oT4>+foc~`s81VO4rm{j?q0zue6 zkxR$K3#JJseQH+qitqD18$C}A*SnpeIwJfpm7~?r!%ZpYQ_9AcCHfSD4;rHo({-Zt3$|B? zhZSLotDLED@9l)xNi`L%7us1q@9UiwCg2J^B9m~XbD(`;n^@;?ny7RT2hmL4Ms7-; z{Sxx3tD3FqcZ7Zua?rtTlvGs0tP}tXvRk*EuWPGLFBYb5^?#QW_4PgT zj#K!=ik2MP&53ET0e(J9qq>?6$Q#MLB2E3>KytBe(t}0Icf!cBd^@@8p{E!B^_4K; zQqNhY;}(O#uMgK0Ro0P<#hZC~SLo@Ew)zsQrYQj zDF4P=>}z1Zn3^z?szM(kt<2EImGhlPmpSnjv=x?xAJX+(#lh|CYk|F-Hw}wv@r_n{ z9;V3ll|b|O0hWBqgdd|N*E$}`P!Rvoifl`f$TCk}RuNTO2($OK1((w`UsrY7cbjQ5 z-Z^QluqVF-f(q7KKh4?}dQPTg6zbiLqa8o)$c&D_mXA!DmNQb71MBcS~hyxWrm$SJgg!*j-TFK zv&bNZeP?ptKm<&{!l1)-F_$ThtQRrh_vrQg3K$>6e_efvULrR&lCCje5*B-@@x3C@ zRN@RIGRUPvS?Un3*j$;r`dP(sxIPQES0oEEMj<_|iK6Zg9wDoGs_WrsL@s^o`Iq(7 zfFVBSi_p82=9R_-uhIk}86uzuLk=A%&pba(;Ww*7m=jaxMs!kSFGuG_F!g)$J3f*_ zPP1u}veu~&%hYB5`%?aVD6ij? zQ8GbdCjCwCqeJEwk6bT&*KG&nMj#bJ|+79%EtY--SrH5?E{Nda`@Nou{ zPPf#aDk?R7TnW0EwUxD%B_6>o%<&Vcd-MU@se882jY3qU`FRd0f0tDYLIkO<)BIr5 zjXT~aU5j04bKElleu}m2 z(|Tt&M)yr8;a%ROkA&v97Z?4BK-P#7mEy^dI~|YYQdJV)!A%hAHNxS1POR$-{*4zC zy@llQ*Dt=WI4yDj^V)0adf3=;)16wgIT?HVGFuXpPt)sooPf+G>KGXRi2N%1s4!CdY1+DKJIb$~@qZ$yvPk(YW0keXA|yID1F~ zxclaTuQXD@hs&TypwOMcvG24g!@Y;D)f7|5H@Pe87aC>D49S8RXC;=u&L0r0kHcQi zOkkh4E`ylZJI^rNCmgz72rEj*&>An)wy*5Y+$q#U`FB8(0S8k?1uz zIt~zdfL8gn`5t~s?b{?_{97->{SJSlrd%21bw)_No9vUx84afAXd@l)U=T0U2B%|* z5oUKE+%B^H1YKk~+-sqM4D=}o=%F`4lt4;gRb?vlEg4yn@19dxE8AF0R~}k9=$D%a z^HBYH^sI&|&yo{azp!B~+p9h-Uw$KAm*20eKYH%%QmzUzw1)T!rveKA74-DZE_=q3nux#@ac2LkgQ{KPhvr|ehCj1 z@6h_dzdyjd{^vb^y*4|J&zBYcDGNgWAMG->Wwi zX;mL+3A(sG(ieU8MkmYAscZ14MDB#EKriHDLXEq8*TdKzEwb#aOtH;8mTiil*m;c@ z7@PZ83uo4rPAyMK#Y>yi&^qb#xeY6DZq;6#xd`B!V`@cOD^3)JB9YbWh$qAm&Xl`Z z=Y`<2Z^YVKAW=x90k6h1#8+J3L6(}Y;@FGpbM%CTpL?l??(Pkaa>F0o$HZYs?qvC& zdp}@{Hr5$pQ;8?9RN?Q&>GVEEpMHM9eeYQ$Ws8YLVx}3N1(M`D;;hY>4|D4GtEq1C z4AKC)AC`myBLs)IL*&9=9&di{tT;yFJ7h4_c|lRP8w&xDiBv|l)X`gyy^bP#PJ?&R z%L>}EEHs)Z-}Ka5X^ZyeeW5LCnX{o%s^y zeLqFTsePvyu!0&RH>Fw$d;<4c)M4SeySJWYIG9}57yiC5ovr}qSLUASKP9YKbWZ3& zs(9{>M9kbrk#0bykRC|$GvoT946L+9RP+g3dG7 zfhlsXr(>h}@9gV&Jh}w#kMr-|B%ZqU<^mS}slR)J)Y7}(6LH@E!HJ*}#^UJYjQ)j1 zqYQmuHBIsXPLnHBm=yy@au#hjKQ|qP$?uEA0^}PfStm`A2w~HH*6NNKNyR^tswFcH zW$6C!>R|3-A9t^Yz$)Kl>k3@@c7LZzc9d+ZBIWdVM!SV(V-ld@*<%IgO++z)Dv6X! zZGHNU6XeC>Cb;VTtI5T>{2qhPkS;;D-4y;ht=^V@Yn4D}`?knGAch0++^LcHAQ$9N z!_JHm?b@v4q#Jk<{@J73W)T?8F1u|}BktV@5 ziv|_E2r65hlE^`*reCx|!(+o*Xu&PV+IJG3OpG@J=S7d1mgtWC5FVnau29T-c4DQ` zyaN!PiNqV04Cqbr<;3?e3sv(%V&9Z*vo&p}?Zl0a2#PERjR3Kre;>k; zXOI6Y71F?eK!~nETw`7uykC7hSldp0Xh(pG9D7K=k5!bMCz_Sle4Yx6Io&<-H(%0_ z-BP-2J`o{wsajPVfSq?jN4B9iSmA`WIi8(V?=$IrDwje-`1! z&9c~RThqUBm;a$uoYKV&vn|U(*_IMtl;#E=)71FB{XTfy#hR>xK%5oTSW zBEszKd&cuky)sYwackM!Rt)EX}9rG*mPUjI}dmWpe*-$a|CmgR_ ztnE3CIg1hC=YBEfbr<|Z>t>wnIk_jM!#s6pYA2THCUSO8?Aa+KhP2`bR7xdg-C-6a zN{iYX5%0HIQV|2HOYf0$k3t?LF@Pz0)Xb?EKD)%DZ<%LHs>=7R7$e%Hwp-mQVdJ8~ zDq#riaw`3B*VZS9{a07_B0iZ2eW~#EZ_XH?|9;A@I03zEmN1ue2)+t@d!=zsB_gWdAnU^vWb`VQ({Ezu0kY8ulBZY9Vw{-4oT3K4490lJcyw;q=ct(AaR6yFUiA; z77?!Kw8;TCxx$1~O;&uRp1r~pe0Z1_xv+4;V+NUd$@21K^9rJXGs{|n2WwteYGfqc z_I`S=_`cpMH;D2;5mDMFzP$R*tz4P!Fm3nG5ZZkPFi{0ysAb&`k<#?O zUAV;Vu&I6HY5J0@<<59a?L6SD=hlRJT==00vh=wziXm0GzPoOovbkxWVB6@dmofW6 zI)%y=`FkGwr%vK6a$?|5PT5PuH5`5?zsS)xjIm1zw5Ae1i^I?E;Fv^)5Tv%0l_S3+ zlIt!Ma!FxcxhZpKl5VSRqBP8)vN$R=_fMd78!N|q$)W%+rLPk;!$ zM1BfLAiXH~!+$+EBEA_5cocU={*+j`8SuhzTlOqCD+G{Lb=Uv{eRQ)5NUu0_&ODdHYYI0`=4Xvg53<+McTr+u>+pa}}{sx&K;{ z$EQA8MPcY4$qM47Lgua&q3(i6dDrD?2PFbJv0=>LY89|fJj_Ba_E)t5Dg5>uZChfa z4@1j#=AoN|=5^cdoe}ha-d^amVduA`{9ho#ALLFQx+U|~Aj z@4qkNV$DT^GxJ$bW^=nkG594Ag+dX$aA1*XFWlHpF>Eu7*pzrD!gu;7RcKbUD-!Ae z9`v#AMA8`}cmTB@PqysD4nfB3LocKB_a7QN=^D;2wzuhe-p2R`@wo&{C3J%dL%T3QaSt5VNX zQ*fx;kP4ogh<=}UQ@@cj-D5`#)BHG(7G3(7K&79jr9y|~a%CH*KY@A?GZV$xPvuRn zYq@I6e!md_qm-+llZGZ&;xXc3E{cr-KhD?+LqoU#V-HnCQA_xx%kMLkh^#s+D{&KUPaJk`DR?%M ze16sCCnr~vFCzD3p07;We~zRFY{P#F7DloE;DQT?W&k^5A(umxR5~g`1ILMFv9)Ay zYad))-QfHec4CV4`Olm1S5^{IQZsOfN?Rt^vNS$@RdiiV>v-pUk2 zB~jG!hjwUm$M$zumyOK~`|?&(y?m2t2MDD?e^}B!$1)08E8xy?6aKXYd zYVF3t^#P@grN>YVqdo}N&wG}g9TNw>FZ6srTW{&R3KCD--NB^#B_CgoQVAY6A)RIU=reSb@ZO5RlBK4G1t)^o# zxSZ)`EQp6`&Tz)_sv4S;NKsvqRehdJ>|iko=q}$k!!#ad<|A{NT={-R>5{gtV|48d zOT(I*N2wdVAhUi?hPY{3AAxG zU~pSoT`5MO?!EWbg+%K#8|OLBb^X1yEnS`(em#jz`oV#H6q+Dz@cZlr$oV`9^&6Mw zS=(T(0w9pke0IG@3S~v#)>$u8(_6ey2Ng)G@5r)x^Qz$7{JU9~^rejZv(rc-e={r* zqKLq%f2@Ef|x_(%m z6Ub{^^^2HPv)n}pEK99qbhR9<5o|R!_j^c{R9;?tvFGZyssB0yi8%zs-wEWu=YapL zI;a@q99?I>NepEHrnRErgoXiwu8%1Shi2k1yelW?IhbORGL7 z1~xD_ZlWE^7C^nO*f5C&)%Ba(;hfA54)})xs)FVAVO;ypH1py-H8yK9rez6)ZE!t z`TTVb{~~^Ed|aYo;rn3aL2Kat(bkgX?=5N*>mgZCy6q6?3QU*k3&D5B0AV1flU?N? znBQ5!s5DzrRkIrnleek(Ed|pzgLA^w!vpI!nlnNW zGuK?y(eJy)(6bJ4h`#d}=Cieqo+@jp@07L5*|F{M8@ zZ3z5DO|X-mRlU1)rObWGCxHwH42a!XH2l- zr1$2P0(_8GDOT0v*~hmZ$}Yl2-+5u0<{f@ZQW;8q-$}Z?P_D1us!5*ZP~Y1;)0jBt z?WQnThxE&Ma=A*P_xx(utj~9_+U@t)W|9z?Rhxk-cR>sIH|miXyTi7_TxG}IZbw5s z1EH2JjYk&qa+|sJr>A1E?M=T^S!2pZyc~sR$L2X4c#ci{Jw?h-Fq!JE#&<<}ts(HI{?QP3weRMETqX*lHM4zMgB!gHXuOe<)j{b`6Z($$O-SdT_I3Gj=tLkS=}RmkZOe)Ryc^)`Cs_VlSm_e2~BuqEY%QOrY(cy9n4M z5cfyovY|NZ<&zKKzi0j_PgB6N|M-3W_u~A=KQvSwtX6RE5!Au*EG1>k-eLyHZM0jy z(CE|a)aEm}=zFBu?6I3dqW?`gJzZ#ZLt^(As)H{e0OLo@tP<^1A6UE6SAJHOmGKgW zY@tKYZTf(ID7G+QCX?i~Y4#^&nH`!>W{g?d{{?>ZBk?Q+0RsrZ@IdN`?-G4Rjw-V| zee!G^sb#v;28||$`D^3Lg2_c+RD(V?-M$In)lZ-Vzr6E@k&F6W_OQK%Z@&@WBj&T( zAG;#euG8K%&p9;Zud_=$u=;iQacw*s_Wu1O*bY}SE~$o#xg+MoR!>emQ!-{IhSsWh zJ!g%X4%i>392b5g)APd|Ry%#hhCI{F#4xqc?O8_Mz-aYs_jC8zfrHsf8Gt~>L0|X4(e+s5($Yk$#@=(qMju{WMkq#?7@FD`UEHezd{xm6jNhVySyJ(Cz_i8n7uL% zjiFI}!PJf%Ie(sx7t>L^y^B(1OnrR!K6U65FM%j1ReGH?dALzh1LZa+&JWNlq^bkS z(Toz>+sq)BuHMhdkY%4&y4Kn`fYCb7fM&EjwiHTcP5yR)MJy#%gg^Q^7p);F@~HI0 z?B`vP9CSL%@eW||G}noaON4ecZ1|{h*Mv*he)+ZtZHD?a`ZevW0UMOLSKE zugWGtOhf3CI1dJ{4I_{!_U+9|c(|&OD7BeB`()`lBi?)tzew@B1cX{EuB{H^HK%KT zf$s;+<(+76oj+9Y?bNF0-$SwMi)BYuRb_IxG|8Dh)*dzK`igM9xvr1_xW+N9R%kB& zI!fZ!;0FYf1#WNHS_xidXNu)FY&=b+dWX`@2geB#giT-l*84{1;h`l~6)jRK zzw!EE`ft6qDhL0C?;i?iQ33Vb;Ehs-E&ssEUMZc;an6%=*8Lc6{adMZFbX|TYj1fc zWe<`@9;dX_(PTI)=QsdHXnkRhHofe9E}nYgvxCI^GJ@#8tOiMBJrJ3>WB{(}y*zbj ztU%RT1IlJR8;^zXf#fWeW$hC%8*s@=o$hz^$&UnP#%BDZ@>G#&AL(RtELAKRJ!0y& zmK}xyz|Rt~2c5C=;5z%yJK<~(S7RFAOK#JswYo7&bFJ!J<#t=PjK=l8q6NjD1dpcw zT!`iUJATV3orC^XtNbsU{J%b~kjHd(DoBcnRbE_3Baz5zztjDv3nzl*z1(lvxL)-M zYjKqD0Q}`i)oX7!xaHF$OYprJGiXooUkNF*3(%&4F}|>2a@kE)rUYn_zPzRhl*%2uCe|PBdr@6Gy?o^YKd*-nk6+ zhl0xJ@PO<#?y%2dRoh9k+>`UB1dZXiB>h$v_CmKwYo4aTwGpsz0|&6OC#&j0daTP+ z-wvW&*D7US>i0=_4*Udc)l5Z1B1fxZ3&KVlVjjM-8d~pD?(Arop=;IR+q)=!toW*g z-Nu2pE4kqNwMAV@dx}>-60bI2{)X=YX3+We9AK`1Yi`5Z7o4xG>td+#to>XOiig2 zAw$||aU6oX%5XF@?}6gaujXi&GaY}Bk%z>mdTY(}5-(yi^VVGsdsQ+mH`6pW?0Xg4 zYqSpgUBLRc)p?Mv+OD*;wDM25vZfQYHLct1jy`J|o&2!vGh-2heWY)t_3%idL|Dy6 zbl=a#U;q}b(wQ42+)-`Jy5>i5K=1d1HMRIr%PD~d9-=4B{mW=~9g?LeqU?^TyQ@d8 zcb~qD(G2r8JYd|TMwUB&`#$T$2qD*7+o)ampm;xGXe*VR>)zol#F4ShN&Iwfq!A~5 z*}-9Vn=;VZFTJR0^Pv#FC4FMr^rXI0w+#fC?h6&qGg5^|XDK}lgMa+z!d7AzQDQtp zd0WyDC?;0xp{zIAE!R}dwk3bPW~1wS|9#`x*^LrT>SY$jEf;;OZ@YSX)@jif83Uw5t%R}GZDtZe66YZ?H+mj| z$O2sT?4SE@rc0*zEk{nGnViG)6?#V9x%Xbh`2PF#`y#5^dHjFl5&!d<^+`AjeF*(3F_nx0ipPSa8-&-MPt)zl%Y5U#=zFt@(M$esb>if)OSqyR^^coDTySR*r0cByjjM-{lH zuFm0nKz;ryAm(7Z&tG1TqM416EU+A~*>?(Y&0$%kX1gt5eq7j+s`1aQV;@@g!ZuC5 zCAkL}Xv<=EhH8k6YV^?iA;ZgmLvO)?hs7iJkw1c9PfTU&ZvDab$&>D)mqV= zVvO=?{04o-&kl5y?7JR*ebvB(^K(oZ0lR?=W4Z5YYinc7^tp$R)mL(c6}Z;#39Q#y zUN{I|?3t%@1aCx-u~r<-#f~FA5i_ zLPT2$P!c?&PWCe5s8TlYE}EX06in%D(4?&P>^=zro=@M`66 zbv})q-|WL^g>-zSGvD+@*zar1HHWV0FHV#07>~@4K(VdqAu`#{h+I~`jriBo`i&Je zwy3Qj-g(14xA{`bR!(%DC9Bt#Ilr?yd}ORWbXXWw9Ssr$?-1O^(6Kv;zEqBP`)eEQ zj=JN?hgw|i^=-fP)O#Ddx`C`u$3NunPgUSEOP%MFH%jUxhaI_@7&9zCpI0>s)UJOZ z!DsPb=4<~eWl7(5aKrDQJq&DV$vLv&1ioUdrbxeL1noQIgoFvicmd|IOBtIUAylhT zhd#FEe|_k`d$%rc{r{xczXN0c{q3Mr4(R>~S^0P(QRTGw+;>@hRN2~tDMWyFO(6W8 zBE9=JWng~h*>vK7Dhc7WQIelAw3+G5cBjrJaXVD{U`zpfM0(l9g5X#XmIsdE!K$O!$gOYmvR@S0ro;`rGr`t_6{F*6d(*N9gxYXh>t>Koe zEN&&G$y8-Z@Z>{qPHm3BARAvah404?F@-U93b;Of)?Y%_LuKu?28@1a(=`)|DlWl^xwvwHNIq|2>>ER6IKIe5&X;3gHFJl45Jj z{OKbD^f15EU#uGh@-X@eGNCix6q@_B7(U)~9mi*_PU8qXx=*3JpwPn9FtDX+DP0?e zWftGBsrZztmMWW!w+lg&?|dy8Q|WIM$dYM>wVB}&z8`t9c7k=;Z*#G3D1A8WYo9wc zm|})kryKggpRw@w3zi{w%Bh(}LdyN=iHe3{8!GiO@WBn*49!BFWc%lBbuVL_Ov9)c z(q>9Gf@oDMXQwLM;GqoCJH4AFe(O?(WfD2nV63$KThlWGsI$gkjQOdLID=We?~A(E znPd3_=h zx^Z1s0o%3)dHyNhfcW= zR9=YbXPQ0!VV-Xh$6@MT}dx6Q(BtV+OniK2-Hg|e{__f2qK4- zXN7xA$m&8}T*39uOBl3W-y^AQ+gg*k#mlzSyYi9m)6<7qrLRj4ut_YEF1QhINVg-) zxycc7J>EZG)?v>w9=>{6m5mQ|pG;hB2&GS8QB*2V{A|!cTpS^i$tDi#n$7=UoK;9= zshivA8e9PRV$fl@5Bm~lr(|s#=J$3bIH2rq&d#GEFQGX%dx+%~ScgsD^Cb=&asqi> zZR2|0J^nWmL^R#n+39fGdHch_(OCSD@MBf=!S0R;Hy-p9@_XW{5zg06hRExVAKKp? zDySBc-no_b&t+Vrtrho>cF@#kK2;JL5Ui`6!c+hBSJTpzrH*5MTM~%Z-w($`d;1C7J-Zxk@wH*E)+1A%6estS%l8=kG!uCae_JVb zhm3}{A??*G=~6woX=HxOl0lh9wH~)vWaY6AwQVKt1rL_S0MJ7NFg4VM6QTDt@D+4S zZv{5KC&PBNQiE7BWIG4DxOx3>ExGg_?12x%pf#qxHgn6bQexdM?V@{xQWjjU)$|7; znE>bCd$UD^j|H z7UF=V9{r0)^;HXIv%>Y)v#lv8DegGESYE-AM(bPBwOhum9Geusqv$6L;vh5es9IWz z95|At_|x7$#P}rSJ+-REAv+UaI{py!4pX=C9Sf0)X5axTemB%`4~T?_ak||6l9jPq zS9{tXYyFn!Uxmtpy+QcQ`$Y}=QDm9!-KR0GfreQw*k81y<1d#|Lrhv?UNCBI5q zL{LW?$NC9(cJ#&4XWx-;+FMMgCkOXmQInz}7X^ipS(D$``K*1sL*MuNUE#lw=#%lW z=Kr4Bb70fv6#$IpD@u4w5tZVOoE1{oMngH@h7Im+*AY|-zD`zCOHgRe+#?W%{dBIC2=J} z#*6P`e5+y?pK1{!`1Te3B)NWRfj@3EGq3um0jZQN32(fN<)pB-{!PIM>jl&5P3a8h zN>W>JIj5*8f75}>*OfABfJVW*@1?P*x$?KLKP-b5ihaT0V)M`Xfp7XK*Zt0TD_7Vi zQVB0rdyuEaZ5idn&a)=&aMFdUh3Sf=c|cv@Z?MRd8UZw?m|$r@3Oy1L1HZP!xc}-E z%XG|KC>*P@{pBG;xBdf}aSh!9>;)QtsMcAR<-=K6UY%>Gj0n>kbHTKgx-ynwEA280 zL)c=hmAps7#ZDOZfOd9d!$sF=cl$_R7kc88gW+2bzt-ZTm}C zdzn!7oC}LcJ+bZ;u{E+{z!<(*QT}eF>Sj;+?3ZBu=+rxx-5v+C6`u>so4mSED(^nX z9#e-6)#Ge0qU-PlQ?8U*C|+2$xci}81>P1pTNX3c^T~dQ@b;*`_Uch>ZOo;$HN%-f zvcc~TRXt>rK(@-kz%-lq!+%glPOa?dMY0ssI_~DhNBY_izIE~AuzmGd>uZ`(M}L!s`aBvv+kaw z7uSTDlG;g4(F$NqS$Xw%`UNbRj`7q)KfjUZ7t+-lX3BCjIJ6hk`;~?y%^&L8=$_(1 z&)nHQaKS4aZulA&qxRGd{dp8Rjx}145IZ2WG#Wi!1!eCGNFH0>R8IC3|;&5gm^MbuW{GW%=Nzk{$1>U%uD z@0#b7s$KFXD{-?PE>A|uSzO%XuQGv{p{-rrn6{*gdfOUr)zzRp>-zq#^p(76m6plqj7vk3R{>%x(E1jM|<#P{pj z@GH##qYB1RYD^!j{O?pV9mKj?%e+tiKj?XTJ-^j|@y+g$=hF*!T{T&&pFr00|GaK}ssISoy#>mHE3ap&Q zwGYIMYMBPql<(mzP#*O;78(-*RF`a$7J3})LNR=oHv@6SY@o;~SC6N~D#3-Nm=XU& z+M6I(9SFmw3|_|)6lL^5X`{a-5&hzDMI%4VMSiV?yKjAc@<>rW1rH;9E#u$(BOw14 zF85!AAEU{POA80Q%>;bR54a(u64)=PJnwy3 zAe>S5Iq8b>T%sk#VE<{xcKQi3D(+H$vr1{P7x=g>Q@H$|L8J}o!b5np0cM~dv|MC` zibPJTUN6Tg1|iR`8+Tejt&He5@|k$2h){4PlEv z+6QMbs~X*YgOyc|LN)^KZyxWVFyq@`XkGl)3p2uTVLBH|EMsnC(Ob?!ecSJR{O@ck zEFxif%_bZrK#aS7;f-D363pIj?nc%Yfsa?18S9o{;0%yuDCao}yd&kWh-LXm{KY~# z-II$BxsyA@_uIs=nm^Ohb`XB)kOFF5$*>PS(}|4J;bY*R%CcjyajEG7antjWi+CWlux*XC6ehe!3wV)_zX^es#!s8F4Fl|3&M<7i)}ay#QLJY`I6~ z`7_8x#Y+UWvx;~Bq#7nI-?rX6Xv)7 zXTWFko=9QS&hn|fRv}o_78Vt(T3@Hjgbq1^^SF~G-1HmNf4vJtv2ZN6EE(CS;h43t01M!6`{DJJC-OGu-fzfYFW- ze@Rek7Ao;E#mHj2fx~#IwwXd7yvm{CAmL_bqt zgV+8%!`XTM?^+QNtC`OX8=}SeaG_3Z^-Ri#|%G3);$+DZJsBws|?PsDVE7ROq*^uYBI8%~x=xN*&mj?*1f$^o1j; zy<-`F4!^IiAI{6&t>)KYe&{F8@S4?_ks$#Gh@Y82g=mSZ<4@kEl+mWwLS+W2S5fxC zWYfA|`g>j7{C2>vPiLGK8=Z(@{7+%_y1c5lyL9{mOdc+78|EI9bpmq3hGb<sr-(s^g|9F$JB6<$3k{RdCb_;##+?;rnr=<>gQLgaV)jp9hM!e#*BtuJnK=|luc z)(i!WA?**MxdE+qqnm-!5_@N2J``_gUhTdx13|;AFmeOs&6PDuu~Al@#5Ty%%gvP= zM|}#4IsM9ZC+F7Fh$nBPS010Mj*wNnVGa`HZe|IDp=N$~DvhMIB^L0UoXGm}J?f!k zOUu&kC+@)glL*TXrjGb0Ta6^zpPEJ=KX-%S#{ z$&qxm@rzPy{LlU7Z%mX3NOxlMqz@(=H^`_67n#q#{AtYv`DG&ZN+`@8+T>GjOjQ7h z5jD$HH?*hBNP`w>r5|`q6y)qgiqi>U4Ir@B5*7;HtRrTE=8P`C|P| z(h^5YD_`wQr7~hZB+q7H;TIIt-~JmH<@9~N=0T9~X;O6`vK7!GeO6Q#D<)cNj9kRI zl>$6)iwNf|6b`ohGp!DFls#AI$EjDL@fFrROFGy^_oAe__&&7_^K~6}#RPaj0AK*` zu9EhU(6RfsllwC_2XIql6Q@5$w&djt2GP06GCA6b;eV1I1nX*8Kh1b`;2n9nL?hGo z2QEx;%-Pmq(}uNy&cKCv6?AO}p+?s7dRx?4J>fB`dvnh+ZDVVc!ZP0wGW$8X9jtpN z=pM~_%3$)cO~HfqUdN29jaF=(?57_0X2rZbyJ$&OG{hYrSrUfU-0Z+f;DkF&)~qrZ zup3#ABM24zO`gCIVFWrB$;R+3eyq8;V;KBdSikOQZzbR$$l_oSRoEiJ6(6qxpi6qz zfiXX76gga~&l-1s!(i{wTleSSa-mYUUbF_o$xmM2Ov6Q(D!-|GP-O4y$uwJo(y;dA zvt8s(?x#(KbyMY$e^@kFHvU=ZnU&kp>FN+`w08-wP)|jHyV1|sYy?NFf%okt1rt#G zVzv07p9y*{Umn#2dN+dCY%1s%b1iS3<@lv1d!#z(b%z25#ix!ixz^%W;}=-gOe9$bi&$2Yo4yI42`Jps7s$IiF<% zup4#Qg%gZ+ONxxb`Qy@i^5Y$yh8(P|7oI$`%$`(lard*a;Cb=Kb!dGo;HJuOIbBx> zP?u_a7Xn@<AY zq2j_rvf##3J?CckL>E6L0N9d|k@06L-#2f?BX`3ERlL?p&`z8`Z2X)&Rs=;N_{zd7qJ6LvcKbpHzvt>KEa70 zKeOX>vquQMxB731eZ*Aac4?!%(fCI_gEZzs>J~V%oiK5kbaN&r3y-CugzEe~8zG=0 zdc}(!_ulIk$>+YvQ*rJQUU?9|#c6V?@f6USTVWk&CsG(STD#Ozfc5z%w*9hZW_XIS z5yqAt_MT)Xr&yLd;9Vf2>JeD1-@nA*^0X6gKonInMQ^ke%0x9=1vsyEd@2tgTchi& zQeRzaIzpesNr*G(ZR^5t{iJt?R&)DpY5P*l>+2Ab=hC|(`o-}!WGt83)PApg9%<*{ zHN8mDzux&7=O>^2DCkuW=px{a1hiME07FO$zBJ)sKZ{pmTI$I* zLU-YFMZ5c`cBQuZE zgXZ5xDF2Tt@4t@M5~vf}pe$FjcS#9Dv?OR@1|3a5xx)zhBwpuIg!?@{9Eu{ngqz9| zwq);_%d`F7x%8c53FZ94A`eJ>kDg9AijH^e66P?#_LR}==rD9JkX(A%5AvTEznB}H zwSF7}&ALMG%fK7vR1Kk&-cvQAwZ6BWh#TUZ1`$u^mUe1%+g1eWUYK0N07iMVENW&< z4?m?;M&_)AY=$>0<5N(0@TNlCw=nv?>DI{2iSV%AUZ$teW;3R<;9+96Y1>6UWPBo>?Xp2GL>LxTcX zK9+YdsVal2{tGRswB%_;E?vZhD;HU|e9;uVgX&mz8($8TaSqD{|GIBVG1j}mpNK6$ zE?2MYC!<{36<}bU;_Zj<&~}&#c-PBxByRQXKYy3F)s_EJ&z!5(YxM2eJY_4aM0*$? z9JdIwk<%1Gd}y<;{L6LmR@IX0sDusmeMMaGkW4TD70&e#!2zE1`?XjdAT{r#i-VXdnljbZNa;Z`gs9PCJbOqbzmp6tM9B&CtE@&HjrF(YcRCK zkYPzvBD!$vPv%9u^~G8B7{Ivby#l@qe0(-{vmdR7DebYOeu@h)*ujP}*%X_7D7>77 zb78z6Kf6)f?{|h1pAoDP>ew!uE*IWpn1q2v?nS1a=8V`IbEv1H%ofjU6Z-Pa@B0~R zomciKg?*;L7Da7~w_R$3W&XiTgz!k%kBo)SqV<8l&Gm_5Tk!*Vlq+95nXdLlOZ&n{PB{tbKg<6aLz4Vo$B@UbCs3kdW4utBX!;l= zAk-3&9m1gZIpDgc96Sl#l?OkRq?T3-B+uA3jXs(;U7t;yL0H_2k{-g1*G#@>x=uVf zvks!Q(YqmuQv5KFgZZaepLGzxo(gigei?5Ku%o)^llw>Dlf2y3elwhkus6QVpm?e~ zyCaFk2&gUE%=#{x>6mCF(dYu!%yj4d+TBq8o}4Ta!eKdC?3xWV4EVUEF`B*a_+Xx> z1Qh0nV9a>5E}Vp<7c>lj=wH3Qc)n&)*7yr+|HwMy@-K^}shK*w%J->dsItkac7?&s zF>&3DU;XcYu5#i(xBoy1-AYf~;YA*8=P;eYW4We+Ay~K9epv$|G!YNgxF|{I7yE&t z{raBZtoD7vrmIjr&+}@VeR#*-+-?3^tyYrwIQ!Nd3Di!#LWLCH4elogP0_;+m)R$?W;wd^N980lJq1NGzjC|ISh= zu8!3;&XBrf#24`HeKs%2Nmr9o$$^X`A6HmnbIJ)dFJD5Vg{mtg!XWJm9bHx?dP{d6jgL>@QbG#5VG}Qtd>3DMByEziI zd|kc$doW;YRNvle##e7mK2O?P&FvX*JUodxfII?C0*_jB3>{I~&(j2lB`eWi%v8Xf$d8x zqWzSuTL7b8zmxz9p}RjBBln-oS)*Ph93AB`kz9B%kT{rP672#FuU>;(HfznCJ+)6q z-deymzt!RrSxD^cElc`}%GFwu%)GtuPTK~HI(w?(if|LxdC+vQVw@6N!qWfFO^xm6 zZ(CVkkhotRQoPpH($d~6X=qcXgj~}wn1FHs29v>ngQk8S5r(8)tU0}X$KkUNnr!QL zsu0#~VGc(oEFYo3{j}@iV{cPQYCKFdlq~_PHyA8U&H0{;DwOqVSs_4znV&pXvv@4`udi644}|H z8CgwJQ=v2~1KQysuwigt7vo29xiPd#dJPwm@8~`|{R3X8>)hwyD{EzKWohapp_P)F zY+x3IPnX1;Uo_Th%I2-o3%Fpa-3kmClbRqqo#IW-UCAEf=U7)A8(5-t3hdbJ~U6^@W*s;?A|@;oKW@XY!<% zeq!V%pePO7h7^*ZQDYhx!ibGKHaCxUw`>U8nCT_WYvff=q!x z%w?mh6;bXyy)6p-sv=ly493yTU=d-^zR%q(6k`7PxFaslaeOY3eKpbO&Z$;(+MRLP zCgrs{nqW)f>htn%ClEenXBNA+6PBU}fr_xr?Gt=1y zoTJn6Dx0<2z7L4ao|2LL^U*y)ypt=e!K@y zuQb#Ad~!T}2)%mX5^s4*89T?|iFxnFH(u+FZ?3p~O|ILUT{o{>PB&P@f`2aT{-g|G z9Y%Rog3P6L-?5wFu@%_k0W73!c6$po*06`ZrbtR;Qt8v(0Uvipo<6C+_kmhRKHDOj zA}f!Oo3oV*8t=W5hH?3*uap|X5tmY-q}9Fh40z+*H)*?|nBiWzDkGpnk~}aO>+SOHC4peB<2G0&jq|c#?R(rI%2A*n|3-jw#{f%9) z7*Jni{V8nMAi0!TOT;fL`sz?G`?j!%=;!QR0J>J$bMF|r!I!!{t?=aD$=t)*QNu*N ze3o*L5QQXLFn*82?{*U3`S(CuzCE2`cJsRF!&w0^_Db8;3E}DAla$sgG3QjD+VCdC z+}$r(hHMuKocK|1btBr9`)vSy>7c8R&myLRH!Eeb%djr7#)>lXQaC8cJ|1G4QPbT_ zT}NW#J9BP>zd-EHZr--XerI=@7!T^atO(TA`8Z)RQrdnCyYvdkHrmD!%GvI1Kc4~^ zy@=UHgEL&A?Rz1-ID$oIc(v;G$ejRO$*rY6x8?afN*Qr=Uru~%gma2xCWLch<^%mb zubO=>1c$fUt0?2DJNF`ODcB@@KriJdmonIfJv z3vu*R@|JEIBU%2M8Lk+)#kilmjHcx)Dikv63jp7ZJ>A;{W1d_6fcNUG9x+~yv*+~g z?|T-CO(tlSa`eVz$2B#*pdbVPu+JeeIgK(K5`L4|ssz&bllqy)>3iT;tli4v>_FGe zQD;N@46C#ey3W}NOgq#{&DZ}%V)wbglgaS^;X3=ZA6bnLNuud|FG*RQ5SX;^5j{9( zJ18oiBa1v&22)8rXA@hrKm1Qk6w^?=Ti-`o6$#GCuly?17VkOi!n+1L#D#vh8>yqn zntn~-^&(<%r>){j2%ax5Vy|THkI$Fe*w{@x{e_C#7ksw8x!B}7;nZ+pAxR)-SFiMT zdwb*f+b5ydbG&hFUWa9($UeH$4MOLc#GlJIG0urst+z|34_9rV_A`+V)Ybdbha)d& z>$ccYiYIuXp#&T2iR$!{7|8~IOi6ibYA)du7!AqL9!OmHdH&@2YPnv+?fTMTNLU!z z(Ps-jp-n5cb5>-=BDCfBtq2-W2M~RKjbjx%^EZ^~Gao5VcCBnJO?^@J?2hY}1u@<8 zdEvAKlwsMu%`6w3Dhd#@#e&_y4bR$ZjM7V0jDD@U+%e_MsB>UK(lGaSvi9ygYdyEh zF9{;l%qVP^1(Yl!gVWu8M5<=X&Jn zlm=*^IVJ0ZNncMTGWHr)}BA5poQp&~P;3hJ25lG=2gFjt^d! zh|XsrWmj(OxKVeFjBwHC=jv6O6;;JObC5`2vy?y7kckL?J$xMP?l9;cdJ)oS)GOR` z*85(Ihw@^t7R%fz?m7|-B6yG0NitaPJVd;9a)<+LZXNJo4m|(v#^!pwUU6{XZsBMy zEzf*Y4BElaJWqyLZh=!y!&5|{ckq)C7~Ns?vpju0?QkkdP}&jm zdd8R&SQj<_A%p&2nFrg_0KhJF9l?LPx5)-KN^ug8OXdYBi0Q{g6-OoX_tl%(;rMzM z@Er7i=V4o#7sUv?`OEUH#KGASm~%B|!949J*AvJmyGL1KX+ZI|}DEas-9 zZ|1THdzWpf+h#1;sFJIe*U`3K&t?125gfwF!P%c5+YXGO5Q(wY(SS?b2=VDAVqQ8F z0*X!5(L+geXJ@kf#dk>y(ZE_sH?HyPFzXMu@016^OR(o9Ds$=vnpnmr9w5Qdjs^@-qoYJUBaFIF4ldw4j^J+jYWZrw7k~L|`Kk{?{P?-|<86mj`?^Sn#`0DBRe#I!J?GQiSG+Oo z45<~p{ww9OHAEuhvQx#*!QSUkT3)OlZ_~$p{8M%Q<5;Lwo=2De*@*oMBC05+VzNp)#+L63j=X(4=@igR zvZD=Uy5hsi5H{d*V{bLfKzijptsJfczsU})B0JLr#iuputa*7xZC)jI&wsBrzIr9o zmsx=SQ~vjATJjqK3f8YYXk@%**GAt^F6izYEvQB!yDy2XC?f1_g52;IttrV~f|ptH z!7@=-!csSTik_D4kk^s<_U=Z;^zTtxYq`y2_qd29Gbn1Ky7gi{E}$EFZwy6FM@(snjL7?mcJ4eM1 zmxC?ii!av~< z{aD9WzG-!D)|M32DXvVkS@Y*KkPfBAX^J}wb8}j!<%2b&N{-x*E*(FC@*uwm6tUe& z{mmAh<(Az3FU{2V4kW_2KC~vZs7)R>gA)twG`*Bw3N^uz>J$ixu?lC#^EOXqR-M@V z0#0ujEnNk7R5HCn4u4C1eR+aZ#{2o?`NLN=noX?f2mL=_%*|~7b9~PIQ8@+?*X0wbrxd<_HFJxVX%KY`ly7i~2Sxk;FZK>Wg4Jd& zNHQ~YCZw`FUUHD%%MBomnq_UdgPV*m@0k#O{w|9OB_@MHWrZtGNC;?N`1X#3!K}<<8(z(aTwL zm(?yAA&-MJf|o3ViKRPq$UxyGCSAVi$tycs99!f_-+TJJ;|+FLE|qs7Ggbf^(50?z zG_mphh*KrTEqBGLxXa6Mx!_9oEU#*3q}sARBB zlZy@M(Gm*!#C5m+u;n!Gte?2&K6&s{?E|d>cMZn*jR=Q*F0epOQX(lJyy@eLiD zX?O6I2lpnAGlrX;QGca}InbT{+~NTZGPrpB^B&in3A3(fRt_lV>m&N%_N)RX_iux;R+v{|{KuhQUgkzsSW-|IP} zDsHlGW$4}!AEW0#o>DKE@#)cNsnR62XmhWKBy5368e*UR>1f81)>^%-C&**N1F3n& zT|nluXOHJVX$ehC98A6g{R?i?D_TE=PkYYw>7)498Nmn17Rw`iZd0k>>MYVICR|4J zOJ@?ek+ba=d1aMt^l~Exalv%Xof&!c8d2zEw1xzjxg9?8J<0rwzqUi;g#`Eo+#yO{ z?7N>e-ikm|rTSA>sjl;z1HQgZqk?cohX`%KI1%Zv0|a8${kIqAnVSwlqqY_`F7&20 z{M$Vqd2xk41vF)+@uuu_o5;Lt8xMdaA9GVX^fvoB_{$}wDGJ`gG1N@qmXu(N`VY(+ zWAULu-+n#5sCrDD|6fbcL(l7ucTz(PYr5UK;R z!XEg9?mUoMGP|pzKp9~0BH?G`(U?87I4WC^o53}1F&7ONM$-|Dut8rqIWLaV?vTu} zsAbpaBHf%zv1O`>&yvc+Lp>u^?P*k7=S%Tm_~8#r99zBTwfdYnP+d&2sD++WWqJP# z{m-YKomd)MUfUn&C&2pVbvb-h{X*}wzt&Ek9?WK;UE%0s{m=z%Tb;FAUppr>co4~px_Sq z0GcnhE{@iwY`$B34JtclldQJ9pjY{P!tG{`N&Sj@{yXgK?HEQ@ZGT@tnbRXJ9V+?X zr8WFA#Z`L-HAA?7*LxkzQ7A*M@J^6=XcTaH#WsLj{-%0xtZC*<6`qH^(F;xa$#Yb! zr;SP{c{u@MB-N?Hr+uoxPb)Nm&*;b0b|wf&hxhV~DsKxZhdS5HSgE|O@=pr^caBXi zyE5lN?$d}qf8=oNV8=rPfMX%kS6xGlh~zs(WjjT#5Zvac`Jct_2a8RwPVZOlO^3uR zX>iB{G3@d#2WDqdf=d7=s6y?oIW{(GF#>?@=+Ej~I{lWx&M!9^JNbhFbHvgSMb8%A zaKCD!NL1zN!h0F916@v%)vChC#X*qKC@?iAawv*9u;Aa_x=#(@;-Z~Z%XMsZ*Pcx-?`Cj zi!2Cq|EL-gWO+Du>N*P^-R3|PH1#jL&jy2IkVfl4u+1nJ-Qs#p7|heM${jdU=`ZsZ zmooJ?@k;o%o8so|q}P~4;|urnbGFj4XkpDSrDHw#TbA~oy)exC*nvGS?Jb|t!IMsH z3v?d(w-d5Cl4-cIq$`aOL!bK`b`Gxobl&34ex?o?D=X_M0DSIO+p%??a zGs4Om&_v;=A%2>=XyC+bs@&LvY2*SgiDxeS_T-o7zG29QOoF7K6T_hQSISd`Q_@{#?wWhSHNtKXcgV0*PGzQ*;>%thrqD!P~n3^jmOu_a*9 z@YrJ7(;Fo+&7|kf=Z@k-)x{XiP+MMmTik7<3)k|u@7&?^Bo6lLtvBU<=3GhLuUGGOfC=ne8ziY0`aZ1rqe|1cT?%9D3mb@kaR80R@qd56 z7so;U29Ubu%6?E}_Ltyzl#MKy%! zi_k1R3E657fG*qb8}_mnDY4nzJE6n+pjSQE3X9{kcBo^O>Xu4M7pJc2rV|(@7WKIa zWe7<086+TfgRL9~pg}y1Q-D1Sgsl(Nh=OY#U zX`D{C*ZYC-o|$Yz%dDNF&ok;tI(0Rz4#ma0IqR!^-Oa)<~5>7c4KpvgMaYkgCPy|wDDi=i1@gvqgv}Q4M)}H8TzT&m5OM);=0o=94O8FYM zsQeW;OlwoYaQ%>^XRft;aoI4qa*!x-y#A3BQm;#ts!dTTvg z`5)t2HV8;J5Vb|jhDf29ohW_$hD-vC<@%EPq+Rlv-TuC8ky=1Oiaw8ECz$jIf*&Ce zokj$L+&DTN^tfk9ZRsQ;z!>F5{u_}Nae+E6v>mcS^Etvut%M$*Jq4O)Np8Y$ExTf`*1@kQ|`CJc;nzs!Mxlq(ubV zwQ3n`8Iq%;TYiwSvhYek71?xBcdRR0=zy=u`b7(mc7Z$J+0b&LNIQqFU z9@;3ixz)1$brM`3vo|haQ@*JT;0JT{Vdr%$MS??}@aafJ#R)q;OR%Fdh;sw-?#=o{ zyGd~j$wQtKvQeN4Ob;}ih@^^N9g@-^^L0^Z$E13wK5y|fRiyRR0T`B*e~Kzz%3v7O zscFI}0QjnNf;T-2TTW0M{3Lsd{dHuo1*Yx}w=GQ9J-G!?XTOTg)E+Skg@)o%22sFL zezE`|Qo9Ep?xsVd!=(p^g@(cr|3tn$m*X)BA>Yd~cCO04gM%{hUcV(B3)_)yx9IU& z7=Jy}o8K0R8?Gece`~w_P(%dj!fvojcld5KvfCk8imntoPqfzh^4b}&Kb|FLPPC2C zH_}4xVc`^&>cL5a;2-Mn7dVXiB|3_K&)>Iazx>y67+yibUDe z+-En$^qqgpKq6jC%r&f*C) zoR*szxLWUOE)5lVbq#cqZi2nduKASee|Rt?h36 zL<}z(6=VAZ?e~O>pn{B({dEjDo7j8wsq{zvjUCY=#JObR*4*>vf7D6J20x>MhiZ;q zOr5+Di3&vW#W7>*pT>w@YygF34+f6zM=DKQ$FOkDMb;seOsG)|B~vEItf@@b)0AGS zII4U56)xN?QS6&=ON1O5pL$5m){ij8|j^qE$YBbo}kg% z%6nImrR#vG_ty2;5UB$+UN9$jG=%q@dom}!#nagwdxzKs3u$1aI|C6}G903^3LoVr z2);m5F~Y(Y@!q2X!K6d%!Ggc+WS%T>B#?L>3>PvbM%OJoX=2Q~Uiy1n5X~BdwWVrs zbQ%f)4KXosvOz;rO#MsfXWZjG=cV7lN4r8Ca{dPm`gl&^d%IL|;{zf=+5}V;qD;e? zRH=}w*EyfUbH2_ZE=}ZFOEFAPXU3{fZZmren~xcr9=eJxT@f*wBafCOe7N$y$9ZKH z_YohT_XK^x4)GED0Q~yI<4rVeG&WxPFmG=U-Q8t5I3M+G^`sn*`{c81k3dsj5sxU= z&P`ZTLv^#9^|fIhV$Sv@bvd(vuVb9)J?RQZq{nt)H-9-dV(1Q5{C?`XCjqQAji5|h z8eRJ&wH%;|Av|qv79T#IC%=nA1l3)|(K!D=~*?F5gX zHd@vOkhQ~fz-m3KRmT(_VRr#|Oe9C+zU)_-BHfBtKYjJBeUVd43>Q4s!5ZwM*Gn#y z>97| zCm-Ki#UwZ5wcyCA(}inH+mazw+e8_^ytmWN<*vbG)^Yl28w*UPlyRT0&7ky! zz1fLI5>Um5rAb#tX5YhoGQY~0@U&|5sffg4T<6oo8NF(COuXcJp0VtYsuON=*J4Bo zz)^m}AYMJc^x$j zcGoglBwfAN{t@W-K_fI;phBys&L6X-N0=XDvM$;Fms!LfDND%5S<25;dM~y!EX@yB z@y*Z7)k@+O-uguS2t^AIq5qoTg*j^!{BAGA>$iqn0(&A2RIy&E#s^2M3srOu_d>x) zHi1{RN~PJ;qSY4_qCEc8Se~$_7dFQr!3Q{&nbo}eqw;;`hL1w0LF#e)&0KM z`R9bq=x<7K^Buwi!kx9<*e$x9(6S@BUazaSZ%*v~{yd1@c5_%)!_f%fe%e;S;-fmZ z^tG3wY9OkpJ^Vyc4%Umw@t1r%+Mx}n11AY?)o7P zk?oiSxBLQ8b6RTUu;2G&C?9`F5q36L?LTZ^6f$qw1_f)*jP=9XC`UMyE-m zCI0^&MM3eI{_8e2*1Gq{xB*;y=TXN_Z*#A-w6q{Qid&5y!#V-dNs!Ke5vTu|3jZae zKw4%(xNW&Rj<@<>M|tzSsC=;J&s2DOZXepV-0{v@ANODQ_M=lJwgnCMc&_eV50`3yq6u^wT>hF!A|>$?oTc(nRm+bK>09v zjnzo#;GNRUnmPat!L$hJ`B~{T*B?Ilh5Nm7Bc-!O$e=x`Ph7RAlxgY0&}k*)hVArb z6rv^n(=CA(Av=1ySDL!9(Vv(=12Utk#M(L{sh2f$T5M&3R~XiohTcfF?OSNuX6(9W zJ=x*8Y@OROFsj8sPF6H_6ccoxwrv==a=B9AUK6tudF&jVz=##+bLq|tz6*@b#J&Sz z?fqCZkv&qTDW}g+oQOF%V_#>x(@~vEZ1(U@$xHa8>60n*!35aU+88 z>-*r_Foc(3*(lK<@bkoefSMdxN=k~Q=@(P8{DC~W>CyH$hE>%{o)8F3e_?UzqW4HX zYHa#V36+E!UiK6Xv<81h@UHqKA*zLpb};sPg))E2d>8lZ$8>2ue;XzO^MvGC?!cRH z?u@s3bw_F|6BAM|2hpVp) zi>lrGRZ$Q{kWi!%hAwHz5y_#3?oMgx1_2e39=e9^Zt0R3x@+j}7?`2q%zpMh@7eG9 zG}m0$`mjE%`yao$UHznJcfLnn`x0O_+*>)TG9&BMNJAl$TY%C@y5g{n!7+iWu{PB9 zrtY$f3V5H^GbUfh>F(48ecR8moZ(&3E!D$iZ?2FMX=bF9uOyIjs8(Jjb^7Zi>BllI z+tkMR-^>J07^++zGvFB+%skr9NMN`5u8}ev+0-D1UQ6SP;iNp7zqO! zNws4e8|w0GlFgA`;=Kg`v2P@6Sza4KT%tdtGRqGw0WG(jpg2ZZ0^KP^q7vTCy>N6+#;gFS znxw%O=^4G090sadpB?46>mX2B z+42)OdqNoO36FIT$+3vTSYC2{JaN+o4;wqIE-PBG52Um)S9=@A`+RvSd7Wyy zw)?Xe42>FIqO=8lD6e+f9j8MM4BnOyU{HAZA0GlBRB) zUr$IpI5x)!ioX2w)~-ZGeoxEdXq(xLB&Sr@m)=piVsJb!#_pYWlBf-cu{(6c^`Rbs zeFZ2$sCE4D`uHz|?1DRx@!j)Vk|5o|poi=~@q!G=rqHVOdlzY>kx{rrm7S~&2&H2-I-si3q!}^ z(`3kvOz4>rzMQscc8Ti#pTvyvmUy~w zX*ms+hNk+1L4MHoJKH_?%7-zm+cMKW&)*E&Ps9Trl{4jq+jg}J^z3aX>_Y|(qc#o< z6O2pWYq!#dvjCZpE&E#bc{YB22J@vP4QOx^B~ODD2~GIXh1ZuxhQ5W7aNlM!&T*AfoWQt=Umv!LqCZ~(xHTynb0l?H_%iM32oC>)(JvMK}rmuQKrTG9fEU@;`Op z)Q0M=5WAzZPXOg^M(b2jLLITfJ#w#TYZccO>Mw24;Lpx=XvP)nZ=mD-G)EmcE>7oH zsVGU$W&ZB8FZNY{@7ZQ7#t~O>2$V&1S$n7Ft7oP zmhymK9wy7xBcd$z4ohlTc)emY5W;5ynAhKQv=S_M=Vlk8QurNUA%wjQsA>ZkSjO>y z-(gXWU@C-=A@;Sj)&sqGi!jB>d@UJbFL!`ZHYZ})>TN=NEMs3Wuw1{1Jw-Rgi;XLI z-B0aPcw}j^hGhA?B*hK=B?Ve>mvI7`q@P%>UKrUT_FGo!BR)ZPt5l~tkY`61%Mj(1 zrgB4kyc*JOrOd1pLgE2e(F@`#YyF7d1kVcHxq6?Iht{cjHyH4a;~tlk%auDUCopoB zR{=mTTgy3Q14U)H#xvE8CbrJFRI*mqxoASZ%BLIS6ls>$Lt{06IpPQ+C>%ssj(xVD zT}eOe0S7GF*f7+#x+qJ(VNhdHSkrFt?>fLd4z=;2jI)f2L^+wSt)?WG9#Ah4Ynr0( z%UcmOb*rF2se>TV+Q(EFW*!u!OFMYSd@c}(Bnom32p;9 zTCvt!_mBs%5__x1HznC3dXdeJau+;%e=Pn0K^t<+NjN$0r}*!DN$T(%gJci4sALfR z99b0LuCBAEh=bxW+nuEqLDkPR*U2gAF>D9sL|;h2L>r`w`v+qfkP9zn>A?4J{7LB) zfu6_d;faKcmK8DH8PZL=$m`!~9QSrGGL}Yr9ezIroqc~+@v`@Wt2C&OVBTi$?Vks> z4#s}HRUSJfB~VX-yNFGcoIk+x0<%QM{QF%@B<6T`GakZ(z}UfUue{&rN;#~F{$)xV z?MvPC_W9hdVnIKV7W_K5Rrs@mhRs~_OZ<^4>z}CGfT2UIO^bCluK6bVGyaEawO;sF zZ%*JlmWxAzdBohG%1WkE3*Cpi+V9(wU6I0J+f!9MDQtx^GP9fWl>!^rN~$F?1C!ui zuCF@s>4OF1Dz>Bhtpcv#OQo;O+3ZG?>2jUP&zT5cyvT$)_xMqZYb8I1mtOMII=QK^ zPD^6gl#Ts8dtp`9_EGu6e-8v*^@;b0P(ujGCElxtUQCRKQ{9LwJOJhcR>XtTq1S&e z^_NmV{9#?QZS7mc0=FiS0XgklVo{Yd+$cVCk^j3J%m7i`7q@pF0Momh4+DK^@1uKw z$9et?e1StBE88f*1Nl{9BCpL!@FqmVb5_lldODm4hF)m&ZdA{jPJ5H}Om=Vu?qXAS zs>EL{!&+LpkQIXi+FMSPaG0@y;uD%F+ENjDcr|4U>}WVb_%5!zUyh@hy4Fjhv`pwE|WZKUz#7Jif$td_jOaoe{eJ$fpX-=yJ)z3&jF&8rc!H! zO$?7&=5CYmpCz56GSz2>h5hB`30@TZP&T8??jXv|0=%YOW|w18xSAw3i1$ZL zv~gr#i@|y^=yFIL3A{q@)OKxQU+zc>2SupYd!FVhVgL#k z2IZ4S`ZM$_?_LRs&LkKJ;7|Z`#}$EELHp&&X5&A64hIe6ZfEOFQcYnWE_S&e)TCPA zAELbB)5I6P)nn~YZV36!W^Kdd6xsQ?Swq~^8;WfdDi3n+LFk%nENa9LX2_uh#UE_% zQ1R_!2ljDmkQ|&DP^N(>9eXdKp0QbrJI{XLPaAeyiBx7r# zksewRU^TPq+38X-e9pDy+IJug^ON*%wP=u%U+O#Y(*eMf*lAVa&apP-AN60Gu7m_O zyCv@8`Hx&!`Tm0mT+se|W9X`XXNq~B)!*)af{4UY#5wn;<~(#o^**yvT`Jmi`EOO( zvP_~MjGK=5M2?yPgKL&p!0k7+X?b>YJ=6Zb?Gj`pfENgdj$5IMo}5e~e`$LB!j-U{ zQqC|w@_s>jbN1BK>7@NJ zUH?XNXY~ws7PY|?>y+xf{o`HGjsoj<4QJSS|Akt+Iw#2o;;18a{o7EjvAI+x!67+oY7@DN41I{^<5 z>%BmRwp;j!Y^|@BmnZR=6oga*uk-m~jL2Z``~+kWNWDJ&!X9`8H|eA6yq#8q<+*D|bwy z4Ct{Atfq%Pe?Sagk(xWfTiw(|E0SgyR-qCni0zknHrLRw+xn?VC+(pym_dsa7V5kh zbf@9qw|9{l>{%jaKs<;7Ae2RWy;i+u7vWP}*FR@wAhufCz9|6WHbaE0oHgxj%F3oc z2P|!5$7`c+7b_wqAiw+6`fKuti28ta6?{$=K?x?xDR*#9NP<&-mpi?aCUe16G z4h9H(jWwk}?>i;osgG?)4jV+hF@#8>j}-7)q<{9d5zBpuw(wIYEx#w99;0vQ<>D7& zsjd!1Pxy8%Yl+JbNG}X4ezNgI{U{eyR7vWk+iVp}LK}*TZn=Rb+u)gv(>MIN`=ViV zq~#u#nN~{l^hw#^@|~m=4xf2cl$K1>CHbcNZ*hI@a0^vjO2M2B{Xp)-+&5uKBU$vQ z*`Mc4LMJmy<$~$Di3w;vTecpq-c}2@^ISRb6!1POfl|+YX-}}qJ2SQEn*M$@FSE3T z4HOxje!?k{&VGC%$ohzP*p)f@O$AR+c)O)u!-y4he*l5WVhMFq*1Q5HS1w>+7yDpV z-#4`#bG$wLH{AH}TB76AitD3#ZGn>n_4}YsjEBc+xU6UXlOH^Uqy;Gc%Usyb|AO8S z_p!Y93VM1#^t6pKVa0o9$Ty_@Pi<&JIRkV33AdJgkq%usAw>S-im~4~?@~ShFL=O# zuVJFyA%W%}zzuilDeU}X;atZFjc7vgi*__U<9_A76XM7Am9~OM6JoipB}{~*qyHXN zYAz|_>IpSknz#{j*4jh@*ymhJR6QO9m+&8sM5BPWe;GFG{r1-((>4fHeXDwzUPH-D zP#v7Ds`UJCg--T+n|&Lnn`t`%uk(Vvs?~%Z{n9?9&5ZiR>3VPMZ2o$Hz#djV?a;%? z*DHj2gBP-KkDAlb(_DLtm^e1a{Jo{B2cZRhDMPxG3hHF%?d0#Ewm#hZk*#ijX(P+`hfFKP2jlyB>3C&^y~#QeyE8 zIdtkJ-eIP90`Dr>VB>^bMbV7U6}*x&qQCc?;O&~SAfsLeFJh>eCWC!MegOI?2<@rt5Wi5`1;s{Hz`9U)qXR>uU*w<`+ zy6$-zi4 zMmuD1fUJ$0do)r#)BD%@R%?!eK*+Drk-PeeKN9)vxP!Feg<)o+`?7d9wmb)!eqx|+ z03lVZi;tkdNKsT`s^HnT>+lC$TF%%JY(s{5s=IIPHKGui>xnlx#WImd#Z^y zDEwZ$?@%dIY*l-Cy?#GMXc_<`Wjpwqm64!~r>;velP*H5z5Q@1-y3B43RDJoS#{fV z-+7S&`3EaJ5`T(bHasX+;9;CW4>Ut74_X#|4@8iR{r{>9pH@;Hqq-GOpILSP!o<1n zCNf0>e-7({|7;$YQoZH(2W{#13Laq}%!JWf#JhBNS<=cjjvOC`cbgNg9!KpUbKOE-!ZP7zYx7kpouKoT!>$r*vEbdnK0Uy!fZ}PK$mO!@Xi) zrO6xP$|>z7uPVn@)bRnWNXzjy5T)GUd=ufK?0?x_bZ~gI7vd%t8d_CVm9>%YmCe3y zvtLzLM<0ww#crFyrWElMn-y@T-z0@Fq>+xGjD8H3?Mjphb4>q`19)N3Sd#yu$}Za= zW^>bA1QzPHEJ?Nhye66f2O`sVFY{TvHoh8&)Lwmw2}vb7BApx)l|efQ3(4VsyqS!S z#*wDSQB3m%N0rzg@xT6>^(R&}jChGKR0emx0*P5WWV*U0Np#S)5V%V`$(`Sl`lC=c z>>;>>rhjc+o5l|hG5~K1*=5E>nLwt>5Lpc0YLX=vVJRYVS3U`irOx&765V-K<0tDq zen}vwtLS4diKVk)tlVXaFT9{ya{X5db%KSrZGLN-n+QzbCCFoJ1#;b7=IkLG$g-az zB)1yEW4W=A>FIfSnd-9^^Pqj*V&_JG=fjvbOnL4^?m8QARl*@IuonAN3}Ru$O_TPB z3K*=c>|KL{d^4*L+J_+Pa|N2&{E=9q)WFLYDhYjd@5Kn58*zO@D~-5v;XCuI-iLF; zPJ`Q49RII=KI~z!l8f=%_gUq;UcZW-rJAxmaw#IA9pSYo&gj#;WHo|Eqk~1d1m+_T zCB*1nXqe|MY6NBwTo+;A%5X9K9N7=CaVuIb)vf=H!DS0nfqrpHqlMK0o?rXr4mJPw zDEQv_n_%TyVQtkJ=pbUx4QU^lk=l6nCe6&kQ6QF-|x11c~Jw| zHR^qQ;Msq0bofpT-->`VxVtegM&{jNgcB&m6(*#AnSOonS7~Nlq5~ZaFgHgPcR%>J zg|ev@r91xTROs3#F)clz;Yt$i+~q?(?#Yqp2spRj=;~!}Se-8lF7R1tOBh=aAhCR-J%9V1)!z3r<_TeWqegn1ZMNU=8rqK-$EvNx zI$Z!wx!C!x!5pGZdn4w^vr?T^S@HF$N>+A@zXJ_z@!zQE z%~XU6cx!z4A-tjFgO^y#YgsxMF=`X6zVz#0(+GL~yL5y}9tc*>;b=&|9LzEy0LHQY zYKC$pYE&qO3tw)xU10r2{euH6`2T}63I^y7)sy*yEOh*}r4nyx3w{kCH{Jeu;vZGO z>*qez?QJK<2ZjaQ?1UHtRu7QAp!!$;*g454054j%j=R^R!;sGGV=NzAD6#3ZGp6^X zQ5U9u^w-OftA<_k@4W^Z_czrEXJ{dTa$NsFdi4$R%Cfo_H;+l~;J9l5dp_MXOn6N0 z>_=)B@`Kx*pA*rU?9<13KXrJBd`E*RU7CLx`kX$yI$XYIn_HrvD`w{Aw);!l;CJ`a z1!kN>e3_!DH1Won&m|b(h=lbG(_8BsFlsOwhwv@PU<0n zH8C>=kf=Wu6`!U<2?}Loa^{5R!l>~!bsAUGmawFbmTGbc}VGE3soVxUUw#& z2nCwiK(;-+$PZJkYI7!b+v~M--;tH89=Qo=y>vsQmV$Af?XDVSNObfpl$^Vx0LLAE zmx14fq2CJ3#QInWF4s2&UFAGR1lYrUjmMHg{Z|AGyg4NgjX{*d2N z>D~|cGzt8hbDS84s*(c{TC9uKurxSHBfO z>bVOu-N!|^rgr3o)m;@8*-P_g3R8&Ax%H@ukpP{{!TZ88_*~54p#m+o>vh!(XVvKZ zd?Ue?OkO5#mEkx~j79Z(w3JiU3(;V_toZr8a@0q!je@kDZojek?<{nMpW*>=a?M_s z^Snc6^BPdbk3fEDROmvpr)phY-Dvz-wD?cWKcsVbsz4GJ(}>>QAr__RQBT@k`u7tu zB;O`j_&v?pkdWJ;X<3>q#WL3Z6)faAGu&7)DzkUc;cYfy>CMAaVdbw@jvclb^k)G) z-dQ>&dbNc*g|NliS99IM=UDoad~{Zn38#a`pdz+esH{$|*$=f(88lr&VAET;iuSz* zNmtwaOE7iN+MWkBxMer$wzlm&c5>7t%9%VdrZZT}<4f0RWZajFq>&cD!}<1u40HIK z%sl1!sQWFt-31SwEj+3O_m=fiL~XgBl>KsZ&d)Q_1w~8EZ2?d+S6TTEEEvMeS%7&f zw?>YYNJC`H(8skiTl)0VZxg^iUE+W&^VCruPJJ23?)0%$eG%fmUX3ISKi;*hMccDOl2*jr0*op&N z7sMT7Z4iBkRG`D%LoPOc%)q!|vzb&I*-BH`&3ef3)hoh#D8M0o`5Fe$y)i9pzU3_3 zq=2p3lo8Z1;E$qCwJshVihN!9c7((z#)?&{Z)z&_PF^vX+CChehDDi)&PL$ef}TL9 zt^_UazB4{o!)wu$k_NJ_moO)}Zna`l_{*G44%EbU-YZvt(`LJd zr1azCD^Pz7Sx#PVX~mC#j#scYP)JSli{12S+5M6*@NGtzbs^7L6PNoS$iHbFduzb{wM{!|Z$L`BWG6o3FX9pltg)AOT1lg}* zg5lRyEoL_!*9{+{XE5FNtdi*(rx^!o+g0h1YGSdcYKlk*E zr!z0_2kNmB*n0n0m*;M8drfmYK#7N<8*MSCB>xX;xZHOcNp)v+2R{)p7G{>=y}T7a zX~R34hy=X;T*xeQy&R+e6YxB5AU)k+yE0lt3)hYoO0M}jR7$KE2k_3E?w}i|dytNT14%sds%ZX(pv9C63ql@kI`t zZq)|w6nby~`SgcHH$}Iqx;i_vx;}pc$Y)m%_wr@BE4uFqy+(6`^iw=jgwH*#N$p&{ z7o`COdTUc%GY)$TykxJmwe_Quw4w2uaVhooOv+JbV%l_U(dQT!0Utzgmj` z@57nV&SoZ|McmuPpy+DIU@E>9#WzA5hzToz{Z#D}j#N({-mx%kc1Jv5zyW_XBv4Se zWXcD?ph<@CzacwLzz8*+qg8hL<(eT{S*!cw;GJK|XYh|JFMYq=nR_Ka<7-!o$sN|6tm#>o_}6`@pm& z9{K8q&FO{lL$F1Lf<`^EjJC^g_{(KnS7QOCZwm365Ksm%Z27(q%RDby&c7UsDm=%a zxZe_ZA$i5{aJy`BAT_QE$-jp8z%tGTC~K&O%S$mZW&%n%uBB$i&03Pk;f`qs@gadH zk@~C2dxfq5!$QO2=JB}o-WTFRB5AJ)#jB{d{oTE#&1W&d?`3y<{U#URm&rAKOKu7e)K z(UZYcuZrUi8Pa4xm^P03*0-tDMC)o~~!v<4e9`g>`O4bn#ZFx0!YTS{1qCIf(Q2 z@P2acF*=LA%+#S)SEZ{F=yy;cjL72$h0c`bpIE-JiJ~_W!Jp*cnqNCBcqinim2Cz0 zpf9c~=C{3bRKRD>=UgrgtFRvA@0Zy+Q@d~r~6Q<|cd}D6N_QxVa zp@3pCetTxCkPXHy^~m{9NA*=Xl->r&z8b%woUQn~e1CR(Uu>)xT1%R4%TGFQWmiH* zgm`G{w0L%WIi^ZvOj(|=sh&3^C3ll;H_y@YLviX0-K#2+!_Qu(L88l&$WJ+q%&-Ft zv@CC>NghnZbB_=9UH?Krvg9iTCX&}!3KN71Vu`?HNOwQIE%rt%9{Z{-AtQowfzx2ZyA&DYEH8AM&&TkaTHqAhFIwgHpf?sBOjmr04B;SNY~0`t+1%P$1kg7 zUVp)4is8AP9lYUxzj_=ycU1)aQn2x<1dYtN1DVisJCG^dLJs*g!c)EGS|&j-&bdX` zwyshaj@9U36x3_589J8J^zxt-;zDtI{f z9Sq}){i)-Ovl#FZa|4xlMp#JIi?zXZ6WR}G$4 zyzs<{Mp1t3G|#k8DT#%Oe>7oz8WuKxSN0{hUt9e|SOwt_dQNxo9fq416i0Owj~sXY z%u1_2owYT)YWePgH4*zhX$pw-kuSbF4Dgvv8jg2=)uvSQ;-Ag>Ui@DMoEef$w(Z?J z&Qpfme~|qD0CJZWVppLQooAbuV938IyOd{br)NN+_s=1TUF|$wUk2Oo;M?hh0_2L1 z5N^p`y*bg7M|Z+>{r>0+Se>k%*SV??$9?o1seGtTaEry*XYl2$;Iw0YPG2_EEAjE_ z>2VC#-Y8djHieF54xtH9tlReq+bC~~i3T`~1r~Rcfg6$Z?i_1;_rk1vCaxuof{tl- z>hEINf&F1WYC7V8x~;yRR-|t zhT!hX^y9XC=C0=IU`7C1_4{534&U>4==!y#!A;3)d1fkF>&S>dQ1t>Omj#WC<^+A7 zEd0%rm0$X*>!IFgM0hClDNH9>_GhgWSE4~eYJ0ho=tT0=1nf&rx%vFQ=|)HhIRM*x z(caL_&CR^NI(t6XP0b7i=vh)RQHA6P8tkn&ZGQdfp8lgsKYEkDt78Z2aNJQno-C!x zbN_5yY7XzAyA9yrIUt_6%zpkU7!_RmMEb406f}P|BnPH6T^EeN^IuCaGj-QMbmY14 zrzga9zuDbRbl-VLXIDZ9>8sGJ5}0kEHl5F>4f5r|1))sy8Rnr%hSh}e8B36NZG6;9 z?JvTr$6IK#OEq(=zAE-0=}0t#8{?U?p~8-+jN7}mTTubW47#S42nhUWNju>I?eGw% z%Y^v!`kk$Qx*>;*s=M^@f-bKSu3SSY1@l?!N&OXvM@MBiKO44GFDriXrcYZp{sbMU zoSjN#74MaVxgJMHfYug`Vh6r_G9fRY?(wKeSxX9NICSBpJks3Rn%^-x-fisAJC$9! zXTQazu+>QNmte;8lW@9B->B-DrwVO8S1#P5IP$B77Kei=$RYzI#Eznau<-VFe*vDF zHtcc#?%f$HJ56NRK9vwH)2<%r3)5>->J$(c-q{@A7HMgu2}w4y^wUCYG8j3F?`7MJ zx1OtVEtB?jB7UQL0Sq08s}?+I^?jSN_c_%B!_htl3s%@U42he~tR5TbPUp}D>cMK& zFFPCtS=MtLcF0vZT_h+6bBZTGsh?BGbAK2TkyWAY9qm3V?I%Q9D-=%cIjwCl33%@1 z)L15aAsvfhEZK)wna)o>xHbI(dFcr|$hoo)R94O+M}x~|2K1n`^6Hofm!e}ieS!(g zr2e2i^@d?zAqr}pQBPnrRS-e{PuQ!I5eUX7K_O5 ziGJE+V+?vespUI3@d95-`pE`bP|aFi(l@;of!@mpY*}UGYsj_fsvXOA(yVoU0EOJ9 zoE?a{UPVuXqLZ=o@h7u`SpPvw%XYzS+xTUmf(8 z@*9gr1=LfYtp{uvd5!oB)4uZd-yDI3&{lKp9Cw~4qm7F|x(9^e9oes`6|!r~U$uRz zCo+G=BU}|;r(%)SCy9Mn6YE<{S zkP-cFoU?{O3ZV2WY><#_f(GC;D81C|@plPhSti`58ZT4G6J0 zvfa4B@8LUf=CzkFKCcRF@yPspt0 zItquMV_BfnQly(FFaBRMTYQ#MG!FB3c#LPLsX zEl?}eh^3kW`V$R1tC4GpNSrY}^Bl5t|F^mIE0FeAU_d)r7|`xz4+`f$XgB(&{qEbH zA*R564&ooEtTpLmpX!F>PWJa?9Zff`~GCQcLxG8T;2I&{A4-g6uZYqBqANY(o+FfY4@2jXuzdX&kr zsHiE}L@_tFIJy6;p1=OwMGX4!&&)0(elSDCl(pL{oA@a+oaIq_f}D5N2Z*?0r}b&O zbKS9truYQSa~{6y`{~jYFO!t(Qfe$TO)wlCRe?@5j4GuPJPS~GRdV;hoEy}ztZ zkKyp&Wszl`K>lzO6b)xnIJwpnsf?Zx#uJQ6Niajzgy~`#1*c)=6(7qtBE<$zqC9Q~>LN^C>lM?oYwduy|INUA-xxPI-*CzxR8S9^@ zDd-d1{?dZw_)xY#1FUb}wc>c#@tb?FasK_uNQ)nlBhn8T?d9!ci9@3AF)rtOo$CM7 z?f?%$Wkst|0I+N|?CD*~MyVIQveLUJ0omW;Zv~fDgw9c6DtD(A(eDhXH0fNNWQvbd zoo}KRo2tBavRp95=k%Ib!8H#i5m| z-V(PO!vCFL2&DPfk$(8`8qWD&D*4AZSq%UDy?NGl6-uSoHCF3-Oe0hEkOB4f< zGinMxdm+4{s=67g6+8ltwf0QXTTQIv^nlvUrTV-a;kM8P6Al)OViIr^{VEE{0sW|X z9jB~KkMD>h%V**YvHLk1-uNC&OctH`@vleToj{&dCt3(X?2B!szMQzdxT-Z znpKEKBgkfA9z`}!G)qEx-=VI1&4X8(1XP`F8h@tTFve~t6ZlaP620*DvoBAU0^s-j zn=U}ZMwi}o#c|s+sct486Q)-+aR5>S+G0)DP78=liGyqutGc?$t3!P~y{OzxPc$Q; z{6vM#MkaYW_FFF>AUc{Al?1#G^Fgv0)_Q(p4wIU448t9MQ;w#7m%oGEIiaFBf{bwu z6Ew(Yg=V!O9Jco#{pxzj7yU?WtTe|l9O7%n;u~ZQ-5h*$AU^s(u@Ar>+|!^Z*NYg% zy=WzSI90SXl>nP5bUws&XFu^T9b_i9T_W3v7QA~i>wl?mb!B+@YIZcfCptJMWoUpg zxO@({9imad_SA$v>4N4B<8(n}lCRje{I1=QK-N6+ezpMKr3Sk7QaKfEkM>`I*kB?F zirdf-F3!Q5xlOhE?KXs{=lPl#s3N~?v6<;%|KW_Pzf?CxrNe6-+F$9{pkP~PCju7@ z?C*4g3*ihp4_Psp=sG-27r1!+jI)htD;&UGhD~Q-942c!L3sJoD~*4K0bE=hEj(Zo zl$q+<+?uiBhL%H|wd(lc zh%D+BEc?uvr*nZNfJD&q?xPrlYK9a$6U}6fPv|-RSP@ zM`uEct8J8j3F#7@ZVHoXUS2zeIsD=r>y>z;5$-X*+WnyXbBMOl60#)cWOBy8xw4nK z@W)dd8{)N=4dDo<9&+5{rVs-IB&mewT#T)hL5Wr-Bd_&~-xY^pB`a28aFM#0d#`i3 zZ2V~JZRFS{-r77$6FS-agx!69h6unwY@q|8(1uBud#>wOUN!ztq0>9wSvb?X*Ik#* z!|>NqWo5&Fsw$s6@KKqQW7?{zVK*B;2de+rY%m~5;WWPq32YJ z-}Gta)K|E=9X!86W*%ROqA}cmy6>;OhbKh4XyZC&mwzQ&@IOuXKN9!WIsAvW|6-}y z@4^z&y`_K;GE3B{5*_V?OR4gim9p~6^a^2ysy3UOv#T2s*uPl^S{`Qlh?D}K?;(lm zYO*$P`n{>VK5JwKGs|okmF!WAkK=KdxI?Jnf`vhq;R8LkjD#vjwKgrDD#`$&0f*B;kGtE4n}^$`!d!oHyteluTF@gwx% zDhI|&iNw)&PP<8$bJ}MqWY0~;{N0m@kgm(OT+MnM=>i!%*^230$qkZ}+h{4eiK zrwj4qR{CsR60us1fGumzU4$!NY^tXq4N2N9eDMaDezK__tP#^*b@DpKoSCbA{Ue&A1Q zi8#LzLHeuc#^-jWuc^P^LkE+U+gJroWy z;A5_IAaN8Tx!DOBkt*sa8^Oxa7iA_lYZqXHK^p4A_4(b!<{(D!27+Z~letGZNgKa# zsA&0pffVCvM30A2!%v#h%~UF~+u`MbA!#b9E^umVUWhKdT1QavT{oe7);Bm_&%2ps@J#0eMq8jvnVG0 z^UhAY$yM9S+q=qTO*hwdjcIm1Zfr>*EI{)zZ??E1x|iGO*O&Ye7Io~GQ}otYMylpp zf5K9vjaWcsyh)&Pm~H&P@NnJ>M`m|e+E^SS5+x}MW4MRd4M za6u_Cndq#?WT*G7Jo}s%6xA|?8!=|{=Q?<-=xfAnWcfTva?ksfr`MmAT3bksKbO0x zO{-D8Q*F{OpEKqHtbHhFz(EMEDH^(=+{`WAHQg@U%p5Gqj5Q6sP9+;!{4@o9`?ec| zU0k#yC|VYT#OJw4rh=UaxjOQ1uNCmY_~=&ql;8rNMzW6GqdsS|UTSg!0;A z<9OSh&sC*xOHN6Rb3Ao2pc%oRmiKo}3LHj;`^mc&QVAY|hyd8*Fwq;|P0yaqc7dE> zu>bW0Vvu{J{jL0?yWg(e6I(~8oNtWm?Uw`F1e^E@rqLd7MH#wM(C5I&nDBEo?r-~q zcERqgI5!t&M}0Bl?;K#$LmZi@Hs*jkKj{kyfGxV`ap7=@46hBWGPmwFjp_RC{tQ4v|EOnSY#U#^)xmG|l1K)YZ=x>-ZkGI%uNNt< zD*X{0n}q4tw6ML}HSN#K)s=^I*LV9tXT8Q>Zx`}whPGn&zvo*(YGg;jQpu(J*lww& z1os|OeDE__xD!yg#Ub{h0>y<~%~+m@`GEYrZ!Psh*2i4;sNCAxw@Uw+===9^42p=S zz_4$5CU+Jp0uLBm!Y7I(`52&HJ5c!@R^jqxxiuAodb+g7)@Vy(0*ls-mZ~%^#q@so z4F8PTEQy@MY{HQTc>FqyTo~ad;IWlf#XlQkQ+^w;VPhE6zw~x8krLvOlp#9bw;wE^ z!VWIW-s=~VP`u69n0w8~x2bjgOhE7!qStiKOdfFc$$2k>Z;$$&^TA{rA5@$>6Ilw9DImTu6ZzCIbCn~jaFj}i((&s+(cn{QvXH`l#M%c^`ax}?8`=79H3xZG^pUoWR^Y^M%AM~WKi_c9n z+sIRJCx)7Xtr|-0@R}pwXeYylbBGlI9E92;jUfCdh6%l?DiZzIg8DzF^R-9NN&ndh zN#$cJ2-WkgS5m(cA8ihDEB!4>v`nkjrqT$K4q(mBCL@roCW9YM`zRNJ$TkP*! z%TgG^ml=kRRG>`E&)j>vrETy@QmI3bPAqCW_r6AfM#(EPK>nEywaH`R}}% z8#f4t3fFG!8rI@ain}{OS{zD&1b24`E+rI-Q(TG$w;;vcU5XS7QZ#r=A-F@J zSo>$mzxUeLx4xsCqq6p^D&`~>SgzwlZ4 zC%u&KANRqXjuAfGQK1sLTI!_C?)Z1%)llYS+%x`fIozf?((%b9MG}wSABdL6VF79u ziU8a9%Rk$XfjPwyOYIc9Wfm&di%+Br0yteLj*iBTkKqj-I~a$>FEfKqL$yTDSt&lW z+SCPTN5|v@ym^xLs>Pb#MEXO+&}M`V8ST(&-`lEoAvoC5TfW2iBUr`{SYgd15^O!k z8@nqce6f74MpAjq~_-1fv+{Ap;^z%!Kv_Yc}bSb z{%?v~eOPoURcU)tm!eFUOHqJHXpNs2{(HA1_I;|f;wHHxj%@=x?k5*|LoH+^uqHcR zL1(z68`30sKIBbRg~mzgJ<&cvepMdWytS5b`yz~MH1992l$pA5`)&vLhx>oR6aVFS z{E63JIVD|M52YQkc?7g!C)oi)=nebXX%qtA+Z%yiMW5Ve zW`o6o4tu5+8NdzE}Kr(zbn^ga{OI%MPm5lOM2 zve~vWrluZr4~qds2-L1xhM48K>plvuJv=$&@k>>fk^50c%LV9pdf0%^;^B_y)JUY#rq+#$;Wr~o{>3lRxTDCynlV>)mkr-!jULKo|8y5vHm1_~2zZma8-bzejv{xIA zmg?u#J4Hb|q7KdY@cZzS)S;O#fROt(KN{;jAlR901J5Uh#q*#%;oF7#218XR%VN0L zE-ZNk>Sn&P5y7gx_@#l`gkq%8AQI?23{b6eabRWkKxVJR#8x1>e0 zr=_)^PYI8@AGw5!1x{Pfh$d~3(BbJanc?g1UMi4CVl zyP6lS5CT_M&t`2C;?ngi&IhHSC1kJ2wgyKx8$O&yne@0DFLcT^)oEWg_?p@-3(nXJ zr;HD1b$v>n#Hcj!mEuFF7)(^|N4)(`nY zcO+AG7?+^Tf&?RNJ~Bfb&lY9kG~z0ptl84h+ZzS~^EX^Cj#97&4PV+Ej;#bg*ZUcy zmn-h0A+oTrh17Qg&Dg^YhAm3dDaer4l2cD^kiWIuR0@HqR zO$?xFD>iKW+l88@)iyOB%60EpNzgfK9?Nqn?IFPa$0D(hvJobNQ0t!h7A#}vu~~>f z7h{GsyX1@C&cUXua&n8Ko{GEPb!4V#2)YE~L&b6Vz&odzA6?8#`|=JZ-nFs%v?-PZ zEg#%saPRuL5H6Ti1S&9{xWqiyOPcpvhbg?qbL)sg zTXTjvPvAvecHoxh4l`z}-7@6vif4`hwWI;x_r?_7I$XMd{2mbqfGwb6OeOT6o8q6W zY-eB9jbCv@{<=6u(PrZ-lb9VhNWmb+Pp?SMxgnypcH`~5aKWR#i?9Q>F%+|$FD%%r zL#<@*#r0zZ`2qQ)^zXzLf`8o8eg?k#*BawLbk2YAeCzZkfqUUNqLDv4OC%B&LBu4P zjC$u!XJT~=*-QO14GK^!A(&^Vs8_Rqu{Grd@9J0}PbG*Y7b-Azo+cxWZ7=GO00l`3 z*XOpPEN=D|uMk8?0A|0-#eFwwRxF}n{h`ObEoT7Ce&PZY+xQJSuDo#kwOvJRVwhBn zdvXJ5wdAv-+IG&=+vj9*c$?Z{88sA7DhHwz zfXSpn*>S~O(xu5^T2HZrn~x&4;{4lA&DZUE|7)xt9On0E zh9JPBmOm08G7R1Yc^f_RGyV9Oj_M(a0CH9tSw67PL4*PNYEAbH5qnggWFtIcA$i@w z3_1TGtzBChhCl5V6VMFhkZtMguJi>JSxb7(&KY%bOx#dVoSVb^% zQqNZ9pjP8@RiB^Vr`7~fq)IkNYTZ*nO`eO3l9`Q80ARbLU6Zd7IOwiH##4p@1e z!@O1y3$%E)>vS7peI=R+rK}zgNu3SqQp<=lnjnLbl&^NV%Yoa6_i7csgxh_^5cS`U zntYM>GAHzHcmLhFU2t3;P70HVw1Ll($dvX1oEo_k77A#=S4ng58n|IFI0oQvul)^! zr);>49SNCMsg?w|Kw_EScbY92j?Y>+8GXF!mv?#fZ%OeV@wfkpyZ&41=#p(a?-x{} zX4r|0ea`ZppMc!3-(y4{nE(FmWOvvLN#V~$@ga+STEta{LZyDuuhjmqmr{s(Bl$MK z%w{Ustn&1GApv#{vSwU+)*3!(aiv8`4}dhmfVtxqv9a?*`0yA6b6#^07b!*%)_ifV zBfW7H)j&Ixa=qB+o{Gdi`RpMRlz7*8T`qQJu*gfZBK%C`vFS0ldx&MjIc0h{XcvtFxdBBXf^d0Mu70n>r3O z$u?J8m%bMBQ~ah}8WHY-GH$|2;!fF+qgxlW-tJKTy538m^e{w!E~|FjmUxzO_u_C= z?))2{G*71wW+tY@&~3RJ>8`>Lpvg>km0P%<10mC{Leg8LS+(EV&C=r%(plL;JgbUyEhk+eXNR-&Oy| zj(T53L3M|7@qp*dN*1y1JQA!SH&mr!XIiFz3w5xvf#)e>{j3L&1`&fA+plk$BcD`7 zNVnCl9HkM5wzjq)C)YZ?hl*yL=ZNflJ9g1+%4gID3)<9F6A{D-s$37?gYQ<3+uXmG zo867`M%?4u4hgl_uLwc0O<>1Yvc~YA9!XcX)VHYvhuK8yy78#HjU(zi@Ns=TuoHK} z$~UNc$qqt_)TnSC7WlGl@^5wUj{JWg*N%`o#af91KxbgZ%Le`?wRQrf8T#4atw;{b z5b$-PaAFH3Ybi3zmVG%DM20`+{qtp2mqLpE2QgU?3EI`teXO1(^blJOVpZz zk);jEmFUr5+B!)_=qDh)hsuZi9JEJ#P{^etz=ZqyOh80ZyL;i-OtNOh<@$`6`n z(&%CBwO5I9QC5kN!QBpy-h_f2dij5sIQLrmHCrPyA>+ikUS%-?`(V!kCAO8_z~4)c zML?S(SgH{Tfijhxhjv=5AxIxhgMVUe%&2eTr{5q9f`6FTlNo+z@j>+h6h= zTqAt5T7f4!Co{$RU~3nenDOBr+xgeaSTn$*!w*GyADKaR#mi#MsZ}hgLfXmpf?bnD z`SS7CF+z8TK|$Uelv*b++Y zD|y(6bAo|6wdb5@Li!KBA6O_3t*Mp^r5E&yx@b2j7SN>6R4I;cVQ=34@<=aU+Ujr| zORYo{#RyzDS{#hQ1jUqGoH+dhsm&A{$ZKi6e&rKm)GM_2_@p+s41B(j18}7_P7t0~ zBy>!>&K)SnUGzhKhaq0+553$gFcD6_J-)tEQro)tbXPd+IYYNU`pF9e!tmKn6?~S1 zd+?cE3DvRJ6r|XYt8bBhAa~-3wd58J-G6gs)?4WV6^)cz)H!rQg5Sab508h?TQvDe zbMRdH#-#2jqL-0lTUzp5gn}k0-OST;&r0%K2som%&DYOrCOyu}sdd!F*u3t7A`Xgq zeiX|8!zgc6aqxpHu>@P)`lse*;cnlIXR2mLCeUnBUY+ zV-&wsTK(5NH!^LtYgQMl-rr{uq^fX-4Q3ZW*bWWMZt$mdp^($>*i)2HYJkgOFuSy0 z6r}2zj#N;htx6}kv7tMZUP`-C;wJ6gLLo1D5slXA+VcK^g#8Bx_J2;H*VwJRz0SgtXiaVc5hYVS~6M99Z|`7?)VHr9uF(r?z=FCMC_O)zVP=S7_LMnp4g)^tiOd+`@$Mby(* z_`U9M$QlEdU=Oz`LOOGzV=gAIHC@fsD)TIo%{>h(=Znppb{#^QZ^2!RP4pPht;V)D zZ0NURM*E36>2cgbh(6uQJXlpcRy4V3#`wQp(nl)&5^ zzkG}NRzAW~Wj{{TBoLx%NxC!WguLdPNz6}!-_!5;ws}E+*H0kN#J^1(< zjd$gIyU)*f#wx^=2^v;2))*8H+~0j%j(>MvTr0shzgx-Xw9+OJLe(16HbHnMVYMM3juq&x@TJ5C_(D*YfA4O@-6} zl~ARetVx_-(MK3MJcz$Qkl*F&0zb37$GQ$8dmr&}4m5BwTcnmUT;@L->PC2Ug|t8iz;6q6%RKQCHxeINLJ)R5H;kRt68ZBdzcgS4CqQl^^ApEC2NmCl z_qA^M)cDBmsd!QEtylS6`a3aksLl@BcNWI%T-H(qSWmf~tkj6=d7~Gbe7v0@@M1ad zHsO;Ra@P->$uOI(Q^lZ^O0lwN_NSq`}=UY*hNuc}fA{c`_ zuefwd=w$ff*(~$bZPo>+i*XDM(k@h*3p>rweVXrS%HEsLw-DzCva2Vt@Q&`ubKJD+ zseDK;a_aHjYSYw|zyg(V1MH^p6`fA|Ki`I9#eevb{=1|Wr*BTi^pQef0Eb8y7NSE) zj}2uoP!GYf<_jzxDZ3rL1X2ZNQIf9*L{P~rU^ zh@i$eFqG-Wo&y+CAcRe}3 z-iM^XaoiL$LHRv}e0ZlU4@>r^I&~2+{P#_hG-?+1fJea_r&~0rkg=0;_!+@y>7LO_aID4 z1rv{)tUlTq52p#^D>b)sS}&@`6AM-RDHMMv>`=tC=iJSn8&?US#Y>6R&6H#saC|{* zT`qHyF=3ybTv%p7+=m}$SxTm1i=AD0zK?R*JF0?P6Tq4tA{?Pq8}gLS9fXU23K~nd z&=uO}V@PAD(6)g@I6i4`M|s#DBY~a9TTiA?Y$V1FzCu1W4`!zq>b*xf{qqJ%Dtddx zxq-5g^a|a`vDl)wg)|H5rP5H+p0Ocu9Rl|Sb;R_bVpe?@7SCIinME1(1#3G6Qk5GC z_67c73BwC{s?L_B873I#=)k?0=play!*ysbuKg4Mvxds=iW!}25dVQ-ZYJx}_b_j{ zn$HPTM>qa=4CAuzb4b$EveruA;~o<}n@9V)f7t-Du9fj-wUrYnJZS}7meDNvS%LZ- z1Zgt2!GvQ+kWa2x^GtfvNBsuWtK#WSmZNXh0EypZd$kfz?hbYZLwQUDSK*QlEej@&cdWK5KoL#iwhWH$dmknK#Dy<>b7hyTNR`YO%%)} zVdwRS->{pJcOG-#r|N#XtsmKa!x6g3t*O4Q?drKuL*3Yeo6aOLT6U<8P=xGtpU>X^ zXPvB0O!*}#;oc*&9VKA|#GWIC z^unCgw%;>l?P5fjUl<)e!((zu1cpd0>dhM&zo^3q=cbCA#`kekq@kUI6$Y`;G#o`i z?w4ac$`7(xQ-*#_a{@>7NnvcjB>H}mfegAh2%Z9fBlM`N`r2hsob8HG&5`rk z^!Vc7DeceSgx+8-^*@ZFiNS0bfYaytP<>7u_1?EZr^fx2TB5D?+PaX$T&1$o=z`c_ zoAigh=iBivas2jyuNm``nsQ{`;E700W&c%OUw;25^U8PjU=Q-sV4ki5x><*^V6NUX z5y17Be5xMc1S}TeVrqU`DHHIC?wZRAS~L{OvsY!BUerSmYWWoY18TWE)DwKnxh)O$ zJIZj3{qW7z;nj!JVu27CW$E5K%&5r3o8NTZ^wJmbps0DRhW*7a%WpY*lmI+VgPoERd$%?zwTFBA6 z95urj#me5Y?R*k=&2W8@=)!f%vR|J*G#_zU5eZJ@l?%H-KCVs;1AZqM*A|5@wz8m% zzzeVVJ) z<|@8M{rOj>gevjZyq`a`oT-FrVt*;($PLHZU@(aFtnA@j5V)>h9(zQk5E?91-=N3Z z9BQI2H{MOe(4KDp#Y{Zbzjq}G4fs;v-`2Tv-;`B2*$FKtIX`G?-7WVfrgrx7RlfKP zg$1e%Rd?vzQWJu*;WJZdP3lL+Pb+qTDbvMD$JUg=2Su zzpO!r*Y9n8es3rir3t414Yi*zUEvLlYEz*y!!=Zba|aD}StVR9zF9bp!8}{8#u}1+ zFfw@4Q^7||me!m80{Ze1&{&GAJoeoVZsqI>Rm3^^aU8nhwJ+pV*!M8r zzs*nDDM5Jo9tP9r4S;BruH<}`=IVMRRiZ@u4>-V9dCPiG-GGr!GlawG;#hb0{v!#= z)K*A{NIFvT%~g8l1oD>gF}cI{+mCGt22!Zx;?gUF6~LHhd;`t10Qo|qTIw2MN-ejA z;%Tc`jn)I%`JhCPHnTK8Kd2A|5W?6+hk4yw%5&v4+ipc~60zh!GrK_72bgsVqjEby z0$L%y@S8b3M zAee5cjz9cre-Fm2Z8=fJE3|cT|B)^w^@B3R%<_dOZBFSe(JGsE9WfDHbSm7e5rcg@ za9=!|YQjF(M}6g`PoyxCilwSsKiNB5pK7L>CVjfiQp}{}x9{Q|1WG>JagDmkXT0uz zreSyYZYN4we*InS2ZeKE{2)9`(e2K}R@cjvezV%rlJC7H(mpVF{tvDN;ss2w@Hd(4 zI@YsacSZhn9I3f*_P*O`Fm80F^-LvinJTLzWyS((qJ1!{uD+4bT{4-u_^RtPHuzlX zZ>X6$+RE=NAqx9OP5^5Yn^ZVy88>+#09=o$kIbB67>fC;aK>RINx`@PT%qXwtwWxM z(eG$XRjo1&NpG{${WI5Au8$`*pvI*%JwJt7Hgh8*Xlw5#4Y~stgM|ih<1d>Z(B%KO zarC-wpBLuDD_Gsw19$0;!&<0+_yY)WZ|}m5AHHMh${h+XYu((@Z10AjQ%tls3R~t^ zO^l|H0}orj&EH(4oeQ(run z;Pm`0@eCPT17Z(U+|0dqk3*qrNB^R`D%6diE77K`P$1ghdGDrB#j`Pv2y;mfo%Y$t zIZdHd#D;e>|Mxc5|L}G1qt1PU9qqT!CwHH0YAvPGJW2`R<`2Oim8$(f6$7R$^=ETH z)Z=A}{9Fgj>r^#-tL;)}j%GQ;YLOZjn$t?hNYuN9$ z8r5OTQNDTTz-ucWN20@x9L?~TDmL?hp6u6Isn*{d*87l>yE`)nm&J_;-G1`xC&P*j zg6eH>ED6n-TV_i=l(z6PU;;t-BFskZNbT-Ia>Qs@X2{rl!2Z@=4I-qpAIa=Ss{=k% z_I!1FV|y_O*vfAd`7}vIQ+}<9|1c&RPM!B9D+DiP$D#Hi&|E}BBnI^&T=bR>uQ>9| zbDDLfgZXpqpCazHTMk203T3|<)*JTJzHyL2db!lH)#k5H6pO<^^;f0_28joVTKM*M z$(&D&MR$3r^W+rYn6|nk3%WP!J8HyEHEYSCP%TWm_hoR0uJliL3Nv$7MZfnncYR`P z`r>1dg@u{eu85ZU$vi(5k1nvJN(b+(wL@d^<*J;CqwN&=S5F`DlVp#H%FF-)k3b)> z0~_^!)(XAP>z9)KPoLudo$hO;f$uh)oVT)Zh?)EoEjHc}YPP_2%2Ws$aAKK-q4Z;H za3X~w_9#m4IKnZ{E2{vaN{MLECQD{Hs4F3+M63O#IQaNh@e2;vnjX8x+;@n%C42Gn}hd_j5#dZh{yd}ghlJz?8A>brh$BgOKh zovxZLnPULC`Zq<+fk=G=(uLV6AwpHT$D>0|^jUx6%IApxgRLMyP4MH(thcQt1<6hX zMl;(v%tyN2O0E5ycN$`3#1X5*hfg0raI)qaYTT8*_~r|ty<_j8Wx-KFyjT!c$2bI< zO5Ns3^Yq@D|BKGV#p z_U=ktU9F3~X&}EfqlEsQ1ruY@%AfQQA@6rm}UG`*`m~ zhaS$W3{&A*QmoVwwAl2nCM&?2)5_L-a?Bn_; zcoy{`MR#C&6F`sJ-HXz?U{q6N!K(Ta?Q5sP%CZY|@S?**l@0BK2D-QS9nY=R`|ONu z17HJNUv4S?TP5=zvVZyg%=^q+|Bs;a|4j96k7gV>4U5O%f~nu%LZ5;N)u0yZIHal1 zK}1%ixdm~={J<#7yAYWn86P$kelG|H33K2nI?u=Rn-+{*UMnuz={qGP;Q2W=imXGJ zeQE5njr&50kaK@5z~^ua|FgL={+S3;gV)1=Lj6UP6DNg93-z47JbPY0vOf8=gjsgG zdK}p-6`lv8my@w{ccj1X51b~HtmMV)slZvju#wq1D|tpK8RtwlR*E%4ONI5IQb^i6 z*;spdl@M3Ac-}M%FF{IOA;v7Agk{N=%aftaf^jA>Ye>7*z4XoUY z@p^(3+RNLp&~Nt0c6xvu@WBxrW96LYAzdhbc+oux!@UhyJ!nz zx4HmK57DQ>DY8FW9_b2Sli*Bs9cPJ^21EI(j_w8a=39N5_aRyH&XX zYZ3E1bYgP7%$kingVU^VL~+1FEAs1l5OjWD*a5Nq*{<{^d0XRpW~|{jlS`i$9{jWt za=ECPndze3xds)qn;J3xaVC4gLQGh(D|uOC z+ySKm@N)f1m7cB>wqTUK%-!!*xi8UOdHHRBeFX40OOPpNP1nj=93MN0?-#Mm4&|EV zA_7tF`%=gbIW+6`uF45dl|!B8{_tP0a9~8h@_*f?JzIYi8#bJYH{1niqt}a#E9;*< z*hh8DISI!(HFuz4LG>oJt zB*#wYOD94$Ra#}P4E%J_dHu6Pqf)>HV%YDQhVq7;3Z%i|!M9_BnE;}2B(1mUsgTP% zk}=x$Qa`uBE+SogM;xKk2Tnl=MaDfFXSP{MkVdSOu=~6$ zsfUQe?r5P=frpIfGf!j202pTmkJVwhlzBjK5c_F$9#gEc{3N%(Xvc`DC zGW^9v!5B@=mN|jF7vc`M0QP4c<~#zXDw@((Fu?GRQ^lakRqAe+)(PPiKWn{apL^l@ z7Wc&L9`L=1vGIV>-mVdim1<=mUd5B1LnV(p7Khru^_RY{1p>7}b-e?T3A^Rt`ZXrg zvlemBqU{2|@cyHLSdlJ3htm7_qJ84egRj>y))1~E{m(n-!<}HXKximxfB5YJTtc-j z{QBF0(Yq zGY7lJ?t$_bRP>(<-_>;XK=}VMaj%odc~HbbK(jHq?{oixtO&V3WJe($B2?OS4^m4j*1mvwyi25;Em7(mr}BhHLwg9Byrbw z4l>z&Z)&E9?gSijDY2ZPt^;5lp#cRvh1u{xkT6mX9GMF|{VSte`$Tq&A zOZJ2}K-aKmd$8wS9SzLF*347`&k<5gdB5*jGB<<=zfpVOD)EP|4QMh(;`5CBco?|@ zw{);>{;9F4NP1xU{;WCN!3LP2ZC&kl^+MgaqfRkk$al+goU&=`E3WFafWRZ9ZyJ-v zxVI0hqLnqDIQ!ZM3?JC`#}nT##7C`<;6nT^@|a_s(@>g>fRvfaR>Md-SYoMuigwJe zD69b!9Qg9ntv23vuO%7JuhPz?^OqE3_lEg#&u8t?<&d_SUTim4%H9WGeMl)s=`)k} zR~=lO0-NjKs|ubttsr>s7;(@--RF8@63wc>uUU270}>@9EsYODw;h*P9TjrJ1r59D zQiLO?9lyG>XHML*y+%%(zM*%1Xv{7deHlcXXp+8tV?p77BC!alH45ob?|+=7Xa?yK zaeu5EAC^zqgwT&2t*S*HFtB=3cIDnod#d_lsoctZ4=^8Ts|xk4iVdE^k;Yiq_ov3K zF)#iMXoVk)*Z3Xa3{_a$56b#2TzCu&i82KL^XvIOk5LNezs}3+^lxOXt74;)&SShI zH{VO7D9uL^kZ57ru-p1$r{T%h?s7*7Gb<*Vpu;{kws2g+7-@g%Z~#RP(=$dMfg8e? z6d;(Mao-8Xh*JD?cD4E=7hYmuj|(pFf)+nL#8Q-{-+-i>Xk3PI;P%>R^BOyQWJ5PC zHvasB0X|qXoyFia2HbG!a&D;nZ&~E|cTfYNCxabAZZ;X0xj=^}-1o?M*mAR!6;XN< z?b-^zwQFAyX->bjPsZRmlX_0!Gz=lO9&^cTx&J^7D61H!_7!`T%JqDywUo#jt$vQe@o{~UmY7vsmR_qJq!1Ch;Y*r zvn)DOjdsSKD+Rj>`n7a_W6Z@`J``~NUTHH8gB*10{F&$b({sP^iVtK|IhJu%!fe|g z!wJgbxLO9%`kaQ{qfUa-i^LHY>DAUNFMwrJOB64X764>tc;B+NGCoru)=6rPaIhoY zlS-(ev>Dgu(QQwZhIU_pZ`yc#TArJ?{M0Aa)huJ9Cxh0_Bl2KU`DO=@B^?3T^S*}8co)t@uVmm+KKKoej~AwqObQTw)J>X7t};82c|d5-X|u>W5=cv_@JNRlGtlYSp0`%3R9lpzxt&wJ%IMb#%>o#{PadUWTWHi|hWurjM;bf>= zYqNc!`|*kYw=;JMWWaFK@E>P>#*(KlK;15khcmnlw^?jo}K4yvYHKpVaPk|Za@?E7E!&xtk+TDXi5PD zqc7B$(k?E5_mL~||5vL2)fu_||=fjqieOR6rXpDv%i8K%2xr>)vo#ILF zW*w!h7BE-&sXzL#B5`!fF1Pf6q#Z-vf$c-nDS$flb2^jT-?qG=)MExAEh=ZZJ#2lk z$Zf0_VEgPs^@&Q?1C@v32lB2}a0X8dtLI=-4|R#haUb|h3M80^oMWNPkp0dWcsW`~AwuZWiDTmpH0$r{5>f!A- z(nDjp_V1dP-`bi)K$O}JU75B$7w_8Mxt{25<@q0eL^e*XCwg@=7y{;!A5VNtQL*7C zyqUa~;-CxsfwAYd7D8JES7MzP7*_NowW)~uT+~M_;(9Fn`?FKu%KKF#eVN%=f6Mk| zDIEXJ-@@J$s3JhwIH=YO8@&64epMAG>+;3*Bg9iXTWM!nwvNXw#oRmHc?n>C6&5+& zFVOx_VM$d8|A+wY@2ZHzl9>_PcWK(?m4 zwncBiMiwfyrgi03_&+W+;I0g-NUyxSYRE!7Bk}J^YO9!1hnYnIq;`NKUjjSq&kwCl zH(rIX{E00*T-U3A1-l95pjQh+o+%p*v~oHHK24TYd8%dvW%v^_Y|KFr zsrnKPtAGsL*_?xaYkI49E3*GX&-*8(=^0MK0+axqLPElc__)^3eIN+7>|ze8%dhK3iL$W2NI9_r0omw?8{N9jn{AA#OJ zhVl7jB>3HdG3Ea4tH`cNaGGx3;EeO~%4)$}=X_Ji=j+1#Ho&VaSBo-qz%16~dbdb&Xcegaq zxaYPXuY5k6B=2`d^7DnfOJwc+S3e{V0q>~ybxqMF%kVp*p~Faae~Iut4byKK%|Wf| zcc&UnT(>lpxQ7|LKiFPBK4(fxdXhex-@)nQNxMX9y+!R&`#uovG_ZAD?f6%d?o{WS zlCZ88nfhmCszxmrKBf4ZiAc%u1DR3VA#_qN&lSsUGZ!Lqx%DbaKy+G^ZmU7`aEw*u zP>FZ+J-6=e`xRE!H2&oPeCs8_ySgm}koI|aB>!vO08FB7Yt@RHXelzr>OVR}Ts!m4 z+~3=`UmUfov03w3K_8-;(IzG@3wM|kO>JT+Z;LrPSkku}T|u?_y&28Qr(gqv>K>lj zO^uBvv!Oop8CAzG)$58hzH z9yv_eWn1g0ICr#8G*u5Au!*SJ=*E?B3>Yz`QI@AXpp{?2#eB$!2ha51lF)Yx3=6?Y zFHArF`_p-7{^GxYjp&CDL8BI;asC8Ez-~?79{%p-LNT-1BNYeI+lJh8q3^=%0I z<6?Wolsn5qhojaqJ`!PUY00SqfOmbCuoABpj#H;J;auN`0%CUoy^_!TqQwLP!%8bA zkqMa=4@EpyOff3(02BQ5H3CFj9*7Ry4Ze2}Gk9IjH)CEa8G5}3#-9znVHK?*fBoQi zE>f!Yhikv zVHb<_dMQtwFD)4_BID`muS(~~4JBvOKDK!c|B)zIF8gj3porUR9O1c8i~3YQ?K=7R zKFCEdJ?K=MF5S+|DA_g(^s?tep;o^(W~6RrSOFm4fT;NJblvOkFjER2RXf)wCBwPOfQYHMl#y9|5{ikOhTinprrW*PNZ5?d!O0@u^<7LaP>m z{9X{cOs7u6oLPg8tn1c9h~NzpNd8XDdE=u6roxVeZ|yvIxVyPNXEPFGy?ExGC19Rx zhci^W$usJU#TgAj8Ec*##TpnrFKc|TK;h0lXr5Co`<;pf*xKhUV8H{%O|m7bp-v&q zyowa643iBis7%_%R9W@U-2QL>t~it$*o7be>$9l8=%(<$JeqW=F}TClk`plk1b-OY z`$kAHC_;*!$GnXwtrZ}HGE^wEi~wL2c7rkmV8-xdfJCqKpX4!MDSdsR3aKT7lOu(v zqwN#79obRl)Owwff?#f41O99wYu$dqr3&WcpQ-0zg4Im**4Xt9e_i1z_Wck{=%F`+ z^guMwYpk}J=2|npG(e?K;?AzJp=vVk;8&$i=_bz%@=wWT{u)`;dhI>f zSIL$et2(^uZm?e`0pnnJi$Zt-F|TFiqsUi5Weq6HCQhv5#F^REg|4#pTTRJ(^#I@7twRuHkYIQGM?2K0q5O zc`?QuXoAVb6xpft^lTET6Cd*#Tm?Ej*{L$XqSP5BWnQQsLF(oI*aRI zqFAFCV{dKNQ1!lLput!nSMsV4oLhl@xO?s&zisl=J7OE1bT^p;9eWdrTl`3;o+q!~ z7wOi`c+~hA;LKQCI@w28_QiPVGtrZzLb}IlqTIofWnWn5MB6iqWTA{`02Uk&pc)|5 z%g>jqrYIuvy6#xJTsYf6oTo_8VQONGDM6AoGJz)i@BWPQ6!6PhN|h_K>`{Ug@60j-N^eX5xjwryogYm>Y@6;d@A(U%#1Xr@_S2>i zmo>~Q>22zY2mhWWSl&V>?lAaDd!dF{q=A0+&|Dq+9fd5F%i8&cK&VSjtIp+?DKQ>a zm(jAb?NrdOy`p~!5o{TO4gcJf{15KQOh2(L-+Un!3mP! z*TpW0b#ws4qA*$KpZRX1BS{nbt;mJQ@8Mm|r&eLBhL846@Y(-R#TtW7;5>XgS= z&mEqDyK_UqM)A+hor}>1JdkX~c zx(-HN4r~KX8^7;;#8~rX_$38-7k!4moPcCyvCNg*T1)9IQjQn+POvJdG;$RnCz`_H zZX8fLT?9iilcuSYZS8rkx$3*3b7|Jp6xDIII6|uRlxK`o(P3Ta()V*cQQxhMrYsk9 zM$dd@6sp6jCOP1=hq~jH{j;A)vh+Lw|K3*Ix2FWFUkm7Yl}`Ga(*0y<_6eS~tOQli zi+|{p_$}zSY?l1V^%G+k**YxWHE2j94=WH;;L=wTZ_QObIxAF`*K|u1%O93VIwstA zD=Rff#yWJgH?mHtS~gJ=c_t9Z~ekqNjLiWH#c{4P_?eO3Bu2 zl3%FRv!R#JBgWz{x2|H*(|6qri^VZ82Wl(eaCzT=jGeci$smvq1>r4u77|BJoPytq zVtr$}($25~RL?PD%dGU(h}E{;Go!oZ#WB;m$(FNOJ~xdDl&m}Cg)L9LE2uT8-76%x z&PE6-`mM6^gjTJn*G;+<#bOn%rl-EzDt-bs><5n_V@;(sd0T%sJLRvg%XZ`MTPIK3 zvrkFgReiV;b4-Vc4EMxbbqAV@<<>XZ5`3Ps1?v#DjjV+Tt(PT-87OQ^?$^0nQ%4Pp zBNElXs}dGrbg$t@7X=PvZsBTA9}XS9F2<_-L}yz6NOE^G<(vqG&QU7-(l#(}x|#G+ zHw!>DNCa*?Hq3Fd{(-cQY5BH#MmiojNtc8YcRF9aKrlNAeMtB&G^J_&&ek?GYtU@r#&j1+gBDEdC0 zK=pTTQPn1|9E4LjpG3QbLB$v*GMGD`;{<+Bp3m;UL?^cAR7dObD(dvm zfs5I|%K%~(FV2(vu7l~8xq@~rnvi|POcK{)+3EG>PN{@wh;-PFB$^J|u(~^dJM^E= z3O}k&Zh%nrM@O1Z#W(N(pU4}VzOZIVm3+7qR7$iGgL^j%I9`fbB;~G|R&8Vn+2V6j zxT^Hikxp~gygY9yOLtNlty@oTQAh)eBa%km8C6CZj!>r4uiB>Ujar`0>&Q;af+8%W zorh7Xg%%(2ZV6&+@RD@}ZddPL*OWl)0@Q1Id`)TnE>p%Q=RE&%l)doFK+H<{|EZF= zTNQ*HUDXsdvkt*g_@et?*8A~Mvh#Uq{WasI!my7}!eidY1W&qTBs(9}9Ws`epeWX4ZD+sM=StXUX)> z?}Wc`sx$F6Teq*s)R{$h0;$UDib_e-XTd9yZv5zU7Ovr@9UhJJ+=VDD7TpGP=4b+m z;pchLiXdmiEz`tKG%;4ay7(GQ;(jq(gYI9Bx9I=f@#b*^ouR~rJ_7a7Geqv4y^oc# znl`xb;+z4hQ!?)bKckhD*DzOz<1Y;BizbT)QMzZ^XvIh42t*CyLitW1R@ma_LVljm zp+Nf|vC6WY>^AU+)Qt{uE{8B?ny6)v^Q>3`h5b`a*7P@jnwpTN>3bPN+JsW2#jVHinAt^md*NqQ`z@v-( zt39BgK=J-?#sLEQVTPMi?&vc+M%eK z#H`WURFxn_OIx*x9c^t&C?yf22r&{t2uXy;|N7rAp3i;%@8@}Se$F>JUz|sd^Z1V6 z_n0DWo@|n|#SQZoX4}a2jEH@jW$qjIdltCx)0z6y11SY_SRL{Hv@jO@>BabKw3X_N zQ70=iPi*DP{%STL`$FG)pKR`TN{bfx7K3W(kDfiYX}8Q5tmDwtY502O_jZ+=?9bd4 zi%OYu9fQBEZv>Y}O;w#g8>}aQSp9o-E0uraTt`B9%0gLK+P#Ep&nN717igTn+Gyb- zvq$Z2)P#rAW*;NA>^=k@5dYGn@qDh*y;{2BJW%X9f#qLVi}Jja^=uIMXQueW>MKTF zg4C6pxwjEAOL_IHD2U1r?Fw$4esdwkB`e5`?K0DN@Q%Ldv6j^78w(tPbL6XR=79~vfy%G1h`)geY3Pf zuJ~G7;Ngo(|E$~hy#ddj>~(FU!F+*eQS$;T+&mKIEn5tC_w~DBu5jAgv~H=}VRvn*#K*g|}{&E`BY>wB)I9TEcCvhc59$m*fH;>HIRVpBxap z3nn~!>6HD1Wy2vsWk7HlqD4@?R%*ZEs#eo3RrbD!0q$tRz!e_3f2i@w>jSc&&Ogfw z+^Pf9-=}@{6?t~->2SsR7kBa-^Oowub62&D4-H{ctEV5;b&3a6cb46dyt}M7jHYk> zd6qH+8r;&R{cX*-h7%u00IU*+3?NKCKDYwoM4l^DFMogQo$m%;ye@2H`#f|5dstu8 zwWz9g=J|GPA;op!b;#|$F0S>4Dmv@F4Bs76wm|vPW~uk zd5v6QUaAr?O1T)M#CmenW%x`;9o!hC7#s3>|AV}(Ke4|MJB53tQJ7;B=PLdKuDgAG ztfRG6RXNdS1vh?jJOr1Mf7pqk*E?C(U+>_xn}?Jo^(XcBhkyC`b$xy0>*uysScBYa zRZw!YqVZd249j(N0@Qh6t3&zh0q+gHZ_(2CY8FI|Z(PrQb7?5y%3mMyjYBhi>)O7w zCVbVZsQVIl@@tx18sUt|Y1IBEDY<_!=bEyMo&p5}uJ)?dYbSj+0-{MFSxuB>?TBl= zlz?jBiOWQT!zz9D)U^>Nfa7WVMO%|3;Wo_}h^dQSNtg~qOu9Ucr}M9sAKc;88KEKG z_9n`r&+LobT-&blL%gs}YH;6daW(lm~swUpMoOdHI8gmEYGKlZTe zc@tQu+E+R38%Wjw>FDg)XVAk$Q434@jiMfY^?C?$;=W#A#ZQzMGih)>>$PjI(=x}pX6m`M9|MIkWt;IP@^IZ4J!e>0=pJLaf3tu<=Oi_38P z;0@U=HY)3M%(~Ph7`D$Hzt3wD0YQ&bA%gHh#{kd5Di$X%Vz^C}$iM#cBS z&fPcpesaAm@Xzi4b+Klb?AYH-)8%(#|0I6I>tb@wCQE?7o1N{PUouocz%ltL|A(su zq5`2F^RJTxWn6ceQ;p>Uo+X_YIl~txqq=bK#+>AXr^2RLT*q^!L?rX{%q_o}0da51 z$-(o4$-ZELz0bT$;)4Pi)XcgNUdr4lE+ZQ;KABaWK!d{NZR1MymUdRHCl zU&r4$Fe_Bn^I_C~xc~QtaQ4-gjx!0tdr??^4P8f!FImbnberm-kIl8s?MjW6fWvme zc+#agBJ6>wR$;*UwkL{9EJiGk#S~-P&w6FFKjJiRBv4+|ZlQtIIq*~SW{n39AhK`n8=O2(lWsNSC;L)(*%xYo~vV_dWOFdoHA=ML+bwm||z@7u^mDa$fTB z$E>Vcjika@pn5_>l9;`L@aK1wC4gJ@wzZquZ8#y6u>Rf4lZiiWURn}KxnHv4u9p;* z;rh4&yuaB4Hq&4qanP{)NlbR4)j^Lm^d(I!r2c|^Yu4>k0lM}WYwD8fFnaSxOS6TC zd`UklsQUrCY@<_c9Z|}sre9;}bx|3&)^5vVk%FET(GWZrG8Xr~38h}AD*wOA z`ky=CB?AFwK1nG$dMf&aP0Zq}fj$i7E2eQ{&+Ro-#=IL; z+w~dKdrx>n#I*Er$|O?XS=a`ANIhOZd?LZqlT&~k9Q7C(3wAqU zf9m3ynQpR8_2gwIA7COR{1^2vM@EhDfZj>t0!1oW9_~qIwq3)rK57c5O|Fj zN}ING4BULvms$wm(`RMkx$65YyRmm;@7Hp;-V-rQvU11M>JD0K$9_E=3)YW9O_s)s z!}VNY{2J&?<9Fw!?${aj#}xzwMtA2pLyKnq>PwBymK7DB56r}~-B;T^XwnpL%X^5B zPW3YQoqG8~m2PNhYO1m{#~k;MB1`<5WI$Ko)~$k*%}pp`9|`HdPnv72M(%0p#~pE{ z9&jn6y3vV`r~M<3)WIa7&IW(zz8OI8$&ErbqnD31IQ;|;(WVM1ob1(wq3;}8PQ7>n z)4t?ooO$ZKKXgU>WeZFG*q+nG0_hqse>z09iMrzo11UjmO5a~q(kYR$zKIe#D^oCX zb+4x>?W=uTF8Vpx)1-X6+}aQykH1PBp%IdY=V6D7 zyhPl0UJww2c8~0uO!h%Mo~hg0Lrv3K=9|XIPO5FxvQ&8wz!O@_Bj9dkbI)@SB5Z&_ z8v-`vrIWO1M?dkr#Lq);tY>ROGMOxQ195gV;B*W|48-6@sg? z0y}Sz=A@=-m2v2Y{Pj6W%Mp}UTHWmz1@1J?DN-SA*Ey(V$V&pPb4|)wYhQOWxV0In zK1wm~5)|6$*w~-k{j4RIp4G>14bWwvEh;zIQa1-Y=BVvzP5CE+6^uGl)JUm>&uV+d)fc1#cy4SvF1&#;cp5$+avA&r}bp9gJ`QsGuxt>tOpyPUm4#O zPx8R6B!Q#z4_}#nIW+;*&umKg{^L(}Y6s9lR7=T(hkEAsx5^MXo}{a%>Ru-dPz-K5 ze_)8II!ZpEq@$NTl@x3S4M@k$=&ZevSho(pPtq0Kb%hEv8#z}l^UHeTrnq;)^T*DG zaO~dBJ6&}@-hq$nco~^=+Lw>#c|b`j{j}J0h=@o3{cQoKBfU4G(e^A}K0y6CQsjOj zWqcplK;0IHiO<&T3C8jQB3E?%PPivof|8JTo%sTK38bHJIm~w{yWHaH%}fPDVSQ%D zzK6g3zqzlvR6x2$#7&EMO}tIf6mJ+PrUA0xl z-F|@H8?cRFo`Y`{Y)Nc~_R(SzvE33?hm0;@%&T;jxLpl#pkBd;XH(QR{J{abnVKqc zX3pW@u0nS6cjY1|U~Xx6hKEU5PTAbWEfum9gq!iL1|o*dNazFn@r0lxbUbZJ66+Q@ zY}(fZ0v2JWr~HGLf<)(ga^3MYmGn7W*sXY&>1mQOlCv8MK>my~3sjNxZ3lsMQxlZx{a2j%_bE)B~r z%9hs0MExMXh_*i3i&kNly7$J+!PI*^^XI+ySA+98p%7NdNc!}_6HBNb7)+32|FuFA zG+?>%oDd~ivs~7=m4a^q0e8;eC8{#B%H;Bl5NTf$uK6Y{CVRtb75AsdyU@dJ=P zl5_B)wnUuaASS6lt%x}0)bSrOrGDn6A^2)rTcYQxB!xz;emtN-vlN2`iT7o1sB399 zOaY12*0k~X-Y${DlNaU6i|Pw`vGdj6HLGbxjdG*oqVsRm{eqCtG&_n6i_6Le#Zchz zm7xI6^gBq_ujgrIu8?_9o=b&YqIalhKF8SE^yRJ;WyxvEYtgfCKa=kb(Zy}y_*hG2@YMPg||ff ziIl{y?s|##D5N`VqPqP?`{}3TW&+WbhUj46P5xRX%L0I7hDBOu9F|`J#tHLPhP2ph zV^$Z&yRt)M=O)t9({=9_`Hb{HRMLU*p(1skGQ&lGJ#An5`HUFSq^naDyW!QRd36=i z*}D-`pV(QmZ8l#+RX*+?d8@x~QU=iLaK~b5D;3HSMeymB-g-dm_AS^9?F(j+df-x@ z>cQMZWY)%T>(ohNx7US20wTRCmVc35#G|KhYw`9hIIR_-w>N8B!Z+R)78Iea=NX?n zgQi00D~fHA#Qf^v89bozWT`Kf#F!&tgHU?sNei>Yn4{{b1ZLXyQe#mm64=0+wOpTI zSy1grqg|QFvO|NnxVga0 z{9QLr(2TIeGQ_T7BVWwNx9?fYws@6jI~S&g`)BsheRa9y-%a_yjUqqFU&4=9>4sUQ z-%K7?X5D0yx|y_kYVj@LqGMMHI#Z5tnuDr-!pScC#t*F0u zPDidBa?LPSkR3&C*G?N}i=KMVE8sz4heh*Ra5YJj`x4A<3H8 z?1!d~YST9>9PMq;r&2eZoAAm+xn?|c=aJ3|e75G*jE?AfVan^!?rwP)t0ORkl;dD;81gf;&rSE_ z4?}IBx&*xO_=Jt>=sVcG;il+kBHmJjm(bGDy67KQbM`*pkA)rY7M(agw$HiO{OIHY zd*sUauwxJtVK9hx&;|e>!_m8?p}q*Mrh)Ce)O3Hed*CpjJ`a>;4SEqcM8qT0D-aNg zu0EY7)dbqQID9 zoUpozb|=T{(FtTqPW55hY-{ikzMbcss1JY84F7pn&rQRZe*Jci10EUTh#X1K?OqQQ zKjI4+qgP(3TzL3iwH=17prE4qBMu+f^2 zPJJzU6(;`8CTia^sOwLG+9I+VNyTIc{WB)Wl_bUfw|f2eAPqkkxxFMw=;yciDeO0u zEZTf=?6d>l7~r0JI|cZVoe*oVde(@;U^3g0dGFG=!VQOM7y07YespX~&T@@p9p$rG zv_AxSL40`BWB6UGAmm?soH`U8>9`(0+21>eSs^#8k=<&VDrr)GuEw%>rqoo(I zgj0LYN3R#&niG12iW*Py!snE#-iGWiaoQQaTrNn2p$2v+29m1ug>~1AxP7X)+^4-? zi2W$-lN}IlzTObFbA2TPF27Ght4)Dv5QBs88O?`|+d$P6;=cozSUF!6z+-Qv`MdrKTp^)d9g$29IS_RcA~l6~=e$gjM1$cl*0G z;pu#}BSqs2L4fE`i@_hWLkc~HgZ0n@$Qc?9Y)l_@*Bv>qU<%bMEGwVKG7ZSt+O?2& z=Xzv*j)q%`&c5?NU?e8rSk@%#m6dbzXNaC@OcSF%ifZ~po`M8wPWFS=P5)sxbO-+T z9?Tm_Tar?iyK=*Vmrp$7(zdIV?I&iHQP5}Upi?;TUhka-mcaPK-@O`i5lNjS!MX>& z?{!}~%+InKvDeGt4*w<q+h-Gr~pQUy5FzZuAMkkBGNL9lI*;6MOeI=At6Zey(J1HFX@X zY{0pVq)|+AW-F9te5Q2LhO7pAo$zk$DqO2^KQpk>&c76~8vuT0yvw_z(@>sahcM3B zN}J@?^@eFL-eI|kI_faQ>eclsCC!Q?tH{k`5RamP8()KNf|~v+OM!`D;xa8=xtc;5 zzJS_XAlVfCU%hs5>^S(Z|Af}=9W**i0SzMV#9C(gX0_LO!xvw=@SAXQD50xFYkO*NI z)hA9|a3#3pz^4;F zFEuJoO1Lh0gthGkK6_w?=?3_*^8eg-PfoKtOHI%Jn(6}P_DR`H)0<54lJ?hrofd=p zUeaU3QM}ic?)2?ht-|_){m4RblX)q+pKpfJ(_SgQ!uo7{qRKa z10bUCQ3ur+JLM73-k&qD6nBulQ|CLy0Q+wuuVH*0rgDUxGY&c{Q(W|rXryh{Ege{g zgMFBp{^0vqlXBD|&0=pWoCh7$`-Dylx+964;aHt+j?VzXiScrpiT75?&It>W-*xl* zp3R{R-8a}>GA>Y4wgVfvjMQtVhF&S=s@W+reCgDdi}OuXv*Xbs+GeLe3PO(ZQ9dRd z`!$*B*A3L8u(+OF=y!#p`5&7jPJ6QpW#%JS@fsE#Kd;R}RUWUHx@0g{V=L{Nh)dvo zBVOmNm0=jb>AEi=2oqLiJs&=KVlGev_-IUC@qcZgGkJ5GYiWrplA=8Vnr4H7x3E!W zr{+{@k94>qpL)!9cPQV3qp#|X^6pINjqsSyZAfSo?ds51w+`gL3yhkYk#4Z;9EnSM z#CFD2l~${0nr-ZPKXQ_gj)K?V|2?%1tRCkY|4-`dU%c8B8^3tgpBsEvVsG--$rYJf zowj#F$R<4wpGV5Zctcl0@^DYvS#1!R) z2~U(7TE&*LThxD8kZr%W@1O2)3?jwYuTGUU>Fl2FuuQXzng_Uyg96t~T$mZ!_!$-% zd4Qf_fW9dLjO_w~ynBeCiOp?Iy9)!Ka?ZyCrQ~r{;CSO1`Y?zo3FWPc9Yw!bxl zsK}Ys#7tM9(uj>7xgn}fE5zqZsql`*RPJBtQ?j&hgc)*vCS)zs;(G6v;bCr5(Cat| zE3NQ40Txx0uo{^5SK1TY%)`p}=3}@~CHZ1uMCZlaN{E5JMSv@8)P-yRnaaVfKGO1r3E|n&B(fM8NlOu@tL2s%k zWg$@#?cMPjrDzP4t-d1HHP-D2*?tCQq-ubG`me)JL6$;pE%s>3Pn7kt^d~+c9TLbo zjK4=M;8GF{$G5fbVBNKm&LOLCMC|ln>M50wjr(Tom{L+!jn=2{eEu1ImDxavRxypf zw03cwsHx&~@?u?N>T12v$+z40(Ehz`OFM3|-_(=BkPjab#Qj^RD01V9%KMM3E=Q-0 zfoC+cVPzzra(j~4X(^-8*VE6W{cqjmgxop-RQUD|**iCl%nlL?A_s4+WTa_kT`7aC z-9cOk@}9VDZ?>{+Ixh8#je*{=g&S?=gJX5KV$9FgvwdE?S22svRd4#E;$f~w|A3gY zR^4hYkc+Zc?2wY|v1y-Ewi|B3cnpMJ5#j@IH-J??xIrav^e*jY=_zTvmaDBf4x@uHa67ocCLjaw1>@TZ_ zb1W4gS#R5W5wEbj{TN@p>rZ_&Gva5SWsN)0AHRI@A@*(%cm3q%SkE4ReeHJm4*Y?$ za8Gz|Z?NkKSm=z(QPP1Rh>yFTKG#*rARQ@3jUWAyjG9WbN`opY0N_fo=-m^3D}`Zw z+;;rhlIXf`H+^sjg?+8o70}>{;4;Vvt9mlsGGufB_rSKQln&_&6)!c$~Umm;%hx!b$HfB%vIhI!gXA_0*jrWK7KTRS`I z!XHNM+*jYV@G8Br9$J+{8=aRBFL~%hjE5h=3Dj-LX*Dw-r7<_wt$8}^E=rBO7a%I7 z24w7xhv2m4I=~ta$1&IYqmp}cS5VsRTZ^2OUYP&%*diJaQ52H>sLh_!ThAj) zoWh&glv%RWG9DSBTx86#k*-S&3D8yA=#G$nCA+?HlJQ}!A)%$~2N}pa17>|3`Xlmy z`r1RdC0!g}4C`~gzQ;?{EX%wzq-fp}5b~Mf|4zSc_417Q=TQE8cNvw*di(o4@GjHD z>q!N>UGXg$XZ)oO+es?_RC8FC%As=de-JA;;(t_MsGvMvFpz!7jB(cG**PP}CMC+> z)LeO&l5xo(D*3lknX4yvz$v2K(+_vuxM+0`fY8iCzC@tjUkH+d&f$bRa)NIuOCY<& zfL4k+XSRA{R;Fm z>}E&{p4&Q^ZW4*#Bl}t1W(>*J(5@_WY$=vQ^P|dfTgsZTNPz8YdkHWKSPch*9FNKANhaq-6p3KjQeFnp<3-;dS4a&nvM>X&Lq z2l|IC$_s^T>|iN_^kaYUQE8`hIcz@`-?Br<^_l$E=T;~_V-e`{KT)9q`Wv`UpX=U2rENQcq9>JXl#8~nOJml~b%3VzpD_0_ zb==i_GXR(hNh&QkyGBE&*XMBU5=X&8ncxJTyt~3qTAu`0$r8nzQ~pgw5{XanFGGJ# z>~q1HHF#XwQbQm9TQpE@JwE#%RfBs6!A3X^bDo(SEc{Gw*#pgQ@;x-k;;VHrE7@Yo zi7nCWuit`4*NLl$cci*V4PEBCxXzZuL+B0cm(0U;C?#DS8;LXl0Uz@c9j)#cNI{#$ zU-I-z?3R8_6#ejU7xSw-Bk?s&hn}Rd>UCz=47AKNvANuF#K%DEg=hqfQDj72ZnY(I zt9YBS&B9!nL~|q(ce*0=-JLk=p52W>PMS)kO=gQSOS26sOq~n7&{VA$D`w7Zc*8ul z?}TP8s4FdvpE3)u!@AWqP;o!3R(xRTwg5+@KMXvNz^v=REGGlF7aUuGIR!i>Pb767 zdFC14Y}w&vWqax;{GtB9P{`&mkic|l>&$_v*t|6j{oFC*TIT3@#@F9y)4R$(lH;yQ zeRlNkWI!1};aFKrVocIhdcT&3cPFA8fNeBO=V|j z{<){XsNPv4@?V@k!iv3T`yi|!kBvzxyx z)U*(QSx!7{Tdwc%x+W9wWgPs6A83IC6D{?}5LE<@GPukFX#;BY|ndpWEU6Hn&uA?9%RVYBi~;&eZ_*-oOKy z2d$}+i?%(65={o$C5yR2B_`Vdxofu%no|G(L%e;@J`_tFLb#A_k zv(2Rg>K|^}ax3GJMLx*mXOyNHY|miMXwo!=vEuu@>cqkj8xHIs`t(h`R~D@$?JUl` zwG~1*Dt3hFqT(4vin&PE+@kXR+>KFx=;4RdmY<2*Z2_}>bI51=K%_rjC>KE4S0epr z=}h!!fc~VqIK%0wDC|&m`#Sz&mXyiVtqkTRgkgzFS)b3f2IJ%Fdr9i<4$!Dj@N7&t zQ_;MfmdDq=o(I>ZU~_3&V(Y(Ie#QJ;+Xi^Y`SM04QVaq{Z)Z>ouo;f%+fW$pf7mp2Yv<+s=RD zv+?7rFzH=7-}Xk%bnCIpS1Elt3udjesys}7KVFNr%rL1w&KP34_qWNq`MG$%%Uw<% z_;>j#cGrgATryna*Qx&fR`IO)p ztAs1Ftn#DqSl&9A9qa*m^tpJ8*^#cAlEnCaSgs_Rvi^gBE2A1zNzFsv{>sajr%Y&; zdroCwta1@wiPQ9b3HxcC`S8BTjiBo3pwJPBUQ56UyI7=Mk80n^Vsu6Ah=Xf(?VGif z*FYi)x0!vPW+Y_PA32ilPD4s>I`H-w34sg+E!KPyD()T7R?Lq=W zy!SU}8*}h#g=FAJ{U_0l5i1m-X)Xf0sY|#2$(i*BqSAzc9IE6J=bTX_-6)G>0 z+!0Wx2Lh$(%bgU$D1q>ICmk+^Oc|uWP{|c=IAn#Q#iq#__RZXz@|d@Lz8gJdF5fF2V& zcL|9^NEF%4Dk&><*molXOGUvP(r@as@m|F3szsLXx@HIG%lN-b`_9=yz1qLvkkohAgCG67oXrhB>SLIu=<*xLVkdS=d zRU$7oj|^NeiRdvvUMp(zyYr?xT7vFa^+*aBE^;jw@y1vzt#bR4{#Ux@j@HZF*B_Av zQTVBzb1^KtOIOkibm;WfLld>S)lJ-&TixHywt2B=N@V&5y?U~2Krt_T~N5T+>Uo)v5Qpzmx%zxvvkR>$XAvla7jF5hg(&mHX|IfHer~Us&Qs6+EA2W3-D)=R9c$8~?pH-| zrq@8#AzHU2?fesyoVdLcM?ktw7uL_^fdf$d-(Dz-fWKOZP_!=46 zfhia~v9hVtbIN~a3yr>;WwIKQ@x=A{^~M#R)NC!iFXw3?>AUk${=07zBNJ65%Wc0J zWBc?_{X5}5JFlFn8Q%BwS3bNdvWj1NJ&Ts6oGXhgT9uumD-9=V)lgpREa@%M4d9)H z6Sa8fC2E`X98aExc%8yb0`>4(b$rynL6HpQc>b^d(fa-|7*27paq-DWY2Pz`VIZG1 zmv%$tV!z-_!-d^K3%a$QpMvVG=~eyHVvE@pp-w58_yHkTR*6R|Up4h8ebR!ste68>`XQLgXH|=YB0MzY({B zn4R{MUfc4z2mCzS9}`(6?P}Pdt*u=*KK?*Qj~p1`K2<&6A4t^hQ}2Cp-5mgbrwBRy z2UH2T2Kzp|bCN3MUz$jo-eKq?#uB64>RIP&sq00SDU2Z3-t>?1Co7SCjcBFc+ocHV zOp-vziiRzW`ICcwh+d*^3E=3>!$h?tD7PUEAy#KPM`-Vu{R$!mJ;F{PDZ{*kC^Cr= zOs6LDf+B8))kt)Fo?v>bUjl67$ka} zWZ*0LJQx(7!_aiPpxEq{%)mpozG)XcXS+iiBpVD4j93Kg40-fV3H~+TYfN67Z`A*= z?e#P%vOrWa7E68SqkA4{)gBtL=%-80h-TcaWu58qly#DBmA2hhmzAfq^Xf5cFdUR} zDMzf5n3D)IH+?z=wFte4_l^{3I-{hV8*)6yc;w`FyMVS3+rT0HYrH|oDdP9s(PA!v zF#Y%(JL86tL8*zK+h9b){9lwanBT~^YC)w6PjKRiuRrCw>)+>&^il=dd`Wt!>k^ZV9+R*Axr zKR9t}yo;?3_rF)OQU)KZ)ZAy6oLagx542jzQ61prT&1HInucJ`r6V$uYh7i?X?slM#0ocgmqJ3Quw`Qx8L0Xnk-172_HeWr*bg&yrtmiV7l zHg_cbmk{SqEN$vAnlSmZ<)PLqG&To>igF*~Jwi`*9vX|z(i1Fg^_yNfusC1mp?I!w zMlJVXRXP!ubs8FzBpcQJeW9dP$}P{0)FreqgUTp z(*fe!46&-oYyOR=p@*6ej^enNx~Z2GaSjU)>W`vvfd{-F z>dxX|8DukpgX+JzbE}sew1+`OP9nE@lrh`e7OTNnDRqEK8ves!OyK?dN>W5GZkmK* zH_xxOWu>=%Ryk``@~n|1BaytRLJ`Ugv^P0r*)mnJ$R(b+4U+IUYAqgk5&^R`{qSd! z1QGqfY?4k9=+N0~x^d)=P%}-K`34RSZUi^I?AY++)mTm=?5wLEnfA`N{4+)tJ)I~| z{EsX?@DgNeTvGH6mpL!r#YMsLJ$XO9i`4XfMT@l60g)pgU7khbUFunOnJ-Y)q@;5J zKKaSFR__%eEc^a`GItMnRVJz5G2*wu%k&hp!&M@cJ?k?|+xQnw<<4*Ip{3S&+UHCidomQ^ja`^Y5Z6e|j|+4xOzdbtrv4W{dVfgFqE>Y{0lU zH^C#P9V3=6oNUI)C43ZeOhREDb#>E4|Aa}bEX7wgT@$5Fr)c02t&sWN+)$AAlW8uQ zg|L;!mT~V_`Y!Rm)bLgwOa*E=%+(WrLr+ZHDzK3UiOv(>d=&EzRqr9ZUVj(;mOHpH z`$WU;SUvv$Xq8T2B|+waVf$dp@9Id5Rr-i;V{4s<-+YY_yv;8P&wG@qkM9HIuK?YJ zBl*iyFEk3h$+Y!RTSFgPv3^jvE4TE~0j1?I--ub4wFMDQSj{O7_9q3yR5^=$Gqco( zc$H6m!1UkV7c|(7`0NknDyb(k3JnlTMGrbwtj;4K4TGX&>W+osrCufI5K|arENi5A_^S(~}CQ5fLO3r>zbBhxTG)-@Q_Ica-SNW}-C%}oTKZ;ZGYiq1;VwK8Xd;vS1 zE;N_^F`~p4E1eW8_7}Tmfsi(bv3iiQ@yx`PDd;Ysh`+M%YhQ7czp>p}o!iRi556kQ zq7&V(^;e-pFFSr)rZY=>)8f*76T{#)t>8|RXbTjwMq>Se560_`5`2}ePvmB#jJaeo z$t$HpcWEcSV@JrsE$~8*5P@=nIvIp~am6%3{KgcqbU)Hha<0Qi*4$p!Pka~O%P3!Z zCEh{^13Q;i@PeS*C(ci$Sms`jOjkYwM-`Iv)V*-<3u=HY2atGLNP39*^OIS7BMDmJ z`{KR04`yfdFPtu{u9$*Ehk{QCdkh?k-PE_o3UwajE2fnprbmd4xp2hN*yPcs{$T=U zQLaCvHVu0D5B=*qc9Bo>QhMqiiO+Bs(bF&XGKV!np#_bK$}RDV`>ARikCk3Uo3-gN zL##x=O}C8-H=37IVTaAzifpk!F8a-ccIvl%;`dtx{BuF!HvMna2eeU2-xC{ZmkNvz zQ^<<}7{Q5lv(xb5)XE(r3CLnt$CEyMl{C<$ko@OCSF%)r%H-H#Kk_iA8tvg2HEW6- z$sTxNCLqVN^vqFFgq8SHBY{&d!xA{vpoO0}z~>JoXfJkOGduzw}q^vPS}5~qEE3g>ntX;b>(XZ3Yf zrH-!%y2@~NGg$1`XH2>|>v4?yn?k41S z{-yAQ=jGI!r(>ArUa<+>-*2_~1)NYP|o_M1Y#mIe$q$^PBRkSgB^CgR>&? zGSiwRZjx?R7J?^f%^9S7A4Gf9-8PMh-r%FouL z>c`Qebc$j1nO!gAETi*qaGGw{WgB}HT+pLL3014?cvM=LvE@KeMx9`1<(a*-hqtOL zGdVQAE}W?;zM{&bvcIqVWi=@1W51!LFcJBu8gV?032+ee!sUtdcqEr+f6jdjk*7>H z=0PbdwGMOiZ>Ag1-qiO@_!Ws`w;_VK_nBCbG)va{%8c(`t)&fq8?&-z9u)fx_xIhr zgmfP@QHRK<*r7y#Hqr~AA1HpcNT1M;@-eW4<4xq+MiX5!VnSq{*2QWQ=H%t+UD{6V z{uLFRV7zhta^F5-A9!>$Oaw{rk>o2%>sMA z(7dxNtLP-^QZ;qW4lJ%BoFBX$QgAJDCUWuW+pKYMl1}80-ei<4@Y0al;4a(jZou1F zmJ?gH9Wob~x97f$clE7byWSroVD4(7uccKxe?*)|E3{r-L}4LFsq^p}w;DqUC#;U9^an*_c0U&q5s{#zscK4>NGQqWmjcmPBKk9r6a@gWilb< z^hX&smy9rbB~|NPoj=*kDRRz)#o*}Cz{}Qf8*s5rraeg7#o#pt)9UbCJ&DMuMcw(y z*H^4Byd&O=-g7413yp}ODA3(2)z=4wb}t&;b|C;E$%@h#QD>dD76rSFzQgOW6++qOXn>D4$K|G!=f{S2fO3e@E2GpU6`Oo zF-yKRq0rYi4D^?~{%;F@k(>bITct$Q~;$+=cZM8GKf#SRpeylbf-{{i_h`(;O!} zSepJh#6Q>V!*!@16VWV?eg6861tuD3weAI;LrQvG1-sRWK!nv?DJlsnZWS{TPMG@& zIo{utdL8}f0imkOP)M|0P%6}H?!-rq`o;;QZ=YQ(QzT0s(l2UR@^h#RAp^xI@yN-$ zT5&1T;JO_rr7qL6f8EQvg%1gbV3pGS@(S&nwj0YkW@@Qx+&Vz5+Mcl=Lo;bo@u>&C zgl_oxboHHJwBvLLbyR-i8Z1ScJHo08->cVDGq!A2)mbyfe&R1SHQd>nbzX0fj2Yrf ztg5`iyHYjeVqWz7RFPoF93C>#%nJdc(7$m%=csdSh?Ymwxyapw3XPDZU3BC|z4El= zAw$0ojOSZ%x46#oPz5p4=*eD0bG-BZFnj? z-(*P;J8hhBgxme;H;)u|h3o6`X07=G(ov%$W#KTXu$4TISh+Cr%JAyO*H;CCTAMiq zK@C{zDxKE5hAJ7Sed*-Ny${3M>Jjj1A!sEM76dfd!Tj3QrDWC>HAJ+#AcyK9V@`8+1q`=qG6Peq! zzaqe97V%%)X4e1CZR#@?_DgtVQl}u^f14zVx0IcX{2iz6_uhI{W}GbkA?YR8U&!>` zwPo)I3R>5&7x!-@&@$@Ir4*X*+5Sp?63*V~ZU6pojl^bB?5gK!EX5v>&5KUYp`3{* zoIK~kQ5Q4wtE??Kr~gscbgVRTWg^{rY}!K7Cnh=s-74puP9zW7k@5@EFEsAcv-rmo zxB3%+)9z!0|HIgO|Fhxm;onqilp3uXH4?i@DOyU1S*lvv`n2{|JJg<`_9kdcZKbpy zwP$LzX4HsH#Hbk~5i=1nzWJQ^uYY~tWPufo&=~+Lm z3*<)=9u9(hYuR+~q2a{u28cPu-UCq%?#L{%R^b8|*Sa{oFzg`Pl*Z}KF{j_#_=)n* z=V_m~A_M|k&Ir0E@u1w48l$&4>)^>{hD3qkLAw(Qj zL*#$dO1GT_g^ZD-9X)2{{3}t5=Peh5Q!6V#2K+qmmJGudj-JW9)NZTR*h(b)+sTWS zj%1!Ij@v9#mvHkey1a3Y=r_w}cB6uvtp8)P13Z_- z8IgP~MwWp+p?G2_QeWRdB{o;c+tz}7khRkHmp|^SKvYnFjd)PzwLk*l{k(TssH>d> zLgyX5f8ZLXer;0Ff$xCG8^^g1buw4SS%SZ|5IM+O*N{KWZ|l*2 zfdHtIe-R@`SXbkRsJzg)(z4rmnLB1B{H=f&OQ^NrE!}NmP2Kz<^XAvC zu;-7gWLUO;`T>2kxDfX*?}qt2+6v%h*Exqe%V}+UCq7o^K&{Oj)<3#OeM{nLCv7mj z+992y@Ab6ZM_D9C?02Em=C-TcHD1Z25Xd0UrP*PrzMJeiBnQzHQRJeVje->^fRD_* ze`vSr6wB@UWT;sxX-<p7K8MOdxoY1Xo^lYvq@|m{>;%k2k9`X!&#z61Q?_Z&CzO%&Xl%09+;$m zAE|4XS#WSJo}}Taf?JH#nJo}Wk`TX>_mEza?m87qHX0M?rzV+rJx}sGjmXp1lvcA2 z_?I^S4Z9ur{07uytmQDo=j6Ne&$+2eRif46$#5#}8)+hR`#>7yRadKE3H>#-{pGAp z^}O*JN7)YOyKA@oGc^BZ2rbOh-9I?H<0!yE;CHV>c`DZF%x2Cwz&G%w)`OppwvOM+ zs)!A)(;Iz)E`9{>im36-E-$ff?5MELS=9TjYKa#;L8xWA?vYk!(5wr_raBAK`oslPYsq&0gig| z+~5%m%S32Be=cmpXLYfJm(IFMa3qC?54xDs{U#|-zAIQ4BLj`A=o>KOhqEyveJ}pXoWx6Y8&gL;3-%&fJ)A`AO7% z@+onXJ+!|WyP5i>uj?WJ+%=nklmY@et4^=@&=05^s%WKVb{^TvW_YPqukGyy>h z%_>qS2g30-jGk|meHR(*)_8$3DGHc#n93m`I$6{eo$^thl98L`0BK+`Dn%{W0Ni?O1;EwYG)rAo%@Tl>=8{|{R0`CK%;B7`} zltJjR5V;qm+ORqLNtKh|aa(cc`o2bkP)(p%zNU22wb7}*6vvEqpSu(xpmJ#1f8One zmil}n9qH=W%>sO~0Sh_1Pi`~FeP_UbLhbUp_Akb`2*jpPQVrLTD}&)G;>+c@c&e@H1@ z5@0(X&;8SG?yX_t)fH=fh-qX>K`G~im^Mou?iaX#VO2fCr^W|b(J&G0QwHM7@$-;A z^lAtOc{KibpagnrOjE%UcdDZBjT|U3d~b@C)2SjH3u7Qj{SJYRPtRzEu_H+?4YMR2 zbLm#j(wX3;LCd?+kq_xnyCfq^*W!QH#iHHSqW_$aJBh?!`DJ6I!x{ac{>yQyouDU1Y84~frgogq^gXz;Gs~@=!pX_@ky~-;{z$h+l}v-fjy#jEHW&K z7oGQ@!ij!=p~Uoac&@w@_@;I>TkTTzTA5CyO7W=9|5`aSlb5P zhGU4VP9>tQ29<(a{*B#UJZ)F;CYQGDQDSk;I}%pMt!Kqyr>QtcfO7q2t^r2lyF)u>9>Ne~$CP(sECGF9G2!kgM%IZ3jXAu@S`tqsm2v`wZQ6&HBE_qY%zdl3+%r7 zm>8f6iy))x>cjo`IjK+SP8d=N8pGO-}gNF(Fl?*?|?=9nb_K= zoUL55Mmfxe(n*bfCtpeN>&+UmVi)^6BWP_uh?^1i>ONSTqIJ$-k&#M_tV_BZeRQ!< z*owfkr5JU;oC_g0XV9>bb&LH87__*ac~(R_QU9X#2>j zlMwy;u5s@I?XsTC2|vu~J-HJ9wijZj+x&#b{lS58=(^|)_q@oERp>__s7+&t_4v?- z0yD5P_8|Jx>Is#i;~1(eA>9=&O{Abk#!r4ClO5gtNNK5)aS{1-Vjq;69FzIoLdo_a%*4emwZ$0-m`@H)1LDIV0^+?Gz&5&U( z`nKtWX$&x`V@gSlUlRZ=z!#tYc2(;xNihzz)Lhp`SEJvqJ6AnggcNaf1$!Kq#3cd&~2KX-94?*Dwr z$-qMuTt=lLs_G!!vL`Shr>4*r>bdIhV5O_vqOFUv# z_#37t`dRyS+ZObdkM~V53eekM8|M0YQCoT==63R3zO!R?aj1`FoTt+?T6K09+~A`E zd%>?D|Ey;davi}k^#BA9Q~5P0Z~@ML_jLPi4pf+-o|8yOIC{8PR6x3e(b`G7aGyU5 zh_7F|QTdIh_Zludb*nJsL5?ud=YVO9wb)jo7xPCKWI~sl7oWk09-OlAqS;C7x zVBTxE)hR&rMp@l-%qpkWFNwGagJ3rVBq^NF6AEZkZl0S}Xg}u*K3H?au3~1DwGPLupQ2>ovW-D zxISY@9}#kiJAIh~&YJ%bIG!K4&KT z=^o7_qiixA2Lk=iO?9zkTu8R5A1K&JXTTMeP6yc%I1jZa(RUrkw_lX|yhDq7C-I8u z5k5q|ojG6i<+63M)R-+y?3#Zv+(L{$h?L}TGCF# z6w>r@VK;!6bZSr5D+rWZzWJ{?``>Qfr^EgctkmR4bUjd&9>yDSzo>D#{tm`m~6MFOms{pEN)2kVdw<76U~5sM5CEt}bqr@&ibtoI!2- zu`_}ti+{$^7YDl!bHFJV%Zodr(#ajEo-lUxg^gx_5$S8*or_7g5`%eQ;*Vr86}9(G zDG$)VLS2Q`*rf9!eJwQ?uzET8jl6{q&V-dqfR8N_$xg>G>YuzPw*4Vl!H9CGbITZ_ znJz|S-PIBm$Ko6dRpJn`-R|eXEL8BAg}xuBBiOAuZO`IA%D%^}g4y7YJc}J%XodDY zi{KSGLbyuoer9{=Er!%o3rTPOuBxywSFSE!ds81@QFO{4%O^{?XKssi!e(RjuJawh zM?w`?63y_u2!R`5-|df8XT70^D*!sry-y${Wit>H>yw8l?xQx#@X8RY<7G}ewspguOmvZgem4KIoCoHqfh>f8=()wJ-7h2xuIbJbwO<|C;L%m-hpxa!4MW88N6 z4%7Rxo3Wk;&vV=Fsx&S8mWD4hdC)Nqk)vkav@D;V6&a}VtBKlj)D9YgHIv#NVm<1A z$Z@z3LaQfH_-Tf($-G|ND|Fm%uX@5{Sx`PoO{65AD=IqEnzyr&7CR5xVHsSUPj;N@ zWX)8n_fFc0nfb*7${!($iQxQc^&g4shy^`;TdK2&efp^E6p!?I^t0-Z8fgb!&oeK zB85Yz#)$PwU;AQ{$9&`Baq?nyMus7gZ`dN2Mmmr-);ls^Bj=JIj%yM5asZQY&tX*A zVEs>KPVG-1n3V8OX}OKT>$72 z?x@rv$-u?MJF_e{(|EVt$wgLH$1$R*y_(yM8Ee5>UmvE z?9LuF$SSPlo^o&tc;kibbd0e~%$X1|Xd4)tbW~dcTzgp2IqvW&``(wfK!HU|u z7bz3RMDGnoR?jH$q`vX5a%zHJ#B?wUF93IKRpVCzvIb`4&J<^Dx`$CUR&0(ud}nIM zVlC-D@e&02q&ZWepi5=@e3%y6`!?sHgbX1A^ZaA5jvD{IhOMX&%eLxLNJL zY-b$u@$df*C!*#mNAPCCFA$ z9;ugGFw{lXK)QvuOEf!6C-`A-D7YpX=DWQh*tOeYJ4<+YZ`>6N9oN zr79F(+cRuZxVrz!P2KBB2KMG~#BX4Rr5Zk+L&zn}@zFV$A1`gMqm%eBcD4T?t7I&B z=?!AFpulCg;L5t*g7jPzgUtu@GE)$n(&x1fIm-q44~@ZbkE5M8}8U_ zn?fmRtt%s(9SfA+pk51vP7~_=4!$(=UVpxddk&6uO;?z>w!hxy*fcP7am`PYNe$%I zHstuX0Na%pZmckFzx~ zr6;C7SpF!t{-KGwb1(7oZcm=*C48!sYAtS`l3!?4Jxv_3_k<4iBi|gqh?srT(duur zNFp@h7z@INLbsDSaXpxV#*QPakRho?*m0?QjFsm79MuO({hwX7hQyB(l-zF|)};{?wd=*t z>x90OkZ+j``53e;yn)sY*r@t(xNS zSVfP0JLMy4T)T8|;5%>(tbkYlLX$~$%S~tSbRm+n;M$#9iwrt&$M{3TZ$$a4sa$+{+4XCyboA`3qH5QLug^Vg z62ir`e!gzsD*St-uSyJhBz)ceP<*UhpXucBRow$>!Eaxs(OAb{C8_f_TqhRfHRzvL zWEBz(6{Fm2&suxYcl}8v$a@CrdoLHz_#1Do&%Du-c_X2b>rb<>%hE>luVdT%CIFSw zCp>sX0*4N8ZWu;OXsJI*@&T(OPyUBhV@*@D!(4jO!bWeA@zOJ3QNTwsTKL=Lj}GMxVN zANyN=$NHtDr#7m44=J7JI>J%iB|NkWobo)u{H!N)DLh2m#w65`klcZ2(~?DqJ-Xbx zE(63LupW&8A7vZn3taUI(|Nj1SeTC`wE4F?TAd6{wt8+H#=F;D zc5Ui$zPQ`0GCHs@<~!UZ*xbhkbKbotNv}C{&FecUxy*fLv;Uigr8(R}C@he_4mClH zKOW6?dTAzdgnOz3f=qCHyZKm( zsqqfb?kcyP>bbl5`s2m0)`noZNR^hUofZ0YJgZA8#lcg?ENBVxNCDGAj>z%|Lbbcf zhMeDTXQ3hU+q&liXyL8`68zNDyA$wM6NvHJBBvaV5h2PL<%n3L}pp~+*?3|#e(1eqM7h;sTG z1VO7P3(ekNcYUS$+b=Fpe)|OWB4={WpGFyUYw@3NzF#>MzV3DFM6hfmGfDA|*rXZ+ zwR3-`_eVI;FcRfrl<5tM8fnoM>}GO@MSw%uJu+-mQyyvUI3pXg#J5KHp0EYr@E= zy;LgdxDVnf2cWSn92OuS?hi<#^`twT4z4Kt9#fW~_;kf{%1OukN1Dw3k zz?w8&q}M=)U1sQ#V|&^U4rqJ%sX(_jb;`sqlmj#AvFMMy zg4!w65pTI<2{IlQh5(q(59>@Da>xmEd%(I5;L*0{%`Ib+EZ`3Wk+fUZvh63-tAaQ| zS__2i2a6|$k#~;RzBDL`tzx~u5TMuNlX?1Yvu0#XN1?ZyEno&Wg86W$iS@+5jbooZ zr+Uu|^D@Lh>^sh$Ymt-(HcthA^Mbbx#O}0lIxUq2ub3pIT8~RGU{S@TkTz{3?ey8? zZao$Zt!4c7X>FqYg0j|S08VGlqZdif$Oj$dk5F8}Y5du$Bhih?iWpz}!CPnZhQ1*U4pc!0%~B3@@zt$|b5N_uhnudk?r?L|{ z?q8sYRyYGQ%AEx*J(YC7+4=3#HhH2Vr^ZST8J^uBdhWKfjdvB-xUblDI_pa4OqA{h zUkR_CzfY(B9N)?pGG`pDT|B?}-blK*BAvTbQVu!xiB2%Z{y5$B`(HkQL<)v1^k-~8 zv255q#nTDR8Q$m?OXTT@$KWj zg4{1$+HJ#+f9j@dpDp`PT(Dkuw6wr_PoEB7wlkP#?zH~5Hn%HmcdYlX%)$RFJ9yl1 zsq?Zh9lg7{Q}}o4VjB>vGZp0M(FXl~^t7PyhJ#exL-j1z{iV7jQhaY$GnFhWB;?(y zO1~&&tlU%)>F3q`%>ZZmQ6nzMBYPo(+{yz`j7ETPhmp& zrV49QnCTcFWu?ZDppMX|t7Ah;2D6 zL5HO&cS?`6!1<7s@rD+R)WM41kK$q>3ivKL8;P}S37xMDh6hrf07nysetv!&CmAa@ zKrMc5Wscq;#k{~z=)Jv8yIu1efQb1wb7M`-$3=OPVGd$`Hr|L}aK7rdyRYzX&$IZW zL)kqPGUgrnlv`uswQ<|^+&E`c_;oDEd*Ub<;vP->}oa8*ej#lFwiWtd%Gt`kBZ7nNmon#FBkZJ+w3f9?Sn_gS;R``K!ZT0KJC;@*LsbC4W_ zUY>#mOhFjyxg)mKOS03PcUfHqPE>z7wfa}Kj)y(gz~Ykt9Dgnb+4=4TOZT5bb~I{O5~(We+Py% zwZ4Gm9OxIwK!XB|4GbEGRMqm|=Sdzc1~KDLcRBs=XI8Ue2OTG5!fBlX*5hJ6%zAq> zKK39mHZZ4{jHy#A2yk(CYd;xr*rs#uaJTQ^b?m*R)}5n|T|F$pF*sV=XJ&Gqf3H|J zx3a8oYgmR481&bIyWdIjsP2@Z1p*D6rM{OVvN-wizo#S7jAEhrE804M9HdGgTo$=> z+`SNRQ0IsFSSUUJoXeS^NQ==fLDN$!PEK%NLdAG`(DWVkaRA=m4BYe z|GP;;m2?j3|Lzo(P-4oY6>qKj@Gx-Z_Dbu6Z*=Sl*2Zr8^6ImK&d=#|OL~@@=mndj zcnkV~aU9Iad|ikp(jnxX4$R(MR90^WSQfJ}I;aEN{CY;G6uazXK3NDT_7Ix@Offtc zQ`ZJsrrWXyslMKNvKY0UdjzWq3=1O4UVUjFhPNc@iFt$1yE(AI0){2^(AbnoMN zsTZFEgQp)!Yv@bt4C1K{dM!!Y>oVHIlf7Za1)+Ji%+&(iU3XVnOGFR0rs&X!4uSQU z7j%cPO?xz&RbmB)kGK6TZ^s0GqRr=36&|N0)8*9r)GT-K&4vOXbl0`%P(A4C*vq=` zZd#jo&)e!x4lc1t={l3(=+>fY=x2W==Wa`c*QZ7M)`os3%3bG6vJnx|Sr*Do+z*HJ zxd)#lmAzf%mO=V?n`1SFKZvZ;gzVtxUKXHc?If}2#bD$PGz580cTv%?>WN1!Ud%SR zwLCn6&9G&16$XwcTRonVH-lOq3~2&_Z#GqLmcEQLk-?xsbUL3*PEAPw(3l_QchP|d zaE;ylz_`;#x#nc|i?$Zj_b$Q|4(+M8Lh6BcEE+cnJJ3>R_!4~cyke9)k0>#-WQB!# zvnKaPxeNu7gx2+gM-$y$3f>dVU|wJOuGDs~v}dc6TkUu4a~kNn>e3cyMkxR_oxC<3 zWc>*7Tg^7acZUw(U~-*T703xjuyU=%ffTCo)%{F^sqSemO{QctF&N1B`H5@f$Noy`MZVTg^U0Xcel#o2Ok2+# zLW>v!cdmf6z;jU_0*}I56$l}1rSHHjA+%o15$1hPjmC$guEVB|pO;0ZYs!~KdyXr1 zFz8ft69YOmp7$l67wRaOM|Z#FXmtF%1Y9`(@+#DI{m;3| z#qK6UBSHT#*V>U7eNS4{ip&1x zHuLDVTkd#Gj-fcd9Ih+y;r)A}c-}$rlN_N!Bh@}`V3+{9dnisRm=>51HlB1?5+%3<&S$%b8iS%*;$PSOiWz6;DIlav&} z%wvD@I4$)b{rjHypQ|aB#1_f!tR}Z%+(6xpj9=kELt%B;EyWW08P>V{%fe+T21{cx zSyLeq@2Cepqh7x2O@G>03z!vjWgUNW_v0b-sfRrdW+|WW&2xYJ@5m12V4fptSs*mk zlA~L3IWWFKWBsIP1X*)s6?m3zP5+f#6Xf-*`{yvZmJa&;`-=Y{;FHT#J3wr?K6klk zz`pOC*>jxVqS0IO=I%o?m;U~6XtY7LLc}$BhFR2A)hd*woMl2E#+rP}Um>2F z|A}9)(Y6INK-aiMgh^sI{4akIPFZgTVrNeXD?&yU=~`m5N@AZ_wrL+4)d6cnoa50n zWuA%F3-+7}j4^|_&$|rsr*2YF3UNNG3i~(t`hqlg4&3}3Dh&H45w;gGrNwS1i_X^Mzl4Y0i^z93lDb`Xi@BcY_xXq4Mh<6X<2uB9byfC@;> zxf5}7sr-vO{h?y;xp!PzVqi#6K$}KBL$0cF6Xmr$dfJES4W&(kUFXPshBZV63|?#; z&rlR%{gU(DWx?sbX%8LNL*HWNu#2<7I^+zGN4s+w7_5Y_ne(Erx#!_&Ka|C@;_S&v zYHmq~s^iWFk7SF8)Gc6NiMDIFuDWu;5r^Tw!*0@Ea9!0!g!^cu9|RDOkTU#TyoLm) z3cpm#N`l>>M!UiFzxvNc79z|&ni4H%X;#^%B8`s=SJri19v5J}=lS!W@f%ueHIi@i>fp2_J)QZtOXh!Q#_4~pKq$xRi(iFt2I7^|ps^@=))DdQ6$f?U zvDnJAyVV*xs_x?0Gkt@$LJ}3{Pma)Y$J=X@iMb}p;r$% z)3IkomPTD*JkBtFo3aK{IEE|L9s+JHwWxiXoFL|qnBxcomL|t{N8w3L4^3xAM?GOw zCUp86lWUJ!DJHM>eBDzfRgDb&?}5P%+|$w1m3b%}x@kqbdCiNvsi($W_t?-G9+YHc z3GJ~Y4?2cmg>qu~w0?aWYE@$&JhEqrJ-g`_%%jSHD=zd413L|Hjx1~*uMGjqu9wee zaoXY~^zp^FMs{$Qk6x{+&U9bW-rfsZMcn3=wy*fp;gN&u;wnTw^W;jEF9FT|x#xIt z*1EZk+VE(3gp?Bi-q=m;NS0cW>^bNrmu>p(Ss*d7B(r{#<%7u$AOk-DfIok2DODv% z3zlv*{lAhO{69)|Q2;0&L_11*RVQTDk4bTe3=^Xr?q(Kzrk3)KNnn`<8ut?6M66_e z`|dH93O9{a&_wK`pnX(-JpOOZoOX`z$WCMS*)%iF-wHTCCC-37RM}X#B_ZL^rKNUL_5LUo z_1rG*-Mg}(qB3rrX-*XNMrTPtnvll74If;wIO*rCwlo>zWQqHluvB*Eu}2MO(n@k` znzY?A8aX}0clRS@IE#$D?szsyzH^*rlrBSVFsw|<^ip(8eq8fGD3~*GrK2-i=4-Yk z!RH`m5WG0pffRsvx0?*S_T1;K&Q#|*Y=~mzYWm}uQAmVCQ<1D<@pq^FWS3&r~Ugrxm#WkY$jp-I{)<_NJz+o&(vzC3Ak|1q- zXuw$=rMm;VsX+1L1^hZ6UL?t(rBcipuhfvJ;m5thuK}|m!8@9gxPRixBJyaAY@_0; zN&%<6N}-vI(ZIl|@DJj&E4E)^`bm@qYsnjr#n!-a{mQ&qcwdKUrShxC5$*ayQ*X9h zGq*LfHtij%I?iL-j(;cgA?t`D#!Y?6frsxi3WJSZa)1BzWSxsPc^V+VH zRos4qX&um9J$}ag{*@IWv&z?mF;|Z$$p2L6Vi(W+ScQM`>vnDr{eVV1DACQL+VGD` zf<4UkfQ|7AezPvS^q1z}^w-S~34J?hXW>cVk<0uiUtcqy8IMtu#9IAsLWl0p((Q@= zw%L7lc*4bFl{vti&fN8mSLa8)q4QN!=jo8RXE`J4y>2TnXrb%nCok@O+;(pG`FC_) z)kPxGMQJ0Ei7rk04|MY;4QPF#>czUuYW7*TyJ`;KmFuae)x!BF6KCyS4h;+JJ+CDj z=$KZR5YX4=%Wo_ruR#?&?+aSwu*3ye_MKqO{gUe=OG@EN{6o~rcg9%la0%1LhRA-bbI=29heIeGN z;v8hzUfgI5wa*xW0{q_?84b*n8Pe}w?n8y}D>T$-D>kFndZG*Z-}p2Xd^ef3kCj)D zUZC`Mq@-{Vc9%327K2(JeK!i3%`#x{)-0@|Sv7W-I!#7G7xKd>l{a3&zyeQ#FJnt{ zAZx@QwbP0A7kx7o9TI6zc5W6z<19-b!VTJq2#uv49GBp#z*BA!TdfRCX3ZRx2@S=z zxk1iOwRa&xS-pLEx6-+u29G@2%J)9(@>*p1YG4!Uf>+({YF3lS_FKyxw~fxl~S$ClaD7u&;y+%%r8# zp)5yVic5J@=E?o?>(hwjRcR~WrTF#RfycfzB|OX50)Z%$>=iG;L12QQ{qQObj>)3g zyuxY_cqAL)f}PLmzJ;kUK~!^4KW}u2?8>Sa>DnJD!)Ih%g;gydLh;z;mudjcuPm@f zys3FRy6)S1<+evk;h`OsP*AT6#NFhwF4KVWeI0ie@1^07*?^wT*EIyUAMHB*i$f`< zf4G#Fr)SSWk8|r+4t||?J&PFMRPHU%xbD_e6h9}5j^BP+;F!xZwtUdty_C@-RWQ?A zItV=*p|l<41m}+ zoj$IhJ$iS|471A^O5naR@X!7$%8uq=T!!WcfARsB@_F=`b~!Q{-TpmzGp4 zLxr1fZ3QS6s!bjKF(T3QP?=nF-MFsWMUuRPeGee_W~t$C9Z?stH-%*$;zexNX1|yh ztj5ywV!oj4A}QSSNZ_V^K&iI6;OeKKn*W=Ji}){jxD!GFw|)JP3!fHknnJS$JpX_bzOP2=*_)5aWO1K}D$k1sbyKZ}`B_1_Z)Lwvf~e+kBMrBu5%*x$lb zKh~F=ZG*D({$#eteL32DMJnMUw`+o9A?lvXb!~@+yqYm@GV}Lefp*lP;tDiVQX)Id#YYPm74&_ZQ+6(%00?f92DZf!4Luu3I zS8Tp!ubsan+?5>3B=))R$@R+?s)TGaI#TXVWq$Nxz!p4k3wsn$--x1wMESlVoZXIZYIE6p#TDD{oKDChlMbCVevb&(KwELxH@ z`)1>IEIu;NgFOFD<95f!zW&P=xe{oW4#C;6W14y>a|}s$NJz-RJYa(o$*-O#C1uFe z-gd}uSm4-DsU4_7r4==4l;s|LL@WjJE!UF*41<<|*LY5(Vqs4TXRU?g?9MEy$X$+uxJ5EiF@yGvxaZNqDI zeA2YenY|`W`(u&R!Ho+pm_CRmX85t<3(vndT0*wBf3c)quc^LC{iNhqt8S_potQlL zH7yNjsK1hkpelCY&i*iy0(fdxJ12Ib6+_9p?RYk>a2pb-N!N5|=u$mylEHhy%1tdq zDO@B`wYuXN({8 zqDE7%V&KP5YeBfscKzu}N?%KzoY}tk%G#^%ESG<825bd-9|&&$Q9PbyJ%D2hnxsSa z68%DgZh5m7!H!<^d!kge2lis1L*AvPkdXpS6eF}_dO+a>tFryO@?PV>$aX6g=}E7N zfQGVM_wF738}?nWC84i*HC%=(z@bwBUGIBbXwt9t0_4JCy2CV@fD28LVdyJ@rpK9K zRmf5wTXq)2YErsFpV#NtaU*Hhb5&IgxH)s?73m9-?;3@!&%Z>P%nfh4Htjmb`^K;W zkeQi|RzV`Y(*F#||5iJ@yJ>@9hVch^(Urt}BOH4dCC-{^0~zr_NND+vdmy%ghFlSXi;lIYtY8?7JD^a)wb30F=` z31fQxaVmVTT#1BwviUoEQ-w`?x=&Bfj@i0?gIS)iU1x9CL9tMs0f^n8eB(Pvhryk(BbZe|Fv9dMxqZG5 zrqVD)F4S^k1ya;$g+3C6UUv_Ft}$`6{W?;%>pX!9aiIYBAM1aA zbyAuaB33Enr;M?5tKU~K$*$m^wLhyFYUGsn&l%c4c<&K)M`*;)ng5J;KQwS8B&PDu zcr`RMsd{&X?zVZL{erUXWa(7v#>?6Ik~-EvF5>`hAmdG@(E31VI&S%UWY>5v1TW86Wd z=bQ57j?P&BF%GZ#>D&j{>2lxPnq!`=B2Lz~XV{|Powe!Cs{iRZ>GC);alKXoj$;~; z@aZbB_gvwJHss{W=BagN%{U|~Gu-r)D4I?Xh=bK+G-W^3?d7s1#_^ge&;I5NvsXuK z*!KI~w&4vzF|evoQe7NjJrqD7%}LTUk!%`}+nV{}{(w`kPEgN|0H6pzps;`K&5pB& z(DkHy$6%!?yS`K_-R}tw<<#9gKYpmlo_S*zc39J@wqMb#>8cJhLN4Ny1Q+i49XGz} z79BQ7!g+SeCkf@-5>VEkrsBb=ZM?io=uIu&fzb75fV_}*_SXLHLen-(sN4KU)*#^e z{V35S^bep5vO)Z2ALYyMkMFDqr&yqp+~fz$PJm3k6;Q0*jHqskqG*vjJ5q5~+*bBC zVs0V1&+iQ-oQtm9LA%u_nUUpJ#2svM9D7xaBm3t<_eT3#MX;ymI*sNQpN3N0K%e0D zu5}bw(@J9}uD9~z-0iGwT4EM2rY?F&IgCm%-CSB)%8l=GMaW0YLG=6&=)ihn^xc)x zU(ber>4mlj?09-zGq&48LeCEfJRN&HH5{g5Q`aoMGi+C0FUH#$;J;+D={ZKUuV1!j z93lEfoaw1v+-z@4UDnlxe#Ixc`HO_oqBRd|`@Z_`F}oI;;stzw>zK3op-_u?&I-;e zRuzf%vz$I{p)pow%fOSs0PKueO7VH4xKYm~DB$Hc1tBT#=jR)*ipOUHiz`!~;eO;c zk;&f09iO`I{y&I|!wZSB|1ZWx(e8G4059P6>Ual?KZ0rLj87Lf29%|(Rq2dsB28eG zP+aP9^yp!o7h26!2xpI5HEs&+14J2^+H(<-EkX}+7-4@)HKb59S(dh^!cRUV=svyi z`3-L!eW?m4{SdX2q)YO2szjktO8uME;9j+l-B|_^%Y^fEvPTuFW+C9qx&5nh( zyAPmgj%r)2_u5;cL?9PSH*(;wk3|B-R<7Am<1FT$U>Xv7OA*Ys6^yzShxTd)np@^{ z+QZaUR$_BcTbsol6I+}41}hlq6!htN1=*kIn;(hCLf6WbMQ%6|gBQt+F6)@5-b|-o z$zx>axmGZYH0BQo`W~MNJod~N3pC@0(0d`c-*d4eBIXADLqf1e%I@sSDk=>b8Fv4a z;MTcX4sR4R55?!@=Qf_#8*N3Oul0e)Cq~%yu2Umx*xa6f7W^Qu*cXSmwPrIJcb!XxGgJSV>Ry zIU?byIimBJnS++VZHLxaAj2gv&ou@wnE`{2m#Jm#?))notBCf)HE9$^l?W&BTU+$s zR}~t#_4nyPAvEEy){4()ScV2ND9orqq}etGw6hk-qdS|M%gsFsHv)stRp{AAL< zm$4F?iz<)*fJ=?}0FjiU<`pqv9itJZb1g{{Ru)c+RytH~brS9njTGci&cA(ni%LLK zLDCa#KGT#{55CYx?dyBWDlX^DRJBIW&pXvq8n@FD6>`8~|Az<{GMKM9%f>MLDkQbBiXG97q9@$B8UOGG7d>V3nyf6YHleUbfAA9XV|Y zRC|wQXW^lT4a}M-*)Y`xxV|pas^OoEO-bEIPmpQ8z~o6To^nWKr6#RPmHeb+|3E6B znmSi8Kiuqt7C*oFVf`xjPy>*8Uw3hQ+ua*#Q&zUqk+m)c6-yL;dY95WMry*X?zi|g zo_@QF6+&Xih;}wPqjO@7vY^@7AkTU1stK~|O}lD-5UAyQET`4y=<;>BsRWXY5dn=1 z%<^Pzm=Xf*nO7~g_L~h=-qMAU)E6QyKO{C}891mrL<0T2a1-tOpbkh?$ohlSrERwD zt@4c^`u|hdc}By*c6&d%M2#-W=purM=*;LPf+UjYL`jGmZIqeOgQ$Zfh%!W?+)<); zqK`U==q2jtoiPRP+|PZ^TJL(!bKcjQwfNwRWnb6c*WUmA`@btuyyOH`%-UWN-LO?3 zV-D_)u#M|r^u1LLcKLd9=unR}R;aEsKq7hblduXq1Qp)eEgIx~N|ZiOToTqrUj&G> z#Fa|iMk7bJr>cx3uYhGen{n`qy!pv4$1Absb+H|OZrlwXCrwOq?_$y2I*<8Sw4Q^SSG&|F#N+zuI`wwtku7P zuk3y3_*2N^EB#~5Pz~M&IYqg@UWsRfq8J(Ux8A2lX4%D0#M}_K{pL&)?Qqh{vc|8t z;jXr>5r0>$bydioY8$Qm+f|Re0UC%<2MglbzCp&PVxIx z#Z_K@F6gleQdhxke@!EvkK>)3+qI+l);`GuaBJ9^t%b1WBWOaNao*E(sYu0AnjoY> zs<4%QOp8LFA>UEmY62XOqx?o?GI&8RfL2YY* zbMH0;3_dN(hMx3-p;z1B<{(tTERAuxlfT{U=6h48%R7okKq1}XyRO?lb~Y7qIU$UH zyosxu*W{^tB*GJm+n95Lwu+GnmO|5l6G@pY8B)95hfh)yR$#uz#g=DHwihtSUIV*I zQBpS!8&HYBaodjratUSh5-OiYacDfd_`HU$kQ8*i_w)iPHCJ(bj zNPuqp45@?>=jk#}hB#Qqaaj(HcT$^W5g z`xiE{oQsi@&*riEofKLPiY}@ch3ewu=$bk|nLpH9UDV!Mf-a0d!xrdLkiVd;3}aeT zF5FVeFu`XdRAleTIGIY6Vc$0gYCR1K1vKant(b8_1X^;X6R5}2-7KdR)CRsB-e*H? z9WnD41TtisD|Vz8zZSm05ECD6C3h0$rsk=cSrL>0O-4JJ`*1rpVP!`OoU@vLOP|jD zrETf(i+4hMj)$f9u*4h@HwBE8@>7 z?0QGmB%It2zY>{w_E|C}L{xw#XSzm4FWiZU#YwnbxXauHH{`!T)WfmKGv?%M$@CD5 zGk3R|GZ{IH*{vlay!mPt?0aSGjw7}MPA;3|tZk=}z4MQt66VZjUYQWi?UD7LS!VCE z=za3rX`}roq`M@f<^+(9Z-ze`GhH2VYFu?3qh|N7E)i9k@}3X`bwlFO`{T8-BI{ve zp%J+9hwah}($1V$Hlg)*wrEwIICrUsY#B5DrsquzHi4 z_rF?nF079@IW0Pl_nS0?x3=u3Hqh>WU1}i#2S?m?H1m!VLCmf1c&GARHq*$0BVGAk z_v?7oZlEqWKVu26gA05wv5%zP*9}8|->{_N>Zp*Pdwjj4;Gc4zqth1ipChS|RPV($ zpM~uGsJifgCE*zQmE?rFOkyYONE=>hMN%9-do_`HroXfv5nc;)$Z|}KjA2)EP&3No zaqy?$lvg9^=`xI@_s#R?f0x-+|0a=81X-s2BO?7_B=Ji%S9`j9S4IF0Gh#Ice4GSr zv5_)WyyD?3%G9J^kfRFd*bE}<$+zRi+H390UVjqZAKEv`?Srz?CIZQEC>={ z6uWJ^#(wO6-z8ymz)U+qd%kYep{>e2XeQJG+h@$!P8|~Cy0`We0T8NOXZW)FP9(( zmF0k*$elXMiTAfmeZ+07!M9 zGZ_5)pG^&L;-n8&efkN%+ESFfJIvF@0rGZ+ZLx{(%y4+UST@kpxHHy))bL$R}^(g6sRwdK;WStrE~Uv5=ugvqvKwb&0399?VO~ zcS^yq?-DY9`m`4{EQlGW*v|#Tbqirc);G4*Bu&#y4~h8`+>Zi$roO+a?m`Zn; zEUNgfgM;%|TvBep7)EVD^TLMrYw|>rq81`>K<@gJq&TTR#>s}Bg{>0+ds>GP-7;B9 zn9Z2jr)B56gob2;l^)(|CNBcOJy#msIPqezQ$Tsf4j>kwtb&<*x#{HIU|utSYaM<$ zI!AP?x~8h#(8nO_6z-Q+g4sPL+xkAlpy-mt+rqFimc}FNG8T3(T}zvo`Ld-`yV7e( zhTqHoHf;v3m(eSuQW?9@Cq2!4UBY>>Xb(Arb~d?2j8U0S+qB!wy0W!hS6y|M)mrtK zh+f?}rF41vrvM%Rk(l2l4<=W!6ME%2On3;jIG$rQhh?>B-%E=%6J-U$I6 z1#(<|va+$B{ym0z;539_9|qKB4NMOr^3DlLoNJ#C0_}TjAW+=gqyN_ZE`?bC$0%e8 zZV4Uz@$KOk3O`2aTb!DXoHhPk39k`Cac;d%N-Z&b8p<(#HdJDr23;P~aP?>5dL$zh zOH^D`K{XU>Vm#W4;<r6>DT#pZlAc;o4*VS0Kyx4g9+C z@KssUxt?O`x}r%}Z0Im*YN$^CCcY6-=aCYrwPn83lQsl5?%Bd?^z+}Mb9~gzP~GZn z()wng`LoA%%~h^LTPQ>aq#s#EgRoOo->NEN(7KinAXn}=AX2>Y`+iJ@Vvp`VEcnbM zPb;~e7ySU~6#TbYgB>)HQ(jhFgK9O>Jq~@l}g9$2(2zMaX(sM|r*9$YR>X<(~*uG{`=1DVyvj{x%RqJNgOj z+=z$tDzn?mINc%@to&Er&2fw;B-vfa-u+LpbIx*5cbVG8`xWRxlNFz$$6uL)WMK7^!-wAh9jY;oON6J`0VMWU7|yQq@|ZJ_Y9AYr_P*p=ksq@(UWcpZ!Z^4% zL5w%^ci&C5v=PSHl7&tO)$1CTAoqHvE}B!??wuE2@b{5V8yO)8=Wl}J`7}hZU#D}8 z&6#Xjk}Q1khk`~a|H7+;F6X5sf)~?<1gGe?N$uP{3D2nB6rzfg-qGsmNHp=b3K|*# zcXakM5qG+yYZ%90yG?|BwhDCtly*O-52Se=1;&c_wCk*d=^nYl+^Sy-9K0g5+Z+nn=uqG`;r61M@N9+T0|>`miGo-0JZ^gmNiKP2UVl5TmQ z1{$kfTa_u9`%z0=Gx+^Hc;a++5p2xyJi}$%Vj2}6s;*8y$o)Sn6jm|2sE*8 zA{kEL^M-92*jA?51b0umrHdo|hMe5tsdmHG+d)&5(Ms7Z{KGE=NA^$8yFTyOznVrl zZR}%LR<6Lcmr1wnRzSe2YS$5k%EA#~q+3*TKx=CCUlqxP!n)6#e~k&WpCqA%L3?<;HzP64=oq7I z%Ihy&JF9-0Kg*m`^sIK;V~~b(Q8&ypDSmz7u};{sJ&%)q@&6TR>=Q&o$fC5E0L=_` za1^~Rgw`FIvQf9zD*LCFM_up_?9zb&cJua8RhM}japBr>Cq}o@2MK7n{FRKnb8Xr~ z1+_FnnN5Ho_)Y>PAk#4?B;%$f?KZ7kG{K+ndsr-kmgEGPch}W^0OtS@N}G1mM#jU*Bb27X%E~KxC8b43Db5l|^^0Ul@0YZaxLV zODLx==YFTra?KoV!yNaMH6(dBe5YUYKr-Au8t~~E!?Nsn$e!_r1A`e07~i!fcXNoI zw6d$rW~Htj^}iU18&PMolCo~KnjM=35k?tyw?obn;4-=kcbGc@X+10=ppT*~lNcJr zhf_gyCW}=osi}OFlo@Y>98))^UbnWv>z4-u%I4y!Z^p?4c8Pwl=8ZI*%+8wsQ4Yn5 zgVDp;Ef~fTi_M+lkf}ZOwn>cas}bQPi4-L3NeZ}fbLC}kVWDaeybrAOPT}Vt%yoB6 zYV{;2c!wnAjUiJ;$l1J9@K~*}CuSJKbpN+|Nw8J-M1Z*y^i-O2Rnr#rK9siVo}ZfD z+M}L&4>tKXN=L^(HwW;c$5Sl)R9X3bUsVkjP{fsxsl#A9TDO>Qz_V(_&JDQNfN+TM zVdhW@vVZ#TAd=E;{^zdJ`rrA*i`bA0UG*X}_X)~(PEAHkjO5Wg>Lc6dD8MROWE;1DeCjkQ+~J{TP?IiSQB&_hbd{5~0|W+NMK#{3V%KJW$Cy3K<51 zxe=GLibv6A)@7rHkj+7BeVfFr49sh%mR$f70X$2O82@4EJcCRw^t@ag%g80t@%ee&T zbKdQ=)`d;>i)+!rv6{g*;ML zQrkx;d%?k8n}O*P>ol_gJHKDAQDl~?UYtlM1A&Q(nya7XI@o0ZhhlG#<~9LU+z8Y@LG_G3WE)< zIdUOM&Sxe`dX>rD-;{PI49bG`ayapu(e;VZZo``F3*?ISPH3Z)rH2^MnK<5Q!+l^| zwF##$vE$32SRjR_;}P)aTWfZ{;!ocaG4i0)sy#XGSLQzAL(oMr##!ytg(d=5HGt)Y zDl_VgC+(v?I;N7uUJa__{XmQ~`nc=+z>jFX^WSX;X#yVq-y6vDsy9Scj}`7u>m8X8 z?$K^&-`@H*!$WJP<34F$|5UQnvPpuCAnPVW8_~>+iFyQZn1eFhgz^J?82SMx6$hhM zZw8Efo;~^v#mR09CF@fa0qW#nbj~a2D;1+upS91#f#??cbA5zA?7204^3ZVtru%JE z?$r&>Gi1F!W2H@X+Q9kAL1#3>E*f;z(1KZjfUnx;N7S>zAD_#l-P}LlK-PLdYK#E3 z*PFa926Gy{1U)$7Gx=5hV+IEURWfIMbA%-A)xkEUa%Y5N)O1?g5o?lvvtZ&{mRZCZ zug_`_E&dCZw~R9i{?em4~++hMAk+@*PRiN0^;H`@sC3H{5|;1ijw6y${V&jwk9nS zY@PgdGh}pzqndyK@(c!A;HRhRX(120j;q+wgR@!I*%I9a<(PqF#3WDH!D<)Lh@J6J zv6pDiCWlejNG`1l)D(A|T*Rhr>9qfS8L9j~RIzOrR|MA|cfZh8I04s0zJA2;l^iJl zhTkPZ3dNUoDurym-p9k$8TrCTK3rj`xMBp=uJntpj5V9Uale=!2LBGxcnVE^7@6(4 zN=DY@a~LR1b<^y}=JsG(#w(utK@wmVQw@_D7 zr%z8JkP!IYp7xMBc?>cIG90Cp`c|_tzZ6t;cswBYYBaXuvqESYhK3V-_-mKMLEADC z!Lolszs#uV6}o)Km=CZOOkW*#5?%4ZsT^emkLL51MF9Wo zojvgYL`HV+hM!2K?WT4~qGh@>U+D&hP{E^s76CP8Xf zUJ6zaD4gyr{+)H(nKixHS3Xy&r@;YWGlx}zR@Ye^CfT0aZqhNf=6hzw4#ZOJW38qN zA6NGv(8tZI4+ZP^9yfoh2?Hx(mex>-r*UjMrnx8LgR1!;IeByTLX}Jmm7=8yG#_#* zzSy54zDcb}PUY=y4)5{@`FPYM1>3u`t*S3{i!Z!B%o)$Q!+;FGla`iNYj$@TO6Mb; ziLKvZmdnDVrl!Vp|AZc8&Ps9O{jb)p9{#t)aCx+C<9~4|qsjG914nFK8?|egCik+h znfDGcV+7}tYI8BcXEkzSP&-dwx`e*`<`}k<+(rFGM5~_BT*%k30L*wW@=lw{kcA9{ zWy(zP(6@L-a??bJ$3s|?-fJWTrywx#J}ad}rLJA20KR)z1ly`!yHm-wd%h#4#K38A zO{`)l7hurZ^~BsO^Z9`Jp(DW0k{Uajzy;vf59+i0{Uh`w1rbp|>mbsg4a=Pq+wk>y zF{7r|$?%kKRhv4$g3)faoMft0RL-4*Z~IRYgLFq37MY}=)LC9eVE91E(P#}GyUD;pi04}(E%<-b*=QJFt_nKIXz2Nrb zGveY?E!pP4Wcsmcc&I#$Dutzbumd80UuVj=`2ZTvzh`*v_#JO#z4uCmv$sJ>$zsZ0 zx(*9n-X&552i=!s*LG%#i7bQ<#EJJWA_#RpF^L@vUBzkR=Am0r*#W9?&_Mb4i)P4N z10KOWyL^rmkpZ3?_8V_Ffpn*BSDw{{O<4^|ig>|ay?J1xIt}i~A`?rc-%+ z%A{Bf!n@-MXb=EAB4?J7pDhpV#FWz~3y(A@6aAScL9arNV zBv3jvGNXXgG&qY#FYxGxraiAFb)T}0zhtdYR69=ZrC<}m*O^H|V`BAMxG`Mn^W7f*mr3r%U%t@6#dCJZ zXOIx{#l>m=$_2KTk!`U(ri##sCxH5)pRue*&btH8 z&`NaM%x50D^!=rE(P|M!6?}hg+d8uBRP$Dkny?ti;djFxcNVG^vue7EsCu*F1orfF zZ4u?#QBub{la*9wv2|(8m7h%4(oBZ-Z#~*}DtGh)1!8rj_(BYPd9qe&@tK;+;Or`&YPioomk{PGMzI_i>y-Eu;0%O!5x zv36kJOOZK~n9Igmul1!z=hm=03UZz{1y( z;&B8~xO(13@aRzn%+47lc z&)A|Wu{`qH<_j5MVP953{WHfgzJGR=X7;~GAZ}2z37DvLG3k#`C^KozJ*angq%-Yy zim?XG2~emz2aVbzeVqB?*3nkEgg;D_+GpNKP z!9BuK_Fg`d{0Alr;XS$!c%AMgpe)4Xcb>t;qa3d(!;g{RHY4I<>vHE~w1teQ+rcb~ z&bf7b+iy=0wp^7&+{eAetheW}G(hKp6*FFT0=AU*z#sAHend`SIx~T6t9@Z=Vj*F& zOe3yCI8t?8@_Hac%|{w{`iVt6~eRudVsf#xUmiIY|Srq7)y`(Sp%# zOHBu*wRj2he)(OGeLpRFvMcTDoIwa>w7DF8_wRH*+yn1hPvCq>bDQ!Itfo<%$~=9h zRRr62?3&7b;qb>M-V1gMI7W|ep0Q+lWuG}<>iyRNftLH%a-sAq%f||QC?~}ro9f#t zrdT6&KuBiuNku-`1gO38}<~KBR_7x-5FSW&{ysjmYLU{()8>eqG?Af>pPI#bEdTQ?Z>51ULQi>Ui1D-Hn zvFS~#W+~Ug?aaMeUEy%o@dR=)3|yZoC)>{2mdqupP35}MtXt_a=@8R{b3H5O=gaw7 z4-)N3`zRH6v&37h#;SGqO{nLWrqrZyN`3G*;($$`X04uuouRn7&27qiSnaz|%S_T| zqQBpybAi=@5)9fg1h(GIl(uAimHC+=6mmp&^uje7v469!Jgmuof5tfYh#9h9xIcsK z#2>yfqYgC&;p1Ipf%yKR6mg;er*na@!v*&C=0035(ZOK}jG!Rvy_D-0S&oH@*Q@gv z-8!S3=J>M-XQ-O}?``bidK>E%6GV^1;U$HO&joJvzhxZVt=I!L_{-Vuhq{3%VQd95 z-Y;cV4fK_B)}^cf&%7@;)H0fmgP?% zT>?6buVq!jp3s}kr=yVT@V1KeE8+)Dh=LRuCmaaGp)?3O3(TY7S{or|Arngnz|5&M z-)((S+t9nX1Yb?%aUh6X%4 zLdwktK;kav-8*>x+2$c>SXj>}N53}Qh_Qhtb60K!=ps{6=Mrj|@|LMGZdM?Z7M@S| zv8k{6m#hr{kbSa+HcXt}$LQB)No2n{`P{ZFxV=K>*MGQHE4_oaBKn30XXB(}-Y50I zOZ)&_Ql}SC%=O1D!9S(}g`NhJg6rCY^Ev3x1qP|z32-2#>->?nagn?3!|ten&VY^k zQEHj8-A1)87_;(EwM3^M)$M&=^{Fp+)8HAVM7GboP2ier=1_f}#QUggl~SNxGje(~ zT@245>~hPsWej?dTxLtQz=Lf6lXl9O%8~VL;~mgKy(jK39p68`wNBXJ-Ki`7 zC8^65itv6x@udC^zxKWm~EN64lb9xzNkK6IDTugYhckhv_ryzhBi$7d?+` zHKvXAh|GcTWYIEZSeCV$Lc&{|BjGzVeomc;Qo0N9powQf!oErsoJ}k zG1;h+$}(m>E#{0fW=G^$6D6gSyBix*Y{%O0+U3-4UERMsL9>~jt(@KoH1@Pe=%sPP z$!U(YxU_t4>qVkDd_ zsqnir@F5+)CGRITX(J}zw<(Soly&b&Y^-|zNZmU(J>`jb*~}Q7``K-+rh25~y z)q=`KQ1`zkWJ~(m|K;iU?~!mIwseJ`y!4dIA@1#3bVgBsAtPF`ejBjN2fH%2+(gXH z|Lmt;c-;TvP{3U98Q&NBPg)jxHx-vnzR^3LpD5iFgP#Vms^use{jD|1mHSGk$9)2+ zeAIPRfaD{*CFAgh)*Ier;w5fZ=S|YRgM&nv{f8e1`q&fA4a%HmZW$<&*8DCM@%M)B zjkNBYqyixKa&TD<*nWH&wIZGfaCvWNNYavM;ggmFCKa$tx$Yw|)f?#+w!`3XA~!k~ zu$sW&^jE2@FHgdj&Sf057)r>t=P*6=@z@EB@%N#)I9CIXhk`w4G4C~X6rIwlj@_jI z=nxJr(5~3j@k(_4LUhRohp)V;KqEk#Z3xbp@AkWdt5n)Q2`X+@MhK;&!&_8+r?fY2 zifS3|vDQT{vjN*nZ$Xy{iX**M%+?bGk`=mojVF)|s^SbX;IL`kLnstlc4NoNuto4}#4a zRe@Ptp`|?x*!F-1pADJdw|WkFKB_7j=Mj93HygU!xtd~@VF}tiLE-i{-Iv#WO06iZ zYgy$-nPnCWM2d^aX6kY;J> z#U+OLrs`TVsmq>X55BS;bo{5RA(bYa{%eQke-zII3+bGmw>f{;pemQmYj+j5aDFa-5KmM^F~_lNu zJ=wUe7Ko&e9K52~{IRB5;^~{ehq-mtd3c*#gSVn(HfMOe=`KXkm|X|t5ggayGpYxs zi_LU+1@hs7jwQ`i{j5x=LJKc2Lu%uR!X$COArQyeaemmsWakT z5@9sZvb7230xzpulD7mN$@ znm^*V!|gHOsDQUpNqraiZ3Q0&=4d8_xv30e1mJD<)GhI+0&=h%hQ9nnl_=;3ad#vv zOZ4H~wW(odStl0V1wp7cM@R0$;u6u@8y~a1;zhRqrCWd<8Szi`(l>QwOZ{)T=)bNd zTdweX6=7z{k?lf`YW1P<+Es$z9(Y^L(NnfN{E9KN(c)&|7mSHmC=gn5;DZ&>3v`o{ zKAqW_6CZ?udc+0XuY;h>-FA8!rK8<_AsfF zBYJyg8-PYkC6PRcR&8hsigYdjqTVl$6;LB_>9q5`AB<$rDvTC{6DRIUkqF7TE+5O3 z>t41_H4ZMaXBfowRcX@ml3ixn>r35dyFU>-Helv|WB*$>VJfHfB7VN!>le(&gYhxM z_94I)_VJoxeHMy3)r82|;Pfk-hF7`NI6z;7f(r}TgiN?jDxRv%q6d{;ca>=7fTzAk z8XP~TCNjbH>l`cRcT36Ub3G};KI|j7TI3;3@p%^73ebszNwY4>@o8SD@XFn;Mb^dC z>xkez-{_53xAGTl`4^H8FS!?nV)a}93cM^YEBkVA8SArYl(rzczPy1f`!w())u^jo zrHuX9zhH|NR~{E|GpzKN zNu|*6`-kKd&WrlbTAfEK1a!5s?qdV+DAP6@57u4lV2R*r2kWQCRg0R_CMMo3g~<$E zDl?;=jZ0_kJI9w{daO!G%w69LBBuO~*Gtb=e^AHbTk*2rFrrj3c4MPX1na}YXTHjS z<3VW!na-dcM%Sfddc+AulR_-yWmRgO+&iuZoDl-vd`BOO>D_nKyVN2=rV4G~bZTjM zwwCs`HNM66*FW?S}xVA9j9hbuGK{{bA*ia zxKqL_WA4kIH`yP_-g&9beb_#mBUi{o?Vg`2tTv~u&^7=zU??dm2c8&`jDsbtrabbz zs{?a%bSLH;oa(ztvlTYTNE>}W%?W3*=s*X1u?nl8ntEF#g4a3W4y3Vg^{3Q**U@^0T=@8fs<7o~C)`4;Z$zr~(r9Nau>jZ_M* za2I$e90#8=g`va!M1GVwb|~-kLVKzmlwYtnDhfNU>4pf;LYBC}_S`R^QRc;w<1dHdegH@VH!pGK6|ra$P}dVN}at?VtO|=WV>>r zeDa958RgKi^)cjzuPt)JA$r?Vi8X&ilZyodZ|H5b%!GVIT_Xb@!>$x_@;0`w2Dn7Y z_aZ?KQ(il5%*Kb8YdCmhf;Cfham_nm5Mf?z4{9W^N`$Z_fmC~I_;0ovJy@+;1YO}E zTXdcGXge`_7Zkivb{zlqxn$S#Kz_Y`pED@zIi@S-(VrM46M;`zSRw6z@J~3Z(H7T6 zoKPSA2B5M?nRB+|u>JRdMo)v_iuP2N@QmZxjy?q{)BYWvnOi}B;BbxB~h z21UF{qVa>m(ua=HlI|&1DR>S(2P^!m{1iJqg;AXxg-^G%`#yYdH~RiiA1NJ8uRZQR zKUJ_-i{n21;Xagpe0#pteIi2ghdSHhjK%?*DF;D zr9gESP$EAINjmuMxd}|-m|)E}y#HkK@RDpzex<#F>Tp|C%j=30WxV)>>#Xc`H04(K zAvmL^f_K~6>&e(ah`{4FMV?<)AZ*pE7ul}qWS4QxLNn3OCs(vH`R7sIAJ{ROa z2Kf7*x}Tx=@miOB(g}w_gbKDj(db`Yig<0R-mF;;k)_qGit+kImJYFN^ zWzI5d<-@Z3ijLb~s}scP0NEu~JPJnq?==l9`MK<_QW)mo3<4nz3dlf9%tDYM|nn5o1wxYgV!=vTW zv;HNhXifi9AKOoZsvD4Y3$QQAGF$Jo=&DtJ3PxcEaF#F0_2fl|8-NO@;ifxgO;|<8 zYJ$7sRdZ^Kh%f2Pm4@C~P({OK06&kn>+Hzv+}q-dgaA+U^Dk2nhf~@aNz1LJQ2tk9 z^CrwaR^P!U{?nDHVJ$&CeBzU}!WrL2A?b^@ZkD;Jp^6|NiR^;i)Yt-DUdY|Bh9`cr zJQpvc&qr1iOI&*(-b5&DfQP^3Ng&mChb$a*0#s@;Yif}J0;qqkB}^v>j}Z`CXN3S2g&}IuJ->U5bVy4 z>zf8v>6y3`vf~^R9?b+;_9+S(!`Ia`wEr^I&@n9Sy1{(s(eO23d5pDNMpl^k!`CPZ zMTF9Np1Qr=#GrQTj>)5qT!~rmX4&hfh0i{Q%&=Nc|2Zif=Z9$lMp1rJnYgjVX-r^z zhn3Mu=l(X@qHV=UcywO|uM5(!M>I-d!asi%bDZh5$(i6dQ+)r(j4O!s%GC-H(m|=O zF{KqTwH5RwHD%4DkuJbE2||uj>CGsoTT2wn*U_=+(!I}l{gKdK-cy$fqr@J;(YsAG z6P1sp|4=F4d^KF`=K;#~l$P70NKsInkHe??{Z-IfJ1+VrR!-5W|M$RtO4(NhNqxHR z#{2rIH9CW)`z=S$D=_I`l3vvPwLf#6FRI1(ktrDcaaN<>#mo|0)k9`o-x%r-)56cY z*{?$@Fc}2)Hmm6Bir7QGI=-r`Q!tlLS0u2I+@>nwSjD}3+RiAdddt4|@q7$_*}iO! zCIUelzzPi*+i)*=q5;bC{zf07YBP`raCjW#cYndXIK71b?s(&mZU#RvoRK0}WUEfITS&Ocr&cJE?wn4r9#a z#p$iJoVQX*c4*-G0oH!cA%#55RhE{RBNnC72HLz{OA8@?fGn;Nzx1_@w8}JIhQB5p zR%_2sE;TFWK$_8_a+3h5ubLk2TtS&!k~JX$3$9HM&w^Y_a@1$n3{*v4>X|>Rd()Bb z`rC6$()MgR!`TrqHhVDZ&K_!r4&V;g$> z=a{I+2{4!tkR_7tW5@2$9D!Yh4YSH^9Jx3U%0sT4wiy1-faMwTm(Pjc|NTSQnVWMA zr|i3)m7?9DEn?GLM$W~=r}vysOyIY8@s~&9iXC66neT=gvo5pSikRJF6_)uEUR_A9 z{6LR>@RsH30I2&b?Mx*sZO=u-&*IsTag)6`Agkkp($`Q0-4mbrfkGd}#lXE|4hl=7 z35SI=R84TNtg!ii9}Jw;9);|CW8_Ivn~JP7!ABtdhuq1X%d~nRYAHes0R5uw=BGNU z-}l+1ks-i9{jBjRE#0)6@acO1gV(>|hWQQQGLk~Os^Z?&E7`$oj z514z_dFejd@Ud8Qugy>~ZgCC%(FcEFy~FVrmvq-@O9FZXElOtdPEqCXSZU&R9w62G zTOu~7`I9E7C--D4vT^&Vw7F(Lk>64rXdI^U`NPBE@3k0z8&pwJAa($DBXDzq!?$g0 zKkqU=0{0x!W}S5XLX*v}r*>6%22M+9Vy^H_n6xHL)?fpS^nGy7c=RQHcJ}uEb&NM4cp;h&LAnkU z8D*${@pr%+SiZda?(iQj)$V({q2%=sgK=5<29DzJ`h&ewZ|wT1>~XoC3twKl5KRhi zrHHh^R&|n>%LzPh;JnFy3eFe~>yv30a7i^fh|bcw;eyt0dFS2hwvx}}2;YxPe<%V; zd?DQSidOMzOo;qOh{nd;xi~^ZD_KAI zO&fFJ3HH|gR8ss*O}SPcPnA*+CrDiwxg%?$EAE>BFi#^p>kqB1tUJL2)$5*9_E#k$ z;-%$sOv-Ny^*%rJEgup4h)e1!s+jlsCE8cW#Qm-3VRKUem>S4ECH3Ob@)k$nERppyZjW>v9w?Bk-05o2>hj3M}445&XDrFQ4EKm!w< zLc2;-8BP=pYS|c9IWWo&<||3Y_!q^$w%||pyMEs(a$sLM=Wmdnne_Px#B0?pYY*4E zo_+pU1}yQpYk>TMLVOst>2|`bzZU&6;kPi^FT-g1Gn^pr|kQ>>@(5-cgF9-OcsX+FS zpdcM?>E6aqbSpxx2A90~^ol;oe1lD@Fv{~Ub0C$~V%Y5vEH?^;P8)DX>YqT~FBS&Q zxK6^uoXXF zI({c2>lpr6q(ckzYQVHQIr$!mklRay{=H(;^sb6jIJhG=2o|iy(DZQZk4!RB+>81^ zcq7Funl@xc!4vb{8j%K0sz|YY@kRd+Zq+SQU)X@%tZjpRq`l3LNi*2{X$VfE_af-K z8p3oTC2v2gp=X^67Q525d>M9`Rh6IAq6=&Dk57Lwzp@DSHFzQG{m}Ef_=#bwU1Ou} znM#ixsCPnvkI2!AmK$E18-KIs6e^=mi!YrV9fpB{j*l< zuyYn>iVdW)rZE__>7pE1QDc_C^4?F2w|783$sFBg0hV$#!TVw>)oy>;Ua#eHRHeMp zXVL%Gt9hFg{S5SgzGR`+q-p6bm;gOU8J{dJB<2@(~=digaUu!j6=^#~10&_Uv zi2>cvhin~MVO-IdZw#ob#aiRUuy1UjU8rL;df?Zu!hs~vWjf^+5D0w1-9>yWBoTdk l##$$8{jfZmV|IPf#Ik&8a(L|sbWgNHw=iha?ElWH{|DQ7{7L`- From d3cc8afa6c7139c425795805687c6a4fdfe2e218 Mon Sep 17 00:00:00 2001 From: Mark Vaz Date: Tue, 7 Mar 2023 16:19:48 -0800 Subject: [PATCH 56/57] Add support for Python 3.11 (#608) * Updating for py311 * Document support for python 3.11 --------- Co-authored-by: Manolis Papadakis --- conda/conda-build/conda_build_config.yaml | 1 + scripts/generate-conda-envs.py | 2 +- setup.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/conda/conda-build/conda_build_config.yaml b/conda/conda-build/conda_build_config.yaml index 00fe47139..81326c39a 100644 --- a/conda/conda-build/conda_build_config.yaml +++ b/conda/conda-build/conda_build_config.yaml @@ -5,6 +5,7 @@ gpu_enabled: python: - "3.9,!=3.9.7" - 3.10 + - 3.11 numpy_version: - ">=1.22" diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 7743914f4..18e35d2b3 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -220,7 +220,7 @@ def filename(self) -> str: # --- Setup ------------------------------------------------------------------- -PYTHON_VERSIONS = ("3.9", "3.10") +PYTHON_VERSIONS = ("3.9", "3.10", "3.11") CTK_VERSIONS = ( "none", diff --git a/setup.py b/setup.py index f03a05cc4..83912f31f 100755 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ "Programming Language :: Python", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", ], extras_require={ "test": [ From 8f5dd49ef4f8b173b9be55353428929b5b357ae3 Mon Sep 17 00:00:00 2001 From: Marcin Zalewski Date: Tue, 7 Mar 2023 17:18:46 -0800 Subject: [PATCH 57/57] Tutorial editable install fix (#610) (#613) * replace hello => @target@ * fix library paths for editable installs * deconflict user and auto skbuild cmake args * clean up rapids_export calls in project template --------- Co-authored-by: Jeremy Co-authored-by: Mads R. B. Kristensen --- cmake/legate_helper_functions.cmake | 35 ++++++++++++++++++++--------- examples/hello/setup.py | 5 ++++- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/cmake/legate_helper_functions.cmake b/cmake/legate_helper_functions.cmake index 79f2d1c1f..db269fa78 100644 --- a/cmake/legate_helper_functions.cmake +++ b/cmake/legate_helper_functions.cmake @@ -38,11 +38,16 @@ function(legate_default_cpp_install target) DESTINATION ${lib_dir} EXPORT ${LEGATE_OPT_EXPORT}) + set(final_code_block + "set(${target}_BUILD_LIBDIR ${CMAKE_BINARY_DIR}/legate_${target})" + ) + rapids_export( INSTALL ${target} EXPORT_SET ${LEGATE_OPT_EXPORT} GLOBAL_TARGETS ${target} NAMESPACE legate:: + LANGUAGES ${ENABLED_LANGUAGES} ) # build export targets @@ -51,6 +56,8 @@ function(legate_default_cpp_install target) EXPORT_SET ${LEGATE_OPT_EXPORT} GLOBAL_TARGETS ${target} NAMESPACE legate:: + FINAL_CODE_BLOCK final_code_block + LANGUAGES ${ENABLED_LANGUAGES} ) endfunction() @@ -90,7 +97,7 @@ def get_libpath(): }[platform.system()] def find_lib(libdir): - target = f"libhello{so_ext}*" + target = f"lib@target@{so_ext}*" search_path = Path(libdir) matches = [m for m in search_path.rglob(target)] if matches: @@ -138,14 +145,19 @@ header: str = """ @ONLY ) - # cmake doesn't let you pipe the output of a - # custom command so you have to generate a script - # that writes to a file and THEN run that in a - # custom command + if (DEFINED ${target}_BUILD_LIBDIR) + # this must have been imported from an existing editable build + set(libdir ${${target}_BUILD_LIBDIR}) + else() + # libraries are built in a common spot + set(libdir ${CMAKE_BINARY_DIR}/legate_${target}) + message("libdir to binary dir") + endif() add_custom_target("generate_install_info_py" ALL COMMAND ${CMAKE_COMMAND} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -Dtarget=${target} + -Dlibdir=${libdir} -P ${generate_script} OUTPUT ${install_info_py} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} @@ -229,6 +241,9 @@ function(legate_add_cpp_subdirectory dir) if (NOT ${target}_FOUND) add_subdirectory(${dir} ${CMAKE_BINARY_DIR}/legate_${target}) legate_default_cpp_install(${target} EXPORT ${LEGATE_OPT_EXPORT}) + else() + # Make sure the libdir is visible to other functions + set(${target}_BUILD_LIBDIR "${${target}_BUILD_LIBDIR}" PARENT_SCOPE) endif() else() add_subdirectory(${dir} ${CMAKE_BINARY_DIR}/legate_${target}) @@ -320,9 +335,9 @@ class Mapper : public legate::mapping::LegateMapper { const legate::mapping::MachineQueryInterface* machine_; }; -static const char* const library_name = "hello"; +static const char* const library_name = "@target@"; -Legion::Logger log_hello("hello"); +Legion::Logger log_@target@(library_name); /*static*/ legate::TaskRegistrar& Registry::get_registrar() { @@ -392,16 +407,16 @@ class UserLibrary(Library): return self.name def get_shared_library(self) -> str: - from hello.install_info import libpath + from @target@.install_info import libpath return os.path.join(libpath, f"lib@target@{self.get_library_extension()}") def get_c_header(self) -> str: - from hello.install_info import header + from @target@.install_info import header return header def get_registration_callback(self) -> str: - return "hello_perform_registration" + return "@target@_perform_registration" def get_resource_configuration(self) -> ResourceConfig: assert self.shared_object is not None diff --git a/examples/hello/setup.py b/examples/hello/setup.py index fc918c843..f919989b5 100644 --- a/examples/hello/setup.py +++ b/examples/hello/setup.py @@ -28,7 +28,10 @@ f"-Dlegate_core_ROOT:STRING={legate_dir}", ] -os.environ["SKBUILD_CONFIGURE_OPTIONS"] = " ".join(cmake_flags) +env_cmake_args = os.environ.get("CMAKE_ARGS") +if env_cmake_args is not None: + cmake_flags.append(env_cmake_args) +os.environ["CMAKE_ARGS"] = " ".join(cmake_flags) setup(