aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2015-11-24 03:07:28 -0500
committerIngo Molnar <mingo@kernel.org>2015-11-24 03:07:28 -0500
commit9327ca73474225e5d6f1f96807a90f359124118f (patch)
treef25e0882c41f219103dd7e2fc5d8d1de05224240 /tools/perf
parentb7883a1c4f75edb62fc49da6000c59fb881e3c7b (diff)
parent646a6e846c4dc3812c614fd061603b6db5b8d380 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Allow callchain order (caller, callee) to the libdw and libunwind based DWARF unwinders (Jiri Olsa) - Add missing parent_val initialization in the callchain code, fixing a SEGFAULT when using callchains with 'perf top' (Jiri Olsa) - Add initial 'perf config' command, for now just with a --list command to the contents of the configuration file in use and a basic man page describing its format, commands for doing edits and detailed documentation are being reviewed and proof-read. (Taeung Song) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Build1
-rw-r--r--tools/perf/Documentation/perf-config.txt103
-rw-r--r--tools/perf/builtin-config.c66
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt1
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/tests/dwarf-unwind.c22
-rw-r--r--tools/perf/util/callchain.h1
-rw-r--r--tools/perf/util/unwind-libdw.c53
-rw-r--r--tools/perf/util/unwind-libdw.h2
-rw-r--r--tools/perf/util/unwind-libunwind.c60
11 files changed, 272 insertions, 39 deletions
diff --git a/tools/perf/Build b/tools/perf/Build
index 72237455b400..2c7aaf2ba119 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -1,5 +1,6 @@
1perf-y += builtin-bench.o 1perf-y += builtin-bench.o
2perf-y += builtin-annotate.o 2perf-y += builtin-annotate.o
3perf-y += builtin-config.o
3perf-y += builtin-diff.o 4perf-y += builtin-diff.o
4perf-y += builtin-evlist.o 5perf-y += builtin-evlist.o
5perf-y += builtin-help.o 6perf-y += builtin-help.o
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
new file mode 100644
index 000000000000..b9ca1e304158
--- /dev/null
+++ b/tools/perf/Documentation/perf-config.txt
@@ -0,0 +1,103 @@
1perf-config(1)
2==============
3
4NAME
5----
6perf-config - Get and set variables in a configuration file.
7
8SYNOPSIS
9--------
10[verse]
11'perf config' -l | --list
12
13DESCRIPTION
14-----------
15You can manage variables in a configuration file with this command.
16
17OPTIONS
18-------
19
20-l::
21--list::
22 Show current config variables, name and value, for all sections.
23
24CONFIGURATION FILE
25------------------
26
27The perf configuration file contains many variables to change various
28aspects of each of its tools, including output, disk usage, etc.
29The '$HOME/.perfconfig' file is used to store a per-user configuration.
30The file '$(sysconfdir)/perfconfig' can be used to
31store a system-wide default configuration.
32
33Syntax
34~~~~~~
35
36The file consist of sections. A section starts with its name
37surrounded by square brackets and continues till the next section
38begins. Each variable must be in a section, and have the form
39'name = value', for example:
40
41 [section]
42 name1 = value1
43 name2 = value2
44
45Section names are case sensitive and can contain any characters except
46newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
47respectively). Section headers can't span multiple lines.
48
49Example
50~~~~~~~
51
52Given a $HOME/.perfconfig like this:
53
54#
55# This is the config file, and
56# a '#' and ';' character indicates a comment
57#
58
59 [colors]
60 # Color variables
61 top = red, default
62 medium = green, default
63 normal = lightgray, default
64 selected = white, lightgray
65 code = blue, default
66 addr = magenta, default
67 root = white, blue
68
69 [tui]
70 # Defaults if linked with libslang
71 report = on
72 annotate = on
73 top = on
74
75 [buildid]
76 # Default, disable using /dev/null
77 dir = ~/.debug
78
79 [annotate]
80 # Defaults
81 hide_src_code = false
82 use_offset = true
83 jump_arrows = true
84 show_nr_jumps = false
85
86 [help]
87 # Format can be man, info, web or html
88 format = man
89 autocorrect = 0
90
91 [ui]
92 show-headers = true
93
94 [call-graph]
95 # fp (framepointer), dwarf
96 record-mode = fp
97 print-type = graph
98 order = caller
99 sort-key = function
100
101SEE ALSO
102--------
103linkperf:perf[1]
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644
index 000000000000..427ea7a705b8
--- /dev/null
+++ b/tools/perf/builtin-config.c
@@ -0,0 +1,66 @@
1/*
2 * builtin-config.c
3 *
4 * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
5 *
6 */
7#include "builtin.h"
8
9#include "perf.h"
10
11#include "util/cache.h"
12#include "util/parse-options.h"
13#include "util/util.h"
14#include "util/debug.h"
15
16static const char * const config_usage[] = {
17 "perf config [options]",
18 NULL
19};
20
21enum actions {
22 ACTION_LIST = 1
23} actions;
24
25static struct option config_options[] = {
26 OPT_SET_UINT('l', "list", &actions,
27 "show current config variables", ACTION_LIST),
28 OPT_END()
29};
30
31static int show_config(const char *key, const char *value,
32 void *cb __maybe_unused)
33{
34 if (value)
35 printf("%s=%s\n", key, value);
36 else
37 printf("%s\n", key);
38
39 return 0;
40}
41
42int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
43{
44 int ret = 0;
45
46 argc = parse_options(argc, argv, config_options, config_usage,
47 PARSE_OPT_STOP_AT_NON_OPTION);
48
49 switch (actions) {
50 case ACTION_LIST:
51 if (argc) {
52 pr_err("Error: takes no arguments\n");
53 parse_options_usage(config_usage, config_options, "l", 1);
54 } else {
55 ret = perf_config(show_config, NULL);
56 if (ret < 0)
57 pr_err("Nothing configured, "
58 "please check your ~/.perfconfig file\n");
59 }
60 break;
61 default:
62 usage_with_options(config_usage, config_options);
63 }
64
65 return ret;
66}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3688ad29085f..3f871b54e261 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -17,6 +17,7 @@ extern int cmd_annotate(int argc, const char **argv, const char *prefix);
17extern int cmd_bench(int argc, const char **argv, const char *prefix); 17extern int cmd_bench(int argc, const char **argv, const char *prefix);
18extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix); 18extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix); 19extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
20extern int cmd_config(int argc, const char **argv, const char *prefix);
20extern int cmd_diff(int argc, const char **argv, const char *prefix); 21extern int cmd_diff(int argc, const char **argv, const char *prefix);
21extern int cmd_evlist(int argc, const char **argv, const char *prefix); 22extern int cmd_evlist(int argc, const char **argv, const char *prefix);
22extern int cmd_help(int argc, const char **argv, const char *prefix); 23extern int cmd_help(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00fcaf8a5b8d..acc3ea7d90b7 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
9perf-buildid-list mainporcelain common 9perf-buildid-list mainporcelain common
10perf-data mainporcelain common 10perf-data mainporcelain common
11perf-diff mainporcelain common 11perf-diff mainporcelain common
12perf-config mainporcelain common
12perf-evlist mainporcelain common 13perf-evlist mainporcelain common
13perf-inject mainporcelain common 14perf-inject mainporcelain common
14perf-kmem mainporcelain common 15perf-kmem mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 3d4c7c09adea..4bee53c3f796 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -39,6 +39,7 @@ struct cmd_struct {
39static struct cmd_struct commands[] = { 39static struct cmd_struct commands[] = {
40 { "buildid-cache", cmd_buildid_cache, 0 }, 40 { "buildid-cache", cmd_buildid_cache, 0 },
41 { "buildid-list", cmd_buildid_list, 0 }, 41 { "buildid-list", cmd_buildid_list, 0 },
42 { "config", cmd_config, 0 },
42 { "diff", cmd_diff, 0 }, 43 { "diff", cmd_diff, 0 },
43 { "evlist", cmd_evlist, 0 }, 44 { "evlist", cmd_evlist, 0 },
44 { "help", cmd_help, 0 }, 45 { "help", cmd_help, 0 },
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 01f0b61de53d..b2357e8115a2 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -51,6 +51,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
51 "krava_1", 51 "krava_1",
52 "test__dwarf_unwind" 52 "test__dwarf_unwind"
53 }; 53 };
54 /*
55 * The funcs[MAX_STACK] array index, based on the
56 * callchain order setup.
57 */
58 int idx = callchain_param.order == ORDER_CALLER ?
59 MAX_STACK - *cnt - 1 : *cnt;
54 60
55 if (*cnt >= MAX_STACK) { 61 if (*cnt >= MAX_STACK) {
56 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK); 62 pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
@@ -63,8 +69,10 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
63 return -1; 69 return -1;
64 } 70 }
65 71
66 pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip); 72 (*cnt)++;
67 return strcmp((const char *) symbol, funcs[(*cnt)++]); 73 pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
74 symbol, entry->ip, funcs[idx]);
75 return strcmp((const char *) symbol, funcs[idx]);
68} 76}
69 77
70__attribute__ ((noinline)) 78__attribute__ ((noinline))
@@ -105,8 +113,16 @@ static int compare(void *p1, void *p2)
105 /* Any possible value should be 'thread' */ 113 /* Any possible value should be 'thread' */
106 struct thread *thread = *(struct thread **)p1; 114 struct thread *thread = *(struct thread **)p1;
107 115
108 if (global_unwind_retval == -INT_MAX) 116 if (global_unwind_retval == -INT_MAX) {
117 /* Call unwinder twice for both callchain orders. */
118 callchain_param.order = ORDER_CALLER;
119
109 global_unwind_retval = unwind_thread(thread); 120 global_unwind_retval = unwind_thread(thread);
121 if (!global_unwind_retval) {
122 callchain_param.order = ORDER_CALLEE;
123 global_unwind_retval = unwind_thread(thread);
124 }
125 }
110 126
111 return p1 - p2; 127 return p1 - p2;
112} 128}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 6e9b5f2099e1..8ac8f043004c 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -143,6 +143,7 @@ extern __thread struct callchain_cursor callchain_cursor;
143static inline void callchain_init(struct callchain_root *root) 143static inline void callchain_init(struct callchain_root *root)
144{ 144{
145 INIT_LIST_HEAD(&root->node.val); 145 INIT_LIST_HEAD(&root->node.val);
146 INIT_LIST_HEAD(&root->node.parent_val);
146 147
147 root->node.parent = NULL; 148 root->node.parent = NULL;
148 root->node.hit = 0; 149 root->node.hit = 0;
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 2dcfe9a7c8d0..db8142ba7cb9 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -11,6 +11,7 @@
11#include <linux/types.h> 11#include <linux/types.h>
12#include "event.h" 12#include "event.h"
13#include "perf_regs.h" 13#include "perf_regs.h"
14#include "callchain.h"
14 15
15static char *debuginfo_path; 16static char *debuginfo_path;
16 17
@@ -52,25 +53,28 @@ static int report_module(u64 ip, struct unwind_info *ui)
52 return __report_module(&al, ip, ui); 53 return __report_module(&al, ip, ui);
53} 54}
54 55
56/*
57 * Store all entries within entries array,
58 * we will process it after we finish unwind.
59 */
55static int entry(u64 ip, struct unwind_info *ui) 60static int entry(u64 ip, struct unwind_info *ui)
56 61
57{ 62{
58 struct unwind_entry e; 63 struct unwind_entry *e = &ui->entries[ui->idx++];
59 struct addr_location al; 64 struct addr_location al;
60 65
61 if (__report_module(&al, ip, ui)) 66 if (__report_module(&al, ip, ui))
62 return -1; 67 return -1;
63 68
64 e.ip = ip; 69 e->ip = ip;
65 e.map = al.map; 70 e->map = al.map;
66 e.sym = al.sym; 71 e->sym = al.sym;
67 72
68 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n", 73 pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
69 al.sym ? al.sym->name : "''", 74 al.sym ? al.sym->name : "''",
70 ip, 75 ip,
71 al.map ? al.map->map_ip(al.map, ip) : (u64) 0); 76 al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
72 77 return 0;
73 return ui->cb(&e, ui->arg);
74} 78}
75 79
76static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp) 80static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
@@ -168,7 +172,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
168 struct perf_sample *data, 172 struct perf_sample *data,
169 int max_stack) 173 int max_stack)
170{ 174{
171 struct unwind_info ui = { 175 struct unwind_info *ui, ui_buf = {
172 .sample = data, 176 .sample = data,
173 .thread = thread, 177 .thread = thread,
174 .machine = thread->mg->machine, 178 .machine = thread->mg->machine,
@@ -177,35 +181,54 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
177 .max_stack = max_stack, 181 .max_stack = max_stack,
178 }; 182 };
179 Dwarf_Word ip; 183 Dwarf_Word ip;
180 int err = -EINVAL; 184 int err = -EINVAL, i;
181 185
182 if (!data->user_regs.regs) 186 if (!data->user_regs.regs)
183 return -EINVAL; 187 return -EINVAL;
184 188
185 ui.dwfl = dwfl_begin(&offline_callbacks); 189 ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
186 if (!ui.dwfl) 190 if (!ui)
191 return -ENOMEM;
192
193 *ui = ui_buf;
194
195 ui->dwfl = dwfl_begin(&offline_callbacks);
196 if (!ui->dwfl)
187 goto out; 197 goto out;
188 198
189 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); 199 err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
190 if (err) 200 if (err)
191 goto out; 201 goto out;
192 202
193 err = report_module(ip, &ui); 203 err = report_module(ip, ui);
194 if (err) 204 if (err)
195 goto out; 205 goto out;
196 206
197 if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui)) 207 if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui))
198 goto out; 208 goto out;
199 209
200 err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui); 210 err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
201 211
202 if (err && !ui.max_stack) 212 if (err && !ui->max_stack)
203 err = 0; 213 err = 0;
204 214
215 /*
216 * Display what we got based on the order setup.
217 */
218 for (i = 0; i < ui->idx && !err; i++) {
219 int j = i;
220
221 if (callchain_param.order == ORDER_CALLER)
222 j = ui->idx - i - 1;
223
224 err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
225 }
226
205 out: 227 out:
206 if (err) 228 if (err)
207 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1)); 229 pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
208 230
209 dwfl_end(ui.dwfl); 231 dwfl_end(ui->dwfl);
232 free(ui);
210 return 0; 233 return 0;
211} 234}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 417a1426f3ad..58328669ed16 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -16,6 +16,8 @@ struct unwind_info {
16 unwind_entry_cb_t cb; 16 unwind_entry_cb_t cb;
17 void *arg; 17 void *arg;
18 int max_stack; 18 int max_stack;
19 int idx;
20 struct unwind_entry entries[];
19}; 21};
20 22
21#endif /* __PERF_UNWIND_LIBDW_H */ 23#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index c83832b555e5..3c258a0e4092 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -614,23 +614,48 @@ void unwind__finish_access(struct thread *thread)
614static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, 614static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
615 void *arg, int max_stack) 615 void *arg, int max_stack)
616{ 616{
617 u64 val;
618 unw_word_t ips[max_stack];
617 unw_addr_space_t addr_space; 619 unw_addr_space_t addr_space;
618 unw_cursor_t c; 620 unw_cursor_t c;
619 int ret; 621 int ret, i = 0;
620
621 addr_space = thread__priv(ui->thread);
622 if (addr_space == NULL)
623 return -1;
624 622
625 ret = unw_init_remote(&c, addr_space, ui); 623 ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
626 if (ret) 624 if (ret)
627 display_error(ret); 625 return ret;
628 626
629 while (!ret && (unw_step(&c) > 0) && max_stack--) { 627 ips[i++] = (unw_word_t) val;
630 unw_word_t ip;
631 628
632 unw_get_reg(&c, UNW_REG_IP, &ip); 629 /*
633 ret = ip ? entry(ip, ui->thread, cb, arg) : 0; 630 * If we need more than one entry, do the DWARF
631 * unwind itself.
632 */
633 if (max_stack - 1 > 0) {
634 addr_space = thread__priv(ui->thread);
635 if (addr_space == NULL)
636 return -1;
637
638 ret = unw_init_remote(&c, addr_space, ui);
639 if (ret)
640 display_error(ret);
641
642 while (!ret && (unw_step(&c) > 0) && i < max_stack) {
643 unw_get_reg(&c, UNW_REG_IP, &ips[i]);
644 ++i;
645 }
646
647 max_stack = i;
648 }
649
650 /*
651 * Display what we got based on the order setup.
652 */
653 for (i = 0; i < max_stack && !ret; i++) {
654 int j = i;
655
656 if (callchain_param.order == ORDER_CALLER)
657 j = max_stack - i - 1;
658 ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
634 } 659 }
635 660
636 return ret; 661 return ret;
@@ -640,24 +665,17 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
640 struct thread *thread, 665 struct thread *thread,
641 struct perf_sample *data, int max_stack) 666 struct perf_sample *data, int max_stack)
642{ 667{
643 u64 ip;
644 struct unwind_info ui = { 668 struct unwind_info ui = {
645 .sample = data, 669 .sample = data,
646 .thread = thread, 670 .thread = thread,
647 .machine = thread->mg->machine, 671 .machine = thread->mg->machine,
648 }; 672 };
649 int ret;
650 673
651 if (!data->user_regs.regs) 674 if (!data->user_regs.regs)
652 return -EINVAL; 675 return -EINVAL;
653 676
654 ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP); 677 if (max_stack <= 0)
655 if (ret) 678 return -EINVAL;
656 return ret;
657
658 ret = entry(ip, thread, cb, arg);
659 if (ret)
660 return -ENOMEM;
661 679
662 return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0; 680 return get_entries(&ui, cb, arg, max_stack);
663} 681}