Adding a Spack Package
Glossary terms: Benchmark, Package
A Spack package.py defines how to download, build, and install a benchmark. If a
package already exists in the Spack Packages repository,
Benchpark uses that definition. A package in
repos/spack_repo/benchpark/packages/<benchmark-name>/package.py overrides the
corresponding upstream package.
For the HPL example, create repos/spack_repo/benchpark/packages/hpl/package.py with
the following complete contents:
1# Copyright 2023 Lawrence Livermore National Security, LLC and other
2# Benchpark Project Developers. See the top-level COPYRIGHT file for details.
3#
4# SPDX-License-Identifier: Apache-2.0
5
6import os
7import platform
8
9from spack.package import *
10from spack_repo.builtin.build_systems.autotools import AutotoolsPackage
11
12
13class Hpl(AutotoolsPackage):
14 """HPL is a software package that solves a (random) dense linear system
15 in double precision (64 bits) arithmetic on distributed-memory computers.
16 It can thus be regarded as a portable as well as freely available
17 implementation of the High Performance Computing Linpack Benchmark."""
18
19 homepage = "https://www.netlib.org/benchmark/hpl/"
20 url = "https://www.netlib.org/benchmark/hpl/hpl-2.2.tar.gz"
21 git = "https://github.com/daboehme/HPL-caliper.git"
22
23 # Note: HPL uses autotools starting with 2.3
24
25 version("2.3", sha256="32c5c17d22330e6f2337b681aded51637fb6008d3f0eb7c277b163fadd612830")
26 version("2.2", sha256="ac7534163a09e21a5fa763e4e16dfc119bc84043f6e6a807aba666518f8df440")
27 version("2.3-caliper", branch="master", preferred=False)
28
29 variant("openmp", default=False, description="Enable OpenMP support")
30 variant("caliper", default=False, description="Enable Caliper support")
31
32 depends_on("c", type="build")
33 depends_on("cxx", type="build")
34 depends_on("fortran", type="build")
35
36 depends_on("mpi@1.1:")
37 depends_on("blas")
38
39 depends_on("caliper", when="+caliper")
40 depends_on("adiak@0.4:", when="+caliper")
41
42 requires("@2.3-caliper", when="+caliper")
43
44 # 2.3 adds support for openmpi 4
45 conflicts("^openmpi@4.0.0:", when="@:2.2")
46
47 parallel = False
48
49 arch = "{0}-{1}".format(platform.system(), platform.processor())
50 build_targets = ["arch={0}".format(arch)]
51
52 def setup_build_environment(self, env):
53 spec = self.spec
54 if spec["mpi"].extra_attributes and "extra_link_flags" in spec["mpi"].extra_attributes:
55 env.append_flags("LIBS", spec["mpi"].extra_attributes["extra_link_flags"])
56
57 @when("@:2.2")
58 def autoreconf(self, spec, prefix):
59 # Prevent sanity check from killing the build
60 touch("configure")
61
62 @when("@:2.2")
63 def configure(self, spec, prefix):
64 # List of configuration options
65 # Order is important
66 config = []
67
68 # OpenMP support
69 if "+openmp" in spec:
70 config.append("OMP_DEFS = {0}".format(self.compiler.openmp_flag))
71
72 config.extend(
73 [
74 # Shell
75 "SHELL = /bin/sh",
76 "CD = cd",
77 "CP = cp",
78 "LN_S = ln -fs",
79 "MKDIR = mkdir -p",
80 "RM = /bin/rm -f",
81 "TOUCH = touch",
82 # Platform identifier
83 "ARCH = {0}".format(self.arch),
84 # HPL Directory Structure / HPL library
85 "TOPdir = {0}".format(os.getcwd()),
86 "INCdir = $(TOPdir)/include",
87 "BINdir = $(TOPdir)/bin/$(ARCH)",
88 "LIBdir = $(TOPdir)/lib/$(ARCH)",
89 "HPLlib = $(LIBdir)/libhpl.a",
90 # Message Passing library (MPI)
91 "MPinc = {0}".format(spec["mpi"].prefix.include),
92 "MPlib = -L{0}".format(spec["mpi"].prefix.lib),
93 # Linear Algebra library (BLAS or VSIPL)
94 "LAinc = {0}".format(spec["blas"].prefix.include),
95 "LAlib = {0}".format(spec["blas"].libs.joined()),
96 # F77 / C interface
97 "F2CDEFS = -DAdd_ -DF77_INTEGER=int -DStringSunStyle",
98 # HPL includes / libraries / specifics
99 "HPL_INCLUDES = -I$(INCdir) -I$(INCdir)/$(ARCH) " + "-I$(LAinc) -I$(MPinc)",
100 "HPL_LIBS = $(HPLlib) $(LAlib) $(MPlib)",
101 "HPL_OPTS = -DHPL_DETAILED_TIMING -DHPL_PROGRESS_REPORT",
102 "HPL_DEFS = $(F2CDEFS) $(HPL_OPTS) $(HPL_INCLUDES)",
103 # Compilers / linkers - Optimization flags
104 "CC = {0}".format(spec["mpi"].mpicc),
105 "CCNOOPT = $(HPL_DEFS)",
106 "CCFLAGS = $(HPL_DEFS) -O3",
107 "LINKER = $(CC)",
108 "LINKFLAGS = $(CCFLAGS) $(OMP_DEFS)",
109 "ARCHIVER = ar",
110 "ARFLAGS = r",
111 "RANLIB = echo",
112 ]
113 )
114
115 # Write configuration options to include file
116 with open("Make.{0}".format(self.arch), "w") as makefile:
117 for var in config:
118 makefile.write("{0}\n".format(var))
119
120 @when("@2.3:")
121 def configure_args(self):
122 filter_file(r"^libs10=.*", "libs10=%s" % self.spec["blas"].libs.ld_flags, "configure")
123
124 cc, cflags, ldflags = self.spec["mpi"].mpicc, ["-O3"], []
125 if "+openmp" in self.spec:
126 cflags.append(self.compiler.openmp_flag)
127
128 if (
129 self.spec.satisfies("^intel-mkl")
130 or self.spec.satisfies("^intel-oneapi-mkl")
131 or self.spec.satisfies("^intel-parallel-studio+mkl")
132 ):
133 ldflags.append(self.spec["blas"].libs.ld_flags)
134
135 if "%aocc" in self.spec:
136 if "%aocc@3:" in self.spec:
137 ldflags.extend(["-lamdlibm", "-lm"])
138 if "%aocc@4:" in self.spec:
139 ldflags.append("-lamdalloc")
140
141 config = [f"CC={cc}", f"CFLAGS={' '.join(cflags)}", f"LDFLAGS={' '.join(ldflags)}"]
142
143 if "+caliper" in self.spec:
144 config.append("--with-adiak={0}".format(self.spec["adiak"].prefix))
145 config.append("--with-caliper={0}".format(self.spec["caliper"].prefix))
146
147 return config
148
149 @when("@:2.2")
150 def install(self, spec, prefix):
151 # Manual installation
152 install_tree(join_path("bin", self.arch), prefix.bin)
153 install_tree(join_path("lib", self.arch), prefix.lib)
154 install_tree(join_path("include", self.arch), prefix.include)
155 install_tree("man", prefix.man)
156
157 @run_after("install")
158 def copy_dat(self):
159 if self.spec.satisfies("@2.3:"):
160 # The pre-2.3 makefile would include a default HPL.dat config
161 # file in the bin directory
162 install("./testing/ptest/HPL.dat", join_path(self.prefix.bin, "HPL.dat"))
For a benchmark without an upstream package, follow the Spack Package Creation Tutorial to create
and test its package.py.
Before adding the experiment, create its Ramble application if one is also missing.