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 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
*perf_panel_window
= NULL
;
42 PANEL
*perf_panel
, *main_panel
;
44 int perf_panel_visible
= 0;
45 int perf_line_selected
= 0;
47 int last_display_index
, currently_displayed_index
;
49 struct processtop
*selected_process
= NULL
;
52 int selected_line
= 0; /* select bar position */
53 int selected_in_list
= 0; /* selection relative to the whole list */
54 int list_offset
= 0; /* first index in the list to display (scroll) */
56 char log_lines
[MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
];
58 int max_elements
= 80;
60 int toggle_threads
= -1;
61 int toggle_pause
= -1;
64 GPtrArray
*selected_processes
;
66 pthread_t keyboard_thread
;
75 static void handle_sigterm(int signal
)
84 halfdelay(DEFAULT_DELAY
);
86 intrflush(stdscr
, false);
92 init_pair(1, COLOR_RED
, COLOR_BLACK
); /* - */
93 init_pair(2, COLOR_GREEN
, COLOR_BLACK
); /* + */
94 init_pair(3, COLOR_BLACK
, COLOR_WHITE
); /* keys */
95 init_pair(4, COLOR_WHITE
, COLOR_GREEN
); /* keys activated */
96 init_pair(5, COLOR_WHITE
, COLOR_BLUE
); /* select line */
97 init_pair(6, COLOR_WHITE
, COLOR_GREEN
); /* selected process */
99 termtype
= getenv("TERM");
100 if (!strcmp(termtype
, "xterm") || !strcmp(termtype
, "xterm-color") ||
101 !strcmp(termtype
, "vt220")) {
102 define_key("\033[H", KEY_HOME
);
103 define_key("\033[F", KEY_END
);
104 define_key("\033OP", KEY_F(1));
105 define_key("\033OQ", KEY_F(2));
106 define_key("\033OR", KEY_F(3));
107 define_key("\033OS", KEY_F(4));
108 define_key("\0330U", KEY_F(6));
109 define_key("\033[11~", KEY_F(1));
110 define_key("\033[12~", KEY_F(2));
111 define_key("\033[13~", KEY_F(3));
112 define_key("\033[14~", KEY_F(4));
113 define_key("\033[16~", KEY_F(6));
114 define_key("\033[17;2~", KEY_F(18));
116 signal(SIGTERM
, handle_sigterm
);
117 mousemask(BUTTON1_CLICKED
, NULL
);
121 WINDOW
*create_window(int height
, int width
, int startx
, int starty
)
124 win
= newwin(height
, width
, startx
, starty
);
130 WINDOW
*create_window_no_border(int height
, int width
, int startx
, int starty
)
133 win
= newwin(height
, width
, startx
, starty
);
138 void print_digit(WINDOW
*win
, int digit
)
141 wattron(win
, COLOR_PAIR(1));
142 wprintw(win
, "%d", digit
);
143 wattroff(win
, COLOR_PAIR(1));
144 } else if (digit
> 0) {
145 wattron(win
, COLOR_PAIR(2));
146 wprintw(win
, "+%d", digit
);
147 wattroff(win
, COLOR_PAIR(2));
153 void print_digits(WINDOW
*win
, int first
, int second
)
156 print_digit(win
, first
);
158 print_digit(win
, second
);
162 void print_headers(int line
, char *desc
, int value
, int first
, int second
)
164 wattron(header
, A_BOLD
);
165 mvwprintw(header
, line
, 4, "%s", desc
);
166 wattroff(header
, A_BOLD
);
167 mvwprintw(header
, line
, 16, "%d", value
);
168 wmove(header
, line
, 24);
169 print_digits(header
, first
, second
);
170 wmove(header
, line
, 40);
173 void set_window_title(WINDOW
*win
, char *title
)
175 wattron(win
, A_BOLD
);
176 mvwprintw(win
, 0, 1, title
);
177 wattroff(win
, A_BOLD
);
180 void print_log(char *str
)
183 int current_line
= 1;
184 int current_char
= 1;
186 /* rotate the line buffer */
187 if (nb_log_lines
>= MAX_LOG_LINES
) {
188 tmp
= strndup(log_lines
, MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
);
189 tmp2
= strchr(tmp
, '\n');
190 memset(log_lines
, '\0', strlen(log_lines
));
191 strncat(log_lines
, tmp2
+ 1, strlen(tmp2
) - 1);
192 log_lines
[strlen(log_lines
)] = '\n';
193 log_lines
[strlen(log_lines
)] = '\0';
198 strncat(log_lines
, str
, MAX_LINE_LENGTH
- 1);
200 if (nb_log_lines
< MAX_LOG_LINES
)
201 log_lines
[strlen(log_lines
)] = '\n';
202 log_lines
[strlen(log_lines
)] = '\0';
206 set_window_title(status
, "Status");
207 for (i
= 0; i
< strlen(log_lines
); i
++) {
208 if (log_lines
[i
] == '\n') {
209 wmove(status
, ++current_line
, 1);
212 mvwprintw(status
, current_line
, current_char
++, "%c",
219 int process_selected(struct processtop
*process
)
222 struct processtop
*stored_process
;
224 for (i
= 0; i
< selected_processes
->len
; i
++) {
225 stored_process
= g_ptr_array_index(selected_processes
, i
);
226 if (stored_process
->tid
== process
->tid
)
232 void update_selected_processes()
234 if (process_selected(selected_process
)) {
235 g_ptr_array_remove(selected_processes
, selected_process
);
236 print_log("Process removed");
238 g_ptr_array_add(selected_processes
, selected_process
);
239 print_log("Process added");
243 void print_key(WINDOW
*win
, char *key
, char *desc
, int toggle
)
250 wattron(win
, COLOR_PAIR(pair
));
251 wprintw(footer
, "%s", key
);
252 wattroff(win
, COLOR_PAIR(pair
));
253 wprintw(footer
, ":%s", desc
);
258 sem_wait(&update_display_sem
);
261 print_key(footer
, "F2", "CPUtop ", current_view
== cpu
);
262 print_key(footer
, "F3", "PerfTop ", current_view
== perf
);
263 print_key(footer
, "F4", "IOTop ", current_view
== iostream
);
264 print_key(footer
, "Enter", "Details ", current_view
== process_details
);
265 print_key(footer
, "Space", "Highlight ", 0);
266 print_key(footer
, "q", "Quit | ", 0);
267 print_key(footer
, "P", "Perf Pref ", 0);
268 print_key(footer
, "p", "Pause ", toggle_pause
);
271 sem_post(&update_display_sem
);
278 set_window_title(header
, "Statistics for interval [gathering data...[");
279 wattron(header
, A_BOLD
);
280 mvwprintw(header
, 1, 4, "CPUs");
281 mvwprintw(header
, 2, 4, "Threads");
282 mvwprintw(header
, 3, 4, "FDs");
283 wattroff(header
, A_BOLD
);
287 struct tm
format_timestamp(uint64_t timestamp
)
290 uint64_t ts_sec
= 0, ts_nsec
;
294 ts_sec
+= ts_nsec
/ NSEC_PER_SEC
;
295 ts_nsec
= ts_nsec
% NSEC_PER_SEC
;
297 time_s
= (time_t) ts_sec
;
299 localtime_r(&time_s
, &tm
);
304 static void scale_unit(uint64_t bytes
, char *ret
)
306 if (bytes
>= 1000000000)
307 sprintf(ret
, "%" PRIu64
"G", bytes
/1000000000);
308 if (bytes
>= 1000000)
309 sprintf(ret
, "%" PRIu64
"M", bytes
/1000000);
310 else if (bytes
>= 1000)
311 sprintf(ret
, "%" PRIu64
"K", bytes
/1000);
313 sprintf(ret
, "%" PRIu64
, bytes
);
318 struct processtop
*tmp
;
321 for (i
= 0; i
< data
->process_table
->len
; i
++) {
322 tmp
= g_ptr_array_index(data
->process_table
, i
);
323 total
+= tmp
->fileread
;
324 total
+= tmp
->filewrite
;
332 struct tm start
, end
;
333 uint64_t ts_nsec_start
, ts_nsec_end
;
336 ts_nsec_start
= data
->start
% NSEC_PER_SEC
;
337 start
= format_timestamp(data
->start
);
339 ts_nsec_end
= data
->end
% NSEC_PER_SEC
;
340 end
= format_timestamp(data
->end
);
344 set_window_title(header
, "Statistics for interval ");
345 wattron(header
, A_BOLD
);
347 wprintw(header
, "[%02d:%02d:%02d.%09" PRIu64
", %02d:%02d:%02d.%09" PRIu64
"[",
348 start
.tm_hour
, start
.tm_min
, start
.tm_sec
, ts_nsec_start
,
349 end
.tm_hour
, end
.tm_min
, end
.tm_sec
, ts_nsec_end
);
350 mvwprintw(header
, 1, 4, "CPUs");
351 wattroff(header
, A_BOLD
);
352 wprintw(header
, "\t%d\t(max/cpu : %0.2f%)", data
->cpu_table
->len
,
353 100.0/data
->cpu_table
->len
);
354 print_headers(2, "Threads", data
->nbthreads
, data
->nbnewthreads
,
355 -1*(data
->nbdeadthreads
));
356 print_headers(3, "FDs", data
->nbfiles
, data
->nbnewfiles
,
357 -1*(data
->nbclosedfiles
));
358 scale_unit(total_io(), io
);
359 mvwprintw(header
, 3, 43, "%sB/sec", io
);
363 gint
sort_by_cpu_desc(gconstpointer p1
, gconstpointer p2
)
365 struct processtop
*n1
= *(struct processtop
**)p1
;
366 struct processtop
*n2
= *(struct processtop
**)p2
;
367 unsigned long totaln1
= n1
->totalcpunsec
;
368 unsigned long totaln2
= n2
->totalcpunsec
;
370 if (totaln1
< totaln2
)
372 if (totaln1
== totaln2
)
377 gint
sort_by_cpu_group_by_threads_desc(gconstpointer p1
, gconstpointer p2
)
379 struct processtop
*n1
= *(struct processtop
**)p1
;
380 struct processtop
*n2
= *(struct processtop
**)p2
;
381 unsigned long totaln1
= n1
->threadstotalcpunsec
;
382 unsigned long totaln2
= n2
->threadstotalcpunsec
;
384 if (totaln1
< totaln2
)
386 if (totaln1
== totaln2
)
391 void update_cputop_display()
394 int header_offset
= 2;
395 struct processtop
*tmp
;
396 unsigned long elapsed
;
398 int nblinedisplayed
= 0;
399 int current_line
= 0;
401 elapsed
= data
->end
- data
->start
;
402 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
404 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
406 set_window_title(center
, "CPU Top");
407 wattron(center
, A_BOLD
);
408 mvwprintw(center
, 1, 1, "CPU(%)");
409 mvwprintw(center
, 1, 12, "TGID");
410 mvwprintw(center
, 1, 22, "PID");
411 mvwprintw(center
, 1, 32, "NAME");
412 wattroff(center
, A_BOLD
);
414 max_center_lines
= LINES
- 5 - 7 - 1 - header_offset
;
416 /* iterate the process (thread) list */
417 for (i
= list_offset
; i
< data
->process_table
->len
&&
418 nblinedisplayed
< max_center_lines
; i
++) {
419 tmp
= g_ptr_array_index(data
->process_table
, i
);
421 if (process_selected(tmp
)) {
422 wattron(center
, COLOR_PAIR(6));
423 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
425 if (current_line
== selected_line
) {
426 selected_process
= tmp
;
427 wattron(center
, COLOR_PAIR(5));
428 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
431 mvwprintw(center
, current_line
+ header_offset
, 1, "%1.2f",
432 tmp
->totalcpunsec
/ maxcputime
);
434 mvwprintw(center
, current_line
+ header_offset
, 12, "%d", tmp
->pid
);
436 mvwprintw(center
, current_line
+ header_offset
, 22, "%d", tmp
->tid
);
438 mvwprintw(center
, current_line
+ header_offset
, 32, "%s", tmp
->comm
);
439 wattroff(center
, COLOR_PAIR(6));
440 wattroff(center
, COLOR_PAIR(5));
446 gint
sort_perf(gconstpointer p1
, gconstpointer p2
, gpointer key
)
448 struct processtop
*n1
= *(struct processtop
**) p1
;
449 struct processtop
*n2
= *(struct processtop
**) p2
;
451 struct perfcounter
*tmp1
, *tmp2
;
452 unsigned long totaln2
= 0;
453 unsigned long totaln1
= 0;
458 tmp1
= g_hash_table_lookup(n1
->perf
, key
);
462 totaln1
= tmp1
->count
;
464 tmp2
= g_hash_table_lookup(n2
->perf
, key
);
468 totaln2
= tmp2
->count
;
470 if (totaln1
< totaln2
)
472 if (totaln1
== totaln2
) {
475 if (totaln1
< totaln2
)
482 void print_key_title(char *key
, int line
)
484 wattron(center
, A_BOLD
);
485 mvwprintw(center
, line
, 1, "%s\t", key
);
486 wattroff(center
, A_BOLD
);
489 void update_process_details()
491 unsigned long elapsed
;
493 struct processtop
*tmp
= find_process_tid(data
,
494 selected_process
->tid
,
495 selected_process
->comm
);
496 struct files
*file_tmp
;
500 set_window_title(center
, "Process details");
503 elapsed
= data
->end
- data
->start
;
504 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
506 print_key_title("Name", 1);
507 wprintw(center
, "%s", tmp
->comm
);
508 print_key_title("TID", 2);
509 wprintw(center
, "%d", tmp
->tid
);
511 print_key_title("Does not exit at this time", 3);
515 print_key_title("PID", 3);
516 wprintw(center
, "%d", tmp
->pid
);
517 print_key_title("PPID", 4);
518 wprintw(center
, "%d", tmp
->ppid
);
519 print_key_title("CPU", 5);
520 wprintw(center
, "%1.2f %%", tmp
->totalcpunsec
/maxcputime
);
522 print_key_title("READ B/s", 6);
523 scale_unit(tmp
->fileread
, unit
);
524 wprintw(center
, "%s", unit
);
526 print_key_title("WRITE B/s", 7);
527 scale_unit(tmp
->filewrite
, unit
);
528 wprintw(center
, "%s", unit
);
530 wattron(center
, A_BOLD
);
531 mvwprintw(center
, 8, 1, "FD");
532 mvwprintw(center
, 8, 10, "READ");
533 mvwprintw(center
, 8, 17, "WRITE");
534 mvwprintw(center
, 8, 24, "FILENAME");
535 wattroff(center
, A_BOLD
);
537 for (i
= 0; i
< tmp
->process_files_table
->len
; i
++) {
538 file_tmp
= get_file(tmp
, i
);
539 if (file_tmp
!= NULL
) {
540 mvwprintw(center
, 9 + j
, 1, "%d", i
);
541 scale_unit(file_tmp
->read
, unit
);
542 mvwprintw(center
, 9 + j
, 10, "%s", unit
);
543 scale_unit(file_tmp
->write
, unit
);
544 mvwprintw(center
, 9 + j
, 17, "%s", unit
);
545 mvwprintw(center
, 9 + j
, 24, "%s", file_tmp
->name
);
554 int nblinedisplayed
= 0;
555 int current_line
= 0;
556 struct processtop
*tmp
;
557 int header_offset
= 2;
559 struct perfcounter
*perfn1
, *perfn2
;
560 char *perf_key
= NULL
;
565 set_window_title(center
, "Perf Top");
566 wattron(center
, A_BOLD
);
567 mvwprintw(center
, 1, 1, "PID");
568 mvwprintw(center
, 1, 11, "TID");
569 mvwprintw(center
, 1, 22, "NAME");
572 g_hash_table_iter_init(&iter
, data
->perf_list
);
573 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
574 if (perfn1
->visible
) {
575 /* + 5 to strip the "perf_" prefix */
576 mvwprintw(center
, 1, perf_row
, "%s",
581 perf_key
= (char *) key
;
585 wattroff(center
, A_BOLD
);
587 g_ptr_array_sort_with_data(data
->process_table
, sort_perf
, perf_key
);
589 for (i
= 0; i
< data
->process_table
->len
&&
590 nblinedisplayed
< max_center_lines
; i
++) {
591 tmp
= g_ptr_array_index(data
->process_table
, i
);
593 if (process_selected(tmp
)) {
594 wattron(center
, COLOR_PAIR(6));
595 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
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);
603 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
604 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
605 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
607 g_hash_table_iter_init(&iter
, data
->perf_list
);
610 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
611 if (perfn1
->visible
) {
612 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
614 value
= perfn2
->count
;
617 mvwprintw(center
, current_line
+ header_offset
,
618 perf_row
, "%d", value
);
623 wattroff(center
, COLOR_PAIR(6));
624 wattroff(center
, COLOR_PAIR(5));
630 gint
sort_by_ret_desc(gconstpointer p1
, gconstpointer p2
)
632 struct processtop
*n1
= *(struct processtop
**)p1
;
633 struct processtop
*n2
= *(struct processtop
**)p2
;
635 unsigned long totaln1
= n1
->totalfileread
+ n1
->totalfilewrite
;
636 unsigned long totaln2
= n2
->totalfileread
+ n2
->totalfilewrite
;
638 if (totaln1
< totaln2
)
640 if (totaln1
== totaln2
)
645 void update_iostream()
648 int header_offset
= 2;
649 struct processtop
*tmp
;
650 int nblinedisplayed
= 0;
651 int current_line
= 0;
655 set_window_title(center
, "IO Top");
656 wattron(center
, A_BOLD
);
657 mvwprintw(center
, 1, 1, "PID");
658 mvwprintw(center
, 1, 11, "TID");
659 mvwprintw(center
, 1, 22, "NAME");
660 mvwprintw(center
, 1, 40, "R (B/sec)");
661 mvwprintw(center
, 1, 52, "W (B/sec)");
662 mvwprintw(center
, 1, 64, "Total");
663 wattroff(center
, A_BOLD
);
665 g_ptr_array_sort(data
->process_table
, sort_by_ret_desc
);
667 for (i
= list_offset
; i
< data
->process_table
->len
&&
668 nblinedisplayed
< max_center_lines
; i
++) {
669 tmp
= g_ptr_array_index(data
->process_table
, i
);
671 if (process_selected(tmp
)) {
672 wattron(center
, COLOR_PAIR(6));
673 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
675 if (current_line
== selected_line
) {
676 selected_process
= tmp
;
677 wattron(center
, COLOR_PAIR(5));
678 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
681 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
683 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
685 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
687 /* READ (bytes/sec) */
688 scale_unit(tmp
->fileread
, unit
);
689 mvwprintw(center
, current_line
+ header_offset
, 40, "%s", unit
);
691 /* WRITE (bytes/sec) */
692 scale_unit(tmp
->filewrite
, unit
);
693 mvwprintw(center
, current_line
+ header_offset
, 52, "%s", unit
);
696 total
= tmp
->totalfileread
+ tmp
->totalfilewrite
;
698 scale_unit(total
, unit
);
699 mvwprintw(center
, current_line
+ header_offset
, 64, "%s", unit
);
701 wattroff(center
, COLOR_PAIR(6));
702 wattroff(center
, COLOR_PAIR(5));
708 void update_current_view()
710 sem_wait(&update_display_sem
);
717 switch (current_view
) {
719 update_cputop_display();
724 case process_details
:
725 update_process_details();
731 update_cputop_display();
738 sem_post(&update_display_sem
);
741 void setup_perf_panel()
746 if (perf_panel_window
) {
747 del_panel(perf_panel
);
748 delwin(perf_panel_window
);
750 size
= g_hash_table_size(data
->perf_list
);
751 perf_panel_window
= create_window(size
+ 2, 30, 10, 10);
752 perf_panel
= new_panel(perf_panel_window
);
753 perf_panel_visible
= 0;
754 hide_panel(perf_panel
);
757 void update_perf_panel(int line_selected
, int toggle_view
, int toggle_sort
)
760 struct perfcounter
*perf
;
766 werase(perf_panel_window
);
767 box(perf_panel_window
, 0 , 0);
768 set_window_title(perf_panel_window
, "Perf Preferences ");
769 wattron(perf_panel_window
, A_BOLD
);
770 mvwprintw(perf_panel_window
, g_hash_table_size(data
->perf_list
) + 1, 1,
772 wattroff(perf_panel_window
, A_BOLD
);
774 if (toggle_sort
== 1) {
776 perflist
= g_list_first(g_hash_table_get_keys(data
->perf_list
));
778 perf
= g_hash_table_lookup(data
->perf_list
, perflist
->data
);
779 if (i
!= line_selected
)
784 perflist
= g_list_next(perflist
);
786 update_current_view();
790 perflist
= g_list_first(g_hash_table_get_keys(data
->perf_list
));
792 perf
= g_hash_table_lookup(data
->perf_list
, perflist
->data
);
793 if (i
== line_selected
&& toggle_view
== 1) {
794 perf
->visible
= perf
->visible
== 1 ? 0:1;
795 update_current_view();
797 if (i
== line_selected
) {
798 wattron(perf_panel_window
, COLOR_PAIR(5));
799 mvwhline(perf_panel_window
, i
+ 1, 1, ' ', 30 - 2);
802 wattron(perf_panel_window
, A_BOLD
);
803 mvwprintw(perf_panel_window
, i
+ 1, 1, "[%c] %s",
804 perf
->visible
== 1 ? 'x' : ' ',
805 (char *) perflist
->data
+ 5);
806 wattroff(perf_panel_window
, A_BOLD
);
807 wattroff(perf_panel_window
, COLOR_PAIR(5));
809 perflist
= g_list_next(perflist
);
815 void toggle_perf_panel(void)
817 if (perf_panel_visible
) {
818 hide_panel(perf_panel
);
819 perf_panel_visible
= 0;
822 update_perf_panel(perf_line_selected
, 0, 0);
823 show_panel(perf_panel
);
824 perf_panel_visible
= 1;
830 void display(unsigned int index
)
832 last_display_index
= index
;
833 currently_displayed_index
= index
;
834 data
= g_ptr_array_index(copies
, index
);
837 max_elements
= data
->process_table
->len
;
838 update_current_view();
848 sem_wait(&pause_sem
);
851 void resume_display()
855 sem_post(&pause_sem
);
858 void *handle_keyboard(void *p
)
861 while((ch
= getch())) {
863 /* Move the cursor and scroll */
865 if (perf_panel_visible
) {
866 if (perf_line_selected
< g_hash_table_size(data
->perf_list
) - 1)
867 perf_line_selected
++;
868 update_perf_panel(perf_line_selected
, 0, 0);
870 if (selected_line
< (max_center_lines
- 1) &&
871 selected_line
< max_elements
- 1) {
874 } else if (selected_in_list
< (max_elements
- 1)
875 && (list_offset
< (max_elements
- max_center_lines
))) {
879 update_current_view();
885 if (perf_panel_visible
) {
886 if (perf_line_selected
> 0)
887 perf_line_selected
--;
888 update_perf_panel(perf_line_selected
, 0, 0);
890 if (selected_line
> 0) {
893 } else if (selected_in_list
> 0 && list_offset
> 0) {
897 update_current_view();
903 /* Navigate the history with arrows */
905 if (currently_displayed_index
> 0) {
906 currently_displayed_index
--;
907 print_log("Going back in time");
909 print_log("Cannot rewind, last data is already displayed");
911 data
= g_ptr_array_index(copies
, currently_displayed_index
);
912 max_elements
= data
->process_table
->len
;
914 /* we force to pause the display when moving in time */
915 if (toggle_pause
< 0)
918 update_current_view();
922 if (currently_displayed_index
< last_display_index
) {
923 currently_displayed_index
++;
924 print_log("Going forward in time");
925 data
= g_ptr_array_index(copies
, currently_displayed_index
);
926 max_elements
= data
->process_table
->len
;
927 update_current_view();
930 print_log("Manually moving forward");
932 /* we force to resume the refresh when moving forward */
933 if (toggle_pause
> 0)
939 if (perf_panel_visible
) {
940 update_perf_panel(perf_line_selected
, 1, 0);
942 update_selected_processes();
943 update_current_view();
947 if (perf_panel_visible
)
948 update_perf_panel(perf_line_selected
, 0, 1);
951 case 13: /* FIXME : KEY_ENTER ?? */
952 if (current_view
!= process_details
) {
953 previous_view
= current_view
;
954 current_view
= process_details
;
956 current_view
= previous_view
;
957 previous_view
= process_details
;
959 update_current_view();
965 update_current_view();
970 update_current_view();
975 update_current_view();
978 current_view
= iostream
;
980 update_current_view();
987 toggle_threads
*= -1;
988 update_current_view();
991 if (toggle_pause
< 0) {
1002 update_current_view();
1012 selected_processes
= g_ptr_array_new();
1013 sem_init(&update_display_sem
, 0, 1);
1016 header
= create_window(5, COLS
- 1, 0, 0);
1017 center
= create_window(LINES
- 5 - 7, COLS
- 1, 5, 0);
1018 status
= create_window(MAX_LOG_LINES
+ 2, COLS
- 1, LINES
- 7, 0);
1019 footer
= create_window(1, COLS
- 1, LINES
- 1, 0);
1021 print_log("Starting display");
1023 main_panel
= new_panel(center
);
1031 pthread_create(&keyboard_thread
, NULL
, handle_keyboard
, (void *)NULL
);