[<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