From c963065c26ea34dfe47e0ef6db221d6fd30d0282 Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Tue, 28 Jan 2020 14:32:17 -0600 Subject: [PATCH 1/9] Add XALT EasyBlock --- easybuild/easyblocks/x/xalt.py | 94 ++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 easybuild/easyblocks/x/xalt.py diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py new file mode 100644 index 0000000000..c1d9d1c676 --- /dev/null +++ b/easybuild/easyblocks/x/xalt.py @@ -0,0 +1,94 @@ +## +# Copyright 2020 NVIDIA +# +# This file is triple-licensed under GPLv2 (see below), MIT, and +# BSD three-clause licenses. +# +# This file is part of EasyBuild, +# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), +# with support of Ghent University (http://ugent.be/hpc), +# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be), +# Flemish Research Foundation (FWO) (http://www.fwo.be/en) +# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). +# +# https://github.com/easybuilders/easybuild +# +# EasyBuild is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation v2. +# +# EasyBuild is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with EasyBuild. If not, see . +## +""" +EasyBuild support for XALT, implemented as an easyblock +@author: Scott McMillan (NVIDIA) +""" +import os +import re + +from easybuild.easyblocks.generic.configuremake import ConfigureMake +from easybuild.framework.easyconfig import CUSTOM, MANDATORY +from easybuild.tools.build_log import EasyBuildError +from easybuild.tools.modules import get_software_root +from easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext + + +class EB_XALT(ConfigureMake): + """Support for building and installing XALT.""" + + @staticmethod + def extra_options(): + extra_vars = { + 'config_py': [None, "XALT site filter file", MANDATORY], + 'syshost': ['hardcode:cluster', "System name", CUSTOM], + 'transmission': ['syslog', "", CUSTOM], + } + return ConfigureMake.extra_options(extra_vars) + + def configure_step(self): + """Custom configuration step for XALT.""" + + # Remove the subdir from the install prefix to resolve the + # following configure error. XALT automatically creates a + # versioned directory hierarchy. + # + # Do not install XALT with 2.7.27 as part of the + # prefix. It will lead to many many problems with future + # installs of XALT + # + # Executables built with the current version of XALT + # will not work with future installs of XALT!!! + # + # If you feel that you know better than the developer + # of XALT then you can configure XALT with the configure + # --with-IrefuseToInstallXALTCorrectly=yes and set the prefix + # to include the version + self.installdir = os.path.normpath(re.sub(self.install_subdir, '', self.installdir)) + + # XALT site filter config file is mandatory + if not self.cfg['config_py']: + raise EasyBuildError('XALT site filter config must be specified. ' + 'Use "--try-amend=config_py="') + self.cfg.update('configopts', '--with-config=%s' % self.cfg['config_py']) + + if self.cfg['syshost']: + self.cfg.update('configopts', '--with-syshostConfig=%s' % self.cfg['syshost']) + + if self.cfg['transmission']: + self.cfg.update('configopts', '--with-transmission=%s' % self.cfg['transmission']) + + super(EB_XALT, self).configure_step() + + # Reassemble the default install path + self.installdir = os.path.join(self.installdir, self.install_subdir) + + def make_module_req_guess(self): + """ Limit default guess paths """ + return {'COMPILER_PATH': 'bin', + 'PATH': 'bin'} From 2a5fa0b00896a9b2a35c4b1c66ee9c5c93b08645 Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Tue, 28 Jan 2020 14:56:54 -0600 Subject: [PATCH 2/9] remove unused imports --- easybuild/easyblocks/x/xalt.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index c1d9d1c676..144b409861 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -35,8 +35,6 @@ from easybuild.easyblocks.generic.configuremake import ConfigureMake from easybuild.framework.easyconfig import CUSTOM, MANDATORY from easybuild.tools.build_log import EasyBuildError -from easybuild.tools.modules import get_software_root -from easybuild.tools.systemtools import check_os_dependency, get_shared_lib_ext class EB_XALT(ConfigureMake): From e1804429031b0242f592e93a658b7adacb45ac8d Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Thu, 5 Mar 2020 09:28:37 -0600 Subject: [PATCH 3/9] address PR feedback --- easybuild/easyblocks/x/xalt.py | 100 +++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 11 deletions(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index 144b409861..2250fb4b23 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -35,7 +35,8 @@ from easybuild.easyblocks.generic.configuremake import ConfigureMake from easybuild.framework.easyconfig import CUSTOM, MANDATORY from easybuild.tools.build_log import EasyBuildError - +from easybuild.tools.modules import get_software_root +from easybuild.tools.systemtools import get_shared_lib_ext class EB_XALT(ConfigureMake): """Support for building and installing XALT.""" @@ -44,8 +45,13 @@ class EB_XALT(ConfigureMake): def extra_options(): extra_vars = { 'config_py': [None, "XALT site filter file", MANDATORY], - 'syshost': ['hardcode:cluster', "System name", CUSTOM], - 'transmission': ['syslog', "", CUSTOM], + 'executable_tracking': [True, "Enable executable tracking", CUSTOM], + 'gpu_tracking': [None, "Enable GPU tracking", CUSTOM], + 'logging_url': [None, "Logging URL for transmission", CUSTOM], + 'mysql': [False, "Build with MySQL support", CUSTOM], + 'scalar_sampling': [True, "Enable scalar sampling", CUSTOM], + 'syshost': [None, "System name", MANDATORY], + 'transmission': [None, "Data tranmission method", MANDATORY], } return ConfigureMake.extra_options(extra_vars) @@ -56,7 +62,7 @@ def configure_step(self): # following configure error. XALT automatically creates a # versioned directory hierarchy. # - # Do not install XALT with 2.7.27 as part of the + # Do not install XALT with 2.7.28 as part of the # prefix. It will lead to many many problems with future # installs of XALT # @@ -67,26 +73,98 @@ def configure_step(self): # of XALT then you can configure XALT with the configure # --with-IrefuseToInstallXALTCorrectly=yes and set the prefix # to include the version + orig_installdir = self.installdir self.installdir = os.path.normpath(re.sub(self.install_subdir, '', self.installdir)) # XALT site filter config file is mandatory - if not self.cfg['config_py']: - raise EasyBuildError('XALT site filter config must be specified. ' - 'Use "--try-amend=config_py="') - self.cfg.update('configopts', '--with-config=%s' % self.cfg['config_py']) + config_py = self.cfg['config_py'] + if config_py: + if os.path.exists(config_py): + self.cfg.update('configopts', '--with-config=%s' % config_py) + else: + raise EasyBuildError("Specified XALT configuration file %s does not exist!", config_py) + else: + error_msg = "Location of XALT configuration file must be specified via 'config_py' easyconfig parameter. " + error_msg += "You can edit the easyconfig file, or use 'eb --try-amend=config_py='. " + error_msg += "See https://xalt.readthedocs.io/en/latest/030_site_filtering.html for more information." + raise EasyBuildError(error_msg) + # XALT system name is mandatory if self.cfg['syshost']: self.cfg.update('configopts', '--with-syshostConfig=%s' % self.cfg['syshost']) + else: + error_msg = "The name of the system must be specified via the 'syshost' easyconfig parameter. " + error_msg += "You can edit the easyconfig file, or use 'eb --try-amend=syshost='. " + error_msg += "See https://xalt.readthedocs.io/en/latest/020_site_configuration.html for more information." + raise EasyBuildError(error_msg) + # Transmission method is mandatory if self.cfg['transmission']: self.cfg.update('configopts', '--with-transmission=%s' % self.cfg['transmission']) + else: + error_msg = "The XALT transmission method must be specified via the 'transmission' easyconfig parameter. " + error_msg = "You can edit the easyconfig file, or use 'eb --try-amend=transmission='. " + error_msg += "See https://xalt.readthedocs.io/en/latest/020_site_configuration.html for more information." + raise EasyBuildError(error_msg) + + # GPU tracking + if self.cfg['gpu_tracking'] is True: + # User enabled + self.cfg.update('configopts', '--with-trackGPU=yes') + elif self.cfg['gpu_tracking'] is None: + # Default value, enable GPU tracking if nvml.h is present + # and the CUDA module is loaded + cuda_root = get_software_root('CUDA') + if not cuda_root: + # Try using the system CUDA + cuda_root = '/usr/local/cuda' + nvml_h = os.path.join(cuda_root, "include", "nvml.h") + if os.path.isfile(nvml_h): + self.cfg.update('configopts', '--with-trackGPU=yes') + self.cfg['gpu_tracking'] = True + else: + # User disabled + self.cfg.update('configopts', '--with-trackGPU=no') + + # MySQL + if self.cfg['mysql'] is True: + self.cfg.update('configopts', '--with-MySQL=yes') + else: + self.cfg.update('configopts', '--with-MySQL=no') + # Configure super(EB_XALT, self).configure_step() - # Reassemble the default install path - self.installdir = os.path.join(self.installdir, self.install_subdir) + # Reset the default install path + self.installdir = orig_installdir + + def make_module_extra(self, *args, **kwargs): + txt = super(EB_XALT, self).make_module_extra(*args, **kwargs) + + txt += self.module_generator.prepend_paths('LD_PRELOAD', 'lib64/libxalt_init.so') + txt += self.module_generator.prepend_paths('SINGULARITY_BINDPATH', '') + txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', 'lib64/libxalt_init.so') + txt += self.module_generator.set_environment('XALT_DIR', self.installdir) + txt += self.module_generator.set_environment('XALT_ETC_DIR', '%s' % os.path.join(self.installdir, 'etc')) + txt += self.module_generator.set_environment('XALT_EXECUTABLE_TRACKING', '%s' % ('no', 'yes')[bool(self.cfg['executable_tracking'])]) + txt += self.module_generator.set_environment('XALT_GPU_TRACKING', ('no', 'yes')[bool(self.cfg['gpu_tracking'])]) + if self.cfg['transmission'].lower() == 'curl' and self.cfg['logging_url']: + txt += self.module_generator.set_environment('XALT_LOGGING_URL', self.cfg['logging_url']) + txt += self.module_generator.set_environment('XALT_SCALAR_SAMPLING', '%s' % ('no', 'yes')[bool(self.cfg['scalar_sampling'])]) + + return txt def make_module_req_guess(self): - """ Limit default guess paths """ + """ Limit default guess paths + Do not set CPATH, LD_LIBRARY_PATH, LIBRARY_PATH, include sbin in PATH """ return {'COMPILER_PATH': 'bin', 'PATH': 'bin'} + + def sanity_check_step(self): + """Custom sanity check""" + custom_paths = { + 'files': ['lib64/libxalt_init.%s' % get_shared_lib_ext()], + 'dirs': ['lib64'], + } + + super(EB_XALT, self).sanity_check_step(custom_paths=custom_paths) From 2b0fa176fe7f7262277da55e543cb47d79de919a Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Thu, 5 Mar 2020 09:51:38 -0600 Subject: [PATCH 4/9] fix linter issues --- easybuild/easyblocks/x/xalt.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index 2250fb4b23..73aa08f900 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -38,6 +38,7 @@ from easybuild.tools.modules import get_software_root from easybuild.tools.systemtools import get_shared_lib_ext + class EB_XALT(ConfigureMake): """Support for building and installing XALT.""" @@ -146,11 +147,14 @@ def make_module_extra(self, *args, **kwargs): txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', 'lib64/libxalt_init.so') txt += self.module_generator.set_environment('XALT_DIR', self.installdir) txt += self.module_generator.set_environment('XALT_ETC_DIR', '%s' % os.path.join(self.installdir, 'etc')) - txt += self.module_generator.set_environment('XALT_EXECUTABLE_TRACKING', '%s' % ('no', 'yes')[bool(self.cfg['executable_tracking'])]) - txt += self.module_generator.set_environment('XALT_GPU_TRACKING', ('no', 'yes')[bool(self.cfg['gpu_tracking'])]) + txt += self.module_generator.set_environment('XALT_EXECUTABLE_TRACKING', + ('no', 'yes')[bool(self.cfg['executable_tracking'])]) + txt += self.module_generator.set_environment('XALT_GPU_TRACKING', + ('no', 'yes')[bool(self.cfg['gpu_tracking'])]) if self.cfg['transmission'].lower() == 'curl' and self.cfg['logging_url']: txt += self.module_generator.set_environment('XALT_LOGGING_URL', self.cfg['logging_url']) - txt += self.module_generator.set_environment('XALT_SCALAR_SAMPLING', '%s' % ('no', 'yes')[bool(self.cfg['scalar_sampling'])]) + txt += self.module_generator.set_environment('XALT_SCALAR_SAMPLING', + ('no', 'yes')[bool(self.cfg['scalar_sampling'])]) return txt From 475255254a801a1ddbd89f8608482afddac9d9a9 Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Tue, 10 Mar 2020 11:11:00 -0500 Subject: [PATCH 5/9] use the new XALT site control prefix option --- easybuild/easyblocks/x/xalt.py | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index 73aa08f900..f3fa292824 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -59,23 +59,13 @@ def extra_options(): def configure_step(self): """Custom configuration step for XALT.""" - # Remove the subdir from the install prefix to resolve the - # following configure error. XALT automatically creates a - # versioned directory hierarchy. - # - # Do not install XALT with 2.7.28 as part of the - # prefix. It will lead to many many problems with future - # installs of XALT - # - # Executables built with the current version of XALT - # will not work with future installs of XALT!!! - # - # If you feel that you know better than the developer - # of XALT then you can configure XALT with the configure - # --with-IrefuseToInstallXALTCorrectly=yes and set the prefix - # to include the version - orig_installdir = self.installdir - self.installdir = os.path.normpath(re.sub(self.install_subdir, '', self.installdir)) + # By default, XALT automatically appends 'xalt/' to the + # prefix, i.e., --prefix=/opt will actually install in + # /opt/xalt/. To precisely control the install prefix and + # not append anything to the prefix, use the configure option + # '--with-siteControlledPrefix=yes'. + # See https://xalt.readthedocs.io/en/latest/050_install_and_test.html + self.cfg.update('configopts', '--with-siteControlledPrefix=yes') # XALT site filter config file is mandatory config_py = self.cfg['config_py'] @@ -136,9 +126,6 @@ def configure_step(self): # Configure super(EB_XALT, self).configure_step() - # Reset the default install path - self.installdir = orig_installdir - def make_module_extra(self, *args, **kwargs): txt = super(EB_XALT, self).make_module_extra(*args, **kwargs) From 9f8df1ccc673e0b8499f9bc64bdff8c997c3b49c Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Tue, 10 Mar 2020 11:12:25 -0500 Subject: [PATCH 6/9] remove unnecessary re import --- easybuild/easyblocks/x/xalt.py | 1 - 1 file changed, 1 deletion(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index f3fa292824..302316dd6d 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -30,7 +30,6 @@ @author: Scott McMillan (NVIDIA) """ import os -import re from easybuild.easyblocks.generic.configuremake import ConfigureMake from easybuild.framework.easyconfig import CUSTOM, MANDATORY From e756ce91def48274b1ad927a167a24cdb24e7800 Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Tue, 19 May 2020 17:05:54 -0500 Subject: [PATCH 7/9] resolve review feedback --- easybuild/easyblocks/x/xalt.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index 302316dd6d..6b4133846f 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -105,13 +105,11 @@ def configure_step(self): # Default value, enable GPU tracking if nvml.h is present # and the CUDA module is loaded cuda_root = get_software_root('CUDA') - if not cuda_root: - # Try using the system CUDA - cuda_root = '/usr/local/cuda' - nvml_h = os.path.join(cuda_root, "include", "nvml.h") - if os.path.isfile(nvml_h): - self.cfg.update('configopts', '--with-trackGPU=yes') - self.cfg['gpu_tracking'] = True + if cuda_root: + nvml_h = os.path.join(cuda_root, "include", "nvml.h") + if os.path.isfile(nvml_h): + self.cfg.update('configopts', '--with-trackGPU=yes') + self.cfg['gpu_tracking'] = True else: # User disabled self.cfg.update('configopts', '--with-trackGPU=no') @@ -128,9 +126,7 @@ def configure_step(self): def make_module_extra(self, *args, **kwargs): txt = super(EB_XALT, self).make_module_extra(*args, **kwargs) - txt += self.module_generator.prepend_paths('LD_PRELOAD', 'lib64/libxalt_init.so') - txt += self.module_generator.prepend_paths('SINGULARITY_BINDPATH', '') - txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', 'lib64/libxalt_init.so') + txt += self.module_generator.prepend_paths('LD_PRELOAD', 'lib64/libxalt_init.%s' % get_shared_lib_ext()) txt += self.module_generator.set_environment('XALT_DIR', self.installdir) txt += self.module_generator.set_environment('XALT_ETC_DIR', '%s' % os.path.join(self.installdir, 'etc')) txt += self.module_generator.set_environment('XALT_EXECUTABLE_TRACKING', @@ -142,19 +138,25 @@ def make_module_extra(self, *args, **kwargs): txt += self.module_generator.set_environment('XALT_SCALAR_SAMPLING', ('no', 'yes')[bool(self.cfg['scalar_sampling'])]) + # In order to track containerized executables, bind mount the XALT + # directory in the Singularity container and preload the XALT library + # https://xalt.readthedocs.io/en/latest/050_install_and_test.html#xalt-modulefile + txt += self.module_generator.prepend_paths('SINGULARITY_BINDPATH', '') + txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', 'lib64/libxalt_init.%s' % get_shared_lib_ext()) + return txt def make_module_req_guess(self): - """ Limit default guess paths - Do not set CPATH, LD_LIBRARY_PATH, LIBRARY_PATH, include sbin in PATH """ + """Custom guesses for environment variables""" return {'COMPILER_PATH': 'bin', 'PATH': 'bin'} def sanity_check_step(self): """Custom sanity check""" custom_paths = { - 'files': ['lib64/libxalt_init.%s' % get_shared_lib_ext()], - 'dirs': ['lib64'], + 'files': ['bin/ld', 'bin/ld.gold', 'bin/xalt_extract_record', + 'lib64/libxalt_init.%s' % get_shared_lib_ext()], + 'dirs': ['bin', 'libexec', 'sbin'], } super(EB_XALT, self).sanity_check_step(custom_paths=custom_paths) From f2f8a0f34caf2e0b2439111525f4beffc17b3a00 Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Tue, 19 May 2020 17:11:12 -0500 Subject: [PATCH 8/9] fix line too long linter issue --- easybuild/easyblocks/x/xalt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index 6b4133846f..ec7e49d456 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -142,7 +142,8 @@ def make_module_extra(self, *args, **kwargs): # directory in the Singularity container and preload the XALT library # https://xalt.readthedocs.io/en/latest/050_install_and_test.html#xalt-modulefile txt += self.module_generator.prepend_paths('SINGULARITY_BINDPATH', '') - txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', 'lib64/libxalt_init.%s' % get_shared_lib_ext()) + txt += self.module_generator.prepend_paths('SINGULARITYENV_LD_PRELOAD', + 'lib64/libxalt_init.%s' % get_shared_lib_ext()) return txt From 2de3c4227bbfa057e0599d68f031bd21942236bf Mon Sep 17 00:00:00 2001 From: Scott McMillan Date: Thu, 21 May 2020 12:38:12 -0500 Subject: [PATCH 9/9] Add static_cxx option and sanity test command --- easybuild/easyblocks/x/xalt.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/easybuild/easyblocks/x/xalt.py b/easybuild/easyblocks/x/xalt.py index ec7e49d456..e80b8d24cc 100644 --- a/easybuild/easyblocks/x/xalt.py +++ b/easybuild/easyblocks/x/xalt.py @@ -50,6 +50,7 @@ def extra_options(): 'logging_url': [None, "Logging URL for transmission", CUSTOM], 'mysql': [False, "Build with MySQL support", CUSTOM], 'scalar_sampling': [True, "Enable scalar sampling", CUSTOM], + 'static_cxx': [False, "Statically link libstdc++ and libgcc_s", CUSTOM], 'syshost': [None, "System name", MANDATORY], 'transmission': [None, "Data tranmission method", MANDATORY], } @@ -120,6 +121,12 @@ def configure_step(self): else: self.cfg.update('configopts', '--with-MySQL=no') + # If XALT is built with a more recent compiler than the system + # compiler, then XALT likely will depend on symbol versions not + # available in the system libraries. Link statically as a workaround. + if self.cfg['static_cxx'] is True: + self.cfg.update('configopts', 'LDFLAGS="${LDFLAGS} -static-libstdc++ -static-libgcc"') + # Configure super(EB_XALT, self).configure_step() @@ -159,5 +166,7 @@ def sanity_check_step(self): 'lib64/libxalt_init.%s' % get_shared_lib_ext()], 'dirs': ['bin', 'libexec', 'sbin'], } + custom_commands = ['xalt_configuration_report'] - super(EB_XALT, self).sanity_check_step(custom_paths=custom_paths) + super(EB_XALT, self).sanity_check_step(custom_commands=custom_commands, + custom_paths=custom_paths)