From: Yury Norov <ynorov@nvidia.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,
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
Subject: Re: [PATCH v7 11/12] virt/steal_monitor: Act on steal time periodically and decide on preferred CPUs
Date: Fri, 10 Jul 2026 16:37:03 -0400 [thread overview]
Message-ID: <alFX75dzgkMnDXAD@yury> (raw)
In-Reply-To: <20260709215648.1246821-12-sshegde@linux.ibm.com>
On Fri, Jul 10, 2026 at 03:26:47AM +0530, Shrikanth Hegde wrote:
> schedule work at regular intervals. Interval is determined by
> interval_ms parameter. schedule_delayed_work is used since interval_ms
> is usually in order of milliseconds. Work need not happen instantly.
>
> Periodic work function essentially does:
> - Calculate the steal_ratio as below.
>
> steal_ratio = (delta_steal * 100*100)/(delta_ns * num_cpus())
>
> It is calculated to consider the fractional values of steal time.
> I.e 10 means 0.1% steal time. A few tricks such as divide by 10,000
> are used to avoid possible overflow.
> - If steal value is higher than high threshold, call the method to reduce
> the preferred CPUs.
> - If steal value is lower or equal to low threshold, call the method to
> increase the preferred CPUs.
> - If the steal value is in between, no action is taken.
> - Save the values for next delta calculations.
> - Save the current direction of steal values to avoid oscillations.
> So two consecutive values of high values or low values are taken for
> decrease/increase of preferred CPUs.
> - Ensure design checks are met.
> 1. At least one core/CPU must be there in preferred mask.
> 2. preferred CPUs is subset of active CPUs.
>
> Signed-off-by: Shrikanth Hegde <sshegde@linux.ibm.com>
> ---
> v6->v7:
> - Merge two patches which did periodic work function.
> - Misc checks for early firing, requeue work, math safety.
>
> drivers/virt/steal_monitor/sm_core.c | 76 +++++++++++++++++++++++++++-
> drivers/virt/steal_monitor/sm_core.h | 1 +
> 2 files changed, 76 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/virt/steal_monitor/sm_core.c b/drivers/virt/steal_monitor/sm_core.c
> index 4a03c14337be..09a5c3a299c3 100644
> --- a/drivers/virt/steal_monitor/sm_core.c
> +++ b/drivers/virt/steal_monitor/sm_core.c
> @@ -20,6 +20,12 @@ struct steal_monitor sm_core_ctx = {
> .low_threshold = 200, /* 2% */
> };
>
> +enum sm_direction {
> + SM_DIR_INCREASE = -1,
> + SM_DIR_NONE = 0,
> + SM_DIR_DECREASE = 1,
> +};
> +
> static int param_set_interval_ms(const char *val, const struct kernel_param *kp)
> {
> unsigned int interval;
> @@ -106,14 +112,82 @@ module_param_cb(low_threshold, &low_threshold_ops, &sm_core_ctx.low_threshold, 0
> MODULE_PARM_DESC(low_threshold,
> "Low steal threshold. default: 200 i.e 2%. Must be < high_threshold");
>
> +static void compute_preferred_cpus_work(struct work_struct *work)
> +{
> + u64 curr_steal, delta_steal, delta_ns, steal_ratio;
> + ktime_t now;
> +
> + now = ktime_get();
> + delta_ns = ktime_to_ns(ktime_sub(now, sm_core_ctx.prev_time));
> +
> + if (unlikely(delta_ns < NSEC_PER_MSEC)) {
> + pr_err_ratelimited("steal_monitor: work scheduled too soon delta_ns: %llu\n",
> + delta_ns);
> + goto requeue_work;
> + }
> +
> + curr_steal = get_system_steal_time();
> + delta_steal = curr_steal > sm_core_ctx.prev_steal ?
> + curr_steal - sm_core_ctx.prev_steal : 0;
> +
> + /* Update for next calculation */
> + sm_core_ctx.prev_steal = curr_steal;
> + sm_core_ctx.prev_time = now;
> +
> + /*
> + * steal_ratio = (delta_steal * 100*100)/(delta_ns * num_cpus())
> + * To avoid possible overflow, divide the denominator early.
> + * Note minimum interval is 10ms.
> + */
> + delta_ns = div_u64(delta_ns * get_num_cpus_steal_ratio(), 100 * 100);
> + steal_ratio = div64_u64(delta_steal, delta_ns);
> +
> + if (sm_core_ctx.prev_direction == SM_DIR_DECREASE &&
> + steal_ratio > sm_core_ctx.high_threshold)
> + decrease_preferred_cpus(&sm_core_ctx);
> + if (sm_core_ctx.prev_direction == SM_DIR_INCREASE &&
> + steal_ratio <= sm_core_ctx.low_threshold)
> + increase_preferred_cpus(&sm_core_ctx);
I already said, I don't like this SM_DIR approach. If you want to
avoid oscillations, just increase the gap. If it doesn't work, then we
need to understand why.
> +
> + /*
> + * mark the direction. Increasing the gap between hi and lo_threshold
> + * helps to avoid ping-pongs.
> + */
> + if (steal_ratio > sm_core_ctx.high_threshold)
> + sm_core_ctx.prev_direction = SM_DIR_DECREASE;
> + else if (steal_ratio <= sm_core_ctx.low_threshold)
> + sm_core_ctx.prev_direction = SM_DIR_INCREASE;
> + else
> + sm_core_ctx.prev_direction = SM_DIR_NONE;
> +
> +requeue_work:
> + /* maintain design constructs always */
> + WARN_ON_ONCE(cpumask_empty(cpu_preferred_mask));
> + WARN_ON_ONCE(!cpumask_subset(cpu_preferred_mask, cpu_active_mask));
cpu_read_lock here? And again, you should do something to restore
integrity. WARN_ON is not enough. The simplest and safest thing you
can do is to unload the driver. You definitely shouldn't schedule a
new work against the broken cpu_preferred_mask.
> +
> + /* Trigger for next sampling */
> + schedule_delayed_work(&sm_core_ctx.work,
> + msecs_to_jiffies(sm_core_ctx.interval_ms));
> +}
> +
> static int __init steal_monitor_init(void)
> {
> - pr_info("steal_monitor is enabled\n");
> + pr_info("steal_monitor is enabled. interval: %ums, high_threshold: %u, low_threshold: %u\n",
> + sm_core_ctx.interval_ms, sm_core_ctx.high_threshold, sm_core_ctx.low_threshold);
> +
> + INIT_DELAYED_WORK(&sm_core_ctx.work, compute_preferred_cpus_work);
> + sm_core_ctx.prev_steal = get_system_steal_time();
> + sm_core_ctx.prev_time = ktime_get();
> +
> + schedule_delayed_work(&sm_core_ctx.work,
> + msecs_to_jiffies(sm_core_ctx.interval_ms));
> +
> return 0;
> }
>
> static void __exit steal_monitor_exit(void)
> {
> + cancel_delayed_work_sync(&sm_core_ctx.work);
cancel_delayed_work_sync() is not enough for a self-requeueing work.
compute_preferred_cpus_work() always requeues itself. Module unload
can return with delayed work armed against module text/data. Use
disable_delayed_work_sync() or a stop flag checked before requeueing.
> guard(cpus_read_lock)();
> cpumask_copy(&__cpu_preferred_mask, cpu_active_mask);
>
> diff --git a/drivers/virt/steal_monitor/sm_core.h b/drivers/virt/steal_monitor/sm_core.h
> index ee68cd8b1944..7c7a9bced682 100644
> --- a/drivers/virt/steal_monitor/sm_core.h
> +++ b/drivers/virt/steal_monitor/sm_core.h
> @@ -14,6 +14,7 @@
> #include <linux/kernel_stat.h>
> #include <linux/topology.h>
> #include <linux/sched/isolation.h>
> +#include <linux/math64.h>
>
> struct steal_monitor {
> struct delayed_work work;
> --
> 2.47.3
next prev parent reply other threads:[~2026-07-10 20:37 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 21:56 [PATCH v7 00/12] sched, steal_monitor: Introduce cpu_preferred_mask and steal-driven vCPU backoff Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 01/12] sched/docs: Document cpu_preferred_mask and Preferred CPU concept Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 02/12] cpumask: Introduce cpu_preferred_mask Shrikanth Hegde
2026-07-13 14:53 ` Yury Norov
2026-07-14 6:30 ` Shrikanth Hegde
2026-07-14 13:01 ` Yury Norov
2026-07-09 21:56 ` [PATCH v7 03/12] sysfs: Add preferred CPU file Shrikanth Hegde
2026-07-10 15:41 ` Yury Norov
2026-07-10 17:00 ` Shrikanth Hegde
2026-07-10 23:09 ` Yury Norov
2026-07-13 12:00 ` Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 04/12] sched/core: Try to use a preferred CPU in is_cpu_allowed Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 05/12] sched/fair: Load balance only among preferred CPUs Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 06/12] sched/core: Push current task from non preferred CPU Shrikanth Hegde
2026-07-10 23:02 ` Yury Norov
2026-07-13 12:35 ` Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 07/12] sched/debug: Add migration stats due to non preferred CPUs Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 08/12] virt: Introduce steal monitor driver Shrikanth Hegde
2026-07-10 1:27 ` Randy Dunlap
2026-07-10 4:28 ` Shrikanth Hegde
2026-07-10 20:53 ` Yury Norov
2026-07-13 12:06 ` Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 09/12] virt/steal_monitor: Add control knobs for handling steal values Shrikanth Hegde
2026-07-10 4:27 ` Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 10/12] virt/steal_monitor: Provide functions for managing " Shrikanth Hegde
2026-07-10 4:30 ` Shrikanth Hegde
2026-07-10 20:00 ` Yury Norov
2026-07-13 5:13 ` Shrikanth Hegde
2026-07-14 12:47 ` Yury Norov
2026-07-14 13:15 ` Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 11/12] virt/steal_monitor: Act on steal time periodically and decide on preferred CPUs Shrikanth Hegde
2026-07-10 20:37 ` Yury Norov [this message]
2026-07-13 5:48 ` Shrikanth Hegde
2026-07-14 12:31 ` Yury Norov
2026-07-14 13:08 ` Shrikanth Hegde
2026-07-09 21:56 ` [PATCH v7 12/12] sched, virt/steal_monitor: Keep tick on for faster push on nohz_full CPU Shrikanth Hegde
2026-07-10 6:35 ` Shrikanth Hegde
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=alFX75dzgkMnDXAD@yury \
--to=ynorov@nvidia.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=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=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=vschneid@redhat.com \
--cc=yury.norov@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.