/******************************************************************************* * Copyright (C) 2010, Linaro * Copyright (C) 2010, IBM Corporation * * This file is part of PowerDebug. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Amit Arora (IBM Corporation) * - initial API and implementation *******************************************************************************/ #include "powerdebug.h" #include "clocks.h" static char clk_dir_path[PATH_MAX]; static char clk_name[NAME_MAX]; static int bold[MAX_LINES]; int init_clock_details(void) { char *path = debugfs_locate_mpoint(); struct stat buf; if (path) strcpy(clk_dir_path, path); else { if (!dump) { create_selectedwindow(); sprintf(clock_lines[0], "Unable to locate debugfs " "mount point. Mount debugfs " "and try again..\n"); print_one_clock(0, clock_lines[0], 1, 0); old_clock_line_no = 1; return(1); } else { fprintf(stderr, "powerdebug: Unable to locate debugfs " "mount point. Mount debugfs and try " "again..\n"); exit(1); } } sprintf(clk_dir_path, "%s/clock", clk_dir_path); //strcpy(clk_dir_path, "/debug/clock"); // Hardcoded for testing.. if (stat(clk_dir_path, &buf)) { if (!dump) { create_selectedwindow(); sprintf(clock_lines[0], "Unable to find clock tree" " information at %s.\n", clk_dir_path); print_one_clock(0, clock_lines[0], 1, 0); old_clock_line_no = 1; return(1); } else { fprintf(stderr, "powerdebug: Unable to find clock tree" " information at %s.\n", clk_dir_path); exit(1); } } strcpy(clk_name, ""); return(0); } int get_int_from(char *file) { FILE *filep; char result[NAME_MAX]; int ret; filep = fopen(file, "r"); if (!filep) return -1; //TBD : What should we return on failure, here ? ret = fscanf(filep, "%s", result); fclose(filep); return atoi(result); } int read_and_print_clock_info(int verbose, int hrow, int selected) { if (!old_clock_line_no) read_clock_info(clk_dir_path); if (!clocks_info->num_children) { fprintf(stderr, "powerdebug: No clocks found. Exiting..\n"); exit(1); } print_clock_info(verbose, hrow, selected); //destroy_clocks_info(); hrow = (hrow < old_clock_line_no) ? hrow : old_clock_line_no - 1; return hrow; } int calc_delta_screen_size(int hrow) { if (hrow > (maxy - 3)) return hrow - (maxy - 3); return 0; } void print_clock_info(int verbose, int hrow, int selected) { int i, count = 0, delta; (void)verbose; print_clock_header(); for (i = 0; i < clocks_info->num_children; i++) add_clock_details_recur(clocks_info->children[i], hrow, selected); delta = calc_delta_screen_size(hrow); 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++; } old_clock_line_no = clock_line_no; clock_line_no = 0; } void prepare_name_str(char *namestr, struct clock_info *clock) { int i; strcpy(namestr, ""); if (clock->level > 1) for (i = 0; i < (clock->level - 1); i++) strcat(namestr, " "); strcat(namestr, clock->name); } void add_clock_details_recur(struct clock_info *clock, int hrow, int selected) { 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 %-4d %-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], ""); } 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]); } void destroy_clocks_info(void) { int i; 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; } } } free(clocks_info); clocks_info = NULL; } void destroy_clocks_info_recur(struct clock_info *clock) { 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; } } } } void read_and_dump_clock_info(int verbose) { (void)verbose; printf("Clock Tree :\n"); printf("**********\n"); read_clock_info(clk_dir_path); dump_clock_info(clocks_info, 1, 1); } void read_clock_info(char *clkpath) { DIR *dir; struct dirent *item; char filename[NAME_MAX], clockname[NAME_MAX]; struct clock_info *child; struct clock_info *cur; dir = opendir(clkpath); if (!dir) return; clocks_info = (struct clock_info *)malloc(sizeof(struct clock_info)); memset(clocks_info, 0, sizeof(clocks_info)); strcpy(clocks_info->name, "/"); clocks_info->level = 0; while ((item = readdir(dir))) { /* skip hidden dirs except ".." */ if (item->d_name[0] == '.') continue; strcpy(clockname, item->d_name); sprintf(filename, "%s/%s", clkpath, item->d_name); cur = (struct clock_info *)malloc(sizeof(struct clock_info)); memset(cur, 0, sizeof(struct clock_info)); strcpy(cur->name, clockname); 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); } closedir(dir); } 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); ret = stat(filename, &buf); if (ret < 0) { printf("Error doing a stat on %s\n", filename); exit(1); } if (S_ISREG(buf.st_mode)) { if (!strcmp(item->d_name, "flags")) parent->flags = get_int_from(filename); if (!strcmp(item->d_name, "rate")) parent->rate = get_int_from(filename); if (!strcmp(item->d_name, "usecount")) parent->usecount = get_int_from(filename); continue; } if (!S_ISDIR(buf.st_mode)) continue; 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); return cur; } void insert_children(struct clock_info **parent, struct clock_info *clk) { 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++; } void dump_clock_info(struct clock_info *clk, int level, int bmp) { int i, j; if (!clk) return; for (i = 1, j = 0; i < level; i++, j = (i - 1)) { if (i == (level - 1)) { if (clk->last_child) printf("`-- "); else printf("|-- "); } else { if ((1<name); else { char *unit = "Hz"; double drate = (double)clk->rate; if (drate > 1000 && drate < 1000000) { unit = "KHz"; drate /= 1000; } if (drate > 1000000) { unit = "MHz"; drate /= 1000000; } printf("%s (flags:%d,usecount:%d,rate:%5.2f %s)\n", clk->name, clk->flags, clk->usecount, drate, unit); } if (clk->children) { int tbmp = bmp; int xbmp = -1; if (clk->last_child) { xbmp ^= 1 << (level - 2); xbmp = tbmp & xbmp; } else xbmp = bmp; for (i = 0; i < clk->num_children; i++) { tbmp = xbmp | (1 << level); dump_clock_info(clk->children[i], level + 1, tbmp); } } } char *debugfs_locate_mpoint(void) { int ret; FILE *filep; char **path; char fsname[64]; struct statfs sfs; path = likely_mpoints; while (*path) { ret = statfs(*path, &sfs); if (ret >= 0 && sfs.f_type == (long)DEBUGFS_MAGIC) return *path; path++; } filep = fopen("/proc/mounts", "r"); if (filep == NULL) { fprintf(stderr, "powerdebug: Error opening /proc/mounts."); exit(1); } while (fscanf(filep, "%*s %s %s %*s %*d %*d\n", debugfs_mntpoint, fsname) == 2) if (!strcmp(fsname, "debugfs")) break; fclose(filep); if (strcmp(fsname, "debugfs")) return NULL; return debugfs_mntpoint; }