Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- clocks.c | 422 +++++++++++++++++++--------------------------------------- display.c | 160 +++++++++++++++++++---- powerdebug.c | 66 ++++++---- powerdebug.h | 19 ++- 4 files changed, 325 insertions(+), 342 deletions(-)
diff --git a/clocks.c b/clocks.c index e843b9e..de5476a 100644 --- a/clocks.c +++ b/clocks.c @@ -11,6 +11,10 @@ * Contributors: * Amit Arora amit.arora@linaro.org (IBM Corporation) * - initial API and implementation + * + * Daniel Lezcano daniel.lezcano@linaro.org (IBM Corporation) + * - Rewrote code and API + * *******************************************************************************/
#ifndef _GNU_SOURCE @@ -25,26 +29,12 @@ #include "clocks.h" #include "tree.h"
-#define MAX_LINES 120 - -static char clk_dir_path[PATH_MAX]; -static int bold[MAX_LINES]; -static char clock_lines[MAX_LINES][128]; -static int clock_line_no; -static int old_clock_line_no; - struct clock_info { - char name[NAME_MAX]; int flags; int rate; int usecount; - int num_children; - int last_child; - int expanded; - int level; + bool expanded; char *prefix; - struct clock_info *parent; - struct clock_info **children; } *clocks_info;
static struct tree *clock_tree = NULL; @@ -74,18 +64,15 @@ static int locate_debugfs(char *clk_path) return ret; }
-int clock_init(void) +static struct clock_info *clock_alloc(void) { - if (locate_debugfs(clk_dir_path)) - return -1; - - sprintf(clk_dir_path, "%s/clock", clk_dir_path); + struct clock_info *ci;
- clock_tree = tree_load(clk_dir_path, NULL); - if (!clock_tree) - return -1; + ci = malloc(sizeof(*ci)); + if (ci) + memset(ci, 0, sizeof(*ci));
- return access(clk_dir_path, F_OK); + return ci; }
/* @@ -236,347 +223,206 @@ void find_parents_for_clock(char *clkname, int complete)
strcat(name, clkname); sprintf(str, "Enter Clock Name : %s\n", name); - print_one_clock(2, str, 1, 0); + display_reset_cursor(); + display_print_line(0, str, 1, NULL); + display_refresh_pad(); return; } sprintf(name, "Parents for "%s" Clock : \n", clkname); - print_one_clock(0, name, 1, 1); + display_reset_cursor(); + display_print_line(0, name, 1, NULL); + display_refresh_pad(); dump_all_parents(clkname); }
-static void destroy_clocks_info_recur(struct clock_info *clock) +static inline int read_clock_cb(struct tree *t, void *data) { - int i; - - if (clock && clock->num_children) { - for (i = (clock->num_children - 1); i >= 0; i--) { - fflush(stdin); - destroy_clocks_info_recur(clock->children[i]); - if (!i) { - free(clock->children); - clock->children = NULL; - clock->num_children = 0; - } - } - } -} - -static void destroy_clocks_info(void) -{ - int i; + struct clock_info *clk = t->private;
- if (!clocks_info) - return; + file_read_value(t->path, "flags", "%x", &clk->flags); + file_read_value(t->path, "rate", "%d", &clk->rate); + file_read_value(t->path, "usecount", "%d", &clk->usecount);
- if (clocks_info->num_children) { - for (i = (clocks_info->num_children - 1); i >= 0 ; i--) { - destroy_clocks_info_recur(clocks_info->children[i]); - if (!i) { - free(clocks_info->children); - clocks_info->children = NULL; - } - } - } - clocks_info->num_children = 0; - free(clocks_info); - clocks_info = NULL; + return 0; }
+static int read_clock_info(void) +{ + return tree_for_each(clock_tree, read_clock_cb, NULL); +}
-int read_and_print_clock_info(int hrow, int selected) +static int fill_clock_cb(struct tree *t, void *data) { - print_one_clock(0, "Reading Clock Tree ...", 1, 1); + struct clock_info *clk;
- if (!old_clock_line_no || selected == REFRESH_WINDOW) { - destroy_clocks_info(); - read_clock_info(clk_dir_path); - } + clk = clock_alloc(); + if (!clk) + return -1; + t->private = clk;
- if (!clocks_info || !clocks_info->num_children) { - fprintf(stderr, "powerdebug: No clocks found. Exiting..\n"); - exit(1); + /* we skip the root node but we set it expanded for its children */ + if (!t->parent) { + clk->expanded = true; + return 0; }
- if (selected == CLOCK_SELECTED) - selected = 1; - else - selected = 0; - - print_clock_info(hrow, selected); - hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1; - - return hrow; + return read_clock_cb(t, data); }
-static int calc_delta_screen_size(int hrow) +static int fill_clock_tree(void) { - if (hrow >= (maxy - 3)) - return hrow - (maxy - 4); - - return 0; + return tree_for_each(clock_tree, fill_clock_cb, NULL); }
-static void prepare_name_str(char *namestr, struct clock_info *clock) +static int is_collapsed(struct tree *t, void *data) { - int i; + struct clock_info *clk = t->private;
- strcpy(namestr, ""); - if (clock->level > 1) - for (i = 0; i < (clock->level - 1); i++) - strcat(namestr, " "); - strcat(namestr, clock->name); -} + if (!clk->expanded) + return 1;
-static void collapse_all_subclocks(struct clock_info *clock) -{ - int i; - - clock->expanded = 0; - if (clock->num_children) - for (i = 0; i < clock->num_children; i++) - collapse_all_subclocks(clock->children[i]); + return 0; }
-static void add_clock_details_recur(struct clock_info *clock, - int hrow, int selected) +static char *clock_line(struct tree *t) { - int i; - char *unit = " Hz"; - char rate_str[64]; - char name_str[256]; - double drate = (double)clock->rate; - - if (drate > 1000 && drate < 1000000) { - unit = "KHz"; - drate /= 1000; - } - if (drate > 1000000) { - unit = "MHz"; - drate /= 1000000; - } - if (clock->usecount) - bold[clock_line_no] = 1; - else - bold[clock_line_no] = 0; - - sprintf(rate_str, "%.2f %s", drate, unit); - prepare_name_str(name_str, clock); - sprintf(clock_lines[clock_line_no++], "%-55s 0x%-4x %-12s %-12d %-12d", - name_str, clock->flags, rate_str, clock->usecount, - clock->num_children); - - if (selected && (hrow == (clock_line_no - 1))) { - if (clock->expanded) - collapse_all_subclocks(clock); - else - clock->expanded = 1; - selected = 0; - } - - if (clock->expanded && clock->num_children) - for (i = 0; i < clock->num_children; i++) - add_clock_details_recur(clock->children[i], - hrow, selected); - strcpy(clock_lines[clock_line_no], ""); -} + struct clock_info *clk; + int rate; + const char *clkunit; + char *clkrate, *clkname, *clkline = NULL;
-void print_clock_info(int hrow, int selected) -{ - int i, count = 0, delta; + clk = t->private; + rate = clk->rate; + clkunit = clock_rate(&rate);
- print_clock_header(); + if (asprintf(&clkname, "%*s%s", (t->depth - 1) * 2, "", t->name) < 0) + return NULL;
- for (i = 0; i < clocks_info->num_children; i++) - add_clock_details_recur(clocks_info->children[i], - hrow, selected); + if (asprintf(&clkrate, "%d%s", rate, clkunit) < 0) + goto free_clkname;
- delta = calc_delta_screen_size(hrow); + if (asprintf(&clkline, "%-55s 0x%-16x %-12s %-9d %-8d", clkname, + clk->flags, clkrate, clk->usecount, t->nrchild) < 0) + goto free_clkrate;
- while (clock_lines[count + delta] && - strcmp(clock_lines[count + delta], "")) { - if (count < delta) { - count++; - continue; - } - print_one_clock(count - delta, clock_lines[count + delta], - bold[count + delta], (hrow == (count + delta))); - count++; - } +free_clkrate: + free(clkrate); +free_clkname: + free(clkname);
- old_clock_line_no = clock_line_no; - clock_line_no = 0; + return clkline; }
-static void insert_children(struct clock_info **parent, struct clock_info *clk) +static int clock_print_info_cb(struct tree *t, void *data) { - if (!(*parent)->num_children || (*parent)->children == NULL) { - (*parent)->children = (struct clock_info **) - malloc(sizeof(struct clock_info *)*2); - (*parent)->num_children = 0; - } else - (*parent)->children = (struct clock_info **) - realloc((*parent)->children, - sizeof(struct clock_info *) * - ((*parent)->num_children + 2)); - if ((*parent)->num_children > 0) - (*parent)->children[(*parent)->num_children - 1]->last_child - = 0; - clk->last_child = 1; - (*parent)->children[(*parent)->num_children] = clk; - (*parent)->children[(*parent)->num_children + 1] = NULL; - (*parent)->num_children++; -} + struct clock_info *clock = t->private; + int *line = data; + char *buffer;
-static struct clock_info *read_clock_info_recur(char *clkpath, int level, - struct clock_info *parent) -{ - int ret = 0; - DIR *dir; - char filename[PATH_MAX]; - struct dirent *item; - struct clock_info *cur = NULL; - struct stat buf; - - dir = opendir(clkpath); - if (!dir) - return NULL; - - while ((item = readdir(dir))) { - struct clock_info *child; - /* skip hidden dirs except ".." */ - if (item->d_name[0] == '.' ) - continue; - - sprintf(filename, "%s/%s", clkpath, item->d_name); + /* we skip the root node of the tree */ + if (!t->parent) + return 0;
- ret = stat(filename, &buf); + /* show the clock when *all* its parent is expanded */ + if (tree_for_each_parent(t->parent, is_collapsed, NULL)) + return 0;
- if (ret < 0) { - printf("Error doing a stat on %s\n", filename); - exit(1); - } + buffer = clock_line(t); + if (!buffer) + return -1;
- if (S_ISREG(buf.st_mode)) { - if (!strcmp(item->d_name, "flags")) - file_read_hex(filename, &parent->flags); - if (!strcmp(item->d_name, "rate")) - file_read_int(filename, &parent->rate); - if (!strcmp(item->d_name, "usecount")) - file_read_int(filename, &parent->usecount); - continue; - } + display_print_line(*line, buffer, clock->usecount, t);
- if (!S_ISDIR(buf.st_mode)) - continue; + (*line)++;
- cur = (struct clock_info *)malloc(sizeof(struct clock_info)); - memset(cur, 0, sizeof(cur)); - strcpy(cur->name, item->d_name); - cur->children = NULL; - cur->parent = NULL; - cur->num_children = 0; - cur->expanded = 0; - cur->level = level; - child = read_clock_info_recur(filename, level + 1, cur); - insert_children(&parent, cur); - cur->parent = parent; - } - closedir(dir); + free(buffer);
- return cur; + return 0; }
-static struct clock_info *clock_alloc(const char *name) +static int clock_print_info(void) { - struct clock_info *ci; + int ret, line = 0;
- ci = malloc(sizeof(*ci)); - if (ci) { - memset(ci, 0, sizeof(*ci)); - strcpy(ci->name, name); - } + print_clock_header();
- return ci; -} + display_reset_cursor();
-static int fill_clock_cb(struct tree *t, void *data) -{ - struct clock_info *clkinfo; + ret = tree_for_each(clock_tree, clock_print_info_cb, &line);
- clkinfo = clock_alloc(t->name); - if (!clkinfo) - return -1; + display_refresh_pad(); + + return ret; +}
- t->private = clkinfo; - clkinfo->level = t->depth; +int clock_toggle_expanded(void) +{ + struct tree *t = display_get_row_data(); + struct clock_info *clk = t->private;
- file_read_value(t->path, "flags", "%x", &clkinfo->flags); - file_read_value(t->path, "rate", "%d", &clkinfo->rate); - file_read_value(t->path, "usecount", "%d", &clkinfo->usecount); + clk->expanded = !clk->expanded;
return 0; }
-int read_clock_info(char *clkpath) +/* + * Initialize the clock framework + */ +int clock_init(void) { - DIR *dir; - struct dirent *item; - char filename[NAME_MAX]; - struct clock_info *child; - struct clock_info *cur; - int ret = -1; + char clk_dir_path[PATH_MAX];
- if (tree_for_each(clock_tree, fill_clock_cb, NULL)) + if (locate_debugfs(clk_dir_path)) return -1;
- dir = opendir(clkpath); - if (!dir) - return -1; + sprintf(clk_dir_path, "%s/clock", clk_dir_path);
- clocks_info = clock_alloc("/"); - if (!clocks_info) + if (access(clk_dir_path, F_OK)) return -1;
- while ((item = readdir(dir))) { - - /* skip hidden dirs except ".." */ - if (item->d_name[0] == '.') - continue; - - sprintf(filename, "%s/%s", clkpath, item->d_name); - - cur = clock_alloc(item->d_name); - if (!cur) - goto out; - - cur->parent = clocks_info; - cur->num_children = 0; - cur->expanded = 0; - cur->level = 1; - insert_children(&clocks_info, cur); - child = read_clock_info_recur(filename, 2, cur); - } + clock_tree = tree_load(clk_dir_path, NULL); + if (!clock_tree) + return -1;
- ret = 0; + return fill_clock_tree(); +}
-out: - closedir(dir); +/* + * Read the clock information and fill the tree with the information + * found in the files. Then print the result to the text based interface + * Return 0 on success, < 0 otherwise + */ +int read_and_print_clock_info(int hrow, int selected) +{ + if (read_clock_info()) + return -1;
- return ret; + return clock_print_info(); }
-void read_and_dump_clock_info(char *clk) +/* + * Read the clock information and fill the tree with the information + * found in the files. Then dump to stdout a formatted result. + * @clk : a name for a specific clock we want to show + * Return 0 on success, < 0 otherwise + */ +int read_and_dump_clock_info(char *clk) { - read_clock_info(clk_dir_path); + int ret; + + if (read_clock_info()) + return -1;
if (clk) { printf("\nParents for "%s" Clock :\n\n", clk); - dump_all_parents(clk); + ret = dump_all_parents(clk); printf("\n\n"); } else { printf("\nClock Tree :\n"); printf("**********\n"); - dump_clock_info(); + ret = dump_clock_info(); printf("\n\n"); } + + return ret; } diff --git a/display.c b/display.c index dd5543c..98dc955 100644 --- a/display.c +++ b/display.c @@ -32,11 +32,16 @@ enum { PT_COLOR_DEFAULT = 1,
static WINDOW *header_win; static WINDOW *regulator_win; -static WINDOW *clock_win; +static WINDOW *clock_pad; +static WINDOW *clock_labels; static WINDOW *sensor_win; static WINDOW *footer_win;
int maxx, maxy; + +/* Number of lines in the virtual window */ +static const int maxrows = 1024; + static char footer_items[NUM_FOOTER_ITEMS][64];
static char *win_names[TOTAL_FEATURE_WINS] = { @@ -45,6 +50,16 @@ static char *win_names[TOTAL_FEATURE_WINS] = { "Sensors" };
+struct rowdata { + int attr; + void *data; +}; + +static struct rowdata *rowdata; +static int nrdata; +static int scrolling; +static int cursor; + static void display_fini(void) { endwin(); @@ -83,8 +98,12 @@ int display_init(void) if (!regulator_win) return -1;
- clock_win = subwin(stdscr, maxy - 2, maxx, 1, 0); - if (!clock_win) + clock_labels = subwin(stdscr, maxy - 2, maxx, 1, 0); + if (!clock_labels) + return -1; + + clock_pad = newpad(maxrows, maxx); + if (!clock_pad) return -1;
sensor_win = subwin(stdscr, maxy - 2, maxx, 1, 0); @@ -127,10 +146,6 @@ void create_selectedwindow(int selectedwindow) wrefresh(regulator_win); break;
- case CLOCK: - wrefresh(clock_win); - break; - case SENSOR: wrefresh(sensor_win); break; @@ -234,15 +249,15 @@ void show_regulator_info(struct regulator_info *reg_info, int nr_reg, int verbos
void print_clock_header(void) { - werase(clock_win); - wattron(clock_win, A_BOLD); - print(clock_win, 0, 0, "Name"); - print(clock_win, 54, 0, "Flags"); - print(clock_win, 64, 0, "Rate"); - print(clock_win, 72, 0, "Usecount"); - print(clock_win, 84, 0, "Children"); - wattroff(clock_win, A_BOLD); - wrefresh(clock_win); + werase(clock_labels); + wattron(clock_labels, A_BOLD); + print(clock_labels, 0, 0, "Name"); + print(clock_labels, 56, 0, "Flags"); + print(clock_labels, 75, 0, "Rate"); + print(clock_labels, 88, 0, "Usecount"); + print(clock_labels, 98, 0, "Children"); + wattroff(clock_labels, A_BOLD); + wrefresh(clock_labels); }
void print_sensor_header(void) @@ -259,17 +274,110 @@ void print_sensor_header(void) wrefresh(sensor_win); }
-void print_one_clock(int line, char *str, int bold, int highlight) +int display_refresh_pad(void) { - if (bold) - wattron(clock_win, WA_BOLD); - if (highlight) - wattron(clock_win, WA_STANDOUT); + return prefresh(clock_pad, scrolling, 0, 2, 0, maxy - 2, maxx); +} + +static int inline display_clock_un_select(int line, bool highlight, bool bold) +{ + if (mvwchgat(clock_pad, line, 0, -1, + highlight ? WA_STANDOUT : + bold ? WA_BOLD: WA_NORMAL, 0, NULL) < 0) + return -1; + + return display_refresh_pad(); +} + +int display_clock_select(int line) +{ + return display_clock_un_select(line, true, false); +} + +int display_clock_unselect(int line, bool bold) +{ + return display_clock_un_select(line, false, bold); +} + +void *display_get_row_data(void) +{ + return rowdata[cursor].data; +} + +int display_set_row_data(int line, void *data, int attr) +{ + if (line >= nrdata) { + rowdata = realloc(rowdata, sizeof(struct rowdata) * (line + 1)); + if (!rowdata) + return -1; + nrdata = line + 1; + } + + rowdata[line].data = data; + rowdata[line].attr = attr; + + return 0; +} + +int display_reset_cursor(void) +{ + nrdata = 0; + werase(clock_pad); + return wmove(clock_pad, 0, 0); +} + +int display_print_line(int line, char *str, int bold, void *data) +{ + int attr = 0;
- print(clock_win, 0, line + 1, "%s", str); if (bold) - wattroff(clock_win, WA_BOLD); - if (highlight) - wattroff(clock_win, WA_STANDOUT); - wrefresh(clock_win); + attr |= WA_BOLD; + + if (line == cursor) + attr |= WA_STANDOUT; + + if (display_set_row_data(line, data, attr)) + return -1; + + if (attr) + wattron(clock_pad, attr); + + wprintw(clock_pad, "%s\n", str); + + if (attr) + wattroff(clock_pad, attr); + + return 0; +} + +int display_next_line(void) +{ + if (cursor >= nrdata) + return cursor; + + display_clock_unselect(cursor, rowdata[cursor].attr); + if (cursor < nrdata - 1) { + if (cursor >= (maxy - 4 + scrolling)) + scrolling++; + cursor++; + } + display_clock_select(cursor); + + return cursor; +} + +int display_prev_line(void) +{ + if (cursor >= nrdata) + return cursor; + + display_clock_unselect(cursor, rowdata[cursor].attr); + if (cursor > 0) { + if (cursor <= scrolling) + scrolling--; + cursor--; + } + display_clock_select(cursor); + + return cursor; } diff --git a/powerdebug.c b/powerdebug.c index 8e7e78e..5cf9da7 100644 --- a/powerdebug.c +++ b/powerdebug.c @@ -155,7 +155,7 @@ int getoptions(int argc, char *argv[], struct powerdebug_options *options) }
int keystroke_callback(bool *enter_hit, bool *findparent_ncurses, - char *clkname_str, bool *refreshwin, + char *clkname_str, bool *refreshwin, bool *cont, struct powerdebug_options *options) { char keychar; @@ -177,12 +177,22 @@ int keystroke_callback(bool *enter_hit, bool *findparent_ncurses, }
if (options->selectedwindow == CLOCK) { - if (keystroke == KEY_DOWN) - highlighted_row++; - if (keystroke == KEY_UP && highlighted_row > 0) - highlighted_row--; + + if (keystroke == KEY_DOWN) { + display_next_line(); + *cont = true; + } + + if (keystroke == KEY_UP) { + display_prev_line(); + *cont = true; + } + +#if 0 + /* TODO : fix with a new panel applicable for all subsystems */ if (keystroke == '/') *findparent_ncurses = true; +#endif
if ((keystroke == '\e' || oldselectedwin != options->selectedwindow) && *findparent_ncurses) { @@ -240,6 +250,7 @@ int mainloop(struct powerdebug_options *options, bool findparent_ncurses = false; bool refreshwin = false; bool enter_hit = false; + bool cont = false; char clkname_str[64];
strcpy(clkname_str, ""); @@ -249,9 +260,11 @@ int mainloop(struct powerdebug_options *options, struct timeval tval; fd_set readfds;
- create_windows(options->selectedwindow); - show_header(options->selectedwindow); - create_selectedwindow(options->selectedwindow); + if (options->selectedwindow != CLOCK || !cont) { + create_windows(options->selectedwindow); + show_header(options->selectedwindow); + create_selectedwindow(options->selectedwindow); + }
if (options->selectedwindow == REGULATOR) { regulator_read_info(reg_info, nr_reg); @@ -263,21 +276,26 @@ int mainloop(struct powerdebug_options *options,
int hrow;
- if (!findparent_ncurses) { - int command = 0; - - if (enter_hit) - command = CLOCK_SELECTED; - if (refreshwin) - command = REFRESH_WINDOW; - hrow = read_and_print_clock_info( - highlighted_row, - command); - highlighted_row = hrow; - enter_hit = false; - } else - find_parents_for_clock(clkname_str, - enter_hit); + if (!cont) { + + if (!findparent_ncurses) { + int command = 0; + + if (enter_hit) { + clock_toggle_expanded(); + command = CLOCK_SELECTED; + } + if (refreshwin) + command = REFRESH_WINDOW; + hrow = read_and_print_clock_info( + highlighted_row, + command); + highlighted_row = hrow; + enter_hit = false; + } else + find_parents_for_clock(clkname_str, + enter_hit); + } else cont = false; }
if (options->selectedwindow == SENSOR) @@ -300,7 +318,7 @@ int mainloop(struct powerdebug_options *options, }
if (keystroke_callback(&enter_hit, &findparent_ncurses, - clkname_str, &refreshwin, options)) + clkname_str, &refreshwin, &cont, options)) break;
} diff --git a/powerdebug.h b/powerdebug.h index 535f194..760bcfb 100644 --- a/powerdebug.h +++ b/powerdebug.h @@ -28,14 +28,25 @@ enum {CLOCK, REGULATOR, SENSOR}; enum {CLOCK_SELECTED = 1, REFRESH_WINDOW};
-extern void read_and_dump_clock_info(char *clk); -extern int read_clock_info(char *clkpath); +extern int read_and_dump_clock_info(char *clk); extern void find_parents_for_clock(char *clkname, int complete); extern int read_and_print_clock_info(int hrow, int selected); -extern void print_clock_info(int hrow, int selected); +extern int print_clock_info(int hrow, int selected); extern void print_string_val(char *name, char *val); extern void print_clock_header(void); -extern void print_one_clock(int line, char *str, int bold, int highlight); + +extern int display_print_line(int line, char *str, int bold, void *data); + +extern int display_refresh_pad(void); +extern int display_reset_cursor(void); +extern int display_next_line(void); +extern int display_prev_line(void); + +extern void *display_get_row_data(void); + +extern int clock_toggle_expanded(void); +extern int display_clock_select(int line); +extern int display_clock_unselect(int line, bool bold);
extern void get_sensor_info(char *path, char *name, char *sensor, int verbose); extern int read_and_print_sensor_info(int verbose);