
When clang is installed I get `clang: Permission denied`. Setting CLANG to the full path of clang fixes this. Signed-off-by: Bernhard Kaindl <bernhardkaindl7@gmail.com>
274 lines
9.3 KiB
Python
274 lines
9.3 KiB
Python
# Copyright 2013-2024 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.path
|
|
import re
|
|
import shutil
|
|
from textwrap import dedent
|
|
|
|
import llnl.util.tty as tty
|
|
|
|
from spack.package import *
|
|
|
|
|
|
class LinuxPerf(Package):
|
|
"""The Linux perf tool."""
|
|
|
|
homepage = "https://www.kernel.org/"
|
|
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.5.5.tar.xz"
|
|
|
|
executables = ["^perf$"]
|
|
|
|
maintainers("Jordan474")
|
|
|
|
version("6.9.10", sha256="efd12e335fa67d13a3eae30e4b7b7546e74b8ccc90682e4c3fffab0b22654da1")
|
|
version("6.6.41", sha256="9ec99c578158ab85d99b37791a76643d2ea4c3f72ecbef7b5eb6d60f3de032ef")
|
|
version("5.15.163", sha256="025fc7d8b1560cf456ccae50591fe1ca21c990645df9791aed25820fe78db302")
|
|
|
|
variant("libtraceevent", default=True, description="recommended dependency")
|
|
variant("python", default=True, description="Python support")
|
|
variant("perl", default=True, description="perl script extension")
|
|
variant("slang", default=True, description="TUI support")
|
|
variant("libpfm4", default=True, description="libpfm4 events extension")
|
|
variant("babeltrace", default=True, description="libbabeltrace support for CTF data format")
|
|
variant("libcap", default=True, description="process capabilities considered by perf")
|
|
variant("numactl", default=True, description="numa perf benchmark")
|
|
variant(
|
|
"libaudit",
|
|
default=False,
|
|
description=(
|
|
"get perf-trace syscall table from libaudit at runtime,"
|
|
" rather than unistd.h at buildtime"
|
|
),
|
|
)
|
|
variant("debuginfod", default=False, description="support debuginfod")
|
|
variant(
|
|
"zstd",
|
|
default=True,
|
|
description="Zstandard based runtime trace compression in record mode",
|
|
)
|
|
variant("xz", default=True, description="xz kernel module decompression")
|
|
variant(
|
|
"openssl",
|
|
default=True,
|
|
description="support generating build-ids for ELFs generated by jitdump",
|
|
)
|
|
variant("jvmti", default=False, description="build jvmti agent")
|
|
|
|
depends_on("c", type="build")
|
|
depends_on("gmake", type="build")
|
|
depends_on("pkgconfig", type="build")
|
|
depends_on("flex", type="build")
|
|
depends_on("bison", type="build")
|
|
|
|
depends_on("elfutils")
|
|
depends_on("elfutils +debuginfod", when="+debuginfod")
|
|
depends_on("libunwind components=ptrace")
|
|
depends_on("libiberty")
|
|
depends_on("binutils", type=("build", "link", "run"))
|
|
depends_on("zlib-api")
|
|
|
|
depends_on("libtraceevent", when="+libtraceevent")
|
|
|
|
# jevents requires python >= 3.6
|
|
depends_on("python@3.6:", type=("build", "link", "run"), when="+python")
|
|
depends_on("py-setuptools", type="build", when="+python")
|
|
depends_on("perl", when="+perl")
|
|
depends_on("slang", when="+slang")
|
|
depends_on("libpfm4", when="+libpfm4")
|
|
depends_on("babeltrace@1.5:", when="+babeltrace")
|
|
depends_on("libcap", when="+libcap")
|
|
depends_on("audit-userspace", when="+libaudit")
|
|
depends_on("numactl", when="+numactl")
|
|
depends_on("zstd", when="+zstd")
|
|
depends_on("xz", when="+xz")
|
|
depends_on("openssl", when="+openssl")
|
|
depends_on("openssl@1.1:", when="@5.19: +openssl")
|
|
depends_on("java", when="+jvmti")
|
|
|
|
depends_on("asciidoc", type="build")
|
|
depends_on("xmlto", type="build")
|
|
|
|
conflicts(
|
|
"~libtraceevent",
|
|
when="@6.2:",
|
|
msg="linux 6.2 removed internal libtraceevent, and it's highly recommended",
|
|
)
|
|
|
|
def url_for_version(self, version):
|
|
return f"https://cdn.kernel.org/pub/linux/kernel/v{version[0]}.x/linux-{version}.tar.xz"
|
|
|
|
def setup_build_environment(self, env):
|
|
# This variable is used in the Makefile. If it is defined on the
|
|
# system, it can break the build if there is no build recipe for
|
|
# that specific ARCH
|
|
env.unset("ARCH")
|
|
|
|
@property
|
|
def archive_files(self):
|
|
return [join_path(self.stage.source_path, "tools/perf/FEATURE-DUMP")]
|
|
|
|
def install(self, spec, prefix):
|
|
# TODO:
|
|
# - GTK2=
|
|
# - NO_LIBBPF=1 ?
|
|
# - d3 flamegraph resources (libexec/perf-core/scripts/python/flamegraph.py)
|
|
|
|
version = self.spec.version
|
|
|
|
args = [
|
|
"LIBDW_DIR={}".format(spec["elfutils"].prefix),
|
|
"LIBUNWIND_DIR={}".format(spec["libunwind"].prefix),
|
|
"NO_SHELLCHECK=1",
|
|
]
|
|
|
|
# Setup clang if found in the system's or env's PATH:
|
|
clang = shutil.which("clang")
|
|
if clang:
|
|
args.append("CLANG=" + clang)
|
|
|
|
# Features to check post-install against `perf version --build-options`
|
|
checks = {"dwarf", "libunwind", "libbfd", "zlib"}
|
|
|
|
if version >= Version("6.4"):
|
|
args.append("BUILD_NONDISTRO=1")
|
|
|
|
if "+libaudit" in spec:
|
|
checks.add("libaudit")
|
|
args.append("NO_SYSCALL_TABLE=1") # will look for libaudit
|
|
else:
|
|
checks.add("syscall_table")
|
|
args.append("NO_LIBAUDIT=1")
|
|
|
|
if "+debuginfod" in spec:
|
|
if version >= Version("5.19"): # Not in --build-options before that
|
|
checks.add("debuginfod")
|
|
else:
|
|
args.append("NO_LIBDEBUGINFOD=1")
|
|
|
|
if "+python" in spec:
|
|
checks.add("libpython")
|
|
args.extend(
|
|
[
|
|
"PYTHON={}".format(spec["python"].command),
|
|
"PYTHON_CONFIG={}".format(spec["python"].prefix.bin.join("python-config")),
|
|
]
|
|
)
|
|
else:
|
|
args.append("NO_LIBPYTHON=1")
|
|
|
|
if "+perl" in spec:
|
|
checks.add("libperl")
|
|
else:
|
|
args.append("NO_LIBPERL=1")
|
|
|
|
if "+openssl" in spec:
|
|
checks.add("libcrypto")
|
|
else:
|
|
args.append("NO_LIBCRYPTO=1")
|
|
|
|
if "+slang" in spec:
|
|
checks.add("libslang")
|
|
else:
|
|
args.append("NO_SLANG=1")
|
|
|
|
if "+libpfm4" in spec:
|
|
checks.add("libpfm4")
|
|
if version < Version("6.4"):
|
|
args.append("LIBPFM4=1")
|
|
else:
|
|
if version >= Version("6.4"):
|
|
args.append("NO_LIBPFM4=1")
|
|
|
|
if "+babeltrace" in spec:
|
|
# checks.add("babeltrace") # Not in --build-options ?
|
|
args.append("LIBBABELTRACE_DIR={}".format(spec["babeltrace"].prefix))
|
|
else:
|
|
args.append("NO_LIBBABELTRACE=1")
|
|
|
|
if "+libcap" in spec:
|
|
# checks.add("libcap") # Not in --build-options ?
|
|
pass
|
|
else:
|
|
args.append("NO_LIBCAP=1")
|
|
|
|
if "+numactl" in spec:
|
|
checks.add("libnuma")
|
|
else:
|
|
args.append("NO_LIBNUMA=1")
|
|
|
|
if "+xz" in spec:
|
|
checks.add("lzma")
|
|
else:
|
|
args.append("NO_LZMA=1")
|
|
|
|
if "+zstd" in spec:
|
|
checks.add("zstd")
|
|
args.append("LIBZSTD_DIR={}".format(spec["zstd"].prefix))
|
|
else:
|
|
args.append("NO_LIBZSTD=1")
|
|
|
|
if "+libtraceevent" in spec:
|
|
if version >= Version("6.2"): # Not in --build-options before that
|
|
checks.add("libtraceevent")
|
|
if version >= Version("6.10"):
|
|
args.append("LIBTRACEEVENT_DIR={}".format(spec["libtraceevent"].prefix))
|
|
if version < Version("6.2"):
|
|
args.append("LIBTRACEEVENT_DYNAMIC=1")
|
|
else:
|
|
if version >= Version("6.2"):
|
|
args.append("NO_LIBTRACEEVENT=1")
|
|
|
|
if "+jvmti" in spec:
|
|
# checks.add("jvmti") # Not in --build-options ?
|
|
args.append("JDIR={}".format(spec["java"].prefix))
|
|
else:
|
|
args.append("NO_JVMTI=1")
|
|
|
|
with working_dir("tools/perf"):
|
|
make(
|
|
"V=1",
|
|
f"JOBS={make_jobs}",
|
|
f"prefix={prefix}",
|
|
"DESTDIR=",
|
|
*args,
|
|
"all",
|
|
"install",
|
|
parallel=False,
|
|
)
|
|
|
|
# Create a perfconfig with binutils paths
|
|
perfconfig = str(prefix.join("etc/perfconfig"))
|
|
assert not os.path.exists(perfconfig)
|
|
mkdirp(os.path.dirname(perfconfig))
|
|
with open(perfconfig, "w") as f:
|
|
f.write(
|
|
dedent(
|
|
"""\
|
|
[annotate]
|
|
addr2line = {addr2line}
|
|
objdump = {objdump}
|
|
"""
|
|
).format(
|
|
addr2line=spec["binutils"].prefix.bin.join("addr2line"),
|
|
objdump=spec["binutils"].prefix.bin.join("objdump"),
|
|
)
|
|
)
|
|
|
|
# Post-install dependency check:
|
|
# $ perf version --build-options
|
|
# perf version 6.5.7
|
|
# dwarf: [ on ] # HAVE_DWARF_SUPPORT
|
|
# ...
|
|
perf = Executable(self.prefix.bin.perf)
|
|
output = perf("version", "--build-options", output=str, error=str)
|
|
tty.msg(output) # keep a trace in build log
|
|
enabled = set(re.findall(r"^\s*(\S+)\s*:\s*\[\s*on\s*\]", output, re.MULTILINE))
|
|
missing = set(checks) - enabled
|
|
tty.msg(f"detected features: {sorted(enabled)!r}")
|
|
tty.msg(f"expected features: {sorted(checks)!r}")
|
|
if missing:
|
|
raise InstallError(f"Perf is missing features {sorted(missing)!r}, see log")
|