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
*pref_panel_window
= NULL
;
42 PANEL
*pref_panel
, *main_panel
;
44 int pref_panel_visible
= 0;
45 int pref_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
;
68 struct header_view cputopview
[4];
69 struct header_view iostreamtopview
[3];
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 */
100 init_pair(6, COLOR_WHITE
, COLOR_GREEN
); /* selected process */
102 termtype
= getenv("TERM");
103 if (!strcmp(termtype
, "xterm") || !strcmp(termtype
, "xterm-color") ||
104 !strcmp(termtype
, "vt220")) {
105 define_key("\033[H", KEY_HOME
);
106 define_key("\033[F", KEY_END
);
107 define_key("\033OP", KEY_F(1));
108 define_key("\033OQ", KEY_F(2));
109 define_key("\033OR", KEY_F(3));
110 define_key("\033OS", KEY_F(4));
111 define_key("\0330U", KEY_F(6));
112 define_key("\033[11~", KEY_F(1));
113 define_key("\033[12~", KEY_F(2));
114 define_key("\033[13~", KEY_F(3));
115 define_key("\033[14~", KEY_F(4));
116 define_key("\033[16~", KEY_F(6));
117 define_key("\033[17;2~", KEY_F(18));
119 signal(SIGTERM
, handle_sigterm
);
120 mousemask(BUTTON1_CLICKED
, NULL
);
124 WINDOW
*create_window(int height
, int width
, int startx
, int starty
)
127 win
= newwin(height
, width
, startx
, starty
);
133 WINDOW
*create_window_no_border(int height
, int width
, int startx
, int starty
)
136 win
= newwin(height
, width
, startx
, starty
);
141 void print_digit(WINDOW
*win
, int digit
)
144 wattron(win
, COLOR_PAIR(1));
145 wprintw(win
, "%d", digit
);
146 wattroff(win
, COLOR_PAIR(1));
147 } else if (digit
> 0) {
148 wattron(win
, COLOR_PAIR(2));
149 wprintw(win
, "+%d", digit
);
150 wattroff(win
, COLOR_PAIR(2));
156 void print_digits(WINDOW
*win
, int first
, int second
)
159 print_digit(win
, first
);
161 print_digit(win
, second
);
165 void print_headers(int line
, char *desc
, int value
, int first
, int second
)
167 wattron(header
, A_BOLD
);
168 mvwprintw(header
, line
, 4, "%s", desc
);
169 wattroff(header
, A_BOLD
);
170 mvwprintw(header
, line
, 16, "%d", value
);
171 wmove(header
, line
, 24);
172 print_digits(header
, first
, second
);
173 wmove(header
, line
, 40);
176 void set_window_title(WINDOW
*win
, char *title
)
178 wattron(win
, A_BOLD
);
179 mvwprintw(win
, 0, 1, title
);
180 wattroff(win
, A_BOLD
);
183 void print_log(char *str
)
186 int current_line
= 1;
187 int current_char
= 1;
189 /* rotate the line buffer */
190 if (nb_log_lines
>= MAX_LOG_LINES
) {
191 tmp
= strndup(log_lines
, MAX_LINE_LENGTH
* MAX_LOG_LINES
+ MAX_LOG_LINES
);
192 tmp2
= strchr(tmp
, '\n');
193 memset(log_lines
, '\0', strlen(log_lines
));
194 strncat(log_lines
, tmp2
+ 1, strlen(tmp2
) - 1);
195 log_lines
[strlen(log_lines
)] = '\n';
196 log_lines
[strlen(log_lines
)] = '\0';
201 strncat(log_lines
, str
, MAX_LINE_LENGTH
- 1);
203 if (nb_log_lines
< MAX_LOG_LINES
)
204 log_lines
[strlen(log_lines
)] = '\n';
205 log_lines
[strlen(log_lines
)] = '\0';
209 set_window_title(status
, "Status");
210 for (i
= 0; i
< strlen(log_lines
); i
++) {
211 if (log_lines
[i
] == '\n') {
212 wmove(status
, ++current_line
, 1);
215 mvwprintw(status
, current_line
, current_char
++, "%c",
222 int process_selected(struct processtop
*process
)
225 struct processtop
*stored_process
;
227 for (i
= 0; i
< selected_processes
->len
; i
++) {
228 stored_process
= g_ptr_array_index(selected_processes
, i
);
229 if (stored_process
->tid
== process
->tid
)
235 void update_selected_processes()
237 if (process_selected(selected_process
)) {
238 g_ptr_array_remove(selected_processes
, selected_process
);
239 print_log("Process removed");
241 g_ptr_array_add(selected_processes
, selected_process
);
242 print_log("Process added");
246 void print_key(WINDOW
*win
, char *key
, char *desc
, int toggle
)
253 wattron(win
, COLOR_PAIR(pair
));
254 wprintw(footer
, "%s", key
);
255 wattroff(win
, COLOR_PAIR(pair
));
256 wprintw(footer
, ":%s", desc
);
261 sem_wait(&update_display_sem
);
264 print_key(footer
, "F2", "CPUtop ", current_view
== cpu
);
265 print_key(footer
, "F3", "PerfTop ", current_view
== perf
);
266 print_key(footer
, "F4", "IOTop ", current_view
== iostream
);
267 print_key(footer
, "Enter", "Details ", current_view
== process_details
);
268 print_key(footer
, "Space", "Highlight ", 0);
269 print_key(footer
, "q", "Quit | ", 0);
270 print_key(footer
, "P", "Perf Pref ", 0);
271 print_key(footer
, "p", "Pause ", toggle_pause
);
274 sem_post(&update_display_sem
);
281 set_window_title(header
, "Statistics for interval [gathering data...[");
282 wattron(header
, A_BOLD
);
283 mvwprintw(header
, 1, 4, "CPUs");
284 mvwprintw(header
, 2, 4, "Threads");
285 mvwprintw(header
, 3, 4, "FDs");
286 wattroff(header
, A_BOLD
);
290 struct tm
format_timestamp(uint64_t timestamp
)
293 uint64_t ts_sec
= 0, ts_nsec
;
297 ts_sec
+= ts_nsec
/ NSEC_PER_SEC
;
298 ts_nsec
= ts_nsec
% NSEC_PER_SEC
;
300 time_s
= (time_t) ts_sec
;
302 localtime_r(&time_s
, &tm
);
307 static void scale_unit(uint64_t bytes
, char *ret
)
309 if (bytes
>= 1000000000)
310 sprintf(ret
, "%" PRIu64
"G", bytes
/1000000000);
311 if (bytes
>= 1000000)
312 sprintf(ret
, "%" PRIu64
"M", bytes
/1000000);
313 else if (bytes
>= 1000)
314 sprintf(ret
, "%" PRIu64
"K", bytes
/1000);
316 sprintf(ret
, "%" PRIu64
, bytes
);
321 struct processtop
*tmp
;
324 for (i
= 0; i
< data
->process_table
->len
; i
++) {
325 tmp
= g_ptr_array_index(data
->process_table
, i
);
326 total
+= tmp
->fileread
;
327 total
+= tmp
->filewrite
;
335 struct tm start
, end
;
336 uint64_t ts_nsec_start
, ts_nsec_end
;
339 ts_nsec_start
= data
->start
% NSEC_PER_SEC
;
340 start
= format_timestamp(data
->start
);
342 ts_nsec_end
= data
->end
% NSEC_PER_SEC
;
343 end
= format_timestamp(data
->end
);
347 set_window_title(header
, "Statistics for interval ");
348 wattron(header
, A_BOLD
);
350 wprintw(header
, "[%02d:%02d:%02d.%09" PRIu64
", %02d:%02d:%02d.%09" PRIu64
"[",
351 start
.tm_hour
, start
.tm_min
, start
.tm_sec
, ts_nsec_start
,
352 end
.tm_hour
, end
.tm_min
, end
.tm_sec
, ts_nsec_end
);
353 mvwprintw(header
, 1, 4, "CPUs");
354 wattroff(header
, A_BOLD
);
355 wprintw(header
, "\t%d\t(max/cpu : %0.2f%)", data
->cpu_table
->len
,
356 100.0/data
->cpu_table
->len
);
357 print_headers(2, "Threads", data
->nbthreads
, data
->nbnewthreads
,
358 -1*(data
->nbdeadthreads
));
359 print_headers(3, "FDs", data
->nbfiles
, data
->nbnewfiles
,
360 -1*(data
->nbclosedfiles
));
361 scale_unit(total_io(), io
);
362 mvwprintw(header
, 3, 43, "%sB/sec", io
);
366 gint
sort_by_cpu_desc(gconstpointer p1
, gconstpointer p2
)
368 struct processtop
*n1
= *(struct processtop
**)p1
;
369 struct processtop
*n2
= *(struct processtop
**)p2
;
370 unsigned long totaln1
= n1
->totalcpunsec
;
371 unsigned long totaln2
= n2
->totalcpunsec
;
373 if (totaln1
< totaln2
)
375 if (totaln1
== totaln2
)
380 gint
sort_by_tid_desc(gconstpointer p1
, gconstpointer p2
)
382 struct processtop
*n1
= *(struct processtop
**)p1
;
383 struct processtop
*n2
= *(struct processtop
**)p2
;
384 unsigned long totaln1
= n1
->tid
;
385 unsigned long totaln2
= n2
->tid
;
387 if (totaln1
< totaln2
)
389 if (totaln1
== totaln2
)
394 gint
sort_by_pid_desc(gconstpointer p1
, gconstpointer p2
)
396 struct processtop
*n1
= *(struct processtop
**)p1
;
397 struct processtop
*n2
= *(struct processtop
**)p2
;
398 unsigned long totaln1
= n1
->pid
;
399 unsigned long totaln2
= n2
->pid
;
401 if (totaln1
< totaln2
)
403 if (totaln1
== totaln2
)
408 gint
sort_by_process_read_desc(gconstpointer p1
, gconstpointer p2
)
410 struct processtop
*n1
= *(struct processtop
**)p1
;
411 struct processtop
*n2
= *(struct processtop
**)p2
;
412 unsigned long totaln1
= n1
->fileread
;
413 unsigned long totaln2
= n2
->fileread
;
415 if (totaln1
< totaln2
)
417 if (totaln1
== totaln2
)
422 gint
sort_by_process_write_desc(gconstpointer p1
, gconstpointer p2
)
424 struct processtop
*n1
= *(struct processtop
**)p1
;
425 struct processtop
*n2
= *(struct processtop
**)p2
;
426 unsigned long totaln1
= n1
->filewrite
;
427 unsigned long totaln2
= n2
->filewrite
;
429 if (totaln1
< totaln2
)
431 if (totaln1
== totaln2
)
436 gint
sort_by_process_total_desc(gconstpointer p1
, gconstpointer p2
)
438 struct processtop
*n1
= *(struct processtop
**)p1
;
439 struct processtop
*n2
= *(struct processtop
**)p2
;
440 unsigned long totaln1
= n1
->filewrite
+ n1
->fileread
;
441 unsigned long totaln2
= n2
->filewrite
+ n2
->fileread
;
443 if (totaln1
< totaln2
)
445 if (totaln1
== totaln2
)
450 gint
sort_by_cpu_group_by_threads_desc(gconstpointer p1
, gconstpointer p2
)
452 struct processtop
*n1
= *(struct processtop
**)p1
;
453 struct processtop
*n2
= *(struct processtop
**)p2
;
454 unsigned long totaln1
= n1
->threadstotalcpunsec
;
455 unsigned long totaln2
= n2
->threadstotalcpunsec
;
457 if (totaln1
< totaln2
)
459 if (totaln1
== totaln2
)
464 void update_cputop_display()
467 int header_offset
= 2;
468 struct processtop
*tmp
;
469 unsigned long elapsed
;
471 int nblinedisplayed
= 0;
472 int current_line
= 0;
474 elapsed
= data
->end
- data
->start
;
475 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
477 if (cputopview
[0].sort
== 1)
478 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
479 else if (cputopview
[1].sort
== 1)
480 g_ptr_array_sort(data
->process_table
, sort_by_pid_desc
);
481 else if (cputopview
[2].sort
== 1)
482 g_ptr_array_sort(data
->process_table
, sort_by_tid_desc
);
483 else if (cputopview
[3].sort
== 1)
484 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
486 g_ptr_array_sort(data
->process_table
, sort_by_cpu_desc
);
488 set_window_title(center
, "CPU Top");
489 wattron(center
, A_BOLD
);
490 mvwprintw(center
, 1, 1, cputopview
[0].title
);
491 mvwprintw(center
, 1, 12, cputopview
[1].title
);
492 mvwprintw(center
, 1, 22, cputopview
[2].title
);
493 mvwprintw(center
, 1, 32, cputopview
[3].title
);
494 wattroff(center
, A_BOLD
);
496 max_center_lines
= LINES
- 5 - 7 - 1 - header_offset
;
498 /* iterate the process (thread) list */
499 for (i
= list_offset
; i
< data
->process_table
->len
&&
500 nblinedisplayed
< max_center_lines
; i
++) {
501 tmp
= g_ptr_array_index(data
->process_table
, i
);
503 /* FIXME : random segfault here */
504 if (process_selected(tmp
)) {
505 wattron(center
, COLOR_PAIR(6));
506 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
508 if (current_line
== selected_line
) {
509 selected_process
= tmp
;
510 wattron(center
, COLOR_PAIR(5));
511 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
514 mvwprintw(center
, current_line
+ header_offset
, 1, "%1.2f",
515 tmp
->totalcpunsec
/ maxcputime
);
517 mvwprintw(center
, current_line
+ header_offset
, 12, "%d", tmp
->pid
);
519 mvwprintw(center
, current_line
+ header_offset
, 22, "%d", tmp
->tid
);
521 mvwprintw(center
, current_line
+ header_offset
, 32, "%s", tmp
->comm
);
522 wattroff(center
, COLOR_PAIR(6));
523 wattroff(center
, COLOR_PAIR(5));
529 gint
sort_perf(gconstpointer p1
, gconstpointer p2
, gpointer key
)
531 struct processtop
*n1
= *(struct processtop
**) p1
;
532 struct processtop
*n2
= *(struct processtop
**) p2
;
534 struct perfcounter
*tmp1
, *tmp2
;
535 unsigned long totaln2
= 0;
536 unsigned long totaln1
= 0;
541 tmp1
= g_hash_table_lookup(n1
->perf
, key
);
545 totaln1
= tmp1
->count
;
547 tmp2
= g_hash_table_lookup(n2
->perf
, key
);
551 totaln2
= tmp2
->count
;
553 if (totaln1
< totaln2
)
555 if (totaln1
== totaln2
) {
558 if (totaln1
< totaln2
)
565 void print_key_title(char *key
, int line
)
567 wattron(center
, A_BOLD
);
568 mvwprintw(center
, line
, 1, "%s\t", key
);
569 wattroff(center
, A_BOLD
);
572 void update_process_details()
574 unsigned long elapsed
;
576 struct processtop
*tmp
;
577 struct files
*file_tmp
;
580 char filename_buf
[COLS
];
582 set_window_title(center
, "Process details");
585 tmp
= find_process_tid(data
,
586 selected_process
->tid
,
587 selected_process
->comm
);
588 elapsed
= data
->end
- data
->start
;
589 maxcputime
= elapsed
* data
->cpu_table
->len
/ 100.0;
591 print_key_title("Name", 1);
592 wprintw(center
, "%s", selected_process
->comm
);
593 print_key_title("TID", 2);
594 wprintw(center
, "%d", selected_process
->tid
);
596 print_key_title("Does not exit at this time", 3);
600 print_key_title("PID", 3);
601 wprintw(center
, "%d", tmp
->pid
);
602 print_key_title("PPID", 4);
603 wprintw(center
, "%d", tmp
->ppid
);
604 print_key_title("CPU", 5);
605 wprintw(center
, "%1.2f %%", tmp
->totalcpunsec
/maxcputime
);
607 print_key_title("READ B/s", 6);
608 scale_unit(tmp
->fileread
, unit
);
609 wprintw(center
, "%s", unit
);
611 print_key_title("WRITE B/s", 7);
612 scale_unit(tmp
->filewrite
, unit
);
613 wprintw(center
, "%s", unit
);
615 wattron(center
, A_BOLD
);
616 mvwprintw(center
, 8, 1, "FD");
617 mvwprintw(center
, 8, 10, "READ");
618 mvwprintw(center
, 8, 17, "WRITE");
619 mvwprintw(center
, 8, 24, "FILENAME");
620 wattroff(center
, A_BOLD
);
622 for (i
= selected_line
; i
< tmp
->process_files_table
->len
&&
623 i
< (selected_line
+ max_center_lines
- 7); i
++) {
624 file_tmp
= get_file(tmp
, i
);
625 if (file_tmp
!= NULL
) {
626 mvwprintw(center
, 9 + j
, 1, "%d", i
);
627 scale_unit(file_tmp
->read
, unit
);
628 mvwprintw(center
, 9 + j
, 10, "%s", unit
);
629 scale_unit(file_tmp
->write
, unit
);
630 mvwprintw(center
, 9 + j
, 17, "%s", unit
);
631 snprintf(filename_buf
, COLS
- 25, "%s", file_tmp
->name
);
632 mvwprintw(center
, 9 + j
, 24, "%s", filename_buf
);
641 int nblinedisplayed
= 0;
642 int current_line
= 0;
643 struct processtop
*tmp
;
644 int header_offset
= 2;
646 struct perfcounter
*perfn1
, *perfn2
;
647 char *perf_key
= NULL
;
652 set_window_title(center
, "Perf Top");
653 wattron(center
, A_BOLD
);
654 mvwprintw(center
, 1, 1, "PID");
655 mvwprintw(center
, 1, 11, "TID");
656 mvwprintw(center
, 1, 22, "NAME");
659 g_hash_table_iter_init(&iter
, global_perf_liszt
);
660 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
661 if (perfn1
->visible
) {
662 /* + 5 to strip the "perf_" prefix */
663 mvwprintw(center
, 1, perf_row
, "%s",
668 perf_key
= (char *) key
;
672 wattroff(center
, A_BOLD
);
674 g_ptr_array_sort_with_data(data
->process_table
, sort_perf
, perf_key
);
676 for (i
= 0; i
< data
->process_table
->len
&&
677 nblinedisplayed
< max_center_lines
; i
++) {
678 tmp
= g_ptr_array_index(data
->process_table
, i
);
680 if (process_selected(tmp
)) {
681 wattron(center
, COLOR_PAIR(6));
682 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
684 if (current_line
== selected_line
) {
685 selected_process
= tmp
;
686 wattron(center
, COLOR_PAIR(5));
687 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
690 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
691 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
692 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
694 g_hash_table_iter_init(&iter
, global_perf_liszt
);
697 while (g_hash_table_iter_next (&iter
, &key
, (gpointer
) &perfn1
)) {
698 if (perfn1
->visible
) {
699 perfn2
= g_hash_table_lookup(tmp
->perf
, (char *) key
);
701 value
= perfn2
->count
;
704 mvwprintw(center
, current_line
+ header_offset
,
705 perf_row
, "%d", value
);
710 wattroff(center
, COLOR_PAIR(6));
711 wattroff(center
, COLOR_PAIR(5));
717 void update_iostream()
720 int header_offset
= 2;
721 struct processtop
*tmp
;
722 int nblinedisplayed
= 0;
723 int current_line
= 0;
727 set_window_title(center
, "IO Top");
728 wattron(center
, A_BOLD
);
729 mvwprintw(center
, 1, 1, "PID");
730 mvwprintw(center
, 1, 11, "TID");
731 mvwprintw(center
, 1, 22, "NAME");
732 mvwprintw(center
, 1, 40, "R (B/sec)");
733 mvwprintw(center
, 1, 52, "W (B/sec)");
734 mvwprintw(center
, 1, 64, "Total");
735 wattroff(center
, A_BOLD
);
737 if (iostreamtopview
[0].sort
== 1)
738 g_ptr_array_sort(data
->process_table
, sort_by_process_read_desc
);
739 else if (iostreamtopview
[1].sort
== 1)
740 g_ptr_array_sort(data
->process_table
, sort_by_process_write_desc
);
741 else if (iostreamtopview
[2].sort
== 1)
742 g_ptr_array_sort(data
->process_table
, sort_by_process_total_desc
);
744 g_ptr_array_sort(data
->process_table
, sort_by_process_total_desc
);
746 for (i
= list_offset
; i
< data
->process_table
->len
&&
747 nblinedisplayed
< max_center_lines
; i
++) {
748 tmp
= g_ptr_array_index(data
->process_table
, i
);
750 if (process_selected(tmp
)) {
751 wattron(center
, COLOR_PAIR(6));
752 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
754 if (current_line
== selected_line
) {
755 selected_process
= tmp
;
756 wattron(center
, COLOR_PAIR(5));
757 mvwhline(center
, current_line
+ header_offset
, 1, ' ', COLS
-3);
760 mvwprintw(center
, current_line
+ header_offset
, 1, "%d", tmp
->pid
);
762 mvwprintw(center
, current_line
+ header_offset
, 11, "%d", tmp
->tid
);
764 mvwprintw(center
, current_line
+ header_offset
, 22, "%s", tmp
->comm
);
766 /* READ (bytes/sec) */
767 scale_unit(tmp
->fileread
, unit
);
768 mvwprintw(center
, current_line
+ header_offset
, 40, "%s", unit
);
770 /* WRITE (bytes/sec) */
771 scale_unit(tmp
->filewrite
, unit
);
772 mvwprintw(center
, current_line
+ header_offset
, 52, "%s", unit
);
775 total
= tmp
->totalfileread
+ tmp
->totalfilewrite
;
777 scale_unit(total
, unit
);
778 mvwprintw(center
, current_line
+ header_offset
, 64, "%s", unit
);
780 wattroff(center
, COLOR_PAIR(6));
781 wattroff(center
, COLOR_PAIR(5));
787 void update_current_view()
789 sem_wait(&update_display_sem
);
796 switch (current_view
) {
798 update_cputop_display();
803 case process_details
:
804 update_process_details();
810 update_cputop_display();
817 sem_post(&update_display_sem
);
820 void update_iostream_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
827 if (pref_panel_window
) {
828 del_panel(pref_panel
);
829 delwin(pref_panel_window
);
833 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
834 pref_panel
= new_panel(pref_panel_window
);
836 werase(pref_panel_window
);
837 box(pref_panel_window
, 0 , 0);
838 set_window_title(pref_panel_window
, "IOTop Preferences ");
839 wattron(pref_panel_window
, A_BOLD
);
840 mvwprintw(pref_panel_window
, size
+ 1, 1,
842 wattroff(pref_panel_window
, A_BOLD
);
844 if (*line_selected
> (size
- 1))
845 *line_selected
= size
- 1;
846 if (toggle_sort
== 1) {
847 if (iostreamtopview
[*line_selected
].sort
== 1)
848 iostreamtopview
[*line_selected
].reverse
= 1;
849 for (i
= 0; i
< size
; i
++)
850 iostreamtopview
[i
].sort
= 0;
851 iostreamtopview
[*line_selected
].sort
= 1;
852 update_current_view();
855 for (i
= 0; i
< size
; i
++) {
856 if (i
== *line_selected
) {
857 wattron(pref_panel_window
, COLOR_PAIR(5));
858 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
860 if (iostreamtopview
[i
].sort
== 1)
861 wattron(pref_panel_window
, A_BOLD
);
862 mvwprintw(pref_panel_window
, i
+ 1, 1, "[x] %s",
863 iostreamtopview
[i
].title
);
864 wattroff(pref_panel_window
, A_BOLD
);
865 wattroff(pref_panel_window
, COLOR_PAIR(5));
872 void update_cpu_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
879 if (pref_panel_window
) {
880 del_panel(pref_panel
);
881 delwin(pref_panel_window
);
885 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
886 pref_panel
= new_panel(pref_panel_window
);
888 werase(pref_panel_window
);
889 box(pref_panel_window
, 0 , 0);
890 set_window_title(pref_panel_window
, "CPUTop Preferences ");
891 wattron(pref_panel_window
, A_BOLD
);
892 mvwprintw(pref_panel_window
, size
+ 1, 1,
894 wattroff(pref_panel_window
, A_BOLD
);
896 if (*line_selected
> (size
- 1))
897 *line_selected
= size
- 1;
898 if (toggle_sort
== 1) {
899 /* special case, we don't support sorting by procname for now */
900 if (*line_selected
!= 3) {
901 if (cputopview
[*line_selected
].sort
== 1)
902 cputopview
[*line_selected
].reverse
= 1;
903 for (i
= 0; i
< size
; i
++)
904 cputopview
[i
].sort
= 0;
905 cputopview
[*line_selected
].sort
= 1;
906 update_current_view();
910 for (i
= 0; i
< size
; i
++) {
911 if (i
== *line_selected
) {
912 wattron(pref_panel_window
, COLOR_PAIR(5));
913 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
915 if (cputopview
[i
].sort
== 1)
916 wattron(pref_panel_window
, A_BOLD
);
917 mvwprintw(pref_panel_window
, i
+ 1, 1, "[x] %s",
918 cputopview
[i
].title
);
919 wattroff(pref_panel_window
, A_BOLD
);
920 wattroff(pref_panel_window
, COLOR_PAIR(5));
927 void update_perf_pref(int *line_selected
, int toggle_view
, int toggle_sort
)
930 struct perfcounter
*perf
;
936 if (pref_panel_window
) {
937 del_panel(pref_panel
);
938 delwin(pref_panel_window
);
940 size
= g_hash_table_size(global_perf_liszt
);
942 pref_panel_window
= create_window(size
+ 2, 30, 10, 10);
943 pref_panel
= new_panel(pref_panel_window
);
945 werase(pref_panel_window
);
946 box(pref_panel_window
, 0 , 0);
947 set_window_title(pref_panel_window
, "Perf Preferences ");
948 wattron(pref_panel_window
, A_BOLD
);
949 mvwprintw(pref_panel_window
, g_hash_table_size(global_perf_liszt
) + 1, 1,
951 wattroff(pref_panel_window
, A_BOLD
);
953 if (toggle_sort
== 1) {
955 perflist
= g_list_first(g_hash_table_get_keys(global_perf_liszt
));
957 perf
= g_hash_table_lookup(global_perf_liszt
, perflist
->data
);
958 if (i
!= *line_selected
)
963 perflist
= g_list_next(perflist
);
965 update_current_view();
969 perflist
= g_list_first(g_hash_table_get_keys(global_perf_liszt
));
971 perf
= g_hash_table_lookup(global_perf_liszt
, perflist
->data
);
972 if (i
== *line_selected
&& toggle_view
== 1) {
973 perf
->visible
= perf
->visible
== 1 ? 0:1;
974 update_current_view();
976 if (i
== *line_selected
) {
977 wattron(pref_panel_window
, COLOR_PAIR(5));
978 mvwhline(pref_panel_window
, i
+ 1, 1, ' ', 30 - 2);
981 wattron(pref_panel_window
, A_BOLD
);
982 mvwprintw(pref_panel_window
, i
+ 1, 1, "[%c] %s",
983 perf
->visible
== 1 ? 'x' : ' ',
984 (char *) perflist
->data
+ 5);
985 wattroff(pref_panel_window
, A_BOLD
);
986 wattroff(pref_panel_window
, COLOR_PAIR(5));
988 perflist
= g_list_next(perflist
);
994 int update_preference_panel(int *line_selected
, int toggle_view
, int toggle_sort
)
998 switch(current_view
) {
1000 update_perf_pref(line_selected
, toggle_view
, toggle_sort
);
1003 update_cpu_pref(line_selected
, toggle_view
, toggle_sort
);
1006 update_iostream_pref(line_selected
, toggle_view
, toggle_sort
);
1016 void toggle_pref_panel(void)
1020 if (pref_panel_visible
) {
1021 hide_panel(pref_panel
);
1022 pref_panel_visible
= 0;
1024 ret
= update_preference_panel(&pref_line_selected
, 0, 0);
1027 show_panel(pref_panel
);
1028 pref_panel_visible
= 1;
1034 void display(unsigned int index
)
1036 last_display_index
= index
;
1037 currently_displayed_index
= index
;
1038 data
= g_ptr_array_index(copies
, index
);
1041 max_elements
= data
->process_table
->len
;
1042 update_current_view();
1048 void pause_display()
1052 sem_wait(&pause_sem
);
1055 void resume_display()
1058 print_log("Resume");
1059 sem_post(&pause_sem
);
1062 void *handle_keyboard(void *p
)
1065 while((ch
= getch())) {
1067 /* Move the cursor and scroll */
1069 if (pref_panel_visible
) {
1070 pref_line_selected
++;
1071 update_preference_panel(&pref_line_selected
, 0, 0);
1073 if (selected_line
< (max_center_lines
- 1) &&
1074 selected_line
< max_elements
- 1) {
1077 } else if (selected_in_list
< (max_elements
- 1)
1078 && (list_offset
< (max_elements
- max_center_lines
))) {
1082 update_current_view();
1088 if (pref_panel_visible
) {
1089 if (pref_line_selected
> 0)
1090 pref_line_selected
--;
1091 update_preference_panel(&pref_line_selected
, 0, 0);
1093 if (selected_line
> 0) {
1096 } else if (selected_in_list
> 0 && list_offset
> 0) {
1100 update_current_view();
1106 /* Navigate the history with arrows */
1108 if (currently_displayed_index
> 0) {
1109 currently_displayed_index
--;
1110 print_log("Going back in time");
1112 print_log("Cannot rewind, last data is already displayed");
1114 data
= g_ptr_array_index(copies
, currently_displayed_index
);
1115 max_elements
= data
->process_table
->len
;
1117 /* we force to pause the display when moving in time */
1118 if (toggle_pause
< 0)
1121 update_current_view();
1125 if (currently_displayed_index
< last_display_index
) {
1126 currently_displayed_index
++;
1127 print_log("Going forward in time");
1128 data
= g_ptr_array_index(copies
, currently_displayed_index
);
1129 max_elements
= data
->process_table
->len
;
1130 update_current_view();
1133 print_log("Manually moving forward");
1135 /* we force to resume the refresh when moving forward */
1136 if (toggle_pause
> 0)
1142 if (pref_panel_visible
) {
1143 update_preference_panel(&pref_line_selected
, 1, 0);
1145 update_selected_processes();
1146 update_current_view();
1150 if (pref_panel_visible
)
1151 update_preference_panel(&pref_line_selected
, 0, 1);
1154 case 13: /* FIXME : KEY_ENTER ?? */
1155 if (current_view
!= process_details
) {
1156 previous_view
= current_view
;
1157 current_view
= process_details
;
1159 current_view
= previous_view
;
1160 previous_view
= process_details
;
1162 update_current_view();
1166 if (pref_panel_visible
)
1167 toggle_pref_panel();
1170 update_current_view();
1173 if (pref_panel_visible
)
1174 toggle_pref_panel();
1177 update_current_view();
1180 if (pref_panel_visible
)
1181 toggle_pref_panel();
1182 current_view
= perf
;
1184 update_current_view();
1187 if (pref_panel_visible
)
1188 toggle_pref_panel();
1189 current_view
= iostream
;
1191 update_current_view();
1198 toggle_threads
*= -1;
1199 update_current_view();
1202 if (toggle_pause
< 0) {
1209 toggle_pref_panel();
1213 update_current_view();
1221 void init_view_headers()
1223 cputopview
[0].title
= strdup("CPU(%)");
1224 cputopview
[0].sort
= 1;
1225 cputopview
[1].title
= strdup("TGID");
1226 cputopview
[2].title
= strdup("PID");
1227 cputopview
[3].title
= strdup("NAME");
1229 iostreamtopview
[0].title
= strdup("R (B/sec)");
1230 iostreamtopview
[1].title
= strdup("W (B/sec)");
1231 iostreamtopview
[2].title
= strdup("Total (B)");
1232 iostreamtopview
[2].sort
= 1;
1237 selected_processes
= g_ptr_array_new();
1238 sem_init(&update_display_sem
, 0, 1);
1239 init_view_headers();
1242 header
= create_window(5, COLS
- 1, 0, 0);
1243 center
= create_window(LINES
- 5 - 7, COLS
- 1, 5, 0);
1244 status
= create_window(MAX_LOG_LINES
+ 2, COLS
- 1, LINES
- 7, 0);
1245 footer
= create_window(1, COLS
- 1, LINES
- 1, 0);
1247 print_log("Starting display");
1249 main_panel
= new_panel(center
);
1256 pthread_create(&keyboard_thread
, NULL
, handle_keyboard
, (void *)NULL
);