Files
linux-torvalds-mirror/include/linux/delayacct.h
Wang Yaxin 503efe850c delayacct: add timestamp of delay max
Problem
=======
Commit 658eb5ab91 ("delayacct: add delay max to record delay peak")
introduced the delay max for getdelays, which records abnormal latency
peaks and helps us understand the magnitude of such delays.  However, the
peak latency value alone is insufficient for effective root cause
analysis.  Without the precise timestamp of when the peak occurred, we
still lack the critical context needed to correlate it with other system
events.

Solution
========
To address this, we need to additionally record a precise timestamp when
the maximum latency occurs.  By correlating this timestamp with system
logs and monitoring metrics, we can identify processes with abnormal
resource usage at the same moment, which can help us to pinpoint root
causes.

Use Case
========
bash-4.4# ./getdelays -d -t 227
print delayacct stats ON
TGID    227
CPU         count     real total  virtual total    delay total  delay average      delay max      delay min      delay max timestamp
               46      188000000      192348334        4098012          0.089ms     0.429260ms     0.051205ms    2026-01-15T15:06:58
IO          count    delay total  delay average      delay max      delay min      delay max timestamp
                0              0          0.000ms     0.000000ms     0.000000ms                    N/A
SWAP        count    delay total  delay average      delay max      delay min      delay max timestamp
                0              0          0.000ms     0.000000ms     0.000000ms                    N/A
RECLAIM     count    delay total  delay average      delay max      delay min      delay max timestamp
                0              0          0.000ms     0.000000ms     0.000000ms                    N/A
THRAS HING   count    delay total  delay average      delay max      delay min      delay max timestamp
                0              0          0.000ms     0.000000ms     0.000000ms                    N/A
COMPACT     count    delay total  delay average      delay max      delay min      delay max timestamp
                0              0          0.000ms     0.000000ms     0.000000ms                    N/A
WPCOPY      count    delay total  delay average      delay max      delay min      delay max timestamp
              182       19413338          0.107ms     0.547353ms     0.022462ms    2026-01-15T15:05:24
IRQ         count    delay total  delay average      delay max      delay min      delay max timestamp
                0              0          0.000ms     0.000000ms     0.000000ms                    N/A

Link: https://lkml.kernel.org/r/20260119100241520gWubW8-5QfhSf9gjqcc_E@zte.com.cn
Signed-off-by: Wang Yaxin <wang.yaxin@zte.com.cn>
Cc: Fan Yu <fan.yu9@zte.com.cn>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: xu xin <xu.xin16@zte.com.cn>
Cc: Yang Yang <yang.yang29@zte.com.cn>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2026-01-31 16:16:06 -08:00

297 lines
7.4 KiB
C

/* SPDX-License-Identifier: GPL-2.0-or-later */
/* delayacct.h - per-task delay accounting
*
* Copyright (C) Shailabh Nagar, IBM Corp. 2006
*/
#ifndef _LINUX_DELAYACCT_H
#define _LINUX_DELAYACCT_H
#include <uapi/linux/taskstats.h>
#ifdef CONFIG_TASK_DELAY_ACCT
struct task_delay_info {
raw_spinlock_t lock;
/* For each stat XXX, add following, aligned appropriately
*
* struct timespec XXX_start, XXX_end;
* u64 XXX_delay;
* u32 XXX_count;
*
* Atomicity of updates to XXX_delay, XXX_count protected by
* single lock above (split into XXX_lock if contention is an issue).
*/
/*
* XXX_count is incremented on every XXX operation, the delay
* associated with the operation is added to XXX_delay.
* XXX_delay contains the accumulated delay time in nanoseconds.
*/
u64 blkio_start;
u64 blkio_delay_max;
u64 blkio_delay_min;
u64 blkio_delay; /* wait for sync block io completion */
u64 swapin_start;
u64 swapin_delay_max;
u64 swapin_delay_min;
u64 swapin_delay; /* wait for swapin */
u32 blkio_count; /* total count of the number of sync block */
/* io operations performed */
u32 swapin_count; /* total count of swapin */
u64 freepages_start;
u64 freepages_delay_max;
u64 freepages_delay_min;
u64 freepages_delay; /* wait for memory reclaim */
u64 thrashing_start;
u64 thrashing_delay_max;
u64 thrashing_delay_min;
u64 thrashing_delay; /* wait for thrashing page */
u64 compact_start;
u64 compact_delay_max;
u64 compact_delay_min;
u64 compact_delay; /* wait for memory compact */
u64 wpcopy_start;
u64 wpcopy_delay_max;
u64 wpcopy_delay_min;
u64 wpcopy_delay; /* wait for write-protect copy */
u64 irq_delay_max;
u64 irq_delay_min;
u64 irq_delay; /* wait for IRQ/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 */
struct timespec64 blkio_delay_max_ts;
struct timespec64 swapin_delay_max_ts;
struct timespec64 freepages_delay_max_ts;
struct timespec64 thrashing_delay_max_ts;
struct timespec64 compact_delay_max_ts;
struct timespec64 wpcopy_delay_max_ts;
struct timespec64 irq_delay_max_ts;
};
#endif
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/jump_label.h>
#ifdef CONFIG_TASK_DELAY_ACCT
DECLARE_STATIC_KEY_FALSE(delayacct_key);
extern int delayacct_on; /* Delay accounting turned on/off */
extern struct kmem_cache *delayacct_cache;
extern void delayacct_init(void);
extern void __delayacct_tsk_init(struct task_struct *);
extern void __delayacct_tsk_exit(struct task_struct *);
extern void __delayacct_blkio_start(void);
extern void __delayacct_blkio_end(struct task_struct *);
extern int delayacct_add_tsk(struct taskstats *, struct task_struct *);
extern __u64 __delayacct_blkio_ticks(struct task_struct *);
extern void __delayacct_freepages_start(void);
extern void __delayacct_freepages_end(void);
extern void __delayacct_thrashing_start(bool *in_thrashing);
extern void __delayacct_thrashing_end(bool *in_thrashing);
extern void __delayacct_swapin_start(void);
extern void __delayacct_swapin_end(void);
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);
static inline void delayacct_tsk_init(struct task_struct *tsk)
{
/* reinitialize in case parent's non-null pointer was dup'ed*/
tsk->delays = NULL;
if (delayacct_on)
__delayacct_tsk_init(tsk);
}
/* Free tsk->delays. Called from bad fork and __put_task_struct
* where there's no risk of tsk->delays being accessed elsewhere
*/
static inline void delayacct_tsk_free(struct task_struct *tsk)
{
if (tsk->delays)
kmem_cache_free(delayacct_cache, tsk->delays);
tsk->delays = NULL;
}
static inline void delayacct_blkio_start(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_blkio_start();
}
static inline void delayacct_blkio_end(struct task_struct *p)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (p->delays)
__delayacct_blkio_end(p);
}
static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk)
{
if (tsk->delays)
return __delayacct_blkio_ticks(tsk);
return 0;
}
static inline void delayacct_freepages_start(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_freepages_start();
}
static inline void delayacct_freepages_end(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_freepages_end();
}
static inline void delayacct_thrashing_start(bool *in_thrashing)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_thrashing_start(in_thrashing);
}
static inline void delayacct_thrashing_end(bool *in_thrashing)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_thrashing_end(in_thrashing);
}
static inline void delayacct_swapin_start(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_swapin_start();
}
static inline void delayacct_swapin_end(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_swapin_end();
}
static inline void delayacct_compact_start(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_compact_start();
}
static inline void delayacct_compact_end(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_compact_end();
}
static inline void delayacct_wpcopy_start(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_wpcopy_start();
}
static inline void delayacct_wpcopy_end(void)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (current->delays)
__delayacct_wpcopy_end();
}
static inline void delayacct_irq(struct task_struct *task, u32 delta)
{
if (!static_branch_unlikely(&delayacct_key))
return;
if (task->delays)
__delayacct_irq(task, delta);
}
#else
static inline void delayacct_init(void)
{}
static inline void delayacct_tsk_init(struct task_struct *tsk)
{}
static inline void delayacct_tsk_free(struct task_struct *tsk)
{}
static inline void delayacct_blkio_start(void)
{}
static inline void delayacct_blkio_end(struct task_struct *p)
{}
static inline int delayacct_add_tsk(struct taskstats *d,
struct task_struct *tsk)
{ return 0; }
static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk)
{ return 0; }
static inline int delayacct_is_task_waiting_on_io(struct task_struct *p)
{ return 0; }
static inline void delayacct_freepages_start(void)
{}
static inline void delayacct_freepages_end(void)
{}
static inline void delayacct_thrashing_start(bool *in_thrashing)
{}
static inline void delayacct_thrashing_end(bool *in_thrashing)
{}
static inline void delayacct_swapin_start(void)
{}
static inline void delayacct_swapin_end(void)
{}
static inline void delayacct_compact_start(void)
{}
static inline void delayacct_compact_end(void)
{}
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)
{}
#endif /* CONFIG_TASK_DELAY_ACCT */
#endif