lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <202509021141468809-_7Kz9HvqZ60kTehEJiJ@zte.com.cn>
Date: Tue, 2 Sep 2025 11:41:46 +0800 (CST)
From: <xu.xin16@....com.cn>
To: <fan.yu9@....com.cn>, <akpm@...ux-foundation.org>
Cc: <wang.yaxin@....com.cn>, <corbet@....net>, <linux-kernel@...r.kernel.org>,
        <linux-doc@...r.kernel.org>, <yang.yang29@....com.cn>,
        <fan.yu9@....com.cn>
Subject: Re: [PATCH linux-next 2/3] tools/delaytop: add flexible sorting by delay field

> From: Fan Yu <fan.yu9@....com.cn>
> 
> The delaytop tool only supported sorting by CPU delay, which limited
> its usefulness when users needed to identify bottlenecks in other
> subsystems. Users had no way to sort processes by IO, memory, or
> other delay types to quickly pinpoint specific performance issues.
> 
> Add -s/--sort option to allow sorting by different delay types:
> 1) Basic modes: cpu, io, irq, mem  
> 2) Detailed modes (-M required): swap, reclaim, thrashing, compact, wpcopy
> 
> Users can now quickly identify bottlenecks in specific subsystems
> by sorting processes by the relevant delay metric.
> 
> Signed-off-by: Fan Yu <fan.yu9@....com.cn>
> ---
>  tools/accounting/delaytop.c | 130 +++++++++++++++++++++++++++++++++---
>  1 file changed, 121 insertions(+), 9 deletions(-)

I have tried this function. Nice to use.

Reviewed-by: xu xin <xu.xin16@....com.cn>

> 
> diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c
> index f1e2e1cca4b8..39852cd70bdf 100644
> --- a/tools/accounting/delaytop.c
> +++ b/tools/accounting/delaytop.c
> @@ -173,7 +173,9 @@ static void usage(void)
>  	"  -o, --once               Display once and exit\n"
>  	"  -p, --pid=PID            Monitor only the specified PID\n"
>  	"  -C, --container=PATH     Monitor the container at specified cgroup path\n"
> -	"  -M, --memverbose         Display memory detailed information\n");
> +	"  -M, --memverbose         Display memory detailed information\n"
> +	"  -s, --sort=FIELD         Sort by delay field (default: cpu)\n"
> +	"                           Types: cpu|io|irq|mem|swap|reclaim|thrashing|compact|wpcopy\n");
>  	exit(0);
>  }
> 
> @@ -188,6 +190,7 @@ static void parse_args(int argc, char **argv)
>  		{"pid", required_argument, 0, 'p'},
>  		{"once", no_argument, 0, 'o'},
>  		{"processes", required_argument, 0, 'P'},
> +		{"sort", required_argument, 0, 's'},
>  		{"container", required_argument, 0, 'C'},
>  		{"memverbose", no_argument, 0, 'M'},
>  		{0, 0, 0, 0}
> @@ -206,7 +209,7 @@ static void parse_args(int argc, char **argv)
>  	while (1) {
>  		int option_index = 0;
> 
> -		c = getopt_long(argc, argv, "hd:n:p:oP:C:M", long_options, &option_index);
> +		c = getopt_long(argc, argv, "hd:n:p:oP:C:Ms:", long_options, &option_index);
>  		if (c == -1)
>  			break;
> 
> @@ -256,11 +259,53 @@ static void parse_args(int argc, char **argv)
>  		case 'M':
>  			cfg.mem_verbose_mode = 1;
>  			break;
> +		case 's':
> +			if (strlen(optarg) == 0) {
> +				fprintf(stderr, "Error: empty sort field\n");
> +				exit(1);
> +			}
> +
> +			if (strncmp(optarg, "cpu", 3) == 0)
> +				cfg.sort_field = 'c';
> +			else if (strncmp(optarg, "io", 2) == 0)
> +				cfg.sort_field = 'i';
> +			else if (strncmp(optarg, "irq", 3) == 0)
> +				cfg.sort_field = 'q';
> +			else if (strncmp(optarg, "mem", 3) == 0)
> +				cfg.sort_field = 'm';
> +			else if (strncmp(optarg, "swap", 4) == 0)
> +				cfg.sort_field = 's';
> +			else if (strncmp(optarg, "reclaim", 7) == 0)
> +				cfg.sort_field = 'r';
> +			else if (strncmp(optarg, "thrashing", 9) == 0)
> +				cfg.sort_field = 't';
> +			else if (strncmp(optarg, "compact", 7) == 0)
> +				cfg.sort_field = 'p';
> +			else if (strncmp(optarg, "wpcopy", 7) == 0)
> +				cfg.sort_field = 'w';
> +			else {
> +				fprintf(stderr, "Error: invalid sort field\n");
> +				fprintf(stderr, "Try to use cpu|io|irq|mem|");
> +				fprintf(stderr, "swap|reclaim|thrashing|compact|wpcopy\n");
> +				exit(1);
> +			}
> +			break;
>  		default:
>  			fprintf(stderr, "Try 'delaytop --help' for more information.\n");
>  			exit(1);
>  		}
>  	}
> +
> +	/* Validate sorting field compatibility with memory verbose mode */
> +	if (cfg.mem_verbose_mode == 0 &&
> +		cfg.sort_field == 's' ||
> +		cfg.sort_field == 'r' ||
> +		cfg.sort_field == 't' ||
> +		cfg.sort_field == 'p' ||
> +		cfg.sort_field == 'w') {
> +		fprintf(stderr, "Error: mem verbose mode is off, try to use -M\n");
> +		exit(1);
> +	}
>  }
> 
>  /* Create a raw netlink socket and bind */
> @@ -621,12 +666,77 @@ static int compare_tasks(const void *a, const void *b)
>  	case 'c': /* CPU */
>  		avg1 = average_ms(t1->cpu_delay_total, t1->cpu_count);
>  		avg2 = average_ms(t2->cpu_delay_total, t2->cpu_count);
> -		if (avg1 != avg2)
> -			return avg2 > avg1 ? 1 : -1;
> -		return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
> +		break;
> +	case 'i': /* IO */
> +		avg1 = average_ms(t1->blkio_delay_total, t1->blkio_count);
> +		avg2 = average_ms(t2->blkio_delay_total, t2->blkio_count);
> +		break;
> +	case 'q': /* IRQ */
> +		avg1 = average_ms(t1->irq_delay_total, t1->irq_count);
> +		avg2 = average_ms(t2->irq_delay_total, t2->irq_count);
> +		break;
> +	case 'm': /* MEM(total) */
> +		avg1 = average_ms(task_total_mem_delay(t1), task_total_mem_count(t1));
> +		avg2 = average_ms(task_total_mem_delay(t2), task_total_mem_count(t2));
> +		break;
> +	/* Memory detailed display mode */
> +	case 's': /* swapin (SWAP) */
> +		avg1 = average_ms(t1->swapin_delay_total, t1->swapin_count);
> +		avg2 = average_ms(t2->swapin_delay_total, t2->swapin_count);
> +		break;
> +	case 'r': /* freepages (RCL) */
> +		avg1 = average_ms(t1->freepages_delay_total, t1->freepages_count);
> +		avg2 = average_ms(t2->freepages_delay_total, t2->freepages_count);
> +		break;
> +	case 't': /* thrashing (THR) */
> +		avg1 = average_ms(t1->thrashing_delay_total, t1->thrashing_count);
> +		avg2 = average_ms(t2->thrashing_delay_total, t2->thrashing_count);
> +		break;
> +	case 'p': /* compact (CMP) */
> +		avg1 = average_ms(t1->compact_delay_total, t1->compact_count);
> +		avg2 = average_ms(t2->compact_delay_total, t2->compact_count);
> +		break;
> +	case 'w': /* wpcopy (WP) */
> +		avg1 = average_ms(t1->wpcopy_delay_total, t1->wpcopy_count);
> +		avg2 = average_ms(t2->wpcopy_delay_total, t2->wpcopy_count);
> +		break;
> +	default:
> +		avg1 = average_ms(t1->cpu_delay_total, t1->cpu_count);
> +		avg2 = average_ms(t2->cpu_delay_total, t2->cpu_count);
> +		break;
> +	}
> +
> +	if (avg1 != avg2)
> +		return avg2 > avg1 ? 1 : -1;
> +
> +	return 0;
> +}
> 
> +static const char *get_sort_field(char sort_field)
> +{
> +	switch (sort_field) {
> +	case 'c':
> +		return "CPU";
> +	case 'i':
> +		return "IO";
> +	case 'q':
> +		return "IRQ";
> +	/* MEM(total) */
> +	case 'm':
> +		return "MEM";
> +	/* Memory detailed display mode */
> +	case 's':
> +		return "SWAP";
> +	case 'r':
> +		return "RCL";
> +	case 't':
> +		return "THR";
> +	case 'p':
> +		return "CMP";
> +	case 'w':
> +		return "WP";
>  	default:
> -		return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
> +		return "UNKNOWN"; /* handle error */
>  	}
>  }
> 
> @@ -705,6 +815,7 @@ static void display_results(void)
>  {
>  	time_t now = time(NULL);
>  	struct tm *tm_now = localtime(&now);
> +	const char *sort_field;
>  	FILE *out = stdout;
>  	char timestamp[32];
>  	bool suc = true;
> @@ -766,8 +877,10 @@ static void display_results(void)
>  			container_stats.nr_stopped, container_stats.nr_uninterruptible,
>  			container_stats.nr_io_wait);
>  	}
> -	suc &= BOOL_FPRINT(out, "Top %d processes (sorted by CPU delay):\n",
> -			cfg.max_processes);
> +
> +	/* Task delay output */
> +	suc &= BOOL_FPRINT(out, "Top %d processes (sorted by %s delay):\n",
> +			cfg.max_processes, get_sort_field(cfg.sort_field));
>  	suc &= BOOL_FPRINT(out, "%8s  %8s  %-17s", "PID", "TGID", "COMMAND");
> 
>  	if (!cfg.mem_verbose_mode) {
> @@ -787,7 +900,6 @@ static void display_results(void)
>  		suc &= BOOL_FPRINT(out, "-------------------------\n");
>  	}
> 
> -
>  	count = task_count < cfg.max_processes ? task_count : cfg.max_processes;
> 
>  	for (i = 0; i < count; i++) {
> -- 
> 2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ