97069fe10299347334db8104ca36a45dc233112e
[lttngtop.git] / src / cursesdisplay.c
1 /*
2 * Copyright (C) 2011-2012 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 *
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.
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"
29 #include "iostreamtop.h"
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 */
37 sem_t update_display_sem;
38
39 char *termtype;
40 WINDOW *footer, *header, *center, *status;
41 WINDOW *pref_panel_window = NULL;
42 PANEL *pref_panel, *main_panel;
43
44 int pref_panel_visible = 0;
45 int pref_line_selected = 0;
46 int pref_current_sort = 0;
47
48 int last_display_index, currently_displayed_index;
49
50 struct processtop *selected_process = NULL;
51 int selected_ret;
52
53 int selected_line = 0; /* select bar position */
54 int selected_in_list = 0; /* selection relative to the whole list */
55 int list_offset = 0; /* first index in the list to display (scroll) */
56 int nb_log_lines = 0;
57 char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES];
58
59 int max_elements = 80;
60
61 int toggle_threads = 1;
62 int toggle_virt = -1;
63 int toggle_pause = -1;
64
65 int max_center_lines;
66 GPtrArray *selected_processes;
67
68 pthread_t keyboard_thread;
69
70 struct header_view cputopview[6];
71 struct header_view iostreamtopview[3];
72 struct header_view fileview[3];
73
74 void reset_ncurses()
75 {
76 curs_set(1);
77 endwin();
78 quit = 1;
79 sem_post(&pause_sem);
80 sem_post(&timer);
81 sem_post(&goodtodisplay);
82 sem_post(&end_trace_sem);
83 sem_post(&goodtoupdate);
84 }
85
86 static void handle_sigterm(int signal)
87 {
88 pthread_cancel(keyboard_thread);
89 reset_ncurses();
90 }
91
92 void init_screen()
93 {
94 initscr();
95 noecho();
96 halfdelay(DEFAULT_DELAY);
97 nonl();
98 intrflush(stdscr, false);
99 keypad(stdscr, true);
100 curs_set(0);
101
102 if (has_colors()) {
103 start_color();
104 init_pair(1, COLOR_RED, COLOR_BLACK); /* - */
105 init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */
106 init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */
107 init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */
108 init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */
109 init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */
110 }
111 termtype = getenv("TERM");
112 if (!strcmp(termtype, "xterm") || !strcmp(termtype, "xterm-color") ||
113 !strcmp(termtype, "vt220")) {
114 define_key("\033[H", KEY_HOME);
115 define_key("\033[F", KEY_END);
116 define_key("\033OP", KEY_F(1));
117 define_key("\033OQ", KEY_F(2));
118 define_key("\033OR", KEY_F(3));
119 define_key("\033OS", KEY_F(4));
120 define_key("\0330U", KEY_F(6));
121 define_key("\033[11~", KEY_F(1));
122 define_key("\033[12~", KEY_F(2));
123 define_key("\033[13~", KEY_F(3));
124 define_key("\033[14~", KEY_F(4));
125 define_key("\033[16~", KEY_F(6));
126 define_key("\033[17;2~", KEY_F(18));
127 }
128 signal(SIGTERM, handle_sigterm);
129 signal(SIGINT, handle_sigterm);
130 mousemask(BUTTON1_CLICKED, NULL);
131 refresh();
132 }
133
134 WINDOW *create_window(int height, int width, int startx, int starty)
135 {
136 WINDOW *win;
137 win = newwin(height, width, startx, starty);
138 box(win, 0 , 0);
139 wrefresh(win);
140 return win;
141 }
142
143 WINDOW *create_window_no_border(int height, int width, int startx, int starty)
144 {
145 WINDOW *win;
146 win = newwin(height, width, startx, starty);
147 wrefresh(win);
148 return win;
149 }
150
151 void print_digit(WINDOW *win, int digit)
152 {
153 if (digit < 0) {
154 wattron(win, COLOR_PAIR(1));
155 wprintw(win, "%d", digit);
156 wattroff(win, COLOR_PAIR(1));
157 } else if (digit > 0) {
158 wattron(win, COLOR_PAIR(2));
159 wprintw(win, "+%d", digit);
160 wattroff(win, COLOR_PAIR(2));
161 } else {
162 wprintw(win, "0");
163 }
164 }
165
166 void print_digits(WINDOW *win, int first, int second)
167 {
168 wprintw(win, "(");
169 print_digit(win, first);
170 wprintw(win, ", ");
171 print_digit(win, second);
172 wprintw(win, ")");
173 }
174
175 void print_headers(int line, char *desc, int value, int first, int second)
176 {
177 wattron(header, A_BOLD);
178 mvwprintw(header, line, 4, "%s", desc);
179 wattroff(header, A_BOLD);
180 mvwprintw(header, line, 16, "%d", value);
181 wmove(header, line, 24);
182 print_digits(header, first, second);
183 wmove(header, line, 40);
184 }
185
186 void set_window_title(WINDOW *win, char *title)
187 {
188 wattron(win, A_BOLD);
189 mvwprintw(win, 0, 1, title);
190 wattroff(win, A_BOLD);
191 }
192
193 void print_log(char *str)
194 {
195 int i;
196 int current_line = 1;
197 int current_char = 1;
198 char *tmp, *tmp2;
199 /* rotate the line buffer */
200 if (nb_log_lines >= MAX_LOG_LINES) {
201 tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES);
202 tmp2 = strchr(tmp, '\n');
203 memset(log_lines, '\0', strlen(log_lines));
204 strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1);
205 log_lines[strlen(log_lines)] = '\n';
206 log_lines[strlen(log_lines)] = '\0';
207 free(tmp);
208 }
209 nb_log_lines++;
210
211 strncat(log_lines, str, MAX_LINE_LENGTH - 1);
212
213 if (nb_log_lines < MAX_LOG_LINES)
214 log_lines[strlen(log_lines)] = '\n';
215 log_lines[strlen(log_lines)] = '\0';
216
217 werase(status);
218 box(status, 0 , 0);
219 set_window_title(status, "Status");
220 for (i = 0; i < strlen(log_lines); i++) {
221 if (log_lines[i] == '\n') {
222 wmove(status, ++current_line, 1);
223 current_char = 1;
224 } else {
225 mvwprintw(status, current_line, current_char++, "%c",
226 log_lines[i]);
227 }
228 }
229 wrefresh(status);
230 }
231
232 int process_selected(struct processtop *process)
233 {
234 int i;
235 struct processtop *stored_process;
236
237 for (i = 0; i < selected_processes->len; i++) {
238 stored_process = g_ptr_array_index(selected_processes, i);
239 if (!stored_process)
240 return 0;
241 if (stored_process->tid == process->tid)
242 return 1;
243 }
244 return 0;
245 }
246
247 void update_selected_processes()
248 {
249 int i;
250 struct processtop *stored_process;
251
252 if (process_selected(selected_process)) {
253 for (i = 0; i < selected_processes->len; i++) {
254 stored_process = g_ptr_array_index(selected_processes, i);
255 if (!stored_process)
256 return;
257 if (stored_process->tid == selected_process->tid)
258 g_ptr_array_remove(selected_processes,
259 stored_process);
260 print_log("Process removed");
261 }
262 } else {
263 g_ptr_array_add(selected_processes, selected_process);
264 print_log("Process added");
265 }
266 }
267
268 void print_key(WINDOW *win, char *key, char *desc, int toggle)
269 {
270 int pair;
271 if (toggle > 0)
272 pair = 4;
273 else
274 pair = 3;
275 wattron(win, COLOR_PAIR(pair));
276 wprintw(footer, "%s", key);
277 wattroff(win, COLOR_PAIR(pair));
278 wprintw(footer, ":%s", desc);
279 }
280
281 void update_footer()
282 {
283 sem_wait(&update_display_sem);
284 werase(footer);
285 wmove(footer, 1, 1);
286 print_key(footer, "F2", "CPUtop ", current_view == cpu);
287 print_key(footer, "F3", "PerfTop ", current_view == perf);
288 print_key(footer, "F4", "IOTop ", current_view == iostream);
289 print_key(footer, "Enter", "Details ", current_view == process_details);
290 print_key(footer, "Space", "Highlight ", 0);
291 print_key(footer, "q", "Quit ", 0);
292 print_key(footer, "r", "Pref ", 0);
293 print_key(footer, "t", "Threads ", toggle_threads);
294 print_key(footer, "v", "Virt ", toggle_virt);
295 print_key(footer, "p", "Pause ", toggle_pause);
296
297 wrefresh(footer);
298 sem_post(&update_display_sem);
299 }
300
301 void basic_header()
302 {
303 werase(header);
304 box(header, 0 , 0);
305 set_window_title(header, "Statistics for interval [gathering data...[");
306 wattron(header, A_BOLD);
307 mvwprintw(header, 1, 4, "CPUs");
308 mvwprintw(header, 2, 4, "Threads");
309 mvwprintw(header, 3, 4, "FDs");
310 wattroff(header, A_BOLD);
311 wrefresh(header);
312 }
313
314 static void scale_unit(uint64_t bytes, char *ret)
315 {
316 if (bytes >= 1000000000)
317 sprintf(ret, "%" PRIu64 "G", bytes/1000000000);
318 if (bytes >= 1000000)
319 sprintf(ret, "%" PRIu64 "M", bytes/1000000);
320 else if (bytes >= 1000)
321 sprintf(ret, "%" PRIu64 "K", bytes/1000);
322 else
323 sprintf(ret, "%" PRIu64, bytes);
324 }
325
326 uint64_t total_io()
327 {
328 int i;
329 struct processtop *tmp;
330 uint64_t total = 0;
331
332 for (i = 0; i < data->process_table->len; i++) {
333 tmp = g_ptr_array_index(data->process_table, i);
334 total += tmp->fileread;
335 total += tmp->filewrite;
336 }
337
338 return total;
339 }
340
341 void update_header()
342 {
343 struct tm start, end;
344 uint64_t ts_nsec_start, ts_nsec_end;
345 char io[4];
346
347 ts_nsec_start = data->start % NSEC_PER_SEC;
348 start = format_timestamp(data->start);
349
350 ts_nsec_end = data->end % NSEC_PER_SEC;
351 end = format_timestamp(data->end);
352
353 werase(header);
354 box(header, 0 , 0);
355 set_window_title(header, "Statistics for interval ");
356 wattron(header, A_BOLD);
357
358 wprintw(header, "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[",
359 start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start,
360 end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_end);
361 mvwprintw(header, 1, 4, "CPUs");
362 wattroff(header, A_BOLD);
363 wprintw(header, "\t%d\t(max/cpu : %0.2f%)", data->cpu_table->len,
364 100.0/data->cpu_table->len);
365 print_headers(2, "Threads", data->nbthreads, data->nbnewthreads,
366 -1*(data->nbdeadthreads));
367 print_headers(3, "FDs", data->nbfiles, data->nbnewfiles,
368 -1*(data->nbclosedfiles));
369 scale_unit(total_io(), io);
370 mvwprintw(header, 3, 43, "%sB/sec", io);
371 wrefresh(header);
372 }
373
374 gint sort_by_cpu_desc(gconstpointer p1, gconstpointer p2)
375 {
376 struct processtop *n1 = *(struct processtop **)p1;
377 struct processtop *n2 = *(struct processtop **)p2;
378 unsigned long totaln1 = n1->totalcpunsec;
379 unsigned long totaln2 = n2->totalcpunsec;
380
381 if (totaln1 < totaln2)
382 return 1;
383 if (totaln1 == totaln2)
384 return 0;
385 return -1;
386 }
387
388 gint sort_by_tid_desc(gconstpointer p1, gconstpointer p2)
389 {
390 struct processtop *n1 = *(struct processtop **)p1;
391 struct processtop *n2 = *(struct processtop **)p2;
392 unsigned long totaln1 = n1->tid;
393 unsigned long totaln2 = n2->tid;
394
395 if (totaln1 < totaln2)
396 return 1;
397 if (totaln1 == totaln2)
398 return 0;
399 return -1;
400 }
401
402 gint sort_by_pid_desc(gconstpointer p1, gconstpointer p2)
403 {
404 struct processtop *n1 = *(struct processtop **)p1;
405 struct processtop *n2 = *(struct processtop **)p2;
406 unsigned long totaln1 = n1->pid;
407 unsigned long totaln2 = n2->pid;
408
409 if (totaln1 < totaln2)
410 return 1;
411 if (totaln1 == totaln2)
412 return 0;
413 return -1;
414 }
415
416 gint sort_by_process_read_desc(gconstpointer p1, gconstpointer p2)
417 {
418 struct processtop *n1 = *(struct processtop **)p1;
419 struct processtop *n2 = *(struct processtop **)p2;
420 unsigned long totaln1 = n1->fileread;
421 unsigned long totaln2 = n2->fileread;
422
423 if (totaln1 < totaln2)
424 return 1;
425 if (totaln1 == totaln2)
426 return 0;
427 return -1;
428 }
429
430 gint sort_by_process_write_desc(gconstpointer p1, gconstpointer p2)
431 {
432 struct processtop *n1 = *(struct processtop **)p1;
433 struct processtop *n2 = *(struct processtop **)p2;
434 unsigned long totaln1 = n1->filewrite;
435 unsigned long totaln2 = n2->filewrite;
436
437 if (totaln1 < totaln2)
438 return 1;
439 if (totaln1 == totaln2)
440 return 0;
441 return -1;
442 }
443
444 gint sort_by_process_total_desc(gconstpointer p1, gconstpointer p2)
445 {
446 struct processtop *n1 = *(struct processtop **)p1;
447 struct processtop *n2 = *(struct processtop **)p2;
448 unsigned long totaln1 = n1->totalfilewrite + n1->totalfileread;
449 unsigned long totaln2 = n2->totalfilewrite + n2->totalfileread;
450
451 if (totaln1 < totaln2)
452 return 1;
453 if (totaln1 == totaln2)
454 return 0;
455 return -1;
456 }
457
458 gint sort_by_file_read_desc(gconstpointer p1, gconstpointer p2)
459 {
460 struct files *n1 = *(struct files **)p1;
461 struct files *n2 = *(struct files **)p2;
462 unsigned long totaln1;
463 unsigned long totaln2;
464
465 totaln1 = n1->read;
466 totaln2 = n2->read;
467
468 if (totaln1 < totaln2)
469 return 1;
470 if (totaln1 == totaln2)
471 return 0;
472 return -1;
473 }
474
475 gint sort_by_file_write_desc(gconstpointer p1, gconstpointer p2)
476 {
477 struct files *n1 = *(struct files **)p1;
478 struct files *n2 = *(struct files **)p2;
479 unsigned long totaln1;
480 unsigned long totaln2;
481
482 totaln1 = n1->write;
483 totaln2 = n2->write;
484
485 if (totaln1 < totaln2)
486 return 1;
487 if (totaln1 == totaln2)
488 return 0;
489 return -1;
490 }
491
492 gint sort_by_file_fd_desc(gconstpointer p1, gconstpointer p2)
493 {
494 struct files *n1 = *(struct files **)p1;
495 struct files *n2 = *(struct files **)p2;
496 unsigned long totaln1;
497 unsigned long totaln2;
498
499 totaln1 = n1->fd;
500 totaln2 = n2->fd;
501
502 if (totaln1 < totaln2)
503 return 1;
504 if (totaln1 == totaln2)
505 return 0;
506 return -1;
507 }
508
509 gint sort_by_cpu_group_by_threads_desc(gconstpointer p1, gconstpointer p2)
510 {
511 struct processtop *n1 = *(struct processtop **)p1;
512 struct processtop *n2 = *(struct processtop **)p2;
513 unsigned long totaln1 = n1->threadstotalcpunsec;
514 unsigned long totaln2 = n2->threadstotalcpunsec;
515
516 if (totaln1 < totaln2)
517 return 1;
518 if (totaln1 == totaln2)
519 return 0;
520 return -1;
521 }
522
523 void update_kprobes_display()
524 {
525 int i, column;
526
527 set_window_title(center, "Kprobes Top");
528 /*
529 wattron(center, A_BOLD);
530 column = 1;
531 for (i = 0; i < 6; i++) {
532 if (toggle_virt < 0 && (i == 3 || i == 4)) {
533 continue;
534 }
535 if (cputopview[i].sort) {
536 wattron(center, A_UNDERLINE);
537 pref_current_sort = i;
538 }
539 mvwprintw(center, 1, column, cputopview[i].title);
540 wattroff(center, A_UNDERLINE);
541 column += 10;
542 }
543 wattroff(center, A_BOLD);
544 */
545 }
546
547 void update_cputop_display()
548 {
549 int i;
550 int header_offset = 2;
551 struct processtop *tmp;
552 unsigned long elapsed;
553 double maxcputime;
554 int nblinedisplayed = 0;
555 int current_line = 0;
556 int current_row_offset;
557 int column;
558
559 elapsed = data->end - data->start;
560 maxcputime = elapsed * data->cpu_table->len / 100.0;
561
562 if (cputopview[0].sort == 1)
563 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
564 else if (cputopview[1].sort == 1)
565 g_ptr_array_sort(data->process_table, sort_by_pid_desc);
566 else if (cputopview[2].sort == 1)
567 g_ptr_array_sort(data->process_table, sort_by_tid_desc);
568 else if (cputopview[3].sort == 1)
569 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
570 else
571 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
572
573 set_window_title(center, "CPU Top");
574 wattron(center, A_BOLD);
575 column = 1;
576 for (i = 0; i < 6; i++) {
577 if (toggle_virt < 0 && (i == 3 || i == 4)) {
578 continue;
579 }
580 if (cputopview[i].sort) {
581 wattron(center, A_UNDERLINE);
582 pref_current_sort = i;
583 }
584 mvwprintw(center, 1, column, cputopview[i].title);
585 wattroff(center, A_UNDERLINE);
586 column += 10;
587 }
588 wattroff(center, A_BOLD);
589
590 max_center_lines = LINES - 5 - 7 - 1 - header_offset;
591
592 /* iterate the process (thread) list */
593 for (i = list_offset; i < data->process_table->len &&
594 nblinedisplayed < max_center_lines; i++) {
595 tmp = g_ptr_array_index(data->process_table, i);
596 current_row_offset = 1;
597 if (!opt_tid && (opt_hostname && !lookup_hostname_list(tmp->hostname)))
598 continue;
599 if (!opt_hostname && (opt_tid && !lookup_tid_list(tmp->pid)))
600 continue;
601 if ((opt_tid && !lookup_tid_list(tmp->tid)) &&
602 (opt_hostname && !lookup_hostname_list(tmp->hostname)))
603 continue;
604
605 if (tmp->pid != tmp->tid)
606 if (toggle_threads == -1)
607 continue;
608
609 if (process_selected(tmp)) {
610 wattron(center, COLOR_PAIR(6));
611 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
612 }
613 if (current_line == selected_line) {
614 selected_process = tmp;
615 wattron(center, COLOR_PAIR(5));
616 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
617 }
618 /* CPU(%) */
619 mvwprintw(center, current_line + header_offset,
620 current_row_offset, "%1.2f",
621 tmp->totalcpunsec / maxcputime);
622 current_row_offset += 10;
623 /* PID */
624 mvwprintw(center, current_line + header_offset,
625 current_row_offset, "%d", tmp->pid);
626 current_row_offset += 10;
627 /* TID */
628 mvwprintw(center, current_line + header_offset,
629 current_row_offset, "%d", tmp->tid);
630 current_row_offset += 10;
631 if (toggle_virt > 0) {
632 /* VPID */
633 mvwprintw(center, current_line + header_offset,
634 current_row_offset, "%d", tmp->vpid);
635 current_row_offset += 10;
636 /* VTID */
637 mvwprintw(center, current_line + header_offset,
638 current_row_offset, "%d", tmp->vtid);
639 current_row_offset += 10;
640 }
641 /* NAME */
642 mvwprintw(center, current_line + header_offset,
643 current_row_offset, "%s", tmp->comm);
644 wattroff(center, COLOR_PAIR(6));
645 wattroff(center, COLOR_PAIR(5));
646 nblinedisplayed++;
647 current_line++;
648 }
649 }
650
651 gint sort_perf(gconstpointer p1, gconstpointer p2, gpointer key)
652 {
653 struct processtop *n1 = *(struct processtop **) p1;
654 struct processtop *n2 = *(struct processtop **) p2;
655
656 struct perfcounter *tmp1, *tmp2;
657 unsigned long totaln2 = 0;
658 unsigned long totaln1 = 0;
659
660 if (!key)
661 return 0;
662
663 tmp1 = g_hash_table_lookup(n1->perf, key);
664 if (!tmp1)
665 totaln1 = 0;
666 else
667 totaln1 = tmp1->count;
668
669 tmp2 = g_hash_table_lookup(n2->perf, key);
670 if (!tmp2)
671 totaln2 = 0;
672 else
673 totaln2 = tmp2->count;
674
675 if (totaln1 < totaln2)
676 return 1;
677 if (totaln1 == totaln2) {
678 totaln1 = n1->tid;
679 totaln2 = n2->tid;
680 if (totaln1 < totaln2)
681 return 1;
682 return -1;
683 }
684 return -1;
685 }
686
687 void print_key_title(char *key, int line)
688 {
689 wattron(center, A_BOLD);
690 mvwprintw(center, line, 1, "%s", key);
691 mvwprintw(center, line, 30, " ");
692 wattroff(center, A_BOLD);
693 }
694
695 void update_process_details()
696 {
697 unsigned long elapsed;
698 double maxcputime;
699 struct processtop *tmp;
700 struct files *file_tmp;
701 int i, j = 0;
702 char unit[4];
703 char filename_buf[COLS];
704 int line = 1;
705 int column;
706 GPtrArray *newfilearray = g_ptr_array_new();
707 GHashTableIter iter;
708 struct perfcounter *perfn1, *perfn2;
709 gpointer key;
710
711 set_window_title(center, "Process details");
712
713
714 tmp = find_process_tid(data,
715 selected_process->tid,
716 selected_process->comm);
717 elapsed = data->end - data->start;
718 maxcputime = elapsed * data->cpu_table->len / 100.0;
719
720 print_key_title("Name", line++);
721 wprintw(center, "%s", selected_process->comm);
722 print_key_title("TID", line++);
723 wprintw(center, "%d", selected_process->tid);
724 if (!tmp) {
725 print_key_title("Does not exit at this time", 3);
726 return;
727 }
728
729 print_key_title("PID", line++);
730 wprintw(center, "%d", tmp->pid);
731 print_key_title("PPID", line++);
732 wprintw(center, "%d", tmp->ppid);
733 print_key_title("VPID", line++);
734 wprintw(center, "%d", tmp->vpid);
735 print_key_title("VTID", line++);
736 wprintw(center, "%d", tmp->vtid);
737 print_key_title("VPPID", line++);
738 wprintw(center, "%d", tmp->vppid);
739 print_key_title("CPU", line++);
740 wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
741
742 print_key_title("READ B/s", line++);
743 scale_unit(tmp->fileread, unit);
744 wprintw(center, "%s", unit);
745
746 print_key_title("WRITE B/s", line++);
747 scale_unit(tmp->filewrite, unit);
748 wprintw(center, "%s", unit);
749
750 g_hash_table_iter_init(&iter, global_perf_liszt);
751 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
752 print_key_title((char *) key, line++);
753 perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
754 wprintw(center, "%d", perfn2 ? perfn2->count : 0);
755 }
756 line++;
757
758 wattron(center, A_BOLD);
759 column = 1;
760 for (i = 0; i < 3; i++) {
761 if (fileview[i].sort) {
762 pref_current_sort = i;
763 wattron(center, A_UNDERLINE);
764 }
765 mvwprintw(center, line, column, fileview[i].title);
766 wattroff(center, A_UNDERLINE);
767 column += 10;
768 }
769 mvwprintw(center, line++, column, "FILENAME");
770 wattroff(center, A_BOLD);
771
772 /*
773 * since the process_files_table array could contain NULL file structures,
774 * and that the positions inside the array is important (it is the FD), we
775 * need to create a temporary array that we can sort.
776 */
777 for (i = 0; i < tmp->process_files_table->len; i++) {
778 file_tmp = g_ptr_array_index(tmp->process_files_table, i);
779 if (file_tmp)
780 g_ptr_array_add(newfilearray, file_tmp);
781 }
782
783 if (fileview[0].sort == 1)
784 g_ptr_array_sort(newfilearray, sort_by_file_fd_desc);
785 else if (fileview[1].sort == 1)
786 g_ptr_array_sort(newfilearray, sort_by_file_read_desc);
787 else if (fileview[2].sort == 1)
788 g_ptr_array_sort(newfilearray, sort_by_file_write_desc);
789 else
790 g_ptr_array_sort(newfilearray, sort_by_file_read_desc);
791
792 for (i = selected_line; i < newfilearray->len &&
793 i < (selected_line + max_center_lines - line + 2); i++) {
794 file_tmp = g_ptr_array_index(newfilearray, i);
795 if (!file_tmp)
796 continue;
797 mvwprintw(center, line + j, 1, "%d", file_tmp->fd);
798 scale_unit(file_tmp->read, unit);
799 mvwprintw(center, line + j, 11, "%s", unit);
800 scale_unit(file_tmp->write, unit);
801 mvwprintw(center, line + j, 21, "%s", unit);
802 snprintf(filename_buf, COLS - 25, "%s", file_tmp->name);
803 mvwprintw(center, line + j, 31, "%s", filename_buf);
804 j++;
805 }
806 g_ptr_array_free(newfilearray, TRUE);
807 }
808
809 void update_perf()
810 {
811 int i;
812 int nblinedisplayed = 0;
813 int current_line = 0;
814 struct processtop *tmp;
815 int header_offset = 2;
816 int perf_row = 40;
817 struct perfcounter *perfn1, *perfn2;
818 char *perf_key = NULL;
819 int value;
820 GHashTableIter iter;
821 gpointer key;
822
823 set_window_title(center, "Perf Top");
824 wattron(center, A_BOLD);
825 mvwprintw(center, 1, 1, "PID");
826 mvwprintw(center, 1, 11, "TID");
827 mvwprintw(center, 1, 22, "NAME");
828
829 perf_row = 40;
830 g_hash_table_iter_init(&iter, global_perf_liszt);
831 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
832 if (perfn1->visible) {
833 if (perfn1->sort) {
834 /* pref_current_sort = i; */
835 wattron(center, A_UNDERLINE);
836 }
837 /* + 5 to strip the "perf_" prefix */
838 mvwprintw(center, 1, perf_row, "%s",
839 (char *) key + 5);
840 wattroff(center, A_UNDERLINE);
841 perf_row += 20;
842 }
843 if (perfn1->sort) {
844 perf_key = (char *) key;
845 }
846 }
847 wattroff(center, A_BOLD);
848
849 g_ptr_array_sort_with_data(data->process_table, sort_perf, perf_key);
850
851 for (i = 0; i < data->process_table->len &&
852 nblinedisplayed < max_center_lines; i++) {
853 tmp = g_ptr_array_index(data->process_table, i);
854
855 if (!opt_tid && (opt_hostname && !lookup_hostname_list(tmp->hostname)))
856 continue;
857 if (!opt_hostname && (opt_tid && !lookup_tid_list(tmp->pid)))
858 continue;
859 if ((opt_tid && !lookup_tid_list(tmp->tid)) &&
860 (opt_hostname && !lookup_hostname_list(tmp->hostname)))
861 continue;
862
863 if (tmp->pid != tmp->tid)
864 if (toggle_threads == -1)
865 continue;
866
867 if (process_selected(tmp)) {
868 wattron(center, COLOR_PAIR(6));
869 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
870 }
871 if (current_line == selected_line) {
872 selected_process = tmp;
873 wattron(center, COLOR_PAIR(5));
874 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
875 }
876
877 mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
878 mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
879 mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
880
881 g_hash_table_iter_init(&iter, global_perf_liszt);
882
883 perf_row = 40;
884 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
885 if (perfn1->visible) {
886 perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
887 if (perfn2)
888 value = perfn2->count;
889 else
890 value = 0;
891 mvwprintw(center, current_line + header_offset,
892 perf_row, "%d", value);
893 perf_row += 20;
894 }
895 }
896
897 wattroff(center, COLOR_PAIR(6));
898 wattroff(center, COLOR_PAIR(5));
899 nblinedisplayed++;
900 current_line++;
901 }
902 }
903
904 void update_iostream()
905 {
906 int i;
907 int header_offset = 2;
908 struct processtop *tmp;
909 int nblinedisplayed = 0;
910 int current_line = 0;
911 int total = 0;
912 char unit[4];
913 int column;
914
915 set_window_title(center, "IO Top");
916 wattron(center, A_BOLD);
917 mvwprintw(center, 1, 1, "PID");
918 mvwprintw(center, 1, 11, "TID");
919 mvwprintw(center, 1, 22, "NAME");
920 column = 40;
921 for (i = 0; i < 3; i++) {
922 if (iostreamtopview[i].sort) {
923 pref_current_sort = i;
924 wattron(center, A_UNDERLINE);
925 }
926 mvwprintw(center, 1, column, iostreamtopview[i].title);
927 wattroff(center, A_UNDERLINE);
928 column += 12;
929 }
930 wattroff(center, A_BOLD);
931 wattroff(center, A_UNDERLINE);
932
933 if (iostreamtopview[0].sort == 1)
934 g_ptr_array_sort(data->process_table, sort_by_process_read_desc);
935 else if (iostreamtopview[1].sort == 1)
936 g_ptr_array_sort(data->process_table, sort_by_process_write_desc);
937 else if (iostreamtopview[2].sort == 1)
938 g_ptr_array_sort(data->process_table, sort_by_process_total_desc);
939 else
940 g_ptr_array_sort(data->process_table, sort_by_process_total_desc);
941
942 for (i = list_offset; i < data->process_table->len &&
943 nblinedisplayed < max_center_lines; i++) {
944 tmp = g_ptr_array_index(data->process_table, i);
945
946 if (!opt_tid && (opt_hostname && !lookup_hostname_list(tmp->hostname)))
947 continue;
948 if (!opt_hostname && (opt_tid && !lookup_tid_list(tmp->pid)))
949 continue;
950 if ((opt_tid && !lookup_tid_list(tmp->tid)) &&
951 (opt_hostname && !lookup_hostname_list(tmp->hostname)))
952 continue;
953
954 if (tmp->pid != tmp->tid)
955 if (toggle_threads == -1)
956 continue;
957
958 if (process_selected(tmp)) {
959 wattron(center, COLOR_PAIR(6));
960 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
961 }
962 if (current_line == selected_line) {
963 selected_process = tmp;
964 wattron(center, COLOR_PAIR(5));
965 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
966 }
967 /* TGID */
968 mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
969 /* PID */
970 mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
971 /* NAME */
972 mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
973
974 /* READ (bytes/sec) */
975 scale_unit(tmp->fileread, unit);
976 mvwprintw(center, current_line + header_offset, 40, "%s", unit);
977
978 /* WRITE (bytes/sec) */
979 scale_unit(tmp->filewrite, unit);
980 mvwprintw(center, current_line + header_offset, 52, "%s", unit);
981
982 /* TOTAL STREAM */
983 total = tmp->totalfileread + tmp->totalfilewrite;
984
985 scale_unit(total, unit);
986 mvwprintw(center, current_line + header_offset, 64, "%s", unit);
987
988 wattroff(center, COLOR_PAIR(6));
989 wattroff(center, COLOR_PAIR(5));
990 nblinedisplayed++;
991 current_line++;
992 }
993 }
994
995 void update_current_view()
996 {
997 sem_wait(&update_display_sem);
998 if (!data)
999 return;
1000 update_header();
1001
1002 werase(center);
1003 box(center, 0, 0);
1004 switch (current_view) {
1005 case cpu:
1006 update_cputop_display();
1007 break;
1008 case perf:
1009 update_perf();
1010 break;
1011 case process_details:
1012 update_process_details();
1013 break;
1014 case iostream:
1015 update_iostream();
1016 break;
1017 case tree:
1018 update_cputop_display();
1019 break;
1020 case kprobes:
1021 update_kprobes_display();
1022 break;
1023 default:
1024 break;
1025 }
1026 update_panels();
1027 doupdate();
1028 sem_post(&update_display_sem);
1029 }
1030
1031 void update_process_detail_sort(int *line_selected)
1032 {
1033 int i;
1034 int size;
1035
1036 size = 3;
1037
1038 if (*line_selected > (size - 1))
1039 *line_selected = size - 1;
1040 else if (*line_selected < 0)
1041 *line_selected = 0;
1042
1043 if (fileview[*line_selected].sort == 1)
1044 fileview[*line_selected].reverse = 1;
1045 for (i = 0; i < size; i++)
1046 fileview[i].sort = 0;
1047 fileview[*line_selected].sort = 1;
1048 }
1049
1050 void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort)
1051 {
1052 int i;
1053 int size;
1054
1055 if (!data)
1056 return;
1057 if (pref_panel_window) {
1058 del_panel(pref_panel);
1059 delwin(pref_panel_window);
1060 }
1061 size = 3;
1062
1063 pref_panel_window = create_window(size + 2, 30, 10, 10);
1064 pref_panel = new_panel(pref_panel_window);
1065
1066 werase(pref_panel_window);
1067 box(pref_panel_window, 0 , 0);
1068 set_window_title(pref_panel_window, "Process Detail Preferences ");
1069 wattron(pref_panel_window, A_BOLD);
1070 mvwprintw(pref_panel_window, size + 1, 1,
1071 " 's' : sort, space : toggle");
1072 wattroff(pref_panel_window, A_BOLD);
1073
1074 if (*line_selected > (size - 1))
1075 *line_selected = size - 1;
1076 else if (*line_selected < 0)
1077 *line_selected = 0;
1078 if (toggle_sort == 1) {
1079 update_process_detail_sort(line_selected);
1080 update_current_view();
1081 }
1082
1083 for (i = 0; i < size; i++) {
1084 if (i == *line_selected) {
1085 wattron(pref_panel_window, COLOR_PAIR(5));
1086 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1087 }
1088 if (fileview[i].sort == 1)
1089 wattron(pref_panel_window, A_BOLD);
1090 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1091 fileview[i].title);
1092 wattroff(pref_panel_window, A_BOLD);
1093 wattroff(pref_panel_window, COLOR_PAIR(5));
1094
1095 }
1096 update_panels();
1097 doupdate();
1098 }
1099
1100 void update_iostream_sort(int *line_selected)
1101 {
1102 int i;
1103 int size;
1104
1105 size = 3;
1106 if (*line_selected > (size - 1))
1107 *line_selected = size - 1;
1108 else if (*line_selected < 0)
1109 *line_selected = 0;
1110 if (iostreamtopview[*line_selected].sort == 1)
1111 iostreamtopview[*line_selected].reverse = 1;
1112 for (i = 0; i < size; i++)
1113 iostreamtopview[i].sort = 0;
1114 iostreamtopview[*line_selected].sort = 1;
1115
1116 }
1117
1118 void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort)
1119 {
1120 int i;
1121 int size;
1122
1123 if (!data)
1124 return;
1125 if (pref_panel_window) {
1126 del_panel(pref_panel);
1127 delwin(pref_panel_window);
1128 }
1129 size = 3;
1130
1131 pref_panel_window = create_window(size + 2, 30, 10, 10);
1132 pref_panel = new_panel(pref_panel_window);
1133
1134 werase(pref_panel_window);
1135 box(pref_panel_window, 0 , 0);
1136 set_window_title(pref_panel_window, "IOTop Preferences ");
1137 wattron(pref_panel_window, A_BOLD);
1138 mvwprintw(pref_panel_window, size + 1, 1,
1139 " 's' : sort, space : toggle");
1140 wattroff(pref_panel_window, A_BOLD);
1141
1142 if (*line_selected > (size - 1))
1143 *line_selected = size - 1;
1144 else if (*line_selected < 0)
1145 *line_selected = 0;
1146 if (toggle_sort == 1) {
1147 update_iostream_sort(line_selected);
1148 update_current_view();
1149 }
1150
1151 for (i = 0; i < size; i++) {
1152 if (i == *line_selected) {
1153 wattron(pref_panel_window, COLOR_PAIR(5));
1154 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1155 }
1156 if (iostreamtopview[i].sort == 1)
1157 wattron(pref_panel_window, A_BOLD);
1158 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1159 iostreamtopview[i].title);
1160 wattroff(pref_panel_window, A_BOLD);
1161 wattroff(pref_panel_window, COLOR_PAIR(5));
1162
1163 }
1164 update_panels();
1165 doupdate();
1166 }
1167
1168 void update_cpu_sort(int *line_selected)
1169 {
1170 int i;
1171 int size = 3;
1172
1173 if (*line_selected > (size - 1))
1174 *line_selected = size - 1;
1175 else if (*line_selected < 0)
1176 *line_selected = 0;
1177
1178 /* special case, we don't support sorting by procname for now */
1179 if (*line_selected != 3) {
1180 if (cputopview[*line_selected].sort == 1)
1181 cputopview[*line_selected].reverse = 1;
1182 for (i = 0; i < size; i++)
1183 cputopview[i].sort = 0;
1184 cputopview[*line_selected].sort = 1;
1185 }
1186 }
1187
1188 void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
1189 {
1190 int i;
1191 int size;
1192
1193 if (!data)
1194 return;
1195 if (pref_panel_window) {
1196 del_panel(pref_panel);
1197 delwin(pref_panel_window);
1198 }
1199 size = 4;
1200
1201 pref_panel_window = create_window(size + 2, 30, 10, 10);
1202 pref_panel = new_panel(pref_panel_window);
1203
1204 werase(pref_panel_window);
1205 box(pref_panel_window, 0 , 0);
1206 set_window_title(pref_panel_window, "CPUTop Preferences ");
1207 wattron(pref_panel_window, A_BOLD);
1208 mvwprintw(pref_panel_window, size + 1, 1,
1209 " 's' : sort, space : toggle");
1210 wattroff(pref_panel_window, A_BOLD);
1211
1212 if (*line_selected > (size - 1))
1213 *line_selected = size - 1;
1214 else if (*line_selected < 0)
1215 *line_selected = 0;
1216 if (toggle_sort == 1) {
1217 update_cpu_sort(line_selected);
1218 update_current_view();
1219 }
1220
1221 for (i = 0; i < size; i++) {
1222 if (i == *line_selected) {
1223 wattron(pref_panel_window, COLOR_PAIR(5));
1224 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1225 }
1226 if (cputopview[i].sort == 1)
1227 wattron(pref_panel_window, A_BOLD);
1228 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1229 cputopview[i].title);
1230 wattroff(pref_panel_window, A_BOLD);
1231 wattroff(pref_panel_window, COLOR_PAIR(5));
1232
1233 }
1234 update_panels();
1235 doupdate();
1236 }
1237
1238 void update_perf_sort(int *line_selected)
1239 {
1240 int i;
1241 struct perfcounter *perf;
1242 GList *perflist;
1243 int size;
1244
1245 size = g_hash_table_size(global_perf_liszt);
1246 if (*line_selected > (size - 1))
1247 *line_selected = size - 1;
1248 else if (*line_selected < 0)
1249 *line_selected = 0;
1250
1251 i = 0;
1252 perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
1253 while (perflist) {
1254 perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
1255 if (i != *line_selected)
1256 perf->sort = 0;
1257 else
1258 perf->sort = 1;
1259 i++;
1260 perflist = g_list_next(perflist);
1261 }
1262 }
1263
1264 void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
1265 {
1266 int i;
1267 struct perfcounter *perf;
1268 GList *perflist;
1269 int size;
1270
1271 if (!data)
1272 return;
1273 if (pref_panel_window) {
1274 del_panel(pref_panel);
1275 delwin(pref_panel_window);
1276 }
1277 size = g_hash_table_size(global_perf_liszt);
1278
1279 pref_panel_window = create_window(size + 2, 30, 10, 10);
1280 pref_panel = new_panel(pref_panel_window);
1281
1282 werase(pref_panel_window);
1283 box(pref_panel_window, 0 , 0);
1284 set_window_title(pref_panel_window, "Perf Preferences ");
1285 wattron(pref_panel_window, A_BOLD);
1286 mvwprintw(pref_panel_window, g_hash_table_size(global_perf_liszt) + 1, 1,
1287 " 's' : sort, space : toggle");
1288 wattroff(pref_panel_window, A_BOLD);
1289
1290 if (*line_selected > (size - 1))
1291 *line_selected = size - 1;
1292 else if (*line_selected < 0)
1293 *line_selected = 0;
1294
1295 if (toggle_sort == 1) {
1296 update_perf_sort(line_selected);
1297 update_current_view();
1298 }
1299
1300 i = 0;
1301 perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
1302 while (perflist) {
1303 perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
1304 if (i == *line_selected && toggle_view == 1) {
1305 perf->visible = perf->visible == 1 ? 0:1;
1306 update_current_view();
1307 }
1308 if (i == *line_selected) {
1309 wattron(pref_panel_window, COLOR_PAIR(5));
1310 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1311 }
1312 if (perf->sort == 1)
1313 wattron(pref_panel_window, A_BOLD);
1314 mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
1315 perf->visible == 1 ? 'x' : ' ',
1316 (char *) perflist->data + 5);
1317 wattroff(pref_panel_window, A_BOLD);
1318 wattroff(pref_panel_window, COLOR_PAIR(5));
1319 i++;
1320 perflist = g_list_next(perflist);
1321 }
1322 update_panels();
1323 doupdate();
1324 }
1325
1326 int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
1327 {
1328 int ret = 0;
1329
1330 switch(current_view) {
1331 case perf:
1332 update_perf_pref(line_selected, toggle_view, toggle_sort);
1333 break;
1334 case cpu:
1335 update_cpu_pref(line_selected, toggle_view, toggle_sort);
1336 break;
1337 case iostream:
1338 update_iostream_pref(line_selected, toggle_view, toggle_sort);
1339 break;
1340 case process_details:
1341 update_process_detail_pref(line_selected, toggle_view, toggle_sort);
1342 break;
1343 default:
1344 ret = -1;
1345 break;
1346 }
1347
1348 return ret;
1349 }
1350
1351 int update_sort(int *line_selected)
1352 {
1353 int ret = 0;
1354
1355 switch(current_view) {
1356 case perf:
1357 update_perf_sort(line_selected);
1358 break;
1359 case cpu:
1360 update_cpu_sort(line_selected);
1361 break;
1362 case iostream:
1363 update_iostream_sort(line_selected);
1364 break;
1365 case process_details:
1366 update_process_detail_sort(line_selected);
1367 break;
1368 default:
1369 ret = -1;
1370 break;
1371 }
1372
1373 return ret;
1374 }
1375
1376
1377 void toggle_pref_panel(void)
1378 {
1379 int ret;
1380
1381 if (pref_panel_visible) {
1382 hide_panel(pref_panel);
1383 pref_panel_visible = 0;
1384 } else {
1385 ret = update_preference_panel(&pref_line_selected, 0, 0);
1386 if (ret < 0)
1387 return;
1388 show_panel(pref_panel);
1389 pref_panel_visible = 1;
1390 }
1391 update_panels();
1392 doupdate();
1393 }
1394
1395 void display(unsigned int index)
1396 {
1397 last_display_index = index;
1398 currently_displayed_index = index;
1399 data = g_ptr_array_index(copies, index);
1400 if (!data)
1401 return;
1402 max_elements = data->process_table->len;
1403 update_current_view();
1404 update_footer();
1405 update_panels();
1406 doupdate();
1407 }
1408
1409 void pause_display()
1410 {
1411 toggle_pause = 1;
1412 print_log("Pause");
1413 sem_wait(&pause_sem);
1414 }
1415
1416 void resume_display()
1417 {
1418 toggle_pause = -1;
1419 print_log("Resume");
1420 sem_post(&pause_sem);
1421 }
1422
1423 void *handle_keyboard(void *p)
1424 {
1425 int ch;
1426 while((ch = getch())) {
1427 switch(ch) {
1428 /* Move the cursor and scroll */
1429 case 'j':
1430 case KEY_DOWN:
1431 if (pref_panel_visible) {
1432 pref_line_selected++;
1433 update_preference_panel(&pref_line_selected, 0, 0);
1434 } else {
1435 if (selected_line < (max_center_lines - 1) &&
1436 selected_line < max_elements - 1) {
1437 selected_line++;
1438 selected_in_list++;
1439 } else if (selected_in_list < (max_elements - 1)
1440 && (list_offset < (max_elements - max_center_lines))) {
1441 selected_in_list++;
1442 list_offset++;
1443 }
1444 update_current_view();
1445 }
1446 break;
1447 case KEY_NPAGE:
1448 break;
1449 case 'k':
1450 case KEY_UP:
1451 if (pref_panel_visible) {
1452 if (pref_line_selected > 0)
1453 pref_line_selected--;
1454 update_preference_panel(&pref_line_selected, 0, 0);
1455 } else {
1456 if (selected_line > 0) {
1457 selected_line--;
1458 selected_in_list--;
1459 } else if (selected_in_list > 0 && list_offset > 0) {
1460 selected_in_list--;
1461 list_offset--;
1462 }
1463 update_current_view();
1464 }
1465 break;
1466 case KEY_PPAGE:
1467 break;
1468
1469 /* Navigate the history with arrows */
1470 case KEY_LEFT:
1471 if (currently_displayed_index > 0) {
1472 currently_displayed_index--;
1473 print_log("Going back in time");
1474 } else {
1475 print_log("Cannot rewind, last data is already displayed");
1476 }
1477 data = g_ptr_array_index(copies, currently_displayed_index);
1478 max_elements = data->process_table->len;
1479
1480 /* we force to pause the display when moving in time */
1481 if (toggle_pause < 0)
1482 pause_display();
1483
1484 update_current_view();
1485 update_footer();
1486 break;
1487 case KEY_RIGHT:
1488 if (currently_displayed_index < last_display_index) {
1489 currently_displayed_index++;
1490 print_log("Going forward in time");
1491 data = g_ptr_array_index(copies, currently_displayed_index);
1492 max_elements = data->process_table->len;
1493 update_current_view();
1494 update_footer();
1495 } else {
1496 print_log("Manually moving forward");
1497 sem_post(&timer);
1498 if (toggle_pause > 0) {
1499 sem_post(&pause_sem);
1500 update_current_view();
1501 sem_wait(&pause_sem);
1502 }
1503 }
1504
1505 break;
1506 case ' ':
1507 if (pref_panel_visible) {
1508 update_preference_panel(&pref_line_selected, 1, 0);
1509 } else {
1510 update_selected_processes();
1511 update_current_view();
1512 }
1513 break;
1514 case 's':
1515 if (pref_panel_visible)
1516 update_preference_panel(&pref_line_selected, 0, 1);
1517 break;
1518 case '>':
1519 /* perf uses a hashtable, it is ordered backward */
1520 if (current_view == perf) {
1521 pref_current_sort--;
1522 } else if (!pref_panel_visible) {
1523 pref_current_sort++;
1524 }
1525 update_sort(&pref_current_sort);
1526 update_current_view();
1527 break;
1528 case '<':
1529 /* perf uses a hashtable, it is ordered backward */
1530 if (current_view == perf) {
1531 pref_current_sort++;
1532 } else if (!pref_panel_visible) {
1533 pref_current_sort--;
1534 }
1535 update_sort(&pref_current_sort);
1536 update_current_view();
1537 break;
1538
1539 case 13: /* FIXME : KEY_ENTER ?? */
1540 if (pref_panel_visible)
1541 break;
1542 if (current_view != process_details) {
1543 previous_view = current_view;
1544 current_view = process_details;
1545 } else {
1546 current_view = previous_view;
1547 previous_view = process_details;
1548 }
1549 selected_line = 0;
1550 update_current_view();
1551 break;
1552
1553 case KEY_F(1):
1554 if (pref_panel_visible)
1555 toggle_pref_panel();
1556 current_view = cpu;
1557 selected_line = 0;
1558 update_current_view();
1559 break;
1560 case KEY_F(2):
1561 if (pref_panel_visible)
1562 toggle_pref_panel();
1563 current_view = cpu;
1564 selected_line = 0;
1565 update_current_view();
1566 break;
1567 case KEY_F(3):
1568 if (pref_panel_visible)
1569 toggle_pref_panel();
1570 current_view = perf;
1571 selected_line = 0;
1572 update_current_view();
1573 break;
1574 case KEY_F(4):
1575 if (pref_panel_visible)
1576 toggle_pref_panel();
1577 current_view = iostream;
1578 selected_line = 0;
1579 update_current_view();
1580 break;
1581 case KEY_F(5):
1582 if (pref_panel_visible)
1583 toggle_pref_panel();
1584 current_view = kprobes;
1585 selected_line = 0;
1586 update_current_view();
1587 break;
1588 case KEY_F(10):
1589 case 'q':
1590 reset_ncurses();
1591 /* exit keyboard thread */
1592 pthread_exit(0);
1593 break;
1594 case 't':
1595 toggle_threads *= -1;
1596 update_current_view();
1597 break;
1598 case 'p':
1599 if (toggle_pause < 0) {
1600 pause_display();
1601 } else {
1602 resume_display();
1603 }
1604 break;
1605 case 'r':
1606 toggle_pref_panel();
1607 break;
1608 case 'v':
1609 toggle_virt *= -1;
1610 update_current_view();
1611 break;
1612 /* ESCAPE, but slow to process, don't know why */
1613 case 27:
1614 if (pref_panel_visible)
1615 toggle_pref_panel();
1616 else if (current_view == process_details) {
1617 current_view = previous_view;
1618 previous_view = process_details;
1619 }
1620 update_current_view();
1621 break;
1622 default:
1623 if (data)
1624 update_current_view();
1625 break;
1626 }
1627 update_footer();
1628 }
1629 return NULL;
1630 }
1631
1632 void init_view_headers()
1633 {
1634 cputopview[0].title = strdup("CPU(%)");
1635 cputopview[0].sort = 1;
1636 cputopview[1].title = strdup("PID");
1637 cputopview[2].title = strdup("TID");
1638 cputopview[3].title = strdup("VPID");
1639 cputopview[4].title = strdup("VTID");
1640 cputopview[5].title = strdup("NAME");
1641
1642 iostreamtopview[0].title = strdup("R (B/sec)");
1643 iostreamtopview[1].title = strdup("W (B/sec)");
1644 iostreamtopview[2].title = strdup("Total (B)");
1645 iostreamtopview[2].sort = 1;
1646
1647 fileview[0].title = strdup("FD");
1648 fileview[1].title = strdup("READ");
1649 fileview[1].sort = 1;
1650 fileview[2].title = strdup("WRITE");
1651 }
1652
1653 void init_ncurses()
1654 {
1655 selected_processes = g_ptr_array_new();
1656 sem_init(&update_display_sem, 0, 1);
1657 init_view_headers();
1658 init_screen();
1659
1660 header = create_window(5, COLS - 1, 0, 0);
1661 center = create_window(LINES - 5 - 7, COLS - 1, 5, 0);
1662 status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
1663 footer = create_window(1, COLS - 1, LINES - 1, 0);
1664
1665 print_log("Starting display");
1666
1667 main_panel = new_panel(center);
1668
1669 current_view = cpu;
1670
1671 basic_header();
1672 update_footer();
1673
1674 pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
1675 }
This page took 0.107774 seconds and 3 git commands to generate.