From nobody Sun Apr 12 21:01:33 2026 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B13203BD653 for ; Wed, 1 Apr 2026 21:47:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775080039; cv=none; b=p+zYdiUO6qa/IM63x5uHPsfM/q+anTe0azUD8EoCvdwUus7TynOALPAiMePI/w3mdXSkTc2VXMMkupeDKvWsrqAUIXDHTSFFD9emGPSqKv8WeqnkB+Y4M1KgxpBn8oJhClGxo/rS1TVVwrWsarsNmKpV4ce3AnIVbcNEPHU1OGA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775080039; c=relaxed/simple; bh=Lu/D7waWELyAoc4TIYJ5sqOWbENuO2Cjh6yRq6xGAq4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=YC65x3QJquFtVKgTUIEm5DP0zoB9sQNsICSvKX16DRJOflelOsVxibPA7cT43JQNqZg7EUlznbrlVNQtXJ79sE83jAmQM70ewzk+9iMxWn32E1zIMqj/yuIDuF2/UeIRacNikNOIiKqn/7BrURiMftkY9wxXjyfFoqOqmgrfQV8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=HAS4juu7; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="HAS4juu7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1775080038; x=1806616038; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Lu/D7waWELyAoc4TIYJ5sqOWbENuO2Cjh6yRq6xGAq4=; b=HAS4juu7pK1aflO/SHryl1xT8cGEgt6JIj9EIRzwzqj1YuLklg7Effn4 97w1RcKd+SGiCxAi2ODyfXFLIDB99JbmEkDDX1IdKNOoBe+cjpF1c2uKM DfKSgLszGbSy2G1RDXrPzP7+/55Z9eCtaFhv89z1ZLx5KBefTZszfUBNb 4aWENQaChMI+kiCRlI86Sc4zSkcHserETIi+L0o7bopHhvi313zpedb8U jk0n8l/z55oQGTOuvMTP4AO0lNt1ZWfi5+JVbiBuVSYnP6MtASoyy7vx0 G9sjv3+LqLnn5n4y8dPIAaKbFGR6YkVUVumEbpGVsfKOm0eqN4I+6jBY2 g==; X-CSE-ConnectionGUID: ieVPNJmcStGbVnpd7SlnJg== X-CSE-MsgGUID: vCgMfZSySUuK+/UgHzDB4w== X-IronPort-AV: E=McAfee;i="6800,10657,11746"; a="79740122" X-IronPort-AV: E=Sophos;i="6.23,153,1770624000"; d="scan'208";a="79740122" Received: from fmviesa002.fm.intel.com ([10.60.135.142]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Apr 2026 14:47:17 -0700 X-CSE-ConnectionGUID: PGgiRmAhTlCktY2iuiD+yA== X-CSE-MsgGUID: ncch/t9WQye8D8paSZJuBg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,153,1770624000"; d="scan'208";a="249842500" Received: from b04f130c83f2.jf.intel.com ([10.165.154.98]) by fmviesa002.fm.intel.com with ESMTP; 01 Apr 2026 14:47:16 -0700 From: Tim Chen To: Peter Zijlstra , Ingo Molnar , K Prateek Nayak , "Gautham R . Shenoy" , Vincent Guittot Cc: Chen Yu , Juri Lelli , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , Madadi Vineeth Reddy , Hillf Danton , Shrikanth Hegde , Jianyong Wu , Yangyu Chen , Tingyin Duan , Vern Hao , Vern Hao , Len Brown , Tim Chen , Aubrey Li , Zhao Liu , Chen Yu , Adam Li , Aaron Lu , Tim Chen , Josh Don , Gavin Guo , Qais Yousef , Libo Chen , linux-kernel@vger.kernel.org Subject: [Patch v4 20/22] sched/cache: Add user control to adjust the aggressiveness of cache-aware scheduling Date: Wed, 1 Apr 2026 14:52:32 -0700 Message-Id: <38b46d29cf56285992f4604b450abbf91ecf3313.1775065312.git.tim.c.chen@linux.intel.com> X-Mailer: git-send-email 2.32.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Chen Yu Introduce a set of debugfs knobs to control how aggressive the cache aware scheduling do the task aggregation. (1) aggr_tolerance With sched_cache enabled, the scheduler uses a process's RSS as a proxy for its LLC footprint to determine if aggregating tasks on the preferred LLC could cause cache contention. If RSS exceeds the LLC size, aggregation is skipped. Some workloads with large RSS but small actual memory footprints may still benefit from aggregation. Since the kernel cannot efficiently track per-task cache usage (resctrl is user-space only), userspace can provide a more accurate hint. Introduce /sys/kernel/debug/sched/llc_balancing/aggr_tolerance to let users control how strictly RSS limits aggregation. Values range from 0 to 100: - 0: Cache-aware scheduling is disabled. - 1: Strict; tasks with RSS larger than LLC size are skipped. - >=3D100: Aggressive; tasks are aggregated regardless of RSS. For example, with a 32MB L3 cache: - aggr_tolerance=3D1 -> tasks with RSS > 32MB are skipped. - aggr_tolerance=3D99 -> tasks with RSS > 784GB are skipped (784GB =3D (1 + (99 - 1) * 256) * 32MB). Similarly, /sys/kernel/debug/sched/llc_balancing/aggr_tolerance also controls how strictly the number of active threads is considered when doing cache aware load balance. The number of SMTs is also considered. High SMT counts reduce the aggregation capacity, preventing excessive task aggregation on SMT-heavy systems like Power10/Power11. Yangyu suggested introducing separate aggregation controls for the number of active threads and memory RSS checks. Since there are plans to add per-process/task group controls, fine-grained tunables are deferred to that implementation. (2) epoch_period, epoch_affinity_timeout, imb_pct, overaggr_pct are also turned into tunable. Suggested-by: K Prateek Nayak Suggested-by: Madadi Vineeth Reddy Suggested-by: Shrikanth Hegde Suggested-by: Tingyin Duan Suggested-by: Jianyong Wu Suggested-by: Yangyu Chen Signed-off-by: Chen Yu Co-developed-by: Tim Chen Signed-off-by: Tim Chen --- Notes: v3->v4: Create the debugfs knobs under debug/sched/llc_balancing directory. (Peter Zijlstra) kernel/sched/debug.c | 10 ++++++++ kernel/sched/fair.c | 60 ++++++++++++++++++++++++++++++++++++++------ kernel/sched/sched.h | 5 ++++ 3 files changed, 68 insertions(+), 7 deletions(-) diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c index 3019412d8009..4469e1c152c8 100644 --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -669,6 +669,16 @@ static __init int sched_init_debug(void) llc =3D debugfs_create_dir("llc_balancing", debugfs_sched); debugfs_create_file("enabled", 0644, llc, NULL, &sched_cache_enable_fops); + debugfs_create_u32("aggr_tolerance", 0644, llc, + &llc_aggr_tolerance); + debugfs_create_u32("epoch_period", 0644, llc, + &llc_epoch_period); + debugfs_create_u32("epoch_affinity_timeout", 0644, llc, + &llc_epoch_affinity_timeout); + debugfs_create_u32("overaggr_pct", 0644, llc, + &llc_overaggr_pct); + debugfs_create_u32("imb_pct", 0644, llc, + &llc_imb_pct); #endif =20 debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops= ); diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index a2d1b8b2a188..e4e22696a0b1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1282,6 +1282,11 @@ static void set_next_buddy(struct sched_entity *se); */ #define EPOCH_PERIOD (HZ / 100) /* 10 ms */ #define EPOCH_LLC_AFFINITY_TIMEOUT 5 /* 50 ms */ +__read_mostly unsigned int llc_aggr_tolerance =3D 1; +__read_mostly unsigned int llc_epoch_period =3D EPOCH_PERIOD; +__read_mostly unsigned int llc_epoch_affinity_timeout =3D EPOCH_LLC_AFFINI= TY_TIMEOUT; +__read_mostly unsigned int llc_imb_pct =3D 20; +__read_mostly unsigned int llc_overaggr_pct =3D 50; =20 static int llc_id(int cpu) { @@ -1316,10 +1321,22 @@ static inline bool valid_llc_buf(struct sched_domai= n *sd, return true; } =20 +static inline int get_sched_cache_scale(int mul) +{ + if (!llc_aggr_tolerance) + return 0; + + if (llc_aggr_tolerance >=3D 100) + return INT_MAX; + + return (1 + (llc_aggr_tolerance - 1) * mul); +} + static bool exceed_llc_capacity(struct mm_struct *mm, int cpu) { struct cacheinfo *ci; u64 rss, llc; + int scale; =20 /* * get_cpu_cacheinfo_level() can not be used @@ -1344,13 +1361,42 @@ static bool exceed_llc_capacity(struct mm_struct *m= m, int cpu) rss =3D get_mm_counter(mm, MM_ANONPAGES) + get_mm_counter(mm, MM_SHMEMPAGES); =20 - return (llc < (rss * PAGE_SIZE)); + /* + * Scale the LLC size by 256*llc_aggr_tolerance + * and compare it to the task's RSS size. + * + * Suppose the L3 size is 32MB. If the + * llc_aggr_tolerance is 1: + * When the RSS is larger than 32MB, the process + * is regarded as exceeding the LLC capacity. If + * the llc_aggr_tolerance is 99: + * When the RSS is larger than 784GB, the process + * is regarded as exceeding the LLC capacity: + * 784GB =3D (1 + (99 - 1) * 256) * 32MB + * If the llc_aggr_tolerance is 100: + * ignore the RSS. + */ + scale =3D get_sched_cache_scale(256); + if (scale =3D=3D INT_MAX) + return false; + + return ((llc * (u64)scale) < (rss * PAGE_SIZE)); } =20 static bool exceed_llc_nr(struct mm_struct *mm, int cpu) { + int scale; + + /* + * Scale the number of 'cores' in a LLC by llc_aggr_tolerance + * and compare it to the task's active threads. + */ + scale =3D get_sched_cache_scale(1); + if (scale =3D=3D INT_MAX) + return false; + return !fits_capacity((mm->sc_stat.nr_running_avg * cpu_smt_num_threads), - per_cpu(sd_llc_size, cpu)); + (scale * per_cpu(sd_llc_size, cpu))); } =20 static void account_llc_enqueue(struct rq *rq, struct task_struct *p) @@ -1448,9 +1494,9 @@ static inline void __update_mm_sched(struct rq *rq, long delta =3D now - rq->cpu_epoch_next; =20 if (delta > 0) { - n =3D (delta + EPOCH_PERIOD - 1) / EPOCH_PERIOD; + n =3D (delta + llc_epoch_period - 1) / max(llc_epoch_period, 1U); rq->cpu_epoch +=3D n; - rq->cpu_epoch_next +=3D n * EPOCH_PERIOD; + rq->cpu_epoch_next +=3D n * llc_epoch_period; __shr_u64(&rq->cpu_runtime, n); } =20 @@ -1543,7 +1589,7 @@ void account_mm_sched(struct rq *rq, struct task_stru= ct *p, s64 delta_exec) * has only 1 thread, invalidate its preferred state. */ if (time_after(epoch, - READ_ONCE(mm->sc_stat.epoch) + EPOCH_LLC_AFFINITY_TIMEOUT) || + READ_ONCE(mm->sc_stat.epoch) + llc_epoch_affinity_timeout) || get_nr_threads(p) <=3D 1 || exceed_llc_nr(mm, cpu_of(rq)) || exceed_llc_capacity(mm, cpu_of(rq))) { @@ -10018,7 +10064,7 @@ static inline int task_is_ineligible_on_dst_cpu(str= uct task_struct *p, int dest_ */ static bool fits_llc_capacity(unsigned long util, unsigned long max) { - u32 aggr_pct =3D 50; + u32 aggr_pct =3D llc_overaggr_pct; =20 /* * For single core systems, raise the aggregation @@ -10038,7 +10084,7 @@ static bool fits_llc_capacity(unsigned long util, u= nsigned long max) */ /* Allows dst util to be bigger than src util by up to bias percent */ #define util_greater(util1, util2) \ - ((util1) * 100 > (util2) * 120) + ((util1) * 100 > (util2) * (100 + llc_imb_pct)) =20 static __maybe_unused bool get_llc_stats(int cpu, unsigned long *util, unsigned long *cap) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 5561bdcc8bf5..b757812725f7 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -4038,6 +4038,11 @@ static inline void mm_cid_switch_to(struct task_stru= ct *prev, struct task_struct DECLARE_STATIC_KEY_FALSE(sched_cache_present); DECLARE_STATIC_KEY_FALSE(sched_cache_active); extern int sysctl_sched_cache_user; +extern unsigned int llc_aggr_tolerance; +extern unsigned int llc_epoch_period; +extern unsigned int llc_epoch_affinity_timeout; +extern unsigned int llc_imb_pct; +extern unsigned int llc_overaggr_pct; =20 static inline bool sched_cache_enabled(void) { --=20 2.32.0