2 * Copyright (C) 2011 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
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26 #include <semaphore.h>
28 #include "cursesdisplay.h"
29 #include "lttngtoptypes.h"
30 #include "iostreamtop.h"
33 #define DEFAULT_DELAY 15
34 #define MAX_LINE_LENGTH 50
35 #define MAX_LOG_LINES 4
37 /* to prevent concurrent updates of the different windows */
38 sem_t update_display_sem
;
41 WINDOW
*footer
, *header
, *center
, *status
;
42 WINDOW
*perf_panel_window
= NULL
;
43 PANEL
*perf_panel
, *main_panel
;
45 int perf_panel_visible
= 0;
46 int perf_line_selected
= 0;
48 int last_display_index
, currently_displayed_index
;
50 struct processtop
*selected_process
= NULL
;
55 int selected_line
= 0; /* select bar position */
56 int selected_in_list
= 0; /* selection relative to the whole list */
57 int list_offset
= 0; /* first index in the list to display (scroll) */
59 char log_lines
[MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
];
61 int max_elements
= 80;
63 int toggle_threads
= -1;
64 int toggle_pause
= -1;
69 pthread_t keyboard_thread
;
78 static void handle_sigterm(int signal
)
87 halfdelay(DEFAULT_DELAY
);
89 intrflush(stdscr
, false);
95 init_pair(1, COLOR_RED
, COLOR_BLACK
); /* - */
96 init_pair(2, COLOR_GREEN
, COLOR_BLACK
); /* + */
97 init_pair(3, COLOR_BLACK
, COLOR_WHITE
); /* keys */
98 init_pair(4, COLOR_WHITE
, COLOR_GREEN
); /* keys activated */
99 init_pair(5, COLOR_WHITE
, COLOR_BLUE
); /* select line */
101 termtype
= getenv("TERM");
102 if (!strcmp(termtype
, "xterm") || !strcmp(termtype
, "xterm-color") ||
103 !strcmp(termtype
, "vt220")) {
104 define_key("\033[H", KEY_HOME
);
105 define_key("\033[F", KEY_END
);
106 define_key("\033OP", KEY_F(1));
107 define_key("\033OQ", KEY_F(2));
108 define_key("\033OR", KEY_F(3));
109 define_key("\033OS", KEY_F(4));
110 define_key("\0330U", KEY_F(6));
111 define_key("\033[11~", KEY_F(1));
112 define_key("\033[12~", KEY_F(2));
113 define_key("\033[13~", KEY_F(3));
114 define_key("\033[14~", KEY_F(4));
115 define_key("\033[16~", KEY_F(6));
116 define_key("\033[17;2~", KEY_F(18));
118 signal(SIGTERM
, handle_sigterm
);
119 mousemask(BUTTON1_CLICKED
, NULL
);
123 WINDOW
*create_window(int height
, int width
, int startx
, int starty
)
126 win
= newwin(height
, width
, startx
, starty
);
132 WINDOW
*create_window_no_border(int height
, int width
, int startx
, int starty
)
135 win
= newwin(height
, width
, startx
, starty
);
140 void print_digit(WINDOW
*win
, int digit
)
143 wattron(win
, COLOR_PAIR(1));
144 wprintw(win
, "%d", digit
);
145 wattroff(win
, COLOR_PAIR(1));
146 } else if (digit
> 0) {
147 wattron(win
, COLOR_PAIR(2));
148 wprintw(win
, "+%d", digit
);
149 wattroff(win
, COLOR_PAIR(2));
155 void print_digits(WINDOW
*win
, int first
, int second
)
158 print_digit(win
, first
);
160 print_digit(win
, second
);
164 void print_headers(int line
, char *desc
, int value
, int first
, int second
)
166 wattron(header
, A_BOLD
);
167 mvwprintw(header
, line
, 4, "%s", desc
);
168 wattroff(header
, A_BOLD
);
169 mvwprintw(header
, line
, 16, "N/A", value
);
170 wmove(header
, line
, 24);
171 print_digits(header
, first
, second
);
172 wmove(header
, line
, 40);
175 void set_window_title(WINDOW
*win
, char *title
)
177 wattron(win
, A_BOLD
);
178 mvwprintw(win
, 0, 1, title
);
179 wattroff(win
, A_BOLD
);
182 void print_log(char *str
)
185 int current_line
= 1;
186 int current_char
= 1;
188 /* rotate the line buffer */
189 if (nb_log_lines
>= MAX_LOG_LINES
) {
190 tmp
= strndup(log_lines
, MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
);
191 tmp2
= strchr(tmp
, '\n');
192 memset(log_lines
, '\0', strlen(log_lines
));
193 strncat(log_lines
, tmp2
+ 1, strlen(tmp2
) - 1);
194 log_lines
[strlen(log_lines
)] = '\n';
195 log_lines
[strlen(log_lines
)] = '\0';
200 strncat(log_lines
, str
, MAX_LINE_LENGTH
- 1);
202 if (nb_log_lines
< MAX_LOG_LINES
)
203 log_lines
[strlen(log_lines
)] = '\n';
204 log_lines
[strlen(log_lines
)] = '\0';
208 set_window_title(status
, "Status");
209 for (i
= 0; i
< strlen(log_lines
); i
++) {
210 if (log_lines
[i
] == '\n') {
211 wmove(status
, ++current_line
, 1);
214 mvwprintw(status
, current_line
, current_char
++, "%c",
221 void print_key(WINDOW
*win
, char *key
, char *desc
, int toggle
)
228 wattron(win
, COLOR_PAIR(pair
));
229 wprintw(footer
, "%s", key
);
230 wattroff(win
, COLOR_PAIR(pair
));
231 wprintw(footer
, ":%s", desc
);
236 sem_wait(&update_display_sem
);
239 print_key(footer
, "F2", "CPUtop ", current_view
== cpu
);
240 print_key(footer
, "F3", "PerfTop ", current_view
== perf
);
241 print_key(footer
, "F6", "IOTop ", current_view
== iostream
);
242 print_key(footer
, "Enter", "Details ", current_view
== process_details
);
243 print_key(footer
, "q", "Quit | ", 0);
244 print_key(footer
, "P", "Perf Pref ", 0);
245 print_key(footer
, "p", "Pause ", toggle_pause
);
248 sem_post(&update_display_sem
);
255 set_window_title(header
, "Statistics for interval [gathering data...[");
256 wattron(header
, A_BOLD
);
257 mvwprintw(header
, 1, 4, "CPUs");
258 mvwprintw(header
, 2, 4, "Processes");
259 mvwprintw(header
, 3, 4, "Threads");
260 mvwprintw(header
, 4, 4, "Files");
261 mvwprintw(header
, 5, 4, "Network");
262 mvwprintw(header
, 6, 4, "IO");
263 wattroff(header
, A_BOLD
);
271 set_window_title(header
, "Statistics for interval ");
272 wattron(header
, A_BOLD
);
274 wprintw(header, "[%lu.%lu, %lu.%lu[",
275 data->start.tv_sec, data->start.tv_nsec,
276 data->end.tv_sec, data->end.tv_nsec);
278 wprintw(header
, "[%lu, %lu[",
281 mvwprintw(header
, 1, 4, "CPUs");
282 wattroff(header
, A_BOLD
);
283 wprintw(header
, "\t%d\t(max/cpu : %0.2f%)", data
->cpu_table
->len
,
284 100.0/data
->cpu_table
->len
);
285 print_headers(2, "Processes", data
->nbproc
, data
->nbnewproc
,
286 -1*(data
->nbdeadproc
));
287 print_headers(3, "Threads", data
->nbthreads
, data
->nbnewthreads
,
288 -1*(data
->nbdeadthreads
));
289 print_headers(4, "Files", data
->nbfiles
, data
->nbnewfiles
,
290 -1*(data
->nbclosedfiles
));
291 mvwprintw(header
, 4, 43, "N/A kbytes/sec");
292 print_headers(5, "Network", 114, 0, 0);
293 mvwprintw(header
, 5, 43, "N/A Mbytes/sec");
297 gint
sort_by_cpu_desc(gconstpointer p1
, gconstpointer p2
)
299 struct processtop
*n1
= *(struct processtop
**)p1
;
300 struct processtop
*n2
= *(struct processtop
**)p2
;
301 unsigned long totaln1
= n1
->totalcpunsec
;
302 unsigned long totaln2
= n2
->totalcpunsec
;
304 if (totaln1
< totaln2
)
306 if (totaln1
== totaln2
)
311 gint
sort_by_cpu_group_by_threads_desc(gconstpointer p1
, gconstpointer p2
)
313 struct processtop
*n1
= *(struct processtop
**)p1
;
314 struct processtop
*n2
= *(struct processtop
**)p2
;
315 unsigned long totaln1
= n1
->threadstotalcpunsec
;
316 unsigned long totaln2
= n2
->threadstotalcpunsec
;
318 if (totaln1
< totaln2
)
320 if (totaln1
== totaln2
)
325 void update_cputop_display()
328 int header_offset
= 2;
329 struct processtop
*tmp
;
330 unsigned long elapsed
;
332 int nblinedisplayed
= 0;
333 int current_line
= 0;
335 elapsed
= data
->end
- data
->start
;
336 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
338 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
340 set_window_title(center
, "CPU Top");
341 wattron(center
, A_BOLD
);
342 mvwprintw(center
, 1, 1, "CPU(%)");
343 mvwprintw(center
, 1, 12, "TGID");
344 mvwprintw(center
, 1, 22, "PID");
345 mvwprintw(center
, 1, 32, "NAME");
346 wattroff(center
, A_BOLD
);
348 max_center_lines
= LINES
- 7 - 7 - 1 - header_offset
;
350 /* iterate the process (thread) list */
351 for (i
= list_offset
; i
< data
->process_table
->len
&&
352 nblinedisplayed
< max_center_lines
; i
++) {
353 tmp
= g_ptr_array_index(data
->process_table
, i
);
355 if (current_line
== selected_line
) {
356 selected_process
= tmp
;
357 selected_tid
= tmp
->tid
;
358 selected_comm
= tmp
->comm
;
359 wattron(center
, COLOR_PAIR(5));
360 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
363 mvwprintw(center
, current_line
+ header_offset
, 1, "%1.2f",
364 tmp
->totalcpunsec
/ maxcputime
);
366 mvwprintw(center
, current_line
+ header_offset
, 12, "%d", tmp
->pid
);
368 mvwprintw(center
, current_line
+ header_offset
, 22, "%d", tmp
->tid
);
370 mvwprintw(center
, current_line
+ header_offset
, 32, "%s", tmp
->comm
);
371 wattroff(center
, COLOR_PAIR(5));
377 gint
sort_perf(gconstpointer p1
, gconstpointer p2
, gpointer key
)
379 struct processtop
*n1
= *(struct processtop
**) p1
;
380 struct processtop
*n2
= *(struct processtop
**) p2
;
382 struct perfcounter
*tmp1
, *tmp2
;
383 unsigned long totaln2
= 0;
384 unsigned long totaln1
= 0;
389 tmp1
= g_hash_table_lookup(n1
->perf
, key
);
393 totaln1
= tmp1
->count
;
395 tmp2
= g_hash_table_lookup(n2
->perf
, key
);
399 totaln2
= tmp2
->count
;
401 if (totaln1
< totaln2
)
403 if (totaln1
== totaln2
) {
406 if (totaln1
< totaln2
)
413 void print_key_title(char *key
, int line
)
415 wattron(center
, A_BOLD
);
416 mvwprintw(center
, line
, 1, "%s\t", key
);
417 wattroff(center
, A_BOLD
);
420 void update_process_details()
422 unsigned long elapsed
;
424 struct processtop
*tmp
= find_process_tid(data
, selected_tid
, selected_comm
);
425 struct files
*file_tmp
;
428 set_window_title(center
, "Process details");
431 elapsed
= data
->end
- data
->start
;
432 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
434 print_key_title("Name", 1);
435 wprintw(center
, "%s", selected_comm
);
436 print_key_title("TID", 2);
437 wprintw(center
, "%d", selected_tid
);
439 print_key_title("Does not exit at this time", 3);
443 print_key_title("PID", 3);
444 wprintw(center
, "%d", tmp
->pid
);
445 print_key_title("PPID", 4);
446 wprintw(center
, "%d", tmp
->ppid
);
447 print_key_title("CPU", 5);
448 wprintw(center
, "%1.2f %%", tmp
->totalcpunsec
/maxcputime
);
450 print_key_title("READ B/s", 6);
451 wprintw(center
, "%d", tmp
->fileread
);
453 print_key_title("WRITE B/s", 7);
454 wprintw(center
, "%d", tmp
->filewrite
);
456 for (i
= 0; i
< tmp
->process_files_table
->len
; i
++) {
457 file_tmp
= get_file(tmp
, i
);
458 if (file_tmp
!= NULL
) {
459 print_key_title("file", 8+j
);
460 wprintw(center
, "%s fd = %d", file_tmp
->name
, i
);
461 wprintw(center
, " read = %d", file_tmp
->read
);
462 wprintw(center
, " write = %d", file_tmp
->write
);
471 int nblinedisplayed
= 0;
472 int current_line
= 0;
473 struct processtop
*tmp
;
474 int header_offset
= 2;
476 struct perfcounter
*perfn1
, *perfn2
;
477 char *perf_key
= NULL
;
482 set_window_title(center
, "Perf Top");
483 wattron(center
, A_BOLD
);
484 mvwprintw(center
, 1, 1, "PID");
485 mvwprintw(center
, 1, 11, "TID");
486 mvwprintw(center
, 1, 22, "NAME");
489 g_hash_table_iter_init(&iter
, data
->perf_list
);
490 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
491 if (perfn1
->visible
) {
492 /* + 6 to strip the "_perf_" prefix */
493 mvwprintw(center
, 1, perf_row
, "%s",
498 perf_key
= (char *) key
;
502 wattroff(center
, A_BOLD
);
504 g_ptr_array_sort_with_data(data
->process_table
, sort_perf
, perf_key
);
506 for (i
= 0; i
< data
->process_table
->len
&&
507 nblinedisplayed
< max_center_lines
; i
++) {
508 tmp
= g_ptr_array_index(data
->process_table
, i
);
510 if (current_line
== selected_line
) {
511 selected_process
= tmp
;
512 wattron(center
, COLOR_PAIR(5));
513 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
516 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
517 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
518 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
520 g_hash_table_iter_init(&iter
, data
->perf_list
);
523 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
524 if (perfn1
->visible
) {
525 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
527 value
= perfn2
->count
;
530 mvwprintw(center
, current_line
+ header_offset
,
531 perf_row
, "%d", value
);
536 wattroff(center
, COLOR_PAIR(5));
547 set_window_title(center
, "IO Top");
548 wattron(center
, A_BOLD
);
549 mvwprintw(center
, 1, 10, "READ");
550 mvwprintw(center
, 2, 1, "bytes");
551 mvwprintw(center
, 2, 15, "bytes/sec");
553 mvwprintw(center
, 1, 39, "WRITE");
554 mvwprintw(center
, 2, 33, "bytes");
555 mvwprintw(center
, 2, 45, "bytes/sec");
557 if (toggle_threads
> 0) {
558 mvwprintw(center
, 1, 60, "TGID");
559 mvwprintw(center
, 1, 70, "PID");
562 mvwprintw(center
, 1, 60, "PID(TGID)");
565 mvwprintw(center
, 1, 72 + offset
, "NAME");
566 wattroff(center
, A_BOLD
);
568 for (i
= 3; i
< LINES
- 3 - 8 - 1; i
++) {
569 mvwprintw(center
, i
, 1, "%d", i
*1000);
570 mvwprintw(center
, i
, 15, "%dk", i
);
571 mvwprintw(center
, i
, 28, "| %d", i
*2000);
572 mvwprintw(center
, i
, 45, "%dk", i
*2);
573 if (toggle_threads
> 0) {
574 mvwprintw(center
, i
, 57, "| %d", i
);
575 mvwprintw(center
, i
, 70, "%d", i
);
577 mvwprintw(center
, i
, 57, "| %d", i
);
579 mvwprintw(center
, i
, 72 + offset
, "process_%d", i
);
583 gint
sort_by_ret_desc(gconstpointer p1
, gconstpointer p2
)
585 struct processtop
*n1
= *(struct processtop
**)p1
;
586 struct processtop
*n2
= *(struct processtop
**)p2
;
588 unsigned long totaln1
= n1
->totalfileread
+ n1
->totalfilewrite
;
589 unsigned long totaln2
= n2
->totalfileread
+ n2
->totalfilewrite
;
591 if (totaln1
< totaln2
)
593 if (totaln1
== totaln2
)
598 void update_iostream()
601 int header_offset
= 2;
602 struct processtop
*tmp
;
603 int nblinedisplayed
= 0;
604 int current_line
= 0;
607 set_window_title(center
, "IO Top");
608 wattron(center
, A_BOLD
);
609 mvwprintw(center
, 1, 1, "READ (B/s)");
610 mvwprintw(center
, 1, 20, "WRITE (B/s)");
612 mvwprintw(center
, 1, 40, "TOTAL STREAM");
614 mvwprintw(center
, 1, 60, "TGID");
615 mvwprintw(center
, 1, 80, "PID");
617 mvwprintw(center
, 1, 92, "NAME");
618 wattroff(center
, A_BOLD
);
620 g_ptr_array_sort(data
->process_table
, sort_by_ret_desc
);
622 for (i
= list_offset
; i
< data
->process_table
->len
&&
623 nblinedisplayed
< max_center_lines
; i
++) {
624 tmp
= g_ptr_array_index(data
->process_table
, i
);
626 if (current_line
== selected_line
) {
627 selected_process
= tmp
;
628 selected_tid
= tmp
->tid
;
629 selected_comm
= tmp
->comm
;
630 wattron(center
, COLOR_PAIR(5));
631 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
634 /* READ (bytes/sec) */
635 mvwprintw(center
, current_line
+ header_offset
, 1, "%lu",
638 /* WRITE (bytes/sec) */
639 mvwprintw(center
, current_line
+ header_offset
, 20, "%lu",
643 total
= tmp
->totalfileread
+ tmp
->totalfilewrite
;
645 if (total
>= 1000000)
646 mvwprintw(center
, current_line
+ header_offset
, 40, "%lu MB",
648 else if (total
>= 1000)
649 mvwprintw(center
, current_line
+ header_offset
, 40, "%lu KB",
652 mvwprintw(center
, current_line
+ header_offset
, 40, "%lu B",
656 mvwprintw(center
, current_line
+ header_offset
, 60, "%d", tmp
->pid
);
658 mvwprintw(center
, current_line
+ header_offset
, 80, "%d", tmp
->tid
);
660 mvwprintw(center
, current_line
+ header_offset
, 92, "%s", tmp
->comm
);
661 wattroff(center
, COLOR_PAIR(5));
667 void update_current_view()
669 sem_wait(&update_display_sem
);
676 switch (current_view
) {
678 update_cputop_display();
683 case process_details
:
684 update_process_details();
693 update_cputop_display();
700 sem_post(&update_display_sem
);
703 void setup_perf_panel()
708 if (perf_panel_window
) {
709 del_panel(perf_panel
);
710 delwin(perf_panel_window
);
712 size
= g_hash_table_size(data
->perf_list
);
713 perf_panel_window
= create_window(size
+ 2, 30, 10, 10);
714 perf_panel
= new_panel(perf_panel_window
);
715 perf_panel_visible
= 0;
716 hide_panel(perf_panel
);
719 void update_perf_panel(int line_selected
, int toggle_view
, int toggle_sort
)
722 struct perfcounter
*perf
;
728 werase(perf_panel_window
);
729 box(perf_panel_window
, 0 , 0);
730 set_window_title(perf_panel_window
, "Perf Preferences ");
731 wattron(perf_panel_window
, A_BOLD
);
732 mvwprintw(perf_panel_window
, g_hash_table_size(data
->perf_list
) + 1, 1,
734 wattroff(perf_panel_window
, A_BOLD
);
736 if (toggle_sort
== 1) {
738 perflist
= g_list_first(g_hash_table_get_keys(data
->perf_list
));
740 perf
= g_hash_table_lookup(data
->perf_list
, perflist
->data
);
741 if (i
!= line_selected
)
746 perflist
= g_list_next(perflist
);
748 update_current_view();
752 perflist
= g_list_first(g_hash_table_get_keys(data
->perf_list
));
754 perf
= g_hash_table_lookup(data
->perf_list
, perflist
->data
);
755 if (i
== line_selected
&& toggle_view
== 1) {
756 perf
->visible
= perf
->visible
== 1 ? 0:1;
757 update_current_view();
759 if (i
== line_selected
) {
760 wattron(perf_panel_window
, COLOR_PAIR(5));
761 mvwhline(perf_panel_window
, i
+ 1, 1, ' ', 30 - 2);
764 wattron(perf_panel_window
, A_BOLD
);
765 mvwprintw(perf_panel_window
, i
+ 1, 1, "[%c] %s",
766 perf
->visible
== 1 ? 'x' : ' ',
767 (char *) perflist
->data
+ 6);
768 wattroff(perf_panel_window
, A_BOLD
);
769 wattroff(perf_panel_window
, COLOR_PAIR(5));
771 perflist
= g_list_next(perflist
);
778 void toggle_perf_panel(void)
780 if (perf_panel_visible
) {
781 hide_panel(perf_panel
);
782 perf_panel_visible
= 0;
785 update_perf_panel(perf_line_selected
, 0, 0);
786 show_panel(perf_panel
);
787 perf_panel_visible
= 1;
793 void display(unsigned int index
)
795 last_display_index
= index
;
796 currently_displayed_index
= index
;
797 data
= g_ptr_array_index(copies
, index
);
800 max_elements
= data
->process_table
->len
;
801 update_current_view();
811 sem_wait(&pause_sem
);
814 void resume_display()
818 sem_post(&pause_sem
);
821 void *handle_keyboard(void *p
)
824 while((ch
= getch())) {
826 /* Move the cursor and scroll */
828 if (perf_panel_visible
) {
829 if (perf_line_selected
< g_hash_table_size(data
->perf_list
) - 1)
830 perf_line_selected
++;
831 update_perf_panel(perf_line_selected
, 0, 0);
833 if (selected_line
< (max_center_lines
- 1) &&
834 selected_line
< max_elements
- 1) {
837 } else if (selected_in_list
< (max_elements
- 1)
838 && (list_offset
< (max_elements
- max_center_lines
))) {
842 update_current_view();
846 if ((selected_line
+ 10 < max_center_lines
- 1) &&
847 ((selected_line
+ 10) < max_elements
- 1)) {
849 selected_in_list
+= 10;
850 } else if (max_elements
> max_center_lines
) {
851 selected_line
= max_center_lines
- 1;
852 if (selected_in_list
+ 10 < max_elements
- 1) {
853 selected_in_list
+= 10;
854 list_offset
+= (selected_in_list
- max_center_lines
+ 1);
856 } else if (selected_line
+ 10 > max_elements
) {
857 selected_line
= max_elements
- 1;
859 update_current_view();
862 if (perf_panel_visible
) {
863 if (perf_line_selected
> 0)
864 perf_line_selected
--;
865 update_perf_panel(perf_line_selected
, 0, 0);
867 if (selected_line
> 0) {
870 } else if (selected_in_list
> 0 && list_offset
> 0) {
874 update_current_view();
878 if (selected_line
- 10 > 0)
882 update_current_view();
885 /* Navigate the history with arrows */
887 if (currently_displayed_index
> 0) {
888 currently_displayed_index
--;
889 print_log("Going back in time");
891 print_log("Cannot rewind, last data is already displayed");
893 data
= g_ptr_array_index(copies
, currently_displayed_index
);
894 max_elements
= data
->process_table
->len
;
896 /* we force to pause the display when moving in time */
897 if (toggle_pause
< 0)
900 update_current_view();
904 if (currently_displayed_index
< last_display_index
) {
905 currently_displayed_index
++;
906 print_log("Going forward in time");
907 data
= g_ptr_array_index(copies
, currently_displayed_index
);
908 max_elements
= data
->process_table
->len
;
909 update_current_view();
912 print_log("Manually moving forward");
914 /* we force to resume the refresh when moving forward */
915 if (toggle_pause
> 0)
921 if (perf_panel_visible
)
922 update_perf_panel(perf_line_selected
, 1, 0);
925 if (perf_panel_visible
)
926 update_perf_panel(perf_line_selected
, 0, 1);
929 case 13: /* FIXME : KEY_ENTER ?? */
930 if (current_view
== cpu
) {
931 current_view
= process_details
;
933 update_current_view();
939 update_current_view();
943 update_current_view();
948 update_current_view();
951 current_view
= fileio
;
953 update_current_view();
956 current_view
= netio
;
958 update_current_view();
961 current_view
= iostream
;
963 update_current_view();
970 toggle_threads
*= -1;
971 update_current_view();
974 if (toggle_pause
< 0) {
985 update_current_view();
995 sem_init(&update_display_sem
, 0, 1);
998 header
= create_window(7, COLS
- 1, 0, 0);
999 center
= create_window(LINES
- 7 - 7, COLS
- 1, 7, 0);
1000 status
= create_window(MAX_LOG_LINES
+ 2, COLS
- 1, LINES
- 7, 0);
1001 footer
= create_window(1, COLS
- 1, LINES
- 1, 0);
1003 print_log("Starting display");
1005 main_panel
= new_panel(center
);
1013 pthread_create(&keyboard_thread
, NULL
, handle_keyboard
, (void *)NULL
);