filter on hostname
[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_cputop_display()
524 {
525 int i;
526 int header_offset = 2;
527 struct processtop *tmp;
528 unsigned long elapsed;
529 double maxcputime;
530 int nblinedisplayed = 0;
531 int current_line = 0;
532 int current_row_offset;
533 int column;
534
535 elapsed = data->end - data->start;
536 maxcputime = elapsed * data->cpu_table->len / 100.0;
537
538 if (cputopview[0].sort == 1)
539 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
540 else if (cputopview[1].sort == 1)
541 g_ptr_array_sort(data->process_table, sort_by_pid_desc);
542 else if (cputopview[2].sort == 1)
543 g_ptr_array_sort(data->process_table, sort_by_tid_desc);
544 else if (cputopview[3].sort == 1)
545 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
546 else
547 g_ptr_array_sort(data->process_table, sort_by_cpu_desc);
548
549 set_window_title(center, "CPU Top");
550 wattron(center, A_BOLD);
551 column = 1;
552 for (i = 0; i < 6; i++) {
553 if (toggle_virt < 0 && (i == 3 || i == 4)) {
554 continue;
555 }
556 if (cputopview[i].sort) {
557 wattron(center, A_UNDERLINE);
558 pref_current_sort = i;
559 }
560 mvwprintw(center, 1, column, cputopview[i].title);
561 wattroff(center, A_UNDERLINE);
562 column += 10;
563 }
564 wattroff(center, A_BOLD);
565
566 max_center_lines = LINES - 5 - 7 - 1 - header_offset;
567
568 /* iterate the process (thread) list */
569 for (i = list_offset; i < data->process_table->len &&
570 nblinedisplayed < max_center_lines; i++) {
571 tmp = g_ptr_array_index(data->process_table, i);
572 current_row_offset = 1;
573 if (!opt_tid && (opt_hostname && !lookup_hostname_list(tmp->hostname)))
574 continue;
575 if (!opt_hostname && (opt_tid && !lookup_tid_list(tmp->pid)))
576 continue;
577 if ((opt_tid && !lookup_tid_list(tmp->tid)) &&
578 (opt_hostname && !lookup_hostname_list(tmp->hostname)))
579 continue;
580
581 if (tmp->pid != tmp->tid)
582 if (toggle_threads == -1)
583 continue;
584
585 if (process_selected(tmp)) {
586 wattron(center, COLOR_PAIR(6));
587 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
588 }
589 if (current_line == selected_line) {
590 selected_process = tmp;
591 wattron(center, COLOR_PAIR(5));
592 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
593 }
594 /* CPU(%) */
595 mvwprintw(center, current_line + header_offset,
596 current_row_offset, "%1.2f",
597 tmp->totalcpunsec / maxcputime);
598 current_row_offset += 10;
599 /* PID */
600 mvwprintw(center, current_line + header_offset,
601 current_row_offset, "%d", tmp->pid);
602 current_row_offset += 10;
603 /* TID */
604 mvwprintw(center, current_line + header_offset,
605 current_row_offset, "%d", tmp->tid);
606 current_row_offset += 10;
607 if (toggle_virt > 0) {
608 /* VPID */
609 mvwprintw(center, current_line + header_offset,
610 current_row_offset, "%d", tmp->vpid);
611 current_row_offset += 10;
612 /* VTID */
613 mvwprintw(center, current_line + header_offset,
614 current_row_offset, "%d", tmp->vtid);
615 current_row_offset += 10;
616 }
617 /* NAME */
618 mvwprintw(center, current_line + header_offset,
619 current_row_offset, "%s", tmp->comm);
620 wattroff(center, COLOR_PAIR(6));
621 wattroff(center, COLOR_PAIR(5));
622 nblinedisplayed++;
623 current_line++;
624 }
625 }
626
627 gint sort_perf(gconstpointer p1, gconstpointer p2, gpointer key)
628 {
629 struct processtop *n1 = *(struct processtop **) p1;
630 struct processtop *n2 = *(struct processtop **) p2;
631
632 struct perfcounter *tmp1, *tmp2;
633 unsigned long totaln2 = 0;
634 unsigned long totaln1 = 0;
635
636 if (!key)
637 return 0;
638
639 tmp1 = g_hash_table_lookup(n1->perf, key);
640 if (!tmp1)
641 totaln1 = 0;
642 else
643 totaln1 = tmp1->count;
644
645 tmp2 = g_hash_table_lookup(n2->perf, key);
646 if (!tmp2)
647 totaln2 = 0;
648 else
649 totaln2 = tmp2->count;
650
651 if (totaln1 < totaln2)
652 return 1;
653 if (totaln1 == totaln2) {
654 totaln1 = n1->tid;
655 totaln2 = n2->tid;
656 if (totaln1 < totaln2)
657 return 1;
658 return -1;
659 }
660 return -1;
661 }
662
663 void print_key_title(char *key, int line)
664 {
665 wattron(center, A_BOLD);
666 mvwprintw(center, line, 1, "%s", key);
667 mvwprintw(center, line, 30, " ");
668 wattroff(center, A_BOLD);
669 }
670
671 void update_process_details()
672 {
673 unsigned long elapsed;
674 double maxcputime;
675 struct processtop *tmp;
676 struct files *file_tmp;
677 int i, j = 0;
678 char unit[4];
679 char filename_buf[COLS];
680 int line = 1;
681 int column;
682 GPtrArray *newfilearray = g_ptr_array_new();
683 GHashTableIter iter;
684 struct perfcounter *perfn1, *perfn2;
685 gpointer key;
686
687 set_window_title(center, "Process details");
688
689
690 tmp = find_process_tid(data,
691 selected_process->tid,
692 selected_process->comm);
693 elapsed = data->end - data->start;
694 maxcputime = elapsed * data->cpu_table->len / 100.0;
695
696 print_key_title("Name", line++);
697 wprintw(center, "%s", selected_process->comm);
698 print_key_title("TID", line++);
699 wprintw(center, "%d", selected_process->tid);
700 if (!tmp) {
701 print_key_title("Does not exit at this time", 3);
702 return;
703 }
704
705 print_key_title("PID", line++);
706 wprintw(center, "%d", tmp->pid);
707 print_key_title("PPID", line++);
708 wprintw(center, "%d", tmp->ppid);
709 print_key_title("VPID", line++);
710 wprintw(center, "%d", tmp->vpid);
711 print_key_title("VTID", line++);
712 wprintw(center, "%d", tmp->vtid);
713 print_key_title("VPPID", line++);
714 wprintw(center, "%d", tmp->vppid);
715 print_key_title("CPU", line++);
716 wprintw(center, "%1.2f %%", tmp->totalcpunsec/maxcputime);
717
718 print_key_title("READ B/s", line++);
719 scale_unit(tmp->fileread, unit);
720 wprintw(center, "%s", unit);
721
722 print_key_title("WRITE B/s", line++);
723 scale_unit(tmp->filewrite, unit);
724 wprintw(center, "%s", unit);
725
726 g_hash_table_iter_init(&iter, global_perf_liszt);
727 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
728 print_key_title((char *) key, line++);
729 perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
730 wprintw(center, "%d", perfn2 ? perfn2->count : 0);
731 }
732 line++;
733
734 wattron(center, A_BOLD);
735 column = 1;
736 for (i = 0; i < 3; i++) {
737 if (fileview[i].sort) {
738 pref_current_sort = i;
739 wattron(center, A_UNDERLINE);
740 }
741 mvwprintw(center, line, column, fileview[i].title);
742 wattroff(center, A_UNDERLINE);
743 column += 10;
744 }
745 mvwprintw(center, line++, column, "FILENAME");
746 wattroff(center, A_BOLD);
747
748 /*
749 * since the process_files_table array could contain NULL file structures,
750 * and that the positions inside the array is important (it is the FD), we
751 * need to create a temporary array that we can sort.
752 */
753 for (i = 0; i < tmp->process_files_table->len; i++) {
754 file_tmp = g_ptr_array_index(tmp->process_files_table, i);
755 if (file_tmp)
756 g_ptr_array_add(newfilearray, file_tmp);
757 }
758
759 if (fileview[0].sort == 1)
760 g_ptr_array_sort(newfilearray, sort_by_file_fd_desc);
761 else if (fileview[1].sort == 1)
762 g_ptr_array_sort(newfilearray, sort_by_file_read_desc);
763 else if (fileview[2].sort == 1)
764 g_ptr_array_sort(newfilearray, sort_by_file_write_desc);
765 else
766 g_ptr_array_sort(newfilearray, sort_by_file_read_desc);
767
768 for (i = selected_line; i < newfilearray->len &&
769 i < (selected_line + max_center_lines - line + 2); i++) {
770 file_tmp = g_ptr_array_index(newfilearray, i);
771 if (!file_tmp)
772 continue;
773 mvwprintw(center, line + j, 1, "%d", file_tmp->fd);
774 scale_unit(file_tmp->read, unit);
775 mvwprintw(center, line + j, 11, "%s", unit);
776 scale_unit(file_tmp->write, unit);
777 mvwprintw(center, line + j, 21, "%s", unit);
778 snprintf(filename_buf, COLS - 25, "%s", file_tmp->name);
779 mvwprintw(center, line + j, 31, "%s", filename_buf);
780 j++;
781 }
782 g_ptr_array_free(newfilearray, TRUE);
783 }
784
785 void update_perf()
786 {
787 int i;
788 int nblinedisplayed = 0;
789 int current_line = 0;
790 struct processtop *tmp;
791 int header_offset = 2;
792 int perf_row = 40;
793 struct perfcounter *perfn1, *perfn2;
794 char *perf_key = NULL;
795 int value;
796 GHashTableIter iter;
797 gpointer key;
798
799 set_window_title(center, "Perf Top");
800 wattron(center, A_BOLD);
801 mvwprintw(center, 1, 1, "PID");
802 mvwprintw(center, 1, 11, "TID");
803 mvwprintw(center, 1, 22, "NAME");
804
805 perf_row = 40;
806 g_hash_table_iter_init(&iter, global_perf_liszt);
807 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
808 if (perfn1->visible) {
809 if (perfn1->sort) {
810 /* pref_current_sort = i; */
811 wattron(center, A_UNDERLINE);
812 }
813 /* + 5 to strip the "perf_" prefix */
814 mvwprintw(center, 1, perf_row, "%s",
815 (char *) key + 5);
816 wattroff(center, A_UNDERLINE);
817 perf_row += 20;
818 }
819 if (perfn1->sort) {
820 perf_key = (char *) key;
821 }
822 }
823 wattroff(center, A_BOLD);
824
825 g_ptr_array_sort_with_data(data->process_table, sort_perf, perf_key);
826
827 for (i = 0; i < data->process_table->len &&
828 nblinedisplayed < max_center_lines; i++) {
829 tmp = g_ptr_array_index(data->process_table, i);
830
831 if (!opt_tid && (opt_hostname && !lookup_hostname_list(tmp->hostname)))
832 continue;
833 if (!opt_hostname && (opt_tid && !lookup_tid_list(tmp->pid)))
834 continue;
835 if ((opt_tid && !lookup_tid_list(tmp->tid)) &&
836 (opt_hostname && !lookup_hostname_list(tmp->hostname)))
837 continue;
838
839 if (tmp->pid != tmp->tid)
840 if (toggle_threads == -1)
841 continue;
842
843 if (process_selected(tmp)) {
844 wattron(center, COLOR_PAIR(6));
845 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
846 }
847 if (current_line == selected_line) {
848 selected_process = tmp;
849 wattron(center, COLOR_PAIR(5));
850 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
851 }
852
853 mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
854 mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
855 mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
856
857 g_hash_table_iter_init(&iter, global_perf_liszt);
858
859 perf_row = 40;
860 while (g_hash_table_iter_next (&iter, &key, (gpointer) &perfn1)) {
861 if (perfn1->visible) {
862 perfn2 = g_hash_table_lookup(tmp->perf, (char *) key);
863 if (perfn2)
864 value = perfn2->count;
865 else
866 value = 0;
867 mvwprintw(center, current_line + header_offset,
868 perf_row, "%d", value);
869 perf_row += 20;
870 }
871 }
872
873 wattroff(center, COLOR_PAIR(6));
874 wattroff(center, COLOR_PAIR(5));
875 nblinedisplayed++;
876 current_line++;
877 }
878 }
879
880 void update_iostream()
881 {
882 int i;
883 int header_offset = 2;
884 struct processtop *tmp;
885 int nblinedisplayed = 0;
886 int current_line = 0;
887 int total = 0;
888 char unit[4];
889 int column;
890
891 set_window_title(center, "IO Top");
892 wattron(center, A_BOLD);
893 mvwprintw(center, 1, 1, "PID");
894 mvwprintw(center, 1, 11, "TID");
895 mvwprintw(center, 1, 22, "NAME");
896 column = 40;
897 for (i = 0; i < 3; i++) {
898 if (iostreamtopview[i].sort) {
899 pref_current_sort = i;
900 wattron(center, A_UNDERLINE);
901 }
902 mvwprintw(center, 1, column, iostreamtopview[i].title);
903 wattroff(center, A_UNDERLINE);
904 column += 12;
905 }
906 wattroff(center, A_BOLD);
907 wattroff(center, A_UNDERLINE);
908
909 if (iostreamtopview[0].sort == 1)
910 g_ptr_array_sort(data->process_table, sort_by_process_read_desc);
911 else if (iostreamtopview[1].sort == 1)
912 g_ptr_array_sort(data->process_table, sort_by_process_write_desc);
913 else if (iostreamtopview[2].sort == 1)
914 g_ptr_array_sort(data->process_table, sort_by_process_total_desc);
915 else
916 g_ptr_array_sort(data->process_table, sort_by_process_total_desc);
917
918 for (i = list_offset; i < data->process_table->len &&
919 nblinedisplayed < max_center_lines; i++) {
920 tmp = g_ptr_array_index(data->process_table, i);
921
922 if (!opt_tid && (opt_hostname && !lookup_hostname_list(tmp->hostname)))
923 continue;
924 if (!opt_hostname && (opt_tid && !lookup_tid_list(tmp->pid)))
925 continue;
926 if ((opt_tid && !lookup_tid_list(tmp->tid)) &&
927 (opt_hostname && !lookup_hostname_list(tmp->hostname)))
928 continue;
929
930 if (tmp->pid != tmp->tid)
931 if (toggle_threads == -1)
932 continue;
933
934 if (process_selected(tmp)) {
935 wattron(center, COLOR_PAIR(6));
936 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
937 }
938 if (current_line == selected_line) {
939 selected_process = tmp;
940 wattron(center, COLOR_PAIR(5));
941 mvwhline(center, current_line + header_offset, 1, ' ', COLS-3);
942 }
943 /* TGID */
944 mvwprintw(center, current_line + header_offset, 1, "%d", tmp->pid);
945 /* PID */
946 mvwprintw(center, current_line + header_offset, 11, "%d", tmp->tid);
947 /* NAME */
948 mvwprintw(center, current_line + header_offset, 22, "%s", tmp->comm);
949
950 /* READ (bytes/sec) */
951 scale_unit(tmp->fileread, unit);
952 mvwprintw(center, current_line + header_offset, 40, "%s", unit);
953
954 /* WRITE (bytes/sec) */
955 scale_unit(tmp->filewrite, unit);
956 mvwprintw(center, current_line + header_offset, 52, "%s", unit);
957
958 /* TOTAL STREAM */
959 total = tmp->totalfileread + tmp->totalfilewrite;
960
961 scale_unit(total, unit);
962 mvwprintw(center, current_line + header_offset, 64, "%s", unit);
963
964 wattroff(center, COLOR_PAIR(6));
965 wattroff(center, COLOR_PAIR(5));
966 nblinedisplayed++;
967 current_line++;
968 }
969 }
970
971 void update_current_view()
972 {
973 sem_wait(&update_display_sem);
974 if (!data)
975 return;
976 update_header();
977
978 werase(center);
979 box(center, 0, 0);
980 switch (current_view) {
981 case cpu:
982 update_cputop_display();
983 break;
984 case perf:
985 update_perf();
986 break;
987 case process_details:
988 update_process_details();
989 break;
990 case iostream:
991 update_iostream();
992 break;
993 case tree:
994 update_cputop_display();
995 break;
996 default:
997 break;
998 }
999 update_panels();
1000 doupdate();
1001 sem_post(&update_display_sem);
1002 }
1003
1004 void update_process_detail_sort(int *line_selected)
1005 {
1006 int i;
1007 int size;
1008
1009 size = 3;
1010
1011 if (*line_selected > (size - 1))
1012 *line_selected = size - 1;
1013 else if (*line_selected < 0)
1014 *line_selected = 0;
1015
1016 if (fileview[*line_selected].sort == 1)
1017 fileview[*line_selected].reverse = 1;
1018 for (i = 0; i < size; i++)
1019 fileview[i].sort = 0;
1020 fileview[*line_selected].sort = 1;
1021 }
1022
1023 void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort)
1024 {
1025 int i;
1026 int size;
1027
1028 if (!data)
1029 return;
1030 if (pref_panel_window) {
1031 del_panel(pref_panel);
1032 delwin(pref_panel_window);
1033 }
1034 size = 3;
1035
1036 pref_panel_window = create_window(size + 2, 30, 10, 10);
1037 pref_panel = new_panel(pref_panel_window);
1038
1039 werase(pref_panel_window);
1040 box(pref_panel_window, 0 , 0);
1041 set_window_title(pref_panel_window, "Process Detail Preferences ");
1042 wattron(pref_panel_window, A_BOLD);
1043 mvwprintw(pref_panel_window, size + 1, 1,
1044 " 's' : sort, space : toggle");
1045 wattroff(pref_panel_window, A_BOLD);
1046
1047 if (*line_selected > (size - 1))
1048 *line_selected = size - 1;
1049 else if (*line_selected < 0)
1050 *line_selected = 0;
1051 if (toggle_sort == 1) {
1052 update_process_detail_sort(line_selected);
1053 update_current_view();
1054 }
1055
1056 for (i = 0; i < size; i++) {
1057 if (i == *line_selected) {
1058 wattron(pref_panel_window, COLOR_PAIR(5));
1059 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1060 }
1061 if (fileview[i].sort == 1)
1062 wattron(pref_panel_window, A_BOLD);
1063 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1064 fileview[i].title);
1065 wattroff(pref_panel_window, A_BOLD);
1066 wattroff(pref_panel_window, COLOR_PAIR(5));
1067
1068 }
1069 update_panels();
1070 doupdate();
1071 }
1072
1073 void update_iostream_sort(int *line_selected)
1074 {
1075 int i;
1076 int size;
1077
1078 size = 3;
1079 if (*line_selected > (size - 1))
1080 *line_selected = size - 1;
1081 else if (*line_selected < 0)
1082 *line_selected = 0;
1083 if (iostreamtopview[*line_selected].sort == 1)
1084 iostreamtopview[*line_selected].reverse = 1;
1085 for (i = 0; i < size; i++)
1086 iostreamtopview[i].sort = 0;
1087 iostreamtopview[*line_selected].sort = 1;
1088
1089 }
1090
1091 void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort)
1092 {
1093 int i;
1094 int size;
1095
1096 if (!data)
1097 return;
1098 if (pref_panel_window) {
1099 del_panel(pref_panel);
1100 delwin(pref_panel_window);
1101 }
1102 size = 3;
1103
1104 pref_panel_window = create_window(size + 2, 30, 10, 10);
1105 pref_panel = new_panel(pref_panel_window);
1106
1107 werase(pref_panel_window);
1108 box(pref_panel_window, 0 , 0);
1109 set_window_title(pref_panel_window, "IOTop Preferences ");
1110 wattron(pref_panel_window, A_BOLD);
1111 mvwprintw(pref_panel_window, size + 1, 1,
1112 " 's' : sort, space : toggle");
1113 wattroff(pref_panel_window, A_BOLD);
1114
1115 if (*line_selected > (size - 1))
1116 *line_selected = size - 1;
1117 else if (*line_selected < 0)
1118 *line_selected = 0;
1119 if (toggle_sort == 1) {
1120 update_iostream_sort(line_selected);
1121 update_current_view();
1122 }
1123
1124 for (i = 0; i < size; i++) {
1125 if (i == *line_selected) {
1126 wattron(pref_panel_window, COLOR_PAIR(5));
1127 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1128 }
1129 if (iostreamtopview[i].sort == 1)
1130 wattron(pref_panel_window, A_BOLD);
1131 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1132 iostreamtopview[i].title);
1133 wattroff(pref_panel_window, A_BOLD);
1134 wattroff(pref_panel_window, COLOR_PAIR(5));
1135
1136 }
1137 update_panels();
1138 doupdate();
1139 }
1140
1141 void update_cpu_sort(int *line_selected)
1142 {
1143 int i;
1144 int size = 3;
1145
1146 if (*line_selected > (size - 1))
1147 *line_selected = size - 1;
1148 else if (*line_selected < 0)
1149 *line_selected = 0;
1150
1151 /* special case, we don't support sorting by procname for now */
1152 if (*line_selected != 3) {
1153 if (cputopview[*line_selected].sort == 1)
1154 cputopview[*line_selected].reverse = 1;
1155 for (i = 0; i < size; i++)
1156 cputopview[i].sort = 0;
1157 cputopview[*line_selected].sort = 1;
1158 }
1159 }
1160
1161 void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
1162 {
1163 int i;
1164 int size;
1165
1166 if (!data)
1167 return;
1168 if (pref_panel_window) {
1169 del_panel(pref_panel);
1170 delwin(pref_panel_window);
1171 }
1172 size = 4;
1173
1174 pref_panel_window = create_window(size + 2, 30, 10, 10);
1175 pref_panel = new_panel(pref_panel_window);
1176
1177 werase(pref_panel_window);
1178 box(pref_panel_window, 0 , 0);
1179 set_window_title(pref_panel_window, "CPUTop Preferences ");
1180 wattron(pref_panel_window, A_BOLD);
1181 mvwprintw(pref_panel_window, size + 1, 1,
1182 " 's' : sort, space : toggle");
1183 wattroff(pref_panel_window, A_BOLD);
1184
1185 if (*line_selected > (size - 1))
1186 *line_selected = size - 1;
1187 else if (*line_selected < 0)
1188 *line_selected = 0;
1189 if (toggle_sort == 1) {
1190 update_cpu_sort(line_selected);
1191 update_current_view();
1192 }
1193
1194 for (i = 0; i < size; i++) {
1195 if (i == *line_selected) {
1196 wattron(pref_panel_window, COLOR_PAIR(5));
1197 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1198 }
1199 if (cputopview[i].sort == 1)
1200 wattron(pref_panel_window, A_BOLD);
1201 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1202 cputopview[i].title);
1203 wattroff(pref_panel_window, A_BOLD);
1204 wattroff(pref_panel_window, COLOR_PAIR(5));
1205
1206 }
1207 update_panels();
1208 doupdate();
1209 }
1210
1211 void update_perf_sort(int *line_selected)
1212 {
1213 int i;
1214 struct perfcounter *perf;
1215 GList *perflist;
1216 int size;
1217
1218 size = g_hash_table_size(global_perf_liszt);
1219 if (*line_selected > (size - 1))
1220 *line_selected = size - 1;
1221 else if (*line_selected < 0)
1222 *line_selected = 0;
1223
1224 i = 0;
1225 perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
1226 while (perflist) {
1227 perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
1228 if (i != *line_selected)
1229 perf->sort = 0;
1230 else
1231 perf->sort = 1;
1232 i++;
1233 perflist = g_list_next(perflist);
1234 }
1235 }
1236
1237 void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
1238 {
1239 int i;
1240 struct perfcounter *perf;
1241 GList *perflist;
1242 int size;
1243
1244 if (!data)
1245 return;
1246 if (pref_panel_window) {
1247 del_panel(pref_panel);
1248 delwin(pref_panel_window);
1249 }
1250 size = g_hash_table_size(global_perf_liszt);
1251
1252 pref_panel_window = create_window(size + 2, 30, 10, 10);
1253 pref_panel = new_panel(pref_panel_window);
1254
1255 werase(pref_panel_window);
1256 box(pref_panel_window, 0 , 0);
1257 set_window_title(pref_panel_window, "Perf Preferences ");
1258 wattron(pref_panel_window, A_BOLD);
1259 mvwprintw(pref_panel_window, g_hash_table_size(global_perf_liszt) + 1, 1,
1260 " 's' : sort, space : toggle");
1261 wattroff(pref_panel_window, A_BOLD);
1262
1263 if (*line_selected > (size - 1))
1264 *line_selected = size - 1;
1265 else if (*line_selected < 0)
1266 *line_selected = 0;
1267
1268 if (toggle_sort == 1) {
1269 update_perf_sort(line_selected);
1270 update_current_view();
1271 }
1272
1273 i = 0;
1274 perflist = g_list_first(g_hash_table_get_keys(global_perf_liszt));
1275 while (perflist) {
1276 perf = g_hash_table_lookup(global_perf_liszt, perflist->data);
1277 if (i == *line_selected && toggle_view == 1) {
1278 perf->visible = perf->visible == 1 ? 0:1;
1279 update_current_view();
1280 }
1281 if (i == *line_selected) {
1282 wattron(pref_panel_window, COLOR_PAIR(5));
1283 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1284 }
1285 if (perf->sort == 1)
1286 wattron(pref_panel_window, A_BOLD);
1287 mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
1288 perf->visible == 1 ? 'x' : ' ',
1289 (char *) perflist->data + 5);
1290 wattroff(pref_panel_window, A_BOLD);
1291 wattroff(pref_panel_window, COLOR_PAIR(5));
1292 i++;
1293 perflist = g_list_next(perflist);
1294 }
1295 update_panels();
1296 doupdate();
1297 }
1298
1299 int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
1300 {
1301 int ret = 0;
1302
1303 switch(current_view) {
1304 case perf:
1305 update_perf_pref(line_selected, toggle_view, toggle_sort);
1306 break;
1307 case cpu:
1308 update_cpu_pref(line_selected, toggle_view, toggle_sort);
1309 break;
1310 case iostream:
1311 update_iostream_pref(line_selected, toggle_view, toggle_sort);
1312 break;
1313 case process_details:
1314 update_process_detail_pref(line_selected, toggle_view, toggle_sort);
1315 break;
1316 default:
1317 ret = -1;
1318 break;
1319 }
1320
1321 return ret;
1322 }
1323
1324 int update_sort(int *line_selected)
1325 {
1326 int ret = 0;
1327
1328 switch(current_view) {
1329 case perf:
1330 update_perf_sort(line_selected);
1331 break;
1332 case cpu:
1333 update_cpu_sort(line_selected);
1334 break;
1335 case iostream:
1336 update_iostream_sort(line_selected);
1337 break;
1338 case process_details:
1339 update_process_detail_sort(line_selected);
1340 break;
1341 default:
1342 ret = -1;
1343 break;
1344 }
1345
1346 return ret;
1347 }
1348
1349
1350 void toggle_pref_panel(void)
1351 {
1352 int ret;
1353
1354 if (pref_panel_visible) {
1355 hide_panel(pref_panel);
1356 pref_panel_visible = 0;
1357 } else {
1358 ret = update_preference_panel(&pref_line_selected, 0, 0);
1359 if (ret < 0)
1360 return;
1361 show_panel(pref_panel);
1362 pref_panel_visible = 1;
1363 }
1364 update_panels();
1365 doupdate();
1366 }
1367
1368 void display(unsigned int index)
1369 {
1370 last_display_index = index;
1371 currently_displayed_index = index;
1372 data = g_ptr_array_index(copies, index);
1373 if (!data)
1374 return;
1375 max_elements = data->process_table->len;
1376 update_current_view();
1377 update_footer();
1378 update_panels();
1379 doupdate();
1380 }
1381
1382 void pause_display()
1383 {
1384 toggle_pause = 1;
1385 print_log("Pause");
1386 sem_wait(&pause_sem);
1387 }
1388
1389 void resume_display()
1390 {
1391 toggle_pause = -1;
1392 print_log("Resume");
1393 sem_post(&pause_sem);
1394 }
1395
1396 void *handle_keyboard(void *p)
1397 {
1398 int ch;
1399 while((ch = getch())) {
1400 switch(ch) {
1401 /* Move the cursor and scroll */
1402 case 'j':
1403 case KEY_DOWN:
1404 if (pref_panel_visible) {
1405 pref_line_selected++;
1406 update_preference_panel(&pref_line_selected, 0, 0);
1407 } else {
1408 if (selected_line < (max_center_lines - 1) &&
1409 selected_line < max_elements - 1) {
1410 selected_line++;
1411 selected_in_list++;
1412 } else if (selected_in_list < (max_elements - 1)
1413 && (list_offset < (max_elements - max_center_lines))) {
1414 selected_in_list++;
1415 list_offset++;
1416 }
1417 update_current_view();
1418 }
1419 break;
1420 case KEY_NPAGE:
1421 break;
1422 case 'k':
1423 case KEY_UP:
1424 if (pref_panel_visible) {
1425 if (pref_line_selected > 0)
1426 pref_line_selected--;
1427 update_preference_panel(&pref_line_selected, 0, 0);
1428 } else {
1429 if (selected_line > 0) {
1430 selected_line--;
1431 selected_in_list--;
1432 } else if (selected_in_list > 0 && list_offset > 0) {
1433 selected_in_list--;
1434 list_offset--;
1435 }
1436 update_current_view();
1437 }
1438 break;
1439 case KEY_PPAGE:
1440 break;
1441
1442 /* Navigate the history with arrows */
1443 case KEY_LEFT:
1444 if (currently_displayed_index > 0) {
1445 currently_displayed_index--;
1446 print_log("Going back in time");
1447 } else {
1448 print_log("Cannot rewind, last data is already displayed");
1449 }
1450 data = g_ptr_array_index(copies, currently_displayed_index);
1451 max_elements = data->process_table->len;
1452
1453 /* we force to pause the display when moving in time */
1454 if (toggle_pause < 0)
1455 pause_display();
1456
1457 update_current_view();
1458 update_footer();
1459 break;
1460 case KEY_RIGHT:
1461 if (currently_displayed_index < last_display_index) {
1462 currently_displayed_index++;
1463 print_log("Going forward in time");
1464 data = g_ptr_array_index(copies, currently_displayed_index);
1465 max_elements = data->process_table->len;
1466 update_current_view();
1467 update_footer();
1468 } else {
1469 print_log("Manually moving forward");
1470 sem_post(&timer);
1471 if (toggle_pause > 0) {
1472 sem_post(&pause_sem);
1473 update_current_view();
1474 sem_wait(&pause_sem);
1475 }
1476 }
1477
1478 break;
1479 case ' ':
1480 if (pref_panel_visible) {
1481 update_preference_panel(&pref_line_selected, 1, 0);
1482 } else {
1483 update_selected_processes();
1484 update_current_view();
1485 }
1486 break;
1487 case 's':
1488 if (pref_panel_visible)
1489 update_preference_panel(&pref_line_selected, 0, 1);
1490 break;
1491 case '>':
1492 /* perf uses a hashtable, it is ordered backward */
1493 if (current_view == perf) {
1494 pref_current_sort--;
1495 } else if (!pref_panel_visible) {
1496 pref_current_sort++;
1497 }
1498 update_sort(&pref_current_sort);
1499 update_current_view();
1500 break;
1501 case '<':
1502 /* perf uses a hashtable, it is ordered backward */
1503 if (current_view == perf) {
1504 pref_current_sort++;
1505 } else if (!pref_panel_visible) {
1506 pref_current_sort--;
1507 }
1508 update_sort(&pref_current_sort);
1509 update_current_view();
1510 break;
1511
1512 case 13: /* FIXME : KEY_ENTER ?? */
1513 if (pref_panel_visible)
1514 break;
1515 if (current_view != process_details) {
1516 previous_view = current_view;
1517 current_view = process_details;
1518 } else {
1519 current_view = previous_view;
1520 previous_view = process_details;
1521 }
1522 selected_line = 0;
1523 update_current_view();
1524 break;
1525
1526 case KEY_F(1):
1527 if (pref_panel_visible)
1528 toggle_pref_panel();
1529 current_view = cpu;
1530 selected_line = 0;
1531 update_current_view();
1532 break;
1533 case KEY_F(2):
1534 if (pref_panel_visible)
1535 toggle_pref_panel();
1536 current_view = cpu;
1537 selected_line = 0;
1538 update_current_view();
1539 break;
1540 case KEY_F(3):
1541 if (pref_panel_visible)
1542 toggle_pref_panel();
1543 current_view = perf;
1544 selected_line = 0;
1545 update_current_view();
1546 break;
1547 case KEY_F(4):
1548 if (pref_panel_visible)
1549 toggle_pref_panel();
1550 current_view = iostream;
1551 selected_line = 0;
1552 update_current_view();
1553 break;
1554 case KEY_F(10):
1555 case 'q':
1556 reset_ncurses();
1557 /* exit keyboard thread */
1558 pthread_exit(0);
1559 break;
1560 case 't':
1561 toggle_threads *= -1;
1562 update_current_view();
1563 break;
1564 case 'p':
1565 if (toggle_pause < 0) {
1566 pause_display();
1567 } else {
1568 resume_display();
1569 }
1570 break;
1571 case 'r':
1572 toggle_pref_panel();
1573 break;
1574 case 'v':
1575 toggle_virt *= -1;
1576 update_current_view();
1577 break;
1578 /* ESCAPE, but slow to process, don't know why */
1579 case 27:
1580 if (pref_panel_visible)
1581 toggle_pref_panel();
1582 else if (current_view == process_details) {
1583 current_view = previous_view;
1584 previous_view = process_details;
1585 }
1586 update_current_view();
1587 break;
1588 default:
1589 if (data)
1590 update_current_view();
1591 break;
1592 }
1593 update_footer();
1594 }
1595 return NULL;
1596 }
1597
1598 void init_view_headers()
1599 {
1600 cputopview[0].title = strdup("CPU(%)");
1601 cputopview[0].sort = 1;
1602 cputopview[1].title = strdup("PID");
1603 cputopview[2].title = strdup("TID");
1604 cputopview[3].title = strdup("VPID");
1605 cputopview[4].title = strdup("VTID");
1606 cputopview[5].title = strdup("NAME");
1607
1608 iostreamtopview[0].title = strdup("R (B/sec)");
1609 iostreamtopview[1].title = strdup("W (B/sec)");
1610 iostreamtopview[2].title = strdup("Total (B)");
1611 iostreamtopview[2].sort = 1;
1612
1613 fileview[0].title = strdup("FD");
1614 fileview[1].title = strdup("READ");
1615 fileview[1].sort = 1;
1616 fileview[2].title = strdup("WRITE");
1617 }
1618
1619 void init_ncurses()
1620 {
1621 selected_processes = g_ptr_array_new();
1622 sem_init(&update_display_sem, 0, 1);
1623 init_view_headers();
1624 init_screen();
1625
1626 header = create_window(5, COLS - 1, 0, 0);
1627 center = create_window(LINES - 5 - 7, COLS - 1, 5, 0);
1628 status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
1629 footer = create_window(1, COLS - 1, LINES - 1, 0);
1630
1631 print_log("Starting display");
1632
1633 main_panel = new_panel(center);
1634
1635 current_view = cpu;
1636
1637 basic_header();
1638 update_footer();
1639
1640 pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
1641 }
This page took 0.136169 seconds and 4 git commands to generate.