better to run autoreconf than running every auto* tool by hand.
[lttngtop.git] / src / cursesdisplay.c
CommitLineData
1fc22eb4
JD
1/*
2 * Copyright (C) 2011 Julien Desfossez
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
71bd7ce1
AM
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1fc22eb4
JD
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <signal.h>
21#include <string.h>
22#include <ncurses.h>
23#include <panel.h>
24#include <pthread.h>
25#include <semaphore.h>
26
27#include "cursesdisplay.h"
28#include "lttngtoptypes.h"
b093de8a 29#include "iostreamtop.h"
1fc22eb4
JD
30#include "common.h"
31
32#define DEFAULT_DELAY 15
33#define MAX_LINE_LENGTH 50
34#define MAX_LOG_LINES 4
35
36/* to prevent concurrent updates of the different windows */
37sem_t update_display_sem;
38
39char *termtype;
40WINDOW *footer, *header, *center, *status;
0d91c12a
JD
41WINDOW *pref_panel_window = NULL;
42PANEL *pref_panel, *main_panel;
1fc22eb4 43
0d91c12a 44int pref_panel_visible = 0;
3b15348c 45int pref_line_selected = 0;
1fc22eb4
JD
46
47int last_display_index, currently_displayed_index;
48
49struct processtop *selected_process = NULL;
1fc22eb4
JD
50int selected_ret;
51
52int selected_line = 0; /* select bar position */
53int selected_in_list = 0; /* selection relative to the whole list */
54int list_offset = 0; /* first index in the list to display (scroll) */
55int nb_log_lines = 0;
56char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES];
57
58int max_elements = 80;
59
60int toggle_threads = -1;
61int toggle_pause = -1;
1fc22eb4
JD
62
63int max_center_lines;
635dc837 64GPtrArray *selected_processes;
1fc22eb4
JD
65
66pthread_t keyboard_thread;
67
3b15348c
JD
68struct cputopview cputopview[4];
69
1fc22eb4
JD
70void reset_ncurses()
71{
72 curs_set(1);
73 endwin();
74 exit(0);
75}
76
77static void handle_sigterm(int signal)
78{
79 reset_ncurses();
80}
81
82void init_screen()
83{
84 initscr();
85 noecho();
86 halfdelay(DEFAULT_DELAY);
87 nonl();
88 intrflush(stdscr, false);
89 keypad(stdscr, true);
90 curs_set(0);
91
92 if (has_colors()) {
93 start_color();
94 init_pair(1, COLOR_RED, COLOR_BLACK); /* - */
95 init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */
96 init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */
97 init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */
98 init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */
635dc837 99 init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */
1fc22eb4
JD
100 }
101 termtype = getenv("TERM");
102 if (!strcmp(termtype, "xterm") || !strcmp(termtype, "xterm-color") ||
103 !strcmp(termtype, "vt220")) {
104 define_key("\033[H", KEY_HOME);
105 define_key("\033[F", KEY_END);
106 define_key("\033OP", KEY_F(1));
107 define_key("\033OQ", KEY_F(2));
108 define_key("\033OR", KEY_F(3));
109 define_key("\033OS", KEY_F(4));
110 define_key("\0330U", KEY_F(6));
111 define_key("\033[11~", KEY_F(1));
112 define_key("\033[12~", KEY_F(2));
113 define_key("\033[13~", KEY_F(3));
114 define_key("\033[14~", KEY_F(4));
115 define_key("\033[16~", KEY_F(6));
116 define_key("\033[17;2~", KEY_F(18));
117 }
118 signal(SIGTERM, handle_sigterm);
119 mousemask(BUTTON1_CLICKED, NULL);
120 refresh();
121}
122
123WINDOW *create_window(int height, int width, int startx, int starty)
124{
125 WINDOW *win;
126 win = newwin(height, width, startx, starty);
127 box(win, 0 , 0);
128 wrefresh(win);
129 return win;
130}
131
132WINDOW *create_window_no_border(int height, int width, int startx, int starty)
133{
134 WINDOW *win;
135 win = newwin(height, width, startx, starty);
136 wrefresh(win);
137 return win;
138}
139
140void print_digit(WINDOW *win, int digit)
141{
142 if (digit < 0) {
143 wattron(win, COLOR_PAIR(1));
144 wprintw(win, "%d", digit);
145 wattroff(win, COLOR_PAIR(1));
146 } else if (digit > 0) {
147 wattron(win, COLOR_PAIR(2));
148 wprintw(win, "+%d", digit);
149 wattroff(win, COLOR_PAIR(2));
150 } else {
151 wprintw(win, "0");
152 }
153}
154
155void print_digits(WINDOW *win, int first, int second)
156{
157 wprintw(win, "(");
158 print_digit(win, first);
159 wprintw(win, ", ");
160 print_digit(win, second);
161 wprintw(win, ")");
162}
163
164void print_headers(int line, char *desc, int value, int first, int second)
165{
166 wattron(header, A_BOLD);
167 mvwprintw(header, line, 4, "%s", desc);
168 wattroff(header, A_BOLD);
e05a35a6 169 mvwprintw(header, line, 16, "%d", value);
1fc22eb4
JD
170 wmove(header, line, 24);
171 print_digits(header, first, second);
172 wmove(header, line, 40);
173}
174
175void set_window_title(WINDOW *win, char *title)
176{
177 wattron(win, A_BOLD);
178 mvwprintw(win, 0, 1, title);
179 wattroff(win, A_BOLD);
180}
181
182void print_log(char *str)
183{
184 int i;
185 int current_line = 1;
186 int current_char = 1;
187 char *tmp, *tmp2;
188 /* rotate the line buffer */
189 if (nb_log_lines >= MAX_LOG_LINES) {
190 tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES);
191 tmp2 = strchr(tmp, '\n');
192 memset(log_lines, '\0', strlen(log_lines));
193 strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1);
194 log_lines[strlen(log_lines)] = '\n';
195 log_lines[strlen(log_lines)] = '\0';
196 free(tmp);
197 }
198 nb_log_lines++;
199
200 strncat(log_lines, str, MAX_LINE_LENGTH - 1);
201
202 if (nb_log_lines < MAX_LOG_LINES)
203 log_lines[strlen(log_lines)] = '\n';
204 log_lines[strlen(log_lines)] = '\0';
205
206 werase(status);
207 box(status, 0 , 0);
208 set_window_title(status, "Status");
209 for (i = 0; i < strlen(log_lines); i++) {
210 if (log_lines[i] == '\n') {
211 wmove(status, ++current_line, 1);
212 current_char = 1;
213 } else {
b093de8a
MB
214 mvwprintw(status, current_line, current_char++, "%c",
215 log_lines[i]);
1fc22eb4
JD
216 }
217 }
218 wrefresh(status);
219}
220
635dc837
JD
221int process_selected(struct processtop *process)
222{
223 int i;
224 struct processtop *stored_process;
225
226 for (i = 0; i < selected_processes->len; i++) {
227 stored_process = g_ptr_array_index(selected_processes, i);
228 if (stored_process->tid == process->tid)
229 return 1;
230 }
231 return 0;
232}
233
234void update_selected_processes()
235{
236 if (process_selected(selected_process)) {
237 g_ptr_array_remove(selected_processes, selected_process);
238 print_log("Process removed");
239 } else {
240 g_ptr_array_add(selected_processes, selected_process);
241 print_log("Process added");
242 }
243}
244
1fc22eb4
JD
245void print_key(WINDOW *win, char *key, char *desc, int toggle)
246{
247 int pair;
248 if (toggle > 0)
249 pair = 4;
250 else
251 pair = 3;
252 wattron(win, COLOR_PAIR(pair));
253 wprintw(footer, "%s", key);
254 wattroff(win, COLOR_PAIR(pair));
255 wprintw(footer, ":%s", desc);
256}
257
258void update_footer()
259{
260 sem_wait(&update_display_sem);
261 werase(footer);
262 wmove(footer, 1, 1);
263 print_key(footer, "F2", "CPUtop ", current_view == cpu);
264 print_key(footer, "F3", "PerfTop ", current_view == perf);
e7be7d41 265 print_key(footer, "F4", "IOTop ", current_view == iostream);
1fc22eb4 266 print_key(footer, "Enter", "Details ", current_view == process_details);
635dc837 267 print_key(footer, "Space", "Highlight ", 0);
1fc22eb4
JD
268 print_key(footer, "q", "Quit | ", 0);
269 print_key(footer, "P", "Perf Pref ", 0);
270 print_key(footer, "p", "Pause ", toggle_pause);
271
272 wrefresh(footer);
273 sem_post(&update_display_sem);
274}
275
276void basic_header()
277{
278 werase(header);
279 box(header, 0 , 0);
280 set_window_title(header, "Statistics for interval [gathering data...[");
281 wattron(header, A_BOLD);
282 mvwprintw(header, 1, 4, "CPUs");
e05a35a6 283 mvwprintw(header, 2, 4, "Threads");
dc8f04dd 284 mvwprintw(header, 3, 4, "FDs");
1fc22eb4
JD
285 wattroff(header, A_BOLD);
286 wrefresh(header);
287}
288
91be6bb5
JD
289struct tm format_timestamp(uint64_t timestamp)
290{
291 struct tm tm;
292 uint64_t ts_sec = 0, ts_nsec;
293 time_t time_s;
294
295 ts_nsec = timestamp;
296 ts_sec += ts_nsec / NSEC_PER_SEC;
297 ts_nsec = ts_nsec % NSEC_PER_SEC;
298
299 time_s = (time_t) ts_sec;
300
301 localtime_r(&time_s, &tm);
302
303 return tm;
304}
305
69362330
JD
306static void scale_unit(uint64_t bytes, char *ret)
307{
308 if (bytes >= 1000000000)
309 sprintf(ret, "%" PRIu64 "G", bytes/1000000000);
310 if (bytes >= 1000000)
311 sprintf(ret, "%" PRIu64 "M", bytes/1000000);
312 else if (bytes >= 1000)
313 sprintf(ret, "%" PRIu64 "K", bytes/1000);
314 else
315 sprintf(ret, "%" PRIu64, bytes);
316}
317uint64_t total_io()
318{
319 int i;
320 struct processtop *tmp;
321 uint64_t total = 0;
322
323 for (i = 0; i < data->process_table->len; i++) {
324 tmp = g_ptr_array_index(data->process_table, i);
325 total += tmp->fileread;
326 total += tmp->filewrite;
327 }
328
329 return total;
330}
331
1fc22eb4
JD
332void update_header()
333{
91be6bb5
JD
334 struct tm start, end;
335 uint64_t ts_nsec_start, ts_nsec_end;
69362330 336 char io[4];
91be6bb5
JD
337
338 ts_nsec_start = data->start % NSEC_PER_SEC;
339 start = format_timestamp(data->start);
340
341 ts_nsec_end = data->end % NSEC_PER_SEC;
342 end = format_timestamp(data->end);
343
1fc22eb4
JD
344 werase(header);
345 box(header, 0 , 0);
346 set_window_title(header, "Statistics for interval ");
347 wattron(header, A_BOLD);
91be6bb5
JD
348
349 wprintw(header, "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[",
350 start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start,
351 end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_end);
1fc22eb4
JD
352 mvwprintw(header, 1, 4, "CPUs");
353 wattroff(header, A_BOLD);
354 wprintw(header, "\t%d\t(max/cpu : %0.2f%)", data->cpu_table->len,
355 100.0/data->cpu_table->len);
e05a35a6 356 print_headers(2, "Threads", data->nbthreads, data->nbnewthreads,
1fc22eb4 357 -1*(data->nbdeadthreads));
dc8f04dd 358 print_headers(3, "FDs", data->nbfiles, data->nbnewfiles,
1fc22eb4 359 -1*(data->nbclosedfiles));
69362330
JD
360 scale_unit(total_io(), io);
361 mvwprintw(header, 3, 43, "%sB/sec", io);
1fc22eb4
JD
362 wrefresh(header);
363}
364
365gint sort_by_cpu_desc(gconstpointer p1, gconstpointer p2)
366{
367 struct processtop *n1 = *(struct processtop **)p1;
368 struct processtop *n2 = *(struct processtop **)p2;
369 unsigned long totaln1 = n1->totalcpunsec;
370 unsigned long totaln2 = n2->totalcpunsec;
371
372 if (totaln1 < totaln2)
373 return 1;
374 if (totaln1 == totaln2)
375 return 0;
376 return -1;
377}
378
3b15348c
JD
379gint sort_by_tid_desc(gconstpointer p1, gconstpointer p2)
380{
381 struct processtop *n1 = *(struct processtop **)p1;
382 struct processtop *n2 = *(struct processtop **)p2;
383 unsigned long totaln1 = n1->tid;
384 unsigned long totaln2 = n2->tid;
385
386 if (totaln1 < totaln2)
387 return 1;
388 if (totaln1 == totaln2)
389 return 0;
390 return -1;
391}
392
393gint sort_by_pid_desc(gconstpointer p1, gconstpointer p2)
394{
395 struct processtop *n1 = *(struct processtop **)p1;
396 struct processtop *n2 = *(struct processtop **)p2;
397 unsigned long totaln1 = n1->pid;
398 unsigned long totaln2 = n2->pid;
399
400 if (totaln1 < totaln2)
401 return 1;
402 if (totaln1 == totaln2)
403 return 0;
404 return -1;
405}
406
1fc22eb4
JD
407gint sort_by_cpu_group_by_threads_desc(gconstpointer p1, gconstpointer p2)
408{
409 struct processtop *n1 = *(struct processtop **)p1;
410 struct processtop *n2 = *(struct processtop **)p2;
411 unsigned long totaln1 = n1->threadstotalcpunsec;
412 unsigned long totaln2 = n2->threadstotalcpunsec;
413
414 if (totaln1 < totaln2)
415 return 1;
416 if (totaln1 == totaln2)
417 return 0;
418 return -1;
419}
420
421void update_cputop_display()
422{
423 int i;
424 int header_offset = 2;
425 struct processtop *tmp;
426 unsigned long elapsed;
427 double maxcputime;
428 int nblinedisplayed = 0;
429 int current_line = 0;
430
431 elapsed = data->end - data->start;
432 maxcputime = elapsed * data->cpu_table->len / 100.0;
433
3b15348c
JD
434 if (cputopview[0].sort == 1)
435 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
436 else if (cputopview[1].sort == 1)
437 g_ptr_array_sort(data->process_table, sort_by_pid_desc);
438 else if (cputopview[2].sort == 1)
439 g_ptr_array_sort(data->process_table, sort_by_tid_desc);
440 else if (cputopview[3].sort == 1)
441 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
442 else
443 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
1fc22eb4
JD
444
445 set_window_title(center, "CPU Top");
446 wattron(center, A_BOLD);
3b15348c
JD
447 mvwprintw(center, 1, 1, cputopview[0].title);
448 mvwprintw(center, 1, 12, cputopview[1].title);
449 mvwprintw(center, 1, 22, cputopview[2].title);
450 mvwprintw(center, 1, 32, cputopview[3].title);
1fc22eb4
JD
451 wattroff(center, A_BOLD);
452
dc8f04dd 453 max_center_lines = LINES - 5 - 7 - 1 - header_offset;
1fc22eb4
JD
454
455 /* iterate the process (thread) list */
456 for (i = list_offset; i < data->process_table->len &&
457 nblinedisplayed < max_center_lines; i++) {
458 tmp = g_ptr_array_index(data->process_table, i);
459
97514683 460 /* FIXME : random segfault here */
635dc837
JD
461 if (process_selected(tmp)) {
462 wattron(center, COLOR_PAIR(6));
463 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
464 }
1fc22eb4
JD
465 if (current_line == selected_line) {
466 selected_process = tmp;
1fc22eb4
JD
467 wattron(center, COLOR_PAIR(5));
468 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
469 }
470 /* CPU(%) */
471 mvwprintw(center, current_line + header_offset, 1, "%1.2f",
472 tmp->totalcpunsec / maxcputime);
473 /* TGID */
474 mvwprintw(center, current_line + header_offset, 12, "%d", tmp->pid);
475 /* PID */
476 mvwprintw(center, current_line + header_offset, 22, "%d", tmp->tid);
477 /* NAME */
478 mvwprintw(center, current_line + header_offset, 32, "%s", tmp->comm);
635dc837 479 wattroff(center, COLOR_PAIR(6));
1fc22eb4
JD
480 wattroff(center, COLOR_PAIR(5));
481 nblinedisplayed++;
482 current_line++;
483 }
484}
485
486gint sort_perf(gconstpointer p1, gconstpointer p2, gpointer key)
487{
488 struct processtop *n1 = *(struct processtop **) p1;
489 struct processtop *n2 = *(struct processtop **) p2;
490
491 struct perfcounter *tmp1, *tmp2;
492 unsigned long totaln2 = 0;
493 unsigned long totaln1 = 0;
494
495 if (!key)
496 return 0;
497
498 tmp1 = g_hash_table_lookup(n1->perf, key);
499 if (!tmp1)
500 totaln1 = 0;
501 else
502 totaln1 = tmp1->count;
503
504 tmp2 = g_hash_table_lookup(n2->perf, key);
505 if (!tmp2)
506 totaln2 = 0;
507 else
508 totaln2 = tmp2->count;
509
510 if (totaln1 < totaln2)
511 return 1;
512 if (totaln1 == totaln2) {
513 totaln1 = n1->tid;
514 totaln2 = n2->tid;
515 if (totaln1 < totaln2)
516 return 1;
517 return -1;
518 }
519 return -1;
520}
521
522void print_key_title(char *key, int line)
523{
524 wattron(center, A_BOLD);
525 mvwprintw(center, line, 1, "%s\t", key);
526 wattroff(center, A_BOLD);
527}
528
529void update_process_details()
530{
531 unsigned long elapsed;
532 double maxcputime;
d26643ed 533 struct processtop *tmp;
b093de8a
MB
534 struct files *file_tmp;
535 int i, j = 0;
69362330 536 char unit[4];
97514683 537 char filename_buf[COLS];
1fc22eb4
JD
538
539 set_window_title(center, "Process details");
540
541
d26643ed
JD
542 tmp = find_process_tid(data,
543 selected_process->tid,
544 selected_process->comm);
1fc22eb4
JD
545 elapsed = data->end - data->start;
546 maxcputime = elapsed * data->cpu_table->len / 100.0;
547
548 print_key_title("Name", 1);
d26643ed 549 wprintw(center, "%s", selected_process->comm);
1fc22eb4 550 print_key_title("TID", 2);
d26643ed 551 wprintw(center, "%d", selected_process->tid);
1fc22eb4
JD
552 if (!tmp) {
553 print_key_title("Does not exit at this time", 3);
554 return;
555 }
556
557 print_key_title("PID", 3);
558 wprintw(center, "%d", tmp->pid);
559 print_key_title("PPID", 4);
560 wprintw(center, "%d", tmp->ppid);
561 print_key_title("CPU", 5);
562 wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
b093de8a
MB
563
564 print_key_title("READ B/s", 6);
69362330
JD
565 scale_unit(tmp->fileread, unit);
566 wprintw(center, "%s", unit);
b093de8a
MB
567
568 print_key_title("WRITE B/s", 7);
69362330
JD
569 scale_unit(tmp->filewrite, unit);
570 wprintw(center, "%s", unit);
b093de8a 571
93d80d35
JD
572 wattron(center, A_BOLD);
573 mvwprintw(center, 8, 1, "FD");
69362330
JD
574 mvwprintw(center, 8, 10, "READ");
575 mvwprintw(center, 8, 17, "WRITE");
576 mvwprintw(center, 8, 24, "FILENAME");
93d80d35
JD
577 wattroff(center, A_BOLD);
578
97514683
JD
579 for (i = selected_line; i < tmp->process_files_table->len &&
580 i < (selected_line + max_center_lines - 7); i++) {
b093de8a
MB
581 file_tmp = get_file(tmp, i);
582 if (file_tmp != NULL) {
93d80d35 583 mvwprintw(center, 9 + j, 1, "%d", i);
69362330
JD
584 scale_unit(file_tmp->read, unit);
585 mvwprintw(center, 9 + j, 10, "%s", unit);
586 scale_unit(file_tmp->write, unit);
587 mvwprintw(center, 9 + j, 17, "%s", unit);
97514683
JD
588 snprintf(filename_buf, COLS - 25, "%s", file_tmp->name);
589 mvwprintw(center, 9 + j, 24, "%s", filename_buf);
b093de8a
MB
590 j++;
591 }
592 }
1fc22eb4
JD
593}
594
595void update_perf()
596{
bb053abb 597 int i;
1fc22eb4
JD
598 int nblinedisplayed = 0;
599 int current_line = 0;
600 struct processtop *tmp;
601 int header_offset = 2;
602 int perf_row = 40;
603 struct perfcounter *perfn1, *perfn2;
1fc22eb4
JD
604 char *perf_key = NULL;
605 int value;
85db4618
JD
606 GHashTableIter iter;
607 gpointer key;
1fc22eb4
JD
608
609 set_window_title(center, "Perf Top");
610 wattron(center, A_BOLD);
611 mvwprintw(center, 1, 1, "PID");
612 mvwprintw(center, 1, 11, "TID");
613 mvwprintw(center, 1, 22, "NAME");
614
615 perf_row = 40;
0d91c12a 616 g_hash_table_iter_init(&iter, global_perf_liszt);
85db4618 617 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
1fc22eb4 618 if (perfn1->visible) {
6419078d 619 /* + 5 to strip the "perf_" prefix */
1fc22eb4 620 mvwprintw(center, 1, perf_row, "%s",
6419078d 621 (char *) key + 5);
1fc22eb4
JD
622 perf_row += 20;
623 }
624 if (perfn1->sort) {
85db4618 625 perf_key = (char *) key;
1fc22eb4 626 }
1fc22eb4 627 }
85db4618 628
1fc22eb4
JD
629 wattroff(center, A_BOLD);
630
631 g_ptr_array_sort_with_data(data->process_table, sort_perf, perf_key);
85db4618 632
91be6bb5 633 for (i = 0; i < data->process_table->len &&
1fc22eb4 634 nblinedisplayed < max_center_lines; i++) {
1fc22eb4
JD
635 tmp = g_ptr_array_index(data->process_table, i);
636
635dc837
JD
637 if (process_selected(tmp)) {
638 wattron(center, COLOR_PAIR(6));
639 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
640 }
1fc22eb4
JD
641 if (current_line == selected_line) {
642 selected_process = tmp;
643 wattron(center, COLOR_PAIR(5));
644 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
645 }
646
647 mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
648 mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
649 mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
650
0d91c12a 651 g_hash_table_iter_init(&iter, global_perf_liszt);
1fc22eb4
JD
652
653 perf_row = 40;
85db4618 654 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
1fc22eb4 655 if (perfn1->visible) {
85db4618 656 perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
1fc22eb4
JD
657 if (perfn2)
658 value = perfn2->count;
659 else
660 value = 0;
b093de8a
MB
661 mvwprintw(center, current_line + header_offset,
662 perf_row, "%d", value);
1fc22eb4
JD
663 perf_row += 20;
664 }
1fc22eb4
JD
665 }
666
635dc837 667 wattroff(center, COLOR_PAIR(6));
1fc22eb4
JD
668 wattroff(center, COLOR_PAIR(5));
669 nblinedisplayed++;
670 current_line++;
671 }
672}
673
1fc22eb4
JD
674gint sort_by_ret_desc(gconstpointer p1, gconstpointer p2)
675{
676 struct processtop *n1 = *(struct processtop **)p1;
677 struct processtop *n2 = *(struct processtop **)p2;
b093de8a
MB
678
679 unsigned long totaln1 = n1->totalfileread + n1->totalfilewrite;
680 unsigned long totaln2 = n2->totalfileread + n2->totalfilewrite;
1fc22eb4
JD
681
682 if (totaln1 < totaln2)
683 return 1;
684 if (totaln1 == totaln2)
685 return 0;
686 return -1;
687}
688
689void update_iostream()
690{
691 int i;
692 int header_offset = 2;
693 struct processtop *tmp;
694 int nblinedisplayed = 0;
695 int current_line = 0;
b093de8a 696 int total = 0;
69362330 697 char unit[4];
1fc22eb4
JD
698
699 set_window_title(center, "IO Top");
700 wattron(center, A_BOLD);
69362330
JD
701 mvwprintw(center, 1, 1, "PID");
702 mvwprintw(center, 1, 11, "TID");
703 mvwprintw(center, 1, 22, "NAME");
704 mvwprintw(center, 1, 40, "R (B/sec)");
705 mvwprintw(center, 1, 52, "W (B/sec)");
706 mvwprintw(center, 1, 64, "Total");
1fc22eb4
JD
707 wattroff(center, A_BOLD);
708
709 g_ptr_array_sort(data->process_table, sort_by_ret_desc);
710
711 for (i = list_offset; i < data->process_table->len &&
712 nblinedisplayed < max_center_lines; i++) {
713 tmp = g_ptr_array_index(data->process_table, i);
714
635dc837
JD
715 if (process_selected(tmp)) {
716 wattron(center, COLOR_PAIR(6));
717 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
718 }
1fc22eb4
JD
719 if (current_line == selected_line) {
720 selected_process = tmp;
1fc22eb4
JD
721 wattron(center, COLOR_PAIR(5));
722 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
723 }
69362330
JD
724 /* TGID */
725 mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
726 /* PID */
727 mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
728 /* NAME */
729 mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
b093de8a 730
1fc22eb4 731 /* READ (bytes/sec) */
69362330
JD
732 scale_unit(tmp->fileread, unit);
733 mvwprintw(center, current_line + header_offset, 40, "%s", unit);
1fc22eb4
JD
734
735 /* WRITE (bytes/sec) */
69362330
JD
736 scale_unit(tmp->filewrite, unit);
737 mvwprintw(center, current_line + header_offset, 52, "%s", unit);
1fc22eb4
JD
738
739 /* TOTAL STREAM */
b093de8a
MB
740 total = tmp->totalfileread + tmp->totalfilewrite;
741
69362330
JD
742 scale_unit(total, unit);
743 mvwprintw(center, current_line + header_offset, 64, "%s", unit);
b093de8a 744
635dc837 745 wattroff(center, COLOR_PAIR(6));
1fc22eb4
JD
746 wattroff(center, COLOR_PAIR(5));
747 nblinedisplayed++;
748 current_line++;
749 }
750}
751
752void update_current_view()
753{
754 sem_wait(&update_display_sem);
755 if (!data)
756 return;
757 update_header();
758
759 werase(center);
760 box(center, 0, 0);
761 switch (current_view) {
762 case cpu:
763 update_cputop_display();
764 break;
765 case perf:
766 update_perf();
767 break;
768 case process_details:
769 update_process_details();
770 break;
1fc22eb4
JD
771 case iostream:
772 update_iostream();
773 break;
774 case tree:
775 update_cputop_display();
776 break;
777 default:
778 break;
779 }
780 update_panels();
781 doupdate();
782 sem_post(&update_display_sem);
783}
784
3b15348c
JD
785void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
786{
787 int i;
788 int size;
789
790 if (!data)
791 return;
792 if (pref_panel_window) {
793 del_panel(pref_panel);
794 delwin(pref_panel_window);
795 }
796 size = 4;
797
798 pref_panel_window = create_window(size + 2, 30, 10, 10);
799 pref_panel = new_panel(pref_panel_window);
800
801 werase(pref_panel_window);
802 box(pref_panel_window, 0 , 0);
803 set_window_title(pref_panel_window, "CPUTop Preferences ");
804 wattron(pref_panel_window, A_BOLD);
805 mvwprintw(pref_panel_window, size + 1, 1,
806 " 's' to sort");
807 wattroff(pref_panel_window, A_BOLD);
808
809 if (*line_selected > 3)
810 *line_selected = 3;
811 if (toggle_sort == 1) {
812 /* special case, we don't support sorting by procname for now */
813 if (*line_selected != 3) {
814 if (cputopview[*line_selected].sort == 1)
815 cputopview[*line_selected].reverse = 1;
816 for (i = 0; i < 4; i++)
817 cputopview[i].sort = 0;
818 cputopview[*line_selected].sort = 1;
819 update_current_view();
820 }
821 }
822
823 for (i = 0; i < 4; i++) {
824 if (i == *line_selected) {
825 wattron(pref_panel_window, COLOR_PAIR(5));
826 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
827 }
828 if (cputopview[i].sort == 1)
829 wattron(pref_panel_window, A_BOLD);
830 mvwprintw(pref_panel_window, i + 1, 1, "[x] %s",
831 cputopview[i].title);
832 wattroff(pref_panel_window, A_BOLD);
833 wattroff(pref_panel_window, COLOR_PAIR(5));
834
835 }
836 update_panels();
837 doupdate();
838}
839
840void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
1fc22eb4 841{
1e05f0ae
JD
842 int i;
843 struct perfcounter *perf;
844 GList *perflist;
1fc22eb4 845 int size;
1e05f0ae 846
1fc22eb4
JD
847 if (!data)
848 return;
0d91c12a
JD
849 if (pref_panel_window) {
850 del_panel(pref_panel);
851 delwin(pref_panel_window);
1fc22eb4 852 }
0d91c12a 853 size = g_hash_table_size(global_perf_liszt);
1e05f0ae 854
0d91c12a
JD
855 pref_panel_window = create_window(size + 2, 30, 10, 10);
856 pref_panel = new_panel(pref_panel_window);
1fc22eb4 857
0d91c12a
JD
858 werase(pref_panel_window);
859 box(pref_panel_window, 0 , 0);
860 set_window_title(pref_panel_window, "Perf Preferences ");
861 wattron(pref_panel_window, A_BOLD);
862 mvwprintw(pref_panel_window, g_hash_table_size(global_perf_liszt) + 1, 1,
b093de8a 863 " 's' to sort");
0d91c12a 864 wattroff(pref_panel_window, A_BOLD);
1fc22eb4
JD
865
866 if (toggle_sort == 1) {
867 i = 0;
0d91c12a 868 perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
1fc22eb4 869 while (perflist) {
0d91c12a 870 perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
3b15348c 871 if (i != *line_selected)
1fc22eb4
JD
872 perf->sort = 0;
873 else
874 perf->sort = 1;
875 i++;
876 perflist = g_list_next(perflist);
877 }
878 update_current_view();
879 }
880
881 i = 0;
0d91c12a 882 perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
1fc22eb4 883 while (perflist) {
0d91c12a 884 perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
3b15348c 885 if (i == *line_selected && toggle_view == 1) {
1fc22eb4
JD
886 perf->visible = perf->visible == 1 ? 0:1;
887 update_current_view();
888 }
3b15348c 889 if (i == *line_selected) {
0d91c12a
JD
890 wattron(pref_panel_window, COLOR_PAIR(5));
891 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1fc22eb4
JD
892 }
893 if (perf->sort == 1)
0d91c12a
JD
894 wattron(pref_panel_window, A_BOLD);
895 mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
1fc22eb4 896 perf->visible == 1 ? 'x' : ' ',
b8a1df45 897 (char *) perflist->data + 5);
0d91c12a
JD
898 wattroff(pref_panel_window, A_BOLD);
899 wattroff(pref_panel_window, COLOR_PAIR(5));
1fc22eb4
JD
900 i++;
901 perflist = g_list_next(perflist);
902 }
903 update_panels();
904 doupdate();
905}
906
3b15348c 907int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
1fc22eb4 908{
1e05f0ae
JD
909 int ret = 0;
910
0d91c12a
JD
911 switch(current_view) {
912 case perf:
3b15348c
JD
913 update_perf_pref(line_selected, toggle_view, toggle_sort);
914 break;
915 case cpu:
916 update_cpu_pref(line_selected, toggle_view, toggle_sort);
0d91c12a
JD
917 break;
918 default:
1e05f0ae 919 ret = -1;
0d91c12a
JD
920 break;
921 }
1e05f0ae
JD
922
923 return ret;
0d91c12a
JD
924}
925
926void toggle_pref_panel(void)
927{
1e05f0ae
JD
928 int ret;
929
0d91c12a
JD
930 if (pref_panel_visible) {
931 hide_panel(pref_panel);
932 pref_panel_visible = 0;
1fc22eb4 933 } else {
3b15348c 934 ret = update_preference_panel(&pref_line_selected, 0, 0);
1e05f0ae
JD
935 if (ret < 0)
936 return;
0d91c12a
JD
937 show_panel(pref_panel);
938 pref_panel_visible = 1;
1fc22eb4
JD
939 }
940 update_panels();
941 doupdate();
942}
943
944void display(unsigned int index)
945{
946 last_display_index = index;
947 currently_displayed_index = index;
948 data = g_ptr_array_index(copies, index);
949 if (!data)
950 return;
951 max_elements = data->process_table->len;
952 update_current_view();
953 update_footer();
954 update_panels();
955 doupdate();
956}
957
958void pause_display()
959{
960 toggle_pause = 1;
961 print_log("Pause");
962 sem_wait(&pause_sem);
963}
964
965void resume_display()
966{
967 toggle_pause = -1;
968 print_log("Resume");
969 sem_post(&pause_sem);
970}
971
972void *handle_keyboard(void *p)
973{
974 int ch;
975 while((ch = getch())) {
976 switch(ch) {
977 /* Move the cursor and scroll */
978 case KEY_DOWN:
0d91c12a 979 if (pref_panel_visible) {
3b15348c
JD
980 pref_line_selected++;
981 update_preference_panel(&pref_line_selected, 0, 0);
1fc22eb4
JD
982 } else {
983 if (selected_line < (max_center_lines - 1) &&
984 selected_line < max_elements - 1) {
985 selected_line++;
986 selected_in_list++;
987 } else if (selected_in_list < (max_elements - 1)
988 && (list_offset < (max_elements - max_center_lines))) {
989 selected_in_list++;
990 list_offset++;
991 }
992 update_current_view();
993 }
994 break;
995 case KEY_NPAGE:
1fc22eb4
JD
996 break;
997 case KEY_UP:
0d91c12a 998 if (pref_panel_visible) {
3b15348c
JD
999 if (pref_line_selected > 0)
1000 pref_line_selected--;
1001 update_preference_panel(&pref_line_selected, 0, 0);
1fc22eb4
JD
1002 } else {
1003 if (selected_line > 0) {
1004 selected_line--;
1005 selected_in_list--;
1006 } else if (selected_in_list > 0 && list_offset > 0) {
1007 selected_in_list--;
1008 list_offset--;
1009 }
1010 update_current_view();
1011 }
1012 break;
1013 case KEY_PPAGE:
1fc22eb4
JD
1014 break;
1015
1016 /* Navigate the history with arrows */
1017 case KEY_LEFT:
1018 if (currently_displayed_index > 0) {
1019 currently_displayed_index--;
1020 print_log("Going back in time");
1021 } else {
1022 print_log("Cannot rewind, last data is already displayed");
1023 }
1024 data = g_ptr_array_index(copies, currently_displayed_index);
1025 max_elements = data->process_table->len;
1026
1027 /* we force to pause the display when moving in time */
1028 if (toggle_pause < 0)
1029 pause_display();
1030
1031 update_current_view();
1032 update_footer();
1033 break;
1034 case KEY_RIGHT:
1035 if (currently_displayed_index < last_display_index) {
1036 currently_displayed_index++;
1037 print_log("Going forward in time");
1038 data = g_ptr_array_index(copies, currently_displayed_index);
1039 max_elements = data->process_table->len;
1040 update_current_view();
1041 update_footer();
1042 } else {
1043 print_log("Manually moving forward");
1044 sem_post(&timer);
1045 /* we force to resume the refresh when moving forward */
1046 if (toggle_pause > 0)
1047 resume_display();
1048 }
1049
1050 break;
1051 case ' ':
0d91c12a 1052 if (pref_panel_visible) {
3b15348c 1053 update_preference_panel(&pref_line_selected, 1, 0);
635dc837
JD
1054 } else {
1055 update_selected_processes();
1056 update_current_view();
1057 }
1fc22eb4
JD
1058 break;
1059 case 's':
0d91c12a 1060 if (pref_panel_visible)
3b15348c 1061 update_preference_panel(&pref_line_selected, 0, 1);
1fc22eb4
JD
1062 break;
1063
1064 case 13: /* FIXME : KEY_ENTER ?? */
041aa219
JD
1065 if (current_view != process_details) {
1066 previous_view = current_view;
1fc22eb4 1067 current_view = process_details;
041aa219
JD
1068 } else {
1069 current_view = previous_view;
1070 previous_view = process_details;
1fc22eb4
JD
1071 }
1072 update_current_view();
1073 break;
1074
1075 case KEY_F(1):
3b15348c
JD
1076 if (pref_panel_visible)
1077 toggle_pref_panel();
1fc22eb4 1078 current_view = cpu;
af54ebcf 1079 selected_line = 0;
1fc22eb4
JD
1080 update_current_view();
1081 break;
1082 case KEY_F(2):
3b15348c
JD
1083 if (pref_panel_visible)
1084 toggle_pref_panel();
1fc22eb4 1085 current_view = cpu;
af54ebcf 1086 selected_line = 0;
1fc22eb4
JD
1087 update_current_view();
1088 break;
1089 case KEY_F(3):
3b15348c
JD
1090 if (pref_panel_visible)
1091 toggle_pref_panel();
1fc22eb4 1092 current_view = perf;
af54ebcf 1093 selected_line = 0;
1fc22eb4
JD
1094 update_current_view();
1095 break;
1096 case KEY_F(4):
3b15348c
JD
1097 if (pref_panel_visible)
1098 toggle_pref_panel();
1fc22eb4 1099 current_view = iostream;
af54ebcf 1100 selected_line = 0;
1fc22eb4
JD
1101 update_current_view();
1102 break;
1103 case KEY_F(10):
1104 case 'q':
1105 reset_ncurses();
1106 break;
1107 case 't':
1108 toggle_threads *= -1;
1109 update_current_view();
1110 break;
1111 case 'p':
1112 if (toggle_pause < 0) {
1113 pause_display();
1114 } else {
1115 resume_display();
1116 }
1117 break;
1118 case 'P':
0d91c12a 1119 toggle_pref_panel();
1fc22eb4
JD
1120 break;
1121 default:
b093de8a
MB
1122 if (data)
1123 update_current_view();
1fc22eb4
JD
1124 break;
1125 }
1126 update_footer();
1127 }
1128 return NULL;
1129}
1130
1131void init_ncurses()
1132{
635dc837 1133 selected_processes = g_ptr_array_new();
1fc22eb4
JD
1134 sem_init(&update_display_sem, 0, 1);
1135 init_screen();
1136
dc8f04dd
JD
1137 header = create_window(5, COLS - 1, 0, 0);
1138 center = create_window(LINES - 5 - 7, COLS - 1, 5, 0);
1fc22eb4
JD
1139 status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
1140 footer = create_window(1, COLS - 1, LINES - 1, 0);
1141
3b15348c
JD
1142 cputopview[0].title = strdup("CPU(%)");
1143 cputopview[0].sort = 1;
1144 cputopview[1].title = strdup("TGID");
1145 cputopview[2].title = strdup("PID");
1146 cputopview[3].title = strdup("NAME");
1fc22eb4
JD
1147 print_log("Starting display");
1148
1149 main_panel = new_panel(center);
1fc22eb4
JD
1150
1151 current_view = cpu;
1152
1153 basic_header();
1154 update_footer();
1155
1156 pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
1157}
This page took 0.07467 seconds and 4 git commands to generate.