hpctoolkit: Add build_system=meson
(#42059)
HPCToolkit `develop` now can optionally be built via Meson. This PR adds the `build_system=(autotools|meson)` variant and splits the build-system-dependent pieces into `AutotoolsBuilder` and `MesonBuilder`. The default is to build with `autotools`. As of writing, the Meson is simply a wrapper around the original Autotools build, hence the build requires a native file listing install prefixes of all dependencies (which are internally mapped to `--with-{pkg}={prefix}` arguments for `./configure`). This is an unconventional but temporary state of affairs until the build system is fully ported to Meson and conventional dependency acquisition techniques like `pkg-config` and `cmake` are practically available.
This commit is contained in:
parent
acbf0d99c4
commit
61421b3a67
@ -3,14 +3,16 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||||
|
|
||||||
|
import configparser
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
from spack.package import *
|
from spack.package import *
|
||||||
|
|
||||||
|
|
||||||
class Hpctoolkit(AutotoolsPackage):
|
class Hpctoolkit(AutotoolsPackage, MesonPackage):
|
||||||
"""HPCToolkit is an integrated suite of tools for measurement and analysis
|
"""HPCToolkit is an integrated suite of tools for measurement and analysis
|
||||||
of program performance on computers ranging from multicore desktop systems
|
of program performance on computers ranging from multicore desktop systems
|
||||||
to the nation's largest supercomputers. By using statistical sampling of
|
to the nation's largest supercomputers. By using statistical sampling of
|
||||||
@ -57,13 +59,14 @@ class Hpctoolkit(AutotoolsPackage):
|
|||||||
"cray",
|
"cray",
|
||||||
default=False,
|
default=False,
|
||||||
description="Build hpcprof-mpi for Cray systems (may require --dirty).",
|
description="Build hpcprof-mpi for Cray systems (may require --dirty).",
|
||||||
|
when="build_system=autotools",
|
||||||
)
|
)
|
||||||
|
|
||||||
variant(
|
variant(
|
||||||
"cray-static",
|
"cray-static",
|
||||||
default=False,
|
default=False,
|
||||||
description="Build old rev of hpcprof-mpi statically on Cray systems.",
|
description="Build old rev of hpcprof-mpi statically on Cray systems.",
|
||||||
when="@:2022.09+cray",
|
when="@:2022.09+cray build_system=autotools",
|
||||||
)
|
)
|
||||||
|
|
||||||
variant(
|
variant(
|
||||||
@ -104,18 +107,33 @@ class Hpctoolkit(AutotoolsPackage):
|
|||||||
variant("rocm", default=False, description="Support ROCM on AMD GPUs.", when="@2022.04:")
|
variant("rocm", default=False, description="Support ROCM on AMD GPUs.", when="@2022.04:")
|
||||||
|
|
||||||
# Other variants.
|
# Other variants.
|
||||||
variant("debug", default=False, description="Build in debug (develop) mode.")
|
variant(
|
||||||
|
"debug",
|
||||||
|
default=False,
|
||||||
|
description="Build in debug (develop) mode.",
|
||||||
|
when="build_system=autotools",
|
||||||
|
)
|
||||||
variant("viewer", default=True, description="Include hpcviewer.")
|
variant("viewer", default=True, description="Include hpcviewer.")
|
||||||
|
|
||||||
variant(
|
variant(
|
||||||
"python", default=False, description="Support unwinding Python source.", when="@2023.03:"
|
"python", default=False, description="Support unwinding Python source.", when="@2023.03:"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
build_system(conditional("meson", when="@develop"), "autotools", default="autotools")
|
||||||
|
|
||||||
with when("@develop build_system=autotools"):
|
with when("@develop build_system=autotools"):
|
||||||
depends_on("autoconf", type="build")
|
depends_on("autoconf", type="build")
|
||||||
depends_on("automake", type="build")
|
depends_on("automake", type="build")
|
||||||
depends_on("libtool", type="build")
|
depends_on("libtool", type="build")
|
||||||
|
|
||||||
|
with when("build_system=meson"):
|
||||||
|
depends_on("meson@1.1.0:", type="build")
|
||||||
|
depends_on("gmake", type="build")
|
||||||
|
depends_on("m4", type="build")
|
||||||
|
depends_on("autoconf", type="build")
|
||||||
|
depends_on("automake", type="build")
|
||||||
|
depends_on("libtool", type="build")
|
||||||
|
|
||||||
boost_libs = (
|
boost_libs = (
|
||||||
"+atomic +chrono +date_time +filesystem +system +thread +timer"
|
"+atomic +chrono +date_time +filesystem +system +thread +timer"
|
||||||
" +graph +regex +shared +multithreaded visibility=global"
|
" +graph +regex +shared +multithreaded visibility=global"
|
||||||
@ -201,8 +219,41 @@ def patch(self):
|
|||||||
if os.access("hpcrun-fmt.txt", os.F_OK):
|
if os.access("hpcrun-fmt.txt", os.F_OK):
|
||||||
os.rename("hpcrun-fmt.txt", "hpcrun-fmt.readme")
|
os.rename("hpcrun-fmt.txt", "hpcrun-fmt.readme")
|
||||||
|
|
||||||
flag_handler = AutotoolsPackage.build_system_flags
|
# We only want hpctoolkit and hpcviewer paths and man paths in the
|
||||||
|
# module file. The run dependencies are all curried into hpctoolkit
|
||||||
|
# and we don't want to risk exposing a package if the application
|
||||||
|
# uses a different version of the same package.
|
||||||
|
def setup_run_environment(self, env):
|
||||||
|
spec = self.spec
|
||||||
|
env.clear()
|
||||||
|
env.prepend_path("PATH", spec.prefix.bin)
|
||||||
|
env.prepend_path("MANPATH", spec.prefix.share.man)
|
||||||
|
env.prepend_path("CPATH", spec.prefix.include)
|
||||||
|
env.prepend_path("LD_LIBRARY_PATH", spec.prefix.lib.hpctoolkit)
|
||||||
|
if "+viewer" in spec:
|
||||||
|
env.prepend_path("PATH", spec["hpcviewer"].prefix.bin)
|
||||||
|
env.prepend_path("MANPATH", spec["hpcviewer"].prefix.share.man)
|
||||||
|
|
||||||
|
def test_sort(self):
|
||||||
|
"""build and run selection sort unit test"""
|
||||||
|
exe = "tst-sort"
|
||||||
|
cxx = which(os.environ["CXX"])
|
||||||
|
cxx(self.test_suite.current_test_data_dir.join("sort.cpp"), "-o", exe)
|
||||||
|
|
||||||
|
hpcrun = which("hpcrun")
|
||||||
|
meas = "tst-sort.m"
|
||||||
|
hpcrun("-e", "REALTIME@5000", "-t", "-o", meas, "./" + exe)
|
||||||
|
|
||||||
|
hpcstruct = which("hpcstruct")
|
||||||
|
struct = "tst-sort.hpcstruct"
|
||||||
|
hpcstruct("-j", "4", "--time", "-o", struct, "./" + exe)
|
||||||
|
|
||||||
|
hpcprof = which("hpcprof")
|
||||||
|
db = "tst-sort.d"
|
||||||
|
hpcprof("-S", struct, "-o", db, meas)
|
||||||
|
|
||||||
|
|
||||||
|
class AutotoolsBuilder(spack.build_systems.autotools.AutotoolsBuilder):
|
||||||
def configure_args(self):
|
def configure_args(self):
|
||||||
spec = self.spec
|
spec = self.spec
|
||||||
|
|
||||||
@ -293,29 +344,14 @@ def configure_args(self):
|
|||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
# We only want hpctoolkit and hpcviewer paths and man paths in the
|
flag_handler = AutotoolsPackage.build_system_flags
|
||||||
# module file. The run dependencies are all curried into hpctoolkit
|
|
||||||
# and we don't want to risk exposing a package if the application
|
|
||||||
# uses a different version of the same package.
|
|
||||||
def setup_run_environment(self, env):
|
|
||||||
spec = self.spec
|
|
||||||
env.clear()
|
|
||||||
env.prepend_path("PATH", spec.prefix.bin)
|
|
||||||
env.prepend_path("MANPATH", spec.prefix.share.man)
|
|
||||||
env.prepend_path("CPATH", spec.prefix.include)
|
|
||||||
env.prepend_path("LD_LIBRARY_PATH", spec.prefix.lib.hpctoolkit)
|
|
||||||
if "+viewer" in spec:
|
|
||||||
env.prepend_path("PATH", spec["hpcviewer"].prefix.bin)
|
|
||||||
env.prepend_path("MANPATH", spec["hpcviewer"].prefix.share.man)
|
|
||||||
|
|
||||||
# Build tests (spack install --run-tests). Disable the default
|
# Build tests (spack install --run-tests). Disable the default
|
||||||
# spack tests and run autotools 'make check', but only from the
|
# spack tests and run autotools 'make check', but only from the
|
||||||
# tests directory.
|
# tests directory.
|
||||||
build_time_test_callbacks = [] # type: List[str]
|
build_time_test_callbacks = [] # type: List[str]
|
||||||
install_time_test_callbacks = [] # type: List[str]
|
install_time_test_callbacks = ["check_install"] # type: List[str]
|
||||||
|
|
||||||
@run_after("install")
|
|
||||||
@on_package_attributes(run_tests=True)
|
|
||||||
def check_install(self):
|
def check_install(self):
|
||||||
if not self.spec.satisfies("@2022:"):
|
if not self.spec.satisfies("@2022:"):
|
||||||
tty.warn("requires 2022.01.15 or later")
|
tty.warn("requires 2022.01.15 or later")
|
||||||
@ -324,25 +360,80 @@ def check_install(self):
|
|||||||
with working_dir("tests"):
|
with working_dir("tests"):
|
||||||
make("check")
|
make("check")
|
||||||
|
|
||||||
# Post-Install tests (spack test run). These are the same tests
|
|
||||||
# but with a different Makefile that works outside the build
|
|
||||||
# directory.
|
|
||||||
@run_after("install")
|
|
||||||
def copy_test_files(self):
|
|
||||||
if self.spec.satisfies("@2022:"):
|
|
||||||
self.cache_extra_test_sources(["tests"])
|
|
||||||
|
|
||||||
def test_run_sort(self):
|
class MesonBuilder(spack.build_systems.meson.MesonBuilder):
|
||||||
"""build and run selection sort unit test"""
|
def meson_args(self):
|
||||||
if not self.spec.satisfies("@2022:"):
|
spec = self.spec
|
||||||
raise SkipTest("No tests exist for versions prior to 2022.01.15")
|
|
||||||
|
|
||||||
test_dir = self.test_suite.current_test_cache_dir.tests
|
args = [
|
||||||
with working_dir(test_dir):
|
"-Dhpcprof_mpi=" + ("enabled" if "+mpi" in spec else "disabled"),
|
||||||
make = which("make")
|
"-Dpython=" + ("enabled" if "+python" in spec else "disabled"),
|
||||||
make("-f", "Makefile.spack", "all")
|
"-Dpapi=" + ("enabled" if "+papi" in spec else "disabled"),
|
||||||
|
"-Dopencl=" + ("enabled" if "+opencl" in spec else "disabled"),
|
||||||
|
"-Dcuda=" + ("enabled" if "+cuda" in spec else "disabled"),
|
||||||
|
"-Drocm=" + ("enabled" if "+rocm" in spec else "disabled"),
|
||||||
|
"-Dlevel0=" + ("enabled" if "+level_zero" in spec else "disabled"),
|
||||||
|
"-Dgtpin=" + ("enabled" if "+gtpin" in spec else "disabled"),
|
||||||
|
]
|
||||||
|
|
||||||
run_sort = which(join_path(".", "run-sort"))
|
# We use a native file to provide paths to all the dependencies.
|
||||||
assert run_sort, "run-sort is missing"
|
cfg = configparser.ConfigParser()
|
||||||
|
cfg["properties"] = {}
|
||||||
|
cfg["binaries"] = {}
|
||||||
|
|
||||||
run_sort()
|
cfg["properties"]["prefix_boost"] = f"'''{spec['boost'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_bzip"] = f"'''{spec['bzip2'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_dyninst"] = f"'''{spec['dyninst'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_elfutils"] = f"'''{spec['elfutils'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_tbb"] = f"'''{spec['intel-tbb'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_libmonitor"] = f"'''{spec['libmonitor'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_libunwind"] = f"'''{spec['libunwind'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_xerces"] = f"'''{spec['xerces-c'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_lzma"] = f"'''{spec['xz'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_zlib"] = f"'''{spec['zlib-api'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_libiberty"] = f"'''{spec['libiberty'].prefix}'''"
|
||||||
|
|
||||||
|
if spec.target.family == "x86_64":
|
||||||
|
cfg["properties"]["prefix_xed"] = f"'''{spec['intel-xed'].prefix}'''"
|
||||||
|
|
||||||
|
cfg["properties"]["prefix_memkind"] = f"'''{spec['memkind'].prefix}'''"
|
||||||
|
|
||||||
|
if spec.satisfies("+papi"):
|
||||||
|
cfg["properties"]["prefix_papi"] = f"'''{spec['papi'].prefix}'''"
|
||||||
|
else:
|
||||||
|
cfg["properties"]["prefix_perfmon"] = f"'''{spec['libpfm4'].prefix}'''"
|
||||||
|
|
||||||
|
cfg["properties"]["prefix_yaml_cpp"] = f"'''{spec['yaml-cpp'].prefix}'''"
|
||||||
|
|
||||||
|
if "+cuda" in spec:
|
||||||
|
cfg["properties"]["prefix_cuda"] = f"'''{spec['cuda'].prefix}'''"
|
||||||
|
|
||||||
|
if "+level_zero" in spec:
|
||||||
|
cfg["properties"]["prefix_level0"] = f"'''{spec['oneapi-level-zero'].prefix}'''"
|
||||||
|
|
||||||
|
if "+gtpin" in spec:
|
||||||
|
cfg["properties"]["prefix_gtpin"] = f"'''{spec['intel-gtpin'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_igc"] = f"'''{spec['oneapi-igc'].prefix}'''"
|
||||||
|
|
||||||
|
if "+opencl" in spec:
|
||||||
|
cfg["properties"]["prefix_opencl"] = f"'''{spec['opencl-c-headers'].prefix}'''"
|
||||||
|
|
||||||
|
if "+rocm" in spec:
|
||||||
|
cfg["properties"]["prefix_rocm_hip"] = f"'''{spec['hip'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_rocm_hsa"] = f"'''{spec['hsa-rocr-dev'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_rocm_tracer"] = f"'''{spec['roctracer-dev'].prefix}'''"
|
||||||
|
cfg["properties"]["prefix_rocm_profiler"] = f"'''{spec['rocprofiler-dev'].prefix}'''"
|
||||||
|
|
||||||
|
if "+python" in spec:
|
||||||
|
cfg["binaries"]["python"] = f"'''{spec['python'].command}'''"
|
||||||
|
|
||||||
|
if "+mpi" in spec:
|
||||||
|
cfg["binaries"]["mpicxx"] = f"'''{spec['mpi'].mpicxx}'''"
|
||||||
|
|
||||||
|
native_fd, native_path = tempfile.mkstemp(
|
||||||
|
prefix="spack-native.", suffix=".ini", dir=self.stage.path
|
||||||
|
)
|
||||||
|
with os.fdopen(native_fd, "w") as native_f:
|
||||||
|
cfg.write(native_f)
|
||||||
|
|
||||||
|
return ["--native-file", native_path] + args
|
||||||
|
54
var/spack/repos/builtin/packages/hpctoolkit/test/sort.cpp
Normal file
54
var/spack/repos/builtin/packages/hpctoolkit/test/sort.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// Copyright (c) 2002-2023, Rice University.
|
||||||
|
// See the file LICENSE for details.
|
||||||
|
//
|
||||||
|
// Simple selection sort, shows a couple of loops, some C++
|
||||||
|
// templates.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
typedef list <long> llist;
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
llist olist, nlist;
|
||||||
|
long n, N, sum;
|
||||||
|
|
||||||
|
N = 80000;
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
N = atol(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for (n = 1; n <= N; n += 2) {
|
||||||
|
olist.push_front(n);
|
||||||
|
olist.push_back(n + 1);
|
||||||
|
sum += 2 * n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "orig list: " << N << " " << sum << endl;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
while (olist.size() > 0) {
|
||||||
|
auto min = olist.begin();
|
||||||
|
|
||||||
|
for (auto it = olist.begin(); it != olist.end(); ++it) {
|
||||||
|
if (*it < *min) {
|
||||||
|
min = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sum += *min;
|
||||||
|
nlist.push_back(*min);
|
||||||
|
olist.erase(min);
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "new list: " << N << " " << sum << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user