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: <20250902100510629gbt-dwxQ09_35jcv_YO3U@zte.com.cn>
Date: Tue, 2 Sep 2025 10:05:10 +0800 (CST)
From: <fan.yu9@....com.cn>
To: <akpm@...ux-foundation.org>, <wang.yaxin@....com.cn>
Cc: <corbet@....net>, <linux-kernel@...r.kernel.org>,
        <linux-doc@...r.kernel.org>, <xu.xin16@....com.cn>,
        <yang.yang29@....com.cn>, <fan.yu9@....com.cn>
Subject: [PATCH linux-next 3/3] tools/delaytop: add interactive mode with keyboard controls

From: Fan Yu <fan.yu9@....com.cn>

The original delaytop only supported static output with limited
interaction. Users had to restart the tool with different command-line
options to change sorting or display modes, which disrupted continuous
monitoring and reduced productivity during performance investigations.

Adds real-time interactive controls through keyboard input:
1) Add interactive menu system with visual prompts
2) Support dynamic sorting changes without restarting
3) Enable toggle of memory verbose mode with 'M' key

The interactive mode transforms delaytop from a static monitoring tool
into a dynamic investigation platform, allowing users to adapt the
view in real-time based on observed performance patterns.

Signed-off-by: Fan Yu <fan.yu9@....com.cn>
---
 tools/accounting/delaytop.c | 112 ++++++++++++++++++++++++++----------
 1 file changed, 82 insertions(+), 30 deletions(-)

diff --git a/tools/accounting/delaytop.c b/tools/accounting/delaytop.c
index 39852cd70bdf..21fb215d2928 100644
--- a/tools/accounting/delaytop.c
+++ b/tools/accounting/delaytop.c
@@ -140,6 +140,7 @@ static struct task_info tasks[MAX_TASKS];
 static int task_count;
 static int running = 1;
 static struct container_stats container_stats;
+static int sort_selected;

 /* Netlink socket variables */
 static int nl_sd = -1;
@@ -878,6 +879,17 @@ static void display_results(void)
 			container_stats.nr_io_wait);
 	}

+	/* Interacive command */
+	suc &= BOOL_FPRINT(out, "[o]sort [M]memverbose [q]quit\n");
+	if (sort_selected) {
+		if (cfg.mem_verbose_mode)
+			suc &= BOOL_FPRINT(out,
+			"sort selection: [c]CPU [i]IO [s]SWAP [r]RCL [t]THR [p]CMP [w]WP [q]IRQ\n");
+		else
+			suc &= BOOL_FPRINT(out,
+			"sort selection: [c]CPU [i]IO [m]MEM [q]IRQ\n");
+	}
+
 	/* Task delay output */
 	suc &= BOOL_FPRINT(out, "Top %d processes (sorted by %s delay):\n",
 			cfg.max_processes, get_sort_field(cfg.sort_field));
@@ -944,11 +956,73 @@ static void display_results(void)
 		perror("Error writing to output");
 }

+/* Check for keyboard input with timeout based on cfg.delay */
+static char check_for_keypress(void)
+{
+	struct timeval tv = {cfg.delay, 0};
+	fd_set readfds;
+	char ch = 0;
+
+	FD_ZERO(&readfds);
+	FD_SET(STDIN_FILENO, &readfds);
+	int r = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
+
+	if (r > 0 && FD_ISSET(STDIN_FILENO, &readfds)) {
+		read(STDIN_FILENO, &ch, 1);
+		return ch;
+	}
+
+	return 0;
+}
+
+/* Handle keyboard input: sorting selection, mode toggle, or quit */
+static void handle_keypress(char ch, int *running)
+{
+	if (sort_selected) {
+		switch (ch) {
+		case 'c':
+		case 'i':
+		case 'q':
+		case 'm':
+			cfg.sort_field = ch;
+			break;
+		/* Only for memory verbose mode */
+		case 's':
+		case 'r':
+		case 't':
+		case 'p':
+		case 'w':
+			if (cfg.mem_verbose_mode)
+				cfg.sort_field = ch;
+			break;
+		default:
+			break;
+		}
+		sort_selected = 0;
+	} else {
+		switch (ch) {
+		case 'o':
+			sort_selected = 1;
+			break;
+		case 'M':
+			cfg.mem_verbose_mode = !cfg.mem_verbose_mode;
+			cfg.sort_field = 'c'; /* Change to default sort mode */
+			break;
+		case 'q':
+		case 'Q':
+			*running = 0;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
 /* Main function */
 int main(int argc, char **argv)
 {
 	int iterations = 0;
-	int use_q_quit = 0;
+	char keypress;

 	/* Parse command line arguments */
 	parse_args(argc, argv);
@@ -968,12 +1042,8 @@ int main(int argc, char **argv)
 		exit(1);
 	}

-	if (!cfg.output_one_time) {
-		use_q_quit = 1;
-		enable_raw_mode();
-		printf("Press 'q' to quit.\n");
-		fflush(stdout);
-	}
+	/* Set terminal to non-canonical mode for interaction */
+	enable_raw_mode();

 	/* Main loop */
 	while (running) {
@@ -1001,32 +1071,14 @@ int main(int argc, char **argv)
 		if (cfg.output_one_time)
 			break;

-		/* Check for 'q' key to quit */
-		if (use_q_quit) {
-			struct timeval tv = {cfg.delay, 0};
-			fd_set readfds;
-
-			FD_ZERO(&readfds);
-			FD_SET(STDIN_FILENO, &readfds);
-			int r = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);
-
-			if (r > 0 && FD_ISSET(STDIN_FILENO, &readfds)) {
-				char ch = 0;
-
-				read(STDIN_FILENO, &ch, 1);
-				if (ch == 'q' || ch == 'Q') {
-					running = 0;
-					break;
-				}
-			}
-		} else {
-			sleep(cfg.delay);
-		}
+		/* Keypress for interactive usage */
+		keypress = check_for_keypress();
+		if (keypress)
+			handle_keypress(keypress, &running);
 	}

 	/* Restore terminal mode */
-	if (use_q_quit)
-		disable_raw_mode();
+	disable_raw_mode();

 	/* Cleanup */
 	close(nl_sd);
-- 
2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ