2 * Copyright (C) 2011-2012 Julien Desfossez
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;
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.
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.
20 #ifdef HAVE_LIBNCURSES
29 #include <semaphore.h>
31 #include "cursesdisplay.h"
32 #include "lttngtoptypes.h"
33 #include "iostreamtop.h"
36 #define DEFAULT_DELAY 15
37 #define MAX_LINE_LENGTH 50
38 #define MAX_LOG_LINES 4
40 /* to prevent concurrent updates of the different windows */
41 sem_t update_display_sem
;
44 WINDOW
*footer
, *header
, *center
, *status
;
45 WINDOW
*pref_panel_window
= NULL
;
46 PANEL
*pref_panel
, *main_panel
;
48 int pref_panel_visible
= 0;
49 int pref_line_selected
= 0;
50 int pref_current_sort
= 0;
52 int last_display_index
, currently_displayed_index
;
54 struct processtop
*selected_process
= NULL
;
57 int selected_line
= 0; /* select bar position */
58 int selected_in_list
= 0; /* selection relative to the whole list */
59 int list_offset
= 0; /* first index in the list to display (scroll) */
61 char log_lines
[MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
];
63 int max_elements
= 80;
65 int toggle_threads
= 1;
67 int toggle_pause
= -1;
69 int filter_host_panel
= 0;
73 pthread_t keyboard_thread
;
75 struct header_view cputopview
[6];
76 struct header_view iostreamtopview
[3];
77 struct header_view fileview
[3];
78 struct header_view kprobeview
[2];
87 sem_post(&goodtodisplay
);
88 sem_post(&end_trace_sem
);
89 sem_post(&goodtoupdate
);
92 static void handle_sigterm(int signal
)
94 pthread_cancel(keyboard_thread
);
102 halfdelay(DEFAULT_DELAY
);
104 intrflush(stdscr
, false);
105 keypad(stdscr
, true);
110 init_pair(1, COLOR_RED
, COLOR_BLACK
); /* - */
111 init_pair(2, COLOR_GREEN
, COLOR_BLACK
); /* + */
112 init_pair(3, COLOR_BLACK
, COLOR_WHITE
); /* keys */
113 init_pair(4, COLOR_WHITE
, COLOR_GREEN
); /* keys activated */
114 init_pair(5, COLOR_BLACK
, COLOR_YELLOW
); /* select line */
115 init_pair(6, COLOR_GREEN
, COLOR_BLACK
); /* selected process */
116 init_pair(7, COLOR_RED
, COLOR_YELLOW
); /* selected process + line*/
118 termtype
= getenv("TERM");
119 if (!strcmp(termtype
, "xterm") || !strcmp(termtype
, "xterm-color") ||
120 !strcmp(termtype
, "vt220")) {
121 define_key("\033[H", KEY_HOME
);
122 define_key("\033[F", KEY_END
);
123 define_key("\033OP", KEY_F(1));
124 define_key("\033OQ", KEY_F(2));
125 define_key("\033OR", KEY_F(3));
126 define_key("\033OS", KEY_F(4));
127 define_key("\0330U", KEY_F(6));
128 define_key("\033[11~", KEY_F(1));
129 define_key("\033[12~", KEY_F(2));
130 define_key("\033[13~", KEY_F(3));
131 define_key("\033[14~", KEY_F(4));
132 define_key("\033[16~", KEY_F(6));
133 define_key("\033[17;2~", KEY_F(18));
135 signal(SIGTERM
, handle_sigterm
);
136 signal(SIGINT
, handle_sigterm
);
137 mousemask(BUTTON1_CLICKED
, NULL
);
141 WINDOW
*create_window(int height
, int width
, int startx
, int starty
)
144 win
= newwin(height
, width
, startx
, starty
);
150 WINDOW
*create_window_no_border(int height
, int width
, int startx
, int starty
)
153 win
= newwin(height
, width
, startx
, starty
);
158 void print_digit(WINDOW
*win
, int digit
)
161 wattron(win
, COLOR_PAIR(1));
162 wprintw(win
, "%d", digit
);
163 wattroff(win
, COLOR_PAIR(1));
164 } else if (digit
> 0) {
165 wattron(win
, COLOR_PAIR(2));
166 wprintw(win
, "+%d", digit
);
167 wattroff(win
, COLOR_PAIR(2));
173 void print_digits(WINDOW
*win
, int first
, int second
)
176 print_digit(win
, first
);
178 print_digit(win
, second
);
182 void print_headers(int line
, char *desc
, int value
, int first
, int second
)
184 wattron(header
, A_BOLD
);
185 mvwprintw(header
, line
, 4, "%s", desc
);
186 wattroff(header
, A_BOLD
);
187 mvwprintw(header
, line
, 16, "%d", value
);
188 wmove(header
, line
, 24);
189 print_digits(header
, first
, second
);
190 wmove(header
, line
, 40);
193 void set_window_title(WINDOW
*win
, char *title
)
195 wattron(win
, A_BOLD
);
196 mvwprintw(win
, 0, 1, title
);
197 wattroff(win
, A_BOLD
);
200 void print_log(char *str
)
203 int current_line
= 1;
204 int current_char
= 1;
206 /* rotate the line buffer */
207 if (nb_log_lines
>= MAX_LOG_LINES
) {
208 tmp
= strndup(log_lines
, MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
);
209 tmp2
= strchr(tmp
, '\n');
210 memset(log_lines
, '\0', strlen(log_lines
));
211 strncat(log_lines
, tmp2
+ 1, strlen(tmp2
) - 1);
212 log_lines
[strlen(log_lines
)] = '\n';
213 log_lines
[strlen(log_lines
)] = '\0';
218 strncat(log_lines
, str
, MAX_LINE_LENGTH
- 1);
220 if (nb_log_lines
< MAX_LOG_LINES
)
221 log_lines
[strlen(log_lines
)] = '\n';
222 log_lines
[strlen(log_lines
)] = '\0';
226 set_window_title(status
, "Status");
227 for (i
= 0; i
< strlen(log_lines
); i
++) {
228 if (log_lines
[i
] == '\n') {
229 wmove(status
, ++current_line
, 1);
232 mvwprintw(status
, current_line
, current_char
++, "%c",
239 int process_selected(struct processtop
*process
)
241 if (lookup_filter_tid_list(process
->tid
))
246 void update_selected_processes()
248 if (process_selected(selected_process
)) {
249 remove_filter_tid_list(selected_process
->tid
);
251 add_filter_tid_list(selected_process
);
255 void print_key(WINDOW
*win
, char *key
, char *desc
, int toggle
)
262 wattron(win
, COLOR_PAIR(pair
));
263 wprintw(footer
, "%s", key
);
264 wattroff(win
, COLOR_PAIR(pair
));
265 wprintw(footer
, ":%s", desc
);
270 sem_wait(&update_display_sem
);
273 print_key(footer
, "F2", "CPUtop ", current_view
== cpu
);
274 print_key(footer
, "F3", "PerfTop ", current_view
== perf
);
275 print_key(footer
, "F4", "IOTop ", current_view
== iostream
);
276 print_key(footer
, "Enter", "Details ", current_view
== process_details
);
277 print_key(footer
, "Space", "Highlight ", 0);
278 print_key(footer
, "q", "Quit ", 0);
279 print_key(footer
, "r", "Pref ", 0);
280 print_key(footer
, "t", "Threads ", toggle_threads
);
281 print_key(footer
, "v", "Virt ", toggle_virt
);
282 print_key(footer
, "p", "Pause ", toggle_pause
);
285 sem_post(&update_display_sem
);
292 set_window_title(header
, "Statistics for interval [gathering data...[");
293 wattron(header
, A_BOLD
);
294 mvwprintw(header
, 1, 4, "CPUs");
295 mvwprintw(header
, 2, 4, "Threads");
296 mvwprintw(header
, 3, 4, "FDs");
297 wattroff(header
, A_BOLD
);
301 static void scale_unit(uint64_t bytes
, char *ret
)
303 if (bytes
>= 1000000000)
304 sprintf(ret
, "%" PRIu64
"G", bytes
/1000000000);
305 if (bytes
>= 1000000)
306 sprintf(ret
, "%" PRIu64
"M", bytes
/1000000);
307 else if (bytes
>= 1000)
308 sprintf(ret
, "%" PRIu64
"K", bytes
/1000);
310 sprintf(ret
, "%" PRIu64
, bytes
);
316 struct processtop
*tmp
;
319 for (i
= 0; i
< data
->process_table
->len
; i
++) {
320 tmp
= g_ptr_array_index(data
->process_table
, i
);
321 total
+= tmp
->fileread
;
322 total
+= tmp
->filewrite
;
330 struct tm start
, end
;
331 uint64_t ts_nsec_start
, ts_nsec_end
;
334 ts_nsec_start
= data
->start
% NSEC_PER_SEC
;
335 start
= format_timestamp(data
->start
);
337 ts_nsec_end
= data
->end
% NSEC_PER_SEC
;
338 end
= format_timestamp(data
->end
);
342 set_window_title(header
, "Statistics for interval ");
343 wattron(header
, A_BOLD
);
345 wprintw(header
, "[%02d:%02d:%02d.%09" PRIu64
", %02d:%02d:%02d.%09" PRIu64
"[",
346 start
.tm_hour
, start
.tm_min
, start
.tm_sec
, ts_nsec_start
,
347 end
.tm_hour
, end
.tm_min
, end
.tm_sec
, ts_nsec_end
);
348 mvwprintw(header
, 1, 4, "CPUs");
349 wattroff(header
, A_BOLD
);
350 wprintw(header
, "\t%d\t(max/cpu : %0.2f%)", data
->cpu_table
->len
,
351 100.0/data
->cpu_table
->len
);
352 print_headers(2, "Threads", data
->nbthreads
, data
->nbnewthreads
,
353 -1*(data
->nbdeadthreads
));
354 print_headers(3, "FDs", data
->nbfiles
, data
->nbnewfiles
,
355 -1*(data
->nbclosedfiles
));
356 scale_unit(total_io(), io
);
357 mvwprintw(header
, 3, 43, "%sB/sec", io
);
361 gint
sort_by_cpu_desc(gconstpointer p1
, gconstpointer p2
)
363 struct processtop
*n1
= *(struct processtop
**)p1
;
364 struct processtop
*n2
= *(struct processtop
**)p2
;
365 unsigned long totaln1
= n1
->totalcpunsec
;
366 unsigned long totaln2
= n2
->totalcpunsec
;
368 if (totaln1
< totaln2
)
370 if (totaln1
== totaln2
)
375 gint
sort_by_tid_desc(gconstpointer p1
, gconstpointer p2
)
377 struct processtop
*n1
= *(struct processtop
**)p1
;
378 struct processtop
*n2
= *(struct processtop
**)p2
;
379 unsigned long totaln1
= n1
->tid
;
380 unsigned long totaln2
= n2
->tid
;
382 if (totaln1
< totaln2
)
384 if (totaln1
== totaln2
)
389 gint
sort_by_pid_desc(gconstpointer p1
, gconstpointer p2
)
391 struct processtop
*n1
= *(struct processtop
**)p1
;
392 struct processtop
*n2
= *(struct processtop
**)p2
;
393 unsigned long totaln1
= n1
->pid
;
394 unsigned long totaln2
= n2
->pid
;
396 if (totaln1
< totaln2
)
398 if (totaln1
== totaln2
)
403 gint
sort_by_process_read_desc(gconstpointer p1
, gconstpointer p2
)
405 struct processtop
*n1
= *(struct processtop
**)p1
;
406 struct processtop
*n2
= *(struct processtop
**)p2
;
407 unsigned long totaln1
= n1
->fileread
;
408 unsigned long totaln2
= n2
->fileread
;
410 if (totaln1
< totaln2
)
412 if (totaln1
== totaln2
)
417 gint
sort_by_process_write_desc(gconstpointer p1
, gconstpointer p2
)
419 struct processtop
*n1
= *(struct processtop
**)p1
;
420 struct processtop
*n2
= *(struct processtop
**)p2
;
421 unsigned long totaln1
= n1
->filewrite
;
422 unsigned long totaln2
= n2
->filewrite
;
424 if (totaln1
< totaln2
)
426 if (totaln1
== totaln2
)
431 gint
sort_by_process_total_desc(gconstpointer p1
, gconstpointer p2
)
433 struct processtop
*n1
= *(struct processtop
**)p1
;
434 struct processtop
*n2
= *(struct processtop
**)p2
;
435 unsigned long totaln1
= n1
->totalfilewrite
+ n1
->totalfileread
;
436 unsigned long totaln2
= n2
->totalfilewrite
+ n2
->totalfileread
;
438 if (totaln1
< totaln2
)
440 if (totaln1
== totaln2
)
445 gint
sort_by_file_read_desc(gconstpointer p1
, gconstpointer p2
)
447 struct files
*n1
= *(struct files
**)p1
;
448 struct files
*n2
= *(struct files
**)p2
;
449 unsigned long totaln1
;
450 unsigned long totaln2
;
455 if (totaln1
< totaln2
)
457 if (totaln1
== totaln2
)
462 gint
sort_by_file_write_desc(gconstpointer p1
, gconstpointer p2
)
464 struct files
*n1
= *(struct files
**)p1
;
465 struct files
*n2
= *(struct files
**)p2
;
466 unsigned long totaln1
;
467 unsigned long totaln2
;
472 if (totaln1
< totaln2
)
474 if (totaln1
== totaln2
)
479 gint
sort_by_file_fd_desc(gconstpointer p1
, gconstpointer p2
)
481 struct files
*n1
= *(struct files
**)p1
;
482 struct files
*n2
= *(struct files
**)p2
;
483 unsigned long totaln1
;
484 unsigned long totaln2
;
489 if (totaln1
< totaln2
)
491 if (totaln1
== totaln2
)
496 gint
sort_by_cpu_group_by_threads_desc(gconstpointer p1
, gconstpointer p2
)
498 struct processtop
*n1
= *(struct processtop
**)p1
;
499 struct processtop
*n2
= *(struct processtop
**)p2
;
500 unsigned long totaln1
= n1
->threadstotalcpunsec
;
501 unsigned long totaln2
= n2
->threadstotalcpunsec
;
503 if (totaln1
< totaln2
)
505 if (totaln1
== totaln2
)
510 void update_kprobes_display()
513 struct kprobes
*probe
;
514 int header_offset
= 2;
515 int current_line
= 0;
517 set_window_title(center
, "Kprobes Top ");
518 wattron(center
, A_BOLD
);
520 for (i
= 0; i
< 2; i
++) {
521 if (kprobeview
[i
].sort
) {
522 wattron(center
, A_UNDERLINE
);
523 pref_current_sort
= i
;
525 mvwprintw(center
, 1, column
, "%s", kprobeview
[i
].title
);
526 wattroff(center
, A_UNDERLINE
);
529 wattroff(center
, A_BOLD
);
531 for (i
= 0; i
< data
->kprobes_table
->len
; i
++) {
533 probe
= g_ptr_array_index(data
->kprobes_table
, i
);
534 mvwprintw(center
, current_line
+ header_offset
, column
,
535 "%s", probe
->probe_name
+ 6);
537 mvwprintw(center
, current_line
+ header_offset
, column
,
543 void update_cputop_display()
546 int header_offset
= 2;
547 struct processtop
*tmp
;
548 unsigned long elapsed
;
550 int nblinedisplayed
= 0;
551 int current_line
= 0;
552 int current_row_offset
;
555 elapsed
= data
->end
- data
->start
;
556 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
558 if (cputopview
[0].sort
== 1)
559 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
560 else if (cputopview
[1].sort
== 1)
561 g_ptr_array_sort(data
->process_table
, sort_by_pid_desc
);
562 else if (cputopview
[2].sort
== 1)
563 g_ptr_array_sort(data
->process_table
, sort_by_tid_desc
);
564 else if (cputopview
[3].sort
== 1)
565 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
567 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
569 set_window_title(center
, "CPU Top");
570 wattron(center
, A_BOLD
);
572 for (i
= 0; i
< 6; i
++) {
573 if (toggle_virt
< 0 && (i
== 3 || i
== 4)) {
576 if (cputopview
[i
].sort
) {
577 wattron(center
, A_UNDERLINE
);
578 pref_current_sort
= i
;
580 mvwprintw(center
, 1, column
, cputopview
[i
].title
);
581 wattroff(center
, A_UNDERLINE
);
584 wattroff(center
, A_BOLD
);
586 max_center_lines
= LINES
- 5 - 7 - 1 - header_offset
;
588 /* iterate the process (thread) list */
589 for (i
= list_offset
; i
< data
->process_table
->len
&&
590 nblinedisplayed
< max_center_lines
; i
++) {
591 tmp
= g_ptr_array_index(data
->process_table
, i
);
592 current_row_offset
= 1;
593 if (toggle_filter
> 0 && !lookup_filter_tid_list(tmp
->tid
))
596 if (tmp
->pid
!= tmp
->tid
)
597 if (toggle_threads
== -1)
601 if (current_line
== selected_line
) {
602 selected_process
= tmp
;
603 wattron(center
, COLOR_PAIR(5));
604 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
606 /* filtered process */
607 if (process_selected(tmp
)) {
608 if (current_line
== selected_line
)
609 wattron(center
, COLOR_PAIR(7));
611 wattron(center
, COLOR_PAIR(6));
614 mvwprintw(center
, current_line
+ header_offset
,
615 current_row_offset
, "%1.2f",
616 tmp
->totalcpunsec
/ maxcputime
);
617 current_row_offset
+= 10;
619 mvwprintw(center
, current_line
+ header_offset
,
620 current_row_offset
, "%d", tmp
->pid
);
621 current_row_offset
+= 10;
623 mvwprintw(center
, current_line
+ header_offset
,
624 current_row_offset
, "%d", tmp
->tid
);
625 current_row_offset
+= 10;
626 if (toggle_virt
> 0) {
628 mvwprintw(center
, current_line
+ header_offset
,
629 current_row_offset
, "%d", tmp
->vpid
);
630 current_row_offset
+= 10;
632 mvwprintw(center
, current_line
+ header_offset
,
633 current_row_offset
, "%d", tmp
->vtid
);
634 current_row_offset
+= 10;
637 mvwprintw(center
, current_line
+ header_offset
,
638 current_row_offset
, "%s", tmp
->comm
);
639 wattroff(center
, COLOR_PAIR(7));
640 wattroff(center
, COLOR_PAIR(6));
641 wattroff(center
, COLOR_PAIR(5));
647 gint
sort_perf(gconstpointer p1
, gconstpointer p2
, gpointer key
)
649 struct processtop
*n1
= *(struct processtop
**) p1
;
650 struct processtop
*n2
= *(struct processtop
**) p2
;
652 struct perfcounter
*tmp1
, *tmp2
;
653 unsigned long totaln2
= 0;
654 unsigned long totaln1
= 0;
659 tmp1
= g_hash_table_lookup(n1
->perf
, key
);
663 totaln1
= tmp1
->count
;
665 tmp2
= g_hash_table_lookup(n2
->perf
, key
);
669 totaln2
= tmp2
->count
;
671 if (totaln1
< totaln2
)
673 if (totaln1
== totaln2
) {
676 if (totaln1
< totaln2
)
683 void print_key_title(char *key
, int line
)
685 wattron(center
, A_BOLD
);
686 mvwprintw(center
, line
, 1, "%s", key
);
687 mvwprintw(center
, line
, 30, " ");
688 wattroff(center
, A_BOLD
);
691 void update_process_details()
693 unsigned long elapsed
;
695 struct processtop
*tmp
;
696 struct files
*file_tmp
;
699 char filename_buf
[COLS
];
702 GPtrArray
*newfilearray
= g_ptr_array_new();
704 struct perfcounter
*perfn1
, *perfn2
;
707 set_window_title(center
, "Process details");
710 tmp
= find_process_tid(data
,
711 selected_process
->tid
,
712 selected_process
->comm
);
713 elapsed
= data
->end
- data
->start
;
714 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
716 print_key_title("Name", line
++);
717 wprintw(center
, "%s", selected_process
->comm
);
718 print_key_title("TID", line
++);
719 wprintw(center
, "%d", selected_process
->tid
);
721 print_key_title("Does not exit at this time", 3);
725 print_key_title("PID", line
++);
726 wprintw(center
, "%d", tmp
->pid
);
727 print_key_title("PPID", line
++);
728 wprintw(center
, "%d", tmp
->ppid
);
729 print_key_title("VPID", line
++);
730 wprintw(center
, "%d", tmp
->vpid
);
731 print_key_title("VTID", line
++);
732 wprintw(center
, "%d", tmp
->vtid
);
733 print_key_title("VPPID", line
++);
734 wprintw(center
, "%d", tmp
->vppid
);
735 print_key_title("CPU", line
++);
736 wprintw(center
, "%1.2f %%", tmp
->totalcpunsec
/maxcputime
);
738 print_key_title("READ B/s", line
++);
739 scale_unit(tmp
->fileread
, unit
);
740 wprintw(center
, "%s", unit
);
742 print_key_title("WRITE B/s", line
++);
743 scale_unit(tmp
->filewrite
, unit
);
744 wprintw(center
, "%s", unit
);
746 g_hash_table_iter_init(&iter
, global_perf_liszt
);
747 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
748 print_key_title((char *) key
, line
++);
749 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
750 wprintw(center
, "%d", perfn2
? perfn2
->count
: 0);
754 wattron(center
, A_BOLD
);
756 for (i
= 0; i
< 3; i
++) {
757 if (fileview
[i
].sort
) {
758 pref_current_sort
= i
;
759 wattron(center
, A_UNDERLINE
);
761 mvwprintw(center
, line
, column
, fileview
[i
].title
);
762 wattroff(center
, A_UNDERLINE
);
765 mvwprintw(center
, line
++, column
, "FILENAME");
766 wattroff(center
, A_BOLD
);
769 * since the process_files_table array could contain NULL file structures,
770 * and that the positions inside the array is important (it is the FD), we
771 * need to create a temporary array that we can sort.
773 for (i
= 0; i
< tmp
->process_files_table
->len
; i
++) {
774 file_tmp
= g_ptr_array_index(tmp
->process_files_table
, i
);
776 g_ptr_array_add(newfilearray
, file_tmp
);
779 if (fileview
[0].sort
== 1)
780 g_ptr_array_sort(newfilearray
, sort_by_file_fd_desc
);
781 else if (fileview
[1].sort
== 1)
782 g_ptr_array_sort(newfilearray
, sort_by_file_read_desc
);
783 else if (fileview
[2].sort
== 1)
784 g_ptr_array_sort(newfilearray
, sort_by_file_write_desc
);
786 g_ptr_array_sort(newfilearray
, sort_by_file_read_desc
);
788 for (i
= selected_line
; i
< newfilearray
->len
&&
789 i
< (selected_line
+ max_center_lines
- line
+ 2); i
++) {
790 file_tmp
= g_ptr_array_index(newfilearray
, i
);
793 mvwprintw(center
, line
+ j
, 1, "%d", file_tmp
->fd
);
794 scale_unit(file_tmp
->read
, unit
);
795 mvwprintw(center
, line
+ j
, 11, "%s", unit
);
796 scale_unit(file_tmp
->write
, unit
);
797 mvwprintw(center
, line
+ j
, 21, "%s", unit
);
798 snprintf(filename_buf
, COLS
- 25, "%s", file_tmp
->name
);
799 mvwprintw(center
, line
+ j
, 31, "%s", filename_buf
);
802 g_ptr_array_free(newfilearray
, TRUE
);
808 int nblinedisplayed
= 0;
809 int current_line
= 0;
810 struct processtop
*tmp
;
811 int header_offset
= 2;
813 struct perfcounter
*perfn1
, *perfn2
;
814 char *perf_key
= NULL
;
819 set_window_title(center
, "Perf Top");
820 wattron(center
, A_BOLD
);
821 mvwprintw(center
, 1, 1, "PID");
822 mvwprintw(center
, 1, 11, "TID");
823 mvwprintw(center
, 1, 22, "NAME");
826 g_hash_table_iter_init(&iter
, global_perf_liszt
);
827 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
828 if (perfn1
->visible
) {
830 /* pref_current_sort = i; */
831 wattron(center
, A_UNDERLINE
);
833 /* + 5 to strip the "perf_" prefix */
834 mvwprintw(center
, 1, perf_row
, "%s",
836 wattroff(center
, A_UNDERLINE
);
840 perf_key
= (char *) key
;
843 wattroff(center
, A_BOLD
);
845 g_ptr_array_sort_with_data(data
->process_table
, sort_perf
, perf_key
);
847 for (i
= 0; i
< data
->process_table
->len
&&
848 nblinedisplayed
< max_center_lines
; i
++) {
849 tmp
= g_ptr_array_index(data
->process_table
, i
);
851 if (toggle_filter
> 0 && !lookup_filter_tid_list(tmp
->tid
))
854 if (tmp
->pid
!= tmp
->tid
)
855 if (toggle_threads
== -1)
858 if (process_selected(tmp
)) {
859 if (current_line
== selected_line
)
860 wattron(center
, COLOR_PAIR(7));
862 wattron(center
, COLOR_PAIR(6));
864 if (current_line
== selected_line
) {
865 selected_process
= tmp
;
866 wattron(center
, COLOR_PAIR(5));
867 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
870 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
871 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
872 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
874 g_hash_table_iter_init(&iter
, global_perf_liszt
);
877 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
878 if (perfn1
->visible
) {
879 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
881 value
= perfn2
->count
;
884 mvwprintw(center
, current_line
+ header_offset
,
885 perf_row
, "%d", value
);
890 wattroff(center
, COLOR_PAIR(6));
891 wattroff(center
, COLOR_PAIR(5));
897 void update_iostream()
900 int header_offset
= 2;
901 struct processtop
*tmp
;
902 int nblinedisplayed
= 0;
903 int current_line
= 0;
908 set_window_title(center
, "IO Top");
909 wattron(center
, A_BOLD
);
910 mvwprintw(center
, 1, 1, "PID");
911 mvwprintw(center
, 1, 11, "TID");
912 mvwprintw(center
, 1, 22, "NAME");
914 for (i
= 0; i
< 3; i
++) {
915 if (iostreamtopview
[i
].sort
) {
916 pref_current_sort
= i
;
917 wattron(center
, A_UNDERLINE
);
919 mvwprintw(center
, 1, column
, iostreamtopview
[i
].title
);
920 wattroff(center
, A_UNDERLINE
);
923 wattroff(center
, A_BOLD
);
924 wattroff(center
, A_UNDERLINE
);
926 if (iostreamtopview
[0].sort
== 1)
927 g_ptr_array_sort(data
->process_table
, sort_by_process_read_desc
);
928 else if (iostreamtopview
[1].sort
== 1)
929 g_ptr_array_sort(data
->process_table
, sort_by_process_write_desc
);
930 else if (iostreamtopview
[2].sort
== 1)
931 g_ptr_array_sort(data
->process_table
, sort_by_process_total_desc
);
933 g_ptr_array_sort(data
->process_table
, sort_by_process_total_desc
);
935 for (i
= list_offset
; i
< data
->process_table
->len
&&
936 nblinedisplayed
< max_center_lines
; i
++) {
937 tmp
= g_ptr_array_index(data
->process_table
, i
);
939 if (toggle_filter
> 0 && !lookup_filter_tid_list(tmp
->tid
))
942 if (tmp
->pid
!= tmp
->tid
)
943 if (toggle_threads
== -1)
946 if (process_selected(tmp
)) {
947 if (current_line
== selected_line
)
948 wattron(center
, COLOR_PAIR(7));
950 wattron(center
, COLOR_PAIR(6));
952 if (current_line
== selected_line
) {
953 selected_process
= tmp
;
954 wattron(center
, COLOR_PAIR(5));
955 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
958 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
960 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
962 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
964 /* READ (bytes/sec) */
965 scale_unit(tmp
->fileread
, unit
);
966 mvwprintw(center
, current_line
+ header_offset
, 40, "%s", unit
);
968 /* WRITE (bytes/sec) */
969 scale_unit(tmp
->filewrite
, unit
);
970 mvwprintw(center
, current_line
+ header_offset
, 52, "%s", unit
);
973 total
= tmp
->totalfileread
+ tmp
->totalfilewrite
;
975 scale_unit(total
, unit
);
976 mvwprintw(center
, current_line
+ header_offset
, 64, "%s", unit
);
978 wattroff(center
, COLOR_PAIR(6));
979 wattroff(center
, COLOR_PAIR(5));
985 void update_current_view()
987 sem_wait(&update_display_sem
);
994 switch (current_view
) {
996 update_cputop_display();
1001 case process_details
:
1002 update_process_details();
1008 update_cputop_display();
1011 update_kprobes_display();
1018 sem_post(&update_display_sem
);
1021 void update_process_detail_sort(int *line_selected
)
1028 if (*line_selected
> (size
- 1))
1029 *line_selected
= size
- 1;
1030 else if (*line_selected
< 0)
1033 if (fileview
[*line_selected
].sort
== 1)
1034 fileview
[*line_selected
].reverse
= 1;
1035 for (i
= 0; i
< size
; i
++)
1036 fileview
[i
].sort
= 0;
1037 fileview
[*line_selected
].sort
= 1;
1040 void update_process_detail_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1047 if (pref_panel_window
) {
1048 del_panel(pref_panel
);
1049 delwin(pref_panel_window
);
1053 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1054 pref_panel
= new_panel(pref_panel_window
);
1056 werase(pref_panel_window
);
1057 box(pref_panel_window
, 0 , 0);
1058 set_window_title(pref_panel_window
, "Process Detail Preferences ");
1059 wattron(pref_panel_window
, A_BOLD
);
1060 mvwprintw(pref_panel_window
, size
+ 1, 1,
1061 " 's' : sort, space : toggle");
1062 wattroff(pref_panel_window
, A_BOLD
);
1064 if (*line_selected
> (size
- 1))
1065 *line_selected
= size
- 1;
1066 else if (*line_selected
< 0)
1068 if (toggle_sort
== 1) {
1069 update_process_detail_sort(line_selected
);
1070 update_current_view();
1073 for (i
= 0; i
< size
; i
++) {
1074 if (i
== *line_selected
) {
1075 wattron(pref_panel_window
, COLOR_PAIR(5));
1076 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1078 if (fileview
[i
].sort
== 1)
1079 wattron(pref_panel_window
, A_BOLD
);
1080 mvwprintw(pref_panel_window
, i
+ 1, 1, "[-] %s",
1082 wattroff(pref_panel_window
, A_BOLD
);
1083 wattroff(pref_panel_window
, COLOR_PAIR(5));
1090 void update_iostream_sort(int *line_selected
)
1096 if (*line_selected
> (size
- 1))
1097 *line_selected
= size
- 1;
1098 else if (*line_selected
< 0)
1100 if (iostreamtopview
[*line_selected
].sort
== 1)
1101 iostreamtopview
[*line_selected
].reverse
= 1;
1102 for (i
= 0; i
< size
; i
++)
1103 iostreamtopview
[i
].sort
= 0;
1104 iostreamtopview
[*line_selected
].sort
= 1;
1108 void update_iostream_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1115 if (pref_panel_window
) {
1116 del_panel(pref_panel
);
1117 delwin(pref_panel_window
);
1121 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1122 pref_panel
= new_panel(pref_panel_window
);
1124 werase(pref_panel_window
);
1125 box(pref_panel_window
, 0 , 0);
1126 set_window_title(pref_panel_window
, "IOTop Preferences ");
1127 wattron(pref_panel_window
, A_BOLD
);
1128 mvwprintw(pref_panel_window
, size
+ 1, 1,
1129 " 's' : sort, space : toggle");
1130 wattroff(pref_panel_window
, A_BOLD
);
1132 if (*line_selected
> (size
- 1))
1133 *line_selected
= size
- 1;
1134 else if (*line_selected
< 0)
1136 if (toggle_sort
== 1) {
1137 update_iostream_sort(line_selected
);
1138 update_current_view();
1141 for (i
= 0; i
< size
; i
++) {
1142 if (i
== *line_selected
) {
1143 wattron(pref_panel_window
, COLOR_PAIR(5));
1144 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1146 if (iostreamtopview
[i
].sort
== 1)
1147 wattron(pref_panel_window
, A_BOLD
);
1148 mvwprintw(pref_panel_window
, i
+ 1, 1, "[-] %s",
1149 iostreamtopview
[i
].title
);
1150 wattroff(pref_panel_window
, A_BOLD
);
1151 wattroff(pref_panel_window
, COLOR_PAIR(5));
1158 void update_cpu_sort(int *line_selected
)
1163 if (*line_selected
> (size
- 1))
1164 *line_selected
= size
- 1;
1165 else if (*line_selected
< 0)
1168 /* special case, we don't support sorting by procname for now */
1169 if (*line_selected
!= 3) {
1170 if (cputopview
[*line_selected
].sort
== 1)
1171 cputopview
[*line_selected
].reverse
= 1;
1172 for (i
= 0; i
< size
; i
++)
1173 cputopview
[i
].sort
= 0;
1174 cputopview
[*line_selected
].sort
= 1;
1178 void update_cpu_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1185 if (pref_panel_window
) {
1186 del_panel(pref_panel
);
1187 delwin(pref_panel_window
);
1191 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1192 pref_panel
= new_panel(pref_panel_window
);
1194 werase(pref_panel_window
);
1195 box(pref_panel_window
, 0 , 0);
1196 set_window_title(pref_panel_window
, "CPUTop Preferences ");
1197 wattron(pref_panel_window
, A_BOLD
);
1198 mvwprintw(pref_panel_window
, size
+ 1, 1,
1199 " 's' : sort, space : toggle");
1200 wattroff(pref_panel_window
, A_BOLD
);
1202 if (*line_selected
> (size
- 1))
1203 *line_selected
= size
- 1;
1204 else if (*line_selected
< 0)
1206 if (toggle_sort
== 1) {
1207 update_cpu_sort(line_selected
);
1208 update_current_view();
1211 for (i
= 0; i
< size
; i
++) {
1212 if (i
== *line_selected
) {
1213 wattron(pref_panel_window
, COLOR_PAIR(5));
1214 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1216 if (cputopview
[i
].sort
== 1)
1217 wattron(pref_panel_window
, A_BOLD
);
1218 mvwprintw(pref_panel_window
, i
+ 1, 1, "[-] %s",
1219 cputopview
[i
].title
);
1220 wattroff(pref_panel_window
, A_BOLD
);
1221 wattroff(pref_panel_window
, COLOR_PAIR(5));
1228 void update_perf_sort(int *line_selected
)
1231 struct perfcounter
*perf
;
1235 size
= g_hash_table_size(global_perf_liszt
);
1236 if (*line_selected
> (size
- 1))
1237 *line_selected
= size
- 1;
1238 else if (*line_selected
< 0)
1242 perflist
= g_list_first(g_hash_table_get_keys(global_perf_liszt
));
1244 perf
= g_hash_table_lookup(global_perf_liszt
, perflist
->data
);
1245 if (i
!= *line_selected
)
1250 perflist
= g_list_next(perflist
);
1254 void update_perf_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1257 struct perfcounter
*perf
;
1263 if (pref_panel_window
) {
1264 del_panel(pref_panel
);
1265 delwin(pref_panel_window
);
1267 size
= g_hash_table_size(global_perf_liszt
);
1269 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1270 pref_panel
= new_panel(pref_panel_window
);
1272 werase(pref_panel_window
);
1273 box(pref_panel_window
, 0 , 0);
1274 set_window_title(pref_panel_window
, "Perf Preferences ");
1275 wattron(pref_panel_window
, A_BOLD
);
1276 mvwprintw(pref_panel_window
, g_hash_table_size(global_perf_liszt
) + 1, 1,
1277 " 's' : sort, space : toggle");
1278 wattroff(pref_panel_window
, A_BOLD
);
1280 if (*line_selected
> (size
- 1))
1281 *line_selected
= size
- 1;
1282 else if (*line_selected
< 0)
1285 if (toggle_sort
== 1) {
1286 update_perf_sort(line_selected
);
1287 update_current_view();
1291 perflist
= g_list_first(g_hash_table_get_keys(global_perf_liszt
));
1293 perf
= g_hash_table_lookup(global_perf_liszt
, perflist
->data
);
1294 if (i
== *line_selected
&& toggle_view
== 1) {
1295 perf
->visible
= perf
->visible
== 1 ? 0:1;
1296 update_current_view();
1298 if (i
== *line_selected
) {
1299 wattron(pref_panel_window
, COLOR_PAIR(5));
1300 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1302 if (perf
->sort
== 1)
1303 wattron(pref_panel_window
, A_BOLD
);
1304 mvwprintw(pref_panel_window
, i
+ 1, 1, "[%c] %s",
1305 perf
->visible
== 1 ? 'x' : ' ',
1306 (char *) perflist
->data
+ 5);
1307 wattroff(pref_panel_window
, A_BOLD
);
1308 wattroff(pref_panel_window
, COLOR_PAIR(5));
1310 perflist
= g_list_next(perflist
);
1316 void update_hostname_pref(int *line_selected
, int toggle_filter
, int toggle_sort
)
1325 if (pref_panel_window
) {
1326 del_panel(pref_panel
);
1327 delwin(pref_panel_window
);
1329 size
= g_hash_table_size(global_host_list
);
1331 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1332 pref_panel
= new_panel(pref_panel_window
);
1334 werase(pref_panel_window
);
1335 box(pref_panel_window
, 0 , 0);
1336 set_window_title(pref_panel_window
, "Hosts Preferences ");
1337 wattron(pref_panel_window
, A_BOLD
);
1338 mvwprintw(pref_panel_window
, g_hash_table_size(global_host_list
) + 1, 1,
1339 " space : toggle filter");
1340 wattroff(pref_panel_window
, A_BOLD
);
1342 if (*line_selected
> (size
- 1))
1343 *line_selected
= size
- 1;
1344 else if (*line_selected
< 0)
1348 hostlist
= g_list_first(g_hash_table_get_keys(global_host_list
));
1350 host
= g_hash_table_lookup(global_host_list
, hostlist
->data
);
1351 if (i
== *line_selected
&& toggle_filter
== 1) {
1352 host
->filter
= host
->filter
== 1 ? 0:1;
1353 update_hostname_filter(host
);
1354 update_current_view();
1356 if (i
== *line_selected
) {
1357 wattron(pref_panel_window
, COLOR_PAIR(5));
1358 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1360 if (host
->filter
== 1)
1361 wattron(pref_panel_window
, A_BOLD
);
1362 mvwprintw(pref_panel_window
, i
+ 1, 1, "[%c] %s",
1363 host
->filter
== 1 ? 'x' : ' ',
1364 (char *) hostlist
->data
);
1365 wattroff(pref_panel_window
, A_BOLD
);
1366 wattroff(pref_panel_window
, COLOR_PAIR(5));
1368 hostlist
= g_list_next(hostlist
);
1374 int update_preference_panel(int *line_selected
, int toggle_view
, int toggle_sort
)
1378 switch(current_view
) {
1380 if (filter_host_panel
)
1381 update_hostname_pref(line_selected
,
1382 toggle_view
, toggle_sort
);
1384 update_perf_pref(line_selected
,
1385 toggle_view
, toggle_sort
);
1388 if (filter_host_panel
)
1389 update_hostname_pref(line_selected
,
1390 toggle_view
, toggle_sort
);
1392 update_cpu_pref(line_selected
,
1393 toggle_view
, toggle_sort
);
1396 if (filter_host_panel
)
1397 update_hostname_pref(line_selected
,
1398 toggle_view
, toggle_sort
);
1400 update_iostream_pref(line_selected
,
1401 toggle_view
, toggle_sort
);
1403 case process_details
:
1404 update_process_detail_pref(line_selected
,
1405 toggle_view
, toggle_sort
);
1415 int update_sort(int *line_selected
)
1419 switch(current_view
) {
1421 update_perf_sort(line_selected
);
1424 update_cpu_sort(line_selected
);
1427 update_iostream_sort(line_selected
);
1429 case process_details
:
1430 update_process_detail_sort(line_selected
);
1440 void toggle_pref_panel(void)
1444 if (pref_panel_visible
) {
1445 hide_panel(pref_panel
);
1446 pref_panel_visible
= 0;
1448 ret
= update_preference_panel(&pref_line_selected
, 0, 0);
1451 show_panel(pref_panel
);
1452 pref_panel_visible
= 1;
1458 void toggle_host_panel(void)
1462 filter_host_panel
= filter_host_panel
? 0 : 1;
1463 if (pref_panel_visible
) {
1464 hide_panel(pref_panel
);
1465 pref_panel_visible
= 0;
1467 ret
= update_preference_panel(&pref_line_selected
, 0, 0);
1470 show_panel(pref_panel
);
1471 pref_panel_visible
= 1;
1477 void display(unsigned int index
)
1479 last_display_index
= index
;
1480 currently_displayed_index
= index
;
1481 data
= g_ptr_array_index(copies
, index
);
1484 max_elements
= data
->process_table
->len
;
1485 update_current_view();
1491 void pause_display()
1495 sem_wait(&pause_sem
);
1498 void resume_display()
1501 print_log("Resume");
1502 sem_post(&pause_sem
);
1505 void *handle_keyboard(void *p
)
1508 while((ch
= getch())) {
1510 /* Move the cursor and scroll */
1513 if (pref_panel_visible
) {
1514 pref_line_selected
++;
1515 update_preference_panel(&pref_line_selected
, 0, 0);
1517 if (selected_line
< (max_center_lines
- 1) &&
1518 selected_line
< max_elements
- 1) {
1521 } else if (selected_in_list
< (max_elements
- 1)
1522 && (list_offset
< (max_elements
- max_center_lines
))) {
1526 update_current_view();
1533 if (pref_panel_visible
) {
1534 if (pref_line_selected
> 0)
1535 pref_line_selected
--;
1536 update_preference_panel(&pref_line_selected
, 0, 0);
1538 if (selected_line
> 0) {
1541 } else if (selected_in_list
> 0 && list_offset
> 0) {
1545 update_current_view();
1551 /* Navigate the history with arrows */
1553 if (currently_displayed_index
> 0) {
1554 currently_displayed_index
--;
1555 print_log("Going back in time");
1557 print_log("Cannot rewind, last data is already displayed");
1559 data
= g_ptr_array_index(copies
, currently_displayed_index
);
1560 max_elements
= data
->process_table
->len
;
1562 /* we force to pause the display when moving in time */
1563 if (toggle_pause
< 0)
1566 update_current_view();
1570 if (currently_displayed_index
< last_display_index
) {
1571 currently_displayed_index
++;
1572 print_log("Going forward in time");
1573 data
= g_ptr_array_index(copies
, currently_displayed_index
);
1574 max_elements
= data
->process_table
->len
;
1575 update_current_view();
1578 print_log("Manually moving forward");
1580 if (toggle_pause
> 0) {
1581 sem_post(&pause_sem
);
1582 update_current_view();
1583 sem_wait(&pause_sem
);
1589 if (pref_panel_visible
) {
1590 update_preference_panel(&pref_line_selected
, 1, 0);
1592 update_selected_processes();
1593 if (toggle_filter
> 0) {
1594 max_elements
= g_hash_table_size(global_filter_list
);
1595 if (selected_line
>= max_elements
)
1596 selected_line
= max_elements
- 1;
1598 update_current_view();
1602 if (pref_panel_visible
)
1603 update_preference_panel(&pref_line_selected
, 0, 1);
1606 /* perf uses a hashtable, it is ordered backward */
1607 if (current_view
== perf
) {
1608 pref_current_sort
--;
1609 } else if (!pref_panel_visible
) {
1610 pref_current_sort
++;
1612 update_sort(&pref_current_sort
);
1613 update_current_view();
1616 /* perf uses a hashtable, it is ordered backward */
1617 if (current_view
== perf
) {
1618 pref_current_sort
++;
1619 } else if (!pref_panel_visible
) {
1620 pref_current_sort
--;
1622 update_sort(&pref_current_sort
);
1623 update_current_view();
1626 case 13: /* FIXME : KEY_ENTER ?? */
1627 if (pref_panel_visible
)
1629 if (current_view
!= process_details
) {
1630 previous_view
= current_view
;
1631 current_view
= process_details
;
1633 current_view
= previous_view
;
1634 previous_view
= process_details
;
1637 update_current_view();
1641 if (pref_panel_visible
)
1642 toggle_pref_panel();
1645 update_current_view();
1648 if (pref_panel_visible
)
1649 toggle_pref_panel();
1652 update_current_view();
1655 if (pref_panel_visible
)
1656 toggle_pref_panel();
1657 current_view
= perf
;
1659 update_current_view();
1662 if (pref_panel_visible
)
1663 toggle_pref_panel();
1664 current_view
= iostream
;
1666 update_current_view();
1669 if (pref_panel_visible
)
1670 toggle_pref_panel();
1671 current_view
= kprobes
;
1673 update_current_view();
1678 /* exit keyboard thread */
1682 toggle_filter
*= -1;
1684 if (toggle_filter
> 0)
1685 max_elements
= g_hash_table_size(global_filter_list
);
1687 max_elements
= data
->process_table
->len
;
1688 update_current_view();
1691 toggle_host_panel();
1694 toggle_threads
*= -1;
1695 update_current_view();
1698 if (toggle_pause
< 0) {
1705 toggle_pref_panel();
1709 update_current_view();
1711 /* ESCAPE, but slow to process, don't know why */
1713 if (pref_panel_visible
)
1714 toggle_pref_panel();
1715 else if (current_view
== process_details
) {
1716 current_view
= previous_view
;
1717 previous_view
= process_details
;
1719 update_current_view();
1723 update_current_view();
1731 void init_view_headers()
1733 cputopview
[0].title
= strdup("CPU(%)");
1734 cputopview
[0].sort
= 1;
1735 cputopview
[1].title
= strdup("PID");
1736 cputopview
[2].title
= strdup("TID");
1737 cputopview
[3].title
= strdup("VPID");
1738 cputopview
[4].title
= strdup("VTID");
1739 cputopview
[5].title
= strdup("NAME");
1741 iostreamtopview
[0].title
= strdup("R (B/sec)");
1742 iostreamtopview
[1].title
= strdup("W (B/sec)");
1743 iostreamtopview
[2].title
= strdup("Total (B)");
1744 iostreamtopview
[2].sort
= 1;
1746 fileview
[0].title
= strdup("FD");
1747 fileview
[1].title
= strdup("READ");
1748 fileview
[1].sort
= 1;
1749 fileview
[2].title
= strdup("WRITE");
1751 kprobeview
[0].title
= strdup("NAME");
1752 kprobeview
[1].title
= strdup("HIT");
1753 kprobeview
[1].sort
= 1;
1758 sem_init(&update_display_sem
, 0, 1);
1759 init_view_headers();
1762 header
= create_window(5, COLS
- 1, 0, 0);
1763 center
= create_window(LINES
- 5 - 7, COLS
- 1, 5, 0);
1764 status
= create_window(MAX_LOG_LINES
+ 2, COLS
- 1, LINES
- 7, 0);
1765 footer
= create_window(1, COLS
- 1, LINES
- 1, 0);
1767 print_log("Starting display");
1769 main_panel
= new_panel(center
);
1776 pthread_create(&keyboard_thread
, NULL
, handle_keyboard
, (void *)NULL
);
1779 #endif /* HAVE_LIBNCURSES */