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.
25 #include <semaphore.h>
27 #include "cursesdisplay.h"
28 #include "lttngtoptypes.h"
29 #include "iostreamtop.h"
32 #define DEFAULT_DELAY 15
33 #define MAX_LINE_LENGTH 50
34 #define MAX_LOG_LINES 4
36 /* to prevent concurrent updates of the different windows */
37 sem_t update_display_sem
;
40 WINDOW
*footer
, *header
, *center
, *status
;
41 WINDOW
*pref_panel_window
= NULL
;
42 PANEL
*pref_panel
, *main_panel
;
44 int pref_panel_visible
= 0;
45 int pref_line_selected
= 0;
46 int pref_current_sort
= 0;
48 int last_display_index
, currently_displayed_index
;
50 struct processtop
*selected_process
= NULL
;
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) */
57 char log_lines
[MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
];
59 int max_elements
= 80;
61 int toggle_threads
= 1;
63 int toggle_pause
= -1;
65 int filter_host_panel
= 0;
69 pthread_t keyboard_thread
;
71 struct header_view cputopview
[6];
72 struct header_view iostreamtopview
[3];
73 struct header_view fileview
[3];
74 struct header_view kprobeview
[2];
83 sem_post(&goodtodisplay
);
84 sem_post(&end_trace_sem
);
85 sem_post(&goodtoupdate
);
88 static void handle_sigterm(int signal
)
90 pthread_cancel(keyboard_thread
);
98 halfdelay(DEFAULT_DELAY
);
100 intrflush(stdscr
, false);
101 keypad(stdscr
, true);
106 init_pair(1, COLOR_RED
, COLOR_BLACK
); /* - */
107 init_pair(2, COLOR_GREEN
, COLOR_BLACK
); /* + */
108 init_pair(3, COLOR_BLACK
, COLOR_WHITE
); /* keys */
109 init_pair(4, COLOR_WHITE
, COLOR_GREEN
); /* keys activated */
110 init_pair(5, COLOR_BLACK
, COLOR_YELLOW
); /* select line */
111 init_pair(6, COLOR_GREEN
, COLOR_BLACK
); /* selected process */
112 init_pair(7, COLOR_RED
, COLOR_YELLOW
); /* selected process + line*/
114 termtype
= getenv("TERM");
115 if (!strcmp(termtype
, "xterm") || !strcmp(termtype
, "xterm-color") ||
116 !strcmp(termtype
, "vt220")) {
117 define_key("\033[H", KEY_HOME
);
118 define_key("\033[F", KEY_END
);
119 define_key("\033OP", KEY_F(1));
120 define_key("\033OQ", KEY_F(2));
121 define_key("\033OR", KEY_F(3));
122 define_key("\033OS", KEY_F(4));
123 define_key("\0330U", KEY_F(6));
124 define_key("\033[11~", KEY_F(1));
125 define_key("\033[12~", KEY_F(2));
126 define_key("\033[13~", KEY_F(3));
127 define_key("\033[14~", KEY_F(4));
128 define_key("\033[16~", KEY_F(6));
129 define_key("\033[17;2~", KEY_F(18));
131 signal(SIGTERM
, handle_sigterm
);
132 signal(SIGINT
, handle_sigterm
);
133 mousemask(BUTTON1_CLICKED
, NULL
);
137 WINDOW
*create_window(int height
, int width
, int startx
, int starty
)
140 win
= newwin(height
, width
, startx
, starty
);
146 WINDOW
*create_window_no_border(int height
, int width
, int startx
, int starty
)
149 win
= newwin(height
, width
, startx
, starty
);
154 void print_digit(WINDOW
*win
, int digit
)
157 wattron(win
, COLOR_PAIR(1));
158 wprintw(win
, "%d", digit
);
159 wattroff(win
, COLOR_PAIR(1));
160 } else if (digit
> 0) {
161 wattron(win
, COLOR_PAIR(2));
162 wprintw(win
, "+%d", digit
);
163 wattroff(win
, COLOR_PAIR(2));
169 void print_digits(WINDOW
*win
, int first
, int second
)
172 print_digit(win
, first
);
174 print_digit(win
, second
);
178 void print_headers(int line
, char *desc
, int value
, int first
, int second
)
180 wattron(header
, A_BOLD
);
181 mvwprintw(header
, line
, 4, "%s", desc
);
182 wattroff(header
, A_BOLD
);
183 mvwprintw(header
, line
, 16, "%d", value
);
184 wmove(header
, line
, 24);
185 print_digits(header
, first
, second
);
186 wmove(header
, line
, 40);
189 void set_window_title(WINDOW
*win
, char *title
)
191 wattron(win
, A_BOLD
);
192 mvwprintw(win
, 0, 1, title
);
193 wattroff(win
, A_BOLD
);
196 void print_log(char *str
)
199 int current_line
= 1;
200 int current_char
= 1;
202 /* rotate the line buffer */
203 if (nb_log_lines
>= MAX_LOG_LINES
) {
204 tmp
= strndup(log_lines
, MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
);
205 tmp2
= strchr(tmp
, '\n');
206 memset(log_lines
, '\0', strlen(log_lines
));
207 strncat(log_lines
, tmp2
+ 1, strlen(tmp2
) - 1);
208 log_lines
[strlen(log_lines
)] = '\n';
209 log_lines
[strlen(log_lines
)] = '\0';
214 strncat(log_lines
, str
, MAX_LINE_LENGTH
- 1);
216 if (nb_log_lines
< MAX_LOG_LINES
)
217 log_lines
[strlen(log_lines
)] = '\n';
218 log_lines
[strlen(log_lines
)] = '\0';
222 set_window_title(status
, "Status");
223 for (i
= 0; i
< strlen(log_lines
); i
++) {
224 if (log_lines
[i
] == '\n') {
225 wmove(status
, ++current_line
, 1);
228 mvwprintw(status
, current_line
, current_char
++, "%c",
235 int process_selected(struct processtop
*process
)
237 if (lookup_filter_tid_list(process
->tid
))
242 void update_selected_processes()
244 if (process_selected(selected_process
)) {
245 remove_filter_tid_list(selected_process
->tid
);
247 add_filter_tid_list(selected_process
);
251 void print_key(WINDOW
*win
, char *key
, char *desc
, int toggle
)
258 wattron(win
, COLOR_PAIR(pair
));
259 wprintw(footer
, "%s", key
);
260 wattroff(win
, COLOR_PAIR(pair
));
261 wprintw(footer
, ":%s", desc
);
266 sem_wait(&update_display_sem
);
269 print_key(footer
, "F2", "CPUtop ", current_view
== cpu
);
270 print_key(footer
, "F3", "PerfTop ", current_view
== perf
);
271 print_key(footer
, "F4", "IOTop ", current_view
== iostream
);
272 print_key(footer
, "Enter", "Details ", current_view
== process_details
);
273 print_key(footer
, "Space", "Highlight ", 0);
274 print_key(footer
, "q", "Quit ", 0);
275 print_key(footer
, "r", "Pref ", 0);
276 print_key(footer
, "t", "Threads ", toggle_threads
);
277 print_key(footer
, "v", "Virt ", toggle_virt
);
278 print_key(footer
, "p", "Pause ", toggle_pause
);
281 sem_post(&update_display_sem
);
288 set_window_title(header
, "Statistics for interval [gathering data...[");
289 wattron(header
, A_BOLD
);
290 mvwprintw(header
, 1, 4, "CPUs");
291 mvwprintw(header
, 2, 4, "Threads");
292 mvwprintw(header
, 3, 4, "FDs");
293 wattroff(header
, A_BOLD
);
297 static void scale_unit(uint64_t bytes
, char *ret
)
299 if (bytes
>= 1000000000)
300 sprintf(ret
, "%" PRIu64
"G", bytes
/1000000000);
301 if (bytes
>= 1000000)
302 sprintf(ret
, "%" PRIu64
"M", bytes
/1000000);
303 else if (bytes
>= 1000)
304 sprintf(ret
, "%" PRIu64
"K", bytes
/1000);
306 sprintf(ret
, "%" PRIu64
, bytes
);
312 struct processtop
*tmp
;
315 for (i
= 0; i
< data
->process_table
->len
; i
++) {
316 tmp
= g_ptr_array_index(data
->process_table
, i
);
317 total
+= tmp
->fileread
;
318 total
+= tmp
->filewrite
;
326 struct tm start
, end
;
327 uint64_t ts_nsec_start
, ts_nsec_end
;
330 ts_nsec_start
= data
->start
% NSEC_PER_SEC
;
331 start
= format_timestamp(data
->start
);
333 ts_nsec_end
= data
->end
% NSEC_PER_SEC
;
334 end
= format_timestamp(data
->end
);
338 set_window_title(header
, "Statistics for interval ");
339 wattron(header
, A_BOLD
);
341 wprintw(header
, "[%02d:%02d:%02d.%09" PRIu64
", %02d:%02d:%02d.%09" PRIu64
"[",
342 start
.tm_hour
, start
.tm_min
, start
.tm_sec
, ts_nsec_start
,
343 end
.tm_hour
, end
.tm_min
, end
.tm_sec
, ts_nsec_end
);
344 mvwprintw(header
, 1, 4, "CPUs");
345 wattroff(header
, A_BOLD
);
346 wprintw(header
, "\t%d\t(max/cpu : %0.2f%)", data
->cpu_table
->len
,
347 100.0/data
->cpu_table
->len
);
348 print_headers(2, "Threads", data
->nbthreads
, data
->nbnewthreads
,
349 -1*(data
->nbdeadthreads
));
350 print_headers(3, "FDs", data
->nbfiles
, data
->nbnewfiles
,
351 -1*(data
->nbclosedfiles
));
352 scale_unit(total_io(), io
);
353 mvwprintw(header
, 3, 43, "%sB/sec", io
);
357 gint
sort_by_cpu_desc(gconstpointer p1
, gconstpointer p2
)
359 struct processtop
*n1
= *(struct processtop
**)p1
;
360 struct processtop
*n2
= *(struct processtop
**)p2
;
361 unsigned long totaln1
= n1
->totalcpunsec
;
362 unsigned long totaln2
= n2
->totalcpunsec
;
364 if (totaln1
< totaln2
)
366 if (totaln1
== totaln2
)
371 gint
sort_by_tid_desc(gconstpointer p1
, gconstpointer p2
)
373 struct processtop
*n1
= *(struct processtop
**)p1
;
374 struct processtop
*n2
= *(struct processtop
**)p2
;
375 unsigned long totaln1
= n1
->tid
;
376 unsigned long totaln2
= n2
->tid
;
378 if (totaln1
< totaln2
)
380 if (totaln1
== totaln2
)
385 gint
sort_by_pid_desc(gconstpointer p1
, gconstpointer p2
)
387 struct processtop
*n1
= *(struct processtop
**)p1
;
388 struct processtop
*n2
= *(struct processtop
**)p2
;
389 unsigned long totaln1
= n1
->pid
;
390 unsigned long totaln2
= n2
->pid
;
392 if (totaln1
< totaln2
)
394 if (totaln1
== totaln2
)
399 gint
sort_by_process_read_desc(gconstpointer p1
, gconstpointer p2
)
401 struct processtop
*n1
= *(struct processtop
**)p1
;
402 struct processtop
*n2
= *(struct processtop
**)p2
;
403 unsigned long totaln1
= n1
->fileread
;
404 unsigned long totaln2
= n2
->fileread
;
406 if (totaln1
< totaln2
)
408 if (totaln1
== totaln2
)
413 gint
sort_by_process_write_desc(gconstpointer p1
, gconstpointer p2
)
415 struct processtop
*n1
= *(struct processtop
**)p1
;
416 struct processtop
*n2
= *(struct processtop
**)p2
;
417 unsigned long totaln1
= n1
->filewrite
;
418 unsigned long totaln2
= n2
->filewrite
;
420 if (totaln1
< totaln2
)
422 if (totaln1
== totaln2
)
427 gint
sort_by_process_total_desc(gconstpointer p1
, gconstpointer p2
)
429 struct processtop
*n1
= *(struct processtop
**)p1
;
430 struct processtop
*n2
= *(struct processtop
**)p2
;
431 unsigned long totaln1
= n1
->totalfilewrite
+ n1
->totalfileread
;
432 unsigned long totaln2
= n2
->totalfilewrite
+ n2
->totalfileread
;
434 if (totaln1
< totaln2
)
436 if (totaln1
== totaln2
)
441 gint
sort_by_file_read_desc(gconstpointer p1
, gconstpointer p2
)
443 struct files
*n1
= *(struct files
**)p1
;
444 struct files
*n2
= *(struct files
**)p2
;
445 unsigned long totaln1
;
446 unsigned long totaln2
;
451 if (totaln1
< totaln2
)
453 if (totaln1
== totaln2
)
458 gint
sort_by_file_write_desc(gconstpointer p1
, gconstpointer p2
)
460 struct files
*n1
= *(struct files
**)p1
;
461 struct files
*n2
= *(struct files
**)p2
;
462 unsigned long totaln1
;
463 unsigned long totaln2
;
468 if (totaln1
< totaln2
)
470 if (totaln1
== totaln2
)
475 gint
sort_by_file_fd_desc(gconstpointer p1
, gconstpointer p2
)
477 struct files
*n1
= *(struct files
**)p1
;
478 struct files
*n2
= *(struct files
**)p2
;
479 unsigned long totaln1
;
480 unsigned long totaln2
;
485 if (totaln1
< totaln2
)
487 if (totaln1
== totaln2
)
492 gint
sort_by_cpu_group_by_threads_desc(gconstpointer p1
, gconstpointer p2
)
494 struct processtop
*n1
= *(struct processtop
**)p1
;
495 struct processtop
*n2
= *(struct processtop
**)p2
;
496 unsigned long totaln1
= n1
->threadstotalcpunsec
;
497 unsigned long totaln2
= n2
->threadstotalcpunsec
;
499 if (totaln1
< totaln2
)
501 if (totaln1
== totaln2
)
506 void update_kprobes_display()
509 struct kprobes
*probe
;
510 int header_offset
= 2;
511 int current_line
= 0;
513 set_window_title(center
, "Kprobes Top ");
514 wattron(center
, A_BOLD
);
516 for (i
= 0; i
< 2; i
++) {
517 if (kprobeview
[i
].sort
) {
518 wattron(center
, A_UNDERLINE
);
519 pref_current_sort
= i
;
521 mvwprintw(center
, 1, column
, "%s", kprobeview
[i
].title
);
522 wattroff(center
, A_UNDERLINE
);
525 wattroff(center
, A_BOLD
);
527 for (i
= 0; i
< data
->kprobes_table
->len
; i
++) {
529 probe
= g_ptr_array_index(data
->kprobes_table
, i
);
530 mvwprintw(center
, current_line
+ header_offset
, column
,
531 "%s", probe
->probe_name
+ 6);
533 mvwprintw(center
, current_line
+ header_offset
, column
,
539 void update_cputop_display()
542 int header_offset
= 2;
543 struct processtop
*tmp
;
544 unsigned long elapsed
;
546 int nblinedisplayed
= 0;
547 int current_line
= 0;
548 int current_row_offset
;
551 elapsed
= data
->end
- data
->start
;
552 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
554 if (cputopview
[0].sort
== 1)
555 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
556 else if (cputopview
[1].sort
== 1)
557 g_ptr_array_sort(data
->process_table
, sort_by_pid_desc
);
558 else if (cputopview
[2].sort
== 1)
559 g_ptr_array_sort(data
->process_table
, sort_by_tid_desc
);
560 else if (cputopview
[3].sort
== 1)
561 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
563 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
565 set_window_title(center
, "CPU Top");
566 wattron(center
, A_BOLD
);
568 for (i
= 0; i
< 6; i
++) {
569 if (toggle_virt
< 0 && (i
== 3 || i
== 4)) {
572 if (cputopview
[i
].sort
) {
573 wattron(center
, A_UNDERLINE
);
574 pref_current_sort
= i
;
576 mvwprintw(center
, 1, column
, cputopview
[i
].title
);
577 wattroff(center
, A_UNDERLINE
);
580 wattroff(center
, A_BOLD
);
582 max_center_lines
= LINES
- 5 - 7 - 1 - header_offset
;
584 /* iterate the process (thread) list */
585 for (i
= list_offset
; i
< data
->process_table
->len
&&
586 nblinedisplayed
< max_center_lines
; i
++) {
587 tmp
= g_ptr_array_index(data
->process_table
, i
);
588 current_row_offset
= 1;
589 if (toggle_filter
> 0 && !lookup_filter_tid_list(tmp
->tid
))
592 if (tmp
->pid
!= tmp
->tid
)
593 if (toggle_threads
== -1)
597 if (current_line
== selected_line
) {
598 selected_process
= tmp
;
599 wattron(center
, COLOR_PAIR(5));
600 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
602 /* filtered process */
603 if (process_selected(tmp
)) {
604 if (current_line
== selected_line
)
605 wattron(center
, COLOR_PAIR(7));
607 wattron(center
, COLOR_PAIR(6));
610 mvwprintw(center
, current_line
+ header_offset
,
611 current_row_offset
, "%1.2f",
612 tmp
->totalcpunsec
/ maxcputime
);
613 current_row_offset
+= 10;
615 mvwprintw(center
, current_line
+ header_offset
,
616 current_row_offset
, "%d", tmp
->pid
);
617 current_row_offset
+= 10;
619 mvwprintw(center
, current_line
+ header_offset
,
620 current_row_offset
, "%d", tmp
->tid
);
621 current_row_offset
+= 10;
622 if (toggle_virt
> 0) {
624 mvwprintw(center
, current_line
+ header_offset
,
625 current_row_offset
, "%d", tmp
->vpid
);
626 current_row_offset
+= 10;
628 mvwprintw(center
, current_line
+ header_offset
,
629 current_row_offset
, "%d", tmp
->vtid
);
630 current_row_offset
+= 10;
633 mvwprintw(center
, current_line
+ header_offset
,
634 current_row_offset
, "%s", tmp
->comm
);
635 wattroff(center
, COLOR_PAIR(7));
636 wattroff(center
, COLOR_PAIR(6));
637 wattroff(center
, COLOR_PAIR(5));
643 gint
sort_perf(gconstpointer p1
, gconstpointer p2
, gpointer key
)
645 struct processtop
*n1
= *(struct processtop
**) p1
;
646 struct processtop
*n2
= *(struct processtop
**) p2
;
648 struct perfcounter
*tmp1
, *tmp2
;
649 unsigned long totaln2
= 0;
650 unsigned long totaln1
= 0;
655 tmp1
= g_hash_table_lookup(n1
->perf
, key
);
659 totaln1
= tmp1
->count
;
661 tmp2
= g_hash_table_lookup(n2
->perf
, key
);
665 totaln2
= tmp2
->count
;
667 if (totaln1
< totaln2
)
669 if (totaln1
== totaln2
) {
672 if (totaln1
< totaln2
)
679 void print_key_title(char *key
, int line
)
681 wattron(center
, A_BOLD
);
682 mvwprintw(center
, line
, 1, "%s", key
);
683 mvwprintw(center
, line
, 30, " ");
684 wattroff(center
, A_BOLD
);
687 void update_process_details()
689 unsigned long elapsed
;
691 struct processtop
*tmp
;
692 struct files
*file_tmp
;
695 char filename_buf
[COLS
];
698 GPtrArray
*newfilearray
= g_ptr_array_new();
700 struct perfcounter
*perfn1
, *perfn2
;
703 set_window_title(center
, "Process details");
706 tmp
= find_process_tid(data
,
707 selected_process
->tid
,
708 selected_process
->comm
);
709 elapsed
= data
->end
- data
->start
;
710 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
712 print_key_title("Name", line
++);
713 wprintw(center
, "%s", selected_process
->comm
);
714 print_key_title("TID", line
++);
715 wprintw(center
, "%d", selected_process
->tid
);
717 print_key_title("Does not exit at this time", 3);
721 print_key_title("PID", line
++);
722 wprintw(center
, "%d", tmp
->pid
);
723 print_key_title("PPID", line
++);
724 wprintw(center
, "%d", tmp
->ppid
);
725 print_key_title("VPID", line
++);
726 wprintw(center
, "%d", tmp
->vpid
);
727 print_key_title("VTID", line
++);
728 wprintw(center
, "%d", tmp
->vtid
);
729 print_key_title("VPPID", line
++);
730 wprintw(center
, "%d", tmp
->vppid
);
731 print_key_title("CPU", line
++);
732 wprintw(center
, "%1.2f %%", tmp
->totalcpunsec
/maxcputime
);
734 print_key_title("READ B/s", line
++);
735 scale_unit(tmp
->fileread
, unit
);
736 wprintw(center
, "%s", unit
);
738 print_key_title("WRITE B/s", line
++);
739 scale_unit(tmp
->filewrite
, unit
);
740 wprintw(center
, "%s", unit
);
742 g_hash_table_iter_init(&iter
, global_perf_liszt
);
743 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
744 print_key_title((char *) key
, line
++);
745 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
746 wprintw(center
, "%d", perfn2
? perfn2
->count
: 0);
750 wattron(center
, A_BOLD
);
752 for (i
= 0; i
< 3; i
++) {
753 if (fileview
[i
].sort
) {
754 pref_current_sort
= i
;
755 wattron(center
, A_UNDERLINE
);
757 mvwprintw(center
, line
, column
, fileview
[i
].title
);
758 wattroff(center
, A_UNDERLINE
);
761 mvwprintw(center
, line
++, column
, "FILENAME");
762 wattroff(center
, A_BOLD
);
765 * since the process_files_table array could contain NULL file structures,
766 * and that the positions inside the array is important (it is the FD), we
767 * need to create a temporary array that we can sort.
769 for (i
= 0; i
< tmp
->process_files_table
->len
; i
++) {
770 file_tmp
= g_ptr_array_index(tmp
->process_files_table
, i
);
772 g_ptr_array_add(newfilearray
, file_tmp
);
775 if (fileview
[0].sort
== 1)
776 g_ptr_array_sort(newfilearray
, sort_by_file_fd_desc
);
777 else if (fileview
[1].sort
== 1)
778 g_ptr_array_sort(newfilearray
, sort_by_file_read_desc
);
779 else if (fileview
[2].sort
== 1)
780 g_ptr_array_sort(newfilearray
, sort_by_file_write_desc
);
782 g_ptr_array_sort(newfilearray
, sort_by_file_read_desc
);
784 for (i
= selected_line
; i
< newfilearray
->len
&&
785 i
< (selected_line
+ max_center_lines
- line
+ 2); i
++) {
786 file_tmp
= g_ptr_array_index(newfilearray
, i
);
789 mvwprintw(center
, line
+ j
, 1, "%d", file_tmp
->fd
);
790 scale_unit(file_tmp
->read
, unit
);
791 mvwprintw(center
, line
+ j
, 11, "%s", unit
);
792 scale_unit(file_tmp
->write
, unit
);
793 mvwprintw(center
, line
+ j
, 21, "%s", unit
);
794 snprintf(filename_buf
, COLS
- 25, "%s", file_tmp
->name
);
795 mvwprintw(center
, line
+ j
, 31, "%s", filename_buf
);
798 g_ptr_array_free(newfilearray
, TRUE
);
804 int nblinedisplayed
= 0;
805 int current_line
= 0;
806 struct processtop
*tmp
;
807 int header_offset
= 2;
809 struct perfcounter
*perfn1
, *perfn2
;
810 char *perf_key
= NULL
;
815 set_window_title(center
, "Perf Top");
816 wattron(center
, A_BOLD
);
817 mvwprintw(center
, 1, 1, "PID");
818 mvwprintw(center
, 1, 11, "TID");
819 mvwprintw(center
, 1, 22, "NAME");
822 g_hash_table_iter_init(&iter
, global_perf_liszt
);
823 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
824 if (perfn1
->visible
) {
826 /* pref_current_sort = i; */
827 wattron(center
, A_UNDERLINE
);
829 /* + 5 to strip the "perf_" prefix */
830 mvwprintw(center
, 1, perf_row
, "%s",
832 wattroff(center
, A_UNDERLINE
);
836 perf_key
= (char *) key
;
839 wattroff(center
, A_BOLD
);
841 g_ptr_array_sort_with_data(data
->process_table
, sort_perf
, perf_key
);
843 for (i
= 0; i
< data
->process_table
->len
&&
844 nblinedisplayed
< max_center_lines
; i
++) {
845 tmp
= g_ptr_array_index(data
->process_table
, i
);
847 if (toggle_filter
> 0 && !lookup_filter_tid_list(tmp
->tid
))
850 if (tmp
->pid
!= tmp
->tid
)
851 if (toggle_threads
== -1)
854 if (process_selected(tmp
)) {
855 if (current_line
== selected_line
)
856 wattron(center
, COLOR_PAIR(7));
858 wattron(center
, COLOR_PAIR(6));
860 if (current_line
== selected_line
) {
861 selected_process
= tmp
;
862 wattron(center
, COLOR_PAIR(5));
863 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
866 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
867 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
868 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
870 g_hash_table_iter_init(&iter
, global_perf_liszt
);
873 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
874 if (perfn1
->visible
) {
875 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
877 value
= perfn2
->count
;
880 mvwprintw(center
, current_line
+ header_offset
,
881 perf_row
, "%d", value
);
886 wattroff(center
, COLOR_PAIR(6));
887 wattroff(center
, COLOR_PAIR(5));
893 void update_iostream()
896 int header_offset
= 2;
897 struct processtop
*tmp
;
898 int nblinedisplayed
= 0;
899 int current_line
= 0;
904 set_window_title(center
, "IO Top");
905 wattron(center
, A_BOLD
);
906 mvwprintw(center
, 1, 1, "PID");
907 mvwprintw(center
, 1, 11, "TID");
908 mvwprintw(center
, 1, 22, "NAME");
910 for (i
= 0; i
< 3; i
++) {
911 if (iostreamtopview
[i
].sort
) {
912 pref_current_sort
= i
;
913 wattron(center
, A_UNDERLINE
);
915 mvwprintw(center
, 1, column
, iostreamtopview
[i
].title
);
916 wattroff(center
, A_UNDERLINE
);
919 wattroff(center
, A_BOLD
);
920 wattroff(center
, A_UNDERLINE
);
922 if (iostreamtopview
[0].sort
== 1)
923 g_ptr_array_sort(data
->process_table
, sort_by_process_read_desc
);
924 else if (iostreamtopview
[1].sort
== 1)
925 g_ptr_array_sort(data
->process_table
, sort_by_process_write_desc
);
926 else if (iostreamtopview
[2].sort
== 1)
927 g_ptr_array_sort(data
->process_table
, sort_by_process_total_desc
);
929 g_ptr_array_sort(data
->process_table
, sort_by_process_total_desc
);
931 for (i
= list_offset
; i
< data
->process_table
->len
&&
932 nblinedisplayed
< max_center_lines
; i
++) {
933 tmp
= g_ptr_array_index(data
->process_table
, i
);
935 if (toggle_filter
> 0 && !lookup_filter_tid_list(tmp
->tid
))
938 if (tmp
->pid
!= tmp
->tid
)
939 if (toggle_threads
== -1)
942 if (process_selected(tmp
)) {
943 if (current_line
== selected_line
)
944 wattron(center
, COLOR_PAIR(7));
946 wattron(center
, COLOR_PAIR(6));
948 if (current_line
== selected_line
) {
949 selected_process
= tmp
;
950 wattron(center
, COLOR_PAIR(5));
951 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
954 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
956 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
958 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
960 /* READ (bytes/sec) */
961 scale_unit(tmp
->fileread
, unit
);
962 mvwprintw(center
, current_line
+ header_offset
, 40, "%s", unit
);
964 /* WRITE (bytes/sec) */
965 scale_unit(tmp
->filewrite
, unit
);
966 mvwprintw(center
, current_line
+ header_offset
, 52, "%s", unit
);
969 total
= tmp
->totalfileread
+ tmp
->totalfilewrite
;
971 scale_unit(total
, unit
);
972 mvwprintw(center
, current_line
+ header_offset
, 64, "%s", unit
);
974 wattroff(center
, COLOR_PAIR(6));
975 wattroff(center
, COLOR_PAIR(5));
981 void update_current_view()
983 sem_wait(&update_display_sem
);
990 switch (current_view
) {
992 update_cputop_display();
997 case process_details
:
998 update_process_details();
1004 update_cputop_display();
1007 update_kprobes_display();
1014 sem_post(&update_display_sem
);
1017 void update_process_detail_sort(int *line_selected
)
1024 if (*line_selected
> (size
- 1))
1025 *line_selected
= size
- 1;
1026 else if (*line_selected
< 0)
1029 if (fileview
[*line_selected
].sort
== 1)
1030 fileview
[*line_selected
].reverse
= 1;
1031 for (i
= 0; i
< size
; i
++)
1032 fileview
[i
].sort
= 0;
1033 fileview
[*line_selected
].sort
= 1;
1036 void update_process_detail_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1043 if (pref_panel_window
) {
1044 del_panel(pref_panel
);
1045 delwin(pref_panel_window
);
1049 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1050 pref_panel
= new_panel(pref_panel_window
);
1052 werase(pref_panel_window
);
1053 box(pref_panel_window
, 0 , 0);
1054 set_window_title(pref_panel_window
, "Process Detail Preferences ");
1055 wattron(pref_panel_window
, A_BOLD
);
1056 mvwprintw(pref_panel_window
, size
+ 1, 1,
1057 " 's' : sort, space : toggle");
1058 wattroff(pref_panel_window
, A_BOLD
);
1060 if (*line_selected
> (size
- 1))
1061 *line_selected
= size
- 1;
1062 else if (*line_selected
< 0)
1064 if (toggle_sort
== 1) {
1065 update_process_detail_sort(line_selected
);
1066 update_current_view();
1069 for (i
= 0; i
< size
; i
++) {
1070 if (i
== *line_selected
) {
1071 wattron(pref_panel_window
, COLOR_PAIR(5));
1072 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1074 if (fileview
[i
].sort
== 1)
1075 wattron(pref_panel_window
, A_BOLD
);
1076 mvwprintw(pref_panel_window
, i
+ 1, 1, "[-] %s",
1078 wattroff(pref_panel_window
, A_BOLD
);
1079 wattroff(pref_panel_window
, COLOR_PAIR(5));
1086 void update_iostream_sort(int *line_selected
)
1092 if (*line_selected
> (size
- 1))
1093 *line_selected
= size
- 1;
1094 else if (*line_selected
< 0)
1096 if (iostreamtopview
[*line_selected
].sort
== 1)
1097 iostreamtopview
[*line_selected
].reverse
= 1;
1098 for (i
= 0; i
< size
; i
++)
1099 iostreamtopview
[i
].sort
= 0;
1100 iostreamtopview
[*line_selected
].sort
= 1;
1104 void update_iostream_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1111 if (pref_panel_window
) {
1112 del_panel(pref_panel
);
1113 delwin(pref_panel_window
);
1117 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1118 pref_panel
= new_panel(pref_panel_window
);
1120 werase(pref_panel_window
);
1121 box(pref_panel_window
, 0 , 0);
1122 set_window_title(pref_panel_window
, "IOTop Preferences ");
1123 wattron(pref_panel_window
, A_BOLD
);
1124 mvwprintw(pref_panel_window
, size
+ 1, 1,
1125 " 's' : sort, space : toggle");
1126 wattroff(pref_panel_window
, A_BOLD
);
1128 if (*line_selected
> (size
- 1))
1129 *line_selected
= size
- 1;
1130 else if (*line_selected
< 0)
1132 if (toggle_sort
== 1) {
1133 update_iostream_sort(line_selected
);
1134 update_current_view();
1137 for (i
= 0; i
< size
; i
++) {
1138 if (i
== *line_selected
) {
1139 wattron(pref_panel_window
, COLOR_PAIR(5));
1140 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1142 if (iostreamtopview
[i
].sort
== 1)
1143 wattron(pref_panel_window
, A_BOLD
);
1144 mvwprintw(pref_panel_window
, i
+ 1, 1, "[-] %s",
1145 iostreamtopview
[i
].title
);
1146 wattroff(pref_panel_window
, A_BOLD
);
1147 wattroff(pref_panel_window
, COLOR_PAIR(5));
1154 void update_cpu_sort(int *line_selected
)
1159 if (*line_selected
> (size
- 1))
1160 *line_selected
= size
- 1;
1161 else if (*line_selected
< 0)
1164 /* special case, we don't support sorting by procname for now */
1165 if (*line_selected
!= 3) {
1166 if (cputopview
[*line_selected
].sort
== 1)
1167 cputopview
[*line_selected
].reverse
= 1;
1168 for (i
= 0; i
< size
; i
++)
1169 cputopview
[i
].sort
= 0;
1170 cputopview
[*line_selected
].sort
= 1;
1174 void update_cpu_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1181 if (pref_panel_window
) {
1182 del_panel(pref_panel
);
1183 delwin(pref_panel_window
);
1187 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1188 pref_panel
= new_panel(pref_panel_window
);
1190 werase(pref_panel_window
);
1191 box(pref_panel_window
, 0 , 0);
1192 set_window_title(pref_panel_window
, "CPUTop Preferences ");
1193 wattron(pref_panel_window
, A_BOLD
);
1194 mvwprintw(pref_panel_window
, size
+ 1, 1,
1195 " 's' : sort, space : toggle");
1196 wattroff(pref_panel_window
, A_BOLD
);
1198 if (*line_selected
> (size
- 1))
1199 *line_selected
= size
- 1;
1200 else if (*line_selected
< 0)
1202 if (toggle_sort
== 1) {
1203 update_cpu_sort(line_selected
);
1204 update_current_view();
1207 for (i
= 0; i
< size
; i
++) {
1208 if (i
== *line_selected
) {
1209 wattron(pref_panel_window
, COLOR_PAIR(5));
1210 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1212 if (cputopview
[i
].sort
== 1)
1213 wattron(pref_panel_window
, A_BOLD
);
1214 mvwprintw(pref_panel_window
, i
+ 1, 1, "[-] %s",
1215 cputopview
[i
].title
);
1216 wattroff(pref_panel_window
, A_BOLD
);
1217 wattroff(pref_panel_window
, COLOR_PAIR(5));
1224 void update_perf_sort(int *line_selected
)
1227 struct perfcounter
*perf
;
1231 size
= g_hash_table_size(global_perf_liszt
);
1232 if (*line_selected
> (size
- 1))
1233 *line_selected
= size
- 1;
1234 else if (*line_selected
< 0)
1238 perflist
= g_list_first(g_hash_table_get_keys(global_perf_liszt
));
1240 perf
= g_hash_table_lookup(global_perf_liszt
, perflist
->data
);
1241 if (i
!= *line_selected
)
1246 perflist
= g_list_next(perflist
);
1250 void update_perf_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
1253 struct perfcounter
*perf
;
1259 if (pref_panel_window
) {
1260 del_panel(pref_panel
);
1261 delwin(pref_panel_window
);
1263 size
= g_hash_table_size(global_perf_liszt
);
1265 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1266 pref_panel
= new_panel(pref_panel_window
);
1268 werase(pref_panel_window
);
1269 box(pref_panel_window
, 0 , 0);
1270 set_window_title(pref_panel_window
, "Perf Preferences ");
1271 wattron(pref_panel_window
, A_BOLD
);
1272 mvwprintw(pref_panel_window
, g_hash_table_size(global_perf_liszt
) + 1, 1,
1273 " 's' : sort, space : toggle");
1274 wattroff(pref_panel_window
, A_BOLD
);
1276 if (*line_selected
> (size
- 1))
1277 *line_selected
= size
- 1;
1278 else if (*line_selected
< 0)
1281 if (toggle_sort
== 1) {
1282 update_perf_sort(line_selected
);
1283 update_current_view();
1287 perflist
= g_list_first(g_hash_table_get_keys(global_perf_liszt
));
1289 perf
= g_hash_table_lookup(global_perf_liszt
, perflist
->data
);
1290 if (i
== *line_selected
&& toggle_view
== 1) {
1291 perf
->visible
= perf
->visible
== 1 ? 0:1;
1292 update_current_view();
1294 if (i
== *line_selected
) {
1295 wattron(pref_panel_window
, COLOR_PAIR(5));
1296 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1298 if (perf
->sort
== 1)
1299 wattron(pref_panel_window
, A_BOLD
);
1300 mvwprintw(pref_panel_window
, i
+ 1, 1, "[%c] %s",
1301 perf
->visible
== 1 ? 'x' : ' ',
1302 (char *) perflist
->data
+ 5);
1303 wattroff(pref_panel_window
, A_BOLD
);
1304 wattroff(pref_panel_window
, COLOR_PAIR(5));
1306 perflist
= g_list_next(perflist
);
1312 void update_hostname_pref(int *line_selected
, int toggle_filter
, int toggle_sort
)
1321 if (pref_panel_window
) {
1322 del_panel(pref_panel
);
1323 delwin(pref_panel_window
);
1325 size
= g_hash_table_size(global_host_list
);
1327 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
1328 pref_panel
= new_panel(pref_panel_window
);
1330 werase(pref_panel_window
);
1331 box(pref_panel_window
, 0 , 0);
1332 set_window_title(pref_panel_window
, "Hosts Preferences ");
1333 wattron(pref_panel_window
, A_BOLD
);
1334 mvwprintw(pref_panel_window
, g_hash_table_size(global_host_list
) + 1, 1,
1335 " space : toggle filter");
1336 wattroff(pref_panel_window
, A_BOLD
);
1338 if (*line_selected
> (size
- 1))
1339 *line_selected
= size
- 1;
1340 else if (*line_selected
< 0)
1344 hostlist
= g_list_first(g_hash_table_get_keys(global_host_list
));
1346 host
= g_hash_table_lookup(global_host_list
, hostlist
->data
);
1347 if (i
== *line_selected
&& toggle_filter
== 1) {
1348 host
->filter
= host
->filter
== 1 ? 0:1;
1349 update_hostname_filter(host
);
1350 update_current_view();
1352 if (i
== *line_selected
) {
1353 wattron(pref_panel_window
, COLOR_PAIR(5));
1354 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
1356 if (host
->filter
== 1)
1357 wattron(pref_panel_window
, A_BOLD
);
1358 mvwprintw(pref_panel_window
, i
+ 1, 1, "[%c] %s",
1359 host
->filter
== 1 ? 'x' : ' ',
1360 (char *) hostlist
->data
);
1361 wattroff(pref_panel_window
, A_BOLD
);
1362 wattroff(pref_panel_window
, COLOR_PAIR(5));
1364 hostlist
= g_list_next(hostlist
);
1370 int update_preference_panel(int *line_selected
, int toggle_view
, int toggle_sort
)
1374 switch(current_view
) {
1376 if (filter_host_panel
)
1377 update_hostname_pref(line_selected
,
1378 toggle_view
, toggle_sort
);
1380 update_perf_pref(line_selected
,
1381 toggle_view
, toggle_sort
);
1384 if (filter_host_panel
)
1385 update_hostname_pref(line_selected
,
1386 toggle_view
, toggle_sort
);
1388 update_cpu_pref(line_selected
,
1389 toggle_view
, toggle_sort
);
1392 if (filter_host_panel
)
1393 update_hostname_pref(line_selected
,
1394 toggle_view
, toggle_sort
);
1396 update_iostream_pref(line_selected
,
1397 toggle_view
, toggle_sort
);
1399 case process_details
:
1400 update_process_detail_pref(line_selected
,
1401 toggle_view
, toggle_sort
);
1411 int update_sort(int *line_selected
)
1415 switch(current_view
) {
1417 update_perf_sort(line_selected
);
1420 update_cpu_sort(line_selected
);
1423 update_iostream_sort(line_selected
);
1425 case process_details
:
1426 update_process_detail_sort(line_selected
);
1436 void toggle_pref_panel(void)
1440 if (pref_panel_visible
) {
1441 hide_panel(pref_panel
);
1442 pref_panel_visible
= 0;
1444 ret
= update_preference_panel(&pref_line_selected
, 0, 0);
1447 show_panel(pref_panel
);
1448 pref_panel_visible
= 1;
1454 void toggle_host_panel(void)
1458 filter_host_panel
= filter_host_panel
? 0 : 1;
1459 if (pref_panel_visible
) {
1460 hide_panel(pref_panel
);
1461 pref_panel_visible
= 0;
1463 ret
= update_preference_panel(&pref_line_selected
, 0, 0);
1466 show_panel(pref_panel
);
1467 pref_panel_visible
= 1;
1473 void display(unsigned int index
)
1475 last_display_index
= index
;
1476 currently_displayed_index
= index
;
1477 data
= g_ptr_array_index(copies
, index
);
1480 max_elements
= data
->process_table
->len
;
1481 update_current_view();
1487 void pause_display()
1491 sem_wait(&pause_sem
);
1494 void resume_display()
1497 print_log("Resume");
1498 sem_post(&pause_sem
);
1501 void *handle_keyboard(void *p
)
1504 while((ch
= getch())) {
1506 /* Move the cursor and scroll */
1509 if (pref_panel_visible
) {
1510 pref_line_selected
++;
1511 update_preference_panel(&pref_line_selected
, 0, 0);
1513 if (selected_line
< (max_center_lines
- 1) &&
1514 selected_line
< max_elements
- 1) {
1517 } else if (selected_in_list
< (max_elements
- 1)
1518 && (list_offset
< (max_elements
- max_center_lines
))) {
1522 update_current_view();
1529 if (pref_panel_visible
) {
1530 if (pref_line_selected
> 0)
1531 pref_line_selected
--;
1532 update_preference_panel(&pref_line_selected
, 0, 0);
1534 if (selected_line
> 0) {
1537 } else if (selected_in_list
> 0 && list_offset
> 0) {
1541 update_current_view();
1547 /* Navigate the history with arrows */
1549 if (currently_displayed_index
> 0) {
1550 currently_displayed_index
--;
1551 print_log("Going back in time");
1553 print_log("Cannot rewind, last data is already displayed");
1555 data
= g_ptr_array_index(copies
, currently_displayed_index
);
1556 max_elements
= data
->process_table
->len
;
1558 /* we force to pause the display when moving in time */
1559 if (toggle_pause
< 0)
1562 update_current_view();
1566 if (currently_displayed_index
< last_display_index
) {
1567 currently_displayed_index
++;
1568 print_log("Going forward in time");
1569 data
= g_ptr_array_index(copies
, currently_displayed_index
);
1570 max_elements
= data
->process_table
->len
;
1571 update_current_view();
1574 print_log("Manually moving forward");
1576 if (toggle_pause
> 0) {
1577 sem_post(&pause_sem
);
1578 update_current_view();
1579 sem_wait(&pause_sem
);
1585 if (pref_panel_visible
) {
1586 update_preference_panel(&pref_line_selected
, 1, 0);
1588 update_selected_processes();
1589 if (toggle_filter
> 0) {
1590 max_elements
= g_hash_table_size(global_filter_list
);
1591 if (selected_line
>= max_elements
)
1592 selected_line
= max_elements
- 1;
1594 update_current_view();
1598 if (pref_panel_visible
)
1599 update_preference_panel(&pref_line_selected
, 0, 1);
1602 /* perf uses a hashtable, it is ordered backward */
1603 if (current_view
== perf
) {
1604 pref_current_sort
--;
1605 } else if (!pref_panel_visible
) {
1606 pref_current_sort
++;
1608 update_sort(&pref_current_sort
);
1609 update_current_view();
1612 /* perf uses a hashtable, it is ordered backward */
1613 if (current_view
== perf
) {
1614 pref_current_sort
++;
1615 } else if (!pref_panel_visible
) {
1616 pref_current_sort
--;
1618 update_sort(&pref_current_sort
);
1619 update_current_view();
1622 case 13: /* FIXME : KEY_ENTER ?? */
1623 if (pref_panel_visible
)
1625 if (current_view
!= process_details
) {
1626 previous_view
= current_view
;
1627 current_view
= process_details
;
1629 current_view
= previous_view
;
1630 previous_view
= process_details
;
1633 update_current_view();
1637 if (pref_panel_visible
)
1638 toggle_pref_panel();
1641 update_current_view();
1644 if (pref_panel_visible
)
1645 toggle_pref_panel();
1648 update_current_view();
1651 if (pref_panel_visible
)
1652 toggle_pref_panel();
1653 current_view
= perf
;
1655 update_current_view();
1658 if (pref_panel_visible
)
1659 toggle_pref_panel();
1660 current_view
= iostream
;
1662 update_current_view();
1665 if (pref_panel_visible
)
1666 toggle_pref_panel();
1667 current_view
= kprobes
;
1669 update_current_view();
1674 /* exit keyboard thread */
1678 toggle_filter
*= -1;
1680 if (toggle_filter
> 0)
1681 max_elements
= g_hash_table_size(global_filter_list
);
1683 max_elements
= data
->process_table
->len
;
1684 update_current_view();
1687 toggle_host_panel();
1690 toggle_threads
*= -1;
1691 update_current_view();
1694 if (toggle_pause
< 0) {
1701 toggle_pref_panel();
1705 update_current_view();
1707 /* ESCAPE, but slow to process, don't know why */
1709 if (pref_panel_visible
)
1710 toggle_pref_panel();
1711 else if (current_view
== process_details
) {
1712 current_view
= previous_view
;
1713 previous_view
= process_details
;
1715 update_current_view();
1719 update_current_view();
1727 void init_view_headers()
1729 cputopview
[0].title
= strdup("CPU(%)");
1730 cputopview
[0].sort
= 1;
1731 cputopview
[1].title
= strdup("PID");
1732 cputopview
[2].title
= strdup("TID");
1733 cputopview
[3].title
= strdup("VPID");
1734 cputopview
[4].title
= strdup("VTID");
1735 cputopview
[5].title
= strdup("NAME");
1737 iostreamtopview
[0].title
= strdup("R (B/sec)");
1738 iostreamtopview
[1].title
= strdup("W (B/sec)");
1739 iostreamtopview
[2].title
= strdup("Total (B)");
1740 iostreamtopview
[2].sort
= 1;
1742 fileview
[0].title
= strdup("FD");
1743 fileview
[1].title
= strdup("READ");
1744 fileview
[1].sort
= 1;
1745 fileview
[2].title
= strdup("WRITE");
1747 kprobeview
[0].title
= strdup("NAME");
1748 kprobeview
[1].title
= strdup("HIT");
1749 kprobeview
[1].sort
= 1;
1754 sem_init(&update_display_sem
, 0, 1);
1755 init_view_headers();
1758 header
= create_window(5, COLS
- 1, 0, 0);
1759 center
= create_window(LINES
- 5 - 7, COLS
- 1, 5, 0);
1760 status
= create_window(MAX_LOG_LINES
+ 2, COLS
- 1, LINES
- 7, 0);
1761 footer
= create_window(1, COLS
- 1, LINES
- 1, 0);
1763 print_log("Starting display");
1765 main_panel
= new_panel(center
);
1772 pthread_create(&keyboard_thread
, NULL
, handle_keyboard
, (void *)NULL
);