From nobody Mon Jun 8 18:58:40 2026 Received: from mxct.zte.com.cn (mxct.zte.com.cn [183.62.165.209]) (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 A00A11427A; Wed, 27 May 2026 13:57:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=183.62.165.209 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779890238; cv=none; b=UnBy/ztO8AbPvEtY0C/JLp3CQaG4gxixTfPjsQUnjXT73LhWB0RyDlreNFyJIePBPEtOWStao6y06APVcRmA9XfqmCxrYTntSry6t2Ll6VRL+WfYciMPDOogiRhUmxode7nvGPGw2IczSrN8eaprLL6kZUpd5UQYGnygJasq/x8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779890238; c=relaxed/simple; bh=m5frYJINE1pm5HkcP1tMMQCNVTrtT++q4aqWT1Fd2ew=; h=Message-ID:In-Reply-To:References:Date:Mime-Version:From:To:Cc: Subject:Content-Type; b=mKDbMEqnlRr3saAnUldEULYb15UNPlNyms0IiKqchSy7DuwK0zH6coLgtXubGihpHdXSM5oqxS5oNJ35UQjkE/pxE+bNl1RA6Iex846DM8Prj1sH5tX0e5duKMYfDm2q7s4Whyg6IwpkMgOAyKHwZKXevOPFl0225wsxKw976YU= 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=183.62.165.209 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 mxct.zte.com.cn (FangMail) with ESMTPS id 4gQWQF3gX9z4xNtb; Wed, 27 May 2026 21:57:09 +0800 (CST) Received: from xaxapp05.zte.com.cn ([10.99.98.109]) by mse-fl2.zte.com.cn with SMTP id 64RDv7fD077420; Wed, 27 May 2026 21:57:07 +0800 (+08) (envelope-from wang.yaxin@zte.com.cn) Received: from mapi (xaxapp04[null]) by mapi (Zmail) with MAPI id mid32; Wed, 27 May 2026 21:57:08 +0800 (CST) X-Zmail-TransId: 2afb6a16f834260-ffa76 X-Mailer: Zmail v1.0 Message-ID: <20260527215708727RJd3QW4iKNdhZHGNE-ZQ2@zte.com.cn> In-Reply-To: <20260527215524044fG7XSpgveHiaFhraq0yAi@zte.com.cn> References: 20260527215524044fG7XSpgveHiaFhraq0yAi@zte.com.cn Date: Wed, 27 May 2026 21:57:08 +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-fl2.zte.com.cn 64RDv7fD077420 X-TLS: YES X-ENVELOPE-SENDER: wang.yaxin@zte.com.cn X-SOURCE-IP: 10.5.228.133 unknown Wed, 27 May 2026 21:57:09 +0800 X-CLEAN: YES X-Fangmail-Anti-Spam-Filtered: true X-Fangmail-MID-QID: 6A16F835.000/4gQWQF3gX9z4xNtb 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 | 142 +++++++++++++++++++++++++++++------- 1 file changed, 117 insertions(+), 25 deletions(-) diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c index 72cc500b44b1..586294b29834 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,6 +376,23 @@ 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"); @@ -699,20 +729,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 +832,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 *)((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,21 +1027,29 @@ 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; @@ -972,7 +1057,14 @@ static void display_results(int psi_ret) for (i =3D 0; i < count; i++) { suc &=3D BOOL_FPRINT(out, "%8d %8d %-15s", 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 18:58:40 2026 Received: from mxct.zte.com.cn (mxct.zte.com.cn [183.62.165.209]) (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 D34D2405C4B; Wed, 27 May 2026 13:58:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=183.62.165.209 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779890304; cv=none; b=bLVm28/7NJ3Pp1gYLYvHECOO5E1cnZvwye5yxL5xM+1QLOBKiA25p15OA66HYErIe4so0vmUhUog9CDSiyyFUg79bLQD1pl4E4WNzVdsI6mzZsMO6mfpNVp2Gms7D4l9R49S2ByoQ5pwMxGSI574bvOXrxNcqlh6aaZNTs3Y5es= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779890304; c=relaxed/simple; bh=iES3RcXaqZfqaLoKOHgqDIEEkFJrbLXua3dimhv5qM8=; h=Message-ID:In-Reply-To:References:Date:Mime-Version:From:To:Cc: Subject:Content-Type; b=ATxIIqKyiKSXDd+ZjnkfYO0hFhPvLtWcFUTMm7gIF/OILrAR9Sni+ReFFPOGwuY/nU47comJYPtD8J/csFvvpmGNpVIRiAwUVeMLWYOoXYkZEaEHNUb8sBHxRktlSeqHPqjP0JSD1JeLPjK6F8g8QBLey2VL+MVdEgTYwMR/isk= 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=183.62.165.209 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 mxct.zte.com.cn (FangMail) with ESMTPS id 4gQWRW3Vc9z4xNtb; Wed, 27 May 2026 21:58:15 +0800 (CST) Received: from xaxapp01.zte.com.cn ([10.88.99.176]) by mse-fl2.zte.com.cn with SMTP id 64RDwBl1078073; Wed, 27 May 2026 21:58:11 +0800 (+08) (envelope-from wang.yaxin@zte.com.cn) Received: from mapi (xaxapp02[null]) by mapi (Zmail) with MAPI id mid32; Wed, 27 May 2026 21:58:14 +0800 (CST) X-Zmail-TransId: 2afa6a16f876663-09e70 X-Mailer: Zmail v1.0 Message-ID: <20260527215814502VwuWtGwZ2XR5lVE-Bny0H@zte.com.cn> In-Reply-To: <20260527215524044fG7XSpgveHiaFhraq0yAi@zte.com.cn> References: 20260527215524044fG7XSpgveHiaFhraq0yAi@zte.com.cn Date: Wed, 27 May 2026 21:58:14 +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 64RDwBl1078073 X-TLS: YES X-ENVELOPE-SENDER: wang.yaxin@zte.com.cn X-SOURCE-IP: 10.5.228.133 unknown Wed, 27 May 2026 21:58:15 +0800 X-CLEAN: YES X-Fangmail-Anti-Spam-Filtered: true X-Fangmail-MID-QID: 6A16F877.000/4gQWRW3Vc9z4xNtb 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 | 100 ++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c index 586294b29834..8d22c43dceed 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); } @@ -730,27 +738,34 @@ 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, 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++; @@ -808,6 +823,38 @@ 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; + 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 */ + return "N/A"; + } + + time_sec =3D (time_t)ts->tv_sec; + tm_info =3D localtime(&time_sec); + if (!tm_info) + return "N/A"; + + snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d %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) { @@ -834,13 +881,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; } @@ -848,26 +896,35 @@ static void get_field_delay_values(const struct task_= info *task, const struct fi count =3D *(unsigned 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 */ } @@ -1028,11 +1085,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) { @@ -1059,11 +1117,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 18:58: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 649FA2F531F; Wed, 27 May 2026 13:59:18 +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=1779890360; cv=none; b=ICzTObK0sd2ygsR/Yubrqf8zMLtzKQgmpySCazfw54KYoyKzDSYzgBgUI6psNmGMA2+gzmMu6BGGLkxOWGuC7rJiYFL42monJD5YKaQXntmnZ069zDbe8qrFsNMZzDML0IvwiylMfhvO96gpJZ2P3NBGl0vgxJ+1TfLNNO8mUDs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779890360; c=relaxed/simple; bh=lPatLY1Gzv7CVlYfEuJxTP25o6SXMmJIk6jUjlNSdaE=; h=Message-ID:In-Reply-To:References:Date:Mime-Version:From:To:Cc: Subject:Content-Type; b=ZmaSC8t+FwIvOi0sTnwkuSWyv1EuGoVBcKTSFwH6peGWkFwMDKlep3/0RlGTVetdPZ+INp/C7SGHZdZoRP/RILcF+BEEnaNITy79CAFPKr+6mAvdo0gLp0KG2N6tuAoMrX19v0oCsDjoN/jx1FwNOHbSPffbASehLV60pdYrFU0= 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-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 4gQWSg3mt3z7Qxs2; Wed, 27 May 2026 21:59:15 +0800 (CST) Received: from xaxapp01.zte.com.cn ([10.88.99.176]) by mse-fl2.zte.com.cn with SMTP id 64RDx9c1078203; Wed, 27 May 2026 21:59:09 +0800 (+08) (envelope-from wang.yaxin@zte.com.cn) Received: from mapi (xaxapp02[null]) by mapi (Zmail) with MAPI id mid32; Wed, 27 May 2026 21:59:12 +0800 (CST) X-Zmail-TransId: 2afa6a16f8b0518-0ad24 X-Mailer: Zmail v1.0 Message-ID: <20260527215912356_JgxYvKzK5-NE2IAC69Vs@zte.com.cn> In-Reply-To: <20260527215524044fG7XSpgveHiaFhraq0yAi@zte.com.cn> References: 20260527215524044fG7XSpgveHiaFhraq0yAi@zte.com.cn Date: Wed, 27 May 2026 21:59: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-fl2.zte.com.cn 64RDx9c1078203 X-TLS: YES X-ENVELOPE-SENDER: wang.yaxin@zte.com.cn X-SOURCE-IP: 10.5.228.133 unknown Wed, 27 May 2026 21:59:15 +0800 X-CLEAN: YES X-Fangmail-Anti-Spam-Filtered: true X-Fangmail-MID-QID: 6A16F8B3.001/4gQWSg3mt3z7Qxs2 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 | 162 ++++++++++-------- 2 files changed, 136 insertions(+), 69 deletions(-) diff --git a/Documentation/accounting/delay-accounting.rst b/Documentation/= accounting/delay-accounting.rst index e209c46241b0..a42d830e65ce 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. + + +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 8d22c43dceed..87fb45a6a6cd 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); } @@ -823,111 +824,129 @@ static double average_ms(unsigned long long total, = unsigned 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 const char *format_kernel_timespec(struct __kernel_timespec *ts) { static char buffer[32]; - struct tm *tm_info; - time_t time_sec; + struct tm tm_info; + __kernel_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"; - } - time_sec =3D (time_t)ts->tv_sec; - tm_info =3D localtime(&time_sec); - if (!tm_info) + time_sec =3D ts->tv_sec; + + /* Use thread-safe localtime_r */ + if (localtime_r(&time_sec, &tm_info) =3D=3D NULL) return "N/A"; - snprintf(buffer, sizeof(buffer), "%04d-%02d-%02d %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); + 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) -{ - const struct task_info *t1 =3D (const struct task_info *)a; - const struct task_info *t2 =3D (const struct task_info *)b; - unsigned long long total1; - unsigned long long total2; - unsigned long count1; - unsigned long count2; - double avg1, avg2; - - 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); - count1 =3D *(unsigned long *)((char *)t1 + cfg.sort_field->count_offset); - count2 =3D *(unsigned long *)((char *)t2 + cfg.sort_field->count_offset); - - avg1 =3D average_ms(total1, count1); - avg2 =3D average_ms(total2, count2); - if (avg1 !=3D avg2) - return avg2 > avg1 ? 1 : -1; - - 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) */ +void field_delay_max_and_ts(const struct task_info *task, const struct fie= ld_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 *)((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 */ +void get_field_delay_values(const struct task_info *task, const struct fie= ld_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 *)((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 */ } +/* Comparison function for sorting tasks */ +static int compare_tasks(const void *a, const void *b) +{ + const struct task_info *t1 =3D (const struct task_info *)a; + const struct task_info *t2 =3D (const struct task_info *)b; + unsigned long long total1; + unsigned long long total2; + 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); + count1 =3D *(unsigned long *)((char *)t1 + cfg.sort_field->count_offset); + count2 =3D *(unsigned long *)((char *)t2 + cfg.sort_field->count_offset); + + avg1 =3D average_ms(total1, count1); + avg2 =3D average_ms(total2, count2); + if (avg1 !=3D avg2) + return avg2 > avg1 ? 1 : -1; + + return 0; +} + /* Sort tasks by selected field */ static void sort_tasks(void) { @@ -1081,8 +1100,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 */ @@ -1123,7 +1147,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