Skip to content

Commit 6b47c9f

Browse files
Wang Yaxinakpm00
authored andcommitted
delaytop: add psi info to show system delay
Support showing whole delay of system by reading PSI, just like the first few lines of information output by the top command. the output of delaytop includes both system-wide delay and delay of individual tasks, providing a more comprehensive reflection of system latency status. Use case ======== bash# ./delaytop System Pressure Information: (avg10/avg60/avg300/total) CPU: full: 0.0%/ 0.0%/ 0.0%/0 some: 0.1%/ 0.0%/ 0.0%/14216596 Memory: full: 0.0%/ 0.0%/ 0.0%/34010659 some: 0.0%/ 0.0%/ 0.0%/35406492 IO: full: 0.1%/ 0.0%/ 0.0%/51029453 some: 0.1%/ 0.0%/ 0.0%/55330465 IRQ: full: 0.0%/ 0.0%/ 0.0%/0 Top 20 processes (sorted by CPU delay): PID TGID COMMAND CPU(ms) IO(ms) SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms) --------------------------------------------------------------------------------------------- 32 32 kworker/2:0H-sy 23.65 0.00 0.00 0.00 0.00 0.00 0.00 0.00 497 497 kworker/R-scsi_ 1.20 0.00 0.00 0.00 0.00 0.00 0.00 0.00 495 495 kworker/R-scsi_ 1.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00 494 494 scsi_eh_0 1.12 0.00 0.00 0.00 0.00 0.00 0.00 0.00 485 485 kworker/R-ata_s 0.90 0.00 0.00 0.00 0.00 0.00 0.00 0.00 574 574 kworker/R-kdmfl 0.36 0.00 0.00 0.00 0.00 0.00 0.00 0.00 34 34 idle_inject/3 0.33 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1123 1123 nde-netfilter 0.28 0.00 0.00 0.00 0.00 0.00 0.00 0.00 60 60 ksoftirqd/7 0.25 0.00 0.00 0.00 0.00 0.00 0.00 0.00 114 114 kworker/0:2-cgr 0.25 0.00 0.00 0.00 0.00 0.00 0.00 0.00 496 496 scsi_eh_1 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00 51 51 cpuhp/6 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1667 1667 atd 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00 45 45 cpuhp/5 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1102 1102 nde-backupservi 0.22 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1098 1098 systemsettings 0.21 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1100 1100 audit-monitor 0.20 0.00 0.00 0.00 0.00 0.00 0.00 0.00 53 53 migration/6 0.20 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1482 1482 sshd 0.19 0.00 0.00 0.00 0.00 0.00 0.00 0.00 39 39 cpuhp/4 0.19 0.00 0.00 0.00 0.00 0.00 0.00 0.00 Link: https://lkml.kernel.org/r/20250710135451340_5pOgpIFi0M5AE7H44W1D@zte.com.cn Co-developed-by: Fan Yu <fan.yu9@zte.com.cn> Signed-off-by: Fan Yu <fan.yu9@zte.com.cn> Signed-off-by: Wang Yaxin <wang.yaxin@zte.com.cn> Signed-off-by: Jiang Kun <jiang.kun2@zte.com.cn> Cc: Balbir Singh <bsingharora@gmail.com> Cc: David Hildenbrand <david@redhat.com> Cc: Peilin He <he.peilin@zte.com.cn> Cc: Qiang Tu <tu.qiang35@zte.com.cn> Cc: wangyong <wang.yong12@zte.com.cn> Cc: xu xin <xu.xin16@zte.com.cn> Cc: Yang Yang <yang.yang29@zte.com.cn> Cc: Yunkai Zhang <zhang.yunkai@zte.com.cn> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 599579e commit 6b47c9f

1 file changed

Lines changed: 149 additions & 14 deletions

File tree

tools/accounting/delaytop.c

Lines changed: 149 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010
* individual tasks (PIDs).
1111
*
1212
* Key features:
13-
* - Collects per-task delay accounting statistics via taskstats.
14-
* - Supports sorting, filtering.
15-
* - Supports both interactive (screen refresh).
13+
* - Collects per-task delay accounting statistics via taskstats.
14+
* - Supports sorting, filtering.
15+
* - Supports both interactive (screen refresh).
1616
*
1717
* Copyright (C) Fan Yu, ZTE Corp. 2025
1818
* Copyright (C) Wang Yaxin, ZTE Corp. 2025
@@ -43,6 +43,14 @@
4343
#include <linux/cgroupstats.h>
4444
#include <ncurses.h>
4545

46+
#define PSI_CPU_SOME "/proc/pressure/cpu"
47+
#define PSI_CPU_FULL "/proc/pressure/cpu"
48+
#define PSI_MEMORY_SOME "/proc/pressure/memory"
49+
#define PSI_MEMORY_FULL "/proc/pressure/memory"
50+
#define PSI_IO_SOME "/proc/pressure/io"
51+
#define PSI_IO_FULL "/proc/pressure/io"
52+
#define PSI_IRQ_FULL "/proc/pressure/irq"
53+
4654
#define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
4755
#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
4856
#define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
@@ -66,6 +74,24 @@ struct config {
6674
char *container_path; /* Path to container cgroup */
6775
};
6876

77+
/* PSI statistics structure */
78+
struct psi_stats {
79+
double cpu_some_avg10, cpu_some_avg60, cpu_some_avg300;
80+
unsigned long long cpu_some_total;
81+
double cpu_full_avg10, cpu_full_avg60, cpu_full_avg300;
82+
unsigned long long cpu_full_total;
83+
double memory_some_avg10, memory_some_avg60, memory_some_avg300;
84+
unsigned long long memory_some_total;
85+
double memory_full_avg10, memory_full_avg60, memory_full_avg300;
86+
unsigned long long memory_full_total;
87+
double io_some_avg10, io_some_avg60, io_some_avg300;
88+
unsigned long long io_some_total;
89+
double io_full_avg10, io_full_avg60, io_full_avg300;
90+
unsigned long long io_full_total;
91+
double irq_full_avg10, irq_full_avg60, irq_full_avg300;
92+
unsigned long long irq_full_total;
93+
};
94+
6995
/* Task delay information structure */
7096
struct task_info {
7197
int pid;
@@ -100,6 +126,7 @@ struct container_stats {
100126

101127
/* Global variables */
102128
static struct config cfg;
129+
static struct psi_stats psi;
103130
static struct task_info tasks[MAX_TASKS];
104131
static int task_count;
105132
static int running = 1;
@@ -130,13 +157,13 @@ static void usage(void)
130157
{
131158
printf("Usage: delaytop [Options]\n"
132159
"Options:\n"
133-
" -h, --help Show this help message and exit\n"
134-
" -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"
135-
" -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n"
136-
" -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n"
137-
" -o, --once Display once and exit\n"
138-
" -p, --pid=PID Monitor only the specified PID\n"
139-
" -C, --container=PATH Monitor the container at specified cgroup path\n");
160+
" -h, --help Show this help message and exit\n"
161+
" -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"
162+
" -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n"
163+
" -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n"
164+
" -o, --once Display once and exit\n"
165+
" -p, --pid=PID Monitor only the specified PID\n"
166+
" -C, --container=PATH Monitor the container at specified cgroup path\n");
140167
exit(0);
141168
}
142169

@@ -276,7 +303,7 @@ static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
276303
memset(&nladdr, 0, sizeof(nladdr));
277304
nladdr.nl_family = AF_NETLINK;
278305
while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
279-
sizeof(nladdr))) < buflen) {
306+
sizeof(nladdr))) < buflen) {
280307
if (r > 0) {
281308
buf += r;
282309
buflen -= r;
@@ -320,6 +347,89 @@ static int get_family_id(int sd)
320347
return id;
321348
}
322349

350+
static void read_psi_stats(void)
351+
{
352+
FILE *fp;
353+
char line[256];
354+
int ret = 0;
355+
/* Zero all fields */
356+
memset(&psi, 0, sizeof(psi));
357+
/* CPU pressure */
358+
fp = fopen(PSI_CPU_SOME, "r");
359+
if (fp) {
360+
while (fgets(line, sizeof(line), fp)) {
361+
if (strncmp(line, "some", 4) == 0) {
362+
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
363+
&psi.cpu_some_avg10, &psi.cpu_some_avg60,
364+
&psi.cpu_some_avg300, &psi.cpu_some_total);
365+
if (ret != 4)
366+
fprintf(stderr, "Failed to parse CPU some PSI data\n");
367+
} else if (strncmp(line, "full", 4) == 0) {
368+
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
369+
&psi.cpu_full_avg10, &psi.cpu_full_avg60,
370+
&psi.cpu_full_avg300, &psi.cpu_full_total);
371+
if (ret != 4)
372+
fprintf(stderr, "Failed to parse CPU full PSI data\n");
373+
}
374+
}
375+
fclose(fp);
376+
}
377+
/* Memory pressure */
378+
fp = fopen(PSI_MEMORY_SOME, "r");
379+
if (fp) {
380+
while (fgets(line, sizeof(line), fp)) {
381+
if (strncmp(line, "some", 4) == 0) {
382+
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
383+
&psi.memory_some_avg10, &psi.memory_some_avg60,
384+
&psi.memory_some_avg300, &psi.memory_some_total);
385+
if (ret != 4)
386+
fprintf(stderr, "Failed to parse Memory some PSI data\n");
387+
} else if (strncmp(line, "full", 4) == 0) {
388+
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
389+
&psi.memory_full_avg10, &psi.memory_full_avg60,
390+
&psi.memory_full_avg300, &psi.memory_full_total);
391+
}
392+
if (ret != 4)
393+
fprintf(stderr, "Failed to parse Memory full PSI data\n");
394+
}
395+
fclose(fp);
396+
}
397+
/* IO pressure */
398+
fp = fopen(PSI_IO_SOME, "r");
399+
if (fp) {
400+
while (fgets(line, sizeof(line), fp)) {
401+
if (strncmp(line, "some", 4) == 0) {
402+
ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
403+
&psi.io_some_avg10, &psi.io_some_avg60,
404+
&psi.io_some_avg300, &psi.io_some_total);
405+
if (ret != 4)
406+
fprintf(stderr, "Failed to parse IO some PSI data\n");
407+
} else if (strncmp(line, "full", 4) == 0) {
408+
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
409+
&psi.io_full_avg10, &psi.io_full_avg60,
410+
&psi.io_full_avg300, &psi.io_full_total);
411+
if (ret != 4)
412+
fprintf(stderr, "Failed to parse IO full PSI data\n");
413+
}
414+
}
415+
fclose(fp);
416+
}
417+
/* IRQ pressure (only full) */
418+
fp = fopen(PSI_IRQ_FULL, "r");
419+
if (fp) {
420+
while (fgets(line, sizeof(line), fp)) {
421+
if (strncmp(line, "full", 4) == 0) {
422+
ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
423+
&psi.irq_full_avg10, &psi.irq_full_avg60,
424+
&psi.irq_full_avg300, &psi.irq_full_total);
425+
if (ret != 4)
426+
fprintf(stderr, "Failed to parse IRQ full PSI data\n");
427+
}
428+
}
429+
fclose(fp);
430+
}
431+
}
432+
323433
static int read_comm(int pid, char *comm_buf, size_t buf_size)
324434
{
325435
char path[64];
@@ -549,7 +659,29 @@ static void display_results(void)
549659
FILE *out = stdout;
550660

551661
fprintf(out, "\033[H\033[J");
552-
662+
/* PSI output (one-line, no cat style) */
663+
fprintf(out, "System Pressure Information: ");
664+
fprintf(out, "(avg10/avg60/avg300/total)\n");
665+
fprintf(out, "CPU:");
666+
fprintf(out, " full: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu", psi.cpu_full_avg10,
667+
psi.cpu_full_avg60, psi.cpu_full_avg300, psi.cpu_full_total);
668+
fprintf(out, " some: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu\n", psi.cpu_some_avg10,
669+
psi.cpu_some_avg60, psi.cpu_some_avg300, psi.cpu_some_total);
670+
671+
fprintf(out, "Memory:");
672+
fprintf(out, " full: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu", psi.memory_full_avg10,
673+
psi.memory_full_avg60, psi.memory_full_avg300, psi.memory_full_total);
674+
fprintf(out, " some: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu\n", psi.memory_some_avg10,
675+
psi.memory_some_avg60, psi.memory_some_avg300, psi.memory_some_total);
676+
677+
fprintf(out, "IO:");
678+
fprintf(out, " full: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu", psi.io_full_avg10,
679+
psi.io_full_avg60, psi.io_full_avg300, psi.io_full_total);
680+
fprintf(out, " some: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu\n", psi.io_some_avg10,
681+
psi.io_some_avg60, psi.io_some_avg300, psi.io_some_total);
682+
fprintf(out, "IRQ:");
683+
fprintf(out, " full: %6.1f%%/%6.1f%%/%6.1f%%/%-10llu\n\n", psi.irq_full_avg10,
684+
psi.irq_full_avg60, psi.irq_full_avg300, psi.irq_full_total);
553685
if (cfg.container_path) {
554686
fprintf(out, "Container Information (%s):\n", cfg.container_path);
555687
fprintf(out, "Processes: running=%d, sleeping=%d, ",
@@ -559,8 +691,8 @@ static void display_results(void)
559691
container_stats.nr_io_wait);
560692
}
561693
fprintf(out, "Top %d processes (sorted by CPU delay):\n\n",
562-
cfg.max_processes);
563-
fprintf(out, " PID TGID COMMAND CPU(ms) IO(ms) ");
694+
cfg.max_processes);
695+
fprintf(out, " PID TGID COMMAND CPU(ms) IO(ms) ");
564696
fprintf(out, "SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms)\n");
565697
fprintf(out, "-----------------------------------------------");
566698
fprintf(out, "----------------------------------------------\n");
@@ -616,6 +748,9 @@ int main(int argc, char **argv)
616748

617749
/* Main loop */
618750
while (running) {
751+
/* Read PSI statistics */
752+
read_psi_stats();
753+
619754
/* Get container stats if container path provided */
620755
if (cfg.container_path)
621756
get_container_stats();

0 commit comments

Comments
 (0)