From nobody Fri Jun 19 08:34:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 109FBC433FE for ; Wed, 6 Apr 2022 13:54:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233868AbiDFN4y (ORCPT ); Wed, 6 Apr 2022 09:56:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35842 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233952AbiDFN40 (ORCPT ); Wed, 6 Apr 2022 09:56:26 -0400 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DEDB8329258; Tue, 5 Apr 2022 19:53:37 -0700 (PDT) Received: from kwepemi500012.china.huawei.com (unknown [172.30.72.55]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4KY89Y0XwBzBry1; Wed, 6 Apr 2022 10:49:21 +0800 (CST) Received: from huawei.com (10.67.174.53) by kwepemi500012.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 6 Apr 2022 10:53:30 +0800 From: Liao Chang To: , , , , , , , , , , , , , , , , , , , , , , , CC: , , , , Subject: [RFC 1/3] softirq: Add two parameters to control CPU bandwidth for use by softirq Date: Wed, 6 Apr 2022 10:52:39 +0800 Message-ID: <20220406025241.191300-2-liaochang1@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220406025241.191300-1-liaochang1@huawei.com> References: <20220406025241.191300-1-liaochang1@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.53] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To kwepemi500012.china.huawei.com (7.221.188.12) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Although kernel merely allow __do_softirq() run for 2ms at most, it does not control the total running time of softirqs on given CPU. In order to prevent softirqs from using up all CPU bandwidth and cause other task starved, Sofitrq Throttling mechanism introduces two parameters in the /proc file system: /proc/sys/kernel/sofitrq_period_ms Defines the period in ms(millisecond) to be considered as 100% of CPU bandwidth, the default value is 1,000 ms(1second). Changes to the value of the period must be very well thought out, as too long or too short are beyond one's expectation. /proc/sys/kernel/softirq_runtime_ms Define the bandwidth available to softirqs on each CPU, the default values is 950 ms(0.95 second) or, in other words, 95% of the CPU bandwidth. Setting this value to -1 means that softirqs might use up to 100% CPU cycles. Signed-off-by: Liao Chang --- include/linux/interrupt.h | 7 ++++ init/Kconfig | 10 ++++++ kernel/softirq.c | 74 +++++++++++++++++++++++++++++++++++++++ kernel/sysctl.c | 16 +++++++++ 4 files changed, 107 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 9367f1cb2e3c..de6973bf72e5 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -605,6 +605,13 @@ extern void __raise_softirq_irqoff(unsigned int nr); extern void raise_softirq_irqoff(unsigned int nr); extern void raise_softirq(unsigned int nr); =20 +#ifdef CONFIG_SOFTIRQ_THROTTLE +extern unsigned int sysctl_softirq_period_ms; +extern int sysctl_softirq_runtime_ms; +int softirq_throttle_handler(struct ctl_table *table, int write, void *buf= fer, + size_t *lenp, loff_t *ppos); +#endif + DECLARE_PER_CPU(struct task_struct *, ksoftirqd); =20 static inline struct task_struct *this_cpu_ksoftirqd(void) diff --git a/init/Kconfig b/init/Kconfig index e9119bf54b1f..a63ebc88a199 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2393,3 +2393,13 @@ config ARCH_HAS_SYNC_CORE_BEFORE_USERMODE # . config ARCH_HAS_SYSCALL_WRAPPER def_bool n + +config SOFTIRQ_THROTTLE + bool "Softirq Throttling Feature" + help + Allow to allocate bandwidth for use by softirq handling. This + saftguard machanism is known as softirq throttling and is controlled + by two parameters in the /proc/ file system: + + /proc/sysctl/kernel/softirq_period_ms + /proc/sysctl/kernel/softirq_runtime_ms diff --git a/kernel/softirq.c b/kernel/softirq.c index 41f470929e99..8aac9e2631fd 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -65,6 +65,76 @@ const char * const softirq_to_name[NR_SOFTIRQS] =3D { "TASKLET", "SCHED", "HRTIMER", "RCU" }; =20 +#ifdef CONFIG_SOFTIRQ_THROTTLE +unsigned int sysctl_softirq_period_ms =3D 1000; +int sysctl_softirq_runtime_ms =3D 950; + +struct softirq_throttle { + unsigned int period; + unsigned int runtime; + raw_spinlock_t lock; +} si_throttle; + +static int softirq_throttle_validate(void) +{ + if (((int)sysctl_softirq_period_ms <=3D 0) || + ((sysctl_softirq_runtime_ms !=3D -1) && + ((unsigned int)sysctl_softirq_runtime_ms > sysctl_softirq_period_ms))) + return -EINVAL; + + return 0; +} + +static void softirq_throttle_update(void) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&si_throttle.lock, flags); + si_throttle.period =3D sysctl_softirq_period_ms; + si_throttle.runtime =3D sysctl_softirq_runtime_ms; + raw_spin_unlock_irqrestore(&si_throttle.lock, flags); +} + +int softirq_throttle_handler(struct ctl_table *table, int write, void *buf= fer, + size_t *lenp, loff_t *ppos) +{ + unsigned int old_period, old_runtime; + static DEFINE_MUTEX(mutex); + int ret; + + mutex_lock(&mutex); + old_period =3D sysctl_softirq_period_ms; + old_runtime =3D sysctl_softirq_runtime_ms; + + ret =3D proc_dointvec(table, write, buffer, lenp, ppos); + if (ret) + goto undo; + if (!write) + goto done; + + ret =3D softirq_throttle_validate(); + if (ret) + goto undo; + + softirq_throttle_update(); + goto done; + +undo: + sysctl_softirq_period_ms =3D old_period; + sysctl_softirq_runtime_ms =3D old_runtime; +done: + mutex_unlock(&mutex); + return ret; +} + +static void softirq_throttle_init(void) +{ + si_throttle.period =3D sysctl_softirq_period_ms; + si_throttle.runtime =3D sysctl_softirq_runtime_ms; + raw_spin_lock_init(&si_throttle.lock); +} +#endif + /* * we cannot loop indefinitely here to avoid userspace starvation, * but we also don't want to introduce a worst case 1/HZ latency @@ -894,6 +964,10 @@ void __init softirq_init(void) { int cpu; =20 +#ifdef CONFIG_SOFTIRQ_THROTTLE + softirq_throttle_init(); +#endif + for_each_possible_cpu(cpu) { per_cpu(tasklet_vec, cpu).tail =3D &per_cpu(tasklet_vec, cpu).head; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5ae443b2882e..e5a9ad391cca 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1771,6 +1771,22 @@ static struct ctl_table kern_table[] =3D { .extra1 =3D SYSCTL_ONE, }, #endif +#ifdef CONFIG_SOFTIRQ_THROTTLE + { + .procname =3D "softirq_period_ms", + .data =3D &sysctl_softirq_period_ms, + .maxlen =3D sizeof(unsigned int), + .mode =3D 0644, + .proc_handler =3D softirq_throttle_handler, + }, + { + .procname =3D "softirq_runtime_ms", + .data =3D &sysctl_softirq_runtime_ms, + .maxlen =3D sizeof(int), + .mode =3D 0644, + .proc_handler =3D softirq_throttle_handler, + }, +#endif #if defined(CONFIG_ENERGY_MODEL) && defined(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) { .procname =3D "sched_energy_aware", --=20 2.17.1 From nobody Fri Jun 19 08:34:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ECAF3C433EF for ; Wed, 6 Apr 2022 14:33:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234847AbiDFOfv (ORCPT ); Wed, 6 Apr 2022 10:35:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235206AbiDFOfY (ORCPT ); Wed, 6 Apr 2022 10:35:24 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F0D38329261; Tue, 5 Apr 2022 19:53:37 -0700 (PDT) Received: from kwepemi500012.china.huawei.com (unknown [172.30.72.55]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4KY8DN2BWCzgYF8; Wed, 6 Apr 2022 10:51:48 +0800 (CST) Received: from huawei.com (10.67.174.53) by kwepemi500012.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 6 Apr 2022 10:53:31 +0800 From: Liao Chang To: , , , , , , , , , , , , , , , , , , , , , , , CC: , , , , Subject: [RFC 2/3] softirq: Do throttling when softirqs use up its bandwidth Date: Wed, 6 Apr 2022 10:52:40 +0800 Message-ID: <20220406025241.191300-3-liaochang1@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220406025241.191300-1-liaochang1@huawei.com> References: <20220406025241.191300-1-liaochang1@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.53] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To kwepemi500012.china.huawei.com (7.221.188.12) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When kernel is about to handle pending softirqs, it will check firstly whether softirq already use up its CPU bandwidth, Once the total duration of softirq handling exceed the max value in the user-specified time window, softirq will be throttled for a while, the throttling will be removed when time window expires. On then other hand, kernel will update the runtime of softirq on given CPU before __do_softirq() function returns. Signed-off-by: Liao Chang --- kernel/softirq.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/kernel/softirq.c b/kernel/softirq.c index 8aac9e2631fd..6de6db794ac5 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -75,6 +75,49 @@ struct softirq_throttle { raw_spinlock_t lock; } si_throttle; =20 +struct softirq_runtime { + bool throttled; + unsigned long duration; + unsigned long expires; + raw_spinlock_t lock; +}; +static DEFINE_PER_CPU(struct softirq_runtime, softirq_runtime); + +static void forward_softirq_expires(struct softirq_runtime *si_runtime) +{ + si_runtime->throttled =3D false; + si_runtime->duration =3D 0UL; + si_runtime->expires =3D jiffies + + msecs_to_jiffies(si_throttle.period - si_throttle.runtime); +} + +static void update_softirq_runtime(unsigned long duration) +{ + struct softirq_runtime *si_runtime =3D this_cpu_ptr(&softirq_runtime); + + raw_spin_lock(&si_runtime->lock); + si_runtime->duration +=3D jiffies_to_msecs(duration); + if ((si_runtime->duration >=3D si_throttle.runtime) && + time_before(jiffies, si_runtime->expires)) { + si_runtime->throttled =3D true; + } + raw_spin_unlock(&si_runtime->lock); +} + +static bool softirq_runtime_exceeded(void) +{ + struct softirq_runtime *si_runtime =3D this_cpu_ptr(&softirq_runtime); + + if ((unsigned int)si_throttle.runtime >=3D si_throttle.period) + return false; + + raw_spin_lock(&si_runtime->lock); + if (!time_before(jiffies, si_runtime->expires)) + forward_softirq_expires(si_runtime); + raw_spin_unlock(&si_runtime->lock); + return si_runtime->throttled; +} + static int softirq_throttle_validate(void) { if (((int)sysctl_softirq_period_ms <=3D 0) || @@ -88,10 +131,18 @@ static int softirq_throttle_validate(void) static void softirq_throttle_update(void) { unsigned long flags; + struct softirq_runtime *si_runtime; =20 raw_spin_lock_irqsave(&si_throttle.lock, flags); si_throttle.period =3D sysctl_softirq_period_ms; si_throttle.runtime =3D sysctl_softirq_runtime_ms; + + for_each_possible_cpu(cpu, &) { + si_runtime =3D per_cpu_ptr(&softirq_runtime, cpu); + raw_spin_lock(&si_runtime->lock); + forward_softirq_expires(si_runtime); + raw_spin_unlock(&si_runtime->lock); + } raw_spin_unlock_irqrestore(&si_throttle.lock, flags); } =20 @@ -129,9 +180,17 @@ int softirq_throttle_handler(struct ctl_table *table, = int write, void *buffer, =20 static void softirq_throttle_init(void) { + struct softirq_runtime *si_runtime; + si_throttle.period =3D sysctl_softirq_period_ms; si_throttle.runtime =3D sysctl_softirq_runtime_ms; raw_spin_lock_init(&si_throttle.lock); + + for_each_possible_cpu(cpu) { + si_runtime =3D per_cpu_ptr(&softirq_runtime, cpu); + forward_softirq_expires(si_runtime); + raw_spin_lock_init(&si_runtime->lock); + } } #endif =20 @@ -592,6 +651,13 @@ asmlinkage __visible void __softirq_entry __do_softirq= (void) __u32 pending; int softirq_bit; =20 +#ifdef CONFIG_SOFTIRQ_THROTTLE + bool exceeded =3D softirq_runtime_exceeded(); + + if (exceeded) + return; +#endif + /* * Mask out PF_MEMALLOC as the current task context is borrowed for the * softirq. A softirq handled, such as network RX, might set PF_MEMALLOC @@ -652,6 +718,10 @@ asmlinkage __visible void __softirq_entry __do_softirq= (void) wakeup_softirqd(); } =20 +#ifdef CONFIG_SOFTIRQ_THROTTLE + update_softirq_runtime(jiffies - (end - MAX_SOFTIRQ_TIME)); +#endif + account_softirq_exit(current); lockdep_softirq_end(in_hardirq); softirq_handle_end(); --=20 2.17.1 From nobody Fri Jun 19 08:34:36 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 21DADC433F5 for ; Wed, 6 Apr 2022 14:18:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234697AbiDFOUZ (ORCPT ); Wed, 6 Apr 2022 10:20:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41034 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234610AbiDFOTi (ORCPT ); Wed, 6 Apr 2022 10:19:38 -0400 Received: from szxga02-in.huawei.com (szxga02-in.huawei.com [45.249.212.188]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E258932925B; Tue, 5 Apr 2022 19:53:37 -0700 (PDT) Received: from kwepemi500012.china.huawei.com (unknown [172.30.72.53]) by szxga02-in.huawei.com (SkyGuard) with ESMTP id 4KY8DP23QhzgYMw; Wed, 6 Apr 2022 10:51:49 +0800 (CST) Received: from huawei.com (10.67.174.53) by kwepemi500012.china.huawei.com (7.221.188.12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.24; Wed, 6 Apr 2022 10:53:32 +0800 From: Liao Chang To: , , , , , , , , , , , , , , , , , , , , , , , CC: , , , , Subject: [RFC 3/3] softirq: Introduce statistics about softirq throttling Date: Wed, 6 Apr 2022 10:52:41 +0800 Message-ID: <20220406025241.191300-4-liaochang1@huawei.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220406025241.191300-1-liaochang1@huawei.com> References: <20220406025241.191300-1-liaochang1@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.53] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To kwepemi500012.china.huawei.com (7.221.188.12) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This patch introduces counting the number of time spent on softirqs for each CPU and the number of time that softirqs has been throttled for each CPU, which are reported in /proc/softirqs, for example: $cat /proc/softirqs CPU0 CPU1 CPU2 CPU3 HI: 0 0 0 0 TIMER: 1088 855 197 4862 NET_TX: 0 0 0 0 NET_RX: 15 1 0 0 BLOCK: 14 11 86 75 IRQ_POLL: 0 0 0 0 TASKLET: 5926026 6133070 5646523 6149053 SCHED: 18061 15939 15746 16004 HRTIMER: 0 0 0 0 RCU: 668 778 939 720 CPU0 CPU1 CPU2 CPU3 DURATION_MS: 91556 69888 66784 73772 THROTTLE_MS: 77820 7328 5828 8904 Row starts with "DURATION_MS:" indicates how many milliseconds used for softirqs on each CPU. Row starts with "THROTTLE_MS:" indicates how many milliseconds softirq throttling lasted on each CPU. Notice: the rate of "THROTTLE_MS" increase is controlled by parameter "kernel.softirq_period_ms" and "kernel.softirq_runtime_ms", generally speaking, the smaller softirq CPU bandwidth is, the faster "THROTTLE_MS" increase, especially when pending softirq workload is very heavy. Signed-off-by: Liao Chang --- fs/proc/softirqs.c | 18 ++++++++++++++++++ include/linux/kernel_stat.h | 27 +++++++++++++++++++++++++++ kernel/softirq.c | 15 +++++++++++++-- 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/fs/proc/softirqs.c b/fs/proc/softirqs.c index 12901dcf57e2..5ea3ede9833e 100644 --- a/fs/proc/softirqs.c +++ b/fs/proc/softirqs.c @@ -22,6 +22,24 @@ static int show_softirqs(struct seq_file *p, void *v) seq_printf(p, " %10u", kstat_softirqs_cpu(i, j)); seq_putc(p, '\n'); } + +#ifdef CONFIG_SOFTIRQ_THROTTLE + seq_puts(p, " "); + for_each_possible_cpu(i) + seq_printf(p, "CPU%-8d", i); + seq_putc(p, '\n'); + + seq_printf(p, "%12s:", "DURATION_MS"); + for_each_possible_cpu(j) + seq_printf(p, " %10lu", kstat_softirq_duration(j)); + seq_putc(p, '\n'); + + seq_printf(p, "%12s:", "THROTTLE_MS"); + for_each_possible_cpu(j) + seq_printf(p, " %10lu", kstat_softirq_throttle(j)); + seq_putc(p, '\n'); +#endif + return 0; } =20 diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 69ae6b278464..bbb52c55aad4 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -38,6 +38,11 @@ struct kernel_cpustat { struct kernel_stat { unsigned long irqs_sum; unsigned int softirqs[NR_SOFTIRQS]; + +#ifdef CONFIG_SOFTIRQ_THROTTLE + unsigned long softirq_duration; + unsigned long softirq_throttle; +#endif }; =20 DECLARE_PER_CPU(struct kernel_stat, kstat); @@ -64,6 +69,28 @@ static inline unsigned int kstat_softirqs_cpu(unsigned i= nt irq, int cpu) return kstat_cpu(cpu).softirqs[irq]; } =20 +#ifdef CONFIG_SOFTIRQ_THROTTLE +static inline unsigned long kstat_softirq_duration(int cpu) +{ + return jiffies_to_msecs(kstat_cpu(cpu).softirq_duration); +} + +static inline unsigned long kstat_softirq_throttle(int cpu) +{ + return jiffies_to_msecs(kstat_cpu(cpu).softirq_throttle); +} + +static inline unsigned long kstat_incr_softirq_duration(unsigned long delt= a) +{ + return kstat_this_cpu->softirq_duration +=3D delta; +} + +static inline unsigned long kstat_incr_softirq_throttle(unsigned long delt= a) +{ + return kstat_this_cpu->softirq_throttle +=3D delta; +} +#endif + /* * Number of interrupts per specific IRQ source, since bootup */ diff --git a/kernel/softirq.c b/kernel/softirq.c index 6de6db794ac5..7fc0dc39f788 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -79,6 +79,7 @@ struct softirq_runtime { bool throttled; unsigned long duration; unsigned long expires; + unsigned long throttled_ts; raw_spinlock_t lock; }; static DEFINE_PER_CPU(struct softirq_runtime, softirq_runtime); @@ -94,12 +95,16 @@ static void forward_softirq_expires(struct softirq_runt= ime *si_runtime) static void update_softirq_runtime(unsigned long duration) { struct softirq_runtime *si_runtime =3D this_cpu_ptr(&softirq_runtime); + unsigned long now =3D jiffies; + + kstat_incr_softirq_duration(duration); =20 raw_spin_lock(&si_runtime->lock); si_runtime->duration +=3D jiffies_to_msecs(duration); if ((si_runtime->duration >=3D si_throttle.runtime) && - time_before(jiffies, si_runtime->expires)) { + time_before(now, si_runtime->expires)) { si_runtime->throttled =3D true; + si_runtime->throttled_ts =3D now; } raw_spin_unlock(&si_runtime->lock); } @@ -107,13 +112,17 @@ static void update_softirq_runtime(unsigned long dura= tion) static bool softirq_runtime_exceeded(void) { struct softirq_runtime *si_runtime =3D this_cpu_ptr(&softirq_runtime); + unsigned long now =3D jiffies; =20 if ((unsigned int)si_throttle.runtime >=3D si_throttle.period) return false; =20 raw_spin_lock(&si_runtime->lock); - if (!time_before(jiffies, si_runtime->expires)) + if (!time_before(now, si_runtime->expires)) { + if (si_runtime->throttled) + kstat_incr_softirq_throttle(now - si_runtime->throttled_ts); forward_softirq_expires(si_runtime); + } raw_spin_unlock(&si_runtime->lock); return si_runtime->throttled; } @@ -140,6 +149,8 @@ static void softirq_throttle_update(void) for_each_possible_cpu(cpu, &) { si_runtime =3D per_cpu_ptr(&softirq_runtime, cpu); raw_spin_lock(&si_runtime->lock); + if (si_runtime->throttled) + kstat_incr_softirq_throttle(jiffies - si_runtime->throttled_ts); forward_softirq_expires(si_runtime); raw_spin_unlock(&si_runtime->lock); } --=20 2.17.1