Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
272 changes: 272 additions & 0 deletions packages/blttest/package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
# Copyright 2013-2021 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import os
import socket
from os.path import join as pjoin

from spack import *


def get_spec_path(spec, package_name, path_replacements={}, use_bin=False):
"""Extracts the prefix path for the given spack package
path_replacements is a dictionary with string replacements for the path.
"""

if not use_bin:
path = spec[package_name].prefix
else:
path = spec[package_name].prefix.bin

path = os.path.realpath(path)

for key in path_replacements:
path = path.replace(key, path_replacements[key])

return path


class Blttest(CachedCMakePackage, CudaPackage, ROCmPackage):
"""This is a package meant to test out basic Spack environments
against BLT's smoke and internal tests"""

maintainers = ['white238']

homepage = "https://github.com/LLNL/blt"
url = "https://github.com/LLNL/blt/archive/v0.4.0.tar.gz"
git = "https://github.com/LLNL/blt.git"
tags = ['radiuss']

maintainers = ['white238', 'davidbeckingsale']

version('develop', branch='develop')
version('main', branch='main')
# Note: 0.4.0+ contains a breaking change to BLT created targets
# if you export targets this could cause problems in downstream
# projects if not handled properly. More info here:
# https://llnl-blt.readthedocs.io/en/develop/tutorial/exporting_targets.html
version('0.4.1', sha256='16cc3e067ddcf48b99358107e5035a17549f52dcc701a35cd18a9d9f536826c1')
version('0.4.0', sha256='f3bc45d28b9b2eb6df43b75d4f6f89a1557d73d012da7b75bac1be0574767193')
version('0.3.6', sha256='6276317c29e7ff8524fbea47d9288ddb40ac06e9f9da5e878bf9011e2c99bf71')
version('0.3.5', sha256='68a1c224bb9203461ae6f5ab0ff3c50b4a58dcce6c2d2799489a1811f425fb84')
version('0.3.0', sha256='bb917a67cb7335d6721c997ba9c5dca70506006d7bba5e0e50033dd0836481a5')
version('0.2.5', sha256='3a000f60194e47b3e5623cc528cbcaf88f7fea4d9620b3c7446ff6658dc582a5')
version('0.2.0', sha256='c0cadf1269c2feb189e398a356e3c49170bc832df95e5564e32bdbb1eb0fa1b3')

root_cmakelists_dir = 'tests/internal'

# -----------------------------------------------------------------------
# Variants
# -----------------------------------------------------------------------
variant('shared', default=True,
description='Enable build of shared libraries')
variant('debug', default=False,
description='Build debug instead of optimized version')

# TODO: change this to a variant with options (cpp11, cpp14, etc...)
#variant('cpp14', default=True, description="Build with C++14 support")

variant('fortran', default=True, description="Build with Fortran support")

variant("mpi", default=True, description="Build MPI support")
variant('openmp', default=True, description='Turn on OpenMP support.')

# -----------------------------------------------------------------------
# Dependencies
# -----------------------------------------------------------------------
# Basics
depends_on("cmake@3.8.2:", type='build')
depends_on("mpi", when="+mpi")

def flag_handler(self, name, flags):
if self.spec.satisfies('%cce') and name == 'fflags':
flags.append('-ef')

if name in ('cflags', 'cxxflags', 'cppflags', 'fflags'):
return (None, None, None) # handled in the cmake cache
return (flags, None, None)

def _get_sys_type(self, spec):
sys_type = spec.architecture
# if on llnl systems, we can use the SYS_TYPE
if "SYS_TYPE" in env:
sys_type = env["SYS_TYPE"]
return sys_type

@property
def cache_name(self):
hostname = socket.gethostname()
if "SYS_TYPE" in env:
# Are we on a LLNL system then strip node number
hostname = hostname.rstrip('1234567890')
return "{0}-{1}-{2}@{3}.cmake".format(
hostname,
self._get_sys_type(self.spec),
self.spec.compiler.name,
self.spec.compiler.version
)

def initconfig_compiler_entries(self):
spec = self.spec
entries = super(Blttest, self).initconfig_compiler_entries()

if "+fortran" in spec or self.compiler.fc is not None:
entries.append(cmake_cache_option("ENABLE_FORTRAN", True))
else:
entries.append(cmake_cache_option("ENABLE_FORTRAN", False))

if ((self.compiler.fc is not None)
and ("gfortran" in self.compiler.fc)
and ("clang" in self.compiler.cxx)):
libdir = pjoin(os.path.dirname(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Spack folks prefer using join_path provided by Spack instead of os.path.join.

os.path.dirname(self.compiler.cxx)), "lib")
flags = ""
for _libpath in [libdir, libdir + "64"]:
if os.path.exists(_libpath):
flags += " -Wl,-rpath,{0}".format(_libpath)
description = ("Adds a missing libstdc++ rpath")
if flags:
entries.append(cmake_cache_string("BLT_EXE_LINKER_FLAGS", flags,
description))

# TODO: reenable when multi-variable variant is made
# if "+cpp14" in spec:
# entries.append(cmake_cache_string("BLT_CXX_STD", "c++14", ""))

return entries

def initconfig_hardware_entries(self):
spec = self.spec
entries = super(Blttest, self).initconfig_hardware_entries()

if "+cuda" in spec:
entries.append(cmake_cache_option("ENABLE_CUDA", True))

# CUDA_FLAGS
cudaflags = "-restrict --expt-extended-lambda "

if not spec.satisfies('cuda_arch=none'):
cuda_arch = spec.variants['cuda_arch'].value[0]
entries.append(cmake_cache_string(
"CMAKE_CUDA_ARCHITECTURES",
cuda_arch))
Comment on lines +150 to +154

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I realize using spec.satisfies() for this check is common for RADIUSS packages, but I believe you could do something like the following:

Suggested change
if not spec.satisfies('cuda_arch=none'):
cuda_arch = spec.variants['cuda_arch'].value[0]
entries.append(cmake_cache_string(
"CMAKE_CUDA_ARCHITECTURES",
cuda_arch))
cuda_arch = spec.variants['cuda_arch'].value
if cuda_arch != 'none':
entries.append(cmake_cache_string(
"CMAKE_CUDA_ARCHITECTURES",
cuda_arch[0]))

cudaflags += '-arch sm_${CMAKE_CUDA_ARCHITECTURES} '
else:
entries.append(
"# cuda_arch could not be determined\n\n")

# TODO: reenable when multi-variable variant is made
# if "+cpp14" in spec:
# cudaflags += " -std=c++14"
# else:
# cudaflags += " -std=c++11"
entries.append(
cmake_cache_string("CMAKE_CUDA_FLAGS", cudaflags))

entries.append(
"# nvcc does not like gtest's 'pthreads' flag\n")
entries.append(
cmake_cache_option("gtest_disable_pthreads", True))

entries.append("#------------------{0}".format("-" * 30))
entries.append("# Hardware Specifics")
entries.append("#------------------{0}\n".format("-" * 30))

# OpenMP
entries.append(cmake_cache_option("ENABLE_OPENMP",
spec.satisfies('+openmp')))

# Enable death tests
entries.append(cmake_cache_option(
"ENABLE_GTEST_DEATH_TESTS",
not spec.satisfies('+cuda target=ppc64le:')
))

if (self.compiler.fc is not None) and ("xlf" in self.compiler.fc):
# Grab lib directory for the current fortran compiler
libdir = pjoin(os.path.dirname(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same join_path suggestion as above.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

There's another at line 225.

os.path.dirname(self.compiler.fc)),
"lib")
description = ("Adds a missing rpath for libraries "
"associated with the fortran compiler")

linker_flags = "${BLT_EXE_LINKER_FLAGS} -Wl,-rpath," + libdir

entries.append(cmake_cache_string("BLT_EXE_LINKER_FLAGS",
linker_flags, description))

if "+shared" in spec:
linker_flags = "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath," \
+ libdir
entries.append(cmake_cache_string(
"CMAKE_SHARED_LINKER_FLAGS",
linker_flags, description))

description = ("Converts C-style comments to Fortran style "
"in preprocessed files")
entries.append(cmake_cache_string(
"BLT_FORTRAN_FLAGS",
"-WF,-C! -qxlf2003=polymorphic",
description))

if spec.satisfies('target=ppc64le:'):
# Fix for working around CMake adding implicit link directories
# returned by the BlueOS compilers to link executables with
# non-system default stdlib
_roots = ["/usr/tce/packages/gcc/gcc-4.9.3",
"/usr/tce/packages/gcc/gcc-4.9.3/gnu"]
_subdirs = ["lib64",
"lib64/gcc/powerpc64le-unknown-linux-gnu/4.9.3"]
Comment on lines +218 to +221

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why not use join_path here instead of explicitly entering / in the paths?

_existing_paths = []
for root in _roots:
for subdir in _subdirs:
_curr_path = pjoin(root, subdir)
if os.path.exists(_curr_path):
_existing_paths.append(_curr_path)
if _existing_paths:
entries.append(cmake_cache_string(
"BLT_CMAKE_IMPLICIT_LINK_DIRECTORIES_EXCLUDE",
";".join(_existing_paths)))

return entries

def initconfig_mpi_entries(self):
spec = self.spec
entries = super(Blttest, self).initconfig_mpi_entries()

if "+mpi" in spec:
entries.append(cmake_cache_option("ENABLE_MPI", True))
if spec['mpi'].name == 'spectrum-mpi':
entries.append(cmake_cache_string("BLT_MPI_COMMAND_APPEND",
"mpibind"))
else:
entries.append(cmake_cache_option("ENABLE_MPI", False))

return entries

def initconfig_package_entries(self):
return []

def cmake_args(self):
options = []

if self.run_tests is False:
options.append('-DENABLE_TESTS=OFF')
else:
options.append('-DENABLE_TESTS=ON')
Comment on lines +255 to +258

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you not simply:

Suggested change
if self.run_tests is False:
options.append('-DENABLE_TESTS=OFF')
else:
options.append('-DENABLE_TESTS=ON')
options.append(self.define('ENABLE_TESTS', self.run_tests))


options.append(self.define_from_variant(
'BUILD_SHARED_LIBS', 'shared'))

return options

@run_after('build')
@on_package_attributes(run_tests=True)
def build_test(self):
Comment on lines +265 to +267

@tldahlgren tldahlgren Dec 8, 2021

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you not just override the check method (and skip the directives) since Spack automatically calls check after the build phase when inheriting from CMakePackage (unless you override build_time_test_callbacks)?

with working_dir(self.build_directory):
print("Running Blttest Unit Tests...")
test_env = {'CTEST_OUTPUT_ON_FAILURE':'1',
'ARGS':'--no-compress-output -T Test -VV'}
make("test", env=test_env)
8 changes: 6 additions & 2 deletions scripts/get-spack
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ then
# A shallow clone is enough, and much faster.
git clone ${SPACK_REPO} --depth 1 --branch ${SPACK_REF} ${SPACK_PATH}
# We tag the commit so we can retrieve which one was used by a given pipeline.
git tag ${CI_PIPELINE_ID}
if [[ ! -z ${CI_PIPELINE_ID} ]]; then
git tag ${CI_PIPELINE_ID}
fi
else
cd ${SPACK_PATH}
git checkout -b temp
git branch -D ${SPACK_REF}
git fetch --depth 1 ${SPACK_REPO} ${SPACK_REF}:${SPACK_REF}
git checkout ${SPACK_REF}
git tag ${CI_PIPELINE_ID}
if [[ ! -z ${CI_PIPELINE_ID} ]]; then
git tag ${CI_PIPELINE_ID}
fi
git branch -D temp
cd -
fi
Expand Down
60 changes: 60 additions & 0 deletions scripts/test-blt
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/bash

#
# Note: This is super hacked together during a hackathon and definitely can be improved
#

SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
REPO_DIR=$SCRIPT_DIR/..
BASE_PATH=test_dir

SPACK_ENV_PATH=$REPO_DIR

# get-spack variables
export SPACK_REPO=https://github.com/spack/spack.git
export SPACK_PATH=spack
export SPACK_BIN=$SPACK_PATH/bin
export SPACK_REF="${SPACK_REF:-develop}"
export CI_PIPELINE_ID="${CI_PIPELINE_ID:-}"

echo "~~~~~~~~~~~~~ test-blt variables ~~~~~~~~~~~~~~"
echo SCRIPT_DIR=$SCRIPT_DIR
echo REPO_DIR=$REPO_DIR
echo BASE_PATH=$BASE_PATH
echo SPACK_REPO=$SPACK_REPO
echo SPACK_PATH=$SPACK_PATH
echo SPACK_REF=$SPACK_REF
echo CI_PIPELINE_ID=$CI_PIPELINE_ID
echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

rm -rf $BASE_PATH
mkdir $BASE_PATH

cd $BASE_PATH
# Setup Spack
$SCRIPT_DIR/get-spack
cp -R $REPO_DIR/packages/* $SPACK_PATH/var/spack/repos/builtin/packages

# Load environment and build/test BLT
mkdir spack-build
cd spack-build
echo "~~ clear SPACK_ENV"
export SPACK_ENV=

echo "~~ do not use home directory"
export SPACK_DISABLE_LOCAL_CONFIG=true

echo "~~ spack clean"
../$SPACK_BIN/spack clean --misc-cache --failures --python-cache

echo "~~ spack env create test1 $REPO_DIR/spack-environments/blt-test/toss3-clang10.yaml"
../$SPACK_BIN/spack env create test1 $REPO_DIR/spack-environments/blt-test/toss3-clang10.yaml

echo "~~ spack install --test=root"
../$SPACK_BIN/spack -e test1 install --keep-stage -v --test=root

# TODO: convert to junit and add as test artifacts
# TODO: copy host-configs to a helpful place
# TODO: profit
cd ..
cd ..
Loading