2022-01-13 03:21:41 +08:00
|
|
|
# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
|
2020-09-01 22:59:06 +08:00
|
|
|
# Spack Project Developers. See the top-level COPYRIGHT file for details.
|
|
|
|
#
|
|
|
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
|
|
|
|
|
|
import os
|
|
|
|
import platform
|
2021-07-09 06:12:30 +08:00
|
|
|
import re
|
|
|
|
|
|
|
|
from spack import *
|
2020-09-01 22:59:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
class Hpcc(MakefilePackage):
|
|
|
|
"""HPC Challenge is a benchmark suite that measures a range memory access
|
|
|
|
patterns.
|
|
|
|
The HPC Challenge benchmark consists of basically 7 tests:
|
|
|
|
1) HPL - the Linpack TPP benchmark which measures the floating point
|
|
|
|
rate of execution for solving a linear system of equations.
|
|
|
|
2) DGEMM - measures the floating point rate of execution of double
|
|
|
|
precision real matrix-matrix multiplication.
|
|
|
|
3) STREAM - a simple synthetic benchmark program that measures
|
|
|
|
sustainable memory bandwidth (in GB/s) and
|
|
|
|
the corresponding computation rate for simple vector kernel.
|
|
|
|
4) PTRANS (parallel matrix transpose) - exercises the communications
|
|
|
|
where pairs of processors communicate
|
|
|
|
with each other simultaneously. It is a useful test of the total
|
|
|
|
communications capacity of the network.
|
|
|
|
5) RandomAccess - measures the rate of integer random updates of memory
|
|
|
|
(GUPS).
|
|
|
|
6) FFT - measures the floating point rate of execution of double
|
|
|
|
precision complex one-dimensional Discrete Fourier Transform (DFT).
|
|
|
|
7) Communication bandwidth and latency - a set of tests to measure
|
|
|
|
latency and bandwidth of a number of simultaneous communication
|
|
|
|
patterns; based on b_eff (effective bandwidth benchmark)."""
|
|
|
|
|
2021-09-02 14:46:27 +08:00
|
|
|
homepage = "https://icl.cs.utk.edu/hpcc"
|
2021-09-14 00:21:35 +08:00
|
|
|
url = "https://icl.cs.utk.edu/projectsfiles/hpcc/download/hpcc-1.5.0.tar.gz"
|
2020-09-01 22:59:06 +08:00
|
|
|
git = "https://github.com/icl-utk-edu/hpcc.git"
|
|
|
|
|
|
|
|
version('develop', branch='main')
|
|
|
|
version('1.5.0', sha256='0a6fef7ab9f3347e549fed65ebb98234feea9ee18aea0c8f59baefbe3cf7ffb8')
|
|
|
|
|
|
|
|
variant(
|
|
|
|
'fft', default='internal', description='FFT library to use',
|
|
|
|
values=('internal', 'fftw2', 'mkl'), multi=False
|
|
|
|
)
|
|
|
|
|
|
|
|
depends_on('gmake', type='build')
|
|
|
|
depends_on('mpi@1.1:')
|
|
|
|
depends_on('blas')
|
|
|
|
depends_on('fftw-api@2+mpi', when='fft=fftw2')
|
|
|
|
depends_on('mkl', when='fft=mkl')
|
|
|
|
|
|
|
|
arch = '{0}-{1}'.format(platform.system(), platform.processor())
|
|
|
|
|
|
|
|
config = {
|
|
|
|
'@SHELL@': '/bin/sh',
|
|
|
|
'@CD@': 'cd',
|
|
|
|
'@CP@': 'cp',
|
|
|
|
'@LN_S@': 'ln -s',
|
|
|
|
'@MKDIR@': 'mkdir',
|
|
|
|
'@RM@': '/bin/rm -f',
|
|
|
|
'@TOUCH@': 'touch',
|
|
|
|
'@ARCHIVER@': 'ar',
|
|
|
|
'@ARFLAGS@': 'r',
|
|
|
|
'@RANLIB@': 'echo',
|
|
|
|
'@ARCH@': arch,
|
|
|
|
'@MPDIR@': '',
|
|
|
|
'@MPINC@': '',
|
|
|
|
'@MPLIB@': '',
|
|
|
|
'@F2CDEFS@': '-DAdd_ -DF77_INTEGER=int -DStringSunStyle',
|
|
|
|
'@LADIR@': '',
|
|
|
|
'@LAINC@': '',
|
|
|
|
'@LALIB@': '',
|
|
|
|
'@CC@': None,
|
|
|
|
'@CCNOOPT@': '',
|
|
|
|
'@CCFLAGS@': '-O3',
|
|
|
|
'@LINKER@': '$(CC)',
|
|
|
|
'@LINKFLAGS@': ''
|
|
|
|
}
|
|
|
|
|
|
|
|
def patch(self):
|
|
|
|
if 'fftw' in self.spec:
|
|
|
|
# spack's fftw2 prefix headers with floating point type
|
|
|
|
filter_file(r"^\s*#include <fftw.h>", "#include <sfftw.h>",
|
|
|
|
"FFT/wrapfftw.h")
|
|
|
|
filter_file(r"^\s*#include <fftw_mpi.h>", "#include <sfftw_mpi.h>",
|
|
|
|
"FFT/wrapmpifftw.h")
|
|
|
|
|
|
|
|
def _write_make_arch(self, spec, prefix):
|
|
|
|
"""write make.arch file"""
|
|
|
|
with working_dir('hpl'):
|
|
|
|
# copy template make.arch file
|
|
|
|
make_arch_filename = 'Make.{0}'.format(self.arch)
|
|
|
|
copy(join_path('setup', 'Make.UNKNOWN.in'), make_arch_filename)
|
|
|
|
|
|
|
|
# fill template with values
|
|
|
|
make_arch = FileFilter(make_arch_filename)
|
|
|
|
for k, v in self.config.items():
|
|
|
|
make_arch.filter(k, v)
|
|
|
|
|
|
|
|
def edit(self, spec, prefix):
|
|
|
|
# Message Passing library (MPI)
|
|
|
|
self.config['@MPINC@'] = spec['mpi'].headers.include_flags
|
|
|
|
self.config['@MPLIB@'] = spec['mpi'].libs.search_flags
|
|
|
|
|
|
|
|
lin_alg_libs = []
|
|
|
|
# FFT
|
|
|
|
if self.spec.variants['fft'].value in ('fftw2', 'mkl'):
|
|
|
|
self.config['@LAINC@'] += ' -DUSING_FFTW'
|
|
|
|
|
|
|
|
if self.spec.variants['fft'].value == 'fftw2':
|
|
|
|
self.config['@LAINC@'] += \
|
|
|
|
spec['fftw-api'].headers.include_flags
|
|
|
|
# fftw does not set up libs for version 2
|
|
|
|
lin_alg_libs.append(
|
|
|
|
join_path(spec['fftw-api'].prefix.lib, 'libsfftw_mpi.so'))
|
|
|
|
lin_alg_libs.append(
|
|
|
|
join_path(spec['fftw-api'].prefix.lib, 'libsfftw.so'))
|
|
|
|
|
|
|
|
elif self.spec.variants['fft'].value == 'mkl' and '^mkl' in spec:
|
|
|
|
mklroot = env['MKLROOT']
|
|
|
|
self.config['@LAINC@'] += \
|
|
|
|
' -I{0}'.format(join_path(mklroot, 'include/fftw'))
|
|
|
|
libfftw2x_cdft = join_path(
|
|
|
|
mklroot, 'lib', 'intel64', 'libfftw2x_cdft_DOUBLE_ilp64.a')
|
|
|
|
libfftw2xc = join_path(
|
|
|
|
mklroot, 'lib', 'intel64', 'libfftw2xc_double_intel.a')
|
|
|
|
if not (os.path.exists(libfftw2x_cdft) and
|
|
|
|
os.path.exists(libfftw2xc)):
|
|
|
|
raise InstallError(
|
|
|
|
"HPCC need fftw2 interface, "
|
|
|
|
"here are brief notes how to make one:\n"
|
|
|
|
"# make fftw2x_cdft interface to mkl\n"
|
|
|
|
"cd $MKLROOT/interfaces/fftw2x_cdft\n"
|
|
|
|
"make libintel64 PRECISION=MKL_DOUBLE "
|
|
|
|
"interface=ilp64 MKLROOT=$MKLROOT\n"
|
|
|
|
"\n"
|
|
|
|
"# make FFTW C wrapper library\n"
|
|
|
|
"cd $MKLROOT/interfaces/fftw2xc\n"
|
|
|
|
"make libintel64 PRECISION=MKL_DOUBLE "
|
|
|
|
"MKLROOT=$MKLROOT\n")
|
|
|
|
lin_alg_libs.append(libfftw2xc)
|
|
|
|
lin_alg_libs.append(libfftw2x_cdft)
|
|
|
|
|
|
|
|
# Linear Algebra library (BLAS or VSIPL)
|
|
|
|
self.config['@LAINC@'] = spec['blas'].headers.include_flags
|
|
|
|
lin_alg_libs = lin_alg_libs + [
|
|
|
|
lib for lib in spec['blas'].libs if lib not in lin_alg_libs]
|
|
|
|
|
|
|
|
# pack all LA/FFT libraries
|
|
|
|
self.config['@LALIB@'] = ' '.join(lin_alg_libs)
|
|
|
|
|
|
|
|
# Compilers / linkers - Optimization flags
|
|
|
|
self.config['@CC@'] = '{0}'.format(spec['mpi'].mpicc)
|
|
|
|
|
|
|
|
# Compiler flags for CPU architecture optimizations
|
|
|
|
if spec.satisfies('%intel'):
|
|
|
|
# with intel-parallel-studio+mpi the '-march' arguments
|
|
|
|
# are not passed to icc
|
|
|
|
arch_opt = spec.target.optimization_flags(
|
|
|
|
spec.compiler.name, spec.compiler.version)
|
|
|
|
self.config['@CCFLAGS@'] = \
|
|
|
|
'-O3 -restrict -ansi-alias -ip {0}'.format(arch_opt)
|
|
|
|
self.config['@CCNOOPT@'] = '-restrict'
|
|
|
|
self._write_make_arch(spec, prefix)
|
|
|
|
|
|
|
|
def build(self, spec, prefix):
|
|
|
|
make('arch={0}'.format(self.arch))
|
|
|
|
|
|
|
|
def check(self):
|
|
|
|
"""Simple check that compiled binary is working:
|
|
|
|
launch with 4 MPI processes and check that test finished."""
|
|
|
|
# copy input
|
|
|
|
copy('_hpccinf.txt', 'hpccinf.txt')
|
|
|
|
# run test
|
|
|
|
run = Executable(
|
|
|
|
join_path(os.path.dirname(self.spec['mpi'].mpicc), 'mpirun'))
|
|
|
|
run('-np', '4', './hpcc')
|
|
|
|
# check output
|
|
|
|
hpccoutf = open('hpccoutf.txt', 'rt').read()
|
|
|
|
if not re.search("End of HPC Challenge tests", hpccoutf):
|
|
|
|
raise Exception("Test run was not successfull!")
|
|
|
|
|
|
|
|
def installcheck(self):
|
|
|
|
"""Same as check but within prefix location"""
|
|
|
|
with working_dir(self.prefix.share.hpcc):
|
|
|
|
# run test
|
|
|
|
run = Executable(
|
|
|
|
join_path(os.path.dirname(self.spec['mpi'].mpicc), 'mpirun'))
|
|
|
|
run('-np', '4', self.prefix.bin.hpcc)
|
|
|
|
# check output
|
|
|
|
hpccoutf = open('hpccoutf.txt', 'rt').read()
|
|
|
|
if not re.search("End of HPC Challenge tests", hpccoutf):
|
|
|
|
raise Exception("Test run was not successfull!")
|
|
|
|
|
|
|
|
def install(self, spec, prefix):
|
|
|
|
# copy executable
|
|
|
|
mkdirp(self.prefix.bin)
|
|
|
|
install('hpcc', prefix.bin)
|
|
|
|
# copy input example
|
|
|
|
mkdirp(self.prefix.share.hpcc)
|
|
|
|
install('_hpccinf.txt',
|
|
|
|
join_path(self.prefix.share.hpcc, 'hpccinf.txt'))
|
|
|
|
# copy documentation
|
|
|
|
mkdirp(self.prefix.doc.hpcc)
|
|
|
|
install('README.html', self.prefix.doc.hpcc)
|
|
|
|
install('README.txt', self.prefix.doc.hpcc)
|
2020-09-08 14:30:02 +08:00
|
|
|
|
|
|
|
def flag_handler(self, name, flags):
|
|
|
|
# old GCC defaults to -std=c90 but C99 is required for "restrict"
|
|
|
|
if self.spec.satisfies('%gcc@:5.1') and name == 'cflags':
|
|
|
|
flags.append(self.compiler.c99_flag)
|
|
|
|
return (flags, None, None)
|