* [PATCHSET] sched/delayacct: get task SOFTIRQ delay
@ 2024-04-02 11:21 Tio Zhang
2024-04-02 11:24 ` [PATCH 1/3] sched: make softirq cputime accounting separately in irqtime Tio Zhang
0 siblings, 1 reply; 4+ messages in thread
From: Tio Zhang @ 2024-04-02 11:21 UTC (permalink / raw)
To: mingo, peterz, juri.lelli, vincent.guittot, rostedt, bsingharora,
corbet, akpm
Cc: linux-kernel, linux-doc, dietmar.eggemann, bsegall, mgorman,
bristot, vschneid, tiozhang, zyhtheonly, zyhtheonly, fuyuanli
We can only get IRQ/SOFTIRQ delay in total now in Delay accounting, but
getting SOFTIRQ delay and IRQ delay separetely would help users reduce
such delays in a more convenient way.
For IRQ delay, we can tuning irq CPU affinity or using threaded-irq.
For SOFTIRQ delay, we can tuning rps/xps or using kernel threads for NAPI.
And this is an example stack a task is delayed mainly by SOFTIRQ(delay
by receiving packets when sending packets):
...
ip_rcv
__netif_receive_skb_core
__netif_receive_skb
process_backlog
net_rx_action
do_softirq
__local_bh_enable_ip
ip_finish_output2
ip_finish_output
ip_output
ip_local_out
ip_send_skb
udp_send_skb
udp_sendmsg
inet_sendmsg
sock_sendmsg
__sys_sendto
do_syscall_64
__libc_sendto
...
So this patchset tries to make SOFTIRQ delay observeable in Delay
accounting and available in taskstats.
(also update tools/accounting/getdelays.c)
Also for backward compatibility, we dont want to change the meaning of
origin IRQ/SOFTIRQ delay, instead we can get real IRQ(interrupt) delay by
the origin IRQ/SOFTIRQ delay minus SOFTIRQ delay added by this patch.
With this patch, the example above results by getdelays.c:
# ./getdelays -t 4600 -d
print delayacct stats ON
TGID 4600
CPU count real total virtual total delay total delay average
3973 10700014780 10698803222 312345815813 78.617ms
IO count delay total delay average
0 0 0.000ms
SWAP count delay total delay average
0 0 0.000ms
RECLAIM count delay total delay average
0 0 0.000ms
THRASHING count delay total delay average
0 0 0.000ms
COMPACT count delay total delay average
0 0 0.000ms
WPCOPY count delay total delay average
40 266859 0.007ms
IRQ count delay total delay average
13450 17756373906 1.320ms
SOFTIRQ count delay total delay average
13450 17639154300 1.311ms
We find out SOFTIRQ impact the delay most, then tune RPS to reduce this.
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH 1/3] sched: make softirq cputime accounting separately in irqtime 2024-04-02 11:21 [PATCHSET] sched/delayacct: get task SOFTIRQ delay Tio Zhang @ 2024-04-02 11:24 ` Tio Zhang 2024-04-02 11:27 ` [PATCH 2/3] delayacct: get delay of SOFTIRQ Tio Zhang 0 siblings, 1 reply; 4+ messages in thread From: Tio Zhang @ 2024-04-02 11:24 UTC (permalink / raw) To: mingo, peterz, juri.lelli, vincent.guittot, rostedt, bsingharora, corbet, akpm Cc: linux-kernel, linux-doc, dietmar.eggemann, bsegall, mgorman, bristot, vschneid, tiozhang, zyhtheonly, zyhtheonly, fuyuanli Currently we account irq{,soft} time in "irqtime.total", when CONFIG_IRQ_TIME_ACCOUNTING=y. Since we account them in the same path (irq{,soft}_enter{,exit}), we can separately count them by filtering the offset. In order to not break backward compatibility, we do not change the meaning of "total", we only let softirq time to be accounted separately in a new field "total_soft". So interrupt time could also be calculated by "total" minus "total_soft". This patch only let softirq cputime stats available in irqtime, do not make it in real usage. Signed-off-by: Tio Zhang <tiozhang@didiglobal.com> --- kernel/sched/cputime.c | 18 ++++++++++++++---- kernel/sched/sched.h | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index af7952f12e6c..23e4bca1e3e8 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -35,13 +35,14 @@ void disable_sched_clock_irqtime(void) } static void irqtime_account_delta(struct irqtime *irqtime, u64 delta, - enum cpu_usage_stat idx) + u64 delta_soft, enum cpu_usage_stat idx) { u64 *cpustat = kcpustat_this_cpu->cpustat; u64_stats_update_begin(&irqtime->sync); cpustat[idx] += delta; irqtime->total += delta; + irqtime->total_soft += delta_soft; irqtime->tick_delta += delta; u64_stats_update_end(&irqtime->sync); } @@ -54,7 +55,7 @@ void irqtime_account_irq(struct task_struct *curr, unsigned int offset) { struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime); unsigned int pc; - s64 delta; + s64 delta, delta_soft = 0; int cpu; if (!sched_clock_irqtime) @@ -65,6 +66,15 @@ void irqtime_account_irq(struct task_struct *curr, unsigned int offset) irqtime->irq_start_time += delta; pc = irq_count() - offset; + /* + * We only account softirq time when we are called by + * account_softirq_enter{,exit} + */ + if ((offset & SOFTIRQ_OFFSET) || (pc & SOFTIRQ_OFFSET)) { + delta_soft = sched_clock_cpu(cpu) - irqtime->soft_start_time; + irqtime->soft_start_time += delta_soft; + } + /* * We do not account for softirq time from ksoftirqd here. * We want to continue accounting softirq time to ksoftirqd thread @@ -72,9 +82,9 @@ void irqtime_account_irq(struct task_struct *curr, unsigned int offset) * that do not consume any time, but still wants to run. */ if (pc & HARDIRQ_MASK) - irqtime_account_delta(irqtime, delta, CPUTIME_IRQ); + irqtime_account_delta(irqtime, delta, delta_soft, CPUTIME_IRQ); else if ((pc & SOFTIRQ_OFFSET) && curr != this_cpu_ksoftirqd()) - irqtime_account_delta(irqtime, delta, CPUTIME_SOFTIRQ); + irqtime_account_delta(irqtime, delta, delta_soft, CPUTIME_SOFTIRQ); } static u64 irqtime_tick_accounted(u64 maxtime) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 001fe047bd5d..f479c61b84b5 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2931,8 +2931,10 @@ static inline void nohz_run_idle_balance(int cpu) { } #ifdef CONFIG_IRQ_TIME_ACCOUNTING struct irqtime { u64 total; + u64 total_soft; u64 tick_delta; u64 irq_start_time; + u64 soft_start_time; struct u64_stats_sync sync; }; @@ -2956,6 +2958,20 @@ static inline u64 irq_time_read(int cpu) return total; } + +static inline u64 irq_time_read_soft(int cpu) +{ + struct irqtime *irqtime = &per_cpu(cpu_irqtime, cpu); + unsigned int seq; + u64 total_soft; + + do { + seq = __u64_stats_fetch_begin(&irqtime->sync); + total_soft = irqtime->total_soft; + } while (__u64_stats_fetch_retry(&irqtime->sync, seq)); + + return total_soft; +} #endif /* CONFIG_IRQ_TIME_ACCOUNTING */ #ifdef CONFIG_CPU_FREQ -- 2.17.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] delayacct: get delay of SOFTIRQ 2024-04-02 11:24 ` [PATCH 1/3] sched: make softirq cputime accounting separately in irqtime Tio Zhang @ 2024-04-02 11:27 ` Tio Zhang 2024-04-02 11:29 ` [PATCH 3/3] delayacct/taskstats: make soft_delay available in taskstats Tio Zhang 0 siblings, 1 reply; 4+ messages in thread From: Tio Zhang @ 2024-04-02 11:27 UTC (permalink / raw) To: mingo, peterz, juri.lelli, vincent.guittot, rostedt, bsingharora, corbet, akpm Cc: linux-kernel, linux-doc, dietmar.eggemann, bsegall, mgorman, bristot, vschneid, tiozhang, zyhtheonly, zyhtheonly, fuyuanli This patch makes SOFTIRQ time accounted by "irqtime.total_soft" in use by adding soft_delay accounts for Delay accounting. Signed-off-by: Tio Zhang <tiozhang@didiglobal.com> --- include/linux/delayacct.h | 11 +++++++---- kernel/delayacct.c | 5 +++-- kernel/sched/core.c | 6 ++++-- kernel/sched/sched.h | 1 + 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/linux/delayacct.h b/include/linux/delayacct.h index 6639f48dac36..bf1d45fcb505 100644 --- a/include/linux/delayacct.h +++ b/include/linux/delayacct.h @@ -49,12 +49,14 @@ struct task_delay_info { u64 wpcopy_delay; /* wait for write-protect copy */ u64 irq_delay; /* wait for IRQ/SOFTIRQ */ + u64 soft_delay; /* wait for SOFTIRQ */ u32 freepages_count; /* total count of memory reclaim */ u32 thrashing_count; /* total count of thrash waits */ u32 compact_count; /* total count of memory compact */ u32 wpcopy_count; /* total count of write-protect copy */ u32 irq_count; /* total count of IRQ/SOFTIRQ */ + u32 soft_count; /* total count of SOFTIRQ */ }; #endif @@ -84,7 +86,7 @@ extern void __delayacct_compact_start(void); extern void __delayacct_compact_end(void); extern void __delayacct_wpcopy_start(void); extern void __delayacct_wpcopy_end(void); -extern void __delayacct_irq(struct task_struct *task, u32 delta); +extern void __delayacct_irq(struct task_struct *task, u32 delta, u32 delta_soft); static inline void delayacct_tsk_init(struct task_struct *tsk) { @@ -219,13 +221,14 @@ static inline void delayacct_wpcopy_end(void) __delayacct_wpcopy_end(); } -static inline void delayacct_irq(struct task_struct *task, u32 delta) +static inline void delayacct_irq(struct task_struct *task, u32 delta, + u32 delta_soft) { if (!static_branch_unlikely(&delayacct_key)) return; if (task->delays) - __delayacct_irq(task, delta); + __delayacct_irq(task, delta, delta_soft); } #else @@ -266,7 +269,7 @@ static inline void delayacct_wpcopy_start(void) {} static inline void delayacct_wpcopy_end(void) {} -static inline void delayacct_irq(struct task_struct *task, u32 delta) +static inline void delayacct_irq(struct task_struct *task, u32 delta, u32 delta_soft) {} #endif /* CONFIG_TASK_DELAY_ACCT */ diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 6f0c358e73d8..8517f1c1df88 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -278,13 +278,14 @@ void __delayacct_wpcopy_end(void) ¤t->delays->wpcopy_count); } -void __delayacct_irq(struct task_struct *task, u32 delta) +void __delayacct_irq(struct task_struct *task, u32 delta, u32 delta_soft) { unsigned long flags; raw_spin_lock_irqsave(&task->delays->lock, flags); task->delays->irq_delay += delta; task->delays->irq_count++; + task->delays->soft_delay += delta_soft; + task->delays->soft_count++; raw_spin_unlock_irqrestore(&task->delays->lock, flags); } - diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 9116bcc90346..2f5fd775b47b 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -698,10 +698,11 @@ static void update_rq_clock_task(struct rq *rq, s64 delta) * In theory, the compile should just see 0 here, and optimize out the call * to sched_rt_avg_update. But I don't trust it... */ - s64 __maybe_unused steal = 0, irq_delta = 0; + s64 __maybe_unused steal = 0, irq_delta = 0, soft_delta = 0; #ifdef CONFIG_IRQ_TIME_ACCOUNTING irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time; + soft_delta = irq_time_read_soft(cpu_of(rq)) - rq->prev_soft_time; /* * Since irq_time is only updated on {soft,}irq_exit, we might run into @@ -722,9 +723,10 @@ static void update_rq_clock_task(struct rq *rq, s64 delta) irq_delta = delta; rq->prev_irq_time += irq_delta; + rq->prev_soft_time += soft_delta; delta -= irq_delta; psi_account_irqtime(rq->curr, irq_delta); - delayacct_irq(rq->curr, irq_delta); + delayacct_irq(rq->curr, irq_delta, soft_delta); #endif #ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING if (static_key_false((¶virt_steal_rq_enabled))) { diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index f479c61b84b5..abf96ad9c301 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1105,6 +1105,7 @@ struct rq { #ifdef CONFIG_IRQ_TIME_ACCOUNTING u64 prev_irq_time; + u64 prev_soft_time; #endif #ifdef CONFIG_PARAVIRT u64 prev_steal_time; -- 2.17.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] delayacct/taskstats: make soft_delay available in taskstats 2024-04-02 11:27 ` [PATCH 2/3] delayacct: get delay of SOFTIRQ Tio Zhang @ 2024-04-02 11:29 ` Tio Zhang 0 siblings, 0 replies; 4+ messages in thread From: Tio Zhang @ 2024-04-02 11:29 UTC (permalink / raw) To: mingo, peterz, juri.lelli, vincent.guittot, rostedt, bsingharora, corbet, akpm Cc: linux-kernel, linux-doc, dietmar.eggemann, bsegall, mgorman, bristot, vschneid, tiozhang, zyhtheonly, zyhtheonly, fuyuanli Also update a new version of tools/accounting/getdelays.c. # ./getdelays -t 4600 -d print delayacct stats ON TGID 4600 CPU count real total virtual total delay total delay average 3973 10700014780 10698803222 312345815813 78.617ms IO count delay total delay average 0 0 0.000ms SWAP count delay total delay average 0 0 0.000ms RECLAIM count delay total delay average 0 0 0.000ms THRASHING count delay total delay average 0 0 0.000ms COMPACT count delay total delay average 0 0 0.000ms WPCOPY count delay total delay average 40 266859 0.007ms IRQ count delay total delay average 13450 17756373906 1.320ms SOFTIRQ count delay total delay average Signed-off-by: Tio Zhang <tiozhang@didiglobal.com> --- Documentation/accounting/delay-accounting.rst | 5 ++++- include/uapi/linux/taskstats.h | 6 +++++- kernel/delayacct.c | 3 +++ tools/accounting/getdelays.c | 8 +++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/accounting/delay-accounting.rst index f61c01fc376e..babff410a39d 100644 --- a/Documentation/accounting/delay-accounting.rst +++ b/Documentation/accounting/delay-accounting.rst @@ -17,6 +17,7 @@ e) thrashing f) direct compact g) write-protect copy h) IRQ/SOFTIRQ +i) SOFTIRQ and makes these statistics available to userspace through the taskstats interface. @@ -50,7 +51,7 @@ this structure. See for a description of the fields pertaining to delay accounting. It will generally be in the form of counters returning the cumulative delay seen for cpu, sync block I/O, swapin, memory reclaim, thrash page -cache, direct compact, write-protect copy, IRQ/SOFTIRQ etc. +cache, direct compact, write-protect copy, IRQ/SOFTIRQ, SOFTIRQ etc. Taking the difference of two successive readings of a given counter (say cpu_delay_total) for a task will give the delay @@ -123,6 +124,8 @@ Get sum of delays, since system boot, for all pids with tgid 5:: 0 0 0.000ms IRQ count delay total delay average 0 0 0.000ms + SOFTIRQ count delay total delay average + 0 0 0.000ms Get IO accounting for pid 1, it works only with -p:: diff --git a/include/uapi/linux/taskstats.h b/include/uapi/linux/taskstats.h index b50b2eb257a0..5412c4d6734d 100644 --- a/include/uapi/linux/taskstats.h +++ b/include/uapi/linux/taskstats.h @@ -34,7 +34,7 @@ */ -#define TASKSTATS_VERSION 14 +#define TASKSTATS_VERSION 15 #define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN * in linux/sched.h */ @@ -202,6 +202,10 @@ struct taskstats { /* v14: Delay waiting for IRQ/SOFTIRQ */ __u64 irq_count; __u64 irq_delay_total; + + /* v15: Delay waiting for SOFTIRQ */ + __u64 soft_count; + __u64 soft_delay_total; }; diff --git a/kernel/delayacct.c b/kernel/delayacct.c index 8517f1c1df88..39d9430d723f 100644 --- a/kernel/delayacct.c +++ b/kernel/delayacct.c @@ -181,6 +181,8 @@ int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->wpcopy_delay_total = (tmp < d->wpcopy_delay_total) ? 0 : tmp; tmp = d->irq_delay_total + tsk->delays->irq_delay; d->irq_delay_total = (tmp < d->irq_delay_total) ? 0 : tmp; + tmp = d->soft_delay_total + tsk->delays->soft_delay; + d->soft_delay_total = (tmp < d->soft_delay_total) ? 0 : tmp; d->blkio_count += tsk->delays->blkio_count; d->swapin_count += tsk->delays->swapin_count; d->freepages_count += tsk->delays->freepages_count; @@ -188,6 +190,7 @@ int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk) d->compact_count += tsk->delays->compact_count; d->wpcopy_count += tsk->delays->wpcopy_count; d->irq_count += tsk->delays->irq_count; + d->soft_count += tsk->delays->soft_count; raw_spin_unlock_irqrestore(&tsk->delays->lock, flags); return 0; diff --git a/tools/accounting/getdelays.c b/tools/accounting/getdelays.c index 1334214546d7..6e4e032e93c4 100644 --- a/tools/accounting/getdelays.c +++ b/tools/accounting/getdelays.c @@ -210,6 +210,8 @@ static void print_delayacct(struct taskstats *t) "WPCOPY %12s%15s%15s\n" " %15llu%15llu%15.3fms\n" "IRQ %15s%15s%15s\n" + " %15llu%15llu%15.3fms\n" + "SOFTIRQ %12s%15s%15s\n" " %15llu%15llu%15.3fms\n", "count", "real total", "virtual total", "delay total", "delay average", @@ -245,7 +247,11 @@ static void print_delayacct(struct taskstats *t) "count", "delay total", "delay average", (unsigned long long)t->irq_count, (unsigned long long)t->irq_delay_total, - average_ms((double)t->irq_delay_total, t->irq_count)); + average_ms((double)t->irq_delay_total, t->irq_count), + "count", "delay total", "delay average", + (unsigned long long)t->soft_count, + (unsigned long long)t->soft_delay_total, + average_ms((double)t->soft_delay_total, t->soft_count)); } static void task_context_switch_counts(struct taskstats *t) -- 2.17.1 ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-04-02 11:29 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-04-02 11:21 [PATCHSET] sched/delayacct: get task SOFTIRQ delay Tio Zhang 2024-04-02 11:24 ` [PATCH 1/3] sched: make softirq cputime accounting separately in irqtime Tio Zhang 2024-04-02 11:27 ` [PATCH 2/3] delayacct: get delay of SOFTIRQ Tio Zhang 2024-04-02 11:29 ` [PATCH 3/3] delayacct/taskstats: make soft_delay available in taskstats Tio Zhang
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox