From f6ddac372097f9011cd6841ea39e14187612f7b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Thu, 20 May 2021 14:52:25 +0200 Subject: [PATCH 1/7] Add AOMP EasyBlock support This PR adds an AOMP EasyBlock to better pick `CUDA` support. --- easybuild/easyblocks/a/aomp.py | 98 ++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 easybuild/easyblocks/a/aomp.py diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py new file mode 100644 index 0000000000..69ac6e4073 --- /dev/null +++ b/easybuild/easyblocks/a/aomp.py @@ -0,0 +1,98 @@ +""" +Support for building and installing AOMP - AMD OpenMP compiler, implemented as +an EasyBlock + +@author: Jørgen Nordmoen (University Center for Information Technology - UiO) +""" + +from easybuild.easyblocks.generic.binary import Binary +from easybuild.framework.easyconfig import CUSTOM +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.config import build_option +from easybuild.tools.modules import get_software_root +from easybuild.tools.systemtools import X86_64, get_cpu_architecture + +AOMP_ALL_COMPONENTS = ['roct', 'rocr', 'project', 'libdevice', 'openmp', + 'extras', 'pgmath', 'flang', 'flang_runtime', 'comgr', + 'rocminfo', 'vdi', 'hipvdi', 'ocl', 'rocdbgapi', + 'rocgdb', 'roctracer', 'rocprofiler'] +AOMP_DEFAULT_COMPONENTS = ['roct', 'rocr', 'project', 'libdevice', 'openmp', + 'extras', 'pgmath', 'flang', 'flang_runtime', + 'comgr', 'rocminfo'] +AOMP_X86_COMPONENTS = ['vdi', 'hipvdi', 'ocl'] +AOMP_DBG_COMPONENTS = ['rocdbgapi', 'rocgdb'] +AOMP_PROF_COMPONENTS = ['roctracer', 'rocprofiler'] + + +class EB_AOMP(Binary): + """Support for installing AOMP""" + + @staticmethod + def extra_options(): + extra_vars = Binary.extra_options() + extra_vars.update({ + 'components': [None, "AOMP components to build. Possible components: " + + ', '.join(AOMP_ALL_COMPONENTS), CUSTOM], + 'cuda_compute_capabilities': [[], "List of CUDA compute capabilities to build with", CUSTOM], + }) + return extra_vars + + def __init__(self, *args, **kwargs): + """Initialize custom class variables for Clang.""" + super(EB_AOMP, self).__init__(*args, **kwargs) + self.cfg['extract_sources'] = True + self.cfg['dontcreateinstalldir'] = True + + def configure_step(self): + """Configure AOMP build and let 'Binary' install""" + # Setup install command + self.cfg['install_cmd'] = './aomp/bin/build_aomp.sh' + # Setup 'preinstallopts' + version_major = self.version.split('.')[0] + install_options = [ + f'AOMP={self.installdir}', + f'AOMP_REPOS="{self.builddir}/aomp{version_major}"', + f'AOMP_CMAKE={get_software_root("CMake")}/bin/cmake', + 'AOMP_CHECK_GIT_BRANCH=0', + 'AOMP_APPLY_ROCM_PATCHES=0', + 'AOMP_STANDALONE_BUILD=1', + ] + if self.cfg['parallel']: + install_options.append(f'NUM_THREADS={self.cfg["parallel"]}') + else: + install_options.append('NUM_THREADS=1') + # Check if CUDA is loaded and alternatively build CUDA backend + if get_software_root('CUDA') or get_software_root('CUDAcore'): + cuda_root = get_software_root('CUDA') or get_software_root('CUDAcore') + install_options.append('AOMP_BUILD_CUDA=1') + install_options.append(f'CUDA="{cuda_root}"') + # Use the commandline / easybuild config option if given, else use + # the value from the EC (as a default) + cuda_cc = build_option('cuda_compute_capabilities') + cuda_cc = cuda_cc or self.cfg['cuda_compute_capabilities'] + if not cuda_cc: + raise EasyBuildError("CUDA module was loaded, " + "indicating a build with CUDA, " + "but no CUDA compute capability " + "was specified!") + # Convert '7.0' to '70' format + cuda_cc = [cc.replace('.', '') for cc in cuda_cc] + install_options.append(f'NVPTXGPUS="{",".join(cuda_cc)}"') + else: + # Explicitly disable CUDA + install_options.append('AOMP_BUILD_CUDA=0') + # Combine install instructions above into 'preinstallopts' + self.cfg['preinstallopts'] = ' '.join(install_options) + # Setup components for install + components = self.cfg.get('components', None) + # If no components were defined we use the default + if not components: + components = AOMP_DEFAULT_COMPONENTS + # NOTE: The following has not been tested properly and is therefore + # removed + # + # Add X86 components if correct architecture + # if get_cpu_architecture() == X86_64: + # components.extend(AOMP_X86_COMPONENTS) + # Only build selected components + self.cfg['installopts'] = 'select ' + ' '.join(components) From 2b4e41e09e2a701619476a43f4b7a82404973495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Thu, 20 May 2021 15:06:39 +0200 Subject: [PATCH 2/7] Fixed lint errors --- easybuild/easyblocks/a/aomp.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py index 69ac6e4073..d1733a461e 100644 --- a/easybuild/easyblocks/a/aomp.py +++ b/easybuild/easyblocks/a/aomp.py @@ -10,7 +10,6 @@ from easybuild.tools.build_log import EasyBuildError from easybuild.tools.config import build_option from easybuild.tools.modules import get_software_root -from easybuild.tools.systemtools import X86_64, get_cpu_architecture AOMP_ALL_COMPONENTS = ['roct', 'rocr', 'project', 'libdevice', 'openmp', 'extras', 'pgmath', 'flang', 'flang_runtime', 'comgr', @@ -93,6 +92,6 @@ def configure_step(self): # # Add X86 components if correct architecture # if get_cpu_architecture() == X86_64: - # components.extend(AOMP_X86_COMPONENTS) + # components.extend(AOMP_X86_COMPONENTS) # Only build selected components self.cfg['installopts'] = 'select ' + ' '.join(components) From e3404e3e7e5318076778c8b2b19e75e37d5e08dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Thu, 20 May 2021 15:20:05 +0200 Subject: [PATCH 3/7] Removed non-ASCII character from name --- easybuild/easyblocks/a/aomp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py index d1733a461e..3328e907df 100644 --- a/easybuild/easyblocks/a/aomp.py +++ b/easybuild/easyblocks/a/aomp.py @@ -2,7 +2,7 @@ Support for building and installing AOMP - AMD OpenMP compiler, implemented as an EasyBlock -@author: Jørgen Nordmoen (University Center for Information Technology - UiO) +@author: Jorgen Nordmoen (University Center for Information Technology - UiO) """ from easybuild.easyblocks.generic.binary import Binary From 4bab973750d7ead69d11d786999be7320de70c74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Thu, 20 May 2021 15:51:23 +0200 Subject: [PATCH 4/7] Move from f-strings to format --- easybuild/easyblocks/a/aomp.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py index 3328e907df..1365e9638a 100644 --- a/easybuild/easyblocks/a/aomp.py +++ b/easybuild/easyblocks/a/aomp.py @@ -49,22 +49,23 @@ def configure_step(self): # Setup 'preinstallopts' version_major = self.version.split('.')[0] install_options = [ - f'AOMP={self.installdir}', - f'AOMP_REPOS="{self.builddir}/aomp{version_major}"', - f'AOMP_CMAKE={get_software_root("CMake")}/bin/cmake', + 'AOMP={!s}'.format(self.installdir), + 'AOMP_REPOS="{!s}/aomp{!s}"'.format(self.builddir, version_major), + 'AOMP_CMAKE={!s}/bin/cmake'.format(get_software_root('CMake')), 'AOMP_CHECK_GIT_BRANCH=0', 'AOMP_APPLY_ROCM_PATCHES=0', 'AOMP_STANDALONE_BUILD=1', ] if self.cfg['parallel']: - install_options.append(f'NUM_THREADS={self.cfg["parallel"]}') + install_options.append( + 'NUM_THREADS={!s}'.format(self.cfg['parallel'])) else: install_options.append('NUM_THREADS=1') # Check if CUDA is loaded and alternatively build CUDA backend if get_software_root('CUDA') or get_software_root('CUDAcore'): cuda_root = get_software_root('CUDA') or get_software_root('CUDAcore') install_options.append('AOMP_BUILD_CUDA=1') - install_options.append(f'CUDA="{cuda_root}"') + install_options.append('CUDA="{!s}"'.format(cuda_root)) # Use the commandline / easybuild config option if given, else use # the value from the EC (as a default) cuda_cc = build_option('cuda_compute_capabilities') @@ -76,7 +77,8 @@ def configure_step(self): "was specified!") # Convert '7.0' to '70' format cuda_cc = [cc.replace('.', '') for cc in cuda_cc] - install_options.append(f'NVPTXGPUS="{",".join(cuda_cc)}"') + cuda_str = ",".join(cuda_cc) + install_options.append('NVPTXGPUS="{!s}"'.format(cuda_str)) else: # Explicitly disable CUDA install_options.append('AOMP_BUILD_CUDA=0') From 4b16eaeef0aa770def4bb44575cf8f1a6f7f9329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Fri, 21 May 2021 11:32:03 +0200 Subject: [PATCH 5/7] Added post install step to move symlink The AOMP build creates a symlink setup so that multiple installations can exist side-by-side. This is not needed by EasyBuild and is even making it difficult to remove and reinstall. To fix this, this commit adds a post install step which makes it the way EB expects. --- easybuild/easyblocks/a/aomp.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py index 1365e9638a..ba899b7aa2 100644 --- a/easybuild/easyblocks/a/aomp.py +++ b/easybuild/easyblocks/a/aomp.py @@ -10,6 +10,8 @@ from easybuild.tools.build_log import EasyBuildError from easybuild.tools.config import build_option from easybuild.tools.modules import get_software_root +import os +import os.path AOMP_ALL_COMPONENTS = ['roct', 'rocr', 'project', 'libdevice', 'openmp', 'extras', 'pgmath', 'flang', 'flang_runtime', 'comgr', @@ -97,3 +99,29 @@ def configure_step(self): # components.extend(AOMP_X86_COMPONENTS) # Only build selected components self.cfg['installopts'] = 'select ' + ' '.join(components) + + def post_install_step(self): + super(EB_AOMP, self).post_install_step() + # The install script will create a symbolic link as the install + # directory, this creates problems for EB as it won't remove the + # symlink. To remedy this we remove the link here and rename the actual + # install directory created by the AOMP install script + if os.path.islink(self.installdir): + os.unlink(self.installdir) + else: + err_str = "Expected '{!s}' to be a symbolic link" \ + " that needed to be removed, but it wasn't!" + raise EasyBuildError(err_str.format(self.installdir)) + # Move the actual directory containing the install + install_name = '{!s}_{!s}'.format(os.path.basename(self.installdir), + self.version) + actual_install = os.path.join(os.path.dirname(self.installdir), + install_name) + if os.path.exists(actual_install) and os.path.isdir(actual_install): + os.rename(actual_install, self.installdir) + else: + err_str = "Tried to move '{!s}' to '{!s}', " \ + " but it either doesn't exist" \ + " or isn't a directory!" + raise EasyBuildError(err_str.format(actual_install, + self.installdir)) From b923ce5181c530f4e5b386b27be98506be84eba6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Tue, 25 May 2021 07:41:13 +0200 Subject: [PATCH 6/7] Removed EC 'cuda_compute_capability' Use only the '--cuda-compute-capabilties' build_option. --- easybuild/easyblocks/a/aomp.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py index ba899b7aa2..921f9ef745 100644 --- a/easybuild/easyblocks/a/aomp.py +++ b/easybuild/easyblocks/a/aomp.py @@ -34,7 +34,6 @@ def extra_options(): extra_vars.update({ 'components': [None, "AOMP components to build. Possible components: " + ', '.join(AOMP_ALL_COMPONENTS), CUSTOM], - 'cuda_compute_capabilities': [[], "List of CUDA compute capabilities to build with", CUSTOM], }) return extra_vars @@ -71,7 +70,6 @@ def configure_step(self): # Use the commandline / easybuild config option if given, else use # the value from the EC (as a default) cuda_cc = build_option('cuda_compute_capabilities') - cuda_cc = cuda_cc or self.cfg['cuda_compute_capabilities'] if not cuda_cc: raise EasyBuildError("CUDA module was loaded, " "indicating a build with CUDA, " From 080ac8109869b03286cb92db09df28948399a4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Nordmoen?= Date: Tue, 8 Jun 2021 07:30:31 +0200 Subject: [PATCH 7/7] Pickup 'cuda_compute_capabilities' from either CMD or EB --- easybuild/easyblocks/a/aomp.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/easybuild/easyblocks/a/aomp.py b/easybuild/easyblocks/a/aomp.py index 921f9ef745..3bff55383f 100644 --- a/easybuild/easyblocks/a/aomp.py +++ b/easybuild/easyblocks/a/aomp.py @@ -7,7 +7,7 @@ from easybuild.easyblocks.generic.binary import Binary from easybuild.framework.easyconfig import CUSTOM -from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.build_log import EasyBuildError, print_warning from easybuild.tools.config import build_option from easybuild.tools.modules import get_software_root import os @@ -67,9 +67,16 @@ def configure_step(self): cuda_root = get_software_root('CUDA') or get_software_root('CUDAcore') install_options.append('AOMP_BUILD_CUDA=1') install_options.append('CUDA="{!s}"'.format(cuda_root)) - # Use the commandline / easybuild config option if given, else use - # the value from the EC (as a default) - cuda_cc = build_option('cuda_compute_capabilities') + # list of CUDA compute capabilities to use can be specifed in two ways (where (2) overrules (1)): + # (1) in the easyconfig file, via the custom cuda_compute_capabilities; + # (2) in the EasyBuild configuration, via --cuda-compute-capabilities configuration option; + ec_cuda_cc = self.cfg['cuda_compute_capabilities'] + cfg_cuda_cc = build_option('cuda_compute_capabilities') + cuda_cc = cfg_cuda_cc or ec_cuda_cc or [] + if cfg_cuda_cc and ec_cuda_cc: + warning_msg = "cuda_compute_capabilities specified in easyconfig (%s) are overruled by " % ec_cuda_cc + warning_msg += "--cuda-compute-capabilities configuration option (%s)" % cfg_cuda_cc + print_warning(warning_msg) if not cuda_cc: raise EasyBuildError("CUDA module was loaded, " "indicating a build with CUDA, "