X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=src%2Fcursesdisplay.cpp;fp=src%2Fcursesdisplay.cpp;h=3cd273fdc0fccdb390b7df8555959dd2c27c7246;hb=715cf83c121d2aeac7ae030d49ff5a31bd6b9ac5;hp=0000000000000000000000000000000000000000;hpb=62895477c7e60525e63e9e5117f92b34d467d0e6;p=lttngtop.git diff --git a/src/cursesdisplay.cpp b/src/cursesdisplay.cpp new file mode 100644 index 0000000..3cd273f --- /dev/null +++ b/src/cursesdisplay.cpp @@ -0,0 +1,1797 @@ +/* + * Copyright (C) 2011-2012 Julien Desfossez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License Version 2 as + * published by the Free Software Foundation; + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define __STDC_FORMAT_MACROS +#include + +#include "cursesdisplay.h" +#include "lttngtoptypes.h" +#include "iostreamtop.h" +#include "common.h" + +#define DEFAULT_DELAY 15 +#define MAX_LINE_LENGTH 50 +#define MAX_LOG_LINES 4 + +using namespace State; + +enum view_list current_view; +enum view_list previous_view; + +/* to prevent concurrent updates of the different windows */ +sem_t update_display_sem; + +char *termtype; +WINDOW *footer, *header, *center, *status; +WINDOW *pref_panel_window = NULL; +PANEL *pref_panel, *main_panel; + +int pref_panel_visible = 0; +int pref_line_selected = 0; +int pref_current_sort = 0; + +Quark selected_process; +int selected_ret; + +int selected_line = 0; /* select bar position */ +int selected_in_list = 0; /* selection relative to the whole list */ +int list_offset = 0; /* first index in the list to display (scroll) */ +int nb_log_lines = 0; +char log_lines[MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES]; + +int max_elements = 80; + +int toggle_threads = 1; +int toggle_pause = -1; + +int max_center_lines; +GPtrArray *selected_processes; + +pthread_t keyboard_thread; + +struct header_view cputopview[4]; +struct header_view iostreamtopview[3]; +struct header_view fileview[3]; + +unsigned long i_start = 0; +unsigned long i_end = 0; + +std::string sort_perf_key; + + +void reset_ncurses() +{ + curs_set(1); + endwin(); + exit(0); +} + +static void handle_sigterm(int signal) +{ + reset_ncurses(); +} + +void init_screen() +{ + initscr(); + noecho(); + halfdelay(DEFAULT_DELAY); + nonl(); + intrflush(stdscr, false); + keypad(stdscr, true); + curs_set(0); + + if (has_colors()) { + start_color(); + init_pair(1, COLOR_RED, COLOR_BLACK); /* - */ + init_pair(2, COLOR_GREEN, COLOR_BLACK); /* + */ + init_pair(3, COLOR_BLACK, COLOR_WHITE); /* keys */ + init_pair(4, COLOR_WHITE, COLOR_GREEN); /* keys activated */ + init_pair(5, COLOR_WHITE, COLOR_BLUE); /* select line */ + init_pair(6, COLOR_WHITE, COLOR_GREEN); /* selected process */ + } + termtype = getenv("TERM"); + if (!strcmp(termtype, "xterm") || !strcmp(termtype, "xterm-color") || + !strcmp(termtype, "vt220")) { + define_key("\033[H", KEY_HOME); + define_key("\033[F", KEY_END); + define_key("\033OP", KEY_F(1)); + define_key("\033OQ", KEY_F(2)); + define_key("\033OR", KEY_F(3)); + define_key("\033OS", KEY_F(4)); + define_key("\0330U", KEY_F(6)); + define_key("\033[11~", KEY_F(1)); + define_key("\033[12~", KEY_F(2)); + define_key("\033[13~", KEY_F(3)); + define_key("\033[14~", KEY_F(4)); + define_key("\033[16~", KEY_F(6)); + define_key("\033[17;2~", KEY_F(18)); + } + signal(SIGTERM, handle_sigterm); + mousemask(BUTTON1_CLICKED, NULL); + refresh(); +} + +WINDOW *create_window(int height, int width, int startx, int starty) +{ + WINDOW *win; + win = newwin(height, width, startx, starty); + box(win, 0 , 0); + wrefresh(win); + return win; +} + +WINDOW *create_window_no_border(int height, int width, int startx, int starty) +{ + WINDOW *win; + win = newwin(height, width, startx, starty); + wrefresh(win); + return win; +} + +void print_digit(WINDOW *win, int digit) +{ + if (digit < 0) { + wattron(win, COLOR_PAIR(1)); + wprintw(win, "%d", digit); + wattroff(win, COLOR_PAIR(1)); + } else if (digit > 0) { + wattron(win, COLOR_PAIR(2)); + wprintw(win, "+%d", digit); + wattroff(win, COLOR_PAIR(2)); + } else { + wprintw(win, "0"); + } +} + +void print_digits(WINDOW *win, int first, int second) +{ + wprintw(win, "("); + print_digit(win, first); + wprintw(win, ", "); + print_digit(win, second); + wprintw(win, ")"); +} + +void print_headers(int line, const char desc[], int value, int first, int second) +{ + wattron(header, A_BOLD); + mvwprintw(header, line, 4, "%s", desc); + wattroff(header, A_BOLD); + mvwprintw(header, line, 16, "%d", value); + wmove(header, line, 24); + print_digits(header, first, second); + wmove(header, line, 40); +} + +void set_window_title(WINDOW *win, const char title[]) +{ + wattron(win, A_BOLD); + mvwprintw(win, 0, 1, title); + wattroff(win, A_BOLD); +} + +void print_log(const char str[]) +{ + unsigned int i; + int current_line = 1; + int current_char = 1; + char *tmp, *tmp2; + /* rotate the line buffer */ + if (nb_log_lines >= MAX_LOG_LINES) { + tmp = strndup(log_lines, MAX_LINE_LENGTH * MAX_LOG_LINES + MAX_LOG_LINES); + tmp2 = strchr(tmp, '\n'); + memset(log_lines, '\0', strlen(log_lines)); + strncat(log_lines, tmp2 + 1, strlen(tmp2) - 1); + log_lines[strlen(log_lines)] = '\n'; + log_lines[strlen(log_lines)] = '\0'; + free(tmp); + } + nb_log_lines++; + + strncat(log_lines, str, MAX_LINE_LENGTH - 1); + + if (nb_log_lines < MAX_LOG_LINES) + log_lines[strlen(log_lines)] = '\n'; + log_lines[strlen(log_lines)] = '\0'; + + werase(status); + box(status, 0 , 0); + set_window_title(status, "Status"); + for (i = 0; i < strlen(log_lines); i++) { + if (log_lines[i] == '\n') { + wmove(status, ++current_line, 1); + current_char = 1; + } else { + mvwprintw(status, current_line, current_char++, "%c", + log_lines[i]); + } + } + wrefresh(status); +} + +int process_selected(Quark proc) +{ + int selected; + get_current_attribute_value_int(&proc, "selected", selected); + return selected; +} + +void update_selected_processes() +{ + Quark selected = state_system->getQuark(selected_process, "selected"); + if (process_selected(selected_process)) { + state_system->updateCurrentState(selected, 0); + print_log("Process removed"); + } else { + state_system->updateCurrentState(selected, 1); + print_log("Process added"); + } +} + +void print_key(WINDOW *win, const char key[], const char desc[], int toggle) +{ + int pair; + if (toggle > 0) + pair = 4; + else + pair = 3; + wattron(win, COLOR_PAIR(pair)); + wprintw(footer, "%s", key); + wattroff(win, COLOR_PAIR(pair)); + wprintw(footer, ":%s", desc); +} + +void update_footer() +{ + sem_wait(&update_display_sem); + werase(footer); + wmove(footer, 1, 1); + print_key(footer, "F2", "CPUtop ", current_view == cpu); + print_key(footer, "F3", "PerfTop ", current_view == perf); + print_key(footer, "F4", "IOTop ", current_view == iostream); + print_key(footer, "Enter", "Details ", current_view == process_details); + print_key(footer, "Space", "Highlight ", 0); + print_key(footer, "q", "Quit ", 0); + print_key(footer, "r", "Pref ", 0); + print_key(footer, "t", "Threads ", toggle_threads); + print_key(footer, "p", "Pause ", toggle_pause); + + wrefresh(footer); + sem_post(&update_display_sem); +} + +void basic_header() +{ + werase(header); + box(header, 0 , 0); + set_window_title(header, "Statistics for interval [gathering data...["); + wattron(header, A_BOLD); + mvwprintw(header, 1, 4, "CPUs"); + mvwprintw(header, 2, 4, "Threads"); + mvwprintw(header, 3, 4, "FDs"); + wattroff(header, A_BOLD); + wrefresh(header); +} + +struct tm format_timestamp(uint64_t timestamp) +{ + struct tm tm; + uint64_t ts_sec = 0, ts_nsec; + time_t time_s; + + ts_nsec = timestamp; + ts_sec += ts_nsec / NSEC_PER_SEC; + ts_nsec = ts_nsec % NSEC_PER_SEC; + + time_s = (time_t) ts_sec; + + localtime_r(&time_s, &tm); + + return tm; +} + +static void scale_unit(uint64_t bytes, char *ret) +{ + if (bytes >= 1000000000) + sprintf(ret, "%" PRIu64 "G", bytes/1000000000); + if (bytes >= 1000000) + sprintf(ret, "%" PRIu64 "M", bytes/1000000); + else if (bytes >= 1000) + sprintf(ret, "%" PRIu64 "K", bytes/1000); + else + sprintf(ret, "%" PRIu64, bytes); +} + +uint64_t total_io() +{ + uint64_t total = 0; + int read, write; + unsigned long birth; + unsigned long real_start; + Quark proc; + + if (get_attribute_value_at_quark(i_end, NULL, "proc", proc)) { + do { + get_attribute_value_at_ulong( + i_end, &proc, "birth", birth); + if (birth > i_start) + real_start = birth; + else + real_start = i_start; + get_interval_value_int(real_start, i_end, &proc, + "fileread", read); + get_interval_value_int(real_start, i_end, &proc, + "filewrite", write); + total += read + write; + + } while (get_attribute_value_at_quark( + i_end, &proc, "next", proc)); + } + + return total; +} + +void update_header() +{ + struct tm start, end; + uint64_t ts_nsec_start, ts_nsec_end; + char io[16]; + int cpu_nb; + int nbthreads, nbnewthreads, nbdeadthreads; + int nbfiles, nbnewfiles, nbdeadfiles; + + ts_nsec_start = i_start % NSEC_PER_SEC; + start = format_timestamp(i_start); + + ts_nsec_end = i_end % NSEC_PER_SEC; + end = format_timestamp(i_end); + + werase(header); + box(header, 0 , 0); + set_window_title(header, "Statistics for interval "); + wattron(header, A_BOLD); + + wprintw(header, + "[%02d:%02d:%02d.%09" PRIu64 ", %02d:%02d:%02d.%09" PRIu64 "[", + start.tm_hour, start.tm_min, start.tm_sec, ts_nsec_start, + end.tm_hour, end.tm_min, end.tm_sec, ts_nsec_end); + mvwprintw(header, 1, 4, "CPUs"); + wattroff(header, A_BOLD); + + cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu")); + get_attribute_value_at_int(i_end, NULL, "nbthreads", nbthreads); + get_interval_value_int(i_start, i_end, NULL, "nbnewthreads", + nbnewthreads); + get_interval_value_int(i_start, i_end, NULL, "nbdeadthreads", + nbdeadthreads); + get_attribute_value_at_int(i_end, NULL, "nbfiles", nbfiles); + get_interval_value_int(i_start, i_end, NULL, "nbnewfiles", nbnewfiles); + get_interval_value_int(i_start, i_end, NULL, "nbdeadfiles", + nbdeadfiles); + + wprintw(header, "\t%d\t(max/cpu : %0.2f%)", cpu_nb, + 100.0/cpu_nb); + print_headers(2, "Threads", nbthreads, nbnewthreads,-1*nbdeadthreads); + print_headers(3, "FDs", nbfiles, nbnewfiles,-1*nbdeadfiles); + scale_unit(total_io(), io); + mvwprintw(header, 3, 43, "%sB/sec", io); + wrefresh(header); +} + +int sort_by_cpu_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + unsigned long total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &p1, "birth", birth1); + get_attribute_value_at_ulong(i_end, &p2, "birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_ulong(start1, i_end, &p1, "totalcpunsec", total1); + get_interval_value_ulong(start2, i_end, &p2, "totalcpunsec", total2); + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +int sort_by_tid_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + int tid1, tid2; + + get_attribute_value_at_int(i_end, &p1, "tid", tid1); + get_attribute_value_at_int(i_end, &p2, "tid", tid2); + + if (tid1 > tid2) + return 1; + if (tid1 == tid2) + return 0; + return -1; +} + +int sort_by_pid_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + int pid1, pid2; + + get_attribute_value_at_int(i_end, &p1, "pid", pid1); + get_attribute_value_at_int(i_end, &p2, "pid", pid2); + + if (pid1 > pid2) + return 1; + if (pid1 == pid2) + return 0; + return -1; +} + + +int sort_by_process_read_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + int total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &p1, "birth", birth1); + get_attribute_value_at_ulong(i_end, &p2, "birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_int(start1, i_end, &p1, "fileread", total1); + get_interval_value_int(start2, i_end, &p2, "fileread", total2); + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +int sort_by_process_write_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + int total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &p1, "birth", birth1); + get_attribute_value_at_ulong(i_end, &p2, "birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_int(start1, i_end, &p1, "filewrite", total1); + get_interval_value_int(start2, i_end, &p2, "filewrite", total2); + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +int sort_by_process_total_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + int p1Read, p2Read; + int p1Write, p2Write; + int total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &p1, "birth", birth1); + get_attribute_value_at_ulong(i_end, &p2, "birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_int(start1, i_end, &p1, "fileread", p1Read); + get_interval_value_int(start2, i_end, &p2, "fileread", p2Read); + get_interval_value_int(start1, i_end, &p1, "filewrite", p1Write); + get_interval_value_int(start2, i_end, &p2, "filewrite", p2Write); + + total1 = p1Read + p1Write; + total2 = p2Read + p2Write; + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +int sort_by_file_read_desc(const void *pf1, const void *pf2) +{ + Quark f1 = *(Quark *)pf1; + Quark f2 = *(Quark *)pf2; + int total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1); + get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_int(start1, i_end, &f1, "file/read", total1); + get_interval_value_int(start2, i_end, &f2, "file/read", total2); + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +int sort_by_file_write_desc(const void *pf1, const void *pf2) +{ + Quark f1 = *(Quark *)pf1; + Quark f2 = *(Quark *)pf2; + int total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &f1, "file/birth", birth1); + get_attribute_value_at_ulong(i_end, &f2, "file/birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_int(start1, i_end, &f1, "file/write", total1); + get_interval_value_int(start2, i_end, &f2, "file/write", total2); + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +int sort_by_file_fd_desc(const void *pf1, const void *pf2) +{ + Quark f1 = *(Quark *)pf1; + Quark f2 = *(Quark *)pf2; + int fd1, fd2; + + get_attribute_value_at_int(i_end, &f1, "file/fd", fd1); + get_attribute_value_at_int(i_end, &f2, "file/fd", fd2); + + if (fd1 > fd2) + return 1; + if (fd1 == fd2) + return 0; + return -1; +} + +int sort_by_cpu_group_by_threads_desc(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + unsigned long total1, total2; + unsigned long birth1, birth2; + unsigned long start1 = i_start; + unsigned long start2 = i_start; + + get_attribute_value_at_ulong(i_end, &p1, "birth", birth1); + get_attribute_value_at_ulong(i_end, &p2, "birth", birth2); + if (birth1 > i_start) + start1 = birth1; + if (birth2 > i_start) + start2 = birth2; + + get_interval_value_ulong(start1, i_end, &p1, "threadstotalcpunsec", + total1); + get_interval_value_ulong(start2, i_end, &p2, "threadstotalcpunsec", + total2); + + if (total1 > total2) + return 1; + if (total1 == total2) + return 0; + return -1; +} + +void update_cputop_display() +{ + unsigned int i; + int header_offset = 2; + unsigned long elapsed; + double maxcputime; + int nblinedisplayed = 0; + int current_line = 0; + int column; + Quark *processes; + int tid, pid; + unsigned long totalcpunsec; + std::string comm; + + Quark cpu_root = state_system->getQuark("cpu"); + Quark proc_root = state_system->getQuark("proc"); + unsigned int cpu_nb = get_sequence_length(i_end, cpu_root); + unsigned int proc_nb = get_sequence_length(i_end, proc_root); + + elapsed = i_end - i_start; + maxcputime = elapsed * cpu_nb / 100.0; + + processes = g_new(Quark, proc_nb); + sequence_to_array(i_end, proc_root, processes, proc_nb); + + if (cputopview[0].sort == 1) + qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc); + else if (cputopview[1].sort == 1) + qsort(processes, proc_nb, sizeof(Quark), sort_by_pid_desc); + else if (cputopview[2].sort == 1) + qsort(processes, proc_nb, sizeof(Quark), sort_by_tid_desc); + else if (cputopview[3].sort == 1) + qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc); + else + qsort(processes, proc_nb, sizeof(Quark), sort_by_cpu_desc); + + set_window_title(center, "CPU Top"); + wattron(center, A_BOLD); + column = 1; + for (i = 0; i < 4; i++) { + if (cputopview[i].sort) { + wattron(center, A_UNDERLINE); + pref_current_sort = i; + } + mvwprintw(center, 1, column, cputopview[i].title); + wattroff(center, A_UNDERLINE); + column += 10; + } + wattroff(center, A_BOLD); + + max_center_lines = LINES - 5 - 7 - 1 - header_offset; + + /* iterate the process (thread) list */ + for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines; + i++) { + get_attribute_value_at_int(i_end, processes + i, "tid", tid); + get_attribute_value_at_int(i_end, processes + i, "pid", pid); + + if (pid != tid) + if (toggle_threads == -1) + continue; + + if (process_selected(processes[i])) { + wattron(center, COLOR_PAIR(6)); + mvwhline(center, current_line + header_offset, 1, ' ', + COLS-3); + } + if (current_line == selected_line) { + selected_process = processes[i]; + wattron(center, COLOR_PAIR(5)); + mvwhline(center, current_line + header_offset, 1, ' ', + COLS-3); + } + /* CPU(%) */ + get_interval_value_ulong(i_start, i_end, processes + i, + "totalcpunsec", totalcpunsec); + mvwprintw(center, current_line + header_offset, 1, "%1.2f", + totalcpunsec / maxcputime); + /* PID */ + mvwprintw(center, current_line + header_offset, 11, "%d", pid); + /* TID */ + mvwprintw(center, current_line + header_offset, 21, "%d", tid); + /* NAME */ + get_attribute_value_at_string(i_end, processes + i, "comm", + comm); + mvwprintw(center, current_line + header_offset, 31, "%s", + comm.c_str()); + wattroff(center, COLOR_PAIR(6)); + wattroff(center, COLOR_PAIR(5)); + nblinedisplayed++; + current_line++; + } + + g_free(processes); +} + +int sort_perf(const void *pp1, const void *pp2) +{ + Quark p1 = *(Quark *)pp1; + Quark p2 = *(Quark *)pp2; + std::string key = sort_perf_key; + int total1; + int total2; + int tid1; + int tid2; + + if (!get_attribute_value_at_int(i_end, &p1, "perf/" + key + "/count", + total1)) + total1 = 0; + + if (!get_attribute_value_at_int(i_end, &p2, "perf/" + key + "/count", + total2)) + total2 = 0; + + + if (total1 < total2) + return 1; + if (total1 == total2) { + get_attribute_value_at_int(i_end, &p1, "tid", tid1); + get_attribute_value_at_int(i_end, &p2, "tid", tid2); + if (tid1 < tid2) + return 1; + return -1; + } + return -1; +} + +void print_key_title(const char key[], int line) +{ + wattron(center, A_BOLD); + mvwprintw(center, line, 1, "%s", key); + mvwprintw(center, line, 30, " "); + wattroff(center, A_BOLD); +} + +void update_process_details() +{ + unsigned long elapsed; + double maxcputime; + unsigned int i, j = 0; + char unit[4]; + char filename_buf[COLS]; + int line = 1; + int column; + unsigned int cpu_nb; + std::string comm; + int tid = -1, pid, ppid, fileread, filewrite; + unsigned long totalcpunsec; + Quark *global_perf; + unsigned int global_perf_nb; + std::string key; + int count; + Quark *files; + unsigned int file_nb; + int fd, read, write; + std::string name; + + set_window_title(center, "Process details"); + + elapsed = i_end - i_start; + cpu_nb = get_sequence_length(i_end, state_system->getQuark("cpu")); + maxcputime = elapsed * cpu_nb / 100.0; + + get_attribute_value_at_int(i_end, &selected_process, "tid", tid); + if (tid == -1) { + print_key_title("Does not exit at this time", 3); + return; + } + + print_key_title("Name", line++); + get_attribute_value_at_string(i_end, &selected_process, "comm", comm); + wprintw(center, "%s", comm.c_str()); + print_key_title("TID", line++); + wprintw(center, "%d", tid); + + print_key_title("PID", line++); + get_attribute_value_at_int(i_end, &selected_process, "pid", pid); + wprintw(center, "%d", pid); + print_key_title("PPID", line++); + get_attribute_value_at_int(i_end, &selected_process, "ppid", ppid); + wprintw(center, "%d", ppid); + print_key_title("CPU", line++); + get_attribute_value_at_ulong(i_end, &selected_process, "totalcpunsec", + totalcpunsec); + wprintw(center, "%1.2f %%", totalcpunsec/maxcputime); + + print_key_title("READ B/s", line++); + get_attribute_value_at_int(i_end, &selected_process, "fileread", + fileread); + scale_unit(fileread, unit); + wprintw(center, "%s", unit); + + print_key_title("WRITE B/s", line++); + get_attribute_value_at_int(i_end, &selected_process, "filewrite", + filewrite); + scale_unit(filewrite, unit); + wprintw(center, "%s", unit); + + + global_perf_nb = get_global_perf_list_size(i_end); + global_perf = g_new(Quark, global_perf_nb); + get_global_perf_list(i_end, global_perf, global_perf_nb); + for (i = 0; i < global_perf_nb; i++) { + get_attribute_value_at_string(i_end, global_perf + i, "key", + key); + print_key_title(key.c_str(), line++); + if (!get_attribute_value_at_int(i_end, global_perf + i, "count", + count)) + count = 0; + wprintw(center, "%d", count); + } + line++; + + wattron(center, A_BOLD); + column = 1; + for (i = 0; i < 3; i++) { + if (fileview[i].sort) { + pref_current_sort = i; + wattron(center, A_UNDERLINE); + } + mvwprintw(center, line, column, fileview[i].title); + wattroff(center, A_UNDERLINE); + column += 10; + } + mvwprintw(center, line++, column, "FILENAME"); + wattroff(center, A_BOLD); + + file_nb = get_number_of_opened_files(i_end, selected_process); + files = g_new(Quark, file_nb); + get_opened_files(i_end, selected_process, files, file_nb); + + if (fileview[0].sort == 1) + qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc); + else if (fileview[1].sort == 1) + qsort(files, file_nb, sizeof(Quark), sort_by_file_read_desc); + else if (fileview[2].sort == 1) + qsort(files, file_nb, sizeof(Quark), sort_by_file_write_desc); + else + qsort(files, file_nb, sizeof(Quark), sort_by_file_fd_desc); + + for (i = selected_line; + i < file_nb && i < (selected_line + max_center_lines - line + 2); + i++) { + get_attribute_value_at_int(i_end, files + i, "fd", fd); + mvwprintw(center, line + j, 1, "%d", fd); + get_attribute_value_at_int(i_end, files + i, "read", read); + scale_unit(read, unit); + mvwprintw(center, line + j, 11, "%s", unit); + get_attribute_value_at_int(i_end, files + i, "write", write); + scale_unit(write, unit); + mvwprintw(center, line + j, 21, "%s", unit); + get_attribute_value_at_string(i_end, files + i, "name", name); + snprintf(filename_buf, COLS - 25, "%s", name.c_str()); + mvwprintw(center, line + j, 31, "%s", filename_buf); + j++; + } + g_free(global_perf); + g_free(files); +} + +void update_perf() +{ + unsigned int i, j; + int nblinedisplayed = 0; + int current_line = 0; + int header_offset = 2; + int perf_row = 40; + int value; + unsigned int global_perf_nb; + Quark *global_perf; + int sort = 0; + int visible = 0; + std::string key; + bool sort_exists; + unsigned int proc_nb; + Quark *procs; + Quark proc_beg; + int tid, pid; + std::string comm; + + set_window_title(center, "Perf Top"); + wattron(center, A_BOLD); + mvwprintw(center, 1, 1, "PID"); + mvwprintw(center, 1, 11, "TID"); + mvwprintw(center, 1, 22, "NAME"); + + perf_row = 40; + global_perf_nb = get_global_perf_list_size(i_end); + global_perf = g_new(Quark, global_perf_nb); + get_global_perf_list(i_end, global_perf, global_perf_nb); + for (i = 0; i < global_perf_nb; i++) { + get_attribute_value_at_int(i_end, global_perf + i, "visible", + visible); + get_attribute_value_at_string(i_end, global_perf + i, "key", + key); + sort_exists = get_attribute_value_at_int(i_end, global_perf + i, + "sort", sort); + if (visible) { + if (sort_exists && sort) { + wattron(center, A_UNDERLINE); + } + /* + 5 to strip the "perf_" prefix */ + mvwprintw(center, 1, perf_row, "%s", + key.c_str() + 5); + wattroff(center, A_UNDERLINE); + perf_row += 20; + } + if (sort_exists && sort) { + sort_perf_key = key; + } + } + wattroff(center, A_BOLD); + + proc_beg = state_system->getQuark("proc"); + proc_nb = get_sequence_length(i_end, proc_beg); + procs = g_new(Quark, proc_nb); + sequence_to_array(i_end, proc_beg, procs, proc_nb); + for (i = 0; i < proc_nb && nblinedisplayed < max_center_lines; i++) { + get_attribute_value_at_int(i_end, procs + i, "tid", tid); + get_attribute_value_at_int(i_end, procs + i, "pid", pid); + get_attribute_value_at_string(i_end, procs + 1, "comm", comm); + + if (pid != tid) + if (toggle_threads == -1) + continue; + + if (process_selected(procs[i])) { + wattron(center, COLOR_PAIR(6)); + mvwhline(center, current_line + header_offset, 1, ' ', + COLS-3); + } + if (current_line == selected_line) { + selected_process = procs[i]; + wattron(center, COLOR_PAIR(5)); + mvwhline(center, current_line + header_offset, 1, ' ', + COLS-3); + } + + mvwprintw(center, current_line + header_offset, 1, "%d", pid); + mvwprintw(center, current_line + header_offset, 11, "%d", tid); + mvwprintw(center, current_line + header_offset, 22, "%s", + comm.c_str()); + + perf_row = 40; + for (j = 0; j < global_perf_nb; j++) { + get_attribute_value_at_int(i_end, global_perf + j, + "visible", visible); + get_attribute_value_at_string(i_end, global_perf + j, + "key", key); + + if (visible) { + if (!get_interval_value_int(i_start, i_end, + procs + i, "perf/" + + key + "/count", + value)) { + value = 0; + } + mvwprintw(center, current_line + header_offset, + perf_row, "%d", value); + perf_row += 20; + } + } + + wattroff(center, COLOR_PAIR(6)); + wattroff(center, COLOR_PAIR(5)); + nblinedisplayed++; + current_line++; + } + g_free(global_perf); + g_free(procs); +} + +void update_iostream() +{ + unsigned int i; + int header_offset = 2; + int nblinedisplayed = 0; + int current_line = 0; + char unit[4]; + int column; + unsigned int proc_nb; + Quark *procs; + Quark proc_root; + int pid, tid, read, write, totalread, totalwrite; + std::string comm; + + set_window_title(center, "IO Top"); + wattron(center, A_BOLD); + mvwprintw(center, 1, 1, "PID"); + mvwprintw(center, 1, 11, "TID"); + mvwprintw(center, 1, 22, "NAME"); + column = 40; + for (i = 0; i < 3; i++) { + if (iostreamtopview[i].sort) { + pref_current_sort = i; + wattron(center, A_UNDERLINE); + } + mvwprintw(center, 1, column, iostreamtopview[i].title); + wattroff(center, A_UNDERLINE); + column += 12; + } + wattroff(center, A_BOLD); + wattroff(center, A_UNDERLINE); + + proc_root = state_system->getQuark("proc"); + proc_nb = get_sequence_length(i_end, proc_root); + procs = g_new(Quark, proc_nb); + sequence_to_array(i_end, proc_root, procs, proc_nb); + + if (iostreamtopview[0].sort == 1) + qsort(procs, proc_nb, sizeof(Quark), sort_by_process_read_desc); + else if (iostreamtopview[1].sort == 1) + qsort(procs, proc_nb, sizeof(Quark), + sort_by_process_write_desc); + else if (iostreamtopview[2].sort == 1) + qsort(procs, proc_nb, sizeof(Quark), + sort_by_process_total_desc); + else + qsort(procs, proc_nb, sizeof(Quark), + sort_by_process_total_desc); + + for (i = list_offset; i < proc_nb && nblinedisplayed < max_center_lines; + i++) { + get_attribute_value_at_int(i_end, procs + i, "tid", tid); + get_attribute_value_at_int(i_end, procs + i, "pid", pid); + get_attribute_value_at_string(i_end, procs + i, "comm", comm); + get_attribute_value_at_int(i_end, procs + i, "fileread", + read); + get_attribute_value_at_int(i_end, procs + i, "filewrite", + write); + get_attribute_value_at_int(i_end, procs + i, "totalfileread", + totalread); + get_attribute_value_at_int(i_end, procs + i, "totalfilewrite", + totalwrite); + + + if (pid != tid) + if (toggle_threads == -1) + continue; + + if (process_selected(procs[i])) { + wattron(center, COLOR_PAIR(6)); + mvwhline(center, current_line + header_offset, 1, ' ', + COLS-3); + } + if (current_line == selected_line) { + selected_process = procs[i]; + wattron(center, COLOR_PAIR(5)); + mvwhline(center, current_line + header_offset, 1, ' ', + COLS-3); + } + /* PID */ + mvwprintw(center, current_line + header_offset, 1, "%d", pid); + /* TID */ + mvwprintw(center, current_line + header_offset, 11, "%d", tid); + /* NAME */ + mvwprintw(center, current_line + header_offset, 22, "%s", + comm.c_str()); + + /* READ (bytes/sec) */ + scale_unit(read, unit); + mvwprintw(center, current_line + header_offset, 40, "%s", unit); + + /* WRITE (bytes/sec) */ + scale_unit(write, unit); + mvwprintw(center, current_line + header_offset, 52, "%s", unit); + + /* TOTAL STREAM */ + scale_unit(totalread + totalwrite, unit); + mvwprintw(center, current_line + header_offset, 64, "%s", unit); + + wattroff(center, COLOR_PAIR(6)); + wattroff(center, COLOR_PAIR(5)); + nblinedisplayed++; + current_line++; + } + g_free(procs); +} + +void update_current_view() +{ + sem_wait(&update_display_sem); + update_header(); + + werase(center); + box(center, 0, 0); + switch (current_view) { + case cpu: + update_cputop_display(); + break; + case perf: + update_perf(); + break; + case process_details: + update_process_details(); + break; + case iostream: + update_iostream(); + break; + case tree: + update_cputop_display(); + break; + default: + break; + } + update_panels(); + doupdate(); + sem_post(&update_display_sem); +} + +void update_process_detail_sort(int *line_selected) +{ + int i; + int size; + + size = 3; + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + + if (fileview[*line_selected].sort == 1) + fileview[*line_selected].reverse = 1; + for (i = 0; i < size; i++) + fileview[i].sort = 0; + fileview[*line_selected].sort = 1; +} + +void update_process_detail_pref(int *line_selected, int toggle_view, int toggle_sort) +{ + int i; + int size; + + if (pref_panel_window) { + del_panel(pref_panel); + delwin(pref_panel_window); + } + size = 3; + + pref_panel_window = create_window(size + 2, 30, 10, 10); + pref_panel = new_panel(pref_panel_window); + + werase(pref_panel_window); + box(pref_panel_window, 0 , 0); + set_window_title(pref_panel_window, "Process Detail Preferences "); + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, size + 1, 1, + " 's' : sort, space : toggle"); + wattroff(pref_panel_window, A_BOLD); + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + if (toggle_sort == 1) { + update_process_detail_sort(line_selected); + update_current_view(); + } + + for (i = 0; i < size; i++) { + if (i == *line_selected) { + wattron(pref_panel_window, COLOR_PAIR(5)); + mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2); + } + if (fileview[i].sort == 1) + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, i + 1, 1, "[-] %s", + fileview[i].title); + wattroff(pref_panel_window, A_BOLD); + wattroff(pref_panel_window, COLOR_PAIR(5)); + + } + update_panels(); + doupdate(); +} + +void update_iostream_sort(int *line_selected) +{ + int i; + int size; + + size = 3; + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + if (iostreamtopview[*line_selected].sort == 1) + iostreamtopview[*line_selected].reverse = 1; + for (i = 0; i < size; i++) + iostreamtopview[i].sort = 0; + iostreamtopview[*line_selected].sort = 1; + +} + +void update_iostream_pref(int *line_selected, int toggle_view, int toggle_sort) +{ + int i; + int size; + + if (pref_panel_window) { + del_panel(pref_panel); + delwin(pref_panel_window); + } + size = 3; + + pref_panel_window = create_window(size + 2, 30, 10, 10); + pref_panel = new_panel(pref_panel_window); + + werase(pref_panel_window); + box(pref_panel_window, 0 , 0); + set_window_title(pref_panel_window, "IOTop Preferences "); + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, size + 1, 1, + " 's' : sort, space : toggle"); + wattroff(pref_panel_window, A_BOLD); + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + if (toggle_sort == 1) { + update_iostream_sort(line_selected); + update_current_view(); + } + + for (i = 0; i < size; i++) { + if (i == *line_selected) { + wattron(pref_panel_window, COLOR_PAIR(5)); + mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2); + } + if (iostreamtopview[i].sort == 1) + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, i + 1, 1, "[-] %s", + iostreamtopview[i].title); + wattroff(pref_panel_window, A_BOLD); + wattroff(pref_panel_window, COLOR_PAIR(5)); + + } + update_panels(); + doupdate(); +} + +void update_cpu_sort(int *line_selected) +{ + int i; + int size = 3; + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + + /* special case, we don't support sorting by procname for now */ + if (*line_selected != 3) { + if (cputopview[*line_selected].sort == 1) + cputopview[*line_selected].reverse = 1; + for (i = 0; i < size; i++) + cputopview[i].sort = 0; + cputopview[*line_selected].sort = 1; + } +} + +void update_cpu_pref(int *line_selected, int toggle_view, int toggle_sort) +{ + int i; + int size; + + if (pref_panel_window) { + del_panel(pref_panel); + delwin(pref_panel_window); + } + size = 4; + + pref_panel_window = create_window(size + 2, 30, 10, 10); + pref_panel = new_panel(pref_panel_window); + + werase(pref_panel_window); + box(pref_panel_window, 0 , 0); + set_window_title(pref_panel_window, "CPUTop Preferences "); + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, size + 1, 1, + " 's' : sort, space : toggle"); + wattroff(pref_panel_window, A_BOLD); + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + if (toggle_sort == 1) { + update_cpu_sort(line_selected); + update_current_view(); + } + + for (i = 0; i < size; i++) { + if (i == *line_selected) { + wattron(pref_panel_window, COLOR_PAIR(5)); + mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2); + } + if (cputopview[i].sort == 1) + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, i + 1, 1, "[-] %s", + cputopview[i].title); + wattroff(pref_panel_window, A_BOLD); + wattroff(pref_panel_window, COLOR_PAIR(5)); + + } + update_panels(); + doupdate(); +} + +void update_perf_sort(int *line_selected) +{ + int i; + int size; + Quark *global_perf; + + size = get_global_perf_list_size(i_end); + global_perf = g_new(Quark, size); + get_global_perf_list(i_end, global_perf, size); + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + + for (i = 0; i < size; i++) { + if (i != *line_selected) + modify_attribute(i_end, global_perf + i, "sort", 0); + else + modify_attribute(i_end, global_perf + i, "sort", 1); + } + + g_free(global_perf); +} + +void update_perf_pref(int *line_selected, int toggle_view, int toggle_sort) +{ + int i; + int size; + Quark *global_perf; + int visible; + int sort; + std::string key; + + if (pref_panel_window) { + del_panel(pref_panel); + delwin(pref_panel_window); + } + + size = get_global_perf_list_size(i_end); + global_perf = g_new(Quark, size); + get_global_perf_list(i_end, global_perf, size); + + pref_panel_window = create_window(size + 2, 30, 10, 10); + pref_panel = new_panel(pref_panel_window); + + werase(pref_panel_window); + box(pref_panel_window, 0 , 0); + set_window_title(pref_panel_window, "Perf Preferences "); + wattron(pref_panel_window, A_BOLD); + mvwprintw(pref_panel_window, size + 1, 1, + " 's' : sort, space : toggle"); + wattroff(pref_panel_window, A_BOLD); + + if (*line_selected > (size - 1)) + *line_selected = size - 1; + else if (*line_selected < 0) + *line_selected = 0; + + if (toggle_sort == 1) { + update_perf_sort(line_selected); + update_current_view(); + } + + for (i = 0; i < size; i++) { + get_attribute_value_at_int(i_end, global_perf + i, + "visible", visible); + get_attribute_value_at_string(i_end, global_perf + i, "key", + key); + if (i == *line_selected && toggle_view == 1) { + visible = visible == 1 ? 0 : 1; + modify_attribute(i_end, global_perf + i, "visible", + visible); + update_current_view(); + } + if (i == *line_selected) { + wattron(pref_panel_window, COLOR_PAIR(5)); + mvwhline(pref_panel_window, i + 1, 1, ' ', 30 - 2); + } + + if (get_attribute_value_at_int(i_end, global_perf + 1, "sort", + sort) && sort) { + wattron(pref_panel_window, A_BOLD); + } + mvwprintw(pref_panel_window, i + 1, 1, "[%c] %s", + visible == 1 ? 'x' : ' ', key.c_str() + 5); + wattroff(pref_panel_window, A_BOLD); + wattroff(pref_panel_window, COLOR_PAIR(5)); + } + update_panels(); + doupdate(); + + g_free(global_perf); +} + +int update_preference_panel(int *line_selected, int toggle_view, int toggle_sort) +{ + int ret = 0; + + switch(current_view) { + case perf: + update_perf_pref(line_selected, toggle_view, toggle_sort); + break; + case cpu: + update_cpu_pref(line_selected, toggle_view, toggle_sort); + break; + case iostream: + update_iostream_pref(line_selected, toggle_view, toggle_sort); + break; + case process_details: + update_process_detail_pref(line_selected, toggle_view, toggle_sort); + break; + default: + ret = -1; + break; + } + + return ret; +} + +int update_sort(int *line_selected) +{ + int ret = 0; + + switch(current_view) { + case perf: + update_perf_sort(line_selected); + break; + case cpu: + update_cpu_sort(line_selected); + break; + case iostream: + update_iostream_sort(line_selected); + break; + case process_details: + update_process_detail_sort(line_selected); + break; + default: + ret = -1; + break; + } + + return ret; +} + + +void toggle_pref_panel(void) +{ + int ret; + + if (pref_panel_visible) { + hide_panel(pref_panel); + pref_panel_visible = 0; + } else { + ret = update_preference_panel(&pref_line_selected, 0, 0); + if (ret < 0) + return; + show_panel(pref_panel); + pref_panel_visible = 1; + } + update_panels(); + doupdate(); +} + +void display() +{ + if (i_start == 0) + i_start = first_display_update; + else + i_start += refresh_display; + i_end = i_start + refresh_display; + + max_elements = get_sequence_length( + i_end, state_system->getQuark("proc")); + update_current_view(); + update_footer(); + update_panels(); + doupdate(); +} + +void pause_display() +{ + toggle_pause = 1; + print_log("Pause"); + sem_wait(&pause_sem); +} + +void resume_display() +{ + toggle_pause = -1; + print_log("Resume"); + sem_post(&pause_sem); +} + +void *handle_keyboard(void *p) +{ + int ch; + while((ch = getch())) { + switch(ch) { + /* Move the cursor and scroll */ + case 'j': + case KEY_DOWN: + if (pref_panel_visible) { + pref_line_selected++; + update_preference_panel(&pref_line_selected, 0, 0); + } else { + if (selected_line < (max_center_lines - 1) && + selected_line < max_elements - 1) { + selected_line++; + selected_in_list++; + } else if (selected_in_list < (max_elements - 1) + && (list_offset < (max_elements - max_center_lines))) { + selected_in_list++; + list_offset++; + } + update_current_view(); + } + break; + case KEY_NPAGE: + break; + case 'k': + case KEY_UP: + if (pref_panel_visible) { + if (pref_line_selected > 0) + pref_line_selected--; + update_preference_panel(&pref_line_selected, 0, 0); + } else { + if (selected_line > 0) { + selected_line--; + selected_in_list--; + } else if (selected_in_list > 0 && list_offset > 0) { + selected_in_list--; + list_offset--; + } + update_current_view(); + } + break; + case KEY_PPAGE: + break; + + /* Navigate the history with arrows */ + case KEY_LEFT: + if ((i_start - refresh_display) >= + first_display_update) { + i_start -= refresh_display; + i_end = i_start + refresh_display; + print_log("Going back in time"); + } else { + print_log("Cannot rewind, last data is already displayed"); + } + max_elements = get_sequence_length( + i_end, state_system->getQuark("proc")); + + /* we force to pause the display when moving in time */ + if (toggle_pause < 0) + pause_display(); + + update_current_view(); + update_footer(); + break; + case KEY_RIGHT: + if ((i_end + refresh_display) <= + last_display_update) { + i_end += refresh_display; + i_start = i_end - refresh_display; + print_log("Going forward in time"); + max_elements = get_sequence_length( + i_end, state_system->getQuark( + "proc")); + update_current_view(); + update_footer(); + } else { + print_log("Manually moving forward"); + sem_post(&timer); + if (toggle_pause > 0) { + sem_post(&pause_sem); + update_current_view(); + sem_wait(&pause_sem); + } + } + + break; + case ' ': + if (pref_panel_visible) { + update_preference_panel(&pref_line_selected, 1, 0); + } else { + update_selected_processes(); + update_current_view(); + } + break; + case 's': + if (pref_panel_visible) + update_preference_panel(&pref_line_selected, 0, 1); + break; + case '>': + /* perf uses a hashtable, it is ordered backward */ + if (current_view == perf) { + pref_current_sort--; + } else if (!pref_panel_visible) { + pref_current_sort++; + } + update_sort(&pref_current_sort); + update_current_view(); + break; + case '<': + /* perf uses a hashtable, it is ordered backward */ + if (current_view == perf) { + pref_current_sort++; + } else if (!pref_panel_visible) { + pref_current_sort--; + } + update_sort(&pref_current_sort); + update_current_view(); + break; + + case 13: /* FIXME : KEY_ENTER ?? */ + if (pref_panel_visible) + break; + if (current_view != process_details) { + previous_view = current_view; + current_view = process_details; + } else { + current_view = previous_view; + previous_view = process_details; + } + update_current_view(); + break; + + case KEY_F(1): + if (pref_panel_visible) + toggle_pref_panel(); + current_view = cpu; + selected_line = 0; + update_current_view(); + break; + case KEY_F(2): + if (pref_panel_visible) + toggle_pref_panel(); + current_view = cpu; + selected_line = 0; + update_current_view(); + break; + case KEY_F(3): + if (pref_panel_visible) + toggle_pref_panel(); + current_view = perf; + selected_line = 0; + update_current_view(); + break; + case KEY_F(4): + if (pref_panel_visible) + toggle_pref_panel(); + current_view = iostream; + selected_line = 0; + update_current_view(); + break; + case KEY_F(10): + case 'q': + reset_ncurses(); + break; + case 't': + toggle_threads *= -1; + update_current_view(); + break; + case 'p': + if (toggle_pause < 0) { + pause_display(); + } else { + resume_display(); + } + break; + case 'r': + toggle_pref_panel(); + break; + /* ESCAPE, but slow to process, don't know why */ + case 27: + if (pref_panel_visible) + toggle_pref_panel(); + else if (current_view == process_details) { + current_view = previous_view; + previous_view = process_details; + } + update_current_view(); + break; + default: + update_current_view(); + break; + } + update_footer(); + } + return NULL; +} + +void init_view_headers() +{ + cputopview[0].title = strdup("CPU(%)"); + cputopview[0].sort = 1; + cputopview[1].title = strdup("PID"); + cputopview[2].title = strdup("TID"); + cputopview[3].title = strdup("NAME"); + + iostreamtopview[0].title = strdup("R (B/sec)"); + iostreamtopview[1].title = strdup("W (B/sec)"); + iostreamtopview[2].title = strdup("Total (B)"); + iostreamtopview[2].sort = 1; + + fileview[0].title = strdup("FD"); + fileview[1].title = strdup("READ"); + fileview[1].sort = 1; + fileview[2].title = strdup("WRITE"); +} + +void init_ncurses() +{ + selected_processes = g_ptr_array_new(); + sem_init(&update_display_sem, 0, 1); + init_view_headers(); + init_screen(); + + header = create_window(5, COLS - 1, 0, 0); + center = create_window(LINES - 5 - 7, COLS - 1, 5, 0); + status = create_window(MAX_LOG_LINES + 2, COLS - 1, LINES - 7, 0); + footer = create_window(1, COLS - 1, LINES - 1, 0); + + print_log("Starting display"); + + main_panel = new_panel(center); + + current_view = cpu; + + basic_header(); + update_footer(); + + pthread_create(&keyboard_thread, NULL, handle_keyboard, (void *)NULL); +}