mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] delayacct: Preserve delay extrema when aggregating taskstats
@ 2026-10-22 16:06 Hungyu Lin
  2026-10-22 16:18 ` Bradley Morgan
  0 siblings, 1 reply; 2+ messages in thread
From: Hungyu Lin @ 2026-10-22 16:06 UTC (permalink / raw)
  To: bsingharora, yang.yang29
  Cc: akpm, brads, wang.yaxin, wang.yong12, xu.xin, jiang.kun2,
	linux-kernel, stable, Hungyu Lin

delayacct_add_tsk() adds each task's statistics to the accumulated TGID
statistics, but overwrites the delay maxima, minima and peak timestamps.
Consequently, the last task determines these fields, and a task with no
recorded delay can erase an earlier task's peak despite a nonzero total.

For example, a four-thread process has a worker writing copy-on-write
pages and a last-created thread with no WPCOPY events. With the group
stopped, getdelays -d -t 49 reports the following before and after the
fix (WPCOPY excerpt, spacing compacted and timestamp column omitted):

Before:
  WPCOPY count delay total delay average  delay max  delay min
          4103     5163661       0.001ms 0.000000ms 0.000000ms

After:
  WPCOPY count delay total delay average  delay max  delay min
          4101     4680983       0.001ms 0.049292ms 0.000208ms

The timings vary between runs. Before the fix, the zero extrema disagree
with the individual worker's nonzero values. After the fix, the group
extrema match the largest maximum and smallest nonzero minimum across
the individual threads.

Keep the largest maximum and its associated timestamp, and combine the
minima with min_not_zero() since zero denotes an unrecorded delay. Apply
this to CPU delay and the seven delay types handled by UPDATE_DELAY().
Single-task queries still start with zeroed statistics and retain the
task's values.

Fixes: 658eb5ab916d ("delayacct: add delay max to record delay peak")
Fixes: f65c64f311ee ("delayacct: add delay min to record delay peak")
Cc: stable@vger.kernel.org
Reviewed-by: Bradley Morgan <brads@mainlining.org>
Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
---
Changes in v2:
- Add a getdelays -d -t before/after example to the commit message, as
  requested by Andrew Morton.
- Add Bradley Morgan's Reviewed-by.
- No code changes.

 kernel/delayacct.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index 479e860aff70..ea1424524654 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -12,14 +12,18 @@
 #include <linux/taskstats.h>
 #include <linux/sysctl.h>
 #include <linux/delayacct.h>
+#include <linux/minmax.h>
 #include <linux/module.h>
 
 #define UPDATE_DELAY(type) \
 do { \
-	d->type##_delay_max = tsk->delays->type##_delay_max; \
-	d->type##_delay_min = tsk->delays->type##_delay_min; \
-	d->type##_delay_max_ts.tv_sec = tsk->delays->type##_delay_max_ts.tv_sec; \
-	d->type##_delay_max_ts.tv_nsec = tsk->delays->type##_delay_max_ts.tv_nsec; \
+	if (tsk->delays->type##_delay_max > d->type##_delay_max) { \
+		d->type##_delay_max = tsk->delays->type##_delay_max; \
+		d->type##_delay_max_ts.tv_sec = tsk->delays->type##_delay_max_ts.tv_sec; \
+		d->type##_delay_max_ts.tv_nsec = tsk->delays->type##_delay_max_ts.tv_nsec; \
+	} \
+	d->type##_delay_min = min_not_zero(d->type##_delay_min, \
+					 tsk->delays->type##_delay_min); \
 	tmp = d->type##_delay_total + tsk->delays->type##_delay; \
 	d->type##_delay_total = (tmp < d->type##_delay_total) ? 0 : tmp; \
 	d->type##_count += tsk->delays->type##_count; \
@@ -174,10 +178,13 @@ int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
 
 	d->cpu_count += t1;
 
-	d->cpu_delay_max = tsk->sched_info.max_run_delay;
-	d->cpu_delay_min = tsk->sched_info.min_run_delay;
-	d->cpu_delay_max_ts.tv_sec = tsk->sched_info.max_run_delay_ts.tv_sec;
-	d->cpu_delay_max_ts.tv_nsec = tsk->sched_info.max_run_delay_ts.tv_nsec;
+	if (tsk->sched_info.max_run_delay > d->cpu_delay_max) {
+		d->cpu_delay_max = tsk->sched_info.max_run_delay;
+		d->cpu_delay_max_ts.tv_sec = tsk->sched_info.max_run_delay_ts.tv_sec;
+		d->cpu_delay_max_ts.tv_nsec = tsk->sched_info.max_run_delay_ts.tv_nsec;
+	}
+	d->cpu_delay_min = min_not_zero(d->cpu_delay_min,
+					tsk->sched_info.min_run_delay);
 	tmp = (s64)d->cpu_delay_total + t2;
 	d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
 	tmp = (s64)d->cpu_run_virtual_total + t3;
-- 
2.43.0


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH v2] delayacct: Preserve delay extrema when aggregating taskstats
  2026-10-22 16:06 [PATCH v2] delayacct: Preserve delay extrema when aggregating taskstats Hungyu Lin
@ 2026-10-22 16:18 ` Bradley Morgan
  0 siblings, 0 replies; 2+ messages in thread
From: Bradley Morgan @ 2026-10-22 16:18 UTC (permalink / raw)
  To: Hungyu Lin, bsingharora, yang.yang29
  Cc: akpm, wang.yaxin, wang.yong12, xu.xin, jiang.kun2, linux-kernel, stable

On 22 October 2026 17:06:48 BST, Hungyu Lin <dennylin0707@gmail.com> wrote:
>delayacct_add_tsk() adds each task's statistics to the accumulated TGID
>statistics, but overwrites the delay maxima, minima and peak timestamps.
>Consequently, the last task determines these fields, and a task with no
>recorded delay can erase an earlier task's peak despite a nonzero total.
>
>For example, a four-thread process has a worker writing copy-on-write
>pages and a last-created thread with no WPCOPY events. With the group
>stopped, getdelays -d -t 49 reports the following before and after the
>fix (WPCOPY excerpt, spacing compacted and timestamp column omitted):
>
>Before:
>  WPCOPY count delay total delay average  delay max  delay min
>          4103     5163661       0.001ms 0.000000ms 0.000000ms
>
>After:
>  WPCOPY count delay total delay average  delay max  delay min
>          4101     4680983       0.001ms 0.049292ms 0.000208ms

Hmmmm... Looks feasible enough, it's a very tiny result.

>
>The timings vary between runs. Before the fix, the zero extrema disagree
>with the individual worker's nonzero values. After the fix, the group
>extrema match the largest maximum and smallest nonzero minimum across
>the individual threads.
>
>Keep the largest maximum and its associated timestamp, and combine the
>minima with min_not_zero() since zero denotes an unrecorded delay. Apply
>this to CPU delay and the seven delay types handled by UPDATE_DELAY().
>Single-task queries still start with zeroed statistics and retain the
>task's values.
>
>Fixes: 658eb5ab916d ("delayacct: add delay max to record delay peak")
>Fixes: f65c64f311ee ("delayacct: add delay min to record delay peak")
>Cc: stable@vger.kernel.org
>Reviewed-by: Bradley Morgan <brads@mainlining.org>
>Signed-off-by: Hungyu Lin <dennylin0707@gmail.com>
>---
>Changes in v2:
>- Add a getdelays -d -t before/after example to the commit message, as
>  requested by Andrew Morton.
>- Add Bradley Morgan's Reviewed-by.
>- No code changes.
>
> kernel/delayacct.c | 23 +++++++++++++++--------
> 1 file changed, 15 insertions(+), 8 deletions(-)
>
>diff --git a/kernel/delayacct.c b/kernel/delayacct.c
>index 479e860aff70..ea1424524654 100644
>--- a/kernel/delayacct.c
>+++ b/kernel/delayacct.c
>@@ -12,14 +12,18 @@
> #include <linux/taskstats.h>
> #include <linux/sysctl.h>
> #include <linux/delayacct.h>
>+#include <linux/minmax.h>
> #include <linux/module.h>
> 
> #define UPDATE_DELAY(type) \
> do { \
>-	d->type##_delay_max = tsk->delays->type##_delay_max; \
>-	d->type##_delay_min = tsk->delays->type##_delay_min; \
>-	d->type##_delay_max_ts.tv_sec = tsk->delays->type##_delay_max_ts.tv_sec; \
>-	d->type##_delay_max_ts.tv_nsec = tsk->delays->type##_delay_max_ts.tv_nsec; \
>+	if (tsk->delays->type##_delay_max > d->type##_delay_max) { \
>+		d->type##_delay_max = tsk->delays->type##_delay_max; \
>+		d->type##_delay_max_ts.tv_sec = tsk->delays->type##_delay_max_ts.tv_sec; \
>+		d->type##_delay_max_ts.tv_nsec = tsk->delays->type##_delay_max_ts.tv_nsec; \
>+	} \
>+	d->type##_delay_min = min_not_zero(d->type##_delay_min, \
>+					 tsk->delays->type##_delay_min); \
> 	tmp = d->type##_delay_total + tsk->delays->type##_delay; \
> 	d->type##_delay_total = (tmp < d->type##_delay_total) ? 0 : tmp; \
> 	d->type##_count += tsk->delays->type##_count; \
>@@ -174,10 +178,13 @@ int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
> 
> 	d->cpu_count += t1;
> 
>-	d->cpu_delay_max = tsk->sched_info.max_run_delay;
>-	d->cpu_delay_min = tsk->sched_info.min_run_delay;
>-	d->cpu_delay_max_ts.tv_sec = tsk->sched_info.max_run_delay_ts.tv_sec;
>-	d->cpu_delay_max_ts.tv_nsec = tsk->sched_info.max_run_delay_ts.tv_nsec;
>+	if (tsk->sched_info.max_run_delay > d->cpu_delay_max) {
>+		d->cpu_delay_max = tsk->sched_info.max_run_delay;
>+		d->cpu_delay_max_ts.tv_sec = tsk->sched_info.max_run_delay_ts.tv_sec;
>+		d->cpu_delay_max_ts.tv_nsec = tsk->sched_info.max_run_delay_ts.tv_nsec;
>+	}
>+	d->cpu_delay_min = min_not_zero(d->cpu_delay_min,
>+					tsk->sched_info.min_run_delay);
> 	tmp = (s64)d->cpu_delay_total + t2;
> 	d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
> 	tmp = (s64)d->cpu_run_virtual_total + t3;
>

--- Thanks!
"I'm not a very positive person" - Linus torvalds

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-22 16:18 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 16:06 [PATCH v2] delayacct: Preserve delay extrema when aggregating taskstats Hungyu Lin
2026-10-22 16:18 ` Bradley Morgan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®