Linux virtualization list
 help / color / mirror / Atom feed
From: Yury Norov <yury.norov@gmail.com>
To: Shrikanth Hegde <sshegde@linux.ibm.com>
Cc: linux-kernel@vger.kernel.org, mingo@kernel.org,
	peterz@infradead.org, juri.lelli@redhat.com,
	vincent.guittot@linaro.org, yury.norov@gmail.com,
	kprateek.nayak@amd.com, iii@linux.ibm.com, corbet@lwn.net,
	meted@linux.ibm.com, tglx@kernel.org, gregkh@linuxfoundation.org,
	pbonzini@redhat.com, seanjc@google.com, vschneid@redhat.com,
	huschle@linux.ibm.com, rostedt@goodmis.org,
	dietmar.eggemann@arm.com, maddy@linux.ibm.com,
	srikar@linux.ibm.com, hdanton@sina.com, chleroy@kernel.org,
	vineeth@bitbyteword.org, frederic@kernel.org, arighi@nvidia.com,
	pauld@redhat.com, christian.loehle@arm.com, tj@kernel.org,
	tommaso.cucinotta@gmail.com, maz@kernel.org, rafael@kernel.org,
	rdunlap@infradead.org, kernellwp@gmail.com,
	linux-doc@vger.kernel.org, jgross@suse.com,
	virtualization@lists.linux.dev
Subject: Re: [PATCH v10 00/12] sched, steal_governor: Introduce preferred CPUs and steal-driven vCPU backoff
Date: Fri, 21 Aug 2026 18:27:15 -0400	[thread overview]
Message-ID: <aojOp7KNsVGGb2CX@yury> (raw)
In-Reply-To: <20260812054033.95658-1-sshegde@linux.ibm.com>

> ========================================
> Performance Numbers (powerpc, x86, s390)
> ========================================
> 
> PowerPC:
> ===================
> VM1: 60VP/30EC and VM2: 30VP/20EC
> Shared physical CPU pool size: 50 Cores. Each core is SMT8.
> (VP - Virtual Core, EC - Entitles Core) -  PowerVM terminologies of SPLPAR[2]
> 
> Default parameter values: 1000ms, 200 low threshold, 500 high threshold
> Both the VMs are running the same workload. Total throughput/time of VM1+VM2
> is being mentioned in all cases.
> 
> Hackbench
>               baseline    steal_governor        steal_governor
>                              disabled               enabled
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 
> 10 groups        5.20   |    5.40 (-3.85%)  |     4.65 (+10.58%)
> 20 groups       11.39   |   12.01 (-5.44%)  |     7.09 (+37.75%)
> 40 groups       20.32   |   19.80 (+2.56%)  |    11.31 (+44.34%)
> 10 groups(-p)    2.37   |    2.26 (+4.64%)  |     2.06 (+13.08%)
> 20 groups(-p)    3.34   |    3.28 (+1.80%)  |     3.20 (+4.19%)
> 40 groups(-p)    4.46   |    4.83 (-8.30%)  |     4.26 (+4.48%)
> Remarks: Net improvement with steal_governor specially high load points.
> 
> schbench ( -L -n 0 -r 30 -s 0)
>               baseline    steal_governor          steal_governor
>                              disabled                 enabled
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> -m 1 -t 128     2475162 |    2621246 (+5.90%)  |      2527299 (+2.11%)
> -m 1 -t 256     1467350 |    1470032 (+0.18%)  |      1492372 (+1.71%)
> -m 1 -t 512     1408813 |    1454687 (+3.26%)  |      1437605 (+2.04%)
> Remarks: Effectively means no-improvements or regressions
> 
> kernbench	baseline    steal_governor     steal_governor
> (elapsed time)	               disabled            enabled
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> -j nr_cpus	231      |      235 (-1.7%) |    199 (+14%)
> Remarks: Net improvement in elapsed time.
> 
> Daytrader - A real life work which is a proxy for trading based
> on db2[3]
>               baseline      steal_governor   steal_governor
>                               disabled          enabled
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> Load@30%	1x	|	0.96x	|	 1.53x			
> Load@60%	1x	|	0.94x	|	 1.41x
> Remarks: Good improvement seen at different load points.
> 
> When there is no steal time (such as dedicated LPAR, or only VM2
> is running) throughput was same with steal_governor enabled/disabled
> which indicates minimal overhead of steal_governor. 
> 
> I have run v10 also on a smaller powerpc LPAR system and it shows
> good improvements.
> 
> =======================================================================
> 
> Data from x86,s390 KVM which Ilya Leoshkevich carried out during OSPM26
> time. *This was based on v2*. Idea is still the name, numbers are
> expected to be better in v10 as some of the overhead has been removed.
> Note: Other variations of the benchmark shows no observable
> difference.
> 
> x86:
> ====
> cascade-lake: 32 threads = 16 cores
> Benchmark      #VMs    #CPUs/VM  ΔRPS     (%std)
> ===============================================
> hackbench         8          16  90.73% ± 9.97%
> hackbench         4          24  52.67% ± 7.43%
> hackbench         4          16  37.96% ± 11.19%
> hackbench         4          32  37.82% ± 4.38%
> hackbench        12           8  36.90% ± 4.74%
> hackbench         8           8  35.30% ± 3.61%
> pgbench          16           4  31.77% ± 2.44%
> hackbench         2          24  25.85% ± 8.63%
> hackbench        16           8  24.87% ± 3.46%
> pgbench          16           8  21.83% ± 2.20%
> pgbench          12           8  21.35% ± 2.15%
> pgbench           8           8  18.46% ± 1.01%
> hackbench         2          32  15.56% ± 4.53%
> pgbench          12           4  14.28% ± 2.04%
> hackbench        16           4  14.07% ± 2.90%
> hackbench        12           4  9.60% ± 3.49%
> [...]
> pgbench           4           8  -1.16% ± 3.60%
> hackbench         4           4  -1.80% ± 9.55%
> sysbench         12           4  -2.19% ± 0.78%
> pgbench           4          24  -2.43% ± 4.38%
> pgbench           4          32  -3.21% ± 0.79%
> sysbench         16           4  -3.22% ± 1.09%
> 
> S390:
> =====
> z16: 16 threads = 8 cores (SMT-2)
> Benchmark      #VMs    #CPUs/VM  ΔRPS    (std%)
> ===============================================
> pgbench           2           8  73.50% ± 35.91%
> pgbench          16           4  61.30% ± 4.09%
> hackbench        16           4  54.11% ± 4.38%
> hackbench        12           4  36.34% ± 4.63%
> pgbench          12           4  34.83% ± 2.57%
> hackbench         8           4  29.75% ± 5.86%
> hackbench         8           8  25.98% ± 5.09%
> pgbench           2           4  23.31% ± 33.44%
> pgbench           2          16  19.95% ± 17.12%
> hackbench         4           8  19.43% ± 9.33%
> pgbench           8           4  19.32% ± 4.50%
> [...]
> schbench          8           8  -0.79% ± 0.33%
> sysbench          8           8  -0.81% ± 0.39%
> hackbench         4          16  -1.11% ± 5.82%
> sysbench          8           4  -1.62% ± 0.49%
> sysbench         16           4  -2.70% ± 0.58%
> schbench         16           4  -2.73% ± 0.91%
> sysbench         12           4  -2.91% ± 0.61%
> hackbench         2          24  -4.99% ± 3.31%
> 
> Summary:
> - Many improvement across archs specially with real life workloads.
> - No major regressions observed.
> - Overhead of steal_governor looks minimal when there is no steal time.
> - Overhead when STEAL_GOVERNOR=n is negligible.

OK, I gave it some testing on my laptop.

The results are pretty consistent: the steal ratio is converged to a
number withing the threshold, but the overall performance is 3-5% worse
comparing to baseline. I tried 2-5% and 1.5-15% boundaries.

It's 4 VMs, each running 8 vCPUs on 8 pCPU machine, the payload is
running for 2 minutes.

  Steal governor off:
  VM         THROUGHPUT       AVG STEAL%
  -------- ------------ ----------------
  0               13802            74.59
  1               11929            76.35
  2               13470            74.61
  3               10259            78.67
  -------- ------------ ----------------
  TOTAL           49460                -
  
  Steal governor on:
  VM         THROUGHPUT       AVG STEAL%
  -------- ------------ ----------------
  0               12921             5.72
  1               12762             6.11
  2               10160             5.99
  3               12098             6.00
  -------- ------------ ----------------
  TOTAL           47941                -


The test is attached below. The results are quite differ from the numbers
above, so maybe I misconfigured something? I didn't use hackbench or
similar benchmarks, just a basic math.

Shrikanth, can you please check my test and results? Is there something 
that I have missed?

I think this series should include some testing. The scripts below look
bulky and they depend on virtme, but they allow to build the proper
kernel and run tests with a single command.

Thanks,
Yury

From 27e548d65bbe0ec01308d3329017619e165d0488 Mon Sep 17 00:00:00 2001
From: Yury Norov <ynorov@nvidia.com>
Date: Wed, 19 Aug 2026 16:31:33 -0400
Subject: [PATCH] steal governor: add testing harness based on vng

Signed-off-by: Yury Norov <ynorov@nvidia.com>
---
 .../virtme-steal-payload.sh                   | 220 ++++++++++++
 .../steal_governor_test/virtme-steal-time.sh  | 321 ++++++++++++++++++
 2 files changed, 541 insertions(+)
 create mode 100755 drivers/virt/steal_governor_test/virtme-steal-payload.sh
 create mode 100755 drivers/virt/steal_governor_test/virtme-steal-time.sh

diff --git a/drivers/virt/steal_governor_test/virtme-steal-payload.sh b/drivers/virt/steal_governor_test/virtme-steal-payload.sh
new file mode 100755
index 000000000000..02a245a900b8
--- /dev/null
+++ b/drivers/virt/steal_governor_test/virtme-steal-payload.sh
@@ -0,0 +1,220 @@
+#!/bin/sh
+# Guest-side measurable workload for the steal governor test.
+
+set -eu
+
+case $# in
+2|3|5) ;;
+*)
+	echo "usage: ${0##*/} VM_ID DURATION_SECONDS [DRIVER [LOW_THRESHOLD HIGH_THRESHOLD]]" >&2
+	exit 2
+	;;
+esac
+
+vm_id=$1
+duration=$2
+driver=${3-}
+low_threshold=${4-}
+high_threshold=${5-}
+
+verify_parameter()
+{
+	parameter=$1
+	expected=$2
+	parameter_file=/sys/module/$driver_sysfs/parameters/$parameter
+
+	if [ ! -r "$parameter_file" ]; then
+		echo "error: driver $driver has no readable $parameter parameter" >&2
+		exit 1
+	fi
+	actual=$(cat "$parameter_file")
+	if [ "$actual" != "$expected" ]; then
+		echo "error: driver $driver $parameter is $actual, expected $expected" >&2
+		exit 1
+	fi
+}
+
+case $vm_id in
+*[!0-9]*|'')
+	echo "error: VM_ID must be a non-negative integer" >&2
+	exit 2
+	;;
+esac
+case $duration in
+*[!0-9]*|'')
+	echo "error: DURATION_SECONDS must be a positive integer" >&2
+	exit 2
+	;;
+esac
+if [ "$duration" -eq 0 ]; then
+	echo "error: DURATION_SECONDS must be greater than zero" >&2
+	exit 2
+fi
+if [ -n "$driver" ]; then
+	case $driver in
+	*[!A-Za-z0-9_.-]*)
+		echo "error: invalid driver module name: $driver" >&2
+		exit 2
+		;;
+	esac
+	if [ -n "$low_threshold" ]; then
+		case $low_threshold:$high_threshold in
+		*[!0-9:]*|:*|*:)
+			echo "error: thresholds must be non-negative integers in percent * 100" >&2
+			exit 2
+			;;
+		esac
+		if [ "$low_threshold" -ge "$high_threshold" ] ||
+		   [ "$high_threshold" -ge 10000 ]; then
+			echo "error: thresholds must satisfy 0 <= LOW < HIGH < 10000" >&2
+			exit 2
+		fi
+	fi
+	if ! command -v modprobe >/dev/null; then
+		echo "error: modprobe is required to load driver $driver" >&2
+		exit 1
+	fi
+	driver_sysfs=$(printf '%s\n' "$driver" | tr '-' '_')
+	if [ ! -d "/sys/module/$driver_sysfs" ]; then
+		if [ -n "$low_threshold" ]; then
+			modprobe "$driver" \
+				low_threshold="$low_threshold" \
+				high_threshold="$high_threshold"
+		else
+			modprobe "$driver"
+		fi
+	fi
+	if [ ! -d "/sys/module/$driver_sysfs" ]; then
+		echo "error: driver $driver has no /sys/module/$driver_sysfs entry after modprobe" >&2
+		exit 1
+	fi
+	if [ -n "$low_threshold" ]; then
+		verify_parameter low_threshold "$low_threshold"
+		verify_parameter high_threshold "$high_threshold"
+	fi
+fi
+
+tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/virtme-steal-payload.XXXXXXXX")
+before=$tmpdir/before
+after=$tmpdir/after
+pids=
+
+stop_workers()
+{
+	for pid in $pids; do
+		kill "$pid" 2>/dev/null || :
+	done
+	for pid in $pids; do
+		wait "$pid" 2>/dev/null || :
+	done
+	pids=
+}
+
+cleanup()
+{
+	stop_workers
+	rm -rf -- "$tmpdir"
+}
+trap cleanup EXIT
+trap 'exit 130' INT
+trap 'exit 143' TERM
+
+awk '$1 ~ /^cpu[0-9]+$/ { print $1, $9 }' /proc/stat >"$before"
+start_time=$(awk '{ print $1 }' /proc/uptime)
+deadline=$(awk -v start="$start_time" -v seconds="$duration" \
+	'BEGIN { printf "%.2f", start + seconds }')
+workers=$(awk '$1 ~ /^cpu[0-9]+$/ { n++ } END { print n }' /proc/stat)
+
+i=0
+while [ "$i" -lt "$workers" ]; do
+	result=$tmpdir/work-$i
+	awk -v deadline="$deadline" -v result="$result" '
+		function uptime(    line, fields) {
+			getline line < "/proc/uptime"
+			close("/proc/uptime")
+			split(line, fields)
+			return fields[1]
+		}
+		BEGIN {
+			batch = 1000
+			units = 0
+			value = 1
+			while (uptime() < deadline) {
+				for (iteration = 0; iteration < batch; iteration++)
+					value = (value * 1103515245 + 12345) % 2147483647
+				units++
+			}
+			printf "%.0f %.0f\n", units, units * batch > result
+		}
+	' </dev/null &
+	pids="$pids $!"
+	i=$((i + 1))
+done
+
+worker_failed=0
+for pid in $pids; do
+	wait "$pid" || worker_failed=1
+done
+pids=
+if [ "$worker_failed" -ne 0 ]; then
+	echo "error: one or more workload processes failed" >&2
+	exit 1
+fi
+
+awk '$1 ~ /^cpu[0-9]+$/ { print $1, $9 }' /proc/stat >"$after"
+end_time=$(awk '{ print $1 }' /proc/uptime)
+elapsed=$(awk -v start="$start_time" -v end="$end_time" \
+	'BEGIN { printf "%.2f", end - start }')
+clk_tck=$(getconf CLK_TCK 2>/dev/null || echo 100)
+
+echo VIRTME_STEAL_REPORT_BEGIN
+driver_status=none
+[ -n "$driver" ] && driver_status=$driver:loaded
+[ -n "$low_threshold" ] && \
+	driver_status="$driver_status,thresholds=$low_threshold..$high_threshold"
+echo "VM $vm_id  kernel=$(uname -r)  vCPUs=$workers  sample=${elapsed}s  driver=$driver_status"
+echo "Workload (unpinned workers)"
+printf '%-10s %12s %16s %16s\n' \
+	WORKER WORK_UNITS ITERATIONS ITERATIONS/s
+printf '%-10s %12s %16s %16s\n' \
+	---------- ------------ ---------------- ----------------
+total_units=0
+total_iterations=0
+i=0
+while [ "$i" -lt "$workers" ]; do
+	read -r units iterations <"$tmpdir/work-$i"
+	rate=$(awk -v iterations="$iterations" -v elapsed="$elapsed" \
+		'BEGIN { printf "%.0f", iterations / elapsed }')
+	printf '%-10s %12s %16s %16s\n' \
+		"worker$i" "$units" "$iterations" "$rate"
+	total_units=$((total_units + units))
+	total_iterations=$((total_iterations + iterations))
+	i=$((i + 1))
+done
+total_rate=$(awk -v iterations="$total_iterations" -v elapsed="$elapsed" \
+	'BEGIN { printf "%.0f", iterations / elapsed }')
+throughput=$(awk -v units="$total_units" -v elapsed="$elapsed" \
+	'BEGIN { printf "%.0f", units / elapsed }')
+printf '%-10s %12s %16s %16s\n' \
+	TOTAL "$total_units" "$total_iterations" "$total_rate"
+
+echo "Steal time by guest CPU"
+printf '%-8s %12s %12s %10s\n' CPU STEAL_TICKS STEAL_s STEAL_%
+printf '%-8s %12s %12s %10s\n' -------- ------------ ------------ ----------
+average_file=$tmpdir/average-steal
+awk -v hz="$clk_tck" -v elapsed="$elapsed" -v cpus="$workers" \
+	-v average_file="$average_file" '
+	NR == FNR { before[$1] = $2; next }
+	{
+		delta = $2 - before[$1]
+		total += delta
+		printf "%-8s %12d %12.2f %10.2f\n", $1, delta,
+		       delta / hz, 100 * delta / hz / elapsed
+	}
+	END {
+		printf "%.2f\n", 100 * total / hz / elapsed / cpus > average_file
+	}
+' "$before" "$after"
+average_steal=$(cat "$average_file")
+echo "VIRTME_STEAL_SUMMARY $vm_id $throughput $average_steal"
+echo VIRTME_STEAL_REPORT_END
diff --git a/drivers/virt/steal_governor_test/virtme-steal-time.sh b/drivers/virt/steal_governor_test/virtme-steal-time.sh
new file mode 100755
index 000000000000..a41d362c7888
--- /dev/null
+++ b/drivers/virt/steal_governor_test/virtme-steal-time.sh
@@ -0,0 +1,321 @@
+#!/usr/bin/env bash
+# Build a minimal KVM guest kernel and measure per-vCPU steal time under load.
+
+set -euo pipefail
+
+script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+kernel_dir=$(CDPATH= cd -- "$script_dir/../../.." && pwd)
+vng=${VNG:-vng}
+build_dir=${BUILD_DIR:-"$kernel_dir/.virtme-steal"}
+payload=${PAYLOAD:-"$script_dir/virtme-steal-payload.sh"}
+vm_count=4
+vcpu_count=$(nproc)
+duration=20
+memory=512M
+driver=
+low_threshold=
+high_threshold=
+verbose=0
+declare -a config_items=()
+
+usage()
+{
+	cat <<EOF
+Usage: ${0##*/} [options] [O=DIR]
+
+Build a virtme-ng minimal kernel with paravirtual steal-time accounting,
+start multiple CPU-bound VMs, and report the steal time of every guest CPU.
+
+Options:
+  -n VMS       number of VMs to run (default: $vm_count)
+  -p VCPUS     vCPUs per VM (default: $vcpu_count)
+  -d SECONDS   workload duration (default: $duration)
+  -m MEMORY    memory per VM (default: $memory)
+  --configitem CONFIG[=VALUE]
+                enable or set a kernel config option (repeatable)
+  --driver MODULE
+                load and verify this module before running the payload
+  -lo VALUE     low steal threshold in percent * 100 (for example, 150 = 1.5%)
+  -hi VALUE     high steal threshold in percent * 100 (for example, 550 = 5.5%)
+  -O DIR       kernel build directory (default: $build_dir)
+  -v, --verbose show per-worker and per-CPU result tables
+  -h            show this help
+
+Environment equivalents: VNG, BUILD_DIR, and PAYLOAD. A custom payload is
+called inside each VM as: PAYLOAD VM_ID DURATION_SECONDS
+[DRIVER [LOW_THRESHOLD HIGH_THRESHOLD]].
+
+Local virtme-ng checkout example:
+  VNG=../virtme-ng/vng ${0##*/}
+
+The positional O=DIR form is equivalent to -O DIR, for example:
+  ${0##*/} -n 4 O=../build-linux-virtme-steal
+
+Config examples:
+  ${0##*/} --configitem CONFIG_SCHEDSTATS --configitem CONFIG_HZ_1000=y
+
+Threshold example:
+  ${0##*/} --driver steal_governor -lo 150 -hi 550
+EOF
+}
+
+while (($#)); do
+	case $1 in
+	-n|-p|-d|-m|-O|-lo|-hi|--configitem|--driver)
+		if (($# < 2)); then
+			echo "error: $1 requires an argument" >&2
+			exit 2
+		fi
+		case $1 in
+		-n) vm_count=$2 ;;
+		-p) vcpu_count=$2 ;;
+		-d) duration=$2 ;;
+		-m) memory=$2 ;;
+		-O) build_dir=$2 ;;
+		-lo) low_threshold=$2 ;;
+		-hi) high_threshold=$2 ;;
+		--configitem) config_items+=("$2") ;;
+		--driver) driver=$2 ;;
+		esac
+		shift 2
+		;;
+	--configitem=?*)
+		config_items+=("${1#*=}")
+		shift
+		;;
+	--driver=?*)
+		driver=${1#*=}
+		shift
+		;;
+	-v|--verbose)
+		verbose=1
+		shift
+		;;
+	-h|--help)
+		usage
+		exit 0
+		;;
+	O=?*)
+		build_dir=${1#O=}
+		shift
+		;;
+	O=|--configitem=|--driver=)
+		echo "error: ${1%%=*}= requires a non-empty argument" >&2
+		exit 2
+		;;
+	*)
+		echo "error: unexpected argument: $1" >&2
+		usage >&2
+		exit 2
+		;;
+	esac
+done
+
+require_positive_integer()
+{
+	local name=$1 value=$2
+
+	if [[ ! $value =~ ^[1-9][0-9]*$ ]]; then
+		echo "error: $name must be a positive integer (got '$value')" >&2
+		exit 2
+	fi
+}
+
+require_positive_integer "VM count" "$vm_count"
+require_positive_integer "vCPU count" "$vcpu_count"
+require_positive_integer "duration" "$duration"
+
+if [[ -n $low_threshold || -n $high_threshold ]]; then
+	if [[ -z $low_threshold || -z $high_threshold ]]; then
+		echo "error: -lo and -hi must be specified together" >&2
+		exit 2
+	fi
+	if [[ ! $low_threshold =~ ^[0-9]+$ || ! $high_threshold =~ ^[0-9]+$ ]]; then
+		echo "error: -lo and -hi must be non-negative integers in percent * 100" >&2
+		exit 2
+	fi
+	low_threshold=$((10#$low_threshold))
+	high_threshold=$((10#$high_threshold))
+	if ((low_threshold >= high_threshold)); then
+		echo "error: -lo must be less than -hi" >&2
+		exit 2
+	fi
+	if ((high_threshold >= 10000)); then
+		echo "error: -hi must be less than 10000 (100%)" >&2
+		exit 2
+	fi
+	if [[ -z $driver ]]; then
+		echo "error: -lo and -hi require --driver MODULE" >&2
+		exit 2
+	fi
+fi
+
+if [[ -n $driver && ! $driver =~ ^[A-Za-z0-9_.-]+$ ]]; then
+	echo "error: invalid driver module name: $driver" >&2
+	exit 2
+fi
+
+for index in "${!config_items[@]}"; do
+	if [[ ! ${config_items[index]} =~ ^CONFIG_[A-Z0-9_]+(=.*)?$ ]]; then
+		echo "error: invalid kernel config item: ${config_items[index]}" >&2
+		exit 2
+	fi
+	if [[ ${config_items[index]} != *=* ]]; then
+		config_items[index]="${config_items[index]}=y"
+	fi
+done
+
+if [[ ! -x $payload ]]; then
+	echo "error: guest payload is not executable: $payload" >&2
+	exit 1
+fi
+if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then
+	echo "error: /dev/kvm is not accessible; KVM is required for steal-time accounting" >&2
+	exit 1
+fi
+
+case $build_dir in
+/*) ;;
+*) build_dir=$PWD/$build_dir ;;
+esac
+
+mkdir -p "$build_dir"
+cd "$kernel_dir"
+
+echo "==> Configuring paravirtual kernel in $build_dir"
+if [[ ! -f $build_dir/.config ]]; then
+	config_args=()
+	for config_item in "${config_items[@]}"; do
+		config_args+=(--configitem "$config_item")
+	done
+	"$vng" --kconfig "${config_args[@]}" \
+		--configitem CONFIG_HYPERVISOR_GUEST=y \
+		--configitem CONFIG_PARAVIRT=y \
+		--configitem CONFIG_KVM_GUEST=y \
+		--configitem CONFIG_PARAVIRT_TIME_ACCOUNTING=y \
+		-- "O=$build_dir"
+else
+	# Preserve an existing local minimal config and add the options needed by
+	# this test. olddefconfig resolves their dependencies for the current tree.
+	config_args=(--file "$build_dir/.config")
+	for config_item in "${config_items[@]}"; do
+		config_name=${config_item%%=*}
+		config_value=${config_item#*=}
+		config_args+=(--set-val "$config_name" "$config_value")
+	done
+	"$kernel_dir/scripts/config" "${config_args[@]}" \
+		-e HYPERVISOR_GUEST \
+		-e PARAVIRT \
+		-e KVM_GUEST \
+		-e PARAVIRT_TIME_ACCOUNTING
+	make -s O="$build_dir" olddefconfig
+fi
+
+echo "==> Building kernel"
+declare -a module_args=()
+if [[ -z $driver ]]; then
+	module_args+=(--skip-modules)
+fi
+"$vng" --build "${module_args[@]}" -- "O=$build_dir"
+
+for option in HYPERVISOR_GUEST PARAVIRT KVM_GUEST PARAVIRT_TIME_ACCOUNTING; do
+	if ! grep -qx "CONFIG_${option}=y" "$build_dir/.config"; then
+		echo "error: CONFIG_${option}=y is required but is absent after configuration" >&2
+		exit 1
+	fi
+done
+
+tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/virtme-steal.XXXXXXXX")
+declare -a vm_pids=()
+
+cleanup()
+{
+	local pid
+
+	for pid in "${vm_pids[@]}"; do
+		kill "$pid" 2>/dev/null || true
+	done
+	wait 2>/dev/null || true
+	rm -rf -- "$tmpdir"
+}
+trap cleanup EXIT
+trap 'exit 130' INT
+trap 'exit 143' TERM
+
+echo "==> Starting $vm_count VMs ($vcpu_count vCPUs each)"
+for ((vm = 0; vm < vm_count; vm++)); do
+	printf -v guest_script '%q %q %q' "$payload" "$vm" "$duration"
+	if [[ -n $driver ]]; then
+		printf -v driver_arg ' %q' "$driver"
+		guest_script+=$driver_arg
+		if [[ -n $low_threshold ]]; then
+			printf -v threshold_args ' %q %q' \
+				"$low_threshold" "$high_threshold"
+			guest_script+=$threshold_args
+		fi
+	fi
+
+	log=$tmpdir/vm-$vm.log
+	"$vng" \
+		"${module_args[@]}" \
+		--name "steal-vm-$vm" \
+		--cpus "$vcpu_count" \
+		--memory "$memory" \
+		--exec "$guest_script" \
+		-- "O=$build_dir" >"$log" 2>&1 &
+	vm_pids+=("$!")
+done
+
+status=0
+total_throughput=0
+if (( ! verbose )); then
+	printf '%-8s %12s %16s\n' VM THROUGHPUT 'AVG STEAL%'
+	printf '%-8s %12s %16s\n' -------- ------------ ----------------
+fi
+for ((vm = 0; vm < vm_count; vm++)); do
+	if ! wait "${vm_pids[vm]}"; then
+		echo "error: VM $vm failed; its complete log follows" >&2
+		status=1
+		echo "--- VM $vm log ---"
+		cat "$tmpdir/vm-$vm.log"
+		continue
+	fi
+	if ! grep -qx VIRTME_STEAL_REPORT_BEGIN "$tmpdir/vm-$vm.log" ||
+	   ! grep -qx VIRTME_STEAL_REPORT_END "$tmpdir/vm-$vm.log"; then
+		echo "error: VM $vm exited without a steal-time report; its complete log follows" >&2
+		cat "$tmpdir/vm-$vm.log"
+		status=1
+		continue
+	fi
+
+	summary=$(awk '/^VIRTME_STEAL_SUMMARY / { print $2, $3, $4 }' \
+		"$tmpdir/vm-$vm.log")
+	if [[ -z $summary ]]; then
+		echo "error: VM $vm exited without a summary; its complete log follows" >&2
+		cat "$tmpdir/vm-$vm.log"
+		status=1
+		continue
+	fi
+
+	if (( verbose )); then
+		echo "--- VM $vm results ---"
+		awk '
+			/^VIRTME_STEAL_REPORT_BEGIN$/ { report = 1; next }
+			/^VIRTME_STEAL_REPORT_END$/ { report = 0 }
+			/^VIRTME_STEAL_SUMMARY / { next }
+			report
+		' "$tmpdir/vm-$vm.log"
+	else
+		read -r summary_vm summary_throughput summary_steal <<<"$summary"
+		printf '%-8s %12s %16s\n' \
+			"$summary_vm" "$summary_throughput" "$summary_steal"
+		total_throughput=$((total_throughput + summary_throughput))
+	fi
+done
+
+if (( ! verbose )); then
+	printf '%-8s %12s %16s\n' -------- ------------ ----------------
+	printf '%-8s %12s %16s\n' TOTAL "$total_throughput" -
+fi
+
+exit "$status"
-- 
2.53.0


      parent reply	other threads:[~2026-08-21 22:27 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-12  5:40 [PATCH v10 00/12] sched, steal_governor: Introduce preferred CPUs and steal-driven vCPU backoff Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 01/12] sched/cputime: Add kcpustat_field_total helper Shrikanth Hegde
2026-08-12 18:44   ` Yury Norov
2026-08-14  9:04   ` Mete Durlu
2026-08-12  5:40 ` [PATCH v10 02/12] sched/docs: Document cpu_preferred_mask and Preferred CPU concept Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 03/12] cpumask: Introduce cpu_preferred_mask Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 04/12] sysfs: Add preferred CPU file Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 05/12] sched/core: Try to use a preferred CPU in is_cpu_allowed Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 06/12] sched/fair: Load balance only among preferred CPUs Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 07/12] sched/core: Push current task from non preferred CPU Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 08/12] sched/debug: Add migration stats due to non preferred CPUs Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 09/12] virt: Introduce steal governor driver Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 10/12] virt/steal_governor: Add control knobs for handling steal values Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 11/12] virt/steal_governor: Implement steal_governor policy loop Shrikanth Hegde
2026-08-12  5:40 ` [PATCH v10 12/12] virt/steal_governor: Enable the driver Shrikanth Hegde
2026-08-12 19:45 ` [PATCH] Re: [PATCH v10 00/12] sched, steal_governor: Introduce preferred CPUs and steal-driven vCPU backoff Ionut Nechita (Sunlight Linux)
2026-08-13  0:13   ` Yury Norov
2026-08-13  6:50     ` Mete Durlu
2026-08-13 11:12       ` Shrikanth Hegde
2026-08-14  9:22         ` Mete Durlu
2026-08-14 11:08           ` Shrikanth Hegde
2026-08-13 10:56     ` Shrikanth Hegde
2026-08-17  7:39 ` Shrikanth Hegde
2026-08-21 22:27 ` Yury Norov [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aojOp7KNsVGGb2CX@yury \
    --to=yury.norov@gmail.com \
    --cc=arighi@nvidia.com \
    --cc=chleroy@kernel.org \
    --cc=christian.loehle@arm.com \
    --cc=corbet@lwn.net \
    --cc=dietmar.eggemann@arm.com \
    --cc=frederic@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=hdanton@sina.com \
    --cc=huschle@linux.ibm.com \
    --cc=iii@linux.ibm.com \
    --cc=jgross@suse.com \
    --cc=juri.lelli@redhat.com \
    --cc=kernellwp@gmail.com \
    --cc=kprateek.nayak@amd.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maddy@linux.ibm.com \
    --cc=maz@kernel.org \
    --cc=meted@linux.ibm.com \
    --cc=mingo@kernel.org \
    --cc=pauld@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rafael@kernel.org \
    --cc=rdunlap@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=seanjc@google.com \
    --cc=srikar@linux.ibm.com \
    --cc=sshegde@linux.ibm.com \
    --cc=tglx@kernel.org \
    --cc=tj@kernel.org \
    --cc=tommaso.cucinotta@gmail.com \
    --cc=vincent.guittot@linaro.org \
    --cc=vineeth@bitbyteword.org \
    --cc=virtualization@lists.linux.dev \
    --cc=vschneid@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox