From 5846fb6e83b54cb302d21e00b45de4b9aaa02993 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 4 May 2021 11:27:22 -0500 Subject: [PATCH 1/7] attempt at topping the setup pie --- setup.py | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/setup.py b/setup.py index 0ce77f32ea..d13cc3e96c 100644 --- a/setup.py +++ b/setup.py @@ -38,21 +38,10 @@ elif sys.platform in ["win32", "cygwin"]: IS_WIN = True else: - assert False, sys.platform + " not supported" + assert False, "We currently do not build for " + sys.platform -if IS_LIN: - DPCPP_ROOT = os.environ["ONEAPI_ROOT"] + r"/compiler/latest/linux" - os.environ["DPCTL_SYCL_INTERFACE_LIBDIR"] = "dpctl" - os.environ["DPCTL_SYCL_INTERFACE_INCLDIR"] = r"dpctl/include" - os.environ["CFLAGS"] = "-fPIC" - -elif IS_WIN: - os.environ["DPCTL_SYCL_INTERFACE_LIBDIR"] = "dpctl" - os.environ["DPCTL_SYCL_INTERFACE_INCLDIR"] = r"dpctl\include" - -dpctl_sycl_interface_lib = os.environ["DPCTL_SYCL_INTERFACE_LIBDIR"] -dpctl_sycl_interface_include = os.environ["DPCTL_SYCL_INTERFACE_INCLDIR"] -sycl_lib = os.environ["ONEAPI_ROOT"] + r"\compiler\latest\windows\lib" +dpctl_sycl_interface_lib = "dpctl" +dpctl_sycl_interface_include = r"dpctl/include" # Get long description with open("README.md", "r", encoding="utf-8") as file: @@ -131,12 +120,12 @@ def extensions(): elif IS_MAC: pass elif IS_WIN: - libs += ["DPCTLSyclInterface", "sycl"] + libs += ["DPCTLSyclInterface"] if IS_LIN: librarys = [dpctl_sycl_interface_lib] elif IS_WIN: - librarys = [dpctl_sycl_interface_lib, sycl_lib] + librarys = [dpctl_sycl_interface_lib] elif IS_MAC: librarys = [dpctl_sycl_interface_lib] From c47e1f95a1373046334d70ff832c61f4c7a1977c Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 4 May 2021 12:34:09 -0500 Subject: [PATCH 2/7] scripts/build_backend.py reorg The logic to build the backend is moved inside a function, allowing to pass argument controlling the build. Currently this is used to specify whether to use L0 support (hardcoded to True), but opens a door to specify custom compiler to use to build SyclInterface library. setup.py no longer uses subprocess to invoke build_backed, but uses importlib to import the function defined there and calls the function with appropriate arguments. scipts/build_backend.py retains the function of the script, calling the build_backend function with default arguments (no L0 support) --- scripts/build_backend.py | 245 +++++++++++++++++++++------------------ setup.py | 12 +- 2 files changed, 141 insertions(+), 116 deletions(-) diff --git a/scripts/build_backend.py b/scripts/build_backend.py index 3970c74ce4..9e809a01d7 100644 --- a/scripts/build_backend.py +++ b/scripts/build_backend.py @@ -18,129 +18,148 @@ """ -import glob -import os -import shutil -import subprocess -import sys - -IS_WIN = False -IS_LIN = False - -if "linux" in sys.platform: - IS_LIN = True -elif sys.platform in ["win32", "cygwin"]: - IS_WIN = True -else: - assert False, sys.platform + " not supported" - -ONEAPI_ROOT = os.environ.get("ONEAPI_ROOT") -CODE_COVERAGE = os.environ.get("CODE_COVERAGE") - -if IS_LIN: - DPCPP_ROOT = os.path.join(ONEAPI_ROOT, r"compiler/latest/linux") -if IS_WIN: - DPCPP_ROOT = os.path.join(ONEAPI_ROOT, r"compiler\latest\windows") - -dpctl_dir = os.getcwd() -build_cmake_dir = os.path.join(dpctl_dir, "build_cmake") -if os.path.exists(build_cmake_dir): - for f in os.listdir(build_cmake_dir): - f_path = os.path.join(build_cmake_dir, f) - if os.path.isdir(f_path): - if (f == "level-zero") and os.path.isdir( - os.path.join(f_path, ".git") - ): - # do not delete Git checkout of level zero headers - pass +def build_backend(l0_support=False): + import glob + import os + import shutil + import subprocess + import sys + + IS_WIN = False + IS_LIN = False + + if "linux" in sys.platform: + IS_LIN = True + elif sys.platform in ["win32", "cygwin"]: + IS_WIN = True + else: + assert False, sys.platform + " not supported" + + CODE_COVERAGE = os.environ.get("CODE_COVERAGE") + ONEAPI_ROOT = os.environ.get("ONEAPI_ROOT") + + if IS_LIN: + DPCPP_ROOT = os.path.join(ONEAPI_ROOT, r"compiler/latest/linux") + elif IS_WIN: + DPCPP_ROOT = os.path.join(ONEAPI_ROOT, r"compiler\latest\windows") + + dpctl_dir = os.getcwd() + build_cmake_dir = os.path.join(dpctl_dir, "build_cmake") + if os.path.exists(build_cmake_dir): + for f in os.listdir(build_cmake_dir): + f_path = os.path.join(build_cmake_dir, f) + if os.path.isdir(f_path): + if (f == "level-zero") and os.path.isdir( + os.path.join(f_path, ".git") + ): + # do not delete Git checkout of level zero headers + pass + else: + shutil.rmtree(f_path) else: - shutil.rmtree(f_path) - else: - os.remove(f_path) -else: - os.mkdir(build_cmake_dir) -os.chdir(build_cmake_dir) - -INSTALL_PREFIX = os.path.join(dpctl_dir, "install") -if os.path.exists(INSTALL_PREFIX): - shutil.rmtree(INSTALL_PREFIX) - -backends = os.path.join(dpctl_dir, "dpctl-capi") - -if IS_LIN: - if CODE_COVERAGE: - cmake_args = [ - "cmake", - "-DCMAKE_BUILD_TYPE=Debug", - "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, - "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, - "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, - "-DCMAKE_C_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "clang"), - "-DCMAKE_CXX_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "dpcpp"), - "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=ON", - "-DDPCTL_BUILD_CAPI_TESTS=ON", - "-DDPCTL_GENERATE_COVERAGE=ON", - "-DDPCTL_COVERAGE_REPORT_OUTPUT_DIR=" + dpctl_dir, - backends, - ] - subprocess.check_call(cmake_args, stderr=subprocess.STDOUT, shell=False) - subprocess.check_call(["make", "V=1", "-j", "4"]) - subprocess.check_call(["make", "install"]) - subprocess.check_call(["make", "lcov-genhtml"]) - + os.remove(f_path) else: + os.mkdir(build_cmake_dir) + os.chdir(build_cmake_dir) + + INSTALL_PREFIX = os.path.join(dpctl_dir, "install") + if os.path.exists(INSTALL_PREFIX): + shutil.rmtree(INSTALL_PREFIX) + + backends = os.path.join(dpctl_dir, "dpctl-capi") + + ENABLE_LO_PROGRAM_CREATION = "ON" if l0_support else "OFF" + + if IS_LIN: + if CODE_COVERAGE: + cmake_args = [ + "cmake", + "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, + "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, + "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, + "-DCMAKE_C_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang"), + "-DCMAKE_CXX_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "dpcpp"), + "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + + ENABLE_LO_PROGRAM_CREATION, + "-DDPCTL_BUILD_CAPI_TESTS=ON", + "-DDPCTL_GENERATE_COVERAGE=ON", + "-DDPCTL_COVERAGE_REPORT_OUTPUT_DIR=" + dpctl_dir, + backends, + ] + subprocess.check_call( + cmake_args, stderr=subprocess.STDOUT, shell=False + ) + subprocess.check_call(["make", "V=1", "-j", "4"]) + subprocess.check_call(["make", "install"]) + subprocess.check_call(["make", "lcov-genhtml"]) + else: + cmake_args = [ + "cmake", + "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, + "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, + "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, + "-DCMAKE_C_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang"), + "-DCMAKE_CXX_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "dpcpp"), + "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + + ENABLE_LO_PROGRAM_CREATION, + backends, + ] + subprocess.check_call( + cmake_args, stderr=subprocess.STDOUT, shell=False + ) + subprocess.check_call(["make", "V=1", "-j", "4"]) + subprocess.check_call(["make", "install"]) + + os.chdir(dpctl_dir) + for file in glob.glob( + os.path.join(dpctl_dir, "install", "lib", "*.so*") + ): + shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) + elif IS_WIN: cmake_args = [ "cmake", + "-G", + "Ninja", "-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, "-DCMAKE_C_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "clang"), + + os.path.join(DPCPP_ROOT, "bin", "clang-cl.exe"), "-DCMAKE_CXX_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "dpcpp"), - "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=ON", + + os.path.join(DPCPP_ROOT, "bin", "dpcpp.exe"), + "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + ENABLE_LO_PROGRAM_CREATION, backends, ] subprocess.check_call(cmake_args, stderr=subprocess.STDOUT, shell=False) - subprocess.check_call(["make", "V=1", "-j", "4"]) - subprocess.check_call(["make", "install"]) - - os.chdir(dpctl_dir) - for file in glob.glob(os.path.join(dpctl_dir, "install", "lib", "*.so*")): - shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) - -if IS_WIN: - cmake_args = [ - "cmake", - "-G", - "Ninja", - "-DCMAKE_BUILD_TYPE=Release", - "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, - "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, - "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, - "-DCMAKE_C_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "clang-cl.exe"), - "-DCMAKE_CXX_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "dpcpp.exe"), - "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=ON", - backends, - ] - subprocess.check_call(cmake_args, stderr=subprocess.STDOUT, shell=False) - subprocess.check_call(["ninja", "-n"]) - subprocess.check_call(["ninja", "install"]) - - os.chdir(dpctl_dir) - for file in glob.glob(os.path.join(dpctl_dir, "install", "lib", "*.lib")): - shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) - - for file in glob.glob(os.path.join(dpctl_dir, "install", "bin", "*.dll")): - shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) - -include_dir = os.path.join(dpctl_dir, "dpctl", "include") -if os.path.exists(include_dir): - shutil.rmtree(include_dir) - -shutil.copytree(os.path.join(dpctl_dir, "dpctl-capi", "include"), include_dir) + subprocess.check_call(["ninja", "-n"]) + subprocess.check_call(["ninja", "install"]) + + os.chdir(dpctl_dir) + for file in glob.glob( + os.path.join(dpctl_dir, "install", "lib", "*.lib") + ): + shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) + + for file in glob.glob( + os.path.join(dpctl_dir, "install", "bin", "*.dll") + ): + shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) + + include_dir = os.path.join(dpctl_dir, "dpctl", "include") + if os.path.exists(include_dir): + shutil.rmtree(include_dir) + + shutil.copytree( + os.path.join(dpctl_dir, "dpctl-capi", "include"), include_dir + ) + + +if __name__ == "__main__": + build_backend() diff --git a/setup.py b/setup.py index d13cc3e96c..4c220c3d1c 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ import os import os.path -import subprocess import sys import numpy as np @@ -103,8 +102,15 @@ def get_suppressed_warning_flags(): def build_backend(): - build_script = os.path.join(os.getcwd(), "scripts", "build_backend.py") - subprocess.check_call([sys.executable, build_script]) + import os.path + from importlib.util import module_from_spec, spec_from_file_location + + spec = spec_from_file_location( + "build_backend", os.path.join("scripts", "build_backend.py") + ) + builder_module = module_from_spec(spec) + spec.loader.exec_module(builder_module) + builder_module.build_backend(l0_support=True) def extensions(): From e44d1a532fcefb0d1f3330a7862d1918d8161b69 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Thu, 20 May 2021 13:55:27 -0500 Subject: [PATCH 3/7] Allow develop/install commands accept CLI options python setup.py develop ---help displays them, with use messaes Options are --level-zerop-support=(true|false) --coverage=(true|false) --sycl-compiler-path=(path to prefix, optional) If path is not provided backend builder looks up ONEAPI_ROOT variable. In the path, builder looks for bin/dpcpp (Linux), or bin/dpcpp.exe (Windows). If found, cmake does see -DDPCTL_DPCPP_ROOT variable set. Otherwise the variable is set, and clang++ is used instead of dpcpp --- scripts/build_backend.py | 137 +++++++++++++++++++++++------------- setup.py | 146 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 225 insertions(+), 58 deletions(-) diff --git a/scripts/build_backend.py b/scripts/build_backend.py index 9e809a01d7..a12b851be4 100644 --- a/scripts/build_backend.py +++ b/scripts/build_backend.py @@ -18,7 +18,9 @@ """ -def build_backend(l0_support=False): +def build_backend( + l0_support=False, code_coverage=False, sycl_compiler_prefix=None +): import glob import os import shutil @@ -35,13 +37,19 @@ def build_backend(l0_support=False): else: assert False, sys.platform + " not supported" - CODE_COVERAGE = os.environ.get("CODE_COVERAGE") - ONEAPI_ROOT = os.environ.get("ONEAPI_ROOT") + if sycl_compiler_prefix is None: + oneapi_root = os.getenv("ONEAPI_ROOT") + if IS_LIN: + DPCPP_ROOT = os.path.join(oneapi_root, r"compiler/latest/linux") + elif IS_WIN: + DPCPP_ROOT = os.path.join(oneapi_root, r"compiler\latest\windows") + else: + DPCPP_ROOT = os.path.join(sycl_compiler_prefix) - if IS_LIN: - DPCPP_ROOT = os.path.join(ONEAPI_ROOT, r"compiler/latest/linux") - elif IS_WIN: - DPCPP_ROOT = os.path.join(ONEAPI_ROOT, r"compiler\latest\windows") + if not os.path.isdir(DPCPP_ROOT): + raise ValueError( + "SYCL compile prefix {} is not a directry".format(DPCPP_ROOT) + ) dpctl_dir = os.getcwd() build_cmake_dir = os.path.join(dpctl_dir, "build_cmake") @@ -71,24 +79,39 @@ def build_backend(l0_support=False): ENABLE_LO_PROGRAM_CREATION = "ON" if l0_support else "OFF" if IS_LIN: - if CODE_COVERAGE: - cmake_args = [ - "cmake", - "-DCMAKE_BUILD_TYPE=Debug", - "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, - "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, - "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, + if os.path.exists(os.path.join(DPCPP_ROOT, "bin", "dpcpp")): + cmake_compiler_args = [ "-DCMAKE_C_COMPILER:PATH=" + os.path.join(DPCPP_ROOT, "bin", "clang"), "-DCMAKE_CXX_COMPILER:PATH=" + os.path.join(DPCPP_ROOT, "bin", "dpcpp"), - "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" - + ENABLE_LO_PROGRAM_CREATION, - "-DDPCTL_BUILD_CAPI_TESTS=ON", - "-DDPCTL_GENERATE_COVERAGE=ON", - "-DDPCTL_COVERAGE_REPORT_OUTPUT_DIR=" + dpctl_dir, - backends, ] + else: + cmake_compiler_args = [ + "-DDPCTL_CUSTOM_DPCPP_INSTALL_DIR=" + DPCPP_ROOT, + "-DCMAKE_C_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang"), + "-DCMAKE_CXX_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang++"), + ] + if code_coverage: + cmake_args = ( + [ + "cmake", + "-DCMAKE_BUILD_TYPE=Debug", + "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, + "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, + ] + + cmake_compiler_args + + [ + "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + + ENABLE_LO_PROGRAM_CREATION, + "-DDPCTL_BUILD_CAPI_TESTS=ON", + "-DDPCTL_GENERATE_COVERAGE=ON", + "-DDPCTL_COVERAGE_REPORT_OUTPUT_DIR=" + dpctl_dir, + backends, + ] + ) subprocess.check_call( cmake_args, stderr=subprocess.STDOUT, shell=False ) @@ -96,20 +119,20 @@ def build_backend(l0_support=False): subprocess.check_call(["make", "install"]) subprocess.check_call(["make", "lcov-genhtml"]) else: - cmake_args = [ - "cmake", - "-DCMAKE_BUILD_TYPE=Release", - "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, - "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, - "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, - "-DCMAKE_C_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "clang"), - "-DCMAKE_CXX_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "dpcpp"), - "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" - + ENABLE_LO_PROGRAM_CREATION, - backends, - ] + cmake_args = ( + [ + "cmake", + "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, + "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, + ] + + cmake_compiler_args + + [ + "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + + ENABLE_LO_PROGRAM_CREATION, + backends, + ] + ) subprocess.check_call( cmake_args, stderr=subprocess.STDOUT, shell=False ) @@ -122,21 +145,37 @@ def build_backend(l0_support=False): ): shutil.copy(file, os.path.join(dpctl_dir, "dpctl")) elif IS_WIN: - cmake_args = [ - "cmake", - "-G", - "Ninja", - "-DCMAKE_BUILD_TYPE=Release", - "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, - "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, - "-DDPCPP_INSTALL_DIR=" + DPCPP_ROOT, - "-DCMAKE_C_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "clang-cl.exe"), - "-DCMAKE_CXX_COMPILER:PATH=" - + os.path.join(DPCPP_ROOT, "bin", "dpcpp.exe"), - "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + ENABLE_LO_PROGRAM_CREATION, - backends, - ] + if os.path.exists(os.path.join(DPCPP_ROOT, "bin", "dpcpp.exe")): + cmake_compiler_args = [ + "-DCMAKE_C_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang-cl.exe"), + "-DCMAKE_CXX_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "dpcpp.exe"), + ] + else: + cmake_compiler_args = [ + "-DDPCTL_CUSTOM_DPCPP_INSTALL_DIR=" + DPCPP_ROOT, + "-DCMAKE_C_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang-cl.exe"), + "-DCMAKE_CXX_COMPILER:PATH=" + + os.path.join(DPCPP_ROOT, "bin", "clang++.exe"), + ] + cmake_args = ( + [ + "cmake", + "-G", + "Ninja", + "-DCMAKE_BUILD_TYPE=Release", + "-DCMAKE_INSTALL_PREFIX=" + INSTALL_PREFIX, + "-DCMAKE_PREFIX_PATH=" + INSTALL_PREFIX, + ] + + cmake_compiler_args + + [ + "-DDPCTL_ENABLE_LO_PROGRAM_CREATION=" + + ENABLE_LO_PROGRAM_CREATION, + backends, + ] + ) subprocess.check_call(cmake_args, stderr=subprocess.STDOUT, shell=False) subprocess.check_call(["ninja", "-n"]) subprocess.check_call(["ninja", "install"]) diff --git a/setup.py b/setup.py index 4c220c3d1c..e30640c25b 100644 --- a/setup.py +++ b/setup.py @@ -101,7 +101,7 @@ def get_suppressed_warning_flags(): return [] -def build_backend(): +def build_backend(l0_support, coverage, sycl_compiler_prefix): import os.path from importlib.util import module_from_spec, spec_from_file_location @@ -110,7 +110,11 @@ def build_backend(): ) builder_module = module_from_spec(spec) spec.loader.exec_module(builder_module) - builder_module.build_backend(l0_support=True) + builder_module.build_backend( + l0_support=l0_support, + code_coverage=coverage, + sycl_compiler_prefix=sycl_compiler_prefix, + ) def extensions(): @@ -118,7 +122,7 @@ def extensions(): eca = get_sdl_cflags() ela = get_sdl_ldflags() libs = [] - librarys = [] + libraries = [] CODE_COVERAGE = os.environ.get("CODE_COVERAGE") if IS_LIN: @@ -129,11 +133,11 @@ def extensions(): libs += ["DPCTLSyclInterface"] if IS_LIN: - librarys = [dpctl_sycl_interface_lib] + libraries = [dpctl_sycl_interface_lib] elif IS_WIN: - librarys = [dpctl_sycl_interface_lib] + libraries = [dpctl_sycl_interface_lib] elif IS_MAC: - librarys = [dpctl_sycl_interface_lib] + libraries = [dpctl_sycl_interface_lib] if IS_LIN or IS_MAC: runtime_library_dirs = ["$ORIGIN"] @@ -150,7 +154,7 @@ def extensions(): ), "extra_link_args": ela, "libraries": libs, - "library_dirs": librarys, + "library_dirs": libraries, "runtime_library_dirs": runtime_library_dirs, "language": "c++", "define_macros": [], @@ -261,14 +265,138 @@ def extensions(): class install(orig_install.install): + description = "Installs dpctl into Python prefix" + user_options = orig_install.install.user_options + [ + ( + "level-zero-support=", + None, + "Whether to enable support for program creation " + "for Level-zero backend", + ), + ( + "sycl-compiler-prefix=", + None, + "Path to SYCL compiler installation. None means " + "read it off ONEAPI_ROOT environment variable or fail.", + ), + ( + "coverage=", + None, + "Whether to generate coverage report " + "when building the backend library", + ), + ] + + def initialize_options(self): + super().initialize_options() + self.level_zero_support = "True" + self.coverage = os.getenv("CODE_COVERAGE", "False") + self.sycl_compiler_prefix = None + + def finalize_options(self): + if isinstance(self.level_zero_support, str): + self.level_zero_support = self.level_zero_support.capitalize() + if self.level_zero_support in ["True", "False", "0", "1"]: + self.level_zero_support = bool(eval(self.level_zero_support)) + else: + raise ValueError( + "--level-zero-support value is invalid, use True/False" + ) + if isinstance(self.coverage, str): + self.coverage = self.coverage.capitalize() + if self.coverage in ["True", "False", "0", "1"]: + self.coverage = bool(eval(self.coverage)) + else: + raise ValueError("--coverage value is invalid, use True/False") + if isinstance(self.sycl_compiler_prefix, str): + if not os.path.exists(os.path.join(self.sycl_compiler_prefix)): + raise ValueError( + "--sycl-compiler-prefix expects a path " + "to an existing directory" + ) + elif self.sycl_compiler_prefix is None: + pass + else: + raise ValueError( + "--sycl-compiler-prefix value is invalid, use a " + "path to compiler intallation. To use oneAPI, use the " + "default value, but remember to activate the compiler " + "environment" + ) + super().finalize_options() + def run(self): - build_backend() + build_backend( + self.level_zero_support, self.coverage, self.sycl_compiler_prefix + ) return super().run() class develop(orig_develop.develop): + description = "Installs dpctl in place" + user_options = orig_develop.develop.user_options + [ + ( + "level-zero-support=", + None, + "Whether to enable support for program creation " + "for Level-zero backend", + ), + ( + "sycl-compiler-prefix=", + None, + "Path to SYCL compiler installation. None means " + "read it off ONEAPI_ROOT environment variable or fail.", + ), + ( + "coverage=", + None, + "Whether to generate coverage report " + "when building the backend library", + ), + ] + + def initialize_options(self): + super().initialize_options() + self.level_zero_support = "True" + self.coverage = os.getenv("CODE_COVERAGE", "False") + self.sycl_compiler_prefix = None + + def finalize_options(self): + if isinstance(self.level_zero_support, str): + self.level_zero_support = self.level_zero_support.capitalize() + if self.level_zero_support in ["True", "False", "0", "1"]: + self.level_zero_support = bool(eval(self.level_zero_support)) + else: + raise ValueError( + "--level-zero-support value is invalid, use True/False" + ) + if isinstance(self.coverage, str): + self.coverage = self.coverage.capitalize() + if self.coverage in ["True", "False", "0", "1"]: + self.coverage = bool(eval(self.coverage)) + else: + raise ValueError("--coverage value is invalid, use True/False") + if isinstance(self.sycl_compiler_prefix, str): + if not os.path.exists(os.path.join(self.sycl_compiler_prefix)): + raise ValueError( + "--sycl-compiler-prefix expects a path " + "to an existing directory" + ) + elif self.sycl_compiler_prefix is None: + pass + else: + raise ValueError( + "--sycl-compiler-prefix value is invalid, use a " + "path to compiler intallation. To use oneAPI, use the " + "default value, but remember to activate the compiler " + "environment" + ) + super().finalize_options() + def run(self): - build_backend() + build_backend( + self.level_zero_support, self.coverage, self.sycl_compiler_prefix + ) return super().run() From d6aef7dbc40b583d41a172bce0daa44bce43ef97 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 21 May 2021 08:19:53 -0500 Subject: [PATCH 4/7] Filled in section for building with custom DPC++ --- docs/docfiles/user_guides/QuickStart.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/docfiles/user_guides/QuickStart.rst b/docs/docfiles/user_guides/QuickStart.rst index 736ec7e8ae..1415475dc8 100644 --- a/docs/docfiles/user_guides/QuickStart.rst +++ b/docs/docfiles/user_guides/QuickStart.rst @@ -165,9 +165,19 @@ to build and install Building using custom dpcpp ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. todo:: +It is possible to build dpctl from source using .. _DPC++ toolchain: https://github.com/intel/llvm/blob/sycl/sycl/doc/GetStartedGuide.md +instead of the DPC++ compiler that comes with oneAPI. One reason for doing this +may be to enable support for CUDA devices. - Instructions coming soon. +Following steps in :ref:`Build and Install with setuptools` use command line +option :code:`--sycl-compiler-prefix`, for example: + +.. code-block:: bash + + python setup.py develop --sycl-compiler-prefix=${DPCPP_ROOT}/llvm/build + +Available options and their descriptions can be retrieved using option +:code:`--help`. Using dpctl ----------- From f94f451124e5720c6c8cd97d9962fba0fa46c647 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 21 May 2021 08:25:44 -0500 Subject: [PATCH 5/7] Added details about building with custom DPC++ toolchain --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ac649349e8..127b34ec27 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,14 @@ For development: python setup.py develop ``` +It is also possible to build dpctl using [DPC++ toolchain](https://github.com/intel/llvm/blob/sycl/sycl/doc/GetStartedGuide.md) instead of oneAPI DPC++. Instead of activating the oneAPI environment, indicate the toolchain installation prefix with `--sycl-compiler-prefix` option, e.g. + +```cmd +python setup.py develop --sycl-compiler-prefix=${DPCPP_ROOT}/llvm/build +``` + +Please use `python setup.py develop --help` for more details. + Install Wheel Package from Pypi ================================== 1. Install dpctl From aadb0cae93967173576f72fd92df2677be74f0ba Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 21 May 2021 12:25:45 -0500 Subject: [PATCH 6/7] Removed use of CODE_COVERAGE environment variable CODE_COVERAGE was used to influence whether the backend SyclInterface library was built in debug mode with coverage over dpctp-capi/ test suite collected or not. It was also influencing how Cython extensions were built. It would pass linetrace=true option to cythonize, and define CYTHON_TRACE preprocessor variable when compiling Cython-generated C++ source files with compiler. This change removes use CODE_COVERAGE all together. Instead: 1. Custom setuptools command 'build_ext' is implemented which auto-adds 'CYTHON_TRACE' to the list of defines received by downstream build_ext command if develop command received --coverage=True cythonize call was removed from extensions() function, allowing ``python setup.py develop --help` execute cleanly without running cythonize. Consequentially, linetrace Cython directive will need to be added to each .pyx file in a separate commit. This is safe to do per https://cython.readthedocs.io/en/latest/src/tutorial/profiling_tutorial.html#enabling-line-tracing since it is a no-op unless CYTHON_TRACE preprocessor variable is also set, which is only done when --coverage=True is used 2. install setuptools command removed support for `--coverage` option, and always builds backend without coverage. This is to avoid inadvertent installation of debug build of library in Python prefix. --- setup.py | 65 ++++++++++++++++++++++++-------------------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/setup.py b/setup.py index e30640c25b..cf7c7a4c19 100644 --- a/setup.py +++ b/setup.py @@ -19,9 +19,9 @@ import sys import numpy as np +import setuptools.command.build_ext as orig_build_ext import setuptools.command.develop as orig_develop import setuptools.command.install as orig_install -from Cython.Build import cythonize from setuptools import Extension, find_packages, setup import versioneer @@ -39,6 +39,9 @@ else: assert False, "We currently do not build for " + sys.platform +# global variable used to pass value of --coverage option of develop command +# to build_ext command +_coverage = False dpctl_sycl_interface_lib = "dpctl" dpctl_sycl_interface_include = r"dpctl/include" @@ -123,7 +126,6 @@ def extensions(): ela = get_sdl_ldflags() libs = [] libraries = [] - CODE_COVERAGE = os.environ.get("CODE_COVERAGE") if IS_LIN: libs += ["rt", "DPCTLSyclInterface"] @@ -160,15 +162,6 @@ def extensions(): "define_macros": [], } - if CODE_COVERAGE: - extension_args.update( - { - "define_macros": [ - ("CYTHON_TRACE", "1"), - ] - } - ) - extensions = [ Extension( "dpctl._sycl_context", @@ -253,15 +246,25 @@ def extensions(): define_macros=extension_args["define_macros"], ), ] - if CODE_COVERAGE: - exts = cythonize( - extensions, - compiler_directives={"linetrace": True}, - language_level=3, - ) - else: - exts = cythonize(extensions, language_level=3) - return exts + # ext = cythonize(extensions, language_level=3) + return extensions + + +class build_ext(orig_build_ext.build_ext): + description = "Build dpctl native extensions" + + def finalize_options(self): + global _coverage + if _coverage: + pre_d = getattr(self, "define", None) + if pre_d is None: + self.define = "CYTHON_TRACE" + else: + self.define = ",".join((pre_d, "CYTHON_TRACE")) + super().finalize_options() + + def run(self): + return super().run() class install(orig_install.install): @@ -279,18 +282,11 @@ class install(orig_install.install): "Path to SYCL compiler installation. None means " "read it off ONEAPI_ROOT environment variable or fail.", ), - ( - "coverage=", - None, - "Whether to generate coverage report " - "when building the backend library", - ), ] def initialize_options(self): super().initialize_options() self.level_zero_support = "True" - self.coverage = os.getenv("CODE_COVERAGE", "False") self.sycl_compiler_prefix = None def finalize_options(self): @@ -302,12 +298,6 @@ def finalize_options(self): raise ValueError( "--level-zero-support value is invalid, use True/False" ) - if isinstance(self.coverage, str): - self.coverage = self.coverage.capitalize() - if self.coverage in ["True", "False", "0", "1"]: - self.coverage = bool(eval(self.coverage)) - else: - raise ValueError("--coverage value is invalid, use True/False") if isinstance(self.sycl_compiler_prefix, str): if not os.path.exists(os.path.join(self.sycl_compiler_prefix)): raise ValueError( @@ -326,9 +316,7 @@ def finalize_options(self): super().finalize_options() def run(self): - build_backend( - self.level_zero_support, self.coverage, self.sycl_compiler_prefix - ) + build_backend(self.level_zero_support, False, self.sycl_compiler_prefix) return super().run() @@ -358,7 +346,7 @@ class develop(orig_develop.develop): def initialize_options(self): super().initialize_options() self.level_zero_support = "True" - self.coverage = os.getenv("CODE_COVERAGE", "False") + self.coverage = "False" self.sycl_compiler_prefix = None def finalize_options(self): @@ -374,6 +362,8 @@ def finalize_options(self): self.coverage = self.coverage.capitalize() if self.coverage in ["True", "False", "0", "1"]: self.coverage = bool(eval(self.coverage)) + global _coverage + _coverage = self.coverage else: raise ValueError("--coverage value is invalid, use True/False") if isinstance(self.sycl_compiler_prefix, str): @@ -404,6 +394,7 @@ def _get_cmdclass(): cmdclass = versioneer.get_cmdclass() cmdclass["install"] = install cmdclass["develop"] = develop + cmdclass["build_ext"] = build_ext return cmdclass From d768dbdbe92a060f00c8748f82f0f9a1a63ae9a9 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Fri, 21 May 2021 12:38:31 -0500 Subject: [PATCH 7/7] Added linetrace=true Cython directive to all .pyx files This is safe to do per https://cython.readthedocs.io/en/latest/src/tutorial/profiling_tutorial.html#enabling-line-tracing Its use allows improved coverage testing of Cython modules when Cython sources are compiled with CYTHON_TRACE/CYTHON_TRACE_NOGIL preprocessor variables defined. --- dpctl/_sycl_context.pyx | 1 + dpctl/_sycl_device.pyx | 1 + dpctl/_sycl_device_factory.pyx | 1 + dpctl/_sycl_event.pyx | 1 + dpctl/_sycl_platform.pyx | 1 + dpctl/_sycl_queue.pyx | 1 + dpctl/_sycl_queue_manager.pyx | 1 + dpctl/memory/_memory.pyx | 1 + dpctl/program/_program.pyx | 1 + dpctl/tensor/_usmarray.pyx | 1 + 10 files changed, 10 insertions(+) diff --git a/dpctl/_sycl_context.pyx b/dpctl/_sycl_context.pyx index 368807bde1..85a1c2f8ab 100644 --- a/dpctl/_sycl_context.pyx +++ b/dpctl/_sycl_context.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """ Implements SyclContext Cython extension type. """ diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index 67319f4a20..5f5f0cbe35 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """ Implements SyclDevice Cython extension type. """ diff --git a/dpctl/_sycl_device_factory.pyx b/dpctl/_sycl_device_factory.pyx index 6081b8791d..5ef67075b0 100644 --- a/dpctl/_sycl_device_factory.pyx +++ b/dpctl/_sycl_device_factory.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """ This module implements several device creation helper functions: diff --git a/dpctl/_sycl_event.pyx b/dpctl/_sycl_event.pyx index d0a062fbc3..807451223f 100644 --- a/dpctl/_sycl_event.pyx +++ b/dpctl/_sycl_event.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """ Implements SyclEvent Cython extension type. """ diff --git a/dpctl/_sycl_platform.pyx b/dpctl/_sycl_platform.pyx index d96f9dd430..dcbd6485f2 100644 --- a/dpctl/_sycl_platform.pyx +++ b/dpctl/_sycl_platform.pyx @@ -16,6 +16,7 @@ # # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """ Implements SyclPlatform Cython extension type. """ diff --git a/dpctl/_sycl_queue.pyx b/dpctl/_sycl_queue.pyx index a0b3f5c347..41aec11772 100644 --- a/dpctl/_sycl_queue.pyx +++ b/dpctl/_sycl_queue.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """ Implements SyclQueue Cython extension type. """ diff --git a/dpctl/_sycl_queue_manager.pyx b/dpctl/_sycl_queue_manager.pyx index 928dd68817..da5ca1d7fb 100644 --- a/dpctl/_sycl_queue_manager.pyx +++ b/dpctl/_sycl_queue_manager.pyx @@ -16,6 +16,7 @@ # # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True from __future__ import print_function diff --git a/dpctl/memory/_memory.pyx b/dpctl/memory/_memory.pyx index bcf2bdbb57..e034084511 100644 --- a/dpctl/memory/_memory.pyx +++ b/dpctl/memory/_memory.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """This file implements Python buffer protocol using Sycl USM shared and host allocators. The USM device allocator is also exposed through this module for diff --git a/dpctl/program/_program.pyx b/dpctl/program/_program.pyx index 9b5601554f..923deef367 100644 --- a/dpctl/program/_program.pyx +++ b/dpctl/program/_program.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True """Implements a Python interface for SYCL's program and kernel runtime classes. diff --git a/dpctl/tensor/_usmarray.pyx b/dpctl/tensor/_usmarray.pyx index 442543c947..e076ffc5fa 100644 --- a/dpctl/tensor/_usmarray.pyx +++ b/dpctl/tensor/_usmarray.pyx @@ -16,6 +16,7 @@ # distutils: language = c++ # cython: language_level=3 +# cython: linetrace=True import numpy as np