#!/bin/bash set -euo pipefail export LC_ALL=C # Настройки. SETC_DIR="$HOME/setc" WORK_ROOT="$HOME/setc-bench" RESULT_DIR="$HOME/res" RUNS=3 CPU=0 RESET_WORK=1 # 0 — продолжить готовые сборки, 1 — начать всё заново. PACKAGER='krosh ' APT_SOURCE=/etc/apt/sources.list.d/alt.list APT_GET=/usr/lib/apt/apt-get RPM_BUILD_GIT=https://git.altlinux.org/gears/r/rpm-build.git RPM_GIT=https://git.altlinux.org/gears/r/rpm.git fail() { printf 'error: %s\n' "$*" >&2 exit 1 } prepare_spec() { local spec=$1 suffix=$2 version release new_release date version=$(sed -n 's/^Version:[[:space:]]*//p' "$spec" | sed -n '1p') release=$(sed -n 's/^Release:[[:space:]]*//p' "$spec" | sed -n '1p') [[ -n $version && -n $release ]] || fail "cannot read Version/Release from $spec" new_release="$release.$suffix" sed -i "0,/^Release:[[:space:]]*$release$/s//Release: $new_release/" "$spec" date=$(date '+%a %b %d %Y') sed -i "/^%changelog/a\\ * $date $PACKAGER $version-$new_release\\ - Local set.c benchmark build.\\ " "$spec" } apt_options() { local root=$1 APT_OPTIONS=( -o 'Dir::Etc::main=-' -o 'Dir::Etc::parts=-' -o "Dir::Etc::sourcelist=$COMMON/sources.list" -o "Dir::Etc::sourceparts=$COMMON/sources.list.d" -o 'Dir::Etc::preferences=-' -o 'Dir::Etc::preferencesparts=-' -o "Dir::State::lists=$COMMON/lists/" -o "Dir::State::status=$COMMON/status" -o "Dir::Cache=$COMMON/cache/" -o "Dir::Cache::archives=$COMMON/cache/archives" -o "Dir::Cache::pkgcache=$COMMON/cache/pkgcache.bin" -o "Dir::Cache::srcpkgcache=$COMMON/cache/srcpkgcache.bin" -o "RPM::RootDir=$root" ) } operation_args() { case $1 in check) ARGS=(-s check) ;; autoremove) ARGS=(-s autoremove) ;; install-rpm-build) ARGS=(-s install rpm-build) ;; install-openuds-server) ARGS=(-s install openuds-server) ;; install-password-store) ARGS=(-s install password-store) ;; upgrade) ARGS=(-o APT::Get::EnableUpgrade=true -s upgrade) ;; dist-upgrade) ARGS=(-s dist-upgrade) ;; *) fail "unknown operation: $1" ;; esac } operation_label() { case $1 in check) printf '%s' '-s check' ;; autoremove) printf '%s' '-s autoremove' ;; install-rpm-build) printf '%s' '-s install rpm-build' ;; install-openuds-server) printf '%s' '-s install openuds-server' ;; install-password-store) printf '%s' '-s install password-store' ;; upgrade) printf '%s' '--enable-upgrade -s upgrade' ;; dist-upgrade) printf '%s' '-s dist-upgrade' ;; esac } run_once() { local operation=$1 variant=$2 run=$3 start end status local libdir="$variant/lib/usr/lib64" local root="$COMMON/root" local raw="$variant/raw" operation_args "$operation" apt_options "$root" start=$(date +%s%N) if env LC_ALL=C APT_CONFIG="$COMMON/apt.conf" \ LD_LIBRARY_PATH="$libdir" \ taskset -c "$CPU" "$APT_GET" -q \ "${APT_OPTIONS[@]}" "${ARGS[@]}" \ >"$raw/$operation.$run.stdout" \ 2>"$raw/$operation.$run.stderr"; then status=0 else status=$? fi end=$(date +%s%N) RUN_TIME=$(awk -v start="$start" -v end="$end" \ 'BEGIN { printf "%.6f", (end - start) / 1000000000 }') RUN_STATUS=$status } benchmark_variant() { local variant=$1 result=$2 operation run average label status_text local -a times statuses local -a operations=( check autoremove install-rpm-build install-openuds-server install-password-store upgrade dist-upgrade ) mkdir -p "$variant/raw" printf 'command\taverage_seconds\trun1_seconds\trun2_seconds\trun3_seconds\texit_status\n' \ >"$result" for operation in "${operations[@]}"; do times=() statuses=() for ((run = 1; run <= RUNS; ++run)); do run_once "$operation" "$variant" "$run" times+=("$RUN_TIME") statuses+=("$RUN_STATUS") printf '%s: run %d/%d: %ss, status=%s\n' \ "$operation" "$run" "$RUNS" "$RUN_TIME" "$RUN_STATUS" done average=$(printf '%s\n' "${times[@]}" | \ awk '{ total += $1 } END { printf "%.6f", total / NR }') status_text=${statuses[0]} for status in "${statuses[@]}"; do if [[ $status != "$status_text" ]]; then status_text=$(IFS=,; printf 'mixed:%s' "${statuses[*]}") break fi done label=$(operation_label "$operation") printf '%s\t%s\t%s\t%s\t%s\t%s\n' \ "$label" "$average" \ "${times[0]}" "${times[1]}" "${times[2]}" "$status_text" \ >>"$result" done } for command in git gear-hsh hsh rpm rpmquery rpm2cpio cpio apt-get apt-cache \ taskset awk sed date sha256sum ldd; do command -v "$command" >/dev/null || fail "required command not found: $command" done [[ -x $APT_GET ]] || fail "not found: $APT_GET" [[ $RUNS -eq 3 ]] || fail 'RUNS must stay equal to 3 for the TSV format below' shopt -s nullglob setc_files=("$SETC_DIR"/*.c) ((${#setc_files[@]} > 0)) || fail "no .c files in $SETC_DIR" if ((RESET_WORK)); then # После прерванной сборки часть chroot принадлежит hasher-псевдопользователю; # обычный rm её не удалит. old_hashers=("$WORK_ROOT"/variants/*/hasher) for old_hasher in "${old_hashers[@]}"; do [[ -d $old_hasher ]] || continue hsh --cleanup-only --workdir="$old_hasher" >/dev/null 2>&1 || true done rm -rf "$WORK_ROOT" fi mkdir -p "$WORK_ROOT/src" "$WORK_ROOT/variants" "$RESULT_DIR" COMMON="$WORK_ROOT/common" if [[ ! -s $COMMON/cache/pkgcache.bin ]]; then rm -rf "$COMMON" mkdir -p \ "$COMMON/lists/partial" \ "$COMMON/cache/archives/partial" \ "$COMMON/sources.list.d" \ "$COMMON/root/var/lib/rpm" : >"$COMMON/apt.conf" : >"$COMMON/status" # Один официальный p11 snapshot без hasher/stuff. Он создаётся до сборок # и затем одинаково используется всеми вариантами. awk '$1 == "rpm" && /p11\/branch/ && $0 !~ /(hasher|stuff)/ { print }' \ "$APT_SOURCE" >"$COMMON/sources.list" [[ -s $COMMON/sources.list ]] || fail "no p11 sources in $APT_SOURCE" cp -a /var/lib/rpm/. "$COMMON/root/var/lib/rpm/" apt_options "$COMMON/root" APT_CONFIG="$COMMON/apt.conf" apt-get -qq "${APT_OPTIONS[@]}" update APT_CONFIG="$COMMON/apt.conf" apt-cache -q "${APT_OPTIONS[@]}" gencaches >/dev/null sha256sum "$COMMON/cache/pkgcache.bin" "$COMMON/cache/srcpkgcache.bin" \ >"$COMMON/cache.sha256" fi # Чистые p11 gear-деревья клонируются один раз. if [[ ! -d $WORK_ROOT/src/rpm-build-base/.git ]]; then git clone --branch p11 --single-branch "$RPM_BUILD_GIT" \ "$WORK_ROOT/src/rpm-build-base" fi if [[ ! -d $WORK_ROOT/src/rpm-base/.git ]]; then git clone --branch p11 --single-branch "$RPM_GIT" \ "$WORK_ROOT/src/rpm-base" fi index=0 for setc in "${setc_files[@]}"; do index=$((index + 1)) id=$(printf 'v%03d' "$index") suffix="setc$id" filename=$(basename "$setc") result_name=${filename%.c}.tsv variant="$WORK_ROOT/variants/$id" source="$variant/src" hasher="$variant/hasher" repo="$hasher/repo/x86_64/RPMS.hasher" printf '\n===== %s: %s =====\n' "$id" "$filename" mkdir -p "$source" "$hasher" "$variant/logs" "$variant/lib" if [[ ! -d $source/rpm-build/.git ]]; then git clone --local "$WORK_ROOT/src/rpm-build-base" "$source/rpm-build" git clone --local "$WORK_ROOT/src/rpm-base" "$source/rpm" # По условию один и тот же входной файл кладётся как lib/set.c в оба пакета. cp "$setc" "$source/rpm-build/lib/set.c" cp "$setc" "$source/rpm/lib/set.c" prepare_spec "$source/rpm-build/rpm-4_0.spec" "$suffix" prepare_spec "$source/rpm/alt/rpm.spec" "$suffix" else cmp -s "$setc" "$source/rpm-build/lib/set.c" && \ cmp -s "$setc" "$source/rpm/lib/set.c" || \ fail "$filename changed; set RESET_WORK=1 and restart" fi rpm_build_rpms=("$repo"/rpm-build-[0-9]*".$suffix".x86_64.rpm) if ((${#rpm_build_rpms[@]} == 0)); then ( cd "$source/rpm-build" gear-hsh \ --commit \ --with-stuff \ --packager="$PACKAGER" \ --no-sisyphus-check=changelog,packager,gpg \ --mountpoints=/proc \ --workdir="$hasher" \ --target=x86_64 ) 2>&1 | tee "$variant/logs/rpm-build.log" else printf 'rpm-build already built: %s\n' "${rpm_build_rpms[0]}" fi librpm_rpms=("$repo"/librpm7-[0-9]*".$suffix".x86_64.rpm) if ((${#librpm_rpms[@]} == 0)); then ( cd "$source/rpm" gear-hsh \ --commit \ --with-stuff \ --packager="$PACKAGER" \ --no-sisyphus-check=changelog,packager,gpg \ --mountpoints=/proc \ --workdir="$hasher" \ --target=x86_64 ) 2>&1 | tee "$variant/logs/rpm.log" else printf 'rpm/librpm7 already built: %s\n' "${librpm_rpms[0]}" fi # [0-9]* исключает отдельный пакет librpm7-debuginfo. librpm_rpms=("$repo"/librpm7-[0-9]*".$suffix".x86_64.rpm) ((${#librpm_rpms[@]} == 1)) || \ fail "expected one librpm7 package for $filename, got ${#librpm_rpms[@]}" rm -rf "$variant/lib" mkdir -p "$variant/lib" ( cd "$variant/lib" rpm2cpio "${librpm_rpms[0]}" | cpio -idm --quiet ) libdir="$variant/lib/usr/lib64" [[ -e $libdir/librpm.so.7 && -e $libdir/librpmio.so.7 ]] || \ fail "librpm libraries were not extracted for $filename" LD_LIBRARY_PATH="$libdir" ldd "$APT_GET" | \ grep -F "$libdir/librpm.so.7" >/dev/null || \ fail "apt-get does not load the built librpm for $filename" benchmark_variant "$variant" "$RESULT_DIR/$result_name" done printf '\nResults:\n' printf ' %s\n' "$RESULT_DIR"/*.tsv