From nobody Mon Jun 8 09:49:40 2026 Received: from mxhk.zte.com.cn (mxhk.zte.com.cn [160.30.148.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5F4A72C029D; Sat, 30 May 2026 03:17:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=160.30.148.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780111051; cv=none; b=GRzAg7unk17Ojc660qerQ4zMbnxpUldvE/g/54vTQ+mRT3oFrKQ2K8l+Jl9U0ZyuKpGYcRW6caOB2KKhA0NMYcrI0TkIwzlZ2YVL/lHNOf/1+Rdo3vmvxkDY5ZZQzh6bSMRZphmYAKNVzDad1TybsAOFEUn1KrhnYLkfypbbbHI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780111051; c=relaxed/simple; bh=Px7I20e7ybS6oXZ3JPIawub8y/4j47DPSZk/FrQ8zww=; h=Message-ID:In-Reply-To:References:Date:Mime-Version:From:To:Cc: Subject:Content-Type; b=CUD4SuOIkQfo9fe/R/q+nVUyiVHD+O9DV61Nux2GZ2UDtho/fidTNlEaM7ZpwzrxOI1Yc2FA/7/sF5Hs5U8Eg49QGtgzD6agb9ZeZbhYvdbKuEN8zrzh4AF4j3UbMEmKePhHPzxwVG70fG7yYZHJuwN8M/WGKiJ/m25gfKCn4uQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zte.com.cn; spf=pass smtp.mailfrom=zte.com.cn; arc=none smtp.client-ip=160.30.148.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zte.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zte.com.cn Received: from mse-fl1.zte.com.cn (unknown [10.5.228.132]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mxhk.zte.com.cn (FangMail) with ESMTPS id 4gS54d29f6z5BNS0; Sat, 30 May 2026 11:17:21 +0800 (CST) Received: from xaxapp04.zte.com.cn ([10.99.98.157]) by mse-fl1.zte.com.cn with SMTP id 64U3HH8s016089; Sat, 30 May 2026 11:17:17 +0800 (+08) (envelope-from wang.yaxin@zte.com.cn) Received: from mapi (xaxapp02[null]) by mapi (Zmail) with MAPI id mid32; Sat, 30 May 2026 11:17:19 +0800 (CST) X-Zmail-TransId: 2afa6a1a56bfff9-ce850 X-Mailer: Zmail v1.0 Message-ID: <20260530111719122GQtS27WxouY6_gxKinVak@zte.com.cn> In-Reply-To: <20260530111602822agJB6QYfIc2NKfQBK1KYf@zte.com.cn> References: 20260530111602822agJB6QYfIc2NKfQBK1KYf@zte.com.cn Date: Sat, 30 May 2026 11:17:19 +0800 (CST) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 From: To: Cc: , , , , , , Subject: =?UTF-8?B?W1BBVENIIDEvM10gZGVsYXl0b3A6IGFkZCBkZWxheSBtYXggZm9yIGRlbGF5dG9w?= X-MAIL: mse-fl1.zte.com.cn 64U3HH8s016089 X-TLS: YES X-ENVELOPE-SENDER: wang.yaxin@zte.com.cn X-SOURCE-IP: 10.5.228.132 unknown Sat, 30 May 2026 11:17:21 +0800 X-CLEAN: YES X-Fangmail-Anti-Spam-Filtered: true X-Fangmail-MID-QID: 6A1A56C1.000/4gS54d29f6z5BNS0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Wang Yaxin Previously delaytop only showed average delays. Add delay_max fields to track the maximum delay value for each delay type (cpu, blkio, irq, swapin, freepages, thrashing, compact, wpcopy) per task. This provides a global view of all tasks' delay spikes, which is essential for identifying processes that experienced brief but significant latency events that would be hidden by average-only metrics. The -t/--type option displays only the specified delay type with avg/max values side by side, allowing focused analysis: delaytop -t cpu # Show only CPU delay with avg/max delaytop -t wpcopy # Show Copy-on-Write delay with avg/max Signed-off-by: Wang Yaxin --- tools/accounting/delaytop.c | 152 +++++++++++++++++++++++++++++------- 1 file changed, 125 insertions(+), 27 deletions(-) diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c index 72cc500b44b1..015ce8b6917f 100644 --- a/tools/accounting/delaytop.c +++ b/tools/accounting/delaytop.c @@ -82,6 +82,7 @@ #define MODE_TYPE_ALL (0xFFFFFFFF) #define MODE_DEFAULT (1 << 0) #define MODE_MEMVERBOSE (1 << 1) +#define MODE_TYPE (1 << 2) /* Display specific type with avg/max */ /* PSI statistics structure */ struct psi_stats { @@ -108,20 +109,28 @@ struct task_info { char command[TASK_COMM_LEN]; unsigned long long cpu_count; unsigned long long cpu_delay_total; + unsigned long long cpu_delay_max; unsigned long long blkio_count; unsigned long long blkio_delay_total; + unsigned long long blkio_delay_max; unsigned long long swapin_count; unsigned long long swapin_delay_total; + unsigned long long swapin_delay_max; unsigned long long freepages_count; unsigned long long freepages_delay_total; + unsigned long long freepages_delay_max; unsigned long long thrashing_count; unsigned long long thrashing_delay_total; + unsigned long long thrashing_delay_max; unsigned long long compact_count; unsigned long long compact_delay_total; + unsigned long long compact_delay_max; unsigned long long wpcopy_count; unsigned long long wpcopy_delay_total; + unsigned long long wpcopy_delay_max; unsigned long long irq_count; unsigned long long irq_delay_total; + unsigned long long irq_delay_max; unsigned long long mem_count; unsigned long long mem_delay_total; }; @@ -153,6 +162,7 @@ struct config { int monitor_pid; /* Monitor specific PID */ char *container_path; /* Path to container cgroup */ const struct field_desc *sort_field; /* Current sort field */ + const struct field_desc *type_field; /* Type field for -t option */ size_t display_mode; /* Current display mode */ }; @@ -164,15 +174,15 @@ static int task_count; static int running =3D 1; static struct container_stats container_stats; static const struct field_desc sort_fields[] =3D { - SORT_FIELD(cpu, c, MODE_DEFAULT), - SORT_FIELD(blkio, i, MODE_DEFAULT), - SORT_FIELD(irq, q, MODE_DEFAULT), + SORT_FIELD(cpu, c, MODE_DEFAULT | MODE_TYPE), + SORT_FIELD(blkio, i, MODE_DEFAULT | MODE_TYPE), + SORT_FIELD(irq, q, MODE_DEFAULT | MODE_TYPE), SORT_FIELD(mem, m, MODE_DEFAULT | MODE_MEMVERBOSE), - SORT_FIELD(swapin, s, MODE_MEMVERBOSE), - SORT_FIELD(freepages, r, MODE_MEMVERBOSE), - SORT_FIELD(thrashing, t, MODE_MEMVERBOSE), - SORT_FIELD(compact, p, MODE_MEMVERBOSE), - SORT_FIELD(wpcopy, w, MODE_MEMVERBOSE), + SORT_FIELD(swapin, s, MODE_MEMVERBOSE | MODE_TYPE), + SORT_FIELD(freepages, r, MODE_MEMVERBOSE | MODE_TYPE), + SORT_FIELD(thrashing, t, MODE_MEMVERBOSE | MODE_TYPE), + SORT_FIELD(compact, p, MODE_MEMVERBOSE | MODE_TYPE), + SORT_FIELD(wpcopy, w, MODE_MEMVERBOSE | MODE_TYPE), END_FIELD }; static int sort_selected; @@ -218,7 +228,7 @@ static const struct field_desc *get_field_by_name(const= char *name) for (field =3D sort_fields; field->name !=3D NULL; field++) { field_len =3D strlen(field->name); - if (field_len !=3D strlen(name)) + if (field_len !=3D strlen(name) || !(field->supported_modes & MODE_TYPE)) continue; if (strncmp(field->name, name, field_len) =3D=3D 0) return field; @@ -265,6 +275,7 @@ static void usage(void) " -p, --pid=3DPID Monitor only the specified PID\n" " -C, --container=3DPATH Monitor the container at specified cgroup p= ath\n" " -s, --sort=3DFIELD Sort by delay field (default: cpu)\n" + " -t, --type=3DFIELD Display only specified delay type with avg/= max\n" " -M, --memverbose Display memory detailed information\n"); exit(0); } @@ -283,6 +294,7 @@ static void parse_args(int argc, char **argv) {"processes", required_argument, 0, 'P'}, {"sort", required_argument, 0, 's'}, {"container", required_argument, 0, 'C'}, + {"type", required_argument, 0, 't'}, {"memverbose", no_argument, 0, 'M'}, {0, 0, 0, 0} }; @@ -292,6 +304,7 @@ static void parse_args(int argc, char **argv) cfg.iterations =3D 0; cfg.max_processes =3D 20; cfg.sort_field =3D &sort_fields[0]; /* Default sorted by CPU delay */ + cfg.type_field =3D NULL; /* No type field by default */ cfg.output_one_time =3D 0; cfg.monitor_pid =3D 0; /* 0 means monitor all PIDs */ cfg.container_path =3D NULL; @@ -300,7 +313,7 @@ static void parse_args(int argc, char **argv) while (1) { int option_index =3D 0; - c =3D getopt_long(argc, argv, "hd:n:p:oP:C:s:M", long_options, &option_i= ndex); + c =3D getopt_long(argc, argv, "hd:n:p:oP:C:s:t:M", long_options, &option= _index); if (c =3D=3D -1) break; @@ -363,9 +376,32 @@ static void parse_args(int argc, char **argv) cfg.sort_field =3D field; break; + case 't': + if (strlen(optarg) =3D=3D 0) { + fprintf(stderr, "Error: empty type field\n"); + exit(1); + } + + field =3D get_field_by_name(optarg); + /* Show available fields if invalid option provided */ + if (!field) { + fprintf(stderr, "Error: invalid type field '%s'\n", optarg); + display_available_fields(MODE_TYPE); + exit(1); + } + + cfg.type_field =3D field; + cfg.display_mode =3D MODE_TYPE; + break; case 'M': cfg.display_mode =3D MODE_MEMVERBOSE; - cfg.sort_field =3D get_field_by_name("mem"); + /* Find first field supporting MODE_MEMVERBOSE for sorting */ + for (field =3D sort_fields; field->name !=3D NULL; field++) { + if (field->supported_modes & MODE_MEMVERBOSE) { + cfg.sort_field =3D field; + break; + } + } break; default: fprintf(stderr, "Try 'delaytop --help' for more information.\n"); @@ -699,20 +735,28 @@ static void fetch_and_fill_task_info(int pid, const c= har *comm) tasks[task_count].command[TASK_COMM_LEN - 1] =3D '\0'; SET_TASK_STAT(task_count, cpu_count); SET_TASK_STAT(task_count, cpu_delay_total); + SET_TASK_STAT(task_count, cpu_delay_max); SET_TASK_STAT(task_count, blkio_count); SET_TASK_STAT(task_count, blkio_delay_total); + SET_TASK_STAT(task_count, blkio_delay_max); SET_TASK_STAT(task_count, swapin_count); SET_TASK_STAT(task_count, swapin_delay_total); + SET_TASK_STAT(task_count, swapin_delay_max); SET_TASK_STAT(task_count, freepages_count); SET_TASK_STAT(task_count, freepages_delay_total); + SET_TASK_STAT(task_count, freepages_delay_max); SET_TASK_STAT(task_count, thrashing_count); SET_TASK_STAT(task_count, thrashing_delay_total); + SET_TASK_STAT(task_count, thrashing_delay_max); SET_TASK_STAT(task_count, compact_count); SET_TASK_STAT(task_count, compact_delay_total); + SET_TASK_STAT(task_count, compact_delay_max); SET_TASK_STAT(task_count, wpcopy_count); SET_TASK_STAT(task_count, wpcopy_delay_total); + SET_TASK_STAT(task_count, wpcopy_delay_max); SET_TASK_STAT(task_count, irq_count); SET_TASK_STAT(task_count, irq_delay_total); + SET_TASK_STAT(task_count, irq_delay_max); set_mem_count(&tasks[task_count]); set_mem_delay_total(&tasks[task_count]); task_count++; @@ -794,6 +838,45 @@ static int compare_tasks(const void *a, const void *b) return 0; } +/* Get delay values for a specific field */ +static void get_field_delay_values(const struct task_info *task, const str= uct field_desc *field, + double *avg_ms, double *max_ms) +{ + unsigned long long total, count, max; + + if (!field) { + *avg_ms =3D 0; + *max_ms =3D 0; + return; + } + + total =3D *(unsigned long long *)((char *)task + field->total_offset); + count =3D *(unsigned long long *)((char *)task + field->count_offset); + *avg_ms =3D average_ms(total, count); + + /* Get max delay based on field name */ + if (strcmp(field->name, "cpu") =3D=3D 0) + max =3D task->cpu_delay_max; + else if (strcmp(field->name, "blkio") =3D=3D 0) + max =3D task->blkio_delay_max; + else if (strcmp(field->name, "irq") =3D=3D 0) + max =3D task->irq_delay_max; + else if (strcmp(field->name, "swapin") =3D=3D 0) + max =3D task->swapin_delay_max; + else if (strcmp(field->name, "freepages") =3D=3D 0) + max =3D task->freepages_delay_max; + else if (strcmp(field->name, "thrashing") =3D=3D 0) + max =3D task->thrashing_delay_max; + else if (strcmp(field->name, "compact") =3D=3D 0) + max =3D task->compact_delay_max; + else if (strcmp(field->name, "wpcopy") =3D=3D 0) + max =3D task->wpcopy_delay_max; + else + max =3D 0; + + *max_ms =3D (double)max / 1000000.0; /* Convert nanoseconds to milliseco= nds */ +} + /* Sort tasks by selected field */ static void sort_tasks(void) { @@ -950,29 +1033,44 @@ static void display_results(int psi_ret) suc &=3D BOOL_FPRINT(out, "Top %d processes (sorted by %s delay):\n", cfg.max_processes, get_name_by_field(cfg.sort_field)); - suc &=3D BOOL_FPRINT(out, "%8s %8s %-17s", "PID", "TGID", "COMMAND"); - if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { - suc &=3D BOOL_FPRINT(out, "%8s %8s %8s %8s %8s %8s\n", - "MEM(ms)", "SWAP(ms)", "RCL(ms)", - "THR(ms)", "CMP(ms)", "WP(ms)"); - suc &=3D BOOL_FPRINT(out, "-----------------------"); - suc &=3D BOOL_FPRINT(out, "-----------------------"); - suc &=3D BOOL_FPRINT(out, "-----------------------"); - suc &=3D BOOL_FPRINT(out, "---------------------\n"); + if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) { + /* Display mode for -t option: show only specified type with avg/max */ + suc &=3D BOOL_FPRINT(out, "%8s %8s %-17s %12s %12s\n", + "PID", "TGID", "COMMAND", + "AVG(ms)", "MAX(ms)"); + suc &=3D BOOL_FPRINT(out, "---------------------------------------------= -------\n"); } else { - suc &=3D BOOL_FPRINT(out, "%8s %8s %8s %8s\n", - "CPU(ms)", "IO(ms)", "IRQ(ms)", "MEM(ms)"); - suc &=3D BOOL_FPRINT(out, "-----------------------"); - suc &=3D BOOL_FPRINT(out, "-----------------------"); - suc &=3D BOOL_FPRINT(out, "--------------------------\n"); + suc &=3D BOOL_FPRINT(out, "%8s %8s %-17s", "PID", "TGID", "COMMAND"); + if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { + suc &=3D BOOL_FPRINT(out, "%8s %8s %8s %8s %8s %8s\n", + "MEM(ms)", "SWAP(ms)", "RCL(ms)", + "THR(ms)", "CMP(ms)", "WP(ms)"); + suc &=3D BOOL_FPRINT(out, "-----------------------"); + suc &=3D BOOL_FPRINT(out, "-----------------------"); + suc &=3D BOOL_FPRINT(out, "-----------------------"); + suc &=3D BOOL_FPRINT(out, "---------------------\n"); + } else { + suc &=3D BOOL_FPRINT(out, "%8s %8s %8s %8s\n", + "CPU(ms)", "IO(ms)", "IRQ(ms)", "MEM(ms)"); + suc &=3D BOOL_FPRINT(out, "-----------------------"); + suc &=3D BOOL_FPRINT(out, "-----------------------"); + suc &=3D BOOL_FPRINT(out, "--------------------------\n"); + } } count =3D task_count < cfg.max_processes ? task_count : cfg.max_processes; for (i =3D 0; i < count; i++) { - suc &=3D BOOL_FPRINT(out, "%8d %8d %-15s", + suc &=3D BOOL_FPRINT(out, "%8d %8d %-17s", tasks[i].pid, tasks[i].tgid, tasks[i].command); - if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { + if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) { + double avg_ms, max_ms; + + get_field_delay_values(&tasks[i], cfg.type_field, &avg_ms, &max_ms); + + suc &=3D BOOL_FPRINT(out, "%12.2f %12.2f\n", + avg_ms, max_ms); + } else if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { suc &=3D BOOL_FPRINT(out, DELAY_FMT_MEMVERBOSE, TASK_AVG(tasks[i], mem), TASK_AVG(tasks[i], swapin), --=20 2.25.1 From nobody Mon Jun 8 09:49:40 2026 Received: from mxhk.zte.com.cn (mxhk.zte.com.cn [160.30.148.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CD51D346781; Sat, 30 May 2026 03:18:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=160.30.148.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780111136; cv=none; b=T7TwMurbuJqjCbmg6x9TzjQaZuzrOUBqD1zbsoqL3XqRPqFVHEqYpYWrkzQ0UQfTGMQM4VlpK+QHA1dvnDi5zFhdj9FotpkSqKPamnLz5bnRlFY+ulOsyW0JZmPbIQ7ge42juY+PmyfPF9dQty37bTk5T/veiCOn1BSkFJbH0iw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780111136; c=relaxed/simple; bh=PspIrvsZpOeHkzFm0275krNb8z9VGI6yiEFJayV9/g4=; h=Message-ID:In-Reply-To:References:Date:Mime-Version:From:To:Cc: Subject:Content-Type; b=hs5LHSNckfstT8Jutr/4Dxf7FoIfqnlsDLuP8qpZvfcVArUymJznDRIIPRG/txZrWIaQugvzxZzGwCBMRcLJ+5AyzviDzqE6U3mfMhTW2xLAlmhJw9uoujfEyy0AACHI4Tn5J7Ts6i/stdtRwHJW93ro4EPUGhIQcEQZjJEJiQY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zte.com.cn; spf=pass smtp.mailfrom=zte.com.cn; arc=none smtp.client-ip=160.30.148.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zte.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zte.com.cn Received: from mse-fl2.zte.com.cn (unknown [10.5.228.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mxhk.zte.com.cn (FangMail) with ESMTPS id 4gS56N3HN7z5BNRf; Sat, 30 May 2026 11:18:52 +0800 (CST) Received: from xaxapp04.zte.com.cn ([10.99.98.157]) by mse-fl2.zte.com.cn with SMTP id 64U3IkqX023548; Sat, 30 May 2026 11:18:46 +0800 (+08) (envelope-from wang.yaxin@zte.com.cn) Received: from mapi (xaxapp04[null]) by mapi (Zmail) with MAPI id mid32; Sat, 30 May 2026 11:18:47 +0800 (CST) X-Zmail-TransId: 2afb6a1a5717f59-c27bc X-Mailer: Zmail v1.0 Message-ID: <20260530111847447SJXUmJ19sbOa-PdvNMVZI@zte.com.cn> In-Reply-To: <20260530111602822agJB6QYfIc2NKfQBK1KYf@zte.com.cn> References: 20260530111602822agJB6QYfIc2NKfQBK1KYf@zte.com.cn Date: Sat, 30 May 2026 11:18:47 +0800 (CST) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 From: To: Cc: , , , , , , Subject: =?UTF-8?B?W1BBVENIIDIvM10gZGVsYXl0b3A6IGFkZCB0aW1lc3RhbXAgb2YgZGVsYXkgbWF4?= X-MAIL: mse-fl2.zte.com.cn 64U3IkqX023548 X-TLS: YES X-ENVELOPE-SENDER: wang.yaxin@zte.com.cn X-SOURCE-IP: 10.5.228.133 unknown Sat, 30 May 2026 11:18:52 +0800 X-CLEAN: YES X-Fangmail-Anti-Spam-Filtered: true X-Fangmail-MID-QID: 6A1A571C.001/4gS56N3HN7z5BNRf Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Wang Yaxin Record the wall-clock timestamp when each maximum delay occurred for all delay types. The timestamp is displayed in the MAX_TIMESTAMP column when using -t/--type option. This enables: - Identifying the time when a process experienced an abnormal delay spike - Correlating delay peaks across multiple processes at the same timestamp - Cross-referencing with system logs, traces, or other metrics at that time - Pinpointing the root cause of latency issues by finding concurrent events Signed-off-by: Wang Yaxin --- tools/accounting/delaytop.c | 103 +++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 20 deletions(-) diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c index 015ce8b6917f..2be975cbc093 100644 --- a/tools/accounting/delaytop.c +++ b/tools/accounting/delaytop.c @@ -110,27 +110,35 @@ struct task_info { unsigned long long cpu_count; unsigned long long cpu_delay_total; unsigned long long cpu_delay_max; + struct __kernel_timespec cpu_delay_max_ts; unsigned long long blkio_count; unsigned long long blkio_delay_total; unsigned long long blkio_delay_max; + struct __kernel_timespec blkio_delay_max_ts; unsigned long long swapin_count; unsigned long long swapin_delay_total; unsigned long long swapin_delay_max; + struct __kernel_timespec swapin_delay_max_ts; unsigned long long freepages_count; unsigned long long freepages_delay_total; unsigned long long freepages_delay_max; + struct __kernel_timespec freepages_delay_max_ts; unsigned long long thrashing_count; unsigned long long thrashing_delay_total; unsigned long long thrashing_delay_max; + struct __kernel_timespec thrashing_delay_max_ts; unsigned long long compact_count; unsigned long long compact_delay_total; unsigned long long compact_delay_max; + struct __kernel_timespec compact_delay_max_ts; unsigned long long wpcopy_count; unsigned long long wpcopy_delay_total; unsigned long long wpcopy_delay_max; + struct __kernel_timespec wpcopy_delay_max_ts; unsigned long long irq_count; unsigned long long irq_delay_total; unsigned long long irq_delay_max; + struct __kernel_timespec irq_delay_max_ts; unsigned long long mem_count; unsigned long long mem_delay_total; }; @@ -275,7 +283,7 @@ static void usage(void) " -p, --pid=3DPID Monitor only the specified PID\n" " -C, --container=3DPATH Monitor the container at specified cgroup p= ath\n" " -s, --sort=3DFIELD Sort by delay field (default: cpu)\n" - " -t, --type=3DFIELD Display only specified delay type with avg/= max\n" + " -t, --type=3DFIELD Display only specified delay type with avg/= max/timestamp\n" " -M, --memverbose Display memory detailed information\n"); exit(0); } @@ -736,27 +744,35 @@ static void fetch_and_fill_task_info(int pid, const c= har *comm) SET_TASK_STAT(task_count, cpu_count); SET_TASK_STAT(task_count, cpu_delay_total); SET_TASK_STAT(task_count, cpu_delay_max); + SET_TASK_STAT(task_count, cpu_delay_max_ts); SET_TASK_STAT(task_count, blkio_count); SET_TASK_STAT(task_count, blkio_delay_total); SET_TASK_STAT(task_count, blkio_delay_max); + SET_TASK_STAT(task_count, blkio_delay_max_ts); SET_TASK_STAT(task_count, swapin_count); SET_TASK_STAT(task_count, swapin_delay_total); SET_TASK_STAT(task_count, swapin_delay_max); + SET_TASK_STAT(task_count, swapin_delay_max_ts); SET_TASK_STAT(task_count, freepages_count); SET_TASK_STAT(task_count, freepages_delay_total); SET_TASK_STAT(task_count, freepages_delay_max); + SET_TASK_STAT(task_count, freepages_delay_max_ts); SET_TASK_STAT(task_count, thrashing_count); SET_TASK_STAT(task_count, thrashing_delay_total); SET_TASK_STAT(task_count, thrashing_delay_max); + SET_TASK_STAT(task_count, thrashing_delay_max_ts); SET_TASK_STAT(task_count, compact_count); SET_TASK_STAT(task_count, compact_delay_total); SET_TASK_STAT(task_count, compact_delay_max); + SET_TASK_STAT(task_count, compact_delay_max_ts); SET_TASK_STAT(task_count, wpcopy_count); SET_TASK_STAT(task_count, wpcopy_delay_total); SET_TASK_STAT(task_count, wpcopy_delay_max); + SET_TASK_STAT(task_count, wpcopy_delay_max_ts); SET_TASK_STAT(task_count, irq_count); SET_TASK_STAT(task_count, irq_delay_total); SET_TASK_STAT(task_count, irq_delay_max); + SET_TASK_STAT(task_count, irq_delay_max_ts); set_mem_count(&tasks[task_count]); set_mem_delay_total(&tasks[task_count]); task_count++; @@ -814,6 +830,40 @@ static double average_ms(unsigned long long total, uns= igned long long count) return (double)total / 1000000.0 / count; } +/* + * Format __kernel_timespec to human readable string (YYYY-MM-DD HH:MM:SS) + * Returns formatted string or "N/A" if timestamp is zero + */ +static const char *format_timespec64(struct __kernel_timespec *ts) +{ + static char buffer[32]; + struct tm *tm_info; + + /* Check if timestamp is zero (not set) or invalid (before year 2000) */ + if ((ts->tv_sec =3D=3D 0 && ts->tv_nsec =3D=3D 0) || ts->tv_sec < 9466848= 00) { + /* 946684800 is timestamp for 2000-01-01 00:00:00 UTC */ + return "N/A"; + } + + /* Check if timestamp is too large for time_t on 32-bit platforms */ + if (sizeof(time_t) < sizeof(ts->tv_sec) && ts->tv_sec > (time_t)-1) + return "N/A"; + + tm_info =3D gmtime((const time_t *)&ts->tv_sec); + if (!tm_info) + return "N/A"; + + snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d", + tm_info->tm_year + 1900, + tm_info->tm_mon + 1, + tm_info->tm_mday, + tm_info->tm_hour, + tm_info->tm_min, + tm_info->tm_sec); + + return buffer; +} + /* Comparison function for sorting tasks */ static int compare_tasks(const void *a, const void *b) { @@ -840,13 +890,14 @@ static int compare_tasks(const void *a, const void *b) /* Get delay values for a specific field */ static void get_field_delay_values(const struct task_info *task, const str= uct field_desc *field, - double *avg_ms, double *max_ms) + double *avg_ms, double *max_ms, struct __kernel_timespec *max_ts) { unsigned long long total, count, max; if (!field) { *avg_ms =3D 0; *max_ms =3D 0; + memset(max_ts, 0, sizeof(*max_ts)); return; } @@ -854,26 +905,35 @@ static void get_field_delay_values(const struct task_= info *task, const struct fi count =3D *(unsigned long long *)((char *)task + field->count_offset); *avg_ms =3D average_ms(total, count); - /* Get max delay based on field name */ - if (strcmp(field->name, "cpu") =3D=3D 0) + /* Get max delay and timestamp based on field name */ + if (strcmp(field->name, "cpu") =3D=3D 0) { max =3D task->cpu_delay_max; - else if (strcmp(field->name, "blkio") =3D=3D 0) + *max_ts =3D task->cpu_delay_max_ts; + } else if (strcmp(field->name, "blkio") =3D=3D 0) { max =3D task->blkio_delay_max; - else if (strcmp(field->name, "irq") =3D=3D 0) + *max_ts =3D task->blkio_delay_max_ts; + } else if (strcmp(field->name, "irq") =3D=3D 0) { max =3D task->irq_delay_max; - else if (strcmp(field->name, "swapin") =3D=3D 0) + *max_ts =3D task->irq_delay_max_ts; + } else if (strcmp(field->name, "swapin") =3D=3D 0) { max =3D task->swapin_delay_max; - else if (strcmp(field->name, "freepages") =3D=3D 0) + *max_ts =3D task->swapin_delay_max_ts; + } else if (strcmp(field->name, "freepages") =3D=3D 0) { max =3D task->freepages_delay_max; - else if (strcmp(field->name, "thrashing") =3D=3D 0) + *max_ts =3D task->freepages_delay_max_ts; + } else if (strcmp(field->name, "thrashing") =3D=3D 0) { max =3D task->thrashing_delay_max; - else if (strcmp(field->name, "compact") =3D=3D 0) + *max_ts =3D task->thrashing_delay_max_ts; + } else if (strcmp(field->name, "compact") =3D=3D 0) { max =3D task->compact_delay_max; - else if (strcmp(field->name, "wpcopy") =3D=3D 0) + *max_ts =3D task->compact_delay_max_ts; + } else if (strcmp(field->name, "wpcopy") =3D=3D 0) { max =3D task->wpcopy_delay_max; - else + *max_ts =3D task->wpcopy_delay_max_ts; + } else { max =3D 0; - + memset(max_ts, 0, sizeof(*max_ts)); + } *max_ms =3D (double)max / 1000000.0; /* Convert nanoseconds to milliseco= nds */ } @@ -1034,11 +1094,12 @@ static void display_results(int psi_ret) cfg.max_processes, get_name_by_field(cfg.sort_field)); if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) { - /* Display mode for -t option: show only specified type with avg/max */ - suc &=3D BOOL_FPRINT(out, "%8s %8s %-17s %12s %12s\n", + /* Display mode for -t option: show only specified type with avg/max/tim= estamp */ + suc &=3D BOOL_FPRINT(out, "%8s %8s %-17s %12s %12s %20s\n", "PID", "TGID", "COMMAND", - "AVG(ms)", "MAX(ms)"); - suc &=3D BOOL_FPRINT(out, "---------------------------------------------= -------\n"); + "AVG(ms)", "MAX(ms)", "MAX_TIMESTAMP"); + suc &=3D BOOL_FPRINT(out, "---------------------------------------------= -----------"); + suc &=3D BOOL_FPRINT(out, "----------------------------------------\n"); } else { suc &=3D BOOL_FPRINT(out, "%8s %8s %-17s", "PID", "TGID", "COMMAND"); if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { @@ -1065,11 +1126,13 @@ static void display_results(int psi_ret) tasks[i].pid, tasks[i].tgid, tasks[i].command); if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) { double avg_ms, max_ms; + struct __kernel_timespec max_ts; - get_field_delay_values(&tasks[i], cfg.type_field, &avg_ms, &max_ms); + get_field_delay_values(&tasks[i], cfg.type_field, &avg_ms, + &max_ms, &max_ts); - suc &=3D BOOL_FPRINT(out, "%12.2f %12.2f\n", - avg_ms, max_ms); + suc &=3D BOOL_FPRINT(out, "%12.2f %12.2f %20s\n", + avg_ms, max_ms, format_timespec64(&max_ts)); } else if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { suc &=3D BOOL_FPRINT(out, DELAY_FMT_MEMVERBOSE, TASK_AVG(tasks[i], mem), --=20 2.25.1 From nobody Mon Jun 8 09:49:40 2026 Received: from mxhk.zte.com.cn (mxhk.zte.com.cn [160.30.148.35]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A529134750D; Sat, 30 May 2026 03:20:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=160.30.148.35 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780111223; cv=none; b=YtwNpnaGPgEvOwdmMUCHz92U6Wy1mcotm0bIX1eqSFAj8RYNr0C5ImRPX3p8T7WK2C1vlFMdQZe8VFwYT0Yz/m3s3p+CkB81aYWONPnvIxg15wnuxoaz28vgoAYsCHAsqSHVgjW2Cy6jAnW7sJR+e5CEA/1N8es4/1MxKMxKRoQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780111223; c=relaxed/simple; bh=Qtp0Ru6vdftY43Q+QVd5MxyrsXV+f5ga2GjZUj+vH/8=; h=Message-ID:In-Reply-To:References:Date:Mime-Version:From:To:Cc: Subject:Content-Type; b=N8bamamrlAZzYldWne1HYw+6L7dZWnGtNXbjX9OOsMhhPvfUUIs9A1eb2mklbW9g6s+qGXocLFTrrO1RZyoKYk84HhpSC1A7r4dukAOUTNhfpAsaAaIjKoZIAHVUkRZ4tOjRPMEdlgYaBlqJszXtDLOei6eZ4QWnM+PsN8FrtyM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zte.com.cn; spf=pass smtp.mailfrom=zte.com.cn; arc=none smtp.client-ip=160.30.148.35 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zte.com.cn Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zte.com.cn Received: from mse-fl1.zte.com.cn (unknown [10.5.228.132]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mxhk.zte.com.cn (FangMail) with ESMTPS id 4gS57y3s2lz8Xrr9; Sat, 30 May 2026 11:20:14 +0800 (CST) Received: from xaxapp01.zte.com.cn ([10.88.99.176]) by mse-fl1.zte.com.cn with SMTP id 64U3KBBj018049; Sat, 30 May 2026 11:20:11 +0800 (+08) (envelope-from wang.yaxin@zte.com.cn) Received: from mapi (xaxapp05[null]) by mapi (Zmail) with MAPI id mid32; Sat, 30 May 2026 11:20:12 +0800 (CST) X-Zmail-TransId: 2afc6a1a576c1a4-c1a07 X-Mailer: Zmail v1.0 Message-ID: <20260530112012440zFFqDEufVtZezQGx8xi2I@zte.com.cn> In-Reply-To: <20260530111602822agJB6QYfIc2NKfQBK1KYf@zte.com.cn> References: 20260530111602822agJB6QYfIc2NKfQBK1KYf@zte.com.cn Date: Sat, 30 May 2026 11:20:12 +0800 (CST) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 From: To: Cc: , , , , , , Subject: =?UTF-8?B?W1BBVENIIDMvM10gZGVsYXl0b3A6IHNvcnQgYnkgbWF4IGRlbGF5IHRvIGhpZ2hsaWdodCB0b3AgbGF0ZW5jeSBwcm9jZXNzZXM=?= X-MAIL: mse-fl1.zte.com.cn 64U3KBBj018049 X-TLS: YES X-ENVELOPE-SENDER: wang.yaxin@zte.com.cn X-SOURCE-IP: 10.5.228.132 unknown Sat, 30 May 2026 11:20:14 +0800 X-CLEAN: YES X-Fangmail-Anti-Spam-Filtered: true X-Fangmail-MID-QID: 6A1A576E.000/4gS57y3s2lz8Xrr9 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Wang Yaxin When using -t/--type option, sort tasks by the maximum delay value of the selected type in descending order (largest delay first). This enables quickly identifying the top N processes with the highest delay spikes, which is essential for diagnosing latency problems by pinpointing which processes contributed most to system delays. Signed-off-by: Wang Yaxin --- Documentation/accounting/delay-accounting.rst | 43 ++++++ tools/accounting/delaytop.c | 124 ++++++++++++------ 2 files changed, 126 insertions(+), 41 deletions(-) diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/= accounting/delay-accounting.rst index e209c46241b0..b7df13ac0436 100644 --- a/Documentation/accounting/delay-accounting.rst +++ b/Documentation/accounting/delay-accounting.rst @@ -212,3 +212,46 @@ Advanced usage examples:: # ./delaytop -d secs Specify refresh interval as secs + + # ./delaytop -t type + Display only specified delay type with avg/max/timestamp + (rows sorted by MAX for that type, largest first) + + + +delaytop add delay_max fields to track the maximum delay value for each de= lay type +(cpu, blkio, irq, swapin, freepages, thrashing, compact, wpcopy) per task. + + bash# ./delaytop -t cpu + System Pressure Information: (avg10/avg60vg300/total) + CPU some: 0.4%/ 0.2%/ 0.1%/ 220(ms) + CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms) + Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms) + Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms) + IO full: 0.0%/ 0.0%/ 0.0%/ 12(ms) + IO some: 0.0%/ 0.0%/ 0.0%/ 13(ms) + IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms) + [o]sort [M]memverbose [q]quit + Top 20 processes (sorted by cpu MAX delay, largest first): + PID TGID COMMAND AVG(ms) MAX(ms) MAX_TIMESTAMP + ------------------------------------------------------------------------ + 9 9 kworker/0:0-eve 0.59 16.87 2026-05-27T13:32:39 + 30 30 kworker/2:0H-kb 2.87 11.36 2026-05-27T13:32:36 + 27 27 migration/2 1.05 9.51 2026-05-27T13:32:37 + 50 50 kworker/2:1-eve 0.50 9.13 2026-05-27T13:32:37 + 15 15 rcu_preempt 0.11 8.98 2026-05-27T13:32:37 + 1 1 init 0.17 7.12 2026-05-27T13:32:38 + 67 67 scsi_eh_0 1.20 4.23 2026-05-27T13:32:37 + 23 23 ksoftirqd/1 1.12 3.77 2026-05-27T13:32:36 + 3 3 pool_workqueue_ 0.72 3.55 2026-05-27T13:32:38 + 62 62 kworker/u20:2-a 0.49 3.03 2026-05-27T13:32:37 + 2 2 kthreadd 0.18 2.82 2026-05-27T13:32:37 + 11 11 kworker/0:1 1.42 2.76 2026-05-27T13:32:36 + 39 39 kworker/u20:0-a 0.10 2.71 2026-05-27T13:32:38 + 17 17 rcu_exp_gp_kthr 0.25 2.65 2026-05-27T13:32:37 + 66 66 kworker/u20:3-e 0.38 2.55 2026-05-27T13:32:37 + 20 20 cpuhp/0 0.53 2.51 2026-05-27T13:32:37 + 28 28 ksoftirqd/2 0.59 2.48 2026-05-27T13:32:37 + 55 55 kworker/u19:1 0.88 2.42 2026-05-27T13:32:37 + 13 13 kworker/R-mm_pe 1.18 2.35 2026-05-27T13:32:36 + 54 54 kworker/3:1-eve 0.14 2.20 2026-05-27T13:32:38 diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c index 2be975cbc093..9d7102fab09d 100644 --- a/tools/accounting/delaytop.c +++ b/tools/accounting/delaytop.c @@ -284,6 +284,7 @@ static void usage(void) " -C, --container=3DPATH Monitor the container at specified cgroup p= ath\n" " -s, --sort=3DFIELD Sort by delay field (default: cpu)\n" " -t, --type=3DFIELD Display only specified delay type with avg/= max/timestamp\n" + " (rows sorted by MAX for that type, largest fi= rst)\n" " -M, --memverbose Display memory detailed information\n"); exit(0); } @@ -822,6 +823,15 @@ static void get_task_delays(void) closedir(dir); } +static void field_delay_max_and_ts(const struct task_info *task, + const struct field_desc *field, + unsigned long long *max_ns, + struct __kernel_timespec *max_ts); +static void get_field_delay_values(const struct task_info *task, + const struct field_desc *field, + double *avg_ms, double *max_ms, + struct __kernel_timespec *max_ts); + /* Calculate average delay in milliseconds */ static double average_ms(unsigned long long total, unsigned long long coun= t) { @@ -831,35 +841,39 @@ static double average_ms(unsigned long long total, un= signed long long count) } /* - * Format __kernel_timespec to human readable string (YYYY-MM-DD HH:MM:SS) + * Format __kernel_timespec to human readable string (YYYY-MM-DDTHH:MM:SS) * Returns formatted string or "N/A" if timestamp is zero */ -static const char *format_timespec64(struct __kernel_timespec *ts) +static const char *format_kernel_timespec(struct __kernel_timespec *ts) { static char buffer[32]; - struct tm *tm_info; + struct tm tm_info; + time_t time_sec; - /* Check if timestamp is zero (not set) or invalid (before year 2000) */ - if ((ts->tv_sec =3D=3D 0 && ts->tv_nsec =3D=3D 0) || ts->tv_sec < 9466848= 00) { - /* 946684800 is timestamp for 2000-01-01 00:00:00 UTC */ + /* Check if timestamp is zero (not set) */ + if (ts->tv_sec =3D=3D 0 && ts->tv_nsec =3D=3D 0) return "N/A"; + + /* Avoid Y2038 truncation: check if timestamp fits in time_t on 32-bit pl= atforms */ + if (sizeof(time_sec) < sizeof(ts->tv_sec)) { + /* On 32-bit platforms, time_t may be 32-bit; check for overflow */ + if (ts->tv_sec > (unsigned long long)(time_t)(-1)) + return "N/A"; } - /* Check if timestamp is too large for time_t on 32-bit platforms */ - if (sizeof(time_t) < sizeof(ts->tv_sec) && ts->tv_sec > (time_t)-1) - return "N/A"; + time_sec =3D (time_t)ts->tv_sec; - tm_info =3D gmtime((const time_t *)&ts->tv_sec); - if (!tm_info) + /* Use thread-safe localtime_r */ + if (localtime_r(&time_sec, &tm_info) =3D=3D NULL) return "N/A"; snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d", - tm_info->tm_year + 1900, - tm_info->tm_mon + 1, - tm_info->tm_mday, - tm_info->tm_hour, - tm_info->tm_min, - tm_info->tm_sec); + tm_info.tm_year + 1900, + tm_info.tm_mon + 1, + tm_info.tm_mday, + tm_info.tm_hour, + tm_info.tm_min, + tm_info.tm_sec); return buffer; } @@ -874,6 +888,17 @@ static int compare_tasks(const void *a, const void *b) unsigned long count1; unsigned long count2; double avg1, avg2; + unsigned long long max1, max2; + struct __kernel_timespec ts_scratch; + + /* -t/--type: default sort by MAX column for the selected type (descendin= g) */ + if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) { + field_delay_max_and_ts(t1, cfg.type_field, &max1, &ts_scratch); + field_delay_max_and_ts(t2, cfg.type_field, &max2, &ts_scratch); + if (max1 !=3D max2) + return max2 > max1 ? 1 : -1; + return 0; + } total1 =3D *(unsigned long long *)((char *)t1 + cfg.sort_field->total_off= set); total2 =3D *(unsigned long long *)((char *)t2 + cfg.sort_field->total_off= set); @@ -888,52 +913,64 @@ static int compare_tasks(const void *a, const void *b) return 0; } -/* Get delay values for a specific field */ -static void get_field_delay_values(const struct task_info *task, const str= uct field_desc *field, - double *avg_ms, double *max_ms, struct __kernel_timespec *max_ts) +/* Max delay (ns) and timestamp for field (shared by display and sort) */ +static void field_delay_max_and_ts(const struct task_info *task, const str= uct field_desc *field, + unsigned long long *max_ns, struct __kernel_timespec *max_ts) { - unsigned long long total, count, max; - if (!field) { - *avg_ms =3D 0; - *max_ms =3D 0; + *max_ns =3D 0; memset(max_ts, 0, sizeof(*max_ts)); return; } - total =3D *(unsigned long long *)((char *)task + field->total_offset); - count =3D *(unsigned long long *)((char *)task + field->count_offset); - *avg_ms =3D average_ms(total, count); - - /* Get max delay and timestamp based on field name */ if (strcmp(field->name, "cpu") =3D=3D 0) { - max =3D task->cpu_delay_max; + *max_ns =3D task->cpu_delay_max; *max_ts =3D task->cpu_delay_max_ts; } else if (strcmp(field->name, "blkio") =3D=3D 0) { - max =3D task->blkio_delay_max; + *max_ns =3D task->blkio_delay_max; *max_ts =3D task->blkio_delay_max_ts; } else if (strcmp(field->name, "irq") =3D=3D 0) { - max =3D task->irq_delay_max; + *max_ns =3D task->irq_delay_max; *max_ts =3D task->irq_delay_max_ts; } else if (strcmp(field->name, "swapin") =3D=3D 0) { - max =3D task->swapin_delay_max; + *max_ns =3D task->swapin_delay_max; *max_ts =3D task->swapin_delay_max_ts; } else if (strcmp(field->name, "freepages") =3D=3D 0) { - max =3D task->freepages_delay_max; + *max_ns =3D task->freepages_delay_max; *max_ts =3D task->freepages_delay_max_ts; } else if (strcmp(field->name, "thrashing") =3D=3D 0) { - max =3D task->thrashing_delay_max; + *max_ns =3D task->thrashing_delay_max; *max_ts =3D task->thrashing_delay_max_ts; } else if (strcmp(field->name, "compact") =3D=3D 0) { - max =3D task->compact_delay_max; + *max_ns =3D task->compact_delay_max; *max_ts =3D task->compact_delay_max_ts; } else if (strcmp(field->name, "wpcopy") =3D=3D 0) { - max =3D task->wpcopy_delay_max; + *max_ns =3D task->wpcopy_delay_max; *max_ts =3D task->wpcopy_delay_max_ts; } else { - max =3D 0; + *max_ns =3D 0; memset(max_ts, 0, sizeof(*max_ts)); } +} + +/* Get delay values for a specific field */ +static void get_field_delay_values(const struct task_info *task, const str= uct field_desc *field, + double *avg_ms, double *max_ms, struct __kernel_timespec *max_ts) +{ + unsigned long long total, count, max; + + if (!field) { + *avg_ms =3D 0; + *max_ms =3D 0; + memset(max_ts, 0, sizeof(*max_ts)); + return; + } + + total =3D *(unsigned long long *)((char *)task + field->total_offset); + count =3D *(unsigned long long *)((char *)task + field->count_offset); + *avg_ms =3D average_ms(total, count); + + field_delay_max_and_ts(task, field, &max, max_ts); *max_ms =3D (double)max / 1000000.0; /* Convert nanoseconds to milliseco= nds */ } @@ -1090,8 +1127,13 @@ static void display_results(int psi_ret) } /* Task delay output */ - suc &=3D BOOL_FPRINT(out, "Top %d processes (sorted by %s delay):\n", - cfg.max_processes, get_name_by_field(cfg.sort_field)); + if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) + suc &=3D BOOL_FPRINT(out, + "Top %d processes (sorted by %s MAX delay, largest first):\n", + cfg.max_processes, get_name_by_field(cfg.type_field)); + else + suc &=3D BOOL_FPRINT(out, "Top %d processes (sorted by %s delay):\n", + cfg.max_processes, get_name_by_field(cfg.sort_field)); if (cfg.display_mode =3D=3D MODE_TYPE && cfg.type_field) { /* Display mode for -t option: show only specified type with avg/max/tim= estamp */ @@ -1132,7 +1174,7 @@ static void display_results(int psi_ret) &max_ms, &max_ts); suc &=3D BOOL_FPRINT(out, "%12.2f %12.2f %20s\n", - avg_ms, max_ms, format_timespec64(&max_ts)); + avg_ms, max_ms, format_kernel_timespec(&max_ts)); } else if (cfg.display_mode =3D=3D MODE_MEMVERBOSE) { suc &=3D BOOL_FPRINT(out, DELAY_FMT_MEMVERBOSE, TASK_AVG(tasks[i], mem), --=20 2.25.1