Skip to content
2 changes: 1 addition & 1 deletion docs/08-analysis-regression.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Both engines read the same CSV schema emitted by the in-VM test harness. The hea
metric,unit,value,more_is_better,kernel_version,instance_id,instance_type,arch
```

(documented in `vm-tests/unixbench-kernel-regression/README.md`). `more_is_better` is computed per metric in the same awk block: every metric defaults to `"true"`; the **only** metric forced to `"false"` is `System_Call_Overhead` (a latency-style metric where larger is worse).
(documented in `vm-tests/unixbench-kernel-regression/README.md`). `more_is_better` is computed per metric in the same awk block: every first-section UnixBench metric — including `System_Call_Overhead` — is `"true"`, because they are all throughput figures reported in loops/iterations per second (lps), where larger is faster. (`System_Call_Overhead` reads as "syscalls completed per fixed interval"; despite the name, a higher value is better.)

The two CSV "sides" come from different run scripts:

Expand Down
7 changes: 5 additions & 2 deletions src/kernel_ci_cloud_labs/providers/aws_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,10 @@ def wait_for_task_completion(self):
finishes the kernelci-api node incomplete/Infrastructure with the
matched line surfaced in error_msg.
* No new VM console output for PULLAB_TASK_HANG_THRESHOLD_SEC seconds
(default 600) -- silent stall, same treatment as a crash.
(default 1200) -- silent stall, same treatment as a crash. The
default accommodates CPU-heavy benchmarks (e.g. UnixBench) whose
console goes quiet for many minutes during a run; lower it via the
env var for faster hang detection on lighter workloads.
* Overall PULLAB_TASK_WAIT_TIMEOUT_SEC seconds elapsed (default 3600)
-- final safety net for whatever isn't covered above.

Expand All @@ -331,7 +334,7 @@ def wait_for_task_completion(self):

poll_interval = float(os.getenv("PULLAB_TASK_POLL_INTERVAL_SEC") or 30)
log_interval = float(os.getenv("PULLAB_TASK_PROGRESS_LOG_SEC") or 120)
hang_threshold = float(os.getenv("PULLAB_TASK_HANG_THRESHOLD_SEC") or 600)
hang_threshold = float(os.getenv("PULLAB_TASK_HANG_THRESHOLD_SEC") or 1200)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth looking at PULLAB_TASK_WAIT_TIMEOUT_SEC alongside this, it's still 3600. If a benchmark can now legitimately go quiet for 20 minutes at a time, the overall hour starts to look tight. Separate fix rather than this PR though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's monitor and decide which tests we really want to execute. If pgbench is quicker, we might be able to reduce this again.

overall_timeout = float(os.getenv("PULLAB_TASK_WAIT_TIMEOUT_SEC") or 3600)

start = time.time()
Expand Down
21 changes: 15 additions & 6 deletions tests/test-in-venv.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,27 @@
set -e

# Configuration
# PYTHON selects the interpreter used to create the virtual environment.
# Override it to build the venv with a specific version, e.g.
# PYTHON=python3.12 tests/test-in-venv.sh
# It may be a name on PATH or an absolute path. All pip/pytest calls go through
# "<python> -m ..." (never the bare pip/python3 shims).
PYTHON="${PYTHON:-python3}"
VENV_DIR=".venv-testing"
MODULE_DIR="$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
STATUS_CACHE="$MODULE_DIR/$VENV_DIR/.git_status_cache"
# Interpreter inside the venv (created from $PYTHON). Used for pip/pytest so the
# correct environment is targeted regardless of which binary bootstrapped it.
VENV_PYTHON="$MODULE_DIR/$VENV_DIR/bin/python"

# Function to create and setup virtual environment
setup_virtual_environment()
{
echo "Setting up virtual environment..."
python3 -m venv "${VENV_DIR}"
echo "Setting up virtual environment with '${PYTHON}'..."
"${PYTHON}" -m venv "${VENV_DIR}"
source "${VENV_DIR}/bin/activate"
pip install --upgrade pip
pip install -e ".[dev]"
"${VENV_PYTHON}" -m pip install --upgrade pip
"${VENV_PYTHON}" -m pip install -e ".[dev]"
}

# Function to activate virtual environment
Expand All @@ -40,7 +49,7 @@ install_module()
{
echo "Installing module..." 1>&2
status=0
output=$(pip install -e "${MODULE_DIR}" 2>&1) || status=$?
output=$("${VENV_PYTHON}" -m pip install -e "${MODULE_DIR}" 2>&1) || status=$?
if [ $status -ne 0 ]; then
echo "Installation failed, with output:" 1>&2
echo "$output" 1>&2
Expand All @@ -53,7 +62,7 @@ run_tests()
{
echo "Running unit tests..." 1>&2
status=0
output=$(python3 -m pytest tests/ -v -m "not integration" 2>&1) || status=$?
output=$("${VENV_PYTHON}" -m pytest tests/ -v -m "not integration" 2>&1) || status=$?
if [ $status -eq 0 ]; then
echo "Unit tests passed" 1>&2
else
Expand Down
258 changes: 8 additions & 250 deletions vm-tests/example-kernel-reboot-test/common_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,253 +2,11 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Common functions for kernel reboot test

# Get results bucket and test paths from environment
RESULTS_BUCKET="${S3_BUCKET:-}"
ARCH=$(uname -m)
KERNEL_RPM_DIR="/tmp/kernel-rpms"

# Validate required environment variables
if [ -z "$RESULTS_BUCKET" ] || [ -z "$RUN_PREFIX" ] || [ -z "$TEST_NAME" ]; then
echo "ERROR: Missing required environment variables (S3_BUCKET, RUN_PREFIX, TEST_NAME)" >&2
exit 1
fi

# Error trap handler to show line where error occurred
error_trap()
{
local exit_code=$?
local line_number=$1
echo "$(date): ERROR: Script failed at line $line_number with exit code $exit_code"
echo "$(date): ERROR: Command that failed: $(sed -n "${line_number}p" "$0")"
exit $exit_code
}
trap 'error_trap $LINENO' ERR

#Return current runnning kernel
get_running_kernel()
{
uname -r
}

# Install a single given package
install_package()
{
local pkg="$1"
local output
echo "Installing package $pkg ..."
if output=$(sudo yum install -y "$pkg" 2>&1) || output=$(sudo dnf install -y "$pkg" 2>&1); then
return 0
else
echo "Failed to install package $pkg:"
echo "$output"
return 1
fi
}

# Install all dependencies for this test
install_test_dependencies()
{
local deps_file="${SOURCE_DIR}/dependencies.txt"

if [ -f "$deps_file" ]; then
while IFS= read -r pkg || [ -n "$pkg" ]; do
# Skip empty lines and comments
[[ -z "$pkg" || "$pkg" =~ ^[[:space:]]*# ]] && continue

# Remove leading/trailing whitespace
pkg=$(echo "$pkg" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

# Install package if not empty
if [ -n "$pkg" ]; then
install_package "$pkg" || return 1
fi
done <"$deps_file"
else
# Fallback to hardcoded dependencies
install_package gcc make tar || return 1
fi
}

# List available kernels from S3
list_kernels_from_s3()
{
S3_PATH="s3://${RESULTS_BUCKET}/${RUN_PREFIX}/shared/kernel-rpms/binary/${ARCH}/"
aws s3 ls "${S3_PATH}" | grep "\.rpm$" | awk '{print $4}'
}

# Download specific kernel RPM from S3
download_kernel_rpm()
{
if [ -z "${1:-}" ]; then
echo "ERROR: download_kernel_rpm requires kernel_name parameter" >&2
return 1
fi
local kernel_name="$1"

S3_PATH="s3://${RESULTS_BUCKET}/${RUN_PREFIX}/shared/kernel-rpms/binary/${ARCH}/"

mkdir -p "$KERNEL_RPM_DIR"
local local_path="${KERNEL_RPM_DIR}/${kernel_name}"

# Download if not already present
if [ -f "$local_path" ]; then
echo "$local_path"
return 0
fi

if aws s3 cp "${S3_PATH}${kernel_name}" "$local_path" --no-progress >&2; then
echo "$local_path"
return 0
else
echo "ERROR: Failed to download kernel" >&2
return 1
fi
}

# Dump boot configuration for debugging kernel install issues
dump_boot_info()
{
echo "=== Boot Debug Info ==="
echo "--- OS ---"
head -2 /etc/os-release 2>/dev/null || true
echo "--- Running kernel ---"
uname -r
echo "--- Installed kernel packages ---"
rpm -qa 'kernel*' | sort
echo "--- vmlinuz files in /boot ---"
ls -la /boot/vmlinuz-* 2>/dev/null || echo "(none)"
echo "--- BLS entries ---"
ls -la /boot/loader/entries/ 2>/dev/null || echo "(no BLS directory)"
echo "--- grubby default ---"
sudo grubby --default-kernel 2>/dev/null || echo "(grubby --default-kernel failed)"
echo "--- grubby --info=ALL ---"
sudo grubby --info=ALL 2>/dev/null || echo "(grubby --info=ALL failed)"
echo "=== End Boot Debug Info ==="
}

# Install kernel RPM, make sure it's used as boot target
install_kernel_rpm()
{
if [ -z "${1:-}" ]; then
echo "ERROR: install_kernel_rpm requires kernel_rpm parameter" >&2
return 1
fi
local kernel_rpm="$1"

# Check architecture compatibility
local host_arch=$(uname -m)
local rpm_arch=$(rpm -qp --queryformat '%{ARCH}' "$kernel_rpm" 2>/dev/null)

if [ "$rpm_arch" != "$host_arch" ]; then
echo "ERROR: Architecture mismatch - Host: $host_arch, RPM: $rpm_arch" >&2
return 1
fi

echo "kernel before installation: $(uname -r)"
echo "Installing kernel from $kernel_rpm (arch: $rpm_arch)"

if sudo yum localinstall -y "$kernel_rpm" 2>/dev/null || sudo dnf install -y "$kernel_rpm" 2>/dev/null; then
dump_boot_info

# Set the newly installed kernel as default boot target.
# Without this, GRUB boots the newest kernel which may not be the one we just installed.
local installed_version
installed_version=$(rpm -qp --queryformat '%{VERSION}' "$kernel_rpm" 2>/dev/null)

# Find the grubby entry matching the installed kernel version.
# Use grep || true to avoid ERR trap when no match is found.
local grub_kernel
grub_kernel=$(sudo grubby --info=ALL 2>/dev/null \
| grep "^kernel=" \
| grep "$installed_version" \
| head -1 \
| sed 's/^kernel=//' \
| tr -d '"' \
|| true)

if [ -z "$grub_kernel" ]; then
# Upstream make binrpm-pkg kernels don't register with grubby.
# Find the vmlinuz file and add a boot entry manually.
local vmlinuz
vmlinuz=$(ls /boot/vmlinuz-*"$installed_version"* 2>/dev/null | head -1)
if [ -n "$vmlinuz" ]; then
echo "Adding grubby entry for $vmlinuz"
local initrd="/boot/initramfs-${installed_version}.img"
if [ ! -f "$initrd" ]; then
echo "Generating initramfs at $initrd"
sudo dracut --force "$initrd" "$installed_version" 2>/dev/null \
|| sudo mkinitrd "$initrd" "$installed_version" 2>/dev/null \
|| true
fi
if [ -f "$initrd" ]; then
sudo grubby --add-kernel="$vmlinuz" \
--initrd="$initrd" \
--title="Linux $installed_version" \
--copy-default \
--make-default
echo "✓ Added and set default: $vmlinuz"
else
echo "WARNING: No initramfs for $installed_version, trying set-default anyway"
sudo grubby --set-default="$vmlinuz" || true
fi
grub_kernel="$vmlinuz"
else
echo "WARNING: No vmlinuz found for version $installed_version"
fi
else
echo "Setting default boot kernel to $grub_kernel"
sudo grubby --set-default="$grub_kernel"
fi

if [ -n "$grub_kernel" ]; then
echo "Verifying default kernel:"
sudo grubby --default-kernel
fi
return 0
else
echo "ERROR: Failed to install new kernel" >&2
return 1
fi
}

# Return kernel RPM with lowest version (downloads from S3)
get_first_kernel_rpm_from_dir()
{
local kernels=$(list_kernels_from_s3 | sort -V)
local first_kernel=$(echo "$kernels" | head -n 1)

if [ -z "$first_kernel" ]; then
return 1
fi

download_kernel_rpm "$first_kernel"
}

# Return kernel RPM with highest version (downloads from S3)
get_last_kernel_rpm_from_dir()
{
local kernels=$(list_kernels_from_s3 | sort -V)
local last_kernel=$(echo "$kernels" | tail -n 1)

if [ -z "$last_kernel" ]; then
return 1
fi

download_kernel_rpm "$last_kernel"
}

# Install a given kernel RPM (passed as argument)
install_specified_kernel_rpm()
{
local kernel_rpm="$1"

if [ -z "$kernel_rpm" ]; then
echo "ERROR: install_specified_kernel_rpm requires a kernel RPM path"
return 1
fi

echo "Installing kernel RPM: $(basename "$kernel_rpm")"
install_kernel_rpm "$kernel_rpm"
}
# Common functions for the kernel reboot test.
#
# All kernel-management logic (environment validation, kernel RPM
# download/selection, install_kernel_rpm, reboot helpers) lives in the shared
# vm-tests/lib/kernel_helpers.sh, included here via the kernel_helpers.sh
# symlink in this directory. SOURCE_DIR is set by the run script before this
# file is sourced.
source "${SOURCE_DIR}/kernel_helpers.sh"
1 change: 1 addition & 0 deletions vm-tests/example-kernel-reboot-test/kernel_helpers.sh
Loading
Loading