Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup in Mesa easyblock + add custom sanity check step #17

Merged
merged 7 commits into from
Mar 23, 2020
94 changes: 78 additions & 16 deletions easybuild/easyblocks/m/mesa.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,46 @@
EasyBuild support for installing Mesa, implemented as an easyblock

@author: Andrew Edmondson (University of Birmingham)
@author: Kenneth Hoste (HPC-UGent)
"""
import os
from distutils.version import LooseVersion

from easybuild.easyblocks.generic.mesonninja import MesonNinja
from easybuild.tools.systemtools import POWER, X86_64, get_cpu_architecture, get_cpu_features
from easybuild.tools.filetools import copy_dir
from easybuild.tools.systemtools import POWER, X86_64, get_cpu_architecture, get_cpu_features, get_shared_lib_ext


class EB_Mesa(MesonNinja):
def configure_step(self, cmd_prefix=''):
"""Custom easyblock for building and installing Mesa."""

def __init__(self, *args, **kwargs):
"""Constructor for custom Mesa easyblock: figure out which vales to pass to swr-arches configuration option."""

super(EB_Mesa, self).__init__(*args, **kwargs)

self.swr_arches = []

if 'swr-arches' not in self.cfg['configopts']:
# set cpu features of SWR for current architecture (only on x86_64)
if get_cpu_architecture() == X86_64:
feat_to_swrarch = {
'avx': 'avx',
'avx1.0': 'avx', # on macOS, AVX is indicated with 'avx1.0' rather than 'avx'
'avx2': 'avx2',
'avx512f': 'skx', # AVX-512 Foundation - introduced in Skylake
'avx512er': 'knl', # AVX-512 Exponential and Reciprocal Instructions implemented in Knights Landing
}
# determine list of values to pass to swr-arches configuration option
cpu_features = get_cpu_features()
self.swr_arches = sorted([swrarch for feat, swrarch in feat_to_swrarch.items() if feat in cpu_features])

def configure_step(self):
"""
Customise the configopts based on the platform
Customise the configure options based on the processor architecture of the host
(x86_64 or not, CPU features, ...)
"""

arch = get_cpu_architecture()
if 'gallium-drivers' not in self.cfg['configopts']:
# Install appropriate Gallium drivers for current architecture
Expand All @@ -45,16 +74,49 @@ def configure_step(self, cmd_prefix=''):
elif arch == POWER:
self.cfg.update('configopts', "-Dgallium-drivers='swrast'")

if 'swr-arches' not in self.cfg['configopts']:
# Set cpu features of SWR for current architecture
cpu_features = set(get_cpu_features())
swr_arches = []
if arch == X86_64:
# avx512f: AVX-512 Foundation - introduced in Skylake
# avx512er: AVX-512 Exponential and Reciprocal Instructions implemented in Knights Landing
x86_features = {'avx': 'avx', 'avx1.0': 'avx', 'avx2': 'avx2', 'avx512f': 'skx', 'avx512er': 'knl'}
swr_arches = [farch for fname, farch in x86_features.items() if fname in cpu_features]
if swr_arches:
self.cfg.update('configopts', "-Dswr-arches=%s" % ','.join(swr_arches))

return super(EB_Mesa, self).configure_step(cmd_prefix=cmd_prefix)
if self.swr_arches:
self.cfg.update('configopts', '-Dswr-arches=' + ','.join(self.swr_arches))

return super(EB_Mesa, self).configure_step()

def install_step(self):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this coming from? internal header doesn't sound like something a user would need. Also why is it not installed if it is meant to?

The description sounds like it belongs to a library not installed. Wouldn't that be bad if the header exist but the library does not?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see easybuilders/easybuild-easyconfigs#9129

It seems like this is no longer needed for the most recent Mesa versions (hence the os.path.exists check)

"""Also copy additional header files after installing Mesa."""

super(EB_Mesa, self).install_step()

# also install header files located in include/GL/internal, unless they're available already;
# we can't enable both DRI and Gallium drivers,
# but we can provide the DRI header file (GL/internal/dri_interface.h)
target_inc_GL_internal = os.path.join(self.installdir, 'include', 'GL', 'internal')
if not os.path.exists(target_inc_GL_internal):
src_inc_GL_internal = os.path.join(self.start_dir, 'include', 'GL', 'internal')
copy_dir(src_inc_GL_internal, target_inc_GL_internal)
self.log.info("Copied %s to %s" % (src_inc_GL_internal, target_inc_GL_internal))

def sanity_check_step(self):
"""Custom sanity check for Mesa."""

shlib_ext = get_shared_lib_ext()

if LooseVersion(self.version) >= LooseVersion('20.0'):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thinking: If this changes so considerably between versions, wouldn't this be better done in the EC?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Time will tell.

Going forward we can always easily overrule the easyblock by including sanity_check_paths in the easyconfig file.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah they take precedence. Didn't know that, than 👍

header_files = [os.path.join('include', 'EGL', x) for x in ['eglmesaext.h', 'eglextchromium.h']]
header_files.extend([
os.path.join('include', 'GL', 'osmesa.h'),
os.path.join('include', 'GL', 'internal', 'dri_interface.h'),
])
else:
gl_inc_files = ['glext.h', 'gl_mangle.h', 'glx.h', 'osmesa.h', 'gl.h', 'glxext.h', 'glx_mangle.h']
gles_inc_files = [('GLES', 'gl.h'), ('GLES2', 'gl2.h'), ('GLES3', 'gl3.h')]
header_files = [os.path.join('include', 'GL', x) for x in gl_inc_files]
header_files.extend([os.path.join('include', x, y) for (x, y) in gles_inc_files])

custom_paths = {
'files': [os.path.join('lib', 'libOSMesa.%s' % shlib_ext)] + header_files,
'dirs': [os.path.join('include', 'GL', 'internal')],
}

if self.swr_arches:
swr_arch_libs = [os.path.join('lib', 'libswr%s.%s' % (a.upper(), shlib_ext)) for a in self.swr_arches]
custom_paths['files'].extend(swr_arch_libs)

super(EB_Mesa, self).sanity_check_step(custom_paths=custom_paths)