aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2014-06-12 07:53:16 -0400
committerIngo Molnar <mingo@kernel.org>2014-06-12 07:53:16 -0400
commit94eb153130ce2c5f5f4959c96ea8197475bd66b6 (patch)
tree452c7fd4bd5d494d8b170fd5e840a5ae004e65ba /tools
parent82b897782d10fcc4930c9d4a15b175348fdd2871 (diff)
parent9b32ba71ba905b90610fc2aad77cb98a373c5624 (diff)
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core
Pull perf/core improvements and fixes from Jiri Olsa: * Bitmask handling and plugin updates (Steven Rostedt) * Fix pipe check regression in attr event callback (Jiri Olsa) * Prettify the tags/TAGS/cscope targets output (Jiri Olsa) * Print array argument as string (Namhyung Kim) * Pass protection and flags bits through mmap2 interface (Peter Zijlstra) * Update perf tool mmap2 interface with protection and flag bits (Don Zickus) * Re-enable mmap interface (Don Zickus) * Add mem-mode documentation to report command (Don Zickus) * Add sort on dcacheline (Don Zickus) Signed-off-by: Jiri Olsa <jolsa@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/event-parse.c113
-rw-r--r--tools/lib/traceevent/event-parse.h25
-rw-r--r--tools/lib/traceevent/event-plugin.c203
-rw-r--r--tools/lib/traceevent/plugin_function.c43
-rw-r--r--tools/perf/Documentation/perf-report.txt23
-rw-r--r--tools/perf/Makefile.perf6
-rw-r--r--tools/perf/builtin-inject.c2
-rw-r--r--tools/perf/perf.c1
-rw-r--r--tools/perf/tests/dwarf-unwind.c2
-rw-r--r--tools/perf/util/event.c57
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evsel.c1
-rw-r--r--tools/perf/util/hist.c9
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/machine.c4
-rw-r--r--tools/perf/util/map.c4
-rw-r--r--tools/perf/util/map.h4
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/sort.c107
-rw-r--r--tools/perf/util/sort.h2
-rw-r--r--tools/perf/util/util.c1
-rw-r--r--tools/perf/util/util.h1
23 files changed, 577 insertions, 37 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index b83184f2d484..93825a17dcce 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -765,6 +765,9 @@ static void free_arg(struct print_arg *arg)
765 case PRINT_BSTRING: 765 case PRINT_BSTRING:
766 free(arg->string.string); 766 free(arg->string.string);
767 break; 767 break;
768 case PRINT_BITMASK:
769 free(arg->bitmask.bitmask);
770 break;
768 case PRINT_DYNAMIC_ARRAY: 771 case PRINT_DYNAMIC_ARRAY:
769 free(arg->dynarray.index); 772 free(arg->dynarray.index);
770 break; 773 break;
@@ -2268,6 +2271,7 @@ static int arg_num_eval(struct print_arg *arg, long long *val)
2268 case PRINT_FIELD ... PRINT_SYMBOL: 2271 case PRINT_FIELD ... PRINT_SYMBOL:
2269 case PRINT_STRING: 2272 case PRINT_STRING:
2270 case PRINT_BSTRING: 2273 case PRINT_BSTRING:
2274 case PRINT_BITMASK:
2271 default: 2275 default:
2272 do_warning("invalid eval type %d", arg->type); 2276 do_warning("invalid eval type %d", arg->type);
2273 ret = 0; 2277 ret = 0;
@@ -2296,6 +2300,7 @@ static char *arg_eval (struct print_arg *arg)
2296 case PRINT_FIELD ... PRINT_SYMBOL: 2300 case PRINT_FIELD ... PRINT_SYMBOL:
2297 case PRINT_STRING: 2301 case PRINT_STRING:
2298 case PRINT_BSTRING: 2302 case PRINT_BSTRING:
2303 case PRINT_BITMASK:
2299 default: 2304 default:
2300 do_warning("invalid eval type %d", arg->type); 2305 do_warning("invalid eval type %d", arg->type);
2301 break; 2306 break;
@@ -2683,6 +2688,35 @@ process_str(struct event_format *event __maybe_unused, struct print_arg *arg,
2683 return EVENT_ERROR; 2688 return EVENT_ERROR;
2684} 2689}
2685 2690
2691static enum event_type
2692process_bitmask(struct event_format *event __maybe_unused, struct print_arg *arg,
2693 char **tok)
2694{
2695 enum event_type type;
2696 char *token;
2697
2698 if (read_expect_type(EVENT_ITEM, &token) < 0)
2699 goto out_free;
2700
2701 arg->type = PRINT_BITMASK;
2702 arg->bitmask.bitmask = token;
2703 arg->bitmask.offset = -1;
2704
2705 if (read_expected(EVENT_DELIM, ")") < 0)
2706 goto out_err;
2707
2708 type = read_token(&token);
2709 *tok = token;
2710
2711 return type;
2712
2713 out_free:
2714 free_token(token);
2715 out_err:
2716 *tok = NULL;
2717 return EVENT_ERROR;
2718}
2719
2686static struct pevent_function_handler * 2720static struct pevent_function_handler *
2687find_func_handler(struct pevent *pevent, char *func_name) 2721find_func_handler(struct pevent *pevent, char *func_name)
2688{ 2722{
@@ -2797,6 +2831,10 @@ process_function(struct event_format *event, struct print_arg *arg,
2797 free_token(token); 2831 free_token(token);
2798 return process_str(event, arg, tok); 2832 return process_str(event, arg, tok);
2799 } 2833 }
2834 if (strcmp(token, "__get_bitmask") == 0) {
2835 free_token(token);
2836 return process_bitmask(event, arg, tok);
2837 }
2800 if (strcmp(token, "__get_dynamic_array") == 0) { 2838 if (strcmp(token, "__get_dynamic_array") == 0) {
2801 free_token(token); 2839 free_token(token);
2802 return process_dynamic_array(event, arg, tok); 2840 return process_dynamic_array(event, arg, tok);
@@ -3324,6 +3362,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
3324 return eval_type(val, arg, 0); 3362 return eval_type(val, arg, 0);
3325 case PRINT_STRING: 3363 case PRINT_STRING:
3326 case PRINT_BSTRING: 3364 case PRINT_BSTRING:
3365 case PRINT_BITMASK:
3327 return 0; 3366 return 0;
3328 case PRINT_FUNC: { 3367 case PRINT_FUNC: {
3329 struct trace_seq s; 3368 struct trace_seq s;
@@ -3556,6 +3595,60 @@ static void print_str_to_seq(struct trace_seq *s, const char *format,
3556 trace_seq_printf(s, format, str); 3595 trace_seq_printf(s, format, str);
3557} 3596}
3558 3597
3598static void print_bitmask_to_seq(struct pevent *pevent,
3599 struct trace_seq *s, const char *format,
3600 int len_arg, const void *data, int size)
3601{
3602 int nr_bits = size * 8;
3603 int str_size = (nr_bits + 3) / 4;
3604 int len = 0;
3605 char buf[3];
3606 char *str;
3607 int index;
3608 int i;
3609
3610 /*
3611 * The kernel likes to put in commas every 32 bits, we
3612 * can do the same.
3613 */
3614 str_size += (nr_bits - 1) / 32;
3615
3616 str = malloc(str_size + 1);
3617 if (!str) {
3618 do_warning("%s: not enough memory!", __func__);
3619 return;
3620 }
3621 str[str_size] = 0;
3622
3623 /* Start out with -2 for the two chars per byte */
3624 for (i = str_size - 2; i >= 0; i -= 2) {
3625 /*
3626 * data points to a bit mask of size bytes.
3627 * In the kernel, this is an array of long words, thus
3628 * endianess is very important.
3629 */
3630 if (pevent->file_bigendian)
3631 index = size - (len + 1);
3632 else
3633 index = len;
3634
3635 snprintf(buf, 3, "%02x", *((unsigned char *)data + index));
3636 memcpy(str + i, buf, 2);
3637 len++;
3638 if (!(len & 3) && i > 0) {
3639 i--;
3640 str[i] = ',';
3641 }
3642 }
3643
3644 if (len_arg >= 0)
3645 trace_seq_printf(s, format, len_arg, str);
3646 else
3647 trace_seq_printf(s, format, str);
3648
3649 free(str);
3650}
3651
3559static void print_str_arg(struct trace_seq *s, void *data, int size, 3652static void print_str_arg(struct trace_seq *s, void *data, int size,
3560 struct event_format *event, const char *format, 3653 struct event_format *event, const char *format,
3561 int len_arg, struct print_arg *arg) 3654 int len_arg, struct print_arg *arg)
@@ -3691,6 +3784,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3691 case PRINT_BSTRING: 3784 case PRINT_BSTRING:
3692 print_str_to_seq(s, format, len_arg, arg->string.string); 3785 print_str_to_seq(s, format, len_arg, arg->string.string);
3693 break; 3786 break;
3787 case PRINT_BITMASK: {
3788 int bitmask_offset;
3789 int bitmask_size;
3790
3791 if (arg->bitmask.offset == -1) {
3792 struct format_field *f;
3793
3794 f = pevent_find_any_field(event, arg->bitmask.bitmask);
3795 arg->bitmask.offset = f->offset;
3796 }
3797 bitmask_offset = data2host4(pevent, data + arg->bitmask.offset);
3798 bitmask_size = bitmask_offset >> 16;
3799 bitmask_offset &= 0xffff;
3800 print_bitmask_to_seq(pevent, s, format, len_arg,
3801 data + bitmask_offset, bitmask_size);
3802 break;
3803 }
3694 case PRINT_OP: 3804 case PRINT_OP:
3695 /* 3805 /*
3696 * The only op for string should be ? : 3806 * The only op for string should be ? :
@@ -4822,6 +4932,9 @@ static void print_args(struct print_arg *args)
4822 case PRINT_BSTRING: 4932 case PRINT_BSTRING:
4823 printf("__get_str(%s)", args->string.string); 4933 printf("__get_str(%s)", args->string.string);
4824 break; 4934 break;
4935 case PRINT_BITMASK:
4936 printf("__get_bitmask(%s)", args->bitmask.bitmask);
4937 break;
4825 case PRINT_TYPE: 4938 case PRINT_TYPE:
4826 printf("(%s)", args->typecast.type); 4939 printf("(%s)", args->typecast.type);
4827 print_args(args->typecast.item); 4940 print_args(args->typecast.item);
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index feab94281634..7a3873ff9a4f 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -107,8 +107,8 @@ typedef int (*pevent_event_handler_func)(struct trace_seq *s,
107typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 107typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent); 108typedef int (*pevent_plugin_unload_func)(struct pevent *pevent);
109 109
110struct plugin_option { 110struct pevent_plugin_option {
111 struct plugin_option *next; 111 struct pevent_plugin_option *next;
112 void *handle; 112 void *handle;
113 char *file; 113 char *file;
114 char *name; 114 char *name;
@@ -135,7 +135,7 @@ struct plugin_option {
135 * PEVENT_PLUGIN_OPTIONS: (optional) 135 * PEVENT_PLUGIN_OPTIONS: (optional)
136 * Plugin options that can be set before loading 136 * Plugin options that can be set before loading
137 * 137 *
138 * struct plugin_option PEVENT_PLUGIN_OPTIONS[] = { 138 * struct pevent_plugin_option PEVENT_PLUGIN_OPTIONS[] = {
139 * { 139 * {
140 * .name = "option-name", 140 * .name = "option-name",
141 * .plugin_alias = "overide-file-name", (optional) 141 * .plugin_alias = "overide-file-name", (optional)
@@ -208,6 +208,11 @@ struct print_arg_string {
208 int offset; 208 int offset;
209}; 209};
210 210
211struct print_arg_bitmask {
212 char *bitmask;
213 int offset;
214};
215
211struct print_arg_field { 216struct print_arg_field {
212 char *name; 217 char *name;
213 struct format_field *field; 218 struct format_field *field;
@@ -274,6 +279,7 @@ enum print_arg_type {
274 PRINT_DYNAMIC_ARRAY, 279 PRINT_DYNAMIC_ARRAY,
275 PRINT_OP, 280 PRINT_OP,
276 PRINT_FUNC, 281 PRINT_FUNC,
282 PRINT_BITMASK,
277}; 283};
278 284
279struct print_arg { 285struct print_arg {
@@ -288,6 +294,7 @@ struct print_arg {
288 struct print_arg_hex hex; 294 struct print_arg_hex hex;
289 struct print_arg_func func; 295 struct print_arg_func func;
290 struct print_arg_string string; 296 struct print_arg_string string;
297 struct print_arg_bitmask bitmask;
291 struct print_arg_op op; 298 struct print_arg_op op;
292 struct print_arg_dynarray dynarray; 299 struct print_arg_dynarray dynarray;
293 }; 300 };
@@ -354,6 +361,8 @@ enum pevent_func_arg_type {
354 361
355enum pevent_flag { 362enum pevent_flag {
356 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */ 363 PEVENT_NSEC_OUTPUT = 1, /* output in NSECS */
364 PEVENT_DISABLE_SYS_PLUGINS = 1 << 1,
365 PEVENT_DISABLE_PLUGINS = 1 << 2,
357}; 366};
358 367
359#define PEVENT_ERRORS \ 368#define PEVENT_ERRORS \
@@ -410,9 +419,19 @@ enum pevent_errno {
410 419
411struct plugin_list; 420struct plugin_list;
412 421
422#define INVALID_PLUGIN_LIST_OPTION ((char **)((unsigned long)-1))
423
413struct plugin_list *traceevent_load_plugins(struct pevent *pevent); 424struct plugin_list *traceevent_load_plugins(struct pevent *pevent);
414void traceevent_unload_plugins(struct plugin_list *plugin_list, 425void traceevent_unload_plugins(struct plugin_list *plugin_list,
415 struct pevent *pevent); 426 struct pevent *pevent);
427char **traceevent_plugin_list_options(void);
428void traceevent_plugin_free_options_list(char **list);
429int traceevent_plugin_add_options(const char *name,
430 struct pevent_plugin_option *options);
431void traceevent_plugin_remove_options(struct pevent_plugin_option *options);
432void traceevent_print_plugins(struct trace_seq *s,
433 const char *prefix, const char *suffix,
434 const struct plugin_list *list);
416 435
417struct cmdline; 436struct cmdline;
418struct cmdline_list; 437struct cmdline_list;
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
index 0c8bf6780e4d..136162c03af1 100644
--- a/tools/lib/traceevent/event-plugin.c
+++ b/tools/lib/traceevent/event-plugin.c
@@ -18,6 +18,7 @@
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19 */ 19 */
20 20
21#include <stdio.h>
21#include <string.h> 22#include <string.h>
22#include <dlfcn.h> 23#include <dlfcn.h>
23#include <stdlib.h> 24#include <stdlib.h>
@@ -30,12 +31,207 @@
30 31
31#define LOCAL_PLUGIN_DIR ".traceevent/plugins" 32#define LOCAL_PLUGIN_DIR ".traceevent/plugins"
32 33
34static struct registered_plugin_options {
35 struct registered_plugin_options *next;
36 struct pevent_plugin_option *options;
37} *registered_options;
38
39static struct trace_plugin_options {
40 struct trace_plugin_options *next;
41 char *plugin;
42 char *option;
43 char *value;
44} *trace_plugin_options;
45
33struct plugin_list { 46struct plugin_list {
34 struct plugin_list *next; 47 struct plugin_list *next;
35 char *name; 48 char *name;
36 void *handle; 49 void *handle;
37}; 50};
38 51
52/**
53 * traceevent_plugin_list_options - get list of plugin options
54 *
55 * Returns an array of char strings that list the currently registered
56 * plugin options in the format of <plugin>:<option>. This list can be
57 * used by toggling the option.
58 *
59 * Returns NULL if there's no options registered. On error it returns
60 * INVALID_PLUGIN_LIST_OPTION
61 *
62 * Must be freed with traceevent_plugin_free_options_list().
63 */
64char **traceevent_plugin_list_options(void)
65{
66 struct registered_plugin_options *reg;
67 struct pevent_plugin_option *op;
68 char **list = NULL;
69 char *name;
70 int count = 0;
71
72 for (reg = registered_options; reg; reg = reg->next) {
73 for (op = reg->options; op->name; op++) {
74 char *alias = op->plugin_alias ? op->plugin_alias : op->file;
75 char **temp = list;
76
77 name = malloc(strlen(op->name) + strlen(alias) + 2);
78 if (!name)
79 goto err;
80
81 sprintf(name, "%s:%s", alias, op->name);
82 list = realloc(list, count + 2);
83 if (!list) {
84 list = temp;
85 free(name);
86 goto err;
87 }
88 list[count++] = name;
89 list[count] = NULL;
90 }
91 }
92 return list;
93
94 err:
95 while (--count >= 0)
96 free(list[count]);
97 free(list);
98
99 return INVALID_PLUGIN_LIST_OPTION;
100}
101
102void traceevent_plugin_free_options_list(char **list)
103{
104 int i;
105
106 if (!list)
107 return;
108
109 if (list == INVALID_PLUGIN_LIST_OPTION)
110 return;
111
112 for (i = 0; list[i]; i++)
113 free(list[i]);
114
115 free(list);
116}
117
118static int
119update_option(const char *file, struct pevent_plugin_option *option)
120{
121 struct trace_plugin_options *op;
122 char *plugin;
123
124 if (option->plugin_alias) {
125 plugin = strdup(option->plugin_alias);
126 if (!plugin)
127 return -1;
128 } else {
129 char *p;
130 plugin = strdup(file);
131 if (!plugin)
132 return -1;
133 p = strstr(plugin, ".");
134 if (p)
135 *p = '\0';
136 }
137
138 /* first look for named options */
139 for (op = trace_plugin_options; op; op = op->next) {
140 if (!op->plugin)
141 continue;
142 if (strcmp(op->plugin, plugin) != 0)
143 continue;
144 if (strcmp(op->option, option->name) != 0)
145 continue;
146
147 option->value = op->value;
148 option->set ^= 1;
149 goto out;
150 }
151
152 /* first look for unnamed options */
153 for (op = trace_plugin_options; op; op = op->next) {
154 if (op->plugin)
155 continue;
156 if (strcmp(op->option, option->name) != 0)
157 continue;
158
159 option->value = op->value;
160 option->set ^= 1;
161 break;
162 }
163
164 out:
165 free(plugin);
166 return 0;
167}
168
169/**
170 * traceevent_plugin_add_options - Add a set of options by a plugin
171 * @name: The name of the plugin adding the options
172 * @options: The set of options being loaded
173 *
174 * Sets the options with the values that have been added by user.
175 */
176int traceevent_plugin_add_options(const char *name,
177 struct pevent_plugin_option *options)
178{
179 struct registered_plugin_options *reg;
180
181 reg = malloc(sizeof(*reg));
182 if (!reg)
183 return -1;
184 reg->next = registered_options;
185 reg->options = options;
186 registered_options = reg;
187
188 while (options->name) {
189 update_option(name, options);
190 options++;
191 }
192 return 0;
193}
194
195/**
196 * traceevent_plugin_remove_options - remove plugin options that were registered
197 * @options: Options to removed that were registered with traceevent_plugin_add_options
198 */
199void traceevent_plugin_remove_options(struct pevent_plugin_option *options)
200{
201 struct registered_plugin_options **last;
202 struct registered_plugin_options *reg;
203
204 for (last = &registered_options; *last; last = &(*last)->next) {
205 if ((*last)->options == options) {
206 reg = *last;
207 *last = reg->next;
208 free(reg);
209 return;
210 }
211 }
212}
213
214/**
215 * traceevent_print_plugins - print out the list of plugins loaded
216 * @s: the trace_seq descripter to write to
217 * @prefix: The prefix string to add before listing the option name
218 * @suffix: The suffix string ot append after the option name
219 * @list: The list of plugins (usually returned by traceevent_load_plugins()
220 *
221 * Writes to the trace_seq @s the list of plugins (files) that is
222 * returned by traceevent_load_plugins(). Use @prefix and @suffix for formating:
223 * @prefix = " ", @suffix = "\n".
224 */
225void traceevent_print_plugins(struct trace_seq *s,
226 const char *prefix, const char *suffix,
227 const struct plugin_list *list)
228{
229 while (list) {
230 trace_seq_printf(s, "%s%s%s", prefix, list->name, suffix);
231 list = list->next;
232 }
233}
234
39static void 235static void
40load_plugin(struct pevent *pevent, const char *path, 236load_plugin(struct pevent *pevent, const char *path,
41 const char *file, void *data) 237 const char *file, void *data)
@@ -148,12 +344,17 @@ load_plugins(struct pevent *pevent, const char *suffix,
148 char *path; 344 char *path;
149 char *envdir; 345 char *envdir;
150 346
347 if (pevent->flags & PEVENT_DISABLE_PLUGINS)
348 return;
349
151 /* 350 /*
152 * If a system plugin directory was defined, 351 * If a system plugin directory was defined,
153 * check that first. 352 * check that first.
154 */ 353 */
155#ifdef PLUGIN_DIR 354#ifdef PLUGIN_DIR
156 load_plugins_dir(pevent, suffix, PLUGIN_DIR, load_plugin, data); 355 if (!(pevent->flags & PEVENT_DISABLE_SYS_PLUGINS))
356 load_plugins_dir(pevent, suffix, PLUGIN_DIR,
357 load_plugin, data);
157#endif 358#endif
158 359
159 /* 360 /*
diff --git a/tools/lib/traceevent/plugin_function.c b/tools/lib/traceevent/plugin_function.c
index 80ba4ff1fe84..a00ec190821a 100644
--- a/tools/lib/traceevent/plugin_function.c
+++ b/tools/lib/traceevent/plugin_function.c
@@ -33,6 +33,29 @@ static int cpus = -1;
33 33
34#define STK_BLK 10 34#define STK_BLK 10
35 35
36struct pevent_plugin_option plugin_options[] =
37{
38 {
39 .name = "parent",
40 .plugin_alias = "ftrace",
41 .description =
42 "Print parent of functions for function events",
43 },
44 {
45 .name = "indent",
46 .plugin_alias = "ftrace",
47 .description =
48 "Try to show function call indents, based on parents",
49 .set = 1,
50 },
51 {
52 .name = NULL,
53 }
54};
55
56static struct pevent_plugin_option *ftrace_parent = &plugin_options[0];
57static struct pevent_plugin_option *ftrace_indent = &plugin_options[1];
58
36static void add_child(struct func_stack *stack, const char *child, int pos) 59static void add_child(struct func_stack *stack, const char *child, int pos)
37{ 60{
38 int i; 61 int i;
@@ -119,7 +142,8 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
119 142
120 parent = pevent_find_function(pevent, pfunction); 143 parent = pevent_find_function(pevent, pfunction);
121 144
122 index = add_and_get_index(parent, func, record->cpu); 145 if (parent && ftrace_indent->set)
146 index = add_and_get_index(parent, func, record->cpu);
123 147
124 trace_seq_printf(s, "%*s", index*3, ""); 148 trace_seq_printf(s, "%*s", index*3, "");
125 149
@@ -128,11 +152,13 @@ static int function_handler(struct trace_seq *s, struct pevent_record *record,
128 else 152 else
129 trace_seq_printf(s, "0x%llx", function); 153 trace_seq_printf(s, "0x%llx", function);
130 154
131 trace_seq_printf(s, " <-- "); 155 if (ftrace_parent->set) {
132 if (parent) 156 trace_seq_printf(s, " <-- ");
133 trace_seq_printf(s, "%s", parent); 157 if (parent)
134 else 158 trace_seq_printf(s, "%s", parent);
135 trace_seq_printf(s, "0x%llx", pfunction); 159 else
160 trace_seq_printf(s, "0x%llx", pfunction);
161 }
136 162
137 return 0; 163 return 0;
138} 164}
@@ -141,6 +167,9 @@ int PEVENT_PLUGIN_LOADER(struct pevent *pevent)
141{ 167{
142 pevent_register_event_handler(pevent, -1, "ftrace", "function", 168 pevent_register_event_handler(pevent, -1, "ftrace", "function",
143 function_handler, NULL); 169 function_handler, NULL);
170
171 traceevent_plugin_add_options("ftrace", plugin_options);
172
144 return 0; 173 return 0;
145} 174}
146 175
@@ -157,6 +186,8 @@ void PEVENT_PLUGIN_UNLOADER(struct pevent *pevent)
157 free(fstack[i].stack); 186 free(fstack[i].stack);
158 } 187 }
159 188
189 traceevent_plugin_remove_options(plugin_options);
190
160 free(fstack); 191 free(fstack);
161 fstack = NULL; 192 fstack = NULL;
162 cpus = -1; 193 cpus = -1;
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index cefdf430d1b4..d2b59af62bc0 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,22 @@ OPTIONS
117 By default, every sort keys not specified in -F will be appended 117 By default, every sort keys not specified in -F will be appended
118 automatically. 118 automatically.
119 119
120 If --mem-mode option is used, following sort keys are also available
121 (incompatible with --branch-stack):
122 symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
123
124 - symbol_daddr: name of data symbol being executed on at the time of sample
125 - dso_daddr: name of library or module containing the data being executed
126 on at the time of sample
127 - locked: whether the bus was locked at the time of sample
128 - tlb: type of tlb access for the data at the time of sample
129 - mem: type of memory access for the data at the time of sample
130 - snoop: type of snoop (if any) for the data at the time of sample
131 - dcacheline: the cacheline the data address is on at the time of sample
132
133 And default sort keys are changed to local_weight, mem, sym, dso,
134 symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
135
120-p:: 136-p::
121--parent=<regex>:: 137--parent=<regex>::
122 A regex filter to identify parent. The parent is a caller of this 138 A regex filter to identify parent. The parent is a caller of this
@@ -260,6 +276,13 @@ OPTIONS
260 Demangle symbol names to human readable form. It's enabled by default, 276 Demangle symbol names to human readable form. It's enabled by default,
261 disable with --no-demangle. 277 disable with --no-demangle.
262 278
279--mem-mode::
280 Use the data addresses of samples in addition to instruction addresses
281 to build the histograms. To generate meaningful output, the perf.data
282 file must have been obtained using perf record -d -W and using a
283 special event -e cpu/mem-loads/ or -e cpu/mem-stores/. See
284 'perf mem' for simpler access.
285
263--percent-limit:: 286--percent-limit::
264 Do not show entries which have an overhead under that percent. 287 Do not show entries which have an overhead under that percent.
265 (Default: 0). 288 (Default: 0).
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index ae20edfcc3f7..9670a16fa577 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -819,15 +819,15 @@ TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol
819TAG_FILES= ../../include/uapi/linux/perf_event.h 819TAG_FILES= ../../include/uapi/linux/perf_event.h
820 820
821TAGS: 821TAGS:
822 $(RM) TAGS 822 $(QUIET_GEN)$(RM) TAGS; \
823 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES) 823 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs etags -a $(TAG_FILES)
824 824
825tags: 825tags:
826 $(RM) tags 826 $(QUIET_GEN)$(RM) tags; \
827 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES) 827 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs ctags -a $(TAG_FILES)
828 828
829cscope: 829cscope:
830 $(RM) cscope* 830 $(QUIET_GEN)$(RM) cscope*; \
831 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES) 831 $(FIND) $(TAG_FOLDERS) -name '*.[hcS]' -print | xargs cscope -b $(TAG_FILES)
832 832
833### Detect prefix changes 833### Detect prefix changes
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 6a3af0013d68..16c7c11ad06e 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -72,7 +72,7 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
72 if (ret) 72 if (ret)
73 return ret; 73 return ret;
74 74
75 if (&inject->output.is_pipe) 75 if (!inject->output.is_pipe)
76 return 0; 76 return 0;
77 77
78 return perf_event__repipe_synth(tool, event); 78 return perf_event__repipe_synth(tool, event);
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 78f7b920e548..95c58fc15284 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -458,6 +458,7 @@ int main(int argc, const char **argv)
458 458
459 /* The page_size is placed in util object. */ 459 /* The page_size is placed in util object. */
460 page_size = sysconf(_SC_PAGE_SIZE); 460 page_size = sysconf(_SC_PAGE_SIZE);
461 cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
461 462
462 cmd = perf_extract_argv0_path(argv[0]); 463 cmd = perf_extract_argv0_path(argv[0]);
463 if (!cmd) 464 if (!cmd)
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 108f0cd49f4e..96adb730b744 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -15,7 +15,7 @@ static int mmap_handler(struct perf_tool *tool __maybe_unused,
15 struct perf_sample *sample __maybe_unused, 15 struct perf_sample *sample __maybe_unused,
16 struct machine *machine) 16 struct machine *machine)
17{ 17{
18 return machine__process_mmap_event(machine, event, NULL); 18 return machine__process_mmap2_event(machine, event, NULL);
19} 19}
20 20
21static int init_live_machine(struct machine *machine) 21static int init_live_machine(struct machine *machine)
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 65795b835b39..d0281bdfa582 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,4 +1,5 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include <sys/mman.h>
2#include "event.h" 3#include "event.h"
3#include "debug.h" 4#include "debug.h"
4#include "hist.h" 5#include "hist.h"
@@ -178,13 +179,14 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
178 return -1; 179 return -1;
179 } 180 }
180 181
181 event->header.type = PERF_RECORD_MMAP; 182 event->header.type = PERF_RECORD_MMAP2;
182 183
183 while (1) { 184 while (1) {
184 char bf[BUFSIZ]; 185 char bf[BUFSIZ];
185 char prot[5]; 186 char prot[5];
186 char execname[PATH_MAX]; 187 char execname[PATH_MAX];
187 char anonstr[] = "//anon"; 188 char anonstr[] = "//anon";
189 unsigned int ino;
188 size_t size; 190 size_t size;
189 ssize_t n; 191 ssize_t n;
190 192
@@ -195,15 +197,20 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
195 strcpy(execname, ""); 197 strcpy(execname, "");
196 198
197 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 199 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
198 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n", 200 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
199 &event->mmap.start, &event->mmap.len, prot, 201 &event->mmap2.start, &event->mmap2.len, prot,
200 &event->mmap.pgoff, 202 &event->mmap2.pgoff, &event->mmap2.maj,
201 execname); 203 &event->mmap2.min,
204 &ino, execname);
205
202 /* 206 /*
203 * Anon maps don't have the execname. 207 * Anon maps don't have the execname.
204 */ 208 */
205 if (n < 4) 209 if (n < 7)
206 continue; 210 continue;
211
212 event->mmap2.ino = (u64)ino;
213
207 /* 214 /*
208 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 215 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
209 */ 216 */
@@ -212,6 +219,21 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
212 else 219 else
213 event->header.misc = PERF_RECORD_MISC_GUEST_USER; 220 event->header.misc = PERF_RECORD_MISC_GUEST_USER;
214 221
222 /* map protection and flags bits */
223 event->mmap2.prot = 0;
224 event->mmap2.flags = 0;
225 if (prot[0] == 'r')
226 event->mmap2.prot |= PROT_READ;
227 if (prot[1] == 'w')
228 event->mmap2.prot |= PROT_WRITE;
229 if (prot[2] == 'x')
230 event->mmap2.prot |= PROT_EXEC;
231
232 if (prot[3] == 's')
233 event->mmap2.flags |= MAP_SHARED;
234 else
235 event->mmap2.flags |= MAP_PRIVATE;
236
215 if (prot[2] != 'x') { 237 if (prot[2] != 'x') {
216 if (!mmap_data || prot[0] != 'r') 238 if (!mmap_data || prot[0] != 'r')
217 continue; 239 continue;
@@ -223,15 +245,15 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool,
223 strcpy(execname, anonstr); 245 strcpy(execname, anonstr);
224 246
225 size = strlen(execname) + 1; 247 size = strlen(execname) + 1;
226 memcpy(event->mmap.filename, execname, size); 248 memcpy(event->mmap2.filename, execname, size);
227 size = PERF_ALIGN(size, sizeof(u64)); 249 size = PERF_ALIGN(size, sizeof(u64));
228 event->mmap.len -= event->mmap.start; 250 event->mmap2.len -= event->mmap.start;
229 event->mmap.header.size = (sizeof(event->mmap) - 251 event->mmap2.header.size = (sizeof(event->mmap2) -
230 (sizeof(event->mmap.filename) - size)); 252 (sizeof(event->mmap2.filename) - size));
231 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 253 memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
232 event->mmap.header.size += machine->id_hdr_size; 254 event->mmap2.header.size += machine->id_hdr_size;
233 event->mmap.pid = tgid; 255 event->mmap2.pid = tgid;
234 event->mmap.tid = pid; 256 event->mmap2.tid = pid;
235 257
236 if (process(tool, event, &synth_sample, machine) != 0) { 258 if (process(tool, event, &synth_sample, machine) != 0) {
237 rc = -1; 259 rc = -1;
@@ -612,12 +634,15 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
612size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 634size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
613{ 635{
614 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 636 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
615 " %02x:%02x %"PRIu64" %"PRIu64"]: %c %s\n", 637 " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n",
616 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 638 event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
617 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 639 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
618 event->mmap2.min, event->mmap2.ino, 640 event->mmap2.min, event->mmap2.ino,
619 event->mmap2.ino_generation, 641 event->mmap2.ino_generation,
620 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 642 (event->mmap2.prot & PROT_READ) ? 'r' : '-',
643 (event->mmap2.prot & PROT_WRITE) ? 'w' : '-',
644 (event->mmap2.prot & PROT_EXEC) ? 'x' : '-',
645 (event->mmap2.flags & MAP_SHARED) ? 's' : 'p',
621 event->mmap2.filename); 646 event->mmap2.filename);
622} 647}
623 648
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index d970232cb270..9ba2eb3bdcfd 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -27,6 +27,8 @@ struct mmap2_event {
27 u32 min; 27 u32 min;
28 u64 ino; 28 u64 ino;
29 u64 ino_generation; 29 u64 ino_generation;
30 u32 prot;
31 u32 flags;
30 char filename[PATH_MAX]; 32 char filename[PATH_MAX];
31}; 33};
32 34
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5c28d82b76c4..21154dabc5fa 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -659,6 +659,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
659 perf_evsel__set_sample_bit(evsel, WEIGHT); 659 perf_evsel__set_sample_bit(evsel, WEIGHT);
660 660
661 attr->mmap = track; 661 attr->mmap = track;
662 attr->mmap2 = track && !perf_missing_features.mmap2;
662 attr->comm = track; 663 attr->comm = track;
663 664
664 if (opts->sample_transaction) 665 if (opts->sample_transaction)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 5a0a4b2cadc4..30df6187ee02 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -128,6 +128,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
128 + unresolved_col_width + 2; 128 + unresolved_col_width + 2;
129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
130 symlen); 130 symlen);
131 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
132 symlen + 1);
131 } else { 133 } else {
132 symlen = unresolved_col_width + 4 + 2; 134 symlen = unresolved_col_width + 4 + 2;
133 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
@@ -439,9 +441,10 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
439 .map = al->map, 441 .map = al->map,
440 .sym = al->sym, 442 .sym = al->sym,
441 }, 443 },
442 .cpu = al->cpu, 444 .cpu = al->cpu,
443 .ip = al->addr, 445 .cpumode = al->cpumode,
444 .level = al->level, 446 .ip = al->addr,
447 .level = al->level,
445 .stat = { 448 .stat = {
446 .nr_events = 1, 449 .nr_events = 1,
447 .period = period, 450 .period = period,
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index d2bf03575d5f..742f49a85725 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -72,6 +72,7 @@ enum hist_column {
72 HISTC_MEM_TLB, 72 HISTC_MEM_TLB,
73 HISTC_MEM_LVL, 73 HISTC_MEM_LVL,
74 HISTC_MEM_SNOOP, 74 HISTC_MEM_SNOOP,
75 HISTC_MEM_DCACHELINE,
75 HISTC_TRANSACTION, 76 HISTC_TRANSACTION,
76 HISTC_NR_COLS, /* Last entry */ 77 HISTC_NR_COLS, /* Last entry */
77}; 78};
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 7409ac8de51c..0e5fea95d596 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1060,6 +1060,8 @@ int machine__process_mmap2_event(struct machine *machine,
1060 event->mmap2.pid, event->mmap2.maj, 1060 event->mmap2.pid, event->mmap2.maj,
1061 event->mmap2.min, event->mmap2.ino, 1061 event->mmap2.min, event->mmap2.ino,
1062 event->mmap2.ino_generation, 1062 event->mmap2.ino_generation,
1063 event->mmap2.prot,
1064 event->mmap2.flags,
1063 event->mmap2.filename, type); 1065 event->mmap2.filename, type);
1064 1066
1065 if (map == NULL) 1067 if (map == NULL)
@@ -1105,7 +1107,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1105 1107
1106 map = map__new(&machine->user_dsos, event->mmap.start, 1108 map = map__new(&machine->user_dsos, event->mmap.start,
1107 event->mmap.len, event->mmap.pgoff, 1109 event->mmap.len, event->mmap.pgoff,
1108 event->mmap.pid, 0, 0, 0, 0, 1110 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1109 event->mmap.filename, 1111 event->mmap.filename,
1110 type); 1112 type);
1111 1113
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 8ccbb32eda25..25c571f4cba6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -138,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
138 138
139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
141 u64 ino_gen, char *filename, 141 u64 ino_gen, u32 prot, u32 flags, char *filename,
142 enum map_type type) 142 enum map_type type)
143{ 143{
144 struct map *map = malloc(sizeof(*map)); 144 struct map *map = malloc(sizeof(*map));
@@ -157,6 +157,8 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
157 map->min = d_min; 157 map->min = d_min;
158 map->ino = ino; 158 map->ino = ino;
159 map->ino_generation = ino_gen; 159 map->ino_generation = ino_gen;
160 map->prot = prot;
161 map->flags = flags;
160 162
161 if ((anon || no_dso) && type == MAP__FUNCTION) { 163 if ((anon || no_dso) && type == MAP__FUNCTION) {
162 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 164 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index ae2d45110588..7758c72522ef 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -35,6 +35,8 @@ struct map {
35 bool referenced; 35 bool referenced;
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u32 prot;
39 u32 flags;
38 u64 pgoff; 40 u64 pgoff;
39 u64 reloc; 41 u64 reloc;
40 u32 maj, min; /* only valid for MMAP2 record */ 42 u32 maj, min; /* only valid for MMAP2 record */
@@ -118,7 +120,7 @@ void map__init(struct map *map, enum map_type type,
118 u64 start, u64 end, u64 pgoff, struct dso *dso); 120 u64 start, u64 end, u64 pgoff, struct dso *dso);
119struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
120 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
121 u64 ino_gen, 123 u64 ino_gen, u32 prot, u32 flags,
122 char *filename, enum map_type type); 124 char *filename, enum map_type type);
123struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 125struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
124void map__delete(struct map *map); 126void map__delete(struct map *map);
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e108207c5de0..af7da565a750 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -215,6 +215,7 @@ static void define_event_symbols(struct event_format *event,
215 case PRINT_BSTRING: 215 case PRINT_BSTRING:
216 case PRINT_DYNAMIC_ARRAY: 216 case PRINT_DYNAMIC_ARRAY:
217 case PRINT_STRING: 217 case PRINT_STRING:
218 case PRINT_BITMASK:
218 break; 219 break;
219 case PRINT_TYPE: 220 case PRINT_TYPE:
220 define_event_symbols(event, ev_name, args->typecast.item); 221 define_event_symbols(event, ev_name, args->typecast.item);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index cd9774df3750..1c419321f707 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -197,6 +197,7 @@ static void define_event_symbols(struct event_format *event,
197 case PRINT_BSTRING: 197 case PRINT_BSTRING:
198 case PRINT_DYNAMIC_ARRAY: 198 case PRINT_DYNAMIC_ARRAY:
199 case PRINT_FUNC: 199 case PRINT_FUNC:
200 case PRINT_BITMASK:
200 /* we should warn... */ 201 /* we should warn... */
201 return; 202 return;
202 } 203 }
@@ -622,6 +623,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
622 fprintf(ofp, "%s=", f->name); 623 fprintf(ofp, "%s=", f->name);
623 if (f->flags & FIELD_IS_STRING || 624 if (f->flags & FIELD_IS_STRING ||
624 f->flags & FIELD_IS_FLAG || 625 f->flags & FIELD_IS_FLAG ||
626 f->flags & FIELD_IS_ARRAY ||
625 f->flags & FIELD_IS_SYMBOLIC) 627 f->flags & FIELD_IS_SYMBOLIC)
626 fprintf(ofp, "%%s"); 628 fprintf(ofp, "%%s");
627 else if (f->flags & FIELD_IS_SIGNED) 629 else if (f->flags & FIELD_IS_SIGNED)
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 45512baaab67..1ec57dd82284 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,3 +1,4 @@
1#include <sys/mman.h>
1#include "sort.h" 2#include "sort.h"
2#include "hist.h" 3#include "hist.h"
3#include "comm.h" 4#include "comm.h"
@@ -784,6 +785,104 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
784 return repsep_snprintf(bf, size, "%-*s", width, out); 785 return repsep_snprintf(bf, size, "%-*s", width, out);
785} 786}
786 787
788static inline u64 cl_address(u64 address)
789{
790 /* return the cacheline of the address */
791 return (address & ~(cacheline_size - 1));
792}
793
794static int64_t
795sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
796{
797 u64 l, r;
798 struct map *l_map, *r_map;
799
800 if (!left->mem_info) return -1;
801 if (!right->mem_info) return 1;
802
803 /* group event types together */
804 if (left->cpumode > right->cpumode) return -1;
805 if (left->cpumode < right->cpumode) return 1;
806
807 l_map = left->mem_info->daddr.map;
808 r_map = right->mem_info->daddr.map;
809
810 /* if both are NULL, jump to sort on al_addr instead */
811 if (!l_map && !r_map)
812 goto addr;
813
814 if (!l_map) return -1;
815 if (!r_map) return 1;
816
817 if (l_map->maj > r_map->maj) return -1;
818 if (l_map->maj < r_map->maj) return 1;
819
820 if (l_map->min > r_map->min) return -1;
821 if (l_map->min < r_map->min) return 1;
822
823 if (l_map->ino > r_map->ino) return -1;
824 if (l_map->ino < r_map->ino) return 1;
825
826 if (l_map->ino_generation > r_map->ino_generation) return -1;
827 if (l_map->ino_generation < r_map->ino_generation) return 1;
828
829 /*
830 * Addresses with no major/minor numbers are assumed to be
831 * anonymous in userspace. Sort those on pid then address.
832 *
833 * The kernel and non-zero major/minor mapped areas are
834 * assumed to be unity mapped. Sort those on address.
835 */
836
837 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
838 (!(l_map->flags & MAP_SHARED)) &&
839 !l_map->maj && !l_map->min && !l_map->ino &&
840 !l_map->ino_generation) {
841 /* userspace anonymous */
842
843 if (left->thread->pid_ > right->thread->pid_) return -1;
844 if (left->thread->pid_ < right->thread->pid_) return 1;
845 }
846
847addr:
848 /* al_addr does all the right addr - start + offset calculations */
849 l = cl_address(left->mem_info->daddr.al_addr);
850 r = cl_address(right->mem_info->daddr.al_addr);
851
852 if (l > r) return -1;
853 if (l < r) return 1;
854
855 return 0;
856}
857
858static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
859 size_t size, unsigned int width)
860{
861
862 uint64_t addr = 0;
863 struct map *map = NULL;
864 struct symbol *sym = NULL;
865 char level = he->level;
866
867 if (he->mem_info) {
868 addr = cl_address(he->mem_info->daddr.al_addr);
869 map = he->mem_info->daddr.map;
870 sym = he->mem_info->daddr.sym;
871
872 /* print [s] for shared data mmaps */
873 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
874 map && (map->type == MAP__VARIABLE) &&
875 (map->flags & MAP_SHARED) &&
876 (map->maj || map->min || map->ino ||
877 map->ino_generation))
878 level = 's';
879 else if (!map)
880 level = 'X';
881 }
882 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
883 width);
884}
885
787struct sort_entry sort_mispredict = { 886struct sort_entry sort_mispredict = {
788 .se_header = "Branch Mispredicted", 887 .se_header = "Branch Mispredicted",
789 .se_cmp = sort__mispredict_cmp, 888 .se_cmp = sort__mispredict_cmp,
@@ -876,6 +975,13 @@ struct sort_entry sort_mem_snoop = {
876 .se_width_idx = HISTC_MEM_SNOOP, 975 .se_width_idx = HISTC_MEM_SNOOP,
877}; 976};
878 977
978struct sort_entry sort_mem_dcacheline = {
979 .se_header = "Data Cacheline",
980 .se_cmp = sort__dcacheline_cmp,
981 .se_snprintf = hist_entry__dcacheline_snprintf,
982 .se_width_idx = HISTC_MEM_DCACHELINE,
983};
984
879static int64_t 985static int64_t
880sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
881{ 987{
@@ -1043,6 +1149,7 @@ static struct sort_dimension memory_sort_dimensions[] = {
1043 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1044 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1045 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1151 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1152 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1046}; 1153};
1047 1154
1048#undef DIM 1155#undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 5bf0098d6b06..041f0c9cea2b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -89,6 +89,7 @@ struct hist_entry {
89 u64 ip; 89 u64 ip;
90 u64 transaction; 90 u64 transaction;
91 s32 cpu; 91 s32 cpu;
92 u8 cpumode;
92 93
93 struct hist_entry_diff diff; 94 struct hist_entry_diff diff;
94 95
@@ -185,6 +186,7 @@ enum sort_type {
185 SORT_MEM_TLB, 186 SORT_MEM_TLB,
186 SORT_MEM_LVL, 187 SORT_MEM_LVL,
187 SORT_MEM_SNOOP, 188 SORT_MEM_SNOOP,
189 SORT_MEM_DCACHELINE,
188}; 190};
189 191
190/* 192/*
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 7fff6be07f07..95aefa78bb07 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -17,6 +17,7 @@
17 * XXX We need to find a better place for these things... 17 * XXX We need to find a better place for these things...
18 */ 18 */
19unsigned int page_size; 19unsigned int page_size;
20int cacheline_size;
20 21
21bool test_attr__enabled; 22bool test_attr__enabled;
22 23
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b03da44e94e4..66864364ccb4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -304,6 +304,7 @@ char *rtrim(char *s);
304void dump_stack(void); 304void dump_stack(void);
305 305
306extern unsigned int page_size; 306extern unsigned int page_size;
307extern int cacheline_size;
307 308
308void get_term_dimensions(struct winsize *ws); 309void get_term_dimensions(struct winsize *ws);
309 310