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