Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Jul 2026 02:26:53 +0000
From:      Olivier Certner <olce@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: e8dec0038bd9 - main - sched_4bsd: Fix conflating priority of differently-niced CPU-bound threads
Message-ID:  <6a5ed8ed.21c87.393dab61@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=e8dec0038bd95f6d940afa19b4d101f466280fd6

commit e8dec0038bd95f6d940afa19b4d101f466280fd6
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2026-06-13 13:09:42 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2026-07-21 02:24:10 +0000

    sched_4bsd: Fix conflating priority of differently-niced CPU-bound threads
    
    We introduced (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) as part of
    ESTCPULIM() in commit eebc148f25c3 ("sched_4bsd: ESTCPULIM(): Allow any
    value in the timeshare range") in order to use more than a fixed number
    (40) of all the available priority levels in the timeshare range (136
    before the 256-queue runqueue work, 224 now) to take into account the
    number of ticks a thread has run ('ts_estcpu').
    
    In the computation of a new thread's priority (resetpriority()), in
    addition to the "ticks running" contribution, the final priority also
    includes a "nice" value contribution.  The final value is clamped into
    the [PRI_MIN_TIMESHARE; PRI_MAX_TRIMESHARE] range.
    
    Problem is that the new "ticks running" contribution now can lead to
    a computed priority value that exceeds PRI_MAX_TRIMESHARE, and is thus
    finally clamped to PRI_MAX_TIMESHARE, which becomes an alias for all
    out-of-bound values.  In particular, this can conflate CPU-hungry
    threads.  With at least two of them competing on the same CPU, with an
    increase of 'ts_estcpu' of ~64 per second (stathz being 127) and the
    minimal decay of 4/5 (load average 2 or more), both threads will easily
    reach the current clamping of 224 (+ PRI_MIN_TIMESHARE), and be
    considered indifferently by the scheduler.
    
    Fix this problem by ensuring that the maximum contribution of
    'ts_estcpu' (via ESTCPULIM()) cannot exceed the timeshare range of
    priorities when the nice contribution is added to it, so the nice
    contribution continues to have an effect on CPU-bound threads.
    
    Introduction of the nice term in ESTCPULIM() (then NICE_WEIGHT *
    PRIO_MAX) has been done in commit bdf423572ee3 ("Scheduler fixes
    equivalent to the ones logged in the following NetBSD commit...") and
    does not appear to have made any real sense even then.
    
    Fixes:          bdf423572ee3 ("Scheduler fixes equivalent to the ones logged in the following NetBSD commit...")
    Fixes:          eebc148f25c3 ("sched_4bsd: ESTCPULIM(): Allow any value in the timeshare range")
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D57826
---
 sys/kern/sched_4bsd.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c
index 53e32026029d..f86dcda218a4 100644
--- a/sys/kern/sched_4bsd.c
+++ b/sys/kern/sched_4bsd.c
@@ -78,8 +78,8 @@
 #define	NICE_WEIGHT		1	/* Priorities per nice level. */
 #define	ESTCPULIM(e)							\
 	min((e), INVERSE_ESTCPU_WEIGHT *				\
-	    (NICE_WEIGHT * (PRIO_MAX - PRIO_MIN) +			\
-	    PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)			\
+	    (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE -			\
+	    (PRIO_MAX - PRIO_MIN) * NICE_WEIGHT)			\
 	    + INVERSE_ESTCPU_WEIGHT - 1)
 
 #define	TS_NAME_LEN (MAXCOMLEN + sizeof(" td ") + sizeof(__XSTRING(UINT_MAX)))
@@ -596,11 +596,13 @@ resetpriority(struct thread *td)
 
 	if (td->td_pri_class != PRI_TIMESHARE)
 		return;
-	newpriority = PUSER +
+	newpriority = PRI_MIN_TIMESHARE +
 	    td_get_sched(td)->ts_estcpu / INVERSE_ESTCPU_WEIGHT +
 	    NICE_WEIGHT * (td->td_proc->p_nice - PRIO_MIN);
-	newpriority = min(max(newpriority, PRI_MIN_TIMESHARE),
-	    PRI_MAX_TIMESHARE);
+	KASSERT(PRI_MIN_TIMESHARE <= newpriority &&
+	    newpriority <= PRI_MAX_TIMESHARE,
+	    ("Out-of-bounds priority, probably 'ts_estcpu' not clamped "
+	    "correctly, see ESTCPULIM()"));
 	sched_user_prio(td, newpriority);
 }
 


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a5ed8ed.21c87.393dab61>