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