2009-11-17 17:41:25

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 1/3] perf symbols: Add a long_name_len member to struct dso

From: Arnaldo Carvalho de Melo <[email protected]>

Using a two bytes hole we already had and since we also need to
calculate this strlen for fetching the buildids. We'll use it in 'perf
top' to auto-adjust the output based on the terminal width.

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/util/symbol.c | 26 +++++++++++++++++++++-----
tools/perf/util/symbol.h | 1 +
2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 1b77e81..5cc96c8 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -109,13 +109,24 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp)
self->start, self->end, self->name);
}

+static void dso__set_long_name(struct dso *self, char *name)
+{
+ self->long_name = name;
+ self->long_name_len = strlen(name);
+}
+
+static void dso__set_basename(struct dso *self)
+{
+ self->short_name = basename(self->long_name);
+}
+
struct dso *dso__new(const char *name)
{
struct dso *self = malloc(sizeof(*self) + strlen(name) + 1);

if (self != NULL) {
strcpy(self->name, name);
- self->long_name = self->name;
+ dso__set_long_name(self, self->name);
self->short_name = self->name;
self->syms = RB_ROOT;
self->find_symbol = dso__find_symbol;
@@ -888,7 +899,7 @@ bool fetch_build_id_table(struct list_head *head)
continue;
have_buildid = true;
memset(&b.header, 0, sizeof(b.header));
- len = strlen(pos->long_name) + 1;
+ len = pos->long_name_len + 1;
len = ALIGN(len, 64);
b.header.size = sizeof(b) + len;

@@ -1165,6 +1176,7 @@ static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter)
dso_name[PATH_MAX];
struct map *map;
struct rb_node *last;
+ char *long_name;

if (dot == NULL || strcmp(dot, ".ko"))
continue;
@@ -1179,9 +1191,11 @@ static int dsos__load_modules_sym_dir(char *dirname, symbol_filter_t filter)
snprintf(path, sizeof(path), "%s/%s",
dirname, dent->d_name);

- map->dso->long_name = strdup(path);
- if (map->dso->long_name == NULL)
+ long_name = strdup(path);
+ if (long_name == NULL)
goto failure;
+ dso__set_long_name(map->dso, long_name);
+ dso__set_basename(map->dso);

err = dso__load_module_sym(map->dso, map, filter);
if (err < 0)
@@ -1420,8 +1434,10 @@ struct dso *dsos__findnew(const char *name)

if (!dso) {
dso = dso__new(name);
- if (dso != NULL)
+ if (dso != NULL) {
dsos__add(dso);
+ dso__set_basename(dso);
+ }
}

return dso;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 51c5a4a..5ad1019 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -66,6 +66,7 @@ struct dso {
u8 has_build_id:1;
unsigned char origin;
u8 build_id[BUILD_ID_SIZE];
+ u16 long_name_len;
const char *short_name;
char *long_name;
char name[0];
--
1.6.2.5


2009-11-17 17:41:08

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 2/3] perf top: Auto adjust symbol and dso widths

From: Arnaldo Carvalho de Melo <[email protected]>

We pre-calculate the symbol name lenght, then after we sort the entries
to print, calculate the biggest one and use that for the symbol name
width justification, then use the dso->long_name->len to justificate the
DSO name, deciding wether using the short or long name depending on how
much space we have on the terminal.

IOW give as much info to the user as the terminal width allows.

Suggested-by: Ingo Molnar <[email protected]>
Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-top.c | 92 +++++++++++++++++++++++++++++++++------------
1 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 89b7f68..a368978 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -78,6 +78,14 @@ static int dump_symtab = 0;

static bool hide_kernel_symbols = false;
static bool hide_user_symbols = false;
+static struct winsize winsize;
+static const char *graph_line =
+ "_____________________________________________________________________"
+ "_____________________________________________________________________";
+static const char *graph_dotted_line =
+ "---------------------------------------------------------------------"
+ "---------------------------------------------------------------------"
+ "---------------------------------------------------------------------";

/*
* Source
@@ -107,6 +115,7 @@ struct sym_entry {
unsigned long snap_count;
double weight;
int skip;
+ u16 name_len;
u8 origin;
struct map *map;
struct source_line *source;
@@ -119,34 +128,40 @@ struct sym_entry {
* Source functions
*/

-/* most GUI terminals set LINES (although some don't export it) */
-static int term_rows(void)
+static void get_term_dimensions(struct winsize *ws)
{
- char *lines_string = getenv("LINES");
- int n_lines;
-
- if (lines_string && (n_lines = atoi(lines_string)) > 0)
- return n_lines;
-#ifdef TIOCGWINSZ
- else {
- struct winsize ws;
- if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_row)
- return ws.ws_row;
+ char *s = getenv("LINES");
+
+ if (s != NULL) {
+ ws->ws_row = atoi(s);
+ s = getenv("COLUMNS");
+ if (s != NULL) {
+ ws->ws_col = atoi(s);
+ if (ws->ws_row && ws->ws_col)
+ return;
+ }
}
+#ifdef TIOCGWINSZ
+ if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+ ws->ws_row && ws->ws_col)
+ return;
#endif
- return 25;
+ ws->ws_row = 25;
+ ws->ws_col = 80;
}

-static void update_print_entries(void)
+static void update_print_entries(struct winsize *ws)
{
- print_entries = term_rows();
+ print_entries = ws->ws_row;
+
if (print_entries > 9)
print_entries -= 9;
}

static void sig_winch_handler(int sig __used)
{
- update_print_entries();
+ get_term_dimensions(&winsize);
+ update_print_entries(&winsize);
}

static void parse_source(struct sym_entry *syme)
@@ -423,6 +438,8 @@ static void print_sym_table(void)
struct sym_entry *syme, *n;
struct rb_root tmp = RB_ROOT;
struct rb_node *nd;
+ int sym_width = 0, dso_width;
+ const int win_width = winsize.ws_col - 1;

samples = userspace_samples = 0;

@@ -434,6 +451,7 @@ static void print_sym_table(void)
list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
syme->snap_count = syme->count[snap];
if (syme->snap_count != 0) {
+
if ((hide_user_symbols &&
syme->origin == PERF_RECORD_MISC_USER) ||
(hide_kernel_symbols &&
@@ -453,8 +471,7 @@ static void print_sym_table(void)

puts(CONSOLE_CLEAR);

- printf(
-"------------------------------------------------------------------------------\n");
+ printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [",
samples_per_sec,
100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
@@ -492,26 +509,44 @@ static void print_sym_table(void)
printf(", %d CPUs)\n", nr_cpus);
}

- printf("------------------------------------------------------------------------------\n\n");
+ printf("%-*.*s\n\n", win_width, win_width, graph_dotted_line);

if (sym_filter_entry) {
show_details(sym_filter_entry);
return;
}

+ /*
+ * Find the longest symbol name that will be displayed
+ */
+ for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
+ syme = rb_entry(nd, struct sym_entry, rb_node);
+ if (++printed > print_entries ||
+ (int)syme->snap_count < count_filter)
+ continue;
+
+ if (syme->name_len > sym_width)
+ sym_width = syme->name_len;
+ }
+
+ printed = 0;
+
if (nr_counters == 1)
printf(" samples pcnt");
else
printf(" weight samples pcnt");

+ dso_width = winsize.ws_col - sym_width - 29;
+
if (verbose)
printf(" RIP ");
- printf(" function DSO\n");
+ printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
printf(" %s _______ _____",
nr_counters == 1 ? " " : "______");
if (verbose)
printf(" ________________");
- printf(" ________________________________ ________________\n\n");
+ printf(" %-*.*s %-*.*s\n\n", sym_width, sym_width, graph_line,
+ dso_width, dso_width, graph_line);

for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
struct symbol *sym;
@@ -534,8 +569,11 @@ static void print_sym_table(void)
percent_color_fprintf(stdout, "%4.1f%%", pcnt);
if (verbose)
printf(" %016llx", sym->start);
- printf(" %-32s", sym->name);
- printf(" %s", syme->map->dso->short_name);
+ printf(" %-*.*s", sym_width, sym_width, sym->name);
+ printf(" %-*.*s", dso_width, dso_width,
+ dso_width >= syme->map->dso->long_name_len ?
+ syme->map->dso->long_name :
+ syme->map->dso->short_name);
printf("\n");
}
}
@@ -718,7 +756,7 @@ static void handle_keypress(int c)
case 'e':
prompt_integer(&print_entries, "Enter display entries (lines)");
if (print_entries == 0) {
- update_print_entries();
+ sig_winch_handler(SIGWINCH);
signal(SIGWINCH, sig_winch_handler);
} else
signal(SIGWINCH, SIG_DFL);
@@ -862,6 +900,9 @@ static int symbol_filter(struct map *map, struct symbol *sym)
}
}

+ if (!syme->skip)
+ syme->name_len = strlen(sym->name);
+
return 0;
}

@@ -1301,8 +1342,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
if (target_pid != -1 || profile_cpu != -1)
nr_cpus = 1;

+ get_term_dimensions(&winsize);
if (print_entries == 0) {
- update_print_entries();
+ update_print_entries(&winsize);
signal(SIGWINCH, sig_winch_handler);
}

--
1.6.2.5

2009-11-17 17:41:10

by Arnaldo Carvalho de Melo

[permalink] [raw]
Subject: [PATCH 3/3] perf top: Suppress DSO column if only one is present

From: Arnaldo Carvalho de Melo <[email protected]>

E.g.

[root@doppio ~]# perf top -U
---------------------------------------------------------------------------
PerfTop: 482 irqs/sec kernel:100.0% [1000Hz cycles], (all, 2 CPUs)
---------------------------------------------------------------------------
DSO: vmlinux
samples pcnt function
_______ _____ _________________________

471.00 47.9% read_hpet
57.00 5.8% acpi_os_read_port
30.00 3.1% hpet_next_event
30.00 3.1% find_busiest_group
22.00 2.2% schedule
18.00 1.8% sched_clock_local
14.00 1.4% _spin_lock_irqsave
14.00 1.4% native_read_tsc
13.00 1.3% trace_hardirqs_off
9.00 0.9% fget_light
9.00 0.9% ioread8
8.00 0.8% do_sys_poll

Cc: Frédéric Weisbecker <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
---
tools/perf/builtin-top.c | 43 ++++++++++++++++++++++++++++++++-----------
1 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index a368978..6db0e37 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -438,8 +438,9 @@ static void print_sym_table(void)
struct sym_entry *syme, *n;
struct rb_root tmp = RB_ROOT;
struct rb_node *nd;
- int sym_width = 0, dso_width;
+ int sym_width = 0, dso_width = 0;
const int win_width = winsize.ws_col - 1;
+ struct dso *unique_dso = NULL, *first_dso = NULL;

samples = userspace_samples = 0;

@@ -509,7 +510,7 @@ static void print_sym_table(void)
printf(", %d CPUs)\n", nr_cpus);
}

- printf("%-*.*s\n\n", win_width, win_width, graph_dotted_line);
+ printf("%-*.*s\n", win_width, win_width, graph_dotted_line);

if (sym_filter_entry) {
show_details(sym_filter_entry);
@@ -525,28 +526,47 @@ static void print_sym_table(void)
(int)syme->snap_count < count_filter)
continue;

+ if (first_dso == NULL)
+ unique_dso = first_dso = syme->map->dso;
+ else if (syme->map->dso != first_dso)
+ unique_dso = NULL;
+
+ if (syme->map->dso->long_name_len > dso_width)
+ dso_width = syme->map->dso->long_name_len;
+
if (syme->name_len > sym_width)
sym_width = syme->name_len;
}

printed = 0;

+ if (unique_dso)
+ printf("DSO: %s\n", unique_dso->long_name);
+ else {
+ int max_dso_width = winsize.ws_col - sym_width - 29;
+ if (dso_width > max_dso_width)
+ dso_width = max_dso_width;
+ putchar('\n');
+ }
if (nr_counters == 1)
printf(" samples pcnt");
else
printf(" weight samples pcnt");

- dso_width = winsize.ws_col - sym_width - 29;
-
if (verbose)
printf(" RIP ");
- printf(" %-*.*s DSO\n", sym_width, sym_width, "function");
+ printf(" %-*.*s", sym_width, sym_width, "function");
+ if (!unique_dso)
+ printf(" DSO");
+ putchar('\n');
printf(" %s _______ _____",
nr_counters == 1 ? " " : "______");
if (verbose)
printf(" ________________");
- printf(" %-*.*s %-*.*s\n\n", sym_width, sym_width, graph_line,
- dso_width, dso_width, graph_line);
+ printf(" %-*.*s", sym_width, sym_width, graph_line);
+ if (!unique_dso)
+ printf(" %-*.*s", dso_width, dso_width, graph_line);
+ puts("\n");

for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) {
struct symbol *sym;
@@ -570,10 +590,11 @@ static void print_sym_table(void)
if (verbose)
printf(" %016llx", sym->start);
printf(" %-*.*s", sym_width, sym_width, sym->name);
- printf(" %-*.*s", dso_width, dso_width,
- dso_width >= syme->map->dso->long_name_len ?
- syme->map->dso->long_name :
- syme->map->dso->short_name);
+ if (!unique_dso)
+ printf(" %-*.*s", dso_width, dso_width,
+ dso_width >= syme->map->dso->long_name_len ?
+ syme->map->dso->long_name :
+ syme->map->dso->short_name);
printf("\n");
}
}
--
1.6.2.5