Convert LTTngTop to C++ and state system
[lttngtop.git] / src / cursesdisplay.cpp
1 /*
2 * Copyright (C) 2011-2012 Julien Desfossez
3 *
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;
7 *
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.
12 *
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.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <signal.h>
21 #include <string.h>
22 #include <ncurses.h>
23 #include <panel.h>
24 #include <pthread.h>
25 #include <semaphore.h>
26
27 #include <state/StateSystem.hpp>
28 #include <state/statevalue/StateValue.hpp>
29 #include <state/statevalue/IntegerStateValue.hpp>
30 #include <state/statevalue/StringStateValue.hpp>
31 #include <state/statevalue/NullStateValue.hpp>
32 #include <state/statevalue/QuarkStateValue.hpp>
33
34 #define __STDC_FORMAT_MACROS
35 #include <inttypes.h>
36
37 #include "cursesdisplay.h"
38 #include "lttngtoptypes.h"
39 #include "iostreamtop.h"
40 #include "common.h"
41
42 #define DEFAULT_DELAY 15
43 #define MAX_LINE_LENGTH 50
44 #define MAX_LOG_LINES 4
45
46 using namespace State;
47
48 enum view_list current_view;
49 enum view_list previous_view;
50
51 /* to prevent concurrent updates of the different windows */
52 sem_t update_display_sem;
53
54 char *termtype;
55 WINDOW *footer, *header, *center, *status;
56 WINDOW *pref_panel_window = NULL;
57 PANEL *pref_panel, *main_panel;
58
59 int pref_panel_visible = 0;
60 int pref_line_selected = 0;
61 int pref_current_sort = 0;
62
63 Quark selected_process;
64 int selected_ret;
65
66 int selected_line = 0; /* select bar position */
67 int selected_in_list = 0; /* selection relative to the whole list */
68 int list_offset = 0; /* first index in the list to display (scroll) */
69 int nb_log_lines = 0;
70 char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES];
71
72 int max_elements = 80;
73
74 int toggle_threads = 1;
75 int toggle_pause = -1;
76
77 int max_center_lines;
78 GPtrArray *selected_processes;
79
80 pthread_t keyboard_thread;
81
82 struct header_view cputopview[4];
83 struct header_view iostreamtopview[3];
84 struct header_view fileview[3];
85
86 unsigned long i_start = 0;
87 unsigned long i_end = 0;
88
89 std::string sort_perf_key;
90
91
92 void reset_ncurses()
93 {
94 curs_set(1);
95 endwin();
96 exit(0);
97 }
98
99 static void handle_sigterm(int signal)
100 {
101 reset_ncurses();
102 }
103
104 void init_screen()
105 {
106 initscr();
107 noecho();
108 halfdelay(DEFAULT_DELAY);
109 nonl();
110 intrflush(stdscr, false);
111 keypad(stdscr, true);
112 curs_set(0);
113
114 if (has_colors()) {
115 start_color();
116 init_pair(1, COLOR_RED, COLOR_BLACK); /* - */
117 init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */
118 init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */
119 init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */
120 init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */
121 init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */
122 }
123 termtype = getenv("TERM");
124 if (!strcmp(termtype, "xterm") || !strcmp(termtype, "xterm-color") ||
125 !strcmp(termtype, "vt220")) {
126 define_key("\033[H", KEY_HOME);
127 define_key("\033[F", KEY_END);
128 define_key("\033OP", KEY_F(1));
129 define_key("\033OQ", KEY_F(2));
130 define_key("\033OR", KEY_F(3));
131 define_key("\033OS", KEY_F(4));
132 define_key("\0330U", KEY_F(6));
133 define_key("\033[11~", KEY_F(1));
134 define_key("\033[12~", KEY_F(2));
135 define_key("\033[13~", KEY_F(3));
136 define_key("\033[14~", KEY_F(4));
137 define_key("\033[16~", KEY_F(6));
138 define_key("\033[17;2~", KEY_F(18));
139 }
140 signal(SIGTERM, handle_sigterm);
141 mousemask(BUTTON1_CLICKED, NULL);
142 refresh();
143 }
144
145 WINDOW *create_window(int height, int width, int startx, int starty)
146 {
147 WINDOW *win;
148 win = newwin(height, width, startx, starty);
149 box(win, 0 , 0);
150 wrefresh(win);
151 return win;
152 }
153
154 WINDOW *create_window_no_border(int height, int width, int startx, int starty)
155 {
156 WINDOW *win;
157 win = newwin(height, width, startx, starty);
158 wrefresh(win);
159 return win;
160 }
161
162 void print_digit(WINDOW *win, int digit)
163 {
164 if (digit < 0) {
165 wattron(win, COLOR_PAIR(1));
166 wprintw(win, "%d", digit);
167 wattroff(win, COLOR_PAIR(1));
168 } else if (digit > 0) {
169 wattron(win, COLOR_PAIR(2));
170 wprintw(win, "+%d", digit);
171 wattroff(win, COLOR_PAIR(2));
172 } else {
173 wprintw(win, "0");
174 }
175 }
176
177 void print_digits(WINDOW *win, int first, int second)
178 {
179 wprintw(win, "(");
180 print_digit(win, first);
181 wprintw(win, ", ");
182 print_digit(win, second);
183 wprintw(win, ")");
184 }
185
186 void print_headers(int line, const char desc[], int value, int first, int second)
187 {
188 wattron(header, A_BOLD);
189 mvwprintw(header, line, 4, "%s", desc);
190 wattroff(header, A_BOLD);
191 mvwprintw(header, line, 16, "%d", value);
192 wmove(header, line, 24);
193 print_digits(header, first, second);
194 wmove(header, line, 40);
195 }
196
197 void set_window_title(WINDOW *win, const char title[])
198 {
199 wattron(win, A_BOLD);
200 mvwprintw(win, 0, 1, title);
201 wattroff(win, A_BOLD);
202 }
203
204 void print_log(const char str[])
205 {
206 unsigned int i;
207 int current_line = 1;
208 int current_char = 1;
209 char *tmp, *tmp2;
210 /* rotate the line buffer */
211 if (nb_log_lines >= MAX_LOG_LINES) {
212 tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES);
213 tmp2 = strchr(tmp, '\n');
214 memset(log_lines, '\0', strlen(log_lines));
215 strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1);
216 log_lines[strlen(log_lines)] = '\n';
217 log_lines[strlen(log_lines)] = '\0';
218 free(tmp);
219 }
220 nb_log_lines++;
221
222 strncat(log_lines, str, MAX_LINE_LENGTH - 1);
223
224 if (nb_log_lines < MAX_LOG_LINES)
225 log_lines[strlen(log_lines)] = '\n';
226 log_lines[strlen(log_lines)] = '\0';
227
228 werase(status);
229 box(status, 0 , 0);
230 set_window_title(status, "Status");
231 for (i = 0; i < strlen(log_lines); i++) {
232 if (log_lines[i] == '\n') {
233 wmove(status, ++current_line, 1);
234 current_char = 1;
235 } else {
236 mvwprintw(status, current_line, current_char++, "%c",
237 log_lines[i]);
238 }
239 }
240 wrefresh(status);
241 }
242
243 int process_selected(Quark proc)
244 {
245 int selected;
246 get_current_attribute_value_int(&proc, "selected", selected);
247 return selected;
248 }
249
250 void update_selected_processes()
251 {
252 Quark selected = state_system->getQuark(selected_process, "selected");
253 if (process_selected(selected_process)) {
254 state_system->updateCurrentState(selected, 0);
255 print_log("Process removed");
256 } else {
257 state_system->updateCurrentState(selected, 1);
258 print_log("Process added");
259 }
260 }
261
262 void print_key(WINDOW *win, const char key[], const char desc[], int toggle)
263 {
264 int pair;
265 if (toggle > 0)
266 pair = 4;
267 else
268 pair = 3;
269 wattron(win, COLOR_PAIR(pair));
270 wprintw(footer, "%s", key);
271 wattroff(win, COLOR_PAIR(pair));
272 wprintw(footer, ":%s", desc);
273 }
274
275 void update_footer()
276 {
277 sem_wait(&update_display_sem);
278 werase(footer);
279 wmove(footer, 1, 1);
280 print_key(footer, "F2", "CPUtop ", current_view == cpu);
281 print_key(footer, "F3", "PerfTop ", current_view == perf);
282 print_key(footer, "F4", "IOTop ", current_view == iostream);
283 print_key(footer, "Enter", "Details ", current_view == process_details);
284 print_key(footer, "Space", "Highlight ", 0);
285 print_key(footer, "q", "Quit ", 0);
286 print_key(footer, "r", "Pref ", 0);
287 print_key(footer, "t", "Threads ", toggle_threads);
288 print_key(footer, "p", "Pause ", toggle_pause);
289
290 wrefresh(footer);
291 sem_post(&update_display_sem);
292 }
293
294 void basic_header()
295 {
296 werase(header);
297 box(header, 0 , 0);
298 set_window_title(header, "Statistics for interval [gathering data...[");
299 wattron(header, A_BOLD);
300 mvwprintw(header, 1, 4, "CPUs");
301 mvwprintw(header, 2, 4, "Threads");
302 mvwprintw(header, 3, 4, "FDs");
303 wattroff(header, A_BOLD);
304 wrefresh(header);
305 }
306
307 struct tm format_timestamp(uint64_t timestamp)
308 {
309 struct tm tm;
310 uint64_t ts_sec = 0, ts_nsec;
311 time_t time_s;
312
313 ts_nsec = timestamp;
314 ts_sec += ts_nsec / NSEC_PER_SEC;
315 ts_nsec = ts_nsec % NSEC_PER_SEC;
316
317 time_s = (time_t) ts_sec;
318
319 localtime_r(&time_s, &tm);
320
321 return tm;
322 }
323
324 static void scale_unit(uint64_t bytes, char *ret)
325 {
326 if (bytes >= 1000000000)
327 sprintf(ret, "%" PRIu64 "G", bytes/1000000000);
328 if (bytes >= 1000000)
329 sprintf(ret, "%" PRIu64 "M", bytes/1000000);
330 else if (bytes >= 1000)
331 sprintf(ret, "%" PRIu64 "K", bytes/1000);
332 else
333 sprintf(ret, "%" PRIu64, bytes);
334 }
335
336 uint64_t total_io()
337 {
338 uint64_t total = 0;
339 int read, write;
340 unsigned long birth;
341 unsigned long real_start;
342 Quark proc;
343
344 if (get_attribute_value_at_quark(i_end, NULL, "proc", proc)) {
345 do {
346 get_attribute_value_at_ulong(
347 i_end, &proc, "birth", birth);
348 if (birth > i_start)
349 real_start = birth;
350 else
351 real_start = i_start;
352 get_interval_value_int(real_start, i_end, &proc,
353 "fileread", read);
354 get_interval_value_int(real_start, i_end, &proc,
355 "filewrite", write);
356 total += read + write;
357
358 } while (get_attribute_value_at_quark(
359 i_end, &proc, "next", proc));
360 }
361
362 return total;
363 }
364
365 void update_header()
366 {
367 struct tm start, end;
368 uint64_t ts_nsec_start, ts_nsec_end;
369 char io[16];
370 int cpu_nb;
371 int nbthreads, nbnewthreads, nbdeadthreads;
372 int nbfiles, nbnewfiles, nbdeadfiles;
373
374 ts_nsec_start = i_start % NSEC_PER_SEC;
375 start = format_timestamp(i_start);
376
377 ts_nsec_end = i_end % NSEC_PER_SEC;
378 end = format_timestamp(i_end);
379
380 werase(header);
381 box(header, 0 , 0);
382 set_window_title(header, "Statistics for interval ");
383 wattron(header, A_BOLD);
384
385 wprintw(header,
386 "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[",
387 start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start,
388 end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_end);
389 mvwprintw(header, 1, 4, "CPUs");
390 wattroff(header, A_BOLD);
391
392 cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu"));
393 get_attribute_value_at_int(i_end, NULL, "nbthreads", nbthreads);
394 get_interval_value_int(i_start, i_end, NULL, "nbnewthreads",
395 nbnewthreads);
396 get_interval_value_int(i_start, i_end, NULL, "nbdeadthreads",
397 nbdeadthreads);
398 get_attribute_value_at_int(i_end, NULL, "nbfiles", nbfiles);
399 get_interval_value_int(i_start, i_end, NULL, "nbnewfiles", nbnewfiles);
400 get_interval_value_int(i_start, i_end, NULL, "nbdeadfiles",
401 nbdeadfiles);
402
403 wprintw(header, "\t%d\t(max/cpu : %0.2f%)", cpu_nb,
404 100.0/cpu_nb);
405 print_headers(2, "Threads", nbthreads, nbnewthreads,-1*nbdeadthreads);
406 print_headers(3, "FDs", nbfiles, nbnewfiles,-1*nbdeadfiles);
407 scale_unit(total_io(), io);
408 mvwprintw(header, 3, 43, "%sB/sec", io);
409 wrefresh(header);
410 }
411
412 int sort_by_cpu_desc(const void *pp1, const void *pp2)
413 {
414 Quark p1 = *(Quark *)pp1;
415 Quark p2 = *(Quark *)pp2;
416 unsigned long total1, total2;
417 unsigned long birth1, birth2;
418 unsigned long start1 = i_start;
419 unsigned long start2 = i_start;
420
421 get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
422 get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
423 if (birth1 > i_start)
424 start1 = birth1;
425 if (birth2 > i_start)
426 start2 = birth2;
427
428 get_interval_value_ulong(start1, i_end, &p1, "totalcpunsec", total1);
429 get_interval_value_ulong(start2, i_end, &p2, "totalcpunsec", total2);
430
431 if (total1 > total2)
432 return 1;
433 if (total1 == total2)
434 return 0;
435 return -1;
436 }
437
438 int sort_by_tid_desc(const void *pp1, const void *pp2)
439 {
440 Quark p1 = *(Quark *)pp1;
441 Quark p2 = *(Quark *)pp2;
442 int tid1, tid2;
443
444 get_attribute_value_at_int(i_end, &p1, "tid", tid1);
445 get_attribute_value_at_int(i_end, &p2, "tid", tid2);
446
447 if (tid1 > tid2)
448 return 1;
449 if (tid1 == tid2)
450 return 0;
451 return -1;
452 }
453
454 int sort_by_pid_desc(const void *pp1, const void *pp2)
455 {
456 Quark p1 = *(Quark *)pp1;
457 Quark p2 = *(Quark *)pp2;
458 int pid1, pid2;
459
460 get_attribute_value_at_int(i_end, &p1, "pid", pid1);
461 get_attribute_value_at_int(i_end, &p2, "pid", pid2);
462
463 if (pid1 > pid2)
464 return 1;
465 if (pid1 == pid2)
466 return 0;
467 return -1;
468 }
469
470
471 int sort_by_process_read_desc(const void *pp1, const void *pp2)
472 {
473 Quark p1 = *(Quark *)pp1;
474 Quark p2 = *(Quark *)pp2;
475 int total1, total2;
476 unsigned long birth1, birth2;
477 unsigned long start1 = i_start;
478 unsigned long start2 = i_start;
479
480 get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
481 get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
482 if (birth1 > i_start)
483 start1 = birth1;
484 if (birth2 > i_start)
485 start2 = birth2;
486
487 get_interval_value_int(start1, i_end, &p1, "fileread", total1);
488 get_interval_value_int(start2, i_end, &p2, "fileread", total2);
489
490 if (total1 > total2)
491 return 1;
492 if (total1 == total2)
493 return 0;
494 return -1;
495 }
496
497 int sort_by_process_write_desc(const void *pp1, const void *pp2)
498 {
499 Quark p1 = *(Quark *)pp1;
500 Quark p2 = *(Quark *)pp2;
501 int total1, total2;
502 unsigned long birth1, birth2;
503 unsigned long start1 = i_start;
504 unsigned long start2 = i_start;
505
506 get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
507 get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
508 if (birth1 > i_start)
509 start1 = birth1;
510 if (birth2 > i_start)
511 start2 = birth2;
512
513 get_interval_value_int(start1, i_end, &p1, "filewrite", total1);
514 get_interval_value_int(start2, i_end, &p2, "filewrite", total2);
515
516 if (total1 > total2)
517 return 1;
518 if (total1 == total2)
519 return 0;
520 return -1;
521 }
522
523 int sort_by_process_total_desc(const void *pp1, const void *pp2)
524 {
525 Quark p1 = *(Quark *)pp1;
526 Quark p2 = *(Quark *)pp2;
527 int p1Read, p2Read;
528 int p1Write, p2Write;
529 int total1, total2;
530 unsigned long birth1, birth2;
531 unsigned long start1 = i_start;
532 unsigned long start2 = i_start;
533
534 get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
535 get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
536 if (birth1 > i_start)
537 start1 = birth1;
538 if (birth2 > i_start)
539 start2 = birth2;
540
541 get_interval_value_int(start1, i_end, &p1, "fileread", p1Read);
542 get_interval_value_int(start2, i_end, &p2, "fileread", p2Read);
543 get_interval_value_int(start1, i_end, &p1, "filewrite", p1Write);
544 get_interval_value_int(start2, i_end, &p2, "filewrite", p2Write);
545
546 total1 = p1Read + p1Write;
547 total2 = p2Read + p2Write;
548
549 if (total1 > total2)
550 return 1;
551 if (total1 == total2)
552 return 0;
553 return -1;
554 }
555
556 int sort_by_file_read_desc(const void *pf1, const void *pf2)
557 {
558 Quark f1 = *(Quark *)pf1;
559 Quark f2 = *(Quark *)pf2;
560 int total1, total2;
561 unsigned long birth1, birth2;
562 unsigned long start1 = i_start;
563 unsigned long start2 = i_start;
564
565 get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1);
566 get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2);
567 if (birth1 > i_start)
568 start1 = birth1;
569 if (birth2 > i_start)
570 start2 = birth2;
571
572 get_interval_value_int(start1, i_end, &f1, "file/read", total1);
573 get_interval_value_int(start2, i_end, &f2, "file/read", total2);
574
575 if (total1 > total2)
576 return 1;
577 if (total1 == total2)
578 return 0;
579 return -1;
580 }
581
582 int sort_by_file_write_desc(const void *pf1, const void *pf2)
583 {
584 Quark f1 = *(Quark *)pf1;
585 Quark f2 = *(Quark *)pf2;
586 int total1, total2;
587 unsigned long birth1, birth2;
588 unsigned long start1 = i_start;
589 unsigned long start2 = i_start;
590
591 get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1);
592 get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2);
593 if (birth1 > i_start)
594 start1 = birth1;
595 if (birth2 > i_start)
596 start2 = birth2;
597
598 get_interval_value_int(start1, i_end, &f1, "file/write", total1);
599 get_interval_value_int(start2, i_end, &f2, "file/write", total2);
600
601 if (total1 > total2)
602 return 1;
603 if (total1 == total2)
604 return 0;
605 return -1;
606 }
607
608 int sort_by_file_fd_desc(const void *pf1, const void *pf2)
609 {
610 Quark f1 = *(Quark *)pf1;
611 Quark f2 = *(Quark *)pf2;
612 int fd1, fd2;
613
614 get_attribute_value_at_int(i_end, &f1, "file/fd", fd1);
615 get_attribute_value_at_int(i_end, &f2, "file/fd", fd2);
616
617 if (fd1 > fd2)
618 return 1;
619 if (fd1 == fd2)
620 return 0;
621 return -1;
622 }
623
624 int sort_by_cpu_group_by_threads_desc(const void *pp1, const void *pp2)
625 {
626 Quark p1 = *(Quark *)pp1;
627 Quark p2 = *(Quark *)pp2;
628 unsigned long total1, total2;
629 unsigned long birth1, birth2;
630 unsigned long start1 = i_start;
631 unsigned long start2 = i_start;
632
633 get_attribute_value_at_ulong(i_end, &p1, "birth", birth1);
634 get_attribute_value_at_ulong(i_end, &p2, "birth", birth2);
635 if (birth1 > i_start)
636 start1 = birth1;
637 if (birth2 > i_start)
638 start2 = birth2;
639
640 get_interval_value_ulong(start1, i_end, &p1, "threadstotalcpunsec",
641 total1);
642 get_interval_value_ulong(start2, i_end, &p2, "threadstotalcpunsec",
643 total2);
644
645 if (total1 > total2)
646 return 1;
647 if (total1 == total2)
648 return 0;
649 return -1;
650 }
651
652 void update_cputop_display()
653 {
654 unsigned int i;
655 int header_offset = 2;
656 unsigned long elapsed;
657 double maxcputime;
658 int nblinedisplayed = 0;
659 int current_line = 0;
660 int column;
661 Quark *processes;
662 int tid, pid;
663 unsigned long totalcpunsec;
664 std::string comm;
665
666 Quark cpu_root = state_system->getQuark("cpu");
667 Quark proc_root = state_system->getQuark("proc");
668 unsigned int cpu_nb = get_sequence_length(i_end, cpu_root);
669 unsigned int proc_nb = get_sequence_length(i_end, proc_root);
670
671 elapsed = i_end - i_start;
672 maxcputime = elapsed * cpu_nb / 100.0;
673
674 processes = g_new(Quark, proc_nb);
675 sequence_to_array(i_end, proc_root, processes, proc_nb);
676
677 if (cputopview[0].sort == 1)
678 qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
679 else if (cputopview[1].sort == 1)
680 qsort(processes, proc_nb, sizeof(Quark), sort_by_pid_desc);
681 else if (cputopview[2].sort == 1)
682 qsort(processes, proc_nb, sizeof(Quark), sort_by_tid_desc);
683 else if (cputopview[3].sort == 1)
684 qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
685 else
686 qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc);
687
688 set_window_title(center, "CPU Top");
689 wattron(center, A_BOLD);
690 column = 1;
691 for (i = 0; i < 4; i++) {
692 if (cputopview[i].sort) {
693 wattron(center, A_UNDERLINE);
694 pref_current_sort = i;
695 }
696 mvwprintw(center, 1, column, cputopview[i].title);
697 wattroff(center, A_UNDERLINE);
698 column += 10;
699 }
700 wattroff(center, A_BOLD);
701
702 max_center_lines = LINES - 5 - 7 - 1 - header_offset;
703
704 /* iterate the process (thread) list */
705 for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines;
706 i++) {
707 get_attribute_value_at_int(i_end, processes + i, "tid", tid);
708 get_attribute_value_at_int(i_end, processes + i, "pid", pid);
709
710 if (pid != tid)
711 if (toggle_threads == -1)
712 continue;
713
714 if (process_selected(processes[i])) {
715 wattron(center, COLOR_PAIR(6));
716 mvwhline(center, current_line + header_offset, 1, ' ',
717 COLS-3);
718 }
719 if (current_line == selected_line) {
720 selected_process = processes[i];
721 wattron(center, COLOR_PAIR(5));
722 mvwhline(center, current_line + header_offset, 1, ' ',
723 COLS-3);
724 }
725 /* CPU(%) */
726 get_interval_value_ulong(i_start, i_end, processes + i,
727 "totalcpunsec", totalcpunsec);
728 mvwprintw(center, current_line + header_offset, 1, "%1.2f",
729 totalcpunsec / maxcputime);
730 /* PID */
731 mvwprintw(center, current_line + header_offset, 11, "%d", pid);
732 /* TID */
733 mvwprintw(center, current_line + header_offset, 21, "%d", tid);
734 /* NAME */
735 get_attribute_value_at_string(i_end, processes + i, "comm",
736 comm);
737 mvwprintw(center, current_line + header_offset, 31, "%s",
738 comm.c_str());
739 wattroff(center, COLOR_PAIR(6));
740 wattroff(center, COLOR_PAIR(5));
741 nblinedisplayed++;
742 current_line++;
743 }
744
745 g_free(processes);
746 }
747
748 int sort_perf(const void *pp1, const void *pp2)
749 {
750 Quark p1 = *(Quark *)pp1;
751 Quark p2 = *(Quark *)pp2;
752 std::string key = sort_perf_key;
753 int total1;
754 int total2;
755 int tid1;
756 int tid2;
757
758 if (!get_attribute_value_at_int(i_end, &p1, "perf/" + key + "/count",
759 total1))
760 total1 = 0;
761
762 if (!get_attribute_value_at_int(i_end, &p2, "perf/" + key + "/count",
763 total2))
764 total2 = 0;
765
766
767 if (total1 < total2)
768 return 1;
769 if (total1 == total2) {
770 get_attribute_value_at_int(i_end, &p1, "tid", tid1);
771 get_attribute_value_at_int(i_end, &p2, "tid", tid2);
772 if (tid1 < tid2)
773 return 1;
774 return -1;
775 }
776 return -1;
777 }
778
779 void print_key_title(const char key[], int line)
780 {
781 wattron(center, A_BOLD);
782 mvwprintw(center, line, 1, "%s", key);
783 mvwprintw(center, line, 30, " ");
784 wattroff(center, A_BOLD);
785 }
786
787 void update_process_details()
788 {
789 unsigned long elapsed;
790 double maxcputime;
791 unsigned int i, j = 0;
792 char unit[4];
793 char filename_buf[COLS];
794 int line = 1;
795 int column;
796 unsigned int cpu_nb;
797 std::string comm;
798 int tid = -1, pid, ppid, fileread, filewrite;
799 unsigned long totalcpunsec;
800 Quark *global_perf;
801 unsigned int global_perf_nb;
802 std::string key;
803 int count;
804 Quark *files;
805 unsigned int file_nb;
806 int fd, read, write;
807 std::string name;
808
809 set_window_title(center, "Process details");
810
811 elapsed = i_end - i_start;
812 cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu"));
813 maxcputime = elapsed * cpu_nb / 100.0;
814
815 get_attribute_value_at_int(i_end, &selected_process, "tid", tid);
816 if (tid == -1) {
817 print_key_title("Does not exit at this time", 3);
818 return;
819 }
820
821 print_key_title("Name", line++);
822 get_attribute_value_at_string(i_end, &selected_process, "comm", comm);
823 wprintw(center, "%s", comm.c_str());
824 print_key_title("TID", line++);
825 wprintw(center, "%d", tid);
826
827 print_key_title("PID", line++);
828 get_attribute_value_at_int(i_end, &selected_process, "pid", pid);
829 wprintw(center, "%d", pid);
830 print_key_title("PPID", line++);
831 get_attribute_value_at_int(i_end, &selected_process, "ppid", ppid);
832 wprintw(center, "%d", ppid);
833 print_key_title("CPU", line++);
834 get_attribute_value_at_ulong(i_end, &selected_process, "totalcpunsec",
835 totalcpunsec);
836 wprintw(center, "%1.2f %%", totalcpunsec/maxcputime);
837
838 print_key_title("READ B/s", line++);
839 get_attribute_value_at_int(i_end, &selected_process, "fileread",
840 fileread);
841 scale_unit(fileread, unit);
842 wprintw(center, "%s", unit);
843
844 print_key_title("WRITE B/s", line++);
845 get_attribute_value_at_int(i_end, &selected_process, "filewrite",
846 filewrite);
847 scale_unit(filewrite, unit);
848 wprintw(center, "%s", unit);
849
850
851 global_perf_nb = get_global_perf_list_size(i_end);
852 global_perf = g_new(Quark, global_perf_nb);
853 get_global_perf_list(i_end, global_perf, global_perf_nb);
854 for (i = 0; i < global_perf_nb; i++) {
855 get_attribute_value_at_string(i_end, global_perf + i, "key",
856 key);
857 print_key_title(key.c_str(), line++);
858 if (!get_attribute_value_at_int(i_end, global_perf + i, "count",
859 count))
860 count = 0;
861 wprintw(center, "%d", count);
862 }
863 line++;
864
865 wattron(center, A_BOLD);
866 column = 1;
867 for (i = 0; i < 3; i++) {
868 if (fileview[i].sort) {
869 pref_current_sort = i;
870 wattron(center, A_UNDERLINE);
871 }
872 mvwprintw(center, line, column, fileview[i].title);
873 wattroff(center, A_UNDERLINE);
874 column += 10;
875 }
876 mvwprintw(center, line++, column, "FILENAME");
877 wattroff(center, A_BOLD);
878
879 file_nb = get_number_of_opened_files(i_end, selected_process);
880 files = g_new(Quark, file_nb);
881 get_opened_files(i_end, selected_process, files, file_nb);
882
883 if (fileview[0].sort == 1)
884 qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc);
885 else if (fileview[1].sort == 1)
886 qsort(files, file_nb, sizeof(Quark), sort_by_file_read_desc);
887 else if (fileview[2].sort == 1)
888 qsort(files, file_nb, sizeof(Quark), sort_by_file_write_desc);
889 else
890 qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc);
891
892 for (i = selected_line;
893 i < file_nb && i < (selected_line + max_center_lines - line + 2);
894 i++) {
895 get_attribute_value_at_int(i_end, files + i, "fd", fd);
896 mvwprintw(center, line + j, 1, "%d", fd);
897 get_attribute_value_at_int(i_end, files + i, "read", read);
898 scale_unit(read, unit);
899 mvwprintw(center, line + j, 11, "%s", unit);
900 get_attribute_value_at_int(i_end, files + i, "write", write);
901 scale_unit(write, unit);
902 mvwprintw(center, line + j, 21, "%s", unit);
903 get_attribute_value_at_string(i_end, files + i, "name", name);
904 snprintf(filename_buf, COLS - 25, "%s", name.c_str());
905 mvwprintw(center, line + j, 31, "%s", filename_buf);
906 j++;
907 }
908 g_free(global_perf);
909 g_free(files);
910 }
911
912 void update_perf()
913 {
914 unsigned int i, j;
915 int nblinedisplayed = 0;
916 int current_line = 0;
917 int header_offset = 2;
918 int perf_row = 40;
919 int value;
920 unsigned int global_perf_nb;
921 Quark *global_perf;
922 int sort = 0;
923 int visible = 0;
924 std::string key;
925 bool sort_exists;
926 unsigned int proc_nb;
927 Quark *procs;
928 Quark proc_beg;
929 int tid, pid;
930 std::string comm;
931
932 set_window_title(center, "Perf Top");
933 wattron(center, A_BOLD);
934 mvwprintw(center, 1, 1, "PID");
935 mvwprintw(center, 1, 11, "TID");
936 mvwprintw(center, 1, 22, "NAME");
937
938 perf_row = 40;
939 global_perf_nb = get_global_perf_list_size(i_end);
940 global_perf = g_new(Quark, global_perf_nb);
941 get_global_perf_list(i_end, global_perf, global_perf_nb);
942 for (i = 0; i < global_perf_nb; i++) {
943 get_attribute_value_at_int(i_end, global_perf + i, "visible",
944 visible);
945 get_attribute_value_at_string(i_end, global_perf + i, "key",
946 key);
947 sort_exists = get_attribute_value_at_int(i_end, global_perf + i,
948 "sort", sort);
949 if (visible) {
950 if (sort_exists && sort) {
951 wattron(center, A_UNDERLINE);
952 }
953 /* + 5 to strip the "perf_" prefix */
954 mvwprintw(center, 1, perf_row, "%s",
955 key.c_str() + 5);
956 wattroff(center, A_UNDERLINE);
957 perf_row += 20;
958 }
959 if (sort_exists && sort) {
960 sort_perf_key = key;
961 }
962 }
963 wattroff(center, A_BOLD);
964
965 proc_beg = state_system->getQuark("proc");
966 proc_nb = get_sequence_length(i_end, proc_beg);
967 procs = g_new(Quark, proc_nb);
968 sequence_to_array(i_end, proc_beg, procs, proc_nb);
969 for (i = 0; i < proc_nb && nblinedisplayed < max_center_lines; i++) {
970 get_attribute_value_at_int(i_end, procs + i, "tid", tid);
971 get_attribute_value_at_int(i_end, procs + i, "pid", pid);
972 get_attribute_value_at_string(i_end, procs + 1, "comm", comm);
973
974 if (pid != tid)
975 if (toggle_threads == -1)
976 continue;
977
978 if (process_selected(procs[i])) {
979 wattron(center, COLOR_PAIR(6));
980 mvwhline(center, current_line + header_offset, 1, ' ',
981 COLS-3);
982 }
983 if (current_line == selected_line) {
984 selected_process = procs[i];
985 wattron(center, COLOR_PAIR(5));
986 mvwhline(center, current_line + header_offset, 1, ' ',
987 COLS-3);
988 }
989
990 mvwprintw(center, current_line + header_offset, 1, "%d", pid);
991 mvwprintw(center, current_line + header_offset, 11, "%d", tid);
992 mvwprintw(center, current_line + header_offset, 22, "%s",
993 comm.c_str());
994
995 perf_row = 40;
996 for (j = 0; j < global_perf_nb; j++) {
997 get_attribute_value_at_int(i_end, global_perf + j,
998 "visible", visible);
999 get_attribute_value_at_string(i_end, global_perf + j,
1000 "key", key);
1001
1002 if (visible) {
1003 if (!get_interval_value_int(i_start, i_end,
1004 procs + i, "perf/" +
1005 key + "/count",
1006 value)) {
1007 value = 0;
1008 }
1009 mvwprintw(center, current_line + header_offset,
1010 perf_row, "%d", value);
1011 perf_row += 20;
1012 }
1013 }
1014
1015 wattroff(center, COLOR_PAIR(6));
1016 wattroff(center, COLOR_PAIR(5));
1017 nblinedisplayed++;
1018 current_line++;
1019 }
1020 g_free(global_perf);
1021 g_free(procs);
1022 }
1023
1024 void update_iostream()
1025 {
1026 unsigned int i;
1027 int header_offset = 2;
1028 int nblinedisplayed = 0;
1029 int current_line = 0;
1030 char unit[4];
1031 int column;
1032 unsigned int proc_nb;
1033 Quark *procs;
1034 Quark proc_root;
1035 int pid, tid, read, write, totalread, totalwrite;
1036 std::string comm;
1037
1038 set_window_title(center, "IO Top");
1039 wattron(center, A_BOLD);
1040 mvwprintw(center, 1, 1, "PID");
1041 mvwprintw(center, 1, 11, "TID");
1042 mvwprintw(center, 1, 22, "NAME");
1043 column = 40;
1044 for (i = 0; i < 3; i++) {
1045 if (iostreamtopview[i].sort) {
1046 pref_current_sort = i;
1047 wattron(center, A_UNDERLINE);
1048 }
1049 mvwprintw(center, 1, column, iostreamtopview[i].title);
1050 wattroff(center, A_UNDERLINE);
1051 column += 12;
1052 }
1053 wattroff(center, A_BOLD);
1054 wattroff(center, A_UNDERLINE);
1055
1056 proc_root = state_system->getQuark("proc");
1057 proc_nb = get_sequence_length(i_end, proc_root);
1058 procs = g_new(Quark, proc_nb);
1059 sequence_to_array(i_end, proc_root, procs, proc_nb);
1060
1061 if (iostreamtopview[0].sort == 1)
1062 qsort(procs, proc_nb, sizeof(Quark), sort_by_process_read_desc);
1063 else if (iostreamtopview[1].sort == 1)
1064 qsort(procs, proc_nb, sizeof(Quark),
1065 sort_by_process_write_desc);
1066 else if (iostreamtopview[2].sort == 1)
1067 qsort(procs, proc_nb, sizeof(Quark),
1068 sort_by_process_total_desc);
1069 else
1070 qsort(procs, proc_nb, sizeof(Quark),
1071 sort_by_process_total_desc);
1072
1073 for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines;
1074 i++) {
1075 get_attribute_value_at_int(i_end, procs + i, "tid", tid);
1076 get_attribute_value_at_int(i_end, procs + i, "pid", pid);
1077 get_attribute_value_at_string(i_end, procs + i, "comm", comm);
1078 get_attribute_value_at_int(i_end, procs + i, "fileread",
1079 read);
1080 get_attribute_value_at_int(i_end, procs + i, "filewrite",
1081 write);
1082 get_attribute_value_at_int(i_end, procs + i, "totalfileread",
1083 totalread);
1084 get_attribute_value_at_int(i_end, procs + i, "totalfilewrite",
1085 totalwrite);
1086
1087
1088 if (pid != tid)
1089 if (toggle_threads == -1)
1090 continue;
1091
1092 if (process_selected(procs[i])) {
1093 wattron(center, COLOR_PAIR(6));
1094 mvwhline(center, current_line + header_offset, 1, ' ',
1095 COLS-3);
1096 }
1097 if (current_line == selected_line) {
1098 selected_process = procs[i];
1099 wattron(center, COLOR_PAIR(5));
1100 mvwhline(center, current_line + header_offset, 1, ' ',
1101 COLS-3);
1102 }
1103 /* PID */
1104 mvwprintw(center, current_line + header_offset, 1, "%d", pid);
1105 /* TID */
1106 mvwprintw(center, current_line + header_offset, 11, "%d", tid);
1107 /* NAME */
1108 mvwprintw(center, current_line + header_offset, 22, "%s",
1109 comm.c_str());
1110
1111 /* READ (bytes/sec) */
1112 scale_unit(read, unit);
1113 mvwprintw(center, current_line + header_offset, 40, "%s", unit);
1114
1115 /* WRITE (bytes/sec) */
1116 scale_unit(write, unit);
1117 mvwprintw(center, current_line + header_offset, 52, "%s", unit);
1118
1119 /* TOTAL STREAM */
1120 scale_unit(totalread + totalwrite, unit);
1121 mvwprintw(center, current_line + header_offset, 64, "%s", unit);
1122
1123 wattroff(center, COLOR_PAIR(6));
1124 wattroff(center, COLOR_PAIR(5));
1125 nblinedisplayed++;
1126 current_line++;
1127 }
1128 g_free(procs);
1129 }
1130
1131 void update_current_view()
1132 {
1133 sem_wait(&update_display_sem);
1134 update_header();
1135
1136 werase(center);
1137 box(center, 0, 0);
1138 switch (current_view) {
1139 case cpu:
1140 update_cputop_display();
1141 break;
1142 case perf:
1143 update_perf();
1144 break;
1145 case process_details:
1146 update_process_details();
1147 break;
1148 case iostream:
1149 update_iostream();
1150 break;
1151 case tree:
1152 update_cputop_display();
1153 break;
1154 default:
1155 break;
1156 }
1157 update_panels();
1158 doupdate();
1159 sem_post(&update_display_sem);
1160 }
1161
1162 void update_process_detail_sort(int *line_selected)
1163 {
1164 int i;
1165 int size;
1166
1167 size = 3;
1168
1169 if (*line_selected > (size - 1))
1170 *line_selected = size - 1;
1171 else if (*line_selected < 0)
1172 *line_selected = 0;
1173
1174 if (fileview[*line_selected].sort == 1)
1175 fileview[*line_selected].reverse = 1;
1176 for (i = 0; i < size; i++)
1177 fileview[i].sort = 0;
1178 fileview[*line_selected].sort = 1;
1179 }
1180
1181 void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort)
1182 {
1183 int i;
1184 int size;
1185
1186 if (pref_panel_window) {
1187 del_panel(pref_panel);
1188 delwin(pref_panel_window);
1189 }
1190 size = 3;
1191
1192 pref_panel_window = create_window(size + 2, 30, 10, 10);
1193 pref_panel = new_panel(pref_panel_window);
1194
1195 werase(pref_panel_window);
1196 box(pref_panel_window, 0 , 0);
1197 set_window_title(pref_panel_window, "Process Detail Preferences ");
1198 wattron(pref_panel_window, A_BOLD);
1199 mvwprintw(pref_panel_window, size + 1, 1,
1200 " 's' : sort, space : toggle");
1201 wattroff(pref_panel_window, A_BOLD);
1202
1203 if (*line_selected > (size - 1))
1204 *line_selected = size - 1;
1205 else if (*line_selected < 0)
1206 *line_selected = 0;
1207 if (toggle_sort == 1) {
1208 update_process_detail_sort(line_selected);
1209 update_current_view();
1210 }
1211
1212 for (i = 0; i < size; i++) {
1213 if (i == *line_selected) {
1214 wattron(pref_panel_window, COLOR_PAIR(5));
1215 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1216 }
1217 if (fileview[i].sort == 1)
1218 wattron(pref_panel_window, A_BOLD);
1219 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1220 fileview[i].title);
1221 wattroff(pref_panel_window, A_BOLD);
1222 wattroff(pref_panel_window, COLOR_PAIR(5));
1223
1224 }
1225 update_panels();
1226 doupdate();
1227 }
1228
1229 void update_iostream_sort(int *line_selected)
1230 {
1231 int i;
1232 int size;
1233
1234 size = 3;
1235 if (*line_selected > (size - 1))
1236 *line_selected = size - 1;
1237 else if (*line_selected < 0)
1238 *line_selected = 0;
1239 if (iostreamtopview[*line_selected].sort == 1)
1240 iostreamtopview[*line_selected].reverse = 1;
1241 for (i = 0; i < size; i++)
1242 iostreamtopview[i].sort = 0;
1243 iostreamtopview[*line_selected].sort = 1;
1244
1245 }
1246
1247 void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort)
1248 {
1249 int i;
1250 int size;
1251
1252 if (pref_panel_window) {
1253 del_panel(pref_panel);
1254 delwin(pref_panel_window);
1255 }
1256 size = 3;
1257
1258 pref_panel_window = create_window(size + 2, 30, 10, 10);
1259 pref_panel = new_panel(pref_panel_window);
1260
1261 werase(pref_panel_window);
1262 box(pref_panel_window, 0 , 0);
1263 set_window_title(pref_panel_window, "IOTop Preferences ");
1264 wattron(pref_panel_window, A_BOLD);
1265 mvwprintw(pref_panel_window, size + 1, 1,
1266 " 's' : sort, space : toggle");
1267 wattroff(pref_panel_window, A_BOLD);
1268
1269 if (*line_selected > (size - 1))
1270 *line_selected = size - 1;
1271 else if (*line_selected < 0)
1272 *line_selected = 0;
1273 if (toggle_sort == 1) {
1274 update_iostream_sort(line_selected);
1275 update_current_view();
1276 }
1277
1278 for (i = 0; i < size; i++) {
1279 if (i == *line_selected) {
1280 wattron(pref_panel_window, COLOR_PAIR(5));
1281 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1282 }
1283 if (iostreamtopview[i].sort == 1)
1284 wattron(pref_panel_window, A_BOLD);
1285 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1286 iostreamtopview[i].title);
1287 wattroff(pref_panel_window, A_BOLD);
1288 wattroff(pref_panel_window, COLOR_PAIR(5));
1289
1290 }
1291 update_panels();
1292 doupdate();
1293 }
1294
1295 void update_cpu_sort(int *line_selected)
1296 {
1297 int i;
1298 int size = 3;
1299
1300 if (*line_selected > (size - 1))
1301 *line_selected = size - 1;
1302 else if (*line_selected < 0)
1303 *line_selected = 0;
1304
1305 /* special case, we don't support sorting by procname for now */
1306 if (*line_selected != 3) {
1307 if (cputopview[*line_selected].sort == 1)
1308 cputopview[*line_selected].reverse = 1;
1309 for (i = 0; i < size; i++)
1310 cputopview[i].sort = 0;
1311 cputopview[*line_selected].sort = 1;
1312 }
1313 }
1314
1315 void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort)
1316 {
1317 int i;
1318 int size;
1319
1320 if (pref_panel_window) {
1321 del_panel(pref_panel);
1322 delwin(pref_panel_window);
1323 }
1324 size = 4;
1325
1326 pref_panel_window = create_window(size + 2, 30, 10, 10);
1327 pref_panel = new_panel(pref_panel_window);
1328
1329 werase(pref_panel_window);
1330 box(pref_panel_window, 0 , 0);
1331 set_window_title(pref_panel_window, "CPUTop Preferences ");
1332 wattron(pref_panel_window, A_BOLD);
1333 mvwprintw(pref_panel_window, size + 1, 1,
1334 " 's' : sort, space : toggle");
1335 wattroff(pref_panel_window, A_BOLD);
1336
1337 if (*line_selected > (size - 1))
1338 *line_selected = size - 1;
1339 else if (*line_selected < 0)
1340 *line_selected = 0;
1341 if (toggle_sort == 1) {
1342 update_cpu_sort(line_selected);
1343 update_current_view();
1344 }
1345
1346 for (i = 0; i < size; i++) {
1347 if (i == *line_selected) {
1348 wattron(pref_panel_window, COLOR_PAIR(5));
1349 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1350 }
1351 if (cputopview[i].sort == 1)
1352 wattron(pref_panel_window, A_BOLD);
1353 mvwprintw(pref_panel_window, i + 1, 1, "[-] %s",
1354 cputopview[i].title);
1355 wattroff(pref_panel_window, A_BOLD);
1356 wattroff(pref_panel_window, COLOR_PAIR(5));
1357
1358 }
1359 update_panels();
1360 doupdate();
1361 }
1362
1363 void update_perf_sort(int *line_selected)
1364 {
1365 int i;
1366 int size;
1367 Quark *global_perf;
1368
1369 size = get_global_perf_list_size(i_end);
1370 global_perf = g_new(Quark, size);
1371 get_global_perf_list(i_end, global_perf, size);
1372
1373 if (*line_selected > (size - 1))
1374 *line_selected = size - 1;
1375 else if (*line_selected < 0)
1376 *line_selected = 0;
1377
1378 for (i = 0; i < size; i++) {
1379 if (i != *line_selected)
1380 modify_attribute(i_end, global_perf + i, "sort", 0);
1381 else
1382 modify_attribute(i_end, global_perf + i, "sort", 1);
1383 }
1384
1385 g_free(global_perf);
1386 }
1387
1388 void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort)
1389 {
1390 int i;
1391 int size;
1392 Quark *global_perf;
1393 int visible;
1394 int sort;
1395 std::string key;
1396
1397 if (pref_panel_window) {
1398 del_panel(pref_panel);
1399 delwin(pref_panel_window);
1400 }
1401
1402 size = get_global_perf_list_size(i_end);
1403 global_perf = g_new(Quark, size);
1404 get_global_perf_list(i_end, global_perf, size);
1405
1406 pref_panel_window = create_window(size + 2, 30, 10, 10);
1407 pref_panel = new_panel(pref_panel_window);
1408
1409 werase(pref_panel_window);
1410 box(pref_panel_window, 0 , 0);
1411 set_window_title(pref_panel_window, "Perf Preferences ");
1412 wattron(pref_panel_window, A_BOLD);
1413 mvwprintw(pref_panel_window, size + 1, 1,
1414 " 's' : sort, space : toggle");
1415 wattroff(pref_panel_window, A_BOLD);
1416
1417 if (*line_selected > (size - 1))
1418 *line_selected = size - 1;
1419 else if (*line_selected < 0)
1420 *line_selected = 0;
1421
1422 if (toggle_sort == 1) {
1423 update_perf_sort(line_selected);
1424 update_current_view();
1425 }
1426
1427 for (i = 0; i < size; i++) {
1428 get_attribute_value_at_int(i_end, global_perf + i,
1429 "visible", visible);
1430 get_attribute_value_at_string(i_end, global_perf + i, "key",
1431 key);
1432 if (i == *line_selected && toggle_view == 1) {
1433 visible = visible == 1 ? 0 : 1;
1434 modify_attribute(i_end, global_perf + i, "visible",
1435 visible);
1436 update_current_view();
1437 }
1438 if (i == *line_selected) {
1439 wattron(pref_panel_window, COLOR_PAIR(5));
1440 mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2);
1441 }
1442
1443 if (get_attribute_value_at_int(i_end, global_perf + 1, "sort",
1444 sort) && sort) {
1445 wattron(pref_panel_window, A_BOLD);
1446 }
1447 mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s",
1448 visible == 1 ? 'x' : ' ', key.c_str() + 5);
1449 wattroff(pref_panel_window, A_BOLD);
1450 wattroff(pref_panel_window, COLOR_PAIR(5));
1451 }
1452 update_panels();
1453 doupdate();
1454
1455 g_free(global_perf);
1456 }
1457
1458 int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort)
1459 {
1460 int ret = 0;
1461
1462 switch(current_view) {
1463 case perf:
1464 update_perf_pref(line_selected, toggle_view, toggle_sort);
1465 break;
1466 case cpu:
1467 update_cpu_pref(line_selected, toggle_view, toggle_sort);
1468 break;
1469 case iostream:
1470 update_iostream_pref(line_selected, toggle_view, toggle_sort);
1471 break;
1472 case process_details:
1473 update_process_detail_pref(line_selected, toggle_view, toggle_sort);
1474 break;
1475 default:
1476 ret = -1;
1477 break;
1478 }
1479
1480 return ret;
1481 }
1482
1483 int update_sort(int *line_selected)
1484 {
1485 int ret = 0;
1486
1487 switch(current_view) {
1488 case perf:
1489 update_perf_sort(line_selected);
1490 break;
1491 case cpu:
1492 update_cpu_sort(line_selected);
1493 break;
1494 case iostream:
1495 update_iostream_sort(line_selected);
1496 break;
1497 case process_details:
1498 update_process_detail_sort(line_selected);
1499 break;
1500 default:
1501 ret = -1;
1502 break;
1503 }
1504
1505 return ret;
1506 }
1507
1508
1509 void toggle_pref_panel(void)
1510 {
1511 int ret;
1512
1513 if (pref_panel_visible) {
1514 hide_panel(pref_panel);
1515 pref_panel_visible = 0;
1516 } else {
1517 ret = update_preference_panel(&pref_line_selected, 0, 0);
1518 if (ret < 0)
1519 return;
1520 show_panel(pref_panel);
1521 pref_panel_visible = 1;
1522 }
1523 update_panels();
1524 doupdate();
1525 }
1526
1527 void display()
1528 {
1529 if (i_start == 0)
1530 i_start = first_display_update;
1531 else
1532 i_start += refresh_display;
1533 i_end = i_start + refresh_display;
1534
1535 max_elements = get_sequence_length(
1536 i_end, state_system->getQuark("proc"));
1537 update_current_view();
1538 update_footer();
1539 update_panels();
1540 doupdate();
1541 }
1542
1543 void pause_display()
1544 {
1545 toggle_pause = 1;
1546 print_log("Pause");
1547 sem_wait(&pause_sem);
1548 }
1549
1550 void resume_display()
1551 {
1552 toggle_pause = -1;
1553 print_log("Resume");
1554 sem_post(&pause_sem);
1555 }
1556
1557 void *handle_keyboard(void *p)
1558 {
1559 int ch;
1560 while((ch = getch())) {
1561 switch(ch) {
1562 /* Move the cursor and scroll */
1563 case 'j':
1564 case KEY_DOWN:
1565 if (pref_panel_visible) {
1566 pref_line_selected++;
1567 update_preference_panel(&pref_line_selected, 0, 0);
1568 } else {
1569 if (selected_line < (max_center_lines - 1) &&
1570 selected_line < max_elements - 1) {
1571 selected_line++;
1572 selected_in_list++;
1573 } else if (selected_in_list < (max_elements - 1)
1574 && (list_offset < (max_elements - max_center_lines))) {
1575 selected_in_list++;
1576 list_offset++;
1577 }
1578 update_current_view();
1579 }
1580 break;
1581 case KEY_NPAGE:
1582 break;
1583 case 'k':
1584 case KEY_UP:
1585 if (pref_panel_visible) {
1586 if (pref_line_selected > 0)
1587 pref_line_selected--;
1588 update_preference_panel(&pref_line_selected, 0, 0);
1589 } else {
1590 if (selected_line > 0) {
1591 selected_line--;
1592 selected_in_list--;
1593 } else if (selected_in_list > 0 && list_offset > 0) {
1594 selected_in_list--;
1595 list_offset--;
1596 }
1597 update_current_view();
1598 }
1599 break;
1600 case KEY_PPAGE:
1601 break;
1602
1603 /* Navigate the history with arrows */
1604 case KEY_LEFT:
1605 if ((i_start - refresh_display) >=
1606 first_display_update) {
1607 i_start -= refresh_display;
1608 i_end = i_start + refresh_display;
1609 print_log("Going back in time");
1610 } else {
1611 print_log("Cannot rewind, last data is already displayed");
1612 }
1613 max_elements = get_sequence_length(
1614 i_end, state_system->getQuark("proc"));
1615
1616 /* we force to pause the display when moving in time */
1617 if (toggle_pause < 0)
1618 pause_display();
1619
1620 update_current_view();
1621 update_footer();
1622 break;
1623 case KEY_RIGHT:
1624 if ((i_end + refresh_display) <=
1625 last_display_update) {
1626 i_end += refresh_display;
1627 i_start = i_end - refresh_display;
1628 print_log("Going forward in time");
1629 max_elements = get_sequence_length(
1630 i_end, state_system->getQuark(
1631 "proc"));
1632 update_current_view();
1633 update_footer();
1634 } else {
1635 print_log("Manually moving forward");
1636 sem_post(&timer);
1637 if (toggle_pause > 0) {
1638 sem_post(&pause_sem);
1639 update_current_view();
1640 sem_wait(&pause_sem);
1641 }
1642 }
1643
1644 break;
1645 case ' ':
1646 if (pref_panel_visible) {
1647 update_preference_panel(&pref_line_selected, 1, 0);
1648 } else {
1649 update_selected_processes();
1650 update_current_view();
1651 }
1652 break;
1653 case 's':
1654 if (pref_panel_visible)
1655 update_preference_panel(&pref_line_selected, 0, 1);
1656 break;
1657 case '>':
1658 /* perf uses a hashtable, it is ordered backward */
1659 if (current_view == perf) {
1660 pref_current_sort--;
1661 } else if (!pref_panel_visible) {
1662 pref_current_sort++;
1663 }
1664 update_sort(&pref_current_sort);
1665 update_current_view();
1666 break;
1667 case '<':
1668 /* perf uses a hashtable, it is ordered backward */
1669 if (current_view == perf) {
1670 pref_current_sort++;
1671 } else if (!pref_panel_visible) {
1672 pref_current_sort--;
1673 }
1674 update_sort(&pref_current_sort);
1675 update_current_view();
1676 break;
1677
1678 case 13: /* FIXME : KEY_ENTER ?? */
1679 if (pref_panel_visible)
1680 break;
1681 if (current_view != process_details) {
1682 previous_view = current_view;
1683 current_view = process_details;
1684 } else {
1685 current_view = previous_view;
1686 previous_view = process_details;
1687 }
1688 update_current_view();
1689 break;
1690
1691 case KEY_F(1):
1692 if (pref_panel_visible)
1693 toggle_pref_panel();
1694 current_view = cpu;
1695 selected_line = 0;
1696 update_current_view();
1697 break;
1698 case KEY_F(2):
1699 if (pref_panel_visible)
1700 toggle_pref_panel();
1701 current_view = cpu;
1702 selected_line = 0;
1703 update_current_view();
1704 break;
1705 case KEY_F(3):
1706 if (pref_panel_visible)
1707 toggle_pref_panel();
1708 current_view = perf;
1709 selected_line = 0;
1710 update_current_view();
1711 break;
1712 case KEY_F(4):
1713 if (pref_panel_visible)
1714 toggle_pref_panel();
1715 current_view = iostream;
1716 selected_line = 0;
1717 update_current_view();
1718 break;
1719 case KEY_F(10):
1720 case 'q':
1721 reset_ncurses();
1722 break;
1723 case 't':
1724 toggle_threads *= -1;
1725 update_current_view();
1726 break;
1727 case 'p':
1728 if (toggle_pause < 0) {
1729 pause_display();
1730 } else {
1731 resume_display();
1732 }
1733 break;
1734 case 'r':
1735 toggle_pref_panel();
1736 break;
1737 /* ESCAPE, but slow to process, don't know why */
1738 case 27:
1739 if (pref_panel_visible)
1740 toggle_pref_panel();
1741 else if (current_view == process_details) {
1742 current_view = previous_view;
1743 previous_view = process_details;
1744 }
1745 update_current_view();
1746 break;
1747 default:
1748 update_current_view();
1749 break;
1750 }
1751 update_footer();
1752 }
1753 return NULL;
1754 }
1755
1756 void init_view_headers()
1757 {
1758 cputopview[0].title = strdup("CPU(%)");
1759 cputopview[0].sort = 1;
1760 cputopview[1].title = strdup("PID");
1761 cputopview[2].title = strdup("TID");
1762 cputopview[3].title = strdup("NAME");
1763
1764 iostreamtopview[0].title = strdup("R (B/sec)");
1765 iostreamtopview[1].title = strdup("W (B/sec)");
1766 iostreamtopview[2].title = strdup("Total (B)");
1767 iostreamtopview[2].sort = 1;
1768
1769 fileview[0].title = strdup("FD");
1770 fileview[1].title = strdup("READ");
1771 fileview[1].sort = 1;
1772 fileview[2].title = strdup("WRITE");
1773 }
1774
1775 void init_ncurses()
1776 {
1777 selected_processes = g_ptr_array_new();
1778 sem_init(&update_display_sem, 0, 1);
1779 init_view_headers();
1780 init_screen();
1781
1782 header = create_window(5, COLS - 1, 0, 0);
1783 center = create_window(LINES - 5 - 7, COLS - 1, 5, 0);
1784 status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0);
1785 footer = create_window(1, COLS - 1, LINES - 1, 0);
1786
1787 print_log("Starting display");
1788
1789 main_panel = new_panel(center);
1790
1791 current_view = cpu;
1792
1793 basic_header();
1794 update_footer();
1795
1796 pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL);
1797 }
This page took 0.066529 seconds and 4 git commands to generate.