Linux Documentation
 help / color / mirror / Atom feed
From: Shrikanth Hegde <sshegde@linux.ibm.com>
To: Yury Norov <ynorov@nvidia.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, jgross@suse.com,
	virtualization@lists.linux.dev
Subject: Re: [PATCH v9 10/11] virt/steal_governor: Implement steal_governor policy loop
Date: Sat, 25 Jul 2026 09:24:51 +0530	[thread overview]
Message-ID: <493495db-01a4-43bc-9261-0456436be933@linux.ibm.com> (raw)
In-Reply-To: <amPTg78qsOw4WpqB@yury>

Hi Yury,

On 7/25/26 2:35 AM, Yury Norov wrote:
> On Fri, Jul 24, 2026 at 07:37:31PM +0530, Shrikanth Hegde wrote:

[...]
    
>> +/* Return collective steal time across system. */
>> +static u64 get_system_steal_time(void)
>> +{
>> +	int cpu;
>> +	u64 total_steal = 0;
>> +
>> +	for_each_possible_cpu(cpu)
>> +		total_steal += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
>> +
>> +	return total_steal;
>> +}
> 
> In v8 I pointed to the identical function in s390 code, and you agreed
> to unify them, but that didn't happen. Please do that in the next
> version.

I thought I will do this refactoring after the series gets merged upstream.
If you insist, I will do this in next version.

> 
>> +/* Return number of CPUs to consider steal ratio. */
>> +static unsigned int get_system_cpus(void)
>> +{
>> +	return num_possible_cpus();
>> +}
>> +
>> +/*
>> + *
> 
> Useless line

My bad. Will remove.

> 
>> + * Called when the steal governor detects high physical CPU contention.
>> + * It finds the last active core in the preferred mask and mark those
>> + * CPUs as non-preferred.
>> + *
>> + * Must ensure:
>> + * - at least one core is always kept as preferred
>> + * - preferred is always subset of active.
>> + */
>> +static void decrease_preferred_cpus(void)
>> +{
>> +	const struct cpumask *first_hk_core;
>> +	int target_cpu = nr_cpu_ids;
>> +	int cpu;
>> +
>> +	guard(cpus_read_lock)();
>> +	cpu = cpumask_first_and(housekeeping_cpumask(HK_TYPE_KERNEL_NOISE),
>> +				cpu_preferred_mask);
>> +	if (cpu >= nr_cpu_ids)
>> +		return;
>> +
>> +	/* Always leave first housekeeping core as preferred. */
>> +	first_hk_core = topology_sibling_cpumask(cpu);
>> +	cpu = cpumask_last(cpu_preferred_mask);
>> +	if (cpu >= nr_cpu_ids)
>> +		return;
>> +
>> +	/* Find the last CPU which doesn't belong to that first hk_core. */
>> +	if (!cpumask_test_cpu(cpu, first_hk_core)) {
>> +		target_cpu = cpu;
>> +	} else {
>> +		for_each_cpu_andnot(cpu, cpu_preferred_mask, first_hk_core)
>> +			target_cpu = cpu;
>> +	}
>> +
>> +	/* Only the first housekeeping core remains */
>> +	if (target_cpu >= nr_cpu_ids)
>> +		return;
>> +
>> +	for_each_cpu_and(cpu, topology_sibling_cpumask(target_cpu),
>> +			 cpu_preferred_mask)
>> +		set_cpu_preferred(cpu, false);
>> +}
>> +
>> +/*
>> + * Called when the steal governor detects no/low physical CPU contention.
>> + * It finds the first active core outside of preferred mask and mark
>> + * those CPUs as preferred.
>> + *
>> + * Must ensure preferred is subset of active.
>> + */
>> +static void increase_preferred_cpus(void)
>> +{
>> +	int first_cpu, cpu;
>> +
>> +	guard(cpus_read_lock)();
>> +	first_cpu = cpumask_first_andnot(cpu_active_mask, cpu_preferred_mask);
>> +
>> +	/* All CPUs are preferred. Nothing to increase further */
>> +	if (first_cpu >= nr_cpu_ids)
>> +		return;
>> +
>> +	for_each_cpu_and(cpu, topology_sibling_cpumask(first_cpu),
>> +			 cpu_active_mask)
>> +		set_cpu_preferred(cpu, true);
>> +}
>> +
>> +static bool preferred_cpus_valid(void)
>> +{
>> +	if (cpumask_empty(cpu_preferred_mask)) {
>> +		pr_err("empty preferred mask. stopping\n");
>> +		return false;
>> +	}
>> +
>> +	if (!cpumask_subset(cpu_preferred_mask, cpu_active_mask)) {
>> +		pr_err("preferred: %*pbl is not subset of active: %*pbl, stopping\n",
>> +		       cpumask_pr_args(cpu_preferred_mask),
>> +		       cpumask_pr_args(cpu_active_mask));
>> +		return false;
>> +	}
>> +
>> +	return true;
>> +}
>> +
>> +static void compute_preferred_cpus_work(struct work_struct *work)
> 
> Bad name. You're not only computing here, but actually adjusting the
> preferred CPUs mask.
> 

adjust_preferred_cpus_work or steal_governor_loop ?

>> +{
>> +	u64 curr_steal, delta_steal, delta_ns, steal_ratio;
>> +	ktime_t now;
>> +
>> +	now = ktime_get();
>> +	delta_ns = ktime_to_ns(ktime_sub(now, sg_ctx.time));
>> +
>> +	if (unlikely(delta_ns < NSEC_PER_MSEC)) {
>> +		pr_err_ratelimited("work scheduled too soon delta_ns: %llu\n", delta_ns);
>> +		goto requeue_work;
>> +	}
>> +
>> +	curr_steal = get_system_steal_time();
>> +	delta_steal = curr_steal > sg_ctx.steal ? curr_steal - sg_ctx.steal : 0;
>> +	sg_ctx.steal = curr_steal;
>> +	sg_ctx.time = now;
>> +
>> +	/*
>> +	 * steal_ratio = (delta_steal * 100*100)/(delta_ns * num_cpus())
>> +	 * To avoid possible overflow, divide the denominator early.
>> +	 * Note minimum interval is 100ms.
>> +	 */
>> +	delta_ns = max_t(u64, div_u64(delta_ns * get_system_cpus(), 10000), 1);
>> +	steal_ratio = div64_u64(delta_steal, delta_ns);
> 
> So if:
> 
> Possible CPUs = 128
> Active CPUs = 8
> Steal on online CPUs = 50%
> Steal on offline CPUS = 0%
> 
> Then calculated ratio would be:
> 
>          (50% × 8 + 0% * 120) / 128 = 3.125%
> 
> Instead of decreasing the number of preferred CPUs, you'll do nothing
> under default thresholds, or even increase.
> 
> Have you tested your driver against such a configuration?

I thought about it, but given range of systems linux supports today, there
will always be configurations where defaults are not good enough.

That is why it is recommended to build it as module. load the driver
will custom high and low threshold.


I had it as active CPUs only earlier. but the concern is, what happens at hotplug.
Since online a new CPUs steal time can add big value, it can trigger high threshold
check, similarly for offline. Plus raciness w.r.t to active CPUs.
(same issue for online CPUs)

Hence I chose it as possible CPUs.

> 
> Also, I'm not quite sure how you'd handle a case when you have half
> of CPUS in your core offlined, but you manage preferred mask per-core,
> so you offline or online less CPUs than expected. Can you mention that
> scenario in the documentation?
> 

If it is with thresholds, it is same case as above. Other than that, i have
tested it doesn;t set for offline CPUs etc.

I am not sure if scaling the thresholds with active CPUs is a good idea or not.
It can easily cause more math headache for users.

>> +
>> +	if (steal_ratio > sg_ctx.high_threshold)
>> +		decrease_preferred_cpus();
>> +	else if (steal_ratio <= sg_ctx.low_threshold)
>> +		increase_preferred_cpus();
>> +	else
>> +		goto requeue_work;
>> +
>> +	if (!preferred_cpus_valid()) {
>> +		restore_preferred_to_active();
>> +		return;
>> +	}
>> +
>> +requeue_work:
>> +	schedule_delayed_work(&sg_ctx.work, sg_ctx.delay);
>> +}
>> +
>>   static int __init steal_governor_init(void)
>>   {
>>   	if (sg_ctx.low_threshold >= sg_ctx.high_threshold) {
>> @@ -117,6 +267,10 @@ static int __init steal_governor_init(void)
>>   	}
>>   
>>   	sg_ctx.delay = msecs_to_jiffies(sg_ctx.interval_ms);
>> +	INIT_DELAYED_WORK(&sg_ctx.work, compute_preferred_cpus_work);
>> +	sg_ctx.steal = get_system_steal_time();
>> +	sg_ctx.time = ktime_get();
>> +	schedule_delayed_work(&sg_ctx.work, sg_ctx.delay);
>>   	pr_info("enabled. interval: %ums, high_threshold: %u, low_threshold: %u\n",
>>   		sg_ctx.interval_ms, sg_ctx.high_threshold, sg_ctx.low_threshold);
>>   
>> @@ -125,6 +279,7 @@ static int __init steal_governor_init(void)
>>   
>>   static void __exit steal_governor_exit(void)
>>   {
>> +	disable_delayed_work_sync(&sg_ctx.work);
>>   	restore_preferred_to_active();
>>   	pr_info("disabled\n");
>>   }
>> -- 
>> 2.47.3


  reply	other threads:[~2026-07-25  3:55 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-24 14:07 [PATCH v9 00/11] sched, steal_governor: Introduce preferred CPUs and steal-driven vCPU backoff Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 01/11] sched/docs: Document cpu_preferred_mask and Preferred CPU concept Shrikanth Hegde
2026-07-24 21:45   ` Yury Norov
2026-07-25  2:22     ` Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 02/11] cpumask: Introduce cpu_preferred_mask Shrikanth Hegde
2026-07-24 20:00   ` Yury Norov
2026-07-25  3:16     ` Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 03/11] sysfs: Add preferred CPU file Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 04/11] sched/core: Try to use a preferred CPU in is_cpu_allowed Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 05/11] sched/fair: Load balance only among preferred CPUs Shrikanth Hegde
2026-07-24 21:40   ` Yury Norov
2026-07-24 14:07 ` [PATCH v9 06/11] sched/core: Push current task from non preferred CPU Shrikanth Hegde
2026-07-24 22:04   ` Yury Norov
2026-07-24 14:07 ` [PATCH v9 07/11] sched/debug: Add migration stats due to non preferred CPUs Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 08/11] virt: Introduce steal governor driver Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 09/11] virt/steal_governor: Add control knobs for handling steal values Shrikanth Hegde
2026-07-24 14:07 ` [PATCH v9 10/11] virt/steal_governor: Implement steal_governor policy loop Shrikanth Hegde
2026-07-24 21:05   ` Yury Norov
2026-07-25  3:54     ` Shrikanth Hegde [this message]
2026-07-24 14:07 ` [PATCH v9 11/11] virt/steal_governor: Enable the driver Shrikanth Hegde
2026-07-24 22:07 ` [PATCH v9 00/11] sched, steal_governor: Introduce preferred CPUs and steal-driven vCPU backoff Yury Norov
2026-07-25  1:53   ` 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=493495db-01a4-43bc-9261-0456436be933@linux.ibm.com \
    --to=sshegde@linux.ibm.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=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=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 \
    --cc=ynorov@nvidia.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox