From 4b1383f8e5b624492c07874689ab7b3715e482a9 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 20 Sep 2022 14:13:50 -0700 Subject: [PATCH 01/24] Add script to generate conda envs --- scripts/generate-conda-envs.py | 241 +++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 scripts/generate-conda-envs.py diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py new file mode 100644 index 0000000000..fe94e05ecf --- /dev/null +++ b/scripts/generate-conda-envs.py @@ -0,0 +1,241 @@ +# Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved. +# +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. +# +# See the LICENSE file for details. +# +from __future__ import annotations + +from dataclasses import dataclass +from typing import Literal, Protocol + +from jinja2 import Template +from typing_extensions import TypeAlias + +# --- Types ------------------------------------------------------------------- + +Req: TypeAlias = str +Reqs: TypeAlias = tuple[Req, ...] +OSType: TypeAlias = Literal["linux", "darwin"] + + +class SectionConfig(Protocol): + heading: str + + @property + def conda(self) -> Reqs: + return () + + @property + def pip(self) -> Reqs: + return () + + +@dataclass(frozen=True) +class CUDAConfig(SectionConfig): + ctk_version: str | None + + header = "cuda" + + @property + def conda(self) -> Reqs: + if self.ctk_version is None: + return () + + return ( + f"cudatoolkit=={self.ctk_version}", # runtime + "cutensor", # runtime + "nccl", # runtime + "pynvml", # tests + ) + + @property + def filename_component(self) -> str: + if self.ctk_version is None: + return "" + + return f"-cuda-{self.ctk_version}" + + +class BuildConfig(SectionConfig): + header = "build" + + @property + def conda(self) -> Reqs: + return ( + "c-compiler", + "cmake>=3.24", + "cxx-compiler", + "gcc_linux-64 # [linux64]", + "git", + "make", + "ninja", + "openmpi", + "scikit-build>=0.13.1", + "setuptools>=60", + "sysroot_linux-64==2.17 # [linux64]", + "zlib", + ) + + +class RuntimeConfig(SectionConfig): + header = "runtime" + + @property + def conda(self) -> Reqs: + return ( + "cffi", + "llvm-openmp", + "numpy>=1.22", + "opt_einsum", + "pyarrow>=5", + "scipy", + "typing_extensions", + ) + + +class TestsConfig(SectionConfig): + header = "tests" + + @property + def conda(self) -> Reqs: + return ( + "clang-tools>=8", + "clang>=8", + "colorama", + "coverage", + "mock", + "mypy>=0.961", + "pre-commit", + "pytest-cov", + "pytest-lazy-fixture", + "pytest", + "types-docutils", + ) + + @property + def pip(self) -> Reqs: + return ("tifffile",) + + +class DocsConfig(SectionConfig): + header = "docs" + + @property + def pip(self) -> Reqs: + return ( + "jinja2", + "markdown<3.4.0", + "pydata-sphinx-theme", + "recommonmark", + "sphinx-copybutton", + "sphinx-markdown-tables", + "sphinx>=4.4.0", + ) + + +@dataclass(frozen=True) +class EnvConfig: + use: str + python: str + os: OSType + ctk: str | None + + @property + def sections(self) -> tuple[SectionConfig, ...]: + return ( + self.cuda, + BuildConfig(), + RuntimeConfig(), + TestsConfig(), + DocsConfig(), + ) + + @property + def cuda(self) -> CUDAConfig: + return CUDAConfig(self.ctk) + + @property + def filename(self) -> str: + python = f"py{self.python.replace('.', '')}" + cuda = self.cuda.filename_component + return f"environment-{self.use}-{self.os}-{python}{cuda}.yaml" + + +# --- Setup ------------------------------------------------------------------- + +PYTHON_VERSIONS = ("3.8", "3.9", "3.10") + +CTK_VERSIONS = ( + "10.2", + "11.0", + "11.1", + "11.2", + "11.3", + "11.4", + "11.5", + "11.6", + "11.7", +) + +OS_NAMES: tuple[OSType, ...] = ("linux", "osx") + + +ENV_TEMPLATE = Template( + """ +name: legate-core-test +channels: + - conda-forge +dependencies: + + - python={{ python }} + {% if conda_sections %} + {% for section in conda_sections %} + + # {{ section.header }} + {% for req in section.conda %} + - {{ req }} + {% endfor %} + {% endfor %} + {% endif %} + {% if pip_sections %} + + - pip + - pip: + {% for section in pip_sections %} + + # {{ section.header }} + {% for req in section.pip %} + - {{ req }} + {% endfor %} + {% endfor %} + {% endif %} +""", + trim_blocks=True, + lstrip_blocks=True, +) + +CONFIGS = [ + EnvConfig("test", python, "linux", ctk) + for python in PYTHON_VERSIONS + for ctk in CTK_VERSIONS + (None,) +] + [EnvConfig("test", python, "darwin", None) for python in PYTHON_VERSIONS] + +# --- Code -------------------------------------------------------------------- + +for config in CONFIGS: + conda_sections = [section for section in config.sections if section.conda] + pip_sections = [section for section in config.sections if section.pip] + + print(f"------- {config.filename}") + out = ENV_TEMPLATE.render( + python=config.python, + conda_sections=conda_sections, + pip_sections=pip_sections, + ) + with open(f"conda/{config.filename}", "w") as f: + f.write(out) From 0621ee75e912a8f0ef77fb25a8adfaa1e38ccc14 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Thu, 29 Sep 2022 14:32:50 -0700 Subject: [PATCH 02/24] remove gcc and sysroot pkgs --- scripts/generate-conda-envs.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index fe94e05ecf..54d5739d9d 100644 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -70,14 +70,12 @@ def conda(self) -> Reqs: "c-compiler", "cmake>=3.24", "cxx-compiler", - "gcc_linux-64 # [linux64]", "git", "make", "ninja", "openmpi", "scikit-build>=0.13.1", "setuptools>=60", - "sysroot_linux-64==2.17 # [linux64]", "zlib", ) From 4bed2948f8b951dd5b1a00633e01696418babd81 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Thu, 29 Sep 2022 14:56:51 -0700 Subject: [PATCH 03/24] split out openmpi and compilers options --- scripts/generate-conda-envs.py | 68 +++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 54d5739d9d..897bcc10e7 100644 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -34,6 +34,9 @@ def conda(self) -> Reqs: def pip(self) -> Reqs: return () + def __str__(self) -> str: + return self.heading + @dataclass(frozen=True) class CUDAConfig(SectionConfig): @@ -53,33 +56,44 @@ def conda(self) -> Reqs: "pynvml", # tests ) - @property - def filename_component(self) -> str: + def __str__(self) -> str: if self.ctk_version is None: return "" return f"-cuda-{self.ctk_version}" +@dataclass(frozen=True) class BuildConfig(SectionConfig): + compilers: bool = True + openmpi: bool = True + header = "build" @property def conda(self) -> Reqs: - return ( - "c-compiler", + pkgs = ( "cmake>=3.24", - "cxx-compiler", "git", "make", "ninja", - "openmpi", "scikit-build>=0.13.1", "setuptools>=60", "zlib", ) + if self.compilers: + pkgs += ("c-compiler", "cxx-compiler") + if self.openmpi: + pkgs += ("openmpi",) + return sorted(pkgs) + def __str__(self) -> str: + val = "-compilers" if self.compilers else "-no-compilers" + val += "-with-openmpi" if self.openmpi else "-without-openmpi" + return val + +@dataclass(frozen=True) class RuntimeConfig(SectionConfig): header = "runtime" @@ -96,6 +110,7 @@ def conda(self) -> Reqs: ) +@dataclass(frozen=True) class TestsConfig(SectionConfig): header = "tests" @@ -120,6 +135,7 @@ def pip(self) -> Reqs: return ("tifffile",) +@dataclass(frozen=True) class DocsConfig(SectionConfig): header = "docs" @@ -142,26 +158,43 @@ class EnvConfig: python: str os: OSType ctk: str | None + compilers: bool + openmpi: bool @property def sections(self) -> tuple[SectionConfig, ...]: return ( self.cuda, - BuildConfig(), - RuntimeConfig(), - TestsConfig(), - DocsConfig(), + self.build, + self.runtime, + self.tests, + self.docs, ) @property def cuda(self) -> CUDAConfig: return CUDAConfig(self.ctk) + @property + def build(self) -> BuildConfig: + return BuildConfig(self.compilers, self.openmpi) + + @property + def runtime(self) -> RuntimeConfig: + return RuntimeConfig() + + @property + def tests(self) -> TestsConfig: + return TestsConfig() + + @property + def docs(self) -> DocsConfig: + return DocsConfig() + @property def filename(self) -> str: python = f"py{self.python.replace('.', '')}" - cuda = self.cuda.filename_component - return f"environment-{self.use}-{self.os}-{python}{cuda}.yaml" + return f"environment-{self.use}-{self.os}-{python}{self.cuda}{self.build}.yaml" # noqa # --- Setup ------------------------------------------------------------------- @@ -218,10 +251,17 @@ def filename(self) -> str: ) CONFIGS = [ - EnvConfig("test", python, "linux", ctk) + EnvConfig("test", python, "linux", ctk, compilers, openmpi) for python in PYTHON_VERSIONS for ctk in CTK_VERSIONS + (None,) -] + [EnvConfig("test", python, "darwin", None) for python in PYTHON_VERSIONS] + for compilers in (True, False) + for openmpi in (True, False) +] + [ + EnvConfig("test", python, "darwin", None, compilers, openmpi) + for python in PYTHON_VERSIONS + for compilers in (True, False) + for openmpi in (True, False) +] # --- Code -------------------------------------------------------------------- From 10a015ce98a625464cc12bdb5d054ddebb24bc2e Mon Sep 17 00:00:00 2001 From: Wonchan Lee Date: Fri, 30 Sep 2022 11:33:50 -0700 Subject: [PATCH 04/24] Adjust consensus match frequency based on field sizes (#402) * Perform consensus match more frequently for bigger free fields * Minor cleanup --- legate/core/runtime.py | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/legate/core/runtime.py b/legate/core/runtime.py index fa4fdaad99..b47624378f 100644 --- a/legate/core/runtime.py +++ b/legate/core/runtime.py @@ -200,9 +200,9 @@ def add_free_field( ) -> None: self._freed_fields.append(FreeFieldInfo(manager, region, field_id)) - def issue_field_match(self) -> None: + def issue_field_match(self, credit: int) -> None: # Increment our match counter - self._match_counter += 1 + self._match_counter += credit if self._match_counter < self._match_frequency: return # If the match counter equals our match frequency then do an exchange @@ -342,9 +342,29 @@ def __init__( ) -> None: super().__init__(runtime, shape, field_size) self._field_match_manager = runtime.field_match_manager + self._update_match_credit() + + def _update_match_credit(self) -> None: + if self.shape.fixed: + size = self.shape.volume() * self.field_size + self._match_credit = ( + size + self.runtime.max_field_reuse_size - 1 + if size > self.runtime.max_field_reuse_size + else self.runtime.max_field_reuse_size + ) // self.runtime.max_field_reuse_size + # No need to update the credit as the exact size is known + self._need_to_update_match_credit = False + # If the shape is unknown, we set the credit such that every new + # free field leads to a consensus match, and ask the manager + # to update the credit. + else: + self._match_credit = self.runtime.max_field_reuse_frequency + self._need_to_update_match_credit = True def try_reuse_field(self) -> Optional[tuple[Region, int]]: - self._field_match_manager.issue_field_match() + if self._need_to_update_match_credit: + self._update_match_credit() + self._field_match_manager.issue_field_match(self._match_credit) # First, if we have a free field then we know everyone has one of those if len(self.free_fields) > 0: @@ -915,6 +935,12 @@ def __init__(self, core_library: CoreLib) -> None: ty.uint32, ) ) + self.max_field_reuse_size = int( + self._core_context.get_tunable( + legion.LEGATE_CORE_TUNABLE_FIELD_REUSE_SIZE, + ty.uint64, + ) + ) self._field_manager_class = ( ConsensusMatchingFieldManager if self._num_nodes > 1 or self._args.consensus @@ -1246,12 +1272,7 @@ def find_region_manager(self, region: Region) -> RegionManager: return self.region_managers_by_region[region] def revive_manager(self, region_mgr: RegionManager) -> None: - lru_managers: Deque[RegionManager] = deque() - for to_check in self.lru_managers: - if to_check is not region_mgr: - lru_managers.append(to_check) - assert len(lru_managers) < len(self.lru_managers) - self.lru_managers = lru_managers + self.lru_managers.remove(region_mgr) def free_region_manager( self, shape: Shape, region: Region, unordered: bool = False From e012e00542c4053d2156ac0885d4e4ae5d9ae81f Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Fri, 30 Sep 2022 14:12:57 -0700 Subject: [PATCH 05/24] add command line args for selection --- scripts/generate-conda-envs.py | 86 ++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 14 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 897bcc10e7..384606a67a 100644 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -57,7 +57,7 @@ def conda(self) -> Reqs: ) def __str__(self) -> str: - if self.ctk_version is None: + if self.ctk_version == "none": return "" return f"-cuda-{self.ctk_version}" @@ -202,6 +202,7 @@ def filename(self) -> str: PYTHON_VERSIONS = ("3.8", "3.9", "3.10") CTK_VERSIONS = ( + "none", "10.2", "11.0", "11.1", @@ -250,14 +251,14 @@ def filename(self) -> str: lstrip_blocks=True, ) -CONFIGS = [ +ALL_CONFIGS = [ EnvConfig("test", python, "linux", ctk, compilers, openmpi) for python in PYTHON_VERSIONS - for ctk in CTK_VERSIONS + (None,) + for ctk in CTK_VERSIONS for compilers in (True, False) for openmpi in (True, False) ] + [ - EnvConfig("test", python, "darwin", None, compilers, openmpi) + EnvConfig("test", python, "darwin", "none", compilers, openmpi) for python in PYTHON_VERSIONS for compilers in (True, False) for openmpi in (True, False) @@ -265,15 +266,72 @@ def filename(self) -> str: # --- Code -------------------------------------------------------------------- -for config in CONFIGS: - conda_sections = [section for section in config.sections if section.conda] - pip_sections = [section for section in config.sections if section.pip] +if __name__ == "__main__": + + import sys + from argparse import ArgumentParser, BooleanOptionalAction - print(f"------- {config.filename}") - out = ENV_TEMPLATE.render( - python=config.python, - conda_sections=conda_sections, - pip_sections=pip_sections, + parser = ArgumentParser() + parser.add_argument( + "--python", + choices=PYTHON_VERSIONS, + default=None, + help="Python version to generate for, (default: all python versions)", + ) + parser.add_argument( + "--ctk", + choices=CTK_VERSIONS, + default=None, + dest="ctk_version", + help="CTK version to generate for (default: all CTK versions)", + ) + parser.add_argument( + "--os", + choices=OS_NAMES, + default=None, + help="OS to generate for, if unset, generate for all OSes", + ) + parser.add_argument( + "--compilers", + action=BooleanOptionalAction, + default=None, + help="Whether to include conda compilers or not (default: both)", + ) + parser.add_argument( + "--openmpi", + action=BooleanOptionalAction, + default=None, + help="Whether to include openmpi or not, (default: both)", ) - with open(f"conda/{config.filename}", "w") as f: - f.write(out) + + args = parser.parse_args(sys.argv[1:]) + + configs = ALL_CONFIGS + + if args.python is not None: + configs = (x for x in configs if x.python == args.python) + if args.ctk_version is not None: + configs = ( + x for x in configs if x.cuda.ctk_version == args.ctk_version + ) + if args.compilers is not None: + configs = (x for x in configs if x.build.compilers == args.compilers) + if args.os is not None: + configs = (x for x in configs if x.os == args.os) + if args.openmpi is not None: + configs = (x for x in configs if x.build.openmpi == args.openmpi) + + for config in configs: + conda_sections = [ + section for section in config.sections if section.conda + ] + pip_sections = [section for section in config.sections if section.pip] + + print(f"--- generating: {config.filename}") + out = ENV_TEMPLATE.render( + python=config.python, + conda_sections=conda_sections, + pip_sections=pip_sections, + ) + with open(f"{config.filename}", "w") as f: + f.write(out) From 2ba6120c5cd1e7751839ff2e28a515377643bb11 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Fri, 30 Sep 2022 14:18:10 -0700 Subject: [PATCH 06/24] help wording --- scripts/generate-conda-envs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 384606a67a..5b749a9c28 100644 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -289,7 +289,7 @@ def filename(self) -> str: "--os", choices=OS_NAMES, default=None, - help="OS to generate for, if unset, generate for all OSes", + help="OS to generate for (default: all OSes)", ) parser.add_argument( "--compilers", @@ -301,7 +301,7 @@ def filename(self) -> str: "--openmpi", action=BooleanOptionalAction, default=None, - help="Whether to include openmpi or not, (default: both)", + help="Whether to include openmpi or not (default: both)", ) args = parser.parse_args(sys.argv[1:]) From adef1fd14e21e1fb496f901daa9087dfc27e242b Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 13:52:04 -0700 Subject: [PATCH 07/24] Make script executable --- scripts/generate-conda-envs.py | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 scripts/generate-conda-envs.py diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py old mode 100644 new mode 100755 index 5b749a9c28..3c173b5940 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + # Copyright (c) 2020-2022, NVIDIA CORPORATION. All rights reserved. # # NVIDIA CORPORATION and its licensors retain all intellectual property From 0a908f9a0d127eb886b89c6cb39f74deb5e46647 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 13:52:22 -0700 Subject: [PATCH 08/24] Fixes for python 3.8 --- scripts/generate-conda-envs.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 3c173b5940..26140dad49 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -13,7 +13,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Literal, Protocol +from typing import Literal, Protocol, Tuple from jinja2 import Template from typing_extensions import TypeAlias @@ -21,7 +21,7 @@ # --- Types ------------------------------------------------------------------- Req: TypeAlias = str -Reqs: TypeAlias = tuple[Req, ...] +Reqs: TypeAlias = Tuple[Req, ...] OSType: TypeAlias = Literal["linux", "darwin"] @@ -164,7 +164,7 @@ class EnvConfig: openmpi: bool @property - def sections(self) -> tuple[SectionConfig, ...]: + def sections(self) -> Tuple[SectionConfig, ...]: return ( self.cuda, self.build, @@ -216,7 +216,7 @@ def filename(self) -> str: "11.7", ) -OS_NAMES: tuple[OSType, ...] = ("linux", "osx") +OS_NAMES: Tuple[OSType, ...] = ("linux", "osx") ENV_TEMPLATE = Template( @@ -271,7 +271,7 @@ def filename(self) -> str: if __name__ == "__main__": import sys - from argparse import ArgumentParser, BooleanOptionalAction + from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument( @@ -295,13 +295,29 @@ def filename(self) -> str: ) parser.add_argument( "--compilers", - action=BooleanOptionalAction, + action="store_true", + dest="compilers", + default=None, + help="Whether to include conda compilers or not (default: both)", + ) + parser.add_argument( + "--no-compilers", + action="store_false", + dest="compilers", default=None, help="Whether to include conda compilers or not (default: both)", ) parser.add_argument( "--openmpi", - action=BooleanOptionalAction, + action="store_true", + dest="openmpi", + default=None, + help="Whether to include openmpi or not (default: both)", + ) + parser.add_argument( + "--no-openmpi", + action="store_false", + dest="openmpi", default=None, help="Whether to include openmpi or not (default: both)", ) From 3a4943d66b2fbd1acb9860472d95e6a349ac6341 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 13:52:49 -0700 Subject: [PATCH 09/24] Remove old environment files --- conda/environment-test-3.10.yml | 58 --------------------------------- conda/environment-test-3.8.yml | 58 --------------------------------- conda/environment-test-3.9.yml | 58 --------------------------------- 3 files changed, 174 deletions(-) delete mode 100644 conda/environment-test-3.10.yml delete mode 100644 conda/environment-test-3.8.yml delete mode 100644 conda/environment-test-3.9.yml diff --git a/conda/environment-test-3.10.yml b/conda/environment-test-3.10.yml deleted file mode 100644 index 736e4c5e0d..0000000000 --- a/conda/environment-test-3.10.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: legate-core-test -channels: - - conda-forge -dependencies: - - python=3.10 - - # build - - git - - nccl - - make - - zlib - - cmake>=3.24 - - ninja - - openmpi - - c-compiler - - cxx-compiler - - gcc_linux-64 # [linux64] - - sysroot_linux-64==2.17 # [linux64] - - setuptools>=60 - - scikit-build>=0.13.1 - - # runtime - - cffi - - numpy>=1.22 - - opt_einsum - - pyarrow>=5 - - scipy - - typing_extensions - - llvm-openmp - - # tests - - clang>=8 - - clang-tools>=8 - - colorama - - coverage - - mock - - mypy>=0.961 - - pre-commit - - pynvml - - pytest - - pytest-cov - - pytest-lazy-fixture - - types-docutils - - # pip dependencies - - pip - - pip: - # docs - - jinja2 - - pydata-sphinx-theme - - recommonmark - - markdown<3.4.0 - - sphinx>=4.4.0 - - sphinx-copybutton - - sphinx-markdown-tables - - # examples - - tifffile diff --git a/conda/environment-test-3.8.yml b/conda/environment-test-3.8.yml deleted file mode 100644 index 9f58e9b5da..0000000000 --- a/conda/environment-test-3.8.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: legate-core-test -channels: - - conda-forge -dependencies: - - python=3.8 - - # build - - git - - nccl - - make - - zlib - - cmake>=3.24 - - ninja - - openmpi - - c-compiler - - cxx-compiler - - gcc_linux-64 # [linux64] - - sysroot_linux-64==2.17 # [linux64] - - setuptools>=60 - - scikit-build>=0.13.1 - - # runtime - - cffi - - numpy>=1.22 - - opt_einsum - - pyarrow>=5 - - scipy - - typing_extensions - - llvm-openmp - - # tests - - clang>=8 - - clang-tools>=8 - - colorama - - coverage - - mock - - mypy>=0.961 - - pre-commit - - pynvml - - pytest - - pytest-cov - - pytest-lazy-fixture - - types-docutils - - # pip dependencies - - pip - - pip: - # docs - - jinja2 - - pydata-sphinx-theme - - recommonmark - - markdown<3.4.0 - - sphinx>=4.4.0 - - sphinx-copybutton - - sphinx-markdown-tables - - # examples - - tifffile diff --git a/conda/environment-test-3.9.yml b/conda/environment-test-3.9.yml deleted file mode 100644 index 9d4eea27dc..0000000000 --- a/conda/environment-test-3.9.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: legate-core-test -channels: - - conda-forge -dependencies: - - python=3.9 - - # build - - git - - nccl - - make - - zlib - - cmake>=3.24 - - ninja - - openmpi - - c-compiler - - cxx-compiler - - gcc_linux-64 # [linux64] - - sysroot_linux-64==2.17 # [linux64] - - setuptools>=60 - - scikit-build>=0.13.1 - - # runtime - - cffi - - numpy>=1.22 - - opt_einsum - - pyarrow>=5 - - scipy - - typing_extensions - - llvm-openmp - - # tests - - clang>=8 - - clang-tools>=8 - - colorama - - coverage - - mock - - mypy>=0.961 - - pre-commit - - pynvml - - pytest - - pytest-cov - - pytest-lazy-fixture - - types-docutils - - # pip dependencies - - pip - - pip: - # docs - - jinja2 - - pydata-sphinx-theme - - recommonmark - - markdown<3.4.0 - - sphinx>=4.4.0 - - sphinx-copybutton - - sphinx-markdown-tables - - # examples - - tifffile From 1436b6942bf7ef365d0d0d673629973d481bf41b Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 13:55:44 -0700 Subject: [PATCH 10/24] Unify file naming for "compilers" and "openmpi" --- 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 26140dad49..a5587e523f 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -91,7 +91,7 @@ def conda(self) -> Reqs: def __str__(self) -> str: val = "-compilers" if self.compilers else "-no-compilers" - val += "-with-openmpi" if self.openmpi else "-without-openmpi" + val += "-openmpi" if self.openmpi else "-no-openmpi" return val From f2fcc26a29ec011c53614447046bcbe38050cd56 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 14:29:37 -0700 Subject: [PATCH 11/24] Fix typo --- 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 a5587e523f..26eb0c9a53 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -52,7 +52,7 @@ def conda(self) -> Reqs: return () return ( - f"cudatoolkit=={self.ctk_version}", # runtime + f"cudatoolkit={self.ctk_version}", # runtime "cutensor", # runtime "nccl", # runtime "pynvml", # tests From dea2c9142b4e7dec0e1a9a60a3e7a97da84b3889 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 15:29:25 -0700 Subject: [PATCH 12/24] Remove optional ninja dependency --- scripts/generate-conda-envs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 26eb0c9a53..ca18691381 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -78,7 +78,6 @@ def conda(self) -> Reqs: "cmake>=3.24", "git", "make", - "ninja", "scikit-build>=0.13.1", "setuptools>=60", "zlib", From 66205755cbf9e5caaf5af4b03ad0a02b52809eb4 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 15:36:59 -0700 Subject: [PATCH 13/24] Not just for the core, include cunumeric also --- scripts/generate-conda-envs.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index ca18691381..2c1b75850d 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -53,7 +53,7 @@ def conda(self) -> Reqs: return ( f"cudatoolkit={self.ctk_version}", # runtime - "cutensor", # runtime + "cutensor>=1.3.3", # runtime "nccl", # runtime "pynvml", # tests ) @@ -104,6 +104,7 @@ def conda(self) -> Reqs: "cffi", "llvm-openmp", "numpy>=1.22", + "openblas=*=*openmp*", "opt_einsum", "pyarrow>=5", "scipy", @@ -127,6 +128,7 @@ def conda(self) -> Reqs: "pre-commit", "pytest-cov", "pytest-lazy-fixture", + "pytest-mock", "pytest", "types-docutils", ) @@ -220,7 +222,7 @@ def filename(self) -> str: ENV_TEMPLATE = Template( """ -name: legate-core-test +name: legate-{{ use }} channels: - conda-forge dependencies: @@ -346,6 +348,7 @@ def filename(self) -> str: print(f"--- generating: {config.filename}") out = ENV_TEMPLATE.render( + use=config.use, python=config.python, conda_sections=conda_sections, pip_sections=pip_sections, From 28a937541fc7daba32260218b57fd7ff0c700937 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 10 Oct 2022 22:37:48 -0700 Subject: [PATCH 14/24] Update build documentation --- BUILD.md | 215 +++++++++++++++++++++++++++++++++++++++++++++++++----- README.md | 128 +++----------------------------- 2 files changed, 207 insertions(+), 136 deletions(-) diff --git a/BUILD.md b/BUILD.md index 8bf5f1ac74..592b6c212c 100644 --- a/BUILD.md +++ b/BUILD.md @@ -23,32 +23,204 @@ The build system is designed to enable two different modes of use: We review each of these modes with examples. +# Dependencies + +The primary method of retrieving dependencies for Legate Core and downstream +libraries is through [conda](https://conda.io). You will need an installation of +conda to follow the instructions below. + +Please use the `scripts/generate-conda-envs.py` script to create a conda +environment file listing all the packages that are required to build, run and +test Legate Core and all downstream libraries. Once you have this file, you can +install the required packages by creating a new conda environment: + +``` +conda env create -n legate -f .yaml +``` + +or by updating an existing environment: + +``` +conda env update -f .yaml +``` + +## Alternative sources for dependencies + +If you do not wish to use conda for some (or all) of the dependencies, you can +remove the corresponding entries from the environment file before passing it to +conda. See the `install.py` section below for instructions on how to provide +alternative locations for these dependencies to the build process. + +Note that this is likely to result in conflicts between conda-provided and +system-provided libraries: + +Conda distributes its own version of certain common libraries (in particular the +C++ standard library), which are also typically available system-wide. Any +system package you include will typically link to the system version, while +conda packages link to the conda version. Often these two different versions, +although incompatible, carry the same version number (`SONAME`), and are +therefore indistinguishable to the dynamic linker. Then, the first component to +specify a link location for this library will cause it to be loaded from there, +and any subsequent link requests for the same library, even if suggesting a +different link location, will get served using the previously linked version. + +This can cause link failures at runtime, e.g. when a system-level library +happens to be the first to load GLIBC, causing any conda library that comes +after to trip GLIBC's internal version checks, since the conda library expects +to find symbols with more recent version numbers than what is available on the +system-wide GLIBC: + +``` +/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /opt/conda/envs/legate/lib/libarrow.so) +``` + +You can usually work around this issue by putting the conda library directory +first in the dynamic library resolution path: + +``` +LD_LIBRARY_PATH="$CONDA_PREFIX/lib:$LD_LIBRARY_PATH" +``` + +This way you can make sure that the (typically more recent) conda version of any +common library will be preferred over the system-wide one, no matter which +component requests it first. + +## Notable dependencies + +### OS (`--os` option) + +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` option) + +In terms of Python compatibility, Legate *roughly* follows the timeline outlined +in [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html). + +### C++17 compatible compiler (`--compilers` option) + +For example: g++, clang, or nvc++. When creating an environment using the +`--compilers` flag, an appropriate compiler for the current system will be +pulled from conda. + +If you need/prefer to use the system-provided compilers (typical for HPC +installations), please use a conda environment generated with `--no-compilers`. +Note that this will likely result in a conda/system library conflict (as +explained above), since the system compilers will typically produce executables +that link against the system-provided libraries, which can shadow the +conda-provided equivalents. + +### CUDA >= 10.2 (`--ctk` flag; optional) + +Only necessary if you wish to run with Nvidia GPUs. + +Some CUDA components necessary for building, e.g. the `nvcc` compiler and driver +stubs, are not distributed through conda. These must instead be installed using +[system-level packages](https://developer.nvidia.com/cuda-downloads). + +Independent of the system-level CUDA installation, conda will need to install an +environment-local copy of the CUDA toolkit (which is what the `--ctk` option +controls). To avoid versioning conflicts it is safest to match the version of +CUDA installed system-wide on your machine + +Legate is tested and guaranteed to be compatible with Volta and later GPU +architectures. You can use Legate with Pascal GPUs as well, but there could +be issues due to lack of independent thread scheduling. Please report any such +issues on GitHub. + +### Fortran compiler (optional) + +Only necessary if you wish to build OpenBLAS from source. + +Not included by default in the generated conda environment files; install +`fortran-compiler` from `conda-forge` if you need it. + +### Numactl (optional) + +Required to support CPU and memory binding in the Legate launcher. + +Not available on conda; typically available through the system-level package +manager. + +## MPI (`--openmpi` option) + +Only necessary if you wish to run on multiple nodes. + +Conda distributes a generic build of OpenMPI, but you may need to use a more +specialized build, e.g. the one distributed by +[MOFED](https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/), +or one provided by your HPC vendor. In that case you should use an environment +file generated with `--no-openmpi`. + +## Networking libraries (e.g. Infiniband, RoCE, UCX; optional) + +Only necessary if you wish to run on multiple nodes. + +Not available on conda; typically available through MOFED or the system-level +package manager. # Building for Users ## Using install.py -For releases <= 22.07, the main method for building Legate was the `install.py` script. -Although the underlying implementation has significantly changed, `install.py` still supports the -same usage and same set of flags. For a full list of flags, users can run: +The Legate Core repository comes with a helper `install.py` script in the +top-level directory, that will build the C++ parts of the library and install +the C++ and Python components under the currently active Python environment. + +To add GPU support, use the `--cuda` flag: ``` -$ ./install.py --help +./install.py --cuda ``` -## Using Conda +You can specify the CUDA toolkit directory and the CUDA architecture you want to +target using the `--with-cuda` and `--arch` flags, e.g.: -Legate can be installed using Conda by pointing to the required channels (`-c`): +``` +./install.py --cuda --with-cuda /usr/local/cuda/ --arch ampere +``` + +By default the script relies on CMake's auto-detection for these settings. + +For multi-node execution Legate uses [GASNet](https://gasnet.lbl.gov/) which can be +requested using the `--network gasnet1` or `--network gasnetex` flag. By default +GASNet will be automatically downloaded and built, but if you have an existing +installation then you can inform the install script using the `--with-gasnet` flag. +You also need to specify the interconnect network of the target machine using the +`--conduit` flag. +For example this would be an installation for a +[DGX SuperPOD](https://www.nvidia.com/en-us/data-center/dgx-superpod/): ``` -conda install -c nvidia -c conda-forge -c legate legate-core +./install.py --network gasnet1 --conduit ibv --cuda --arch ampere +``` +Alternatively, here is an install line for the +[Piz-Daint](https://www.cscs.ch/computers/dismissed/piz-daint-piz-dora/) supercomputer: +``` +./install.py --network gasnet1 --conduit aries --cuda --arch pascal +``` + +In general, cmake will first search the currently active Python environment for +dependencies, then any common system-wide installation directories (e.g. +`/usr/lib`). If a dependency cannot be found but is publicly available in source +form (e.g. OpenBLAS), cmake will fetch and build it automatically. You can +override this search by providing an install location for any dependency +explicitly, using a `--with-dep` flag, e.g. `--with-nccl` and +`--with-openblas`. + +To see all available configuration options, run with the `--help` flag: + +``` +./install.py --help ``` ## Using pip -Legate is not yet registered in a standard pip repository. However, users can still use the -pip installer to build and install Legate. After downloading or cloning the legate.core source, -users can run the following in the legate.core folder: +Legate Core is not yet registered in a standard pip repository. However, users +can still use the pip installer to build and install Legate Core. The following +command will trigger a single-node, CPU-only build of Legate Core, then install +it into the currently active Python environment: ``` $ pip install . @@ -58,18 +230,20 @@ or $ python3 -m pip install . ``` -This will install Legate in the standard packages directory for the environment Python. - -### Advanced Customization +## Advanced Customization -If users need to customize details of the underlying CMake build, they can pass -CMake flags through the `SKBUILD_CONFIGURE_OPTIONS` environment variable: +Legate relies on CMake to select its toolchain and build flags. Users can set +the environment variables `CXX` or `CXXFLAGS` prior to building to override the +CMake defaults. Alternatively, CMake values can be overridden through the +`SKBUILD_CONFIGURE_OPTIONS` variable: ``` $ SKBUILD_CONFIGURE_OPTIONS="-D Legion_USE_CUDA:BOOL=ON" \ pip install . ``` + An alternative syntax using `setup.py` with `scikit-build` is + ``` $ python setup.py install -- -DLegion_USE_CUDA:BOOL=ON ``` @@ -86,15 +260,17 @@ in `setup.py` to drive the build and installation. A `pip install` will trigger 3. pip installation of Python files The CMake build can be configured independently of `pip`, allowing incremental C++ builds directly through CMake. -This simplifies rebuilding `libcunumeric.so` either via command-line or via IDE. +This simplifies rebuilding the C++ shared libraries either via command-line or via IDE. After building the C++ libraries, the `pip install` can be done in "editable" mode using the `-e` flag. This configures the Python site packages to import the Python source tree directly. The Python source can then be edited and used directly for testing without requiring another `pip install`. ## Example -There are several examples in the `scripts` folder. We walk through the steps in the `build-separately-no-install.sh` here. -First, the CMake build needs to be configured, e.g.: +There are several examples in the `scripts` folder. We walk through the steps in +`build-separately-no-install.sh` here. + +First, the CMake build needs to be configured: ``` $ cmake -S . -B build -GNinja -D Legion_USE_CUDA=ON @@ -118,6 +294,7 @@ $ SKBUILD_BUILD_OPTIONS="-D FIND_LEGATE_CORE_CPP=ON -D legate_core_ROOT=$(pwd)/b The Python source tree and CMake build tree are now available with the environment Python for running Legate programs. The diagram below illustrates the -complete workflow for building both Legate core and a downstream package [cuNumeric]() +complete workflow for building both Legate core and a downstream package, +[cuNumeric](https://github.com/nv-legate/cunumeric) drawing diff --git a/README.md b/README.md index 0196550924..b07a575526 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ If you have questions, please contact us at legate(at)nvidia.com. 1. [Why Legate?](#why-legate) 1. [What is the Legate Core?](#what-is-the-legate-core) 1. [How Does Legate Work?](#how-does-legate-work) -1. [How Do I Install Legate?](#how-do-i-install-legate) +1. [How Do I Install Legate?](#installation) 1. [How Do I Use Legate?](#how-do-i-use-legate) 1. [Other FAQs](#other-faqs) 1. [Contributing](#contributing) @@ -215,120 +215,14 @@ 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. + Docker image build scripts, as well as specialized install scripts for supported clusters are available on the [quickstart](https://github.com/nv-legate/quickstart) repo. -Read on for general instructions on building Legate Core from source. - -### Dependencies - -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. - -Legate Core requires the following: - - - Python >= 3.8 - - [CUDA](https://developer.nvidia.com/cuda-downloads) >= 10.2 - - GNU Make - - C++17 compatible compiler (g++, clang, or nvc++) - - numactl (optional, to support CPU and memory binding) - - the Python packages listed in any one of the conda environment files: - - `conda/environment-test-3.8.yml` - - `conda/environment-test-3.9.yml` - - `conda/environment-test-3.10.yml` - -You can install the required Python packages by creating a new conda environment: - -``` -conda env create -n legate -f conda/environment-test-3.10.yml -``` - -or by updating an existing environment: - -``` -conda env update -f conda/environment-test-3.10.yml -``` - -Note that conda will need to install an environment-local copy of the CUDA -toolkit, and by default it will choose the latest available version. To avoid -versioning conflicts, however, it is safer to match the version of CUDA -installed system-wide on your machine. Therefore, we suggest that you add this -as an explicit dependency at the bottom of the conda environment file. For -example, if your system-wide CUDA installation is at version 10.2, add: - -``` - - cudatoolkit=10.2 -``` - -### Installation - -The Legate Core library comes with both a standard `setup.py` script and a -custom `install.py` script in the top-level directory of the repository that -will build and install the Legate Core library. Users can use either script -to install Legate as they will produce the same effect. Users can do a simple -pip installation of a single-node, CPU-only Legate configuration by navigating -to the Legate source directory and running: -``` -pip install . -``` -or -``` -python3 -m pip install . -``` - -This will install Legate into the standard packages of the Python environment. - -To add GPU support or do more complicated customization, Legate provides a -helper `install.py` script. For GPU support, simply use the `--cuda` flag: - -``` -./install.py --cuda -``` - -The first time you request GPU support you may need to use the `--with-cuda` flag to -specify the location of your CUDA installation and the `--with-nccl` flag to specify -the path to your NCCL installation, if these cannot be automatically located by the build system. -You can also specify the name of the CUDA architecture you want to target with the `--arch` -flag. By default the script relies on CMake's auto-detection. -``` -./install.py --cuda --with-cuda /usr/local/cuda/ --with-nccl "$CONDA_PREFIX" --arch ampere -``` -For multi-node support Legate uses [GASNet](https://gasnet.lbl.gov/) which can be -requested using the `--network gasnet1` or `--network gasnetex` flag. By default -GASNet will be automatically downloaded and built, but if you have an existing -installation then you can inform the install script using the `--with-gasnet` flag. -You also need to specify the interconnect network of the target machine using the -`--conduit` flag. - -For example this would be an installation for a -[DGX SuperPOD](https://www.nvidia.com/en-us/data-center/dgx-superpod/): -``` -./install.py --network gasnet1 --conduit ibv --cuda --arch ampere -``` -Alternatively here is an install line for the -[Piz-Daint](https://www.cscs.ch/computers/dismissed/piz-daint-piz-dora/) supercomputer: -``` -./install.py --network gasnet1 --conduit aries --cuda --arch pascal -``` -To see all the options available for installing Legate, run with the `--help` flag: -``` -./install.py --help -``` - -### Toolchain Selection - -Legate relies on CMake to select its toolchain and build flags. -Users can set the environment variables `CXX` or `CXXFLAGS` -prior to building to override the CMake defaults. Alternatively, CMake values -can be overriden through the `SKBUILD_CONFIGURE_OPTIONS` variable, -which is discussed in more detail in the [developer build instructions](BUILD.md). - -### Developer Workflow - -Details on doing incremental CMake builds and editable pip installations can be -found in the [developer build instructions](BUILD.md). +See [BUILD.md] for instructions on building Legate Core from source. ## How Do I Use Legate? @@ -452,9 +346,9 @@ that can adversely effect the performance of the application. Same as normal Python programs, Legate programs can be run using Jupyter Notebook. Currently we support single node execution with multiple CPUs and GPUs, and plan to support multi-node execution in the future. -We leverage Legion's Jupyter support, so you may want to refer to the +We leverage Legion's Jupyter support, so you may want to refer to the [relevant section in Legion's README](https://github.com/StanfordLegion/legion/blob/master/jupyter_notebook/README.md). -To simplify the installation, we provide a script specifically for Legate libraries. +To simplify the installation, we provide a script specifically for Legate libraries. ### Installation of the Legate IPython Kernel @@ -473,7 +367,7 @@ IPython kernel: legate_kernel_nocr(Legate_SM_GPU) has been installed ``` `Legate_SM_GPU` is the kernel name, and you will need to provide it when starting the Jupyter Notebook. `SM` means the kernel is only for -shared memory execution; `GPU` means GPU support is enabled. +shared memory execution; `GPU` means GPU support is enabled. ### Running with Jupyter Notebook @@ -494,14 +388,14 @@ install time. Here is an example of an entry in the json file: "value": 1 } ``` -* `cpus` is the name of the field. +* `cpus` is the name of the field. * `cmd` is used to tell Jupyter how to pass the value for that field to Legate through the CLI, in this case using `--cpus` to set the number of CPUs. -* `value` is the value of the field. +* `value` is the value of the field. -Other configuration options can be added by using the `other_options` field of the json file. +Other configuration options can be added by using the `other_options` field of the json file. ### Magic Command From 4cd486fccfc2c281d8a3619a673e07a7641d1e03 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 11 Oct 2022 12:23:02 -0700 Subject: [PATCH 15/24] Fix a file link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b07a575526..d108c254c2 100644 --- a/README.md +++ b/README.md @@ -222,7 +222,7 @@ Docker image build scripts, as well as specialized install scripts for supported clusters are available on the [quickstart](https://github.com/nv-legate/quickstart) repo. -See [BUILD.md] for instructions on building Legate Core from source. +See [BUILD.md]() for instructions on building Legate Core from source. ## How Do I Use Legate? From 1725e4c15daffaad8afbd2cdc58aa4b308c30a56 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Tue, 11 Oct 2022 12:30:25 -0700 Subject: [PATCH 16/24] Fix formatting --- BUILD.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/BUILD.md b/BUILD.md index 592b6c212c..33ef8937f8 100644 --- a/BUILD.md +++ b/BUILD.md @@ -15,16 +15,10 @@ limitations under the License. --> -# Overview - -The build system is designed to enable two different modes of use: -1. Simple `install.py` helper script or `pip install` for users -2. Highly customizable incremental builds for developers - -We review each of these modes with examples. - # Dependencies +## Getting dependencies through conda + The primary method of retrieving dependencies for Legate Core and downstream libraries is through [conda](https://conda.io). You will need an installation of conda to follow the instructions below. @@ -52,7 +46,7 @@ conda. See the `install.py` section below for instructions on how to provide alternative locations for these dependencies to the build process. Note that this is likely to result in conflicts between conda-provided and -system-provided libraries: +system-provided libraries. Conda distributes its own version of certain common libraries (in particular the C++ standard library), which are also typically available system-wide. Any @@ -93,7 +87,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` option) +### Python >= 3.8 (`--python` option) In terms of Python compatibility, Legate *roughly* follows the timeline outlined in [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html). @@ -143,7 +137,7 @@ Required to support CPU and memory binding in the Legate launcher. Not available on conda; typically available through the system-level package manager. -## MPI (`--openmpi` option) +### MPI (`--openmpi` option) Only necessary if you wish to run on multiple nodes. @@ -153,7 +147,7 @@ specialized build, e.g. the one distributed by or one provided by your HPC vendor. In that case you should use an environment file generated with `--no-openmpi`. -## Networking libraries (e.g. Infiniband, RoCE, UCX; optional) +### Networking libraries (e.g. Infiniband, RoCE, UCX; optional) Only necessary if you wish to run on multiple nodes. From e73f5490667d9a62f69e1062e669c3f52388c015 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 18 Oct 2022 16:00:40 -0700 Subject: [PATCH 17/24] remove typing_extensions dependency --- scripts/generate-conda-envs.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 2c1b75850d..2c126da29d 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -16,13 +16,12 @@ from typing import Literal, Protocol, Tuple from jinja2 import Template -from typing_extensions import TypeAlias # --- Types ------------------------------------------------------------------- -Req: TypeAlias = str -Reqs: TypeAlias = Tuple[Req, ...] -OSType: TypeAlias = Literal["linux", "darwin"] +Req = str +Reqs = Tuple[Req, ...] +OSType = Literal["linux", "darwin"] class SectionConfig(Protocol): From c42bee8ef46343508f367a47ee3a405701c8261d Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 18 Oct 2022 16:22:21 -0700 Subject: [PATCH 18/24] remove jinja dependency --- scripts/generate-conda-envs.py | 70 +++++++++++++++++----------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 2c126da29d..2da8ed26f8 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -13,10 +13,9 @@ from __future__ import annotations from dataclasses import dataclass +from textwrap import indent from typing import Literal, Protocol, Tuple -from jinja2 import Template - # --- Types ------------------------------------------------------------------- Req = str @@ -25,7 +24,7 @@ class SectionConfig(Protocol): - heading: str + header: str @property def conda(self) -> Reqs: @@ -36,7 +35,14 @@ def pip(self) -> Reqs: return () def __str__(self) -> str: - return self.heading + return self.header + + def format(self, kind: str) -> str: + return SECTION_TEMPLATE.format( + header=self.header, + reqs="- " + + "\n- ".join(self.conda if kind == "conda" else self.pip), + ) @dataclass(frozen=True) @@ -219,39 +225,29 @@ def filename(self) -> str: OS_NAMES: Tuple[OSType, ...] = ("linux", "osx") -ENV_TEMPLATE = Template( - """ -name: legate-{{ use }} +ENV_TEMPLATE = """\ +name: legate-{use} channels: - conda-forge dependencies: - - python={{ python }} - {% if conda_sections %} - {% for section in conda_sections %} + - python={python} + +{conda_sections} +{pip} +""" + +SECTION_TEMPLATE = """\ +# {header} +{reqs} - # {{ section.header }} - {% for req in section.conda %} - - {{ req }} - {% endfor %} - {% endfor %} - {% endif %} - {% if pip_sections %} +""" +PIP_TEMPLATE = """\ - pip - pip: - {% for section in pip_sections %} - - # {{ section.header }} - {% for req in section.pip %} - - {{ req }} - {% endfor %} - {% endfor %} - {% endif %} -""", - trim_blocks=True, - lstrip_blocks=True, -) +{pip_sections} +""" ALL_CONFIGS = [ EnvConfig("test", python, "linux", ctk, compilers, openmpi) @@ -340,17 +336,21 @@ def filename(self) -> str: configs = (x for x in configs if x.build.openmpi == args.openmpi) for config in configs: - conda_sections = [ - section for section in config.sections if section.conda - ] - pip_sections = [section for section in config.sections if section.pip] + conda_sections = indent( + "".join(s.format("conda") for s in config.sections if s.conda), + " ", + ) + + pip_sections = indent( + "".join(s.format("pip") for s in config.sections if s.pip), " " + ) print(f"--- generating: {config.filename}") - out = ENV_TEMPLATE.render( + out = ENV_TEMPLATE.format( use=config.use, python=config.python, conda_sections=conda_sections, - pip_sections=pip_sections, + pip=PIP_TEMPLATE.format(pip_sections=pip_sections), ) with open(f"{config.filename}", "w") as f: f.write(out) From a6adafde00f39beb48e678db4e0cb81a222bea89 Mon Sep 17 00:00:00 2001 From: Bryan Van de Ven Date: Tue, 18 Oct 2022 16:24:09 -0700 Subject: [PATCH 19/24] slight vertical whitespace improvemetn --- scripts/generate-conda-envs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 2da8ed26f8..b148cd74e1 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -233,8 +233,7 @@ def filename(self) -> str: - python={python} -{conda_sections} -{pip} +{conda_sections}{pip} """ SECTION_TEMPLATE = """\ From 2ee39fda682940d1e61902ddf03ddbf37452a510 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Fri, 21 Oct 2022 09:40:31 -0700 Subject: [PATCH 20/24] Use custom BooleanFlag action, for the benefit of py3.8 --- scripts/generate-conda-envs.py | 61 ++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index b148cd74e1..454e53eb2b 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -12,6 +12,7 @@ # from __future__ import annotations +from argparse import Action, ArgumentParser from dataclasses import dataclass from textwrap import indent from typing import Literal, Protocol, Tuple @@ -263,10 +264,50 @@ def filename(self) -> str: # --- Code -------------------------------------------------------------------- + +class BooleanFlag(Action): + def __init__( + self, + option_strings, + dest, + default, + required=False, + help="", + metavar=None, + ): + assert all(not opt.startswith("--no") for opt in option_strings) + + def flatten(list): + return [item for sublist in list for item in sublist] + + option_strings = flatten( + [ + [opt, "--no-" + opt[2:], "--no" + opt[2:]] + if opt.startswith("--") + else [opt] + for opt in option_strings + ] + ) + super().__init__( + option_strings, + dest, + nargs=0, + const=None, + default=default, + type=bool, + choices=None, + required=required, + help=help, + metavar=metavar, + ) + + def __call__(self, parser, namespace, values, option_string): + setattr(namespace, self.dest, not option_string.startswith("--no")) + + if __name__ == "__main__": import sys - from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument( @@ -290,28 +331,14 @@ def filename(self) -> str: ) parser.add_argument( "--compilers", - action="store_true", - dest="compilers", - default=None, - help="Whether to include conda compilers or not (default: both)", - ) - parser.add_argument( - "--no-compilers", - action="store_false", + action=BooleanFlag, dest="compilers", default=None, help="Whether to include conda compilers or not (default: both)", ) parser.add_argument( "--openmpi", - action="store_true", - dest="openmpi", - default=None, - help="Whether to include openmpi or not (default: both)", - ) - parser.add_argument( - "--no-openmpi", - action="store_false", + action=BooleanFlag, dest="openmpi", default=None, help="Whether to include openmpi or not (default: both)", From 59f763bf2e340edd03e504fcb3ebdf1d286d7d86 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Fri, 21 Oct 2022 11:12:38 -0700 Subject: [PATCH 21/24] Update build instructions --- BUILD.md | 110 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 50 deletions(-) diff --git a/BUILD.md b/BUILD.md index 33ef8937f8..9097967042 100644 --- a/BUILD.md +++ b/BUILD.md @@ -15,7 +15,7 @@ limitations under the License. --> -# Dependencies +# Getting dependencies ## Getting dependencies through conda @@ -25,60 +25,30 @@ conda to follow the instructions below. Please use the `scripts/generate-conda-envs.py` script to create a conda environment file listing all the packages that are required to build, run and -test Legate Core and all downstream libraries. Once you have this file, you can -install the required packages by creating a new conda environment: +test Legate Core and all downstream libraries. For example: ``` -conda env create -n legate -f .yaml -``` - -or by updating an existing environment: - -``` -conda env update -f .yaml +$ ./scripts/generate-conda-envs.py --python 3.10 --ctk 11.7 --os linux --compilers --openmpi +--- generating: environment-test-linux-py310-cuda-11.7-compilers-openmpi.yaml ``` -## Alternative sources for dependencies - -If you do not wish to use conda for some (or all) of the dependencies, you can -remove the corresponding entries from the environment file before passing it to -conda. See the `install.py` section below for instructions on how to provide -alternative locations for these dependencies to the build process. +Run this script with `-h` to see all available configuration options for the +generated environment file (e.g. all the supported Python versions). See the +[Notable Dependencies](#notable-dependencies) section for more details. -Note that this is likely to result in conflicts between conda-provided and -system-provided libraries. - -Conda distributes its own version of certain common libraries (in particular the -C++ standard library), which are also typically available system-wide. Any -system package you include will typically link to the system version, while -conda packages link to the conda version. Often these two different versions, -although incompatible, carry the same version number (`SONAME`), and are -therefore indistinguishable to the dynamic linker. Then, the first component to -specify a link location for this library will cause it to be loaded from there, -and any subsequent link requests for the same library, even if suggesting a -different link location, will get served using the previously linked version. - -This can cause link failures at runtime, e.g. when a system-level library -happens to be the first to load GLIBC, causing any conda library that comes -after to trip GLIBC's internal version checks, since the conda library expects -to find symbols with more recent version numbers than what is available on the -system-wide GLIBC: +Once you have this environment file, you can install the required packages by +creating a new conda environment: ``` -/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /opt/conda/envs/legate/lib/libarrow.so) +conda env create -n legate -f .yaml ``` -You can usually work around this issue by putting the conda library directory -first in the dynamic library resolution path: +or by updating an existing environment: ``` -LD_LIBRARY_PATH="$CONDA_PREFIX/lib:$LD_LIBRARY_PATH" +conda env update -f .yaml ``` -This way you can make sure that the (typically more recent) conda version of any -common library will be preferred over the system-wide one, no matter which -component requests it first. - ## Notable dependencies ### OS (`--os` option) @@ -154,6 +124,47 @@ Only necessary if you wish to run on multiple nodes. Not available on conda; typically available through MOFED or the system-level package manager. +## Alternative sources for dependencies + +If you do not wish to use conda for some (or all) of the dependencies, you can +remove the corresponding entries from the environment file before passing it to +conda. See [the `install.py` section](#using-installpy) for instructions on how +to provide alternative locations for these dependencies to the build process. + +Note that this is likely to result in conflicts between conda-provided and +system-provided libraries. + +Conda distributes its own version of certain common libraries (in particular the +C++ standard library), which are also typically available system-wide. Any +system package you include will typically link to the system version, while +conda packages link to the conda version. Often these two different versions, +although incompatible, carry the same version number (`SONAME`), and are +therefore indistinguishable to the dynamic linker. Then, the first component to +specify a link location for this library will cause it to be loaded from there, +and any subsequent link requests for the same library, even if suggesting a +different link location, will get served using the previously linked version. + +This can cause link failures at runtime, e.g. when a system-level library +happens to be the first to load GLIBC, causing any conda library that comes +after to trip GLIBC's internal version checks, since the conda library expects +to find symbols with more recent version numbers than what is available on the +system-wide GLIBC: + +``` +/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /opt/conda/envs/legate/lib/libarrow.so) +``` + +You can usually work around this issue by putting the conda library directory +first in the dynamic library resolution path: + +``` +LD_LIBRARY_PATH="$CONDA_PREFIX/lib:$LD_LIBRARY_PATH" +``` + +This way you can make sure that the (typically more recent) conda version of any +common library will be preferred over the system-wide one, no matter which +component requests it first. + # Building for Users ## Using install.py @@ -176,6 +187,13 @@ target using the `--with-cuda` and `--arch` flags, e.g.: ``` By default the script relies on CMake's auto-detection for these settings. +CMake will first search the currently active Python/conda environment +for dependencies, then any common system-wide installation directories (e.g. +`/usr/lib`). If a dependency cannot be found but is publicly available in source +form (e.g. OpenBLAS), cmake will fetch and build it automatically. You can +override this search by providing an install location for any dependency +explicitly, using a `--with-dep` flag, e.g. `--with-nccl` and +`--with-openblas`. For multi-node execution Legate uses [GASNet](https://gasnet.lbl.gov/) which can be requested using the `--network gasnet1` or `--network gasnetex` flag. By default @@ -195,14 +213,6 @@ Alternatively, here is an install line for the ./install.py --network gasnet1 --conduit aries --cuda --arch pascal ``` -In general, cmake will first search the currently active Python environment for -dependencies, then any common system-wide installation directories (e.g. -`/usr/lib`). If a dependency cannot be found but is publicly available in source -form (e.g. OpenBLAS), cmake will fetch and build it automatically. You can -override this search by providing an install location for any dependency -explicitly, using a `--with-dep` flag, e.g. `--with-nccl` and -`--with-openblas`. - To see all available configuration options, run with the `--help` flag: ``` From 45cf3254d8e19fc2b7e24ee7624ac6c43dd9d3fa Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 24 Oct 2022 10:47:23 -0700 Subject: [PATCH 22/24] Fix intra-document reference --- BUILD.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index 9097967042..40955b30ce 100644 --- a/BUILD.md +++ b/BUILD.md @@ -70,8 +70,9 @@ pulled from conda. If you need/prefer to use the system-provided compilers (typical for HPC installations), please use a conda environment generated with `--no-compilers`. -Note that this will likely result in a conda/system library conflict (as -explained above), since the system compilers will typically produce executables +Note that this will likely result in a +[conda/system library conflict](#alternative-sources-for-dependencies), +since the system compilers will typically produce executables that link against the system-provided libraries, which can shadow the conda-provided equivalents. From c8107222e518fed4ef4e7de2ec149847289763f5 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 24 Oct 2022 14:13:15 -0700 Subject: [PATCH 23/24] Revise file naming scheme --- scripts/generate-conda-envs.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/generate-conda-envs.py b/scripts/generate-conda-envs.py index 454e53eb2b..a5cd426ee5 100755 --- a/scripts/generate-conda-envs.py +++ b/scripts/generate-conda-envs.py @@ -68,7 +68,7 @@ def __str__(self) -> str: if self.ctk_version == "none": return "" - return f"-cuda-{self.ctk_version}" + return f"-cuda{self.ctk_version}" @dataclass(frozen=True) @@ -95,8 +95,8 @@ def conda(self) -> Reqs: return sorted(pkgs) def __str__(self) -> str: - val = "-compilers" if self.compilers else "-no-compilers" - val += "-openmpi" if self.openmpi else "-no-openmpi" + val = "-compilers" if self.compilers else "" + val += "-openmpi" if self.openmpi else "" return val @@ -202,8 +202,7 @@ def docs(self) -> DocsConfig: @property def filename(self) -> str: - python = f"py{self.python.replace('.', '')}" - return f"environment-{self.use}-{self.os}-{python}{self.cuda}{self.build}.yaml" # noqa + return f"environment-{self.use}-{self.os}-py{self.python}{self.cuda}{self.build}.yaml" # noqa # --- Setup ------------------------------------------------------------------- From 3bd3b53b575e55eb043ee31133ff9e5b77b723c9 Mon Sep 17 00:00:00 2001 From: Manolis Papadakis Date: Mon, 24 Oct 2022 15:54:11 -0700 Subject: [PATCH 24/24] Update BUILD.md --- BUILD.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/BUILD.md b/BUILD.md index 40955b30ce..5abb0af8df 100644 --- a/BUILD.md +++ b/BUILD.md @@ -15,6 +15,12 @@ limitations under the License. --> +# TL;DR + +1) Check if there are specialized scripts available for your cluster at https://github.com/nv-legate/quickstart. +2) [Install dependencies from conda](#getting-dependencies-through-conda) +3) [Build using install.py](#using-installpy) + # Getting dependencies ## Getting dependencies through conda @@ -118,6 +124,8 @@ specialized build, e.g. the one distributed by or one provided by your HPC vendor. In that case you should use an environment file generated with `--no-openmpi`. +Legate requires a build of MPI that supports `MPI_THREAD_MULTIPLE`. + ### Networking libraries (e.g. Infiniband, RoCE, UCX; optional) Only necessary if you wish to run on multiple nodes. @@ -125,6 +133,8 @@ Only necessary if you wish to run on multiple nodes. Not available on conda; typically available through MOFED or the system-level package manager. +If using UCX, a build configured with `--enable-mt` is required. + ## Alternative sources for dependencies If you do not wish to use conda for some (or all) of the dependencies, you can