diff --git a/workloads/linux/spec2017/build.sh b/workloads/linux/spec2017/build.sh index 24c330a..486ba38 100755 --- a/workloads/linux/spec2017/build.sh +++ b/workloads/linux/spec2017/build.sh @@ -1,12 +1,16 @@ #!/usr/bin/env bash set -euo pipefail +: "${WORKLOAD_BUILD_DIR:?WORKLOAD_BUILD_DIR is required}" : "${SPEC2017_CASE:?SPEC2017_CASE is required}" : "${SPEC2017:?SPEC2017 is required}" : "${SPEC2017_CFG:?SPEC2017_CFG is required}" : "${CROSS_COMPILE:=riscv64-unknown-linux-gnu-}" : "${SPEC2017_TUNE:=base}" : "${SPEC2017_JOBS:=$(nproc)}" +: "${SPEC2017_JEMALLOC_REPO:=https://github.com/jemalloc/jemalloc.git}" +: "${SPEC2017_JEMALLOC_COMMIT:=1a15fe33a48c52bfe26ea83e49f0d317a47da3ea}" +: "${SPEC2017_DOWNLOAD_RETRIES:=3}" : "${SPEC2017_ELF_ONLY:=false}" : "${SPEC2017_ALL_RUNS:=false}" : "${SPEC2017_PROFILING:=1}" @@ -14,8 +18,105 @@ set -euo pipefail : "${SPEC2017_LOG_DIR:=$WORKLOAD_BUILD_DIR/logs}" : "${PKG_DIR:=$WORKLOAD_BUILD_DIR/package}" +SPEC2017_JEMALLOC_ROOT="${SPEC2017_JEMALLOC_ROOT:-${JEMALLOC_INSTALL_PATH:-}}" +jemalloc_root_is_explicit=0 +if [ -n "$SPEC2017_JEMALLOC_ROOT" ]; then + jemalloc_root_is_explicit=1 +fi + +jemalloc_lock_dir="" +cleanup() { + if [ -n "$jemalloc_lock_dir" ]; then + rmdir "$jemalloc_lock_dir" 2>/dev/null || true + fi +} +trap cleanup EXIT + mkdir -p "$SPEC2017_LOG_DIR" +spec2017_progress_prefix() { + local k="${SPEC2017_PROGRESS_K:-1}" + local n="${SPEC2017_PROGRESS_N:-1}" + printf '[spec2017 %s/%s]' "$k" "$n" +} + +status() { + printf '%s %s\n' "$(spec2017_progress_prefix)" "$*" +} + +show_log_tail() { + local log_file="$1" + if [ -f "$log_file" ]; then + echo "$(spec2017_progress_prefix) Last 40 lines from $log_file:" >&2 + tail -n 40 "$log_file" >&2 || true + fi +} + +retry() { + local attempt=1 + while true; do + if "$@"; then + return 0 + fi + if [ "$attempt" -ge "$SPEC2017_DOWNLOAD_RETRIES" ]; then + return 1 + fi + printf '%s Retrying failed command (%s/%s): %s\n' \ + "$(spec2017_progress_prefix)" \ + "$attempt" \ + "$SPEC2017_DOWNLOAD_RETRIES" \ + "$*" >&2 + sleep $((attempt * 2)) + attempt=$((attempt + 1)) + done +} + +retry_git_clone() { + local repo="$1" + local dest="$2" + local attempt=1 + while true; do + rm -rf "$dest" + if git clone "$repo" "$dest"; then + return 0 + fi + if [ "$attempt" -ge "$SPEC2017_DOWNLOAD_RETRIES" ]; then + return 1 + fi + printf '%s Retrying failed git clone (%s/%s): %s\n' \ + "$(spec2017_progress_prefix)" \ + "$attempt" \ + "$SPEC2017_DOWNLOAD_RETRIES" \ + "$repo" >&2 + sleep $((attempt * 2)) + attempt=$((attempt + 1)) + done +} + +prepare_git_checkout() { + local repo="$1" + local commit="$2" + local dest="$3" + local current_commit target_commit + + if [ ! -d "$dest/.git" ]; then + retry_git_clone "$repo" "$dest" + else + git -C "$dest" remote set-url origin "$repo" + fi + + if ! git -C "$dest" cat-file -e "$commit^{commit}" 2>/dev/null; then + retry git -C "$dest" fetch --tags origin + fi + + current_commit="$(git -C "$dest" rev-parse HEAD 2>/dev/null || true)" + target_commit="$(git -C "$dest" rev-parse "$commit")" + if [ "$current_commit" != "$target_commit" ]; then + git -C "$dest" checkout --detach "$commit" + git -C "$dest" clean -ffdx + fi +} + is_true() { case "$1" in 1|true|yes|on) return 0 ;; @@ -23,6 +124,129 @@ is_true() { esac } +cfg_requires_jemalloc() { + grep -Eq 'JEMALLOC_PATH|-ljemalloc' "$SPEC2017_CFG" +} + +resolve_jemalloc_root() { + if [ -n "$SPEC2017_JEMALLOC_ROOT" ]; then + realpath -m "$SPEC2017_JEMALLOC_ROOT" + else + realpath -m "$(dirname "$WORKLOAD_BUILD_DIR")/jemalloc/install" + fi +} + +resolve_jemalloc_host() { + if [ -n "${SPEC2017_JEMALLOC_CONFIGURE_HOST:-}" ]; then + printf '%s\n' "$SPEC2017_JEMALLOC_CONFIGURE_HOST" + else + "${CROSS_COMPILE}gcc" -dumpmachine + fi +} + +jemalloc_cache_metadata() { + local host="$1" + printf '%s\n' \ + "repo=$SPEC2017_JEMALLOC_REPO" \ + "commit=$SPEC2017_JEMALLOC_COMMIT" \ + "cross_compile=$CROSS_COMPILE" \ + "host=$host" +} + +jemalloc_cache_is_current() { + local prefix="$1" + local host="$2" + local metadata_file="$prefix/.workload-builder-jemalloc-meta" + + if [ ! -f "$prefix/lib/libjemalloc.a" ]; then + return 1 + fi + if [ "$jemalloc_root_is_explicit" = 1 ]; then + return 0 + fi + [ -f "$metadata_file" ] && [ "$(cat "$metadata_file")" = "$(jemalloc_cache_metadata "$host")" ] +} + +prepare_jemalloc() { + local base_dir source_dir prefix host log_file rc + base_dir="$(realpath -m "$(dirname "$WORKLOAD_BUILD_DIR")/jemalloc")" + source_dir="$base_dir/source" + prefix="$(resolve_jemalloc_root)" + host="$(resolve_jemalloc_host)" + log_file="$base_dir/build.log" + + if jemalloc_cache_is_current "$prefix" "$host"; then + SPEC2017_JEMALLOC_ROOT="$prefix" + export SPEC2017_JEMALLOC_ROOT + status "Using cached jemalloc: $prefix" + return + fi + + jemalloc_lock_dir="$base_dir/.lock" + mkdir -p "$base_dir" + while ! mkdir "$jemalloc_lock_dir" 2>/dev/null; do + sleep 1 + done + + if jemalloc_cache_is_current "$prefix" "$host"; then + rmdir "$jemalloc_lock_dir" + jemalloc_lock_dir="" + SPEC2017_JEMALLOC_ROOT="$prefix" + export SPEC2017_JEMALLOC_ROOT + status "Using cached jemalloc: $prefix" + return + fi + + status "Preparing jemalloc (log: $log_file)" + : > "$log_file" + + rc=0 + set +e + ( + set -euo pipefail + echo "# jemalloc repo: $SPEC2017_JEMALLOC_REPO" + echo "# jemalloc commit: $SPEC2017_JEMALLOC_COMMIT" + echo "# install prefix: $prefix" + echo "# configure host: $host" + prepare_git_checkout "$SPEC2017_JEMALLOC_REPO" "$SPEC2017_JEMALLOC_COMMIT" "$source_dir" + + cd "$source_dir" + CC="${CROSS_COMPILE}gcc" \ + CXX="${CROSS_COMPILE}g++" \ + AR="${CROSS_COMPILE}ar" \ + LD="${CROSS_COMPILE}ld" \ + RANLIB="${CROSS_COMPILE}ranlib" \ + STRIP="${CROSS_COMPILE}strip" \ + ./autogen.sh --prefix="$prefix" --host="$host" + make -j"$SPEC2017_JOBS" + make install + ) >>"$log_file" 2>&1 + rc=$? + set -e + + if [ "$rc" -ne 0 ]; then + echo "$(spec2017_progress_prefix) jemalloc build failed; see $log_file" >&2 + show_log_tail "$log_file" + return 1 + fi + if [ ! -f "$prefix/lib/libjemalloc.a" ]; then + echo "$(spec2017_progress_prefix) jemalloc install did not produce $prefix/lib/libjemalloc.a" >&2 + return 1 + fi + jemalloc_cache_metadata "$host" > "$prefix/.workload-builder-jemalloc-meta" + + rmdir "$jemalloc_lock_dir" + jemalloc_lock_dir="" + + SPEC2017_JEMALLOC_ROOT="$prefix" + export SPEC2017_JEMALLOC_ROOT + status "jemalloc ready: $prefix" +} + +if cfg_requires_jemalloc; then + prepare_jemalloc +fi + python_args=() if is_true "$SPEC2017_ELF_ONLY"; then python_args+=(--elf-only) @@ -40,6 +264,7 @@ python3 "$WORKLOAD_DIR/spec2017-package.py" \ --cross-compile "$CROSS_COMPILE" \ --compiler-root "${SPEC2017_COMPILER_ROOT:-}" \ --gnu-toolchain-root "${SPEC2017_GNU_TOOLCHAIN_ROOT:-}" \ + --jemalloc-root "${SPEC2017_JEMALLOC_ROOT:-}" \ --log-dir "$SPEC2017_LOG_DIR" \ --tune "$SPEC2017_TUNE" \ --jobs "$SPEC2017_JOBS" \ diff --git a/workloads/linux/spec2017/configs/riscv-gcc15.cfg b/workloads/linux/spec2017/configs/riscv-gcc15.cfg index 5bd3078..6317666 100644 --- a/workloads/linux/spec2017/configs/riscv-gcc15.cfg +++ b/workloads/linux/spec2017/configs/riscv-gcc15.cfg @@ -19,6 +19,10 @@ ignore_errors = 1 default: SPECLANG = %{ENV_CROSS_COMPILE} +JEMALLOC_PATH = ${JEMALLOC_INSTALL_PATH} +JEMALLOC_LIBS = -L$(JEMALLOC_PATH)/lib -ljemalloc -lm +STATIC_LDFLAGS = -z muldefs -static + intspeed,fpspeed,intrate,fprate: CC = $(SPECLANG)gcc -std=c99 CXX = $(SPECLANG)g++ -std=c++03 @@ -104,29 +108,29 @@ intspeed=base=default: COPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) fpspeed=base=default: COPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) intrate=base=default: COPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) fprate=base=default: COPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) intrate,intspeed,fpspeed,fprate: sw_compiler001 = RISC-V GCC cross compiler diff --git a/workloads/linux/spec2017/configs/riscv-gcc16-rva23u64-novec.cfg b/workloads/linux/spec2017/configs/riscv-gcc16-rva23u64-novec.cfg index 5151f3c..5e618d7 100644 --- a/workloads/linux/spec2017/configs/riscv-gcc16-rva23u64-novec.cfg +++ b/workloads/linux/spec2017/configs/riscv-gcc16-rva23u64-novec.cfg @@ -19,6 +19,10 @@ ignore_errors = 1 default: SPECLANG = %{ENV_CROSS_COMPILE} +JEMALLOC_PATH = ${JEMALLOC_INSTALL_PATH} +JEMALLOC_LIBS = -L$(JEMALLOC_PATH)/lib -ljemalloc -lm +STATIC_LDFLAGS = -z muldefs -static + intspeed,fpspeed,intrate,fprate: CC = $(SPECLANG)gcc -std=c99 CXX = $(SPECLANG)g++ -std=c++03 @@ -105,29 +109,29 @@ intspeed=base=default: COPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=$(MARCH) -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=$(MARCH) -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=$(MARCH) -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) fpspeed=base=default: COPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=$(MARCH) -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=$(MARCH) -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=$(MARCH) -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) intrate=base=default: COPTIMIZE = -O3 -flto -ffast-math -march=$(MARCH) -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -march=$(MARCH) -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -march=$(MARCH) -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) fprate=base=default: COPTIMIZE = -O3 -flto -ffast-math -march=$(MARCH) -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -march=$(MARCH) -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -march=$(MARCH) -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) intrate,intspeed,fpspeed,fprate: sw_compiler001 = RISC-V GCC cross compiler diff --git a/workloads/linux/spec2017/configs/riscv-gcc16.cfg b/workloads/linux/spec2017/configs/riscv-gcc16.cfg index 70967d3..a0d2099 100644 --- a/workloads/linux/spec2017/configs/riscv-gcc16.cfg +++ b/workloads/linux/spec2017/configs/riscv-gcc16.cfg @@ -19,6 +19,10 @@ ignore_errors = 1 default: SPECLANG = %{ENV_CROSS_COMPILE} +JEMALLOC_PATH = ${JEMALLOC_INSTALL_PATH} +JEMALLOC_LIBS = -L$(JEMALLOC_PATH)/lib -ljemalloc -lm +STATIC_LDFLAGS = -z muldefs -static + intspeed,fpspeed,intrate,fprate: CC = $(SPECLANG)gcc -std=c99 CXX = $(SPECLANG)g++ -std=c++03 @@ -104,29 +108,29 @@ intspeed=base=default: COPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) fpspeed=base=default: COPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -fopenmp -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) intrate=base=default: COPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=off -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) fprate=base=default: COPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing CXXOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing FOPTIMIZE = -O3 -flto -ffast-math -march=rv64gc_zba_zbb_zbc_zbs -ffp-contract=fast -fno-tree-vectorize -fno-tree-loop-vectorize -fno-strict-aliasing -fallow-argument-mismatch - EXTRA_LIBS = -lpthread -lm - EXTRA_LDFLAGS = -static + EXTRA_LIBS = -lpthread $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = $(STATIC_LDFLAGS) intrate,intspeed,fpspeed,fprate: sw_compiler001 = RISC-V GCC cross compiler diff --git a/workloads/linux/spec2017/rules.mk b/workloads/linux/spec2017/rules.mk index 12d13ab..4405f49 100644 --- a/workloads/linux/spec2017/rules.mk +++ b/workloads/linux/spec2017/rules.mk @@ -19,6 +19,7 @@ SPEC2017_PREPARE_SCRIPT := $(SPEC2017_WORKLOAD_DIR)/prepare-spec-workspace.sh SPEC2017_CROSS_COMPILE ?= riscv64-unknown-linux-gnu- SPEC2017_COMPILER_ROOT ?= SPEC2017_GNU_TOOLCHAIN_ROOT ?= +SPEC2017_JEMALLOC_ROOT ?= SPEC2017_MULTIHART ?= $(MULTIHART) SPEC2017_HARTS ?= $(if $(HARTS),$(HARTS),2) SPEC2017_EXPLICIT_DEFAULT_DTB := $(if $(DEFAULT_DTB),1,$(if $(filter undefined,$(origin SPEC2017_DEFAULT_DTB)),,1)) @@ -61,7 +62,7 @@ spec2017_case_dtb_required_min_memory_bytes = $(if $(filter 1,$(SPEC2017_MULTIHA spec2017_case_cfg = $(if $(SPEC2017_EXPLICIT_CFG),$(SPEC2017_CFG),$(if $(findstring _speed_,$(1)),$(SPEC2017_SPEED_CFG),$(SPEC2017_RATE_CFG))) spec2017_case_cfg_hash = $(shell if [ -f "$(abspath $(call spec2017_case_cfg,$(1)))" ]; then sha256sum "$(abspath $(call spec2017_case_cfg,$(1)))" | cut -d ' ' -f 1; else printf 'missing'; fi) SPEC2017_PYTHON := PYTHONDONTWRITEBYTECODE=1 python3 -SPEC2017_BUILD_VARS_HASH := $(shell printf '%s\n' '$(SPEC2017_PROFILING)' '$(SPEC2017_TUNE)' '$(SPEC2017_CROSS_COMPILE)' '$(SPEC2017_COMPILER_ROOT)' '$(SPEC2017_GNU_TOOLCHAIN_ROOT)' 'multihart=$(SPEC2017_MULTIHART)' 'harts=$(SPEC2017_HARTS)' | sha256sum | cut -d ' ' -f 1) +SPEC2017_BUILD_VARS_HASH := $(shell printf '%s\n' '$(SPEC2017_PROFILING)' '$(SPEC2017_TUNE)' '$(SPEC2017_CROSS_COMPILE)' '$(SPEC2017_COMPILER_ROOT)' '$(SPEC2017_GNU_TOOLCHAIN_ROOT)' 'jemalloc_root=$(SPEC2017_JEMALLOC_ROOT)' 'jemalloc_repo=$(SPEC2017_JEMALLOC_REPO)' 'jemalloc_commit=$(SPEC2017_JEMALLOC_COMMIT)' 'jemalloc_host=$(SPEC2017_JEMALLOC_CONFIGURE_HOST)' 'multihart=$(SPEC2017_MULTIHART)' 'harts=$(SPEC2017_HARTS)' | sha256sum | cut -d ' ' -f 1) SPEC2017_CASE := $(shell $(SPEC2017_PYTHON) $(SPEC2017_HELPER) --resolve-case --bench '$(BENCH)' --input-set '$(SPEC2017_INPUT)' --mode '$(SPEC2017_MODE)' 2>/dev/null) SPEC2017_ALL_CASES := $(shell $(SPEC2017_PYTHON) $(SPEC2017_HELPER) --list-cases --input-set all --mode all 2>/dev/null) SPEC2017_SELECTED_CASES := $(shell $(SPEC2017_PYTHON) $(SPEC2017_HELPER) --list-cases --input-set $(SPEC2017_INPUT) --mode $(SPEC2017_MODE) 2>/dev/null) @@ -137,7 +138,7 @@ $(SPEC2017_BUILD_DIR)/$(1)/build-vars.$(SPEC2017_BUILD_VARS_HASH).stamp: @rm -f "$$(@D)"/build-vars.*.stamp @printf '%s\n' "profiling=$(SPEC2017_PROFILING)" "multihart=$(SPEC2017_MULTIHART)" "harts=$(SPEC2017_HARTS)" > "$$@" -$(SPEC2017_BUILD_DIR)/$(1)/elf/$(1).elf: $(SPEC2017_PREPARE_STAMP) $(SPEC2017_BUILD_DIR)/$(1)/cfg.$(call spec2017_case_cfg_hash,$(1)).stamp $$(SPEC2017_HELPER) $$(SPEC2017_WORKLOAD_DIR)/build.sh +$(SPEC2017_BUILD_DIR)/$(1)/elf/$(1).elf: $(SPEC2017_PREPARE_STAMP) $(SPEC2017_BUILD_DIR)/$(1)/cfg.$(call spec2017_case_cfg_hash,$(1)).stamp $(SPEC2017_BUILD_DIR)/$(1)/build-vars.$(SPEC2017_BUILD_VARS_HASH).stamp $$(SPEC2017_HELPER) $$(SPEC2017_WORKLOAD_DIR)/build.sh @mkdir -p "$$(dir $$@)" @WORKLOAD_DIR="$$(abspath $$(SPEC2017_WORKLOAD_DIR))" \ WORKLOAD_BUILD_DIR="$$(abspath $(SPEC2017_BUILD_DIR)/$(1))" \ @@ -150,6 +151,7 @@ $(SPEC2017_BUILD_DIR)/$(1)/elf/$(1).elf: $(SPEC2017_PREPARE_STAMP) $(SPEC2017_BU SPEC2017_CFG="$(abspath $(call spec2017_case_cfg,$(1)))" \ SPEC2017_COMPILER_ROOT="$$(SPEC2017_COMPILER_ROOT)" \ SPEC2017_GNU_TOOLCHAIN_ROOT="$$(SPEC2017_GNU_TOOLCHAIN_ROOT)" \ + SPEC2017_JEMALLOC_ROOT="$$(SPEC2017_JEMALLOC_ROOT)" \ SPEC2017_TUNE="$$(SPEC2017_TUNE)" \ SPEC2017_JOBS="$$(SPEC2017_JOBS)" \ SPEC2017_ELF_ONLY=1 \ @@ -165,6 +167,7 @@ $(SPEC2017_BUILD_DIR)/$(1)/rootfs.cpio: $(SPEC2017_PREPARE_STAMP) $(SPEC2017_BUI SPEC2017_CFG="$(abspath $(call spec2017_case_cfg,$(1)))" \ SPEC2017_COMPILER_ROOT="$$(SPEC2017_COMPILER_ROOT)" \ SPEC2017_GNU_TOOLCHAIN_ROOT="$$(SPEC2017_GNU_TOOLCHAIN_ROOT)" \ + SPEC2017_JEMALLOC_ROOT="$$(SPEC2017_JEMALLOC_ROOT)" \ SPEC2017_TUNE="$$(SPEC2017_TUNE)" \ SPEC2017_JOBS="$$(SPEC2017_JOBS)" \ SPEC2017_PROFILING="$$(SPEC2017_PROFILING)" \ @@ -215,6 +218,7 @@ $(SPEC2017_IMAGE_DIR)/stamps/$(1).images.stamp: $(SPEC2017_PREPARE_STAMP) $(SPEC SPEC2017_CFG="$(abspath $(call spec2017_case_cfg,$(1)))" \ SPEC2017_COMPILER_ROOT="$$(SPEC2017_COMPILER_ROOT)" \ SPEC2017_GNU_TOOLCHAIN_ROOT="$$(SPEC2017_GNU_TOOLCHAIN_ROOT)" \ + SPEC2017_JEMALLOC_ROOT="$$(SPEC2017_JEMALLOC_ROOT)" \ SPEC2017_TUNE="$$(SPEC2017_TUNE)" \ SPEC2017_JOBS="$$(SPEC2017_JOBS)" \ SPEC2017_ALL_RUNS=1 \ diff --git a/workloads/linux/spec2017/spec2017-package.py b/workloads/linux/spec2017/spec2017-package.py index 4f52f50..6e06d1e 100755 --- a/workloads/linux/spec2017/spec2017-package.py +++ b/workloads/linux/spec2017/spec2017-package.py @@ -235,6 +235,19 @@ def spec_env(spec_dir): return env +def specinvoke_env(spec_dir): + env = os.environ.copy() + env.update(spec_env(spec_dir)) + sensitive_name = re.compile( + r"(?:TOKEN|SECRET|PASSWORD|PASSWD|API[_-]?KEY|PRIVATE[_-]?KEY|CREDENTIAL)", + re.IGNORECASE, + ) + for name in list(env): + if sensitive_name.search(name): + del env[name] + return env + + def tree_metadata(source): source = Path(source).resolve() archive = source / "install_archives" / "cpu2017.tar.xz" @@ -371,7 +384,8 @@ def shared_build_dir_for(out_dir, bench_dir, tune): return out_dir.parent / "_bench-builds" / bench_dir / tune -def shared_build_metadata(spec_cfg, spec_source, cross_compile, tune, compiler_root, gnu_toolchain_root): +def shared_build_metadata(spec_cfg, spec_source, cross_compile, tune, compiler_root, gnu_toolchain_root, jemalloc_root): + jemalloc_library = jemalloc_root / "lib" / "libjemalloc.a" return { "spec_cfg_sha256": file_sha256(spec_cfg), "spec_source": str(spec_source), @@ -380,6 +394,8 @@ def shared_build_metadata(spec_cfg, spec_source, cross_compile, tune, compiler_r "tune": tune, "compiler_root": str(compiler_root), "gnu_toolchain_root": str(gnu_toolchain_root), + "jemalloc_root": str(jemalloc_root), + "jemalloc_library_sha256": file_sha256(jemalloc_library) if jemalloc_library.is_file() else None, } @@ -412,6 +428,11 @@ def explain_missing_elf(output_root, bench_dir, tune): return "\n" + "\n".join(details) +def cfg_requires_jemalloc(spec_cfg): + text = spec_cfg.read_text(encoding="utf-8") + return "JEMALLOC_PATH" in text or "-ljemalloc" in text + + def export_build_log_artifact(build_log, out_dir): if not build_log.is_file(): return None @@ -422,17 +443,18 @@ def export_build_log_artifact(build_log, out_dir): return exported_log -def runcpu_env(spec_dir, cross_compile, compiler_root, gnu_toolchain_root): +def runcpu_env(spec_dir, cross_compile, compiler_root, gnu_toolchain_root, jemalloc_root): env = os.environ.copy() env.update(spec_env(spec_dir)) env["SPEC"] = str(spec_dir) env["CROSS_COMPILE"] = str(cross_compile) env["SPEC2017_COMPILER_ROOT"] = str(compiler_root) env["SPEC2017_GNU_TOOLCHAIN_ROOT"] = str(gnu_toolchain_root) + env["JEMALLOC_INSTALL_PATH"] = str(jemalloc_root) return env -def build_elf(spec_dir, bench_dir, spec_cfg, spec_source, out_dir, log_dir, cross_compile, tune, jobs, compiler_root, gnu_toolchain_root): +def build_elf(spec_dir, bench_dir, spec_cfg, spec_source, out_dir, log_dir, cross_compile, tune, jobs, compiler_root, gnu_toolchain_root, jemalloc_root): shared_dir = shared_build_dir_for(out_dir, bench_dir, tune) output_root = shared_dir / "runcpu-output" generated_cfg = shared_dir / "runcpu-config" / spec_cfg.name @@ -440,7 +462,7 @@ def build_elf(spec_dir, bench_dir, spec_cfg, spec_source, out_dir, log_dir, cros build_log = shared_log_dir / "build.log" exe_dir = output_root / "benchspec" / "CPU" / bench_dir / "exe" metadata_path = shared_dir / "build-meta.json" - metadata = shared_build_metadata(spec_cfg, spec_source, cross_compile, tune, compiler_root, gnu_toolchain_root) + metadata = shared_build_metadata(spec_cfg, spec_source, cross_compile, tune, compiler_root, gnu_toolchain_root, jemalloc_root) if metadata_path.is_file(): try: cached_metadata = load_json(metadata_path) @@ -464,7 +486,7 @@ def build_elf(spec_dir, bench_dir, spec_cfg, spec_source, out_dir, log_dir, cros shared_log_dir.mkdir(parents=True, exist_ok=True) build_local_config(spec_cfg, generated_cfg, output_root, jobs) status(f"Generated SPEC cfg: {generated_cfg}") - env = runcpu_env(spec_dir, cross_compile, compiler_root, gnu_toolchain_root) + env = runcpu_env(spec_dir, cross_compile, compiler_root, gnu_toolchain_root, jemalloc_root) cmd = [ str(spec_dir / "bin" / "runcpu"), "--action", @@ -712,8 +734,7 @@ def populate_x264_run_dir(spec_dir, run_dir): def render_specinvoke_commands(spec_dir, run_dir, cmd_file, log_path): if not cmd_file.is_file(): raise RuntimeError(f"{cmd_file.name} not found in run directory: {run_dir}") - env = os.environ.copy() - env.update(spec_env(spec_dir)) + env = specinvoke_env(spec_dir) output = run( [str(spec_dir / "bin" / "specinvoke"), "-nn", str(cmd_file)], cwd=run_dir, @@ -735,9 +756,9 @@ def render_specinvoke_commands(spec_dir, run_dir, cmd_file, log_path): return commands -def prepare_run_dir(spec_dir, bench_dir, workload, generated_output_root, spec_cfg, tune, log_dir, cross_compile, compiler_root, gnu_toolchain_root): +def prepare_run_dir(spec_dir, bench_dir, workload, generated_output_root, spec_cfg, tune, log_dir, cross_compile, compiler_root, gnu_toolchain_root, jemalloc_root): setup_log = log_dir / "runsetup.log" - env = runcpu_env(spec_dir, cross_compile, compiler_root, gnu_toolchain_root) + env = runcpu_env(spec_dir, cross_compile, compiler_root, gnu_toolchain_root, jemalloc_root) if is_x264_bench(bench_dir): prepare_x264_input_data(spec_dir, log_dir, workload) cmd = [ @@ -822,6 +843,8 @@ def padded_range_name(end_value, start_value="0", suffix=""): def copy_tree_contents(src, dst): dst.mkdir(parents=True, exist_ok=True) for item in src.iterdir(): + if item.name in {"inputgen.cmd", "inputgen.out", "speccmds.cmd", "compare.cmd"}: + continue target = dst / item.name if item.is_symlink(): if target.exists() or target.is_symlink(): @@ -911,7 +934,14 @@ def write_variants_metadata(out_dir, variants): write_json(out_dir / "variants.json", serializable) -def write_runtime_files(pkg_dir, case_name_value, run_commands, profiling, multihart="0"): +def write_runtime_files( + pkg_dir, + case_name_value, + run_commands, + profiling, + multihart="0", + profile_command_index=0, +): spec_root = pkg_dir / "spec" run_sh = spec_root / "run.sh" script_lines = [ @@ -932,13 +962,13 @@ def write_runtime_files(pkg_dir, case_name_value, run_commands, profiling, multi "status=0", "set +e", ] - for command in run_commands: + for command_index, command in enumerate(run_commands): command_lines = [ "if [ \"$status\" -eq 0 ]; then", f" spec_cmd={shlex.quote(command)}", " echo \"CMD: $spec_cmd\"", ] - if profiling == "1" and multihart != "1": + if profiling == "1" and multihart != "1" and command_index == profile_command_index: command_lines.extend([" nemu-trap 256", " nemu-trap 257"]) command_lines.extend( [ @@ -946,12 +976,12 @@ def write_runtime_files(pkg_dir, case_name_value, run_commands, profiling, multi " status=$?", ] ) - if multihart != "1": - command_lines.append(" nemu-trap \"$status\"") command_lines.append("fi") script_lines.extend( command_lines ) + if multihart != "1": + script_lines.append("nemu-trap \"$status\"") script_lines.extend( [ "set -e", @@ -984,7 +1014,14 @@ def package_runtime_variant(variant, run_dir, profiling, multihart): (pkg_dir / "spec").mkdir(parents=True) status(f"Packaging rootfs for {variant['name']}") copy_tree_contents(run_dir, pkg_dir / "spec") - write_runtime_files(pkg_dir, variant["name"], variant["commands"], profiling, multihart) + write_runtime_files( + pkg_dir, + variant["name"], + variant["commands"], + profiling, + multihart, + profile_command_index=len(variant["commands"]) - 1, + ) def package_case(args): @@ -1004,6 +1041,18 @@ def package_case(args): cross_compile, detected_toolchain_root = resolve_cross_compile(args.cross_compile) compiler_root = Path(args.compiler_root).resolve() if args.compiler_root else detected_toolchain_root gnu_toolchain_root = Path(args.gnu_toolchain_root).resolve() if args.gnu_toolchain_root else detected_toolchain_root + env_jemalloc_root = os.environ.get("SPEC2017_JEMALLOC_ROOT") or os.environ.get("JEMALLOC_INSTALL_PATH") + if args.jemalloc_root: + jemalloc_root = Path(args.jemalloc_root).resolve() + elif env_jemalloc_root: + jemalloc_root = Path(env_jemalloc_root).resolve() + else: + jemalloc_root = (out_dir.parent / "jemalloc" / "install").resolve() + if cfg_requires_jemalloc(spec_cfg) and not (jemalloc_root / "lib" / "libjemalloc.a").is_file(): + raise RuntimeError( + f"jemalloc library not found: {jemalloc_root / 'lib' / 'libjemalloc.a'}; " + "set SPEC2017_JEMALLOC_ROOT or JEMALLOC_INSTALL_PATH to a valid install prefix" + ) elf, output_root = build_elf( spec_dir, case["bench_dir"], @@ -1016,6 +1065,7 @@ def package_case(args): args.jobs, compiler_root, gnu_toolchain_root, + jemalloc_root, ) exported_elf = export_elf_artifact(elf, args.case, out_dir) status(f"Exported ELF: {exported_elf}") @@ -1032,6 +1082,7 @@ def package_case(args): cross_compile, compiler_root, gnu_toolchain_root, + jemalloc_root, ) run_commands = shell_from_specinvoke(spec_dir, run_dir, log_dir) if args.all_runs: @@ -1089,6 +1140,7 @@ def main(): parser.add_argument("--cross-compile", default="riscv64-unknown-linux-gnu-") parser.add_argument("--compiler-root") parser.add_argument("--gnu-toolchain-root") + parser.add_argument("--jemalloc-root") parser.add_argument("--log-dir") parser.add_argument("--tune", default="base") parser.add_argument("--jobs", default=str(os.cpu_count() or 1)) diff --git a/workloads/linux/spec2026/build.sh b/workloads/linux/spec2026/build.sh index 36ade0f..f8206a6 100644 --- a/workloads/linux/spec2026/build.sh +++ b/workloads/linux/spec2026/build.sh @@ -1,16 +1,34 @@ #!/usr/bin/env bash set -euo pipefail +: "${WORKLOAD_BUILD_DIR:?WORKLOAD_BUILD_DIR is required}" : "${SPEC2026_CASE:?SPEC2026_CASE is required}" : "${SPEC2026:?SPEC2026 is required}" : "${SPEC2026_CFG:?SPEC2026_CFG is required}" : "${CROSS_COMPILE:=riscv64-unknown-linux-gnu-}" : "${SPEC2026_TUNE:=base}" : "${SPEC2026_JOBS:=$(nproc)}" +: "${SPEC2026_JEMALLOC_REPO:=https://github.com/jemalloc/jemalloc.git}" +: "${SPEC2026_JEMALLOC_COMMIT:=1a15fe33a48c52bfe26ea83e49f0d317a47da3ea}" +: "${SPEC2026_DOWNLOAD_RETRIES:=3}" : "${SPEC2026_ELF_ONLY:=false}" : "${SPEC2026_LOG_DIR:=$WORKLOAD_BUILD_DIR/logs}" : "${PKG_DIR:=$WORKLOAD_BUILD_DIR/package}" +SPEC2026_JEMALLOC_ROOT="${SPEC2026_JEMALLOC_ROOT:-${JEMALLOC_INSTALL_PATH:-}}" +jemalloc_root_is_explicit=0 +if [ -n "$SPEC2026_JEMALLOC_ROOT" ]; then + jemalloc_root_is_explicit=1 +fi + +jemalloc_lock_dir="" +cleanup() { + if [ -n "$jemalloc_lock_dir" ]; then + rmdir "$jemalloc_lock_dir" 2>/dev/null || true + fi +} +trap cleanup EXIT + mkdir -p "$SPEC2026_LOG_DIR" spec2026_progress_prefix() { @@ -23,6 +41,79 @@ status() { printf '%s %s\n' "$(spec2026_progress_prefix)" "$*" } +show_log_tail() { + local log_file="$1" + if [ -f "$log_file" ]; then + echo "$(spec2026_progress_prefix) Last 40 lines from $log_file:" >&2 + tail -n 40 "$log_file" >&2 || true + fi +} + +retry() { + local attempt=1 + while true; do + if "$@"; then + return 0 + fi + if [ "$attempt" -ge "$SPEC2026_DOWNLOAD_RETRIES" ]; then + return 1 + fi + printf '%s Retrying failed command (%s/%s): %s\n' \ + "$(spec2026_progress_prefix)" \ + "$attempt" \ + "$SPEC2026_DOWNLOAD_RETRIES" \ + "$*" >&2 + sleep $((attempt * 2)) + attempt=$((attempt + 1)) + done +} + +retry_git_clone() { + local repo="$1" + local dest="$2" + local attempt=1 + while true; do + rm -rf "$dest" + if git clone "$repo" "$dest"; then + return 0 + fi + if [ "$attempt" -ge "$SPEC2026_DOWNLOAD_RETRIES" ]; then + return 1 + fi + printf '%s Retrying failed git clone (%s/%s): %s\n' \ + "$(spec2026_progress_prefix)" \ + "$attempt" \ + "$SPEC2026_DOWNLOAD_RETRIES" \ + "$repo" >&2 + sleep $((attempt * 2)) + attempt=$((attempt + 1)) + done +} + +prepare_git_checkout() { + local repo="$1" + local commit="$2" + local dest="$3" + local current_commit target_commit + + if [ ! -d "$dest/.git" ]; then + retry_git_clone "$repo" "$dest" + else + git -C "$dest" remote set-url origin "$repo" + fi + + if ! git -C "$dest" cat-file -e "$commit^{commit}" 2>/dev/null; then + retry git -C "$dest" fetch --tags origin + fi + + current_commit="$(git -C "$dest" rev-parse HEAD 2>/dev/null || true)" + target_commit="$(git -C "$dest" rev-parse "$commit")" + if [ "$current_commit" != "$target_commit" ]; then + git -C "$dest" checkout --detach "$commit" + git -C "$dest" clean -ffdx + fi +} + is_true() { case "$1" in 1|true|yes|on) return 0 ;; @@ -30,6 +121,129 @@ is_true() { esac } +cfg_requires_jemalloc() { + grep -Eq 'JEMALLOC_PATH|-ljemalloc' "$SPEC2026_CFG" +} + +resolve_jemalloc_root() { + if [ -n "$SPEC2026_JEMALLOC_ROOT" ]; then + realpath -m "$SPEC2026_JEMALLOC_ROOT" + else + realpath -m "$(dirname "$WORKLOAD_BUILD_DIR")/jemalloc/install" + fi +} + +resolve_jemalloc_host() { + if [ -n "${SPEC2026_JEMALLOC_CONFIGURE_HOST:-}" ]; then + printf '%s\n' "$SPEC2026_JEMALLOC_CONFIGURE_HOST" + else + "${CROSS_COMPILE}gcc" -dumpmachine + fi +} + +jemalloc_cache_metadata() { + local host="$1" + printf '%s\n' \ + "repo=$SPEC2026_JEMALLOC_REPO" \ + "commit=$SPEC2026_JEMALLOC_COMMIT" \ + "cross_compile=$CROSS_COMPILE" \ + "host=$host" +} + +jemalloc_cache_is_current() { + local prefix="$1" + local host="$2" + local metadata_file="$prefix/.workload-builder-jemalloc-meta" + + if [ ! -f "$prefix/lib/libjemalloc.a" ]; then + return 1 + fi + if [ "$jemalloc_root_is_explicit" = 1 ]; then + return 0 + fi + [ -f "$metadata_file" ] && [ "$(cat "$metadata_file")" = "$(jemalloc_cache_metadata "$host")" ] +} + +prepare_jemalloc() { + local base_dir source_dir prefix host log_file rc + base_dir="$(realpath -m "$(dirname "$WORKLOAD_BUILD_DIR")/jemalloc")" + source_dir="$base_dir/source" + prefix="$(resolve_jemalloc_root)" + host="$(resolve_jemalloc_host)" + log_file="$base_dir/build.log" + + if jemalloc_cache_is_current "$prefix" "$host"; then + SPEC2026_JEMALLOC_ROOT="$prefix" + export SPEC2026_JEMALLOC_ROOT + status "Using cached jemalloc: $prefix" + return + fi + + jemalloc_lock_dir="$base_dir/.lock" + mkdir -p "$base_dir" + while ! mkdir "$jemalloc_lock_dir" 2>/dev/null; do + sleep 1 + done + + if jemalloc_cache_is_current "$prefix" "$host"; then + rmdir "$jemalloc_lock_dir" + jemalloc_lock_dir="" + SPEC2026_JEMALLOC_ROOT="$prefix" + export SPEC2026_JEMALLOC_ROOT + status "Using cached jemalloc: $prefix" + return + fi + + status "Preparing jemalloc (log: $log_file)" + : > "$log_file" + + rc=0 + set +e + ( + set -euo pipefail + echo "# jemalloc repo: $SPEC2026_JEMALLOC_REPO" + echo "# jemalloc commit: $SPEC2026_JEMALLOC_COMMIT" + echo "# install prefix: $prefix" + echo "# configure host: $host" + prepare_git_checkout "$SPEC2026_JEMALLOC_REPO" "$SPEC2026_JEMALLOC_COMMIT" "$source_dir" + + cd "$source_dir" + CC="${CROSS_COMPILE}gcc" \ + CXX="${CROSS_COMPILE}g++" \ + AR="${CROSS_COMPILE}ar" \ + LD="${CROSS_COMPILE}ld" \ + RANLIB="${CROSS_COMPILE}ranlib" \ + STRIP="${CROSS_COMPILE}strip" \ + ./autogen.sh --prefix="$prefix" --host="$host" + make -j"$SPEC2026_JOBS" + make install + ) >>"$log_file" 2>&1 + rc=$? + set -e + + if [ "$rc" -ne 0 ]; then + echo "$(spec2026_progress_prefix) jemalloc build failed; see $log_file" >&2 + show_log_tail "$log_file" + return 1 + fi + if [ ! -f "$prefix/lib/libjemalloc.a" ]; then + echo "$(spec2026_progress_prefix) jemalloc install did not produce $prefix/lib/libjemalloc.a" >&2 + return 1 + fi + jemalloc_cache_metadata "$host" > "$prefix/.workload-builder-jemalloc-meta" + + rmdir "$jemalloc_lock_dir" + jemalloc_lock_dir="" + + SPEC2026_JEMALLOC_ROOT="$prefix" + export SPEC2026_JEMALLOC_ROOT + status "jemalloc ready: $prefix" +} + +if cfg_requires_jemalloc; then + prepare_jemalloc +fi + python_args=() if is_true "$SPEC2026_ELF_ONLY"; then python_args+=(--elf-only) @@ -42,6 +256,7 @@ python3 "$WORKLOAD_DIR/spec2026-package.py" \ --pkg-dir "$PKG_DIR" \ --out-dir "$WORKLOAD_BUILD_DIR" \ --cross-compile "$CROSS_COMPILE" \ + --jemalloc-root "${SPEC2026_JEMALLOC_ROOT:-}" \ --log-dir "$SPEC2026_LOG_DIR" \ --tune "$SPEC2026_TUNE" \ --jobs "$SPEC2026_JOBS" \ diff --git a/workloads/linux/spec2026/configs/riscv_gcc15_base.cfg b/workloads/linux/spec2026/configs/riscv_gcc15_base.cfg index d04e052..fa78064 100644 --- a/workloads/linux/spec2026/configs/riscv_gcc15_base.cfg +++ b/workloads/linux/spec2026/configs/riscv_gcc15_base.cfg @@ -44,17 +44,25 @@ default: % define gcc_dir "/opt/gcc-15" %endif +%ifndef %{jemalloc_dir} +% define jemalloc_dir "/opt/jemalloc" +%endif + %define GCCge10 default: preENV_LD_LIBRARY_PATH = %{gcc_dir}/lib64/:%{gcc_dir}/lib/:/lib64 SPECLANG = %{gcc_dir}/bin/riscv64-unknown-linux-gnu- + JEMALLOC_PATH = %{jemalloc_dir} + JEMALLOC_LIBS = $(JEMALLOC_PATH)/lib/libjemalloc.a -lm CC = $(SPECLANG)gcc -std=c18 CXX = $(SPECLANG)g++ -std=c++17 FC = $(SPECLANG)gfortran -std=f2018 CC_VERSION_OPTION = --version CXX_VERSION_OPTION = --version FC_VERSION_OPTION = --version + EXTRA_LIBS = $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = -z muldefs 800.pot3d_s: PORTABILITY = -DSPEC_SUPPRESS_LOCAL_AND_REDUCE diff --git a/workloads/linux/spec2026/configs/riscv_gcc16_rva23u64_novec.cfg b/workloads/linux/spec2026/configs/riscv_gcc16_rva23u64_novec.cfg index 98a169a..697f74e 100644 --- a/workloads/linux/spec2026/configs/riscv_gcc16_rva23u64_novec.cfg +++ b/workloads/linux/spec2026/configs/riscv_gcc16_rva23u64_novec.cfg @@ -44,17 +44,25 @@ default: % define gcc_dir "/opt/gcc-16" %endif +%ifndef %{jemalloc_dir} +% define jemalloc_dir "/opt/jemalloc" +%endif + %define GCCge10 default: preENV_LD_LIBRARY_PATH = %{gcc_dir}/lib64/:%{gcc_dir}/lib/:/lib64 SPECLANG = %{gcc_dir}/bin/riscv64-unknown-linux-gnu- + JEMALLOC_PATH = %{jemalloc_dir} + JEMALLOC_LIBS = $(JEMALLOC_PATH)/lib/libjemalloc.a -lm CC = $(SPECLANG)gcc -std=c18 CXX = $(SPECLANG)g++ -std=c++17 FC = $(SPECLANG)gfortran -std=f2018 CC_VERSION_OPTION = --version CXX_VERSION_OPTION = --version FC_VERSION_OPTION = --version + EXTRA_LIBS = $(JEMALLOC_LIBS) + EXTRA_LDFLAGS = -z muldefs 800.pot3d_s: PORTABILITY = -DSPEC_SUPPRESS_LOCAL_AND_REDUCE diff --git a/workloads/linux/spec2026/rules.mk b/workloads/linux/spec2026/rules.mk index bfcc698..25d256b 100644 --- a/workloads/linux/spec2026/rules.mk +++ b/workloads/linux/spec2026/rules.mk @@ -17,6 +17,8 @@ SPEC2026_SOURCE_SPEC_HASH := $(shell printf '%s\n' "$(SPEC2026_SOURCE_SPEC_ISO)" SPEC2026_PREPARE_STAMP := $(SPEC2026_BUILD_DIR)/spec-src.$(SPEC2026_SOURCE_SPEC_HASH).prepared SPEC2026_PREPARE_SCRIPT := $(SPEC2026_WORKLOAD_DIR)/prepare-spec-workspace.sh SPEC2026_CROSS_COMPILE ?= riscv64-unknown-linux-gnu- +SPEC2026_COMPILER_ROOT ?= +SPEC2026_JEMALLOC_ROOT ?= SPEC2026_TUNE ?= base SPEC2026_JOBS ?= $(shell nproc) SPEC2026_INPUT ?= $(if $(INPUT),$(INPUT),ref) @@ -46,7 +48,7 @@ SPEC2026_SELECTED_CASES := $(shell python3 $(SPEC2026_HELPER) --list-cases --inp SPEC2026_IMAGE_CASES := $(if $(BENCH),$(BENCH),$(shell python3 $(SPEC2026_HELPER) --list-cases --input-set $(SPEC2026_IMAGE_INPUT) --mode $(SPEC2026_IMAGE_MODE) 2>/dev/null)) SPEC2026_DTS_SOURCES := $(shell find $(SPEC2026_DTS_DIR) -type f 2>/dev/null) SPEC2026_CFG_HASH := $(shell if [ -f "$(abspath $(SPEC2026_CFG))" ]; then sha256sum "$(abspath $(SPEC2026_CFG))" | cut -d ' ' -f 1; else printf 'missing'; fi) -SPEC2026_BUILD_VARS_HASH := $(shell printf '%s\n' '$(SPEC2026_INPUT)' '$(SPEC2026_TUNE)' '$(SPEC2026_JOBS)' '$(SPEC2026_CROSS_COMPILE)' | sha256sum | cut -d ' ' -f 1) +SPEC2026_BUILD_VARS_HASH := $(shell printf '%s\n' '$(SPEC2026_INPUT)' '$(SPEC2026_TUNE)' '$(SPEC2026_JOBS)' '$(SPEC2026_CROSS_COMPILE)' '$(SPEC2026_COMPILER_ROOT)' 'jemalloc_root=$(SPEC2026_JEMALLOC_ROOT)' 'jemalloc_repo=$(SPEC2026_JEMALLOC_REPO)' 'jemalloc_commit=$(SPEC2026_JEMALLOC_COMMIT)' 'jemalloc_host=$(SPEC2026_JEMALLOC_CONFIGURE_HOST)' | sha256sum | cut -d ' ' -f 1) spec2026_case_dtb_memory = $(if $(SPEC2026_DTB_MEMORY),$(SPEC2026_DTB_MEMORY),$(if $(filter %_s,$(1)),$(SPEC2026_SPEED_DTB_MEMORY),$(SPEC2026_RATE_DTB_MEMORY))) spec2026_case_dtb_profile = $(if $(SPEC2026_EXPLICIT_DEFAULT_DTB),,$(call spec2026_case_dtb_memory,$(1))) @@ -131,6 +133,8 @@ $(SPEC2026_BUILD_DIR)/$(1)/elf/$(1).elf: $(SPEC2026_PREPARE_STAMP) $(SPEC2026_BU SPEC2026_CASE="$(1)" \ SPEC2026="$$(SPEC2026_PREPARED_SPEC_ROOT)" \ SPEC2026_CFG="$$(abspath $$(SPEC2026_CFG))" \ + SPEC2026_COMPILER_ROOT="$$(SPEC2026_COMPILER_ROOT)" \ + SPEC2026_JEMALLOC_ROOT="$$(SPEC2026_JEMALLOC_ROOT)" \ SPEC2026_TUNE="$$(SPEC2026_TUNE)" \ SPEC2026_JOBS="$$(SPEC2026_JOBS)" \ SPEC2026_ELF_ONLY=1 \ @@ -143,6 +147,8 @@ $(SPEC2026_BUILD_DIR)/$(1)/rootfs.cpio: $(SPEC2026_PREPARE_STAMP) $(SPEC2026_BUI SPEC2026_CASE="$(1)" \ SPEC2026="$$(SPEC2026_PREPARED_SPEC_ROOT)" \ SPEC2026_CFG="$$(abspath $$(SPEC2026_CFG))" \ + SPEC2026_COMPILER_ROOT="$$(SPEC2026_COMPILER_ROOT)" \ + SPEC2026_JEMALLOC_ROOT="$$(SPEC2026_JEMALLOC_ROOT)" \ SPEC2026_INPUT="$$(SPEC2026_INPUT)" \ SPEC2026_TUNE="$$(SPEC2026_TUNE)" \ SPEC2026_JOBS="$$(SPEC2026_JOBS)" \ diff --git a/workloads/linux/spec2026/spec2026-package.py b/workloads/linux/spec2026/spec2026-package.py index 6ca6667..960da19 100644 --- a/workloads/linux/spec2026/spec2026-package.py +++ b/workloads/linux/spec2026/spec2026-package.py @@ -256,13 +256,21 @@ def shared_build_dir_for(out_dir, case_name, tune): return out_dir.parent / "_bench-builds" / case_name / tune -def shared_build_metadata(spec_cfg, spec_dir, cross_compile, tune, compiler_root, jobs): +def cfg_requires_jemalloc(spec_cfg): + text = spec_cfg.read_text(encoding="utf-8") + return "JEMALLOC_PATH" in text or "-ljemalloc" in text + + +def shared_build_metadata(spec_cfg, spec_dir, cross_compile, tune, compiler_root, jemalloc_root, jobs): + jemalloc_library = jemalloc_root / "lib" / "libjemalloc.a" return { "spec_cfg_sha256": file_sha256(spec_cfg), "spec_dir": str(spec_dir), "cross_compile": cross_compile, "tune": tune, "compiler_root": str(compiler_root), + "jemalloc_root": str(jemalloc_root), + "jemalloc_library_sha256": file_sha256(jemalloc_library) if jemalloc_library.is_file() else None, "jobs": jobs, "label": DEFAULT_LABEL, } @@ -319,7 +327,7 @@ def export_build_log_artifact(build_log, out_dir): return exported_log -def build_elf(spec_dir, case_name, spec_cfg, out_dir, log_dir, cross_compile, tune, jobs, compiler_root): +def build_elf(spec_dir, case_name, spec_cfg, out_dir, log_dir, cross_compile, tune, jobs, compiler_root, jemalloc_root): shared_dir = shared_build_dir_for(out_dir, case_name, tune) output_root = shared_dir / "runspec-output" generated_cfg = shared_dir / "runcpu-config" / spec_cfg.name @@ -328,7 +336,7 @@ def build_elf(spec_dir, case_name, spec_cfg, out_dir, log_dir, cross_compile, tu exe_dir = output_root / "benchspec" / "CPU" / case_name / "exe" metadata_path = shared_dir / "build-meta.json" build_state_path = shared_dir / "build-state.json" - metadata = shared_build_metadata(spec_cfg, spec_dir, cross_compile, tune, compiler_root, jobs) + metadata = shared_build_metadata(spec_cfg, spec_dir, cross_compile, tune, compiler_root, jemalloc_root, jobs) cached_metadata = maybe_load_json(metadata_path) if cached_metadata == metadata: @@ -398,6 +406,8 @@ def build_elf(spec_dir, case_name, spec_cfg, out_dir, log_dir, cross_compile, tu "--define", f"gcc_dir={compiler_root}", "--define", + f"jemalloc_dir={jemalloc_root}", + "--define", f"build_ncpus={jobs}", "--tune", tune, @@ -500,7 +510,7 @@ def write_runtime_files(pkg_dir, case_name, primary_run_dir_name): (etc / "inittab").write_text("::sysinit:nemu-exec /bin/sh /spec/run.sh\n", encoding="utf-8") -def package_run_tree(spec_dir, generated_cfg, case_name, pkg_dir, output_root, input_set, tune, jobs, compiler_root, log_dir): +def package_run_tree(spec_dir, generated_cfg, case_name, pkg_dir, output_root, input_set, tune, jobs, compiler_root, jemalloc_root, log_dir): runtime_input_set = normalize_runtime_input_set(input_set) env = os.environ.copy() env.update(spec_env(spec_dir)) @@ -521,6 +531,8 @@ def package_run_tree(spec_dir, generated_cfg, case_name, pkg_dir, output_root, i "--define", f"gcc_dir={compiler_root}", "--define", + f"jemalloc_dir={jemalloc_root}", + "--define", f"build_ncpus={jobs}", "--tune", tune, @@ -575,6 +587,18 @@ def package_case(args): cross_compile, detected_toolchain_root = resolve_cross_compile(args.cross_compile) compiler_root = Path(args.compiler_root).resolve() if args.compiler_root else detected_toolchain_root + env_jemalloc_root = os.environ.get("SPEC2026_JEMALLOC_ROOT") or os.environ.get("JEMALLOC_INSTALL_PATH") + if args.jemalloc_root: + jemalloc_root = Path(args.jemalloc_root).resolve() + elif env_jemalloc_root: + jemalloc_root = Path(env_jemalloc_root).resolve() + else: + jemalloc_root = (out_dir.parent / "jemalloc" / "install").resolve() + if cfg_requires_jemalloc(spec_cfg) and not (jemalloc_root / "lib" / "libjemalloc.a").is_file(): + raise RuntimeError( + f"jemalloc library not found: {jemalloc_root / 'lib' / 'libjemalloc.a'}; " + "set SPEC2026_JEMALLOC_ROOT or JEMALLOC_INSTALL_PATH to a valid install prefix" + ) elf, output_root, generated_cfg = build_elf( spec_dir, @@ -586,6 +610,7 @@ def package_case(args): args.tune, args.jobs, compiler_root, + jemalloc_root, ) exported_elf = export_elf_artifact(elf, args.case, out_dir) status(f"Exported ELF: {exported_elf}") @@ -609,6 +634,7 @@ def package_case(args): args.tune, args.jobs, compiler_root, + jemalloc_root, log_dir, ) @@ -623,6 +649,7 @@ def main(): parser.add_argument("--out-dir") parser.add_argument("--cross-compile", default=os.environ.get("CROSS_COMPILE", "riscv64-unknown-linux-gnu-")) parser.add_argument("--compiler-root") + parser.add_argument("--jemalloc-root") parser.add_argument("--log-dir") parser.add_argument("--tune", default=os.environ.get("SPEC2026_TUNE", "base")) parser.add_argument("--jobs", type=int, default=int(os.environ.get("SPEC2026_JOBS", "1")))