aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/annotate.h2
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/build-id.h2
-rw-r--r--tools/perf/util/callchain.c123
-rw-r--r--tools/perf/util/callchain.h19
-rw-r--r--tools/perf/util/config.c4
-rw-r--r--tools/perf/util/cpumap.c160
-rw-r--r--tools/perf/util/cpumap.h35
-rw-r--r--tools/perf/util/dso.c279
-rw-r--r--tools/perf/util/dso.h52
-rw-r--r--tools/perf/util/dwarf-aux.c7
-rw-r--r--tools/perf/util/event.c61
-rw-r--r--tools/perf/util/event.h31
-rw-r--r--tools/perf/util/evsel.c5
-rw-r--r--tools/perf/util/evsel.h9
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/hist.c677
-rw-r--r--tools/perf/util/hist.h102
-rw-r--r--tools/perf/util/include/linux/bitmap.h3
-rw-r--r--tools/perf/util/include/linux/export.h6
-rw-r--r--tools/perf/util/include/linux/list.h1
-rw-r--r--tools/perf/util/include/linux/types.h29
-rw-r--r--tools/perf/util/machine.c69
-rw-r--r--tools/perf/util/map.c122
-rw-r--r--tools/perf/util/map.h18
-rw-r--r--tools/perf/util/pager.c12
-rw-r--r--tools/perf/util/parse-events.h3
-rw-r--r--tools/perf/util/parse-events.y14
-rw-r--r--tools/perf/util/perf_regs.c10
-rw-r--r--tools/perf/util/perf_regs.h6
-rw-r--r--tools/perf/util/pmu.c6
-rw-r--r--tools/perf/util/pmu.h2
-rw-r--r--tools/perf/util/probe-event.c13
-rw-r--r--tools/perf/util/probe-finder.c15
-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/session.c5
-rw-r--r--tools/perf/util/sort.c630
-rw-r--r--tools/perf/util/sort.h28
-rw-r--r--tools/perf/util/stat.h2
-rw-r--r--tools/perf/util/svghelper.c2
-rw-r--r--tools/perf/util/svghelper.h2
-rw-r--r--tools/perf/util/symbol.c11
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/thread.c52
-rw-r--r--tools/perf/util/thread.h3
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/types.h24
-rw-r--r--tools/perf/util/unwind-libdw.c2
-rw-r--r--tools/perf/util/unwind-libunwind.c2
-rw-r--r--tools/perf/util/unwind.h2
-rw-r--r--tools/perf/util/util.c3
-rw-r--r--tools/perf/util/util.h3
-rw-r--r--tools/perf/util/values.h2
54 files changed, 2311 insertions, 375 deletions
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 56ad4f5287de..112d6e268150 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -3,7 +3,7 @@
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h> 5#include <stdint.h>
6#include "types.h" 6#include <linux/types.h>
7#include "symbol.h" 7#include "symbol.h"
8#include "hist.h" 8#include "hist.h"
9#include "sort.h" 9#include "sort.h"
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index 6baabe63182b..a904a4cfe7d3 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -25,7 +25,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
25 struct addr_location al; 25 struct addr_location al;
26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 26 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
27 struct thread *thread = machine__findnew_thread(machine, sample->pid, 27 struct thread *thread = machine__findnew_thread(machine, sample->pid,
28 sample->pid); 28 sample->tid);
29 29
30 if (thread == NULL) { 30 if (thread == NULL) {
31 pr_err("problem processing %d event, skipping it.\n", 31 pr_err("problem processing %d event, skipping it.\n",
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index 845ef865eced..ae392561470b 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -4,7 +4,7 @@
4#define BUILD_ID_SIZE 20 4#define BUILD_ID_SIZE 20
5 5
6#include "tool.h" 6#include "tool.h"
7#include "types.h" 7#include <linux/types.h>
8 8
9extern struct perf_tool build_id__mark_dso_hit_ops; 9extern struct perf_tool build_id__mark_dso_hit_ops;
10struct dso; 10struct dso;
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 8d9db454f1a9..48b6d3f50012 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -25,6 +25,84 @@
25 25
26__thread struct callchain_cursor callchain_cursor; 26__thread struct callchain_cursor callchain_cursor;
27 27
28int
29parse_callchain_report_opt(const char *arg)
30{
31 char *tok, *tok2;
32 char *endptr;
33
34 symbol_conf.use_callchain = true;
35
36 if (!arg)
37 return 0;
38
39 tok = strtok((char *)arg, ",");
40 if (!tok)
41 return -1;
42
43 /* get the output mode */
44 if (!strncmp(tok, "graph", strlen(arg))) {
45 callchain_param.mode = CHAIN_GRAPH_ABS;
46
47 } else if (!strncmp(tok, "flat", strlen(arg))) {
48 callchain_param.mode = CHAIN_FLAT;
49 } else if (!strncmp(tok, "fractal", strlen(arg))) {
50 callchain_param.mode = CHAIN_GRAPH_REL;
51 } else if (!strncmp(tok, "none", strlen(arg))) {
52 callchain_param.mode = CHAIN_NONE;
53 symbol_conf.use_callchain = false;
54 return 0;
55 } else {
56 return -1;
57 }
58
59 /* get the min percentage */
60 tok = strtok(NULL, ",");
61 if (!tok)
62 goto setup;
63
64 callchain_param.min_percent = strtod(tok, &endptr);
65 if (tok == endptr)
66 return -1;
67
68 /* get the print limit */
69 tok2 = strtok(NULL, ",");
70 if (!tok2)
71 goto setup;
72
73 if (tok2[0] != 'c') {
74 callchain_param.print_limit = strtoul(tok2, &endptr, 0);
75 tok2 = strtok(NULL, ",");
76 if (!tok2)
77 goto setup;
78 }
79
80 /* get the call chain order */
81 if (!strncmp(tok2, "caller", strlen("caller")))
82 callchain_param.order = ORDER_CALLER;
83 else if (!strncmp(tok2, "callee", strlen("callee")))
84 callchain_param.order = ORDER_CALLEE;
85 else
86 return -1;
87
88 /* Get the sort key */
89 tok2 = strtok(NULL, ",");
90 if (!tok2)
91 goto setup;
92 if (!strncmp(tok2, "function", strlen("function")))
93 callchain_param.key = CCKEY_FUNCTION;
94 else if (!strncmp(tok2, "address", strlen("address")))
95 callchain_param.key = CCKEY_ADDRESS;
96 else
97 return -1;
98setup:
99 if (callchain_register_param(&callchain_param) < 0) {
100 pr_err("Can't register callchain params\n");
101 return -1;
102 }
103 return 0;
104}
105
28static void 106static void
29rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, 107rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
30 enum chain_mode mode) 108 enum chain_mode mode)
@@ -538,7 +616,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
538 if (sample->callchain == NULL) 616 if (sample->callchain == NULL)
539 return 0; 617 return 0;
540 618
541 if (symbol_conf.use_callchain || sort__has_parent) { 619 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
620 sort__has_parent) {
542 return machine__resolve_callchain(al->machine, evsel, al->thread, 621 return machine__resolve_callchain(al->machine, evsel, al->thread,
543 sample, parent, al, max_stack); 622 sample, parent, al, max_stack);
544 } 623 }
@@ -551,3 +630,45 @@ int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *samp
551 return 0; 630 return 0;
552 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
553} 632}
633
634int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
635 bool hide_unresolved)
636{
637 al->map = node->map;
638 al->sym = node->sym;
639 if (node->map)
640 al->addr = node->map->map_ip(node->map, node->ip);
641 else
642 al->addr = node->ip;
643
644 if (al->sym == NULL) {
645 if (hide_unresolved)
646 return 0;
647 if (al->map == NULL)
648 goto out;
649 }
650
651 if (al->map->groups == &al->machine->kmaps) {
652 if (machine__is_host(al->machine)) {
653 al->cpumode = PERF_RECORD_MISC_KERNEL;
654 al->level = 'k';
655 } else {
656 al->cpumode = PERF_RECORD_MISC_GUEST_KERNEL;
657 al->level = 'g';
658 }
659 } else {
660 if (machine__is_host(al->machine)) {
661 al->cpumode = PERF_RECORD_MISC_USER;
662 al->level = '.';
663 } else if (perf_guest) {
664 al->cpumode = PERF_RECORD_MISC_GUEST_USER;
665 al->level = 'u';
666 } else {
667 al->cpumode = PERF_RECORD_MISC_HYPERVISOR;
668 al->level = 'H';
669 }
670 }
671
672out:
673 return 1;
674}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8ad97e9b119f..8f84423a75da 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -7,6 +7,13 @@
7#include "event.h" 7#include "event.h"
8#include "symbol.h" 8#include "symbol.h"
9 9
10enum perf_call_graph_mode {
11 CALLCHAIN_NONE,
12 CALLCHAIN_FP,
13 CALLCHAIN_DWARF,
14 CALLCHAIN_MAX
15};
16
10enum chain_mode { 17enum chain_mode {
11 CHAIN_NONE, 18 CHAIN_NONE,
12 CHAIN_FLAT, 19 CHAIN_FLAT,
@@ -155,6 +162,18 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
155 struct perf_evsel *evsel, struct addr_location *al, 162 struct perf_evsel *evsel, struct addr_location *al,
156 int max_stack); 163 int max_stack);
157int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); 164int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
165int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node,
166 bool hide_unresolved);
158 167
159extern const char record_callchain_help[]; 168extern const char record_callchain_help[];
169int parse_callchain_report_opt(const char *arg);
170
171static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
172 struct callchain_cursor *src)
173{
174 *dest = *src;
175
176 dest->first = src->curr;
177 dest->nr -= src->pos;
178}
160#endif /* __PERF_CALLCHAIN_H */ 179#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 3e0fdd369ccb..24519e14ac56 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -11,6 +11,7 @@
11#include "util.h" 11#include "util.h"
12#include "cache.h" 12#include "cache.h"
13#include "exec_cmd.h" 13#include "exec_cmd.h"
14#include "util/hist.h" /* perf_hist_config */
14 15
15#define MAXNAME (256) 16#define MAXNAME (256)
16 17
@@ -355,6 +356,9 @@ int perf_default_config(const char *var, const char *value,
355 if (!prefixcmp(var, "core.")) 356 if (!prefixcmp(var, "core."))
356 return perf_default_core_config(var, value); 357 return perf_default_core_config(var, value);
357 358
359 if (!prefixcmp(var, "hist."))
360 return perf_hist_config(var, value);
361
358 /* Add other config variables here. */ 362 /* Add other config variables here. */
359 return 0; 363 return 0;
360} 364}
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 7fe4994eeb63..c4e55b71010c 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -317,3 +317,163 @@ int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
317{ 317{
318 return cpu_map__build_map(cpus, corep, cpu_map__get_core); 318 return cpu_map__build_map(cpus, corep, cpu_map__get_core);
319} 319}
320
321/* setup simple routines to easily access node numbers given a cpu number */
322static int get_max_num(char *path, int *max)
323{
324 size_t num;
325 char *buf;
326 int err = 0;
327
328 if (filename__read_str(path, &buf, &num))
329 return -1;
330
331 buf[num] = '\0';
332
333 /* start on the right, to find highest node num */
334 while (--num) {
335 if ((buf[num] == ',') || (buf[num] == '-')) {
336 num++;
337 break;
338 }
339 }
340 if (sscanf(&buf[num], "%d", max) < 1) {
341 err = -1;
342 goto out;
343 }
344
345 /* convert from 0-based to 1-based */
346 (*max)++;
347
348out:
349 free(buf);
350 return err;
351}
352
353/* Determine highest possible cpu in the system for sparse allocation */
354static void set_max_cpu_num(void)
355{
356 const char *mnt;
357 char path[PATH_MAX];
358 int ret = -1;
359
360 /* set up default */
361 max_cpu_num = 4096;
362
363 mnt = sysfs__mountpoint();
364 if (!mnt)
365 goto out;
366
367 /* get the highest possible cpu number for a sparse allocation */
368 ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
369 if (ret == PATH_MAX) {
370 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
371 goto out;
372 }
373
374 ret = get_max_num(path, &max_cpu_num);
375
376out:
377 if (ret)
378 pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
379}
380
381/* Determine highest possible node in the system for sparse allocation */
382static void set_max_node_num(void)
383{
384 const char *mnt;
385 char path[PATH_MAX];
386 int ret = -1;
387
388 /* set up default */
389 max_node_num = 8;
390
391 mnt = sysfs__mountpoint();
392 if (!mnt)
393 goto out;
394
395 /* get the highest possible cpu number for a sparse allocation */
396 ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
397 if (ret == PATH_MAX) {
398 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
399 goto out;
400 }
401
402 ret = get_max_num(path, &max_node_num);
403
404out:
405 if (ret)
406 pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
407}
408
409static int init_cpunode_map(void)
410{
411 int i;
412
413 set_max_cpu_num();
414 set_max_node_num();
415
416 cpunode_map = calloc(max_cpu_num, sizeof(int));
417 if (!cpunode_map) {
418 pr_err("%s: calloc failed\n", __func__);
419 return -1;
420 }
421
422 for (i = 0; i < max_cpu_num; i++)
423 cpunode_map[i] = -1;
424
425 return 0;
426}
427
428int cpu__setup_cpunode_map(void)
429{
430 struct dirent *dent1, *dent2;
431 DIR *dir1, *dir2;
432 unsigned int cpu, mem;
433 char buf[PATH_MAX];
434 char path[PATH_MAX];
435 const char *mnt;
436 int n;
437
438 /* initialize globals */
439 if (init_cpunode_map())
440 return -1;
441
442 mnt = sysfs__mountpoint();
443 if (!mnt)
444 return 0;
445
446 n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
447 if (n == PATH_MAX) {
448 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
449 return -1;
450 }
451
452 dir1 = opendir(path);
453 if (!dir1)
454 return 0;
455
456 /* walk tree and setup map */
457 while ((dent1 = readdir(dir1)) != NULL) {
458 if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
459 continue;
460
461 n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
462 if (n == PATH_MAX) {
463 pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
464 continue;
465 }
466
467 dir2 = opendir(buf);
468 if (!dir2)
469 continue;
470 while ((dent2 = readdir(dir2)) != NULL) {
471 if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
472 continue;
473 cpunode_map[cpu] = mem;
474 }
475 closedir(dir2);
476 }
477 closedir(dir1);
478 return 0;
479}
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index b123bb9d6f55..61a654849002 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -4,6 +4,9 @@
4#include <stdio.h> 4#include <stdio.h>
5#include <stdbool.h> 5#include <stdbool.h>
6 6
7#include "perf.h"
8#include "util/debug.h"
9
7struct cpu_map { 10struct cpu_map {
8 int nr; 11 int nr;
9 int map[]; 12 int map[];
@@ -46,4 +49,36 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
46 return map ? map->map[0] == -1 : true; 49 return map ? map->map[0] == -1 : true;
47} 50}
48 51
52int max_cpu_num;
53int max_node_num;
54int *cpunode_map;
55
56int cpu__setup_cpunode_map(void);
57
58static inline int cpu__max_node(void)
59{
60 if (unlikely(!max_node_num))
61 pr_debug("cpu_map not initialized\n");
62
63 return max_node_num;
64}
65
66static inline int cpu__max_cpu(void)
67{
68 if (unlikely(!max_cpu_num))
69 pr_debug("cpu_map not initialized\n");
70
71 return max_cpu_num;
72}
73
74static inline int cpu__get_node(int cpu)
75{
76 if (unlikely(cpunode_map == NULL)) {
77 pr_debug("cpu_map not initialized\n");
78 return -1;
79 }
80
81 return cpunode_map[cpu];
82}
83
49#endif /* __PERF_CPUMAP_H */ 84#endif /* __PERF_CPUMAP_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 64453d63b971..819f10414f08 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1,3 +1,6 @@
1#include <asm/bug.h>
2#include <sys/time.h>
3#include <sys/resource.h>
1#include "symbol.h" 4#include "symbol.h"
2#include "dso.h" 5#include "dso.h"
3#include "machine.h" 6#include "machine.h"
@@ -136,7 +139,48 @@ int dso__read_binary_type_filename(const struct dso *dso,
136 return ret; 139 return ret;
137} 140}
138 141
139static int open_dso(struct dso *dso, struct machine *machine) 142/*
143 * Global list of open DSOs and the counter.
144 */
145static LIST_HEAD(dso__data_open);
146static long dso__data_open_cnt;
147
148static void dso__list_add(struct dso *dso)
149{
150 list_add_tail(&dso->data.open_entry, &dso__data_open);
151 dso__data_open_cnt++;
152}
153
154static void dso__list_del(struct dso *dso)
155{
156 list_del(&dso->data.open_entry);
157 WARN_ONCE(dso__data_open_cnt <= 0,
158 "DSO data fd counter out of bounds.");
159 dso__data_open_cnt--;
160}
161
162static void close_first_dso(void);
163
164static int do_open(char *name)
165{
166 int fd;
167
168 do {
169 fd = open(name, O_RDONLY);
170 if (fd >= 0)
171 return fd;
172
173 pr_debug("dso open failed, mmap: %s\n", strerror(errno));
174 if (!dso__data_open_cnt || errno != EMFILE)
175 break;
176
177 close_first_dso();
178 } while (1);
179
180 return -1;
181}
182
183static int __open_dso(struct dso *dso, struct machine *machine)
140{ 184{
141 int fd; 185 int fd;
142 char *root_dir = (char *)""; 186 char *root_dir = (char *)"";
@@ -154,11 +198,130 @@ static int open_dso(struct dso *dso, struct machine *machine)
154 return -EINVAL; 198 return -EINVAL;
155 } 199 }
156 200
157 fd = open(name, O_RDONLY); 201 fd = do_open(name);
158 free(name); 202 free(name);
159 return fd; 203 return fd;
160} 204}
161 205
206static void check_data_close(void);
207
208/**
209 * dso_close - Open DSO data file
210 * @dso: dso object
211 *
212 * Open @dso's data file descriptor and updates
213 * list/count of open DSO objects.
214 */
215static int open_dso(struct dso *dso, struct machine *machine)
216{
217 int fd = __open_dso(dso, machine);
218
219 if (fd > 0) {
220 dso__list_add(dso);
221 /*
222 * Check if we crossed the allowed number
223 * of opened DSOs and close one if needed.
224 */
225 check_data_close();
226 }
227
228 return fd;
229}
230
231static void close_data_fd(struct dso *dso)
232{
233 if (dso->data.fd >= 0) {
234 close(dso->data.fd);
235 dso->data.fd = -1;
236 dso->data.file_size = 0;
237 dso__list_del(dso);
238 }
239}
240
241/**
242 * dso_close - Close DSO data file
243 * @dso: dso object
244 *
245 * Close @dso's data file descriptor and updates
246 * list/count of open DSO objects.
247 */
248static void close_dso(struct dso *dso)
249{
250 close_data_fd(dso);
251}
252
253static void close_first_dso(void)
254{
255 struct dso *dso;
256
257 dso = list_first_entry(&dso__data_open, struct dso, data.open_entry);
258 close_dso(dso);
259}
260
261static rlim_t get_fd_limit(void)
262{
263 struct rlimit l;
264 rlim_t limit = 0;
265
266 /* Allow half of the current open fd limit. */
267 if (getrlimit(RLIMIT_NOFILE, &l) == 0) {
268 if (l.rlim_cur == RLIM_INFINITY)
269 limit = l.rlim_cur;
270 else
271 limit = l.rlim_cur / 2;
272 } else {
273 pr_err("failed to get fd limit\n");
274 limit = 1;
275 }
276
277 return limit;
278}
279
280static bool may_cache_fd(void)
281{
282 static rlim_t limit;
283
284 if (!limit)
285 limit = get_fd_limit();
286
287 if (limit == RLIM_INFINITY)
288 return true;
289
290 return limit > (rlim_t) dso__data_open_cnt;
291}
292
293/*
294 * Check and close LRU dso if we crossed allowed limit
295 * for opened dso file descriptors. The limit is half
296 * of the RLIMIT_NOFILE files opened.
297*/
298static void check_data_close(void)
299{
300 bool cache_fd = may_cache_fd();
301
302 if (!cache_fd)
303 close_first_dso();
304}
305
306/**
307 * dso__data_close - Close DSO data file
308 * @dso: dso object
309 *
310 * External interface to close @dso's data file descriptor.
311 */
312void dso__data_close(struct dso *dso)
313{
314 close_dso(dso);
315}
316
317/**
318 * dso__data_fd - Get dso's data file descriptor
319 * @dso: dso object
320 * @machine: machine object
321 *
322 * External interface to find dso's file, open it and
323 * returns file descriptor.
324 */
162int dso__data_fd(struct dso *dso, struct machine *machine) 325int dso__data_fd(struct dso *dso, struct machine *machine)
163{ 326{
164 enum dso_binary_type binary_type_data[] = { 327 enum dso_binary_type binary_type_data[] = {
@@ -168,8 +331,13 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
168 }; 331 };
169 int i = 0; 332 int i = 0;
170 333
171 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) 334 if (dso->data.fd >= 0)
172 return open_dso(dso, machine); 335 return dso->data.fd;
336
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd;
340 }
173 341
174 do { 342 do {
175 int fd; 343 int fd;
@@ -178,7 +346,7 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
178 346
179 fd = open_dso(dso, machine); 347 fd = open_dso(dso, machine);
180 if (fd >= 0) 348 if (fd >= 0)
181 return fd; 349 return dso->data.fd = fd;
182 350
183 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
184 352
@@ -260,16 +428,10 @@ dso_cache__memcpy(struct dso_cache *cache, u64 offset,
260} 428}
261 429
262static ssize_t 430static ssize_t
263dso_cache__read(struct dso *dso, struct machine *machine, 431dso_cache__read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
264 u64 offset, u8 *data, ssize_t size)
265{ 432{
266 struct dso_cache *cache; 433 struct dso_cache *cache;
267 ssize_t ret; 434 ssize_t ret;
268 int fd;
269
270 fd = dso__data_fd(dso, machine);
271 if (fd < 0)
272 return -1;
273 435
274 do { 436 do {
275 u64 cache_offset; 437 u64 cache_offset;
@@ -283,16 +445,16 @@ dso_cache__read(struct dso *dso, struct machine *machine,
283 cache_offset = offset & DSO__DATA_CACHE_MASK; 445 cache_offset = offset & DSO__DATA_CACHE_MASK;
284 ret = -EINVAL; 446 ret = -EINVAL;
285 447
286 if (-1 == lseek(fd, cache_offset, SEEK_SET)) 448 if (-1 == lseek(dso->data.fd, cache_offset, SEEK_SET))
287 break; 449 break;
288 450
289 ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); 451 ret = read(dso->data.fd, cache->data, DSO__DATA_CACHE_SIZE);
290 if (ret <= 0) 452 if (ret <= 0)
291 break; 453 break;
292 454
293 cache->offset = cache_offset; 455 cache->offset = cache_offset;
294 cache->size = ret; 456 cache->size = ret;
295 dso_cache__insert(&dso->cache, cache); 457 dso_cache__insert(&dso->data.cache, cache);
296 458
297 ret = dso_cache__memcpy(cache, offset, data, size); 459 ret = dso_cache__memcpy(cache, offset, data, size);
298 460
@@ -301,24 +463,27 @@ dso_cache__read(struct dso *dso, struct machine *machine,
301 if (ret <= 0) 463 if (ret <= 0)
302 free(cache); 464 free(cache);
303 465
304 close(fd);
305 return ret; 466 return ret;
306} 467}
307 468
308static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, 469static ssize_t dso_cache_read(struct dso *dso, u64 offset,
309 u64 offset, u8 *data, ssize_t size) 470 u8 *data, ssize_t size)
310{ 471{
311 struct dso_cache *cache; 472 struct dso_cache *cache;
312 473
313 cache = dso_cache__find(&dso->cache, offset); 474 cache = dso_cache__find(&dso->data.cache, offset);
314 if (cache) 475 if (cache)
315 return dso_cache__memcpy(cache, offset, data, size); 476 return dso_cache__memcpy(cache, offset, data, size);
316 else 477 else
317 return dso_cache__read(dso, machine, offset, data, size); 478 return dso_cache__read(dso, offset, data, size);
318} 479}
319 480
320ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 481/*
321 u64 offset, u8 *data, ssize_t size) 482 * Reads and caches dso data DSO__DATA_CACHE_SIZE size chunks
483 * in the rb_tree. Any read to already cached data is served
484 * by cached data.
485 */
486static ssize_t cached_read(struct dso *dso, u64 offset, u8 *data, ssize_t size)
322{ 487{
323 ssize_t r = 0; 488 ssize_t r = 0;
324 u8 *p = data; 489 u8 *p = data;
@@ -326,7 +491,7 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
326 do { 491 do {
327 ssize_t ret; 492 ssize_t ret;
328 493
329 ret = dso_cache_read(dso, machine, offset, p, size); 494 ret = dso_cache_read(dso, offset, p, size);
330 if (ret < 0) 495 if (ret < 0)
331 return ret; 496 return ret;
332 497
@@ -346,6 +511,67 @@ ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
346 return r; 511 return r;
347} 512}
348 513
514static int data_file_size(struct dso *dso)
515{
516 struct stat st;
517
518 if (!dso->data.file_size) {
519 if (fstat(dso->data.fd, &st)) {
520 pr_err("dso mmap failed, fstat: %s\n", strerror(errno));
521 return -1;
522 }
523 dso->data.file_size = st.st_size;
524 }
525
526 return 0;
527}
528
529static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size)
531{
532 if (data_file_size(dso))
533 return -1;
534
535 /* Check the offset sanity. */
536 if (offset > dso->data.file_size)
537 return -1;
538
539 if (offset + size < offset)
540 return -1;
541
542 return cached_read(dso, offset, data, size);
543}
544
545/**
546 * dso__data_read_offset - Read data from dso file offset
547 * @dso: dso object
548 * @machine: machine object
549 * @offset: file offset
550 * @data: buffer to store data
551 * @size: size of the @data buffer
552 *
553 * External interface to read data from dso file offset. Open
554 * dso data file and use cached_read to get the data.
555 */
556ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
557 u64 offset, u8 *data, ssize_t size)
558{
559 if (dso__data_fd(dso, machine) < 0)
560 return -1;
561
562 return data_read_offset(dso, offset, data, size);
563}
564
565/**
566 * dso__data_read_addr - Read data from dso address
567 * @dso: dso object
568 * @machine: machine object
569 * @add: virtual memory address
570 * @data: buffer to store data
571 * @size: size of the @data buffer
572 *
573 * External interface to read data from dso address.
574 */
349ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 575ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
350 struct machine *machine, u64 addr, 576 struct machine *machine, u64 addr,
351 u8 *data, ssize_t size) 577 u8 *data, ssize_t size)
@@ -473,7 +699,8 @@ struct dso *dso__new(const char *name)
473 dso__set_short_name(dso, dso->name, false); 699 dso__set_short_name(dso, dso->name, false);
474 for (i = 0; i < MAP__NR_TYPES; ++i) 700 for (i = 0; i < MAP__NR_TYPES; ++i)
475 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
476 dso->cache = RB_ROOT; 702 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1;
477 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
478 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
479 dso->loaded = 0; 706 dso->loaded = 0;
@@ -485,6 +712,7 @@ struct dso *dso__new(const char *name)
485 dso->kernel = DSO_TYPE_USER; 712 dso->kernel = DSO_TYPE_USER;
486 dso->needs_swap = DSO_SWAP__UNSET; 713 dso->needs_swap = DSO_SWAP__UNSET;
487 INIT_LIST_HEAD(&dso->node); 714 INIT_LIST_HEAD(&dso->node);
715 INIT_LIST_HEAD(&dso->data.open_entry);
488 } 716 }
489 717
490 return dso; 718 return dso;
@@ -506,7 +734,8 @@ void dso__delete(struct dso *dso)
506 dso->long_name_allocated = false; 734 dso->long_name_allocated = false;
507 } 735 }
508 736
509 dso_cache__free(&dso->cache); 737 dso__data_close(dso);
738 dso_cache__free(&dso->data.cache);
510 dso__free_a2l(dso); 739 dso__free_a2l(dso);
511 zfree(&dso->symsrc_filename); 740 zfree(&dso->symsrc_filename);
512 free(dso); 741 free(dso);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ab06f1c03655..ad553ba257bf 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -4,7 +4,7 @@
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include <linux/types.h>
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10 10
@@ -76,7 +76,6 @@ struct dso {
76 struct list_head node; 76 struct list_head node;
77 struct rb_root symbols[MAP__NR_TYPES]; 77 struct rb_root symbols[MAP__NR_TYPES];
78 struct rb_root symbol_names[MAP__NR_TYPES]; 78 struct rb_root symbol_names[MAP__NR_TYPES];
79 struct rb_root cache;
80 void *a2l; 79 void *a2l;
81 char *symsrc_filename; 80 char *symsrc_filename;
82 unsigned int a2l_fails; 81 unsigned int a2l_fails;
@@ -99,6 +98,15 @@ struct dso {
99 const char *long_name; 98 const char *long_name;
100 u16 long_name_len; 99 u16 long_name_len;
101 u16 short_name_len; 100 u16 short_name_len;
101
102 /* dso data file */
103 struct {
104 struct rb_root cache;
105 int fd;
106 size_t file_size;
107 struct list_head open_entry;
108 } data;
109
102 char name[0]; 110 char name[0];
103}; 111};
104 112
@@ -141,7 +149,47 @@ char dso__symtab_origin(const struct dso *dso);
141int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type, 149int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
142 char *root_dir, char *filename, size_t size); 150 char *root_dir, char *filename, size_t size);
143 151
152/*
153 * The dso__data_* external interface provides following functions:
154 * dso__data_fd
155 * dso__data_close
156 * dso__data_read_offset
157 * dso__data_read_addr
158 *
159 * Please refer to the dso.c object code for each function and
160 * arguments documentation. Following text tries to explain the
161 * dso file descriptor caching.
162 *
163 * The dso__data* interface allows caching of opened file descriptors
164 * to speed up the dso data accesses. The idea is to leave the file
165 * descriptor opened ideally for the whole life of the dso object.
166 *
167 * The current usage of the dso__data_* interface is as follows:
168 *
169 * Get DSO's fd:
170 * int fd = dso__data_fd(dso, machine);
171 * USE 'fd' SOMEHOW
172 *
173 * Read DSO's data:
174 * n = dso__data_read_offset(dso_0, &machine, 0, buf, BUFSIZE);
175 * n = dso__data_read_addr(dso_0, &machine, 0, buf, BUFSIZE);
176 *
177 * Eventually close DSO's fd:
178 * dso__data_close(dso);
179 *
180 * It is not necessary to close the DSO object data file. Each time new
181 * DSO data file is opened, the limit (RLIMIT_NOFILE/2) is checked. Once
182 * it is crossed, the oldest opened DSO object is closed.
183 *
184 * The dso__delete function calls close_dso function to ensure the
185 * data file descriptor gets closed/unmapped before the dso object
186 * is freed.
187 *
188 * TODO
189*/
144int dso__data_fd(struct dso *dso, struct machine *machine); 190int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso);
192
145ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
146 u64 offset, u8 *data, ssize_t size); 194 u64 offset, u8 *data, ssize_t size);
147ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 195ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 7defd77105d0..cc66c4049e09 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -747,14 +747,17 @@ struct __find_variable_param {
747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) 747static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
748{ 748{
749 struct __find_variable_param *fvp = data; 749 struct __find_variable_param *fvp = data;
750 Dwarf_Attribute attr;
750 int tag; 751 int tag;
751 752
752 tag = dwarf_tag(die_mem); 753 tag = dwarf_tag(die_mem);
753 if ((tag == DW_TAG_formal_parameter || 754 if ((tag == DW_TAG_formal_parameter ||
754 tag == DW_TAG_variable) && 755 tag == DW_TAG_variable) &&
755 die_compare_name(die_mem, fvp->name)) 756 die_compare_name(die_mem, fvp->name) &&
757 /* Does the DIE have location information or external instance? */
758 (dwarf_attr(die_mem, DW_AT_external, &attr) ||
759 dwarf_attr(die_mem, DW_AT_location, &attr)))
756 return DIE_FIND_CB_END; 760 return DIE_FIND_CB_END;
757
758 if (dwarf_haspc(die_mem, fvp->addr)) 761 if (dwarf_haspc(die_mem, fvp->addr))
759 return DIE_FIND_CB_CONTINUE; 762 return DIE_FIND_CB_CONTINUE;
760 else 763 else
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9d12aa6dd485..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
@@ -699,7 +724,7 @@ void thread__find_addr_map(struct thread *thread,
699 enum map_type type, u64 addr, 724 enum map_type type, u64 addr,
700 struct addr_location *al) 725 struct addr_location *al)
701{ 726{
702 struct map_groups *mg = &thread->mg; 727 struct map_groups *mg = thread->mg;
703 bool load_map = false; 728 bool load_map = false;
704 729
705 al->machine = machine; 730 al->machine = machine;
@@ -788,7 +813,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
788{ 813{
789 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 814 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
790 struct thread *thread = machine__findnew_thread(machine, sample->pid, 815 struct thread *thread = machine__findnew_thread(machine, sample->pid,
791 sample->pid); 816 sample->tid);
792 817
793 if (thread == NULL) 818 if (thread == NULL)
794 return -1; 819 return -1;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 38457d447a13..e5dd40addb30 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -7,6 +7,7 @@
7#include "../perf.h" 7#include "../perf.h"
8#include "map.h" 8#include "map.h"
9#include "build-id.h" 9#include "build-id.h"
10#include "perf_regs.h"
10 11
11struct mmap_event { 12struct mmap_event {
12 struct perf_event_header header; 13 struct perf_event_header header;
@@ -27,6 +28,8 @@ struct mmap2_event {
27 u32 min; 28 u32 min;
28 u64 ino; 29 u64 ino;
29 u64 ino_generation; 30 u64 ino_generation;
31 u32 prot;
32 u32 flags;
30 char filename[PATH_MAX]; 33 char filename[PATH_MAX];
31}; 34};
32 35
@@ -87,6 +90,10 @@ struct regs_dump {
87 u64 abi; 90 u64 abi;
88 u64 mask; 91 u64 mask;
89 u64 *regs; 92 u64 *regs;
93
94 /* Cached values/mask filled by first register access. */
95 u64 cache_regs[PERF_REGS_MAX];
96 u64 cache_mask;
90}; 97};
91 98
92struct stack_dump { 99struct stack_dump {
@@ -112,6 +119,30 @@ struct sample_read {
112 }; 119 };
113}; 120};
114 121
122struct ip_callchain {
123 u64 nr;
124 u64 ips[0];
125};
126
127struct branch_flags {
128 u64 mispred:1;
129 u64 predicted:1;
130 u64 in_tx:1;
131 u64 abort:1;
132 u64 reserved:60;
133};
134
135struct branch_entry {
136 u64 from;
137 u64 to;
138 struct branch_flags flags;
139};
140
141struct branch_stack {
142 u64 nr;
143 struct branch_entry entries[0];
144};
145
115struct perf_sample { 146struct perf_sample {
116 u64 ip; 147 u64 ip;
117 u32 pid, tid; 148 u32 pid, tid;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 5c28d82b76c4..8606175fe1e8 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -589,10 +589,10 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
589 } 589 }
590 590
591 /* 591 /*
592 * We default some events to a 1 default interval. But keep 592 * We default some events to have a default interval. But keep
593 * it a weak assumption overridable by the user. 593 * it a weak assumption overridable by the user.
594 */ 594 */
595 if (!attr->sample_period || (opts->user_freq != UINT_MAX && 595 if (!attr->sample_period || (opts->user_freq != UINT_MAX ||
596 opts->user_interval != ULLONG_MAX)) { 596 opts->user_interval != ULLONG_MAX)) {
597 if (opts->freq) { 597 if (opts->freq) {
598 perf_evsel__set_sample_bit(evsel, PERIOD); 598 perf_evsel__set_sample_bit(evsel, PERIOD);
@@ -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/evsel.h b/tools/perf/util/evsel.h
index 0c9926cfb292..a52e9a5bb2d0 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -5,12 +5,12 @@
5#include <stdbool.h> 5#include <stdbool.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <linux/perf_event.h> 7#include <linux/perf_event.h>
8#include "types.h" 8#include <linux/types.h>
9#include "xyarray.h" 9#include "xyarray.h"
10#include "cgroup.h" 10#include "cgroup.h"
11#include "hist.h" 11#include "hist.h"
12#include "symbol.h" 12#include "symbol.h"
13 13
14struct perf_counts_values { 14struct perf_counts_values {
15 union { 15 union {
16 struct { 16 struct {
@@ -91,6 +91,11 @@ struct perf_evsel {
91 char *group_name; 91 char *group_name;
92}; 92};
93 93
94union u64_swap {
95 u64 val64;
96 u32 val32[2];
97};
98
94#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists) 99#define hists_to_evsel(h) container_of(h, struct perf_evsel, hists)
95 100
96struct cpu_map; 101struct cpu_map;
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index a2d047bdf4ef..d08cfe499404 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -4,10 +4,10 @@
4#include <linux/perf_event.h> 4#include <linux/perf_event.h>
5#include <sys/types.h> 5#include <sys/types.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include "types.h" 7#include <linux/bitmap.h>
8#include <linux/types.h>
8#include "event.h" 9#include "event.h"
9 10
10#include <linux/bitmap.h>
11 11
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f38590d7561b..30df6187ee02 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -4,6 +4,7 @@
4#include "session.h" 4#include "session.h"
5#include "sort.h" 5#include "sort.h"
6#include "evsel.h" 6#include "evsel.h"
7#include "annotate.h"
7#include <math.h> 8#include <math.h>
8 9
9static bool hists__filter_entry_by_dso(struct hists *hists, 10static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -127,6 +128,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
127 + unresolved_col_width + 2; 128 + unresolved_col_width + 2;
128 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 129 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
129 symlen); 130 symlen);
131 hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
132 symlen + 1);
130 } else { 133 } else {
131 symlen = unresolved_col_width + 4 + 2; 134 symlen = unresolved_col_width + 4 + 2;
132 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, 135 hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
@@ -225,14 +228,20 @@ static void he_stat__decay(struct he_stat *he_stat)
225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 228static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
226{ 229{
227 u64 prev_period = he->stat.period; 230 u64 prev_period = he->stat.period;
231 u64 diff;
228 232
229 if (prev_period == 0) 233 if (prev_period == 0)
230 return true; 234 return true;
231 235
232 he_stat__decay(&he->stat); 236 he_stat__decay(&he->stat);
237 if (symbol_conf.cumulate_callchain)
238 he_stat__decay(he->stat_acc);
233 239
240 diff = prev_period - he->stat.period;
241
242 hists->stats.total_period -= diff;
234 if (!he->filtered) 243 if (!he->filtered)
235 hists->stats.total_period -= prev_period - he->stat.period; 244 hists->stats.total_non_filtered_period -= diff;
236 245
237 return he->stat.period == 0; 246 return he->stat.period == 0;
238} 247}
@@ -259,8 +268,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
259 if (sort__need_collapse) 268 if (sort__need_collapse)
260 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 269 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
261 270
262 hist_entry__free(n);
263 --hists->nr_entries; 271 --hists->nr_entries;
272 if (!n->filtered)
273 --hists->nr_non_filtered_entries;
274
275 hist_entry__free(n);
264 } 276 }
265 } 277 }
266} 278}
@@ -269,14 +281,31 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
269 * histogram, sorted on item, collects periods 281 * histogram, sorted on item, collects periods
270 */ 282 */
271 283
272static struct hist_entry *hist_entry__new(struct hist_entry *template) 284static struct hist_entry *hist_entry__new(struct hist_entry *template,
285 bool sample_self)
273{ 286{
274 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 287 size_t callchain_size = 0;
275 struct hist_entry *he = zalloc(sizeof(*he) + callchain_size); 288 struct hist_entry *he;
289
290 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain)
291 callchain_size = sizeof(struct callchain_root);
292
293 he = zalloc(sizeof(*he) + callchain_size);
276 294
277 if (he != NULL) { 295 if (he != NULL) {
278 *he = *template; 296 *he = *template;
279 297
298 if (symbol_conf.cumulate_callchain) {
299 he->stat_acc = malloc(sizeof(he->stat));
300 if (he->stat_acc == NULL) {
301 free(he);
302 return NULL;
303 }
304 memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
305 if (!sample_self)
306 memset(&he->stat, 0, sizeof(he->stat));
307 }
308
280 if (he->ms.map) 309 if (he->ms.map)
281 he->ms.map->referenced = true; 310 he->ms.map->referenced = true;
282 311
@@ -288,6 +317,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
288 */ 317 */
289 he->branch_info = malloc(sizeof(*he->branch_info)); 318 he->branch_info = malloc(sizeof(*he->branch_info));
290 if (he->branch_info == NULL) { 319 if (he->branch_info == NULL) {
320 free(he->stat_acc);
291 free(he); 321 free(he);
292 return NULL; 322 return NULL;
293 } 323 }
@@ -317,15 +347,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
317 return he; 347 return he;
318} 348}
319 349
320void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
321{
322 if (!h->filtered) {
323 hists__calc_col_len(hists, h);
324 ++hists->nr_entries;
325 hists->stats.total_period += h->stat.period;
326 }
327}
328
329static u8 symbol__parent_filter(const struct symbol *parent) 350static u8 symbol__parent_filter(const struct symbol *parent)
330{ 351{
331 if (symbol_conf.exclude_other && parent == NULL) 352 if (symbol_conf.exclude_other && parent == NULL)
@@ -335,7 +356,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
335 356
336static struct hist_entry *add_hist_entry(struct hists *hists, 357static struct hist_entry *add_hist_entry(struct hists *hists,
337 struct hist_entry *entry, 358 struct hist_entry *entry,
338 struct addr_location *al) 359 struct addr_location *al,
360 bool sample_self)
339{ 361{
340 struct rb_node **p; 362 struct rb_node **p;
341 struct rb_node *parent = NULL; 363 struct rb_node *parent = NULL;
@@ -359,7 +381,10 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
359 cmp = hist_entry__cmp(he, entry); 381 cmp = hist_entry__cmp(he, entry);
360 382
361 if (!cmp) { 383 if (!cmp) {
362 he_stat__add_period(&he->stat, period, weight); 384 if (sample_self)
385 he_stat__add_period(&he->stat, period, weight);
386 if (symbol_conf.cumulate_callchain)
387 he_stat__add_period(he->stat_acc, period, weight);
363 388
364 /* 389 /*
365 * This mem info was allocated from sample__resolve_mem 390 * This mem info was allocated from sample__resolve_mem
@@ -387,15 +412,17 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
387 p = &(*p)->rb_right; 412 p = &(*p)->rb_right;
388 } 413 }
389 414
390 he = hist_entry__new(entry); 415 he = hist_entry__new(entry, sample_self);
391 if (!he) 416 if (!he)
392 return NULL; 417 return NULL;
393 418
394 hists->nr_entries++;
395 rb_link_node(&he->rb_node_in, parent, p); 419 rb_link_node(&he->rb_node_in, parent, p);
396 rb_insert_color(&he->rb_node_in, hists->entries_in); 420 rb_insert_color(&he->rb_node_in, hists->entries_in);
397out: 421out:
398 he_stat__add_cpumode_period(&he->stat, al->cpumode, period); 422 if (sample_self)
423 he_stat__add_cpumode_period(&he->stat, al->cpumode, period);
424 if (symbol_conf.cumulate_callchain)
425 he_stat__add_cpumode_period(he->stat_acc, al->cpumode, period);
399 return he; 426 return he;
400} 427}
401 428
@@ -404,7 +431,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
404 struct symbol *sym_parent, 431 struct symbol *sym_parent,
405 struct branch_info *bi, 432 struct branch_info *bi,
406 struct mem_info *mi, 433 struct mem_info *mi,
407 u64 period, u64 weight, u64 transaction) 434 u64 period, u64 weight, u64 transaction,
435 bool sample_self)
408{ 436{
409 struct hist_entry entry = { 437 struct hist_entry entry = {
410 .thread = al->thread, 438 .thread = al->thread,
@@ -413,9 +441,10 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
413 .map = al->map, 441 .map = al->map,
414 .sym = al->sym, 442 .sym = al->sym,
415 }, 443 },
416 .cpu = al->cpu, 444 .cpu = al->cpu,
417 .ip = al->addr, 445 .cpumode = al->cpumode,
418 .level = al->level, 446 .ip = al->addr,
447 .level = al->level,
419 .stat = { 448 .stat = {
420 .nr_events = 1, 449 .nr_events = 1,
421 .period = period, 450 .period = period,
@@ -429,17 +458,442 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
429 .transaction = transaction, 458 .transaction = transaction,
430 }; 459 };
431 460
432 return add_hist_entry(hists, &entry, al); 461 return add_hist_entry(hists, &entry, al, sample_self);
462}
463
464static int
465iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
466 struct addr_location *al __maybe_unused)
467{
468 return 0;
469}
470
471static int
472iter_add_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
473 struct addr_location *al __maybe_unused)
474{
475 return 0;
476}
477
478static int
479iter_prepare_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
480{
481 struct perf_sample *sample = iter->sample;
482 struct mem_info *mi;
483
484 mi = sample__resolve_mem(sample, al);
485 if (mi == NULL)
486 return -ENOMEM;
487
488 iter->priv = mi;
489 return 0;
490}
491
492static int
493iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al)
494{
495 u64 cost;
496 struct mem_info *mi = iter->priv;
497 struct hist_entry *he;
498
499 if (mi == NULL)
500 return -EINVAL;
501
502 cost = iter->sample->weight;
503 if (!cost)
504 cost = 1;
505
506 /*
507 * must pass period=weight in order to get the correct
508 * sorting from hists__collapse_resort() which is solely
509 * based on periods. We want sorting be done on nr_events * weight
510 * and this is indirectly achieved by passing period=weight here
511 * and the he_stat__add_period() function.
512 */
513 he = __hists__add_entry(&iter->evsel->hists, al, iter->parent, NULL, mi,
514 cost, cost, 0, true);
515 if (!he)
516 return -ENOMEM;
517
518 iter->he = he;
519 return 0;
520}
521
522static int
523iter_finish_mem_entry(struct hist_entry_iter *iter,
524 struct addr_location *al __maybe_unused)
525{
526 struct perf_evsel *evsel = iter->evsel;
527 struct hist_entry *he = iter->he;
528 int err = -EINVAL;
529
530 if (he == NULL)
531 goto out;
532
533 hists__inc_nr_samples(&evsel->hists, he->filtered);
534
535 err = hist_entry__append_callchain(he, iter->sample);
536
537out:
538 /*
539 * We don't need to free iter->priv (mem_info) here since
540 * the mem info was either already freed in add_hist_entry() or
541 * passed to a new hist entry by hist_entry__new().
542 */
543 iter->priv = NULL;
544
545 iter->he = NULL;
546 return err;
547}
548
549static int
550iter_prepare_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
551{
552 struct branch_info *bi;
553 struct perf_sample *sample = iter->sample;
554
555 bi = sample__resolve_bstack(sample, al);
556 if (!bi)
557 return -ENOMEM;
558
559 iter->curr = 0;
560 iter->total = sample->branch_stack->nr;
561
562 iter->priv = bi;
563 return 0;
564}
565
566static int
567iter_add_single_branch_entry(struct hist_entry_iter *iter __maybe_unused,
568 struct addr_location *al __maybe_unused)
569{
570 /* to avoid calling callback function */
571 iter->he = NULL;
572
573 return 0;
574}
575
576static int
577iter_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
578{
579 struct branch_info *bi = iter->priv;
580 int i = iter->curr;
581
582 if (bi == NULL)
583 return 0;
584
585 if (iter->curr >= iter->total)
586 return 0;
587
588 al->map = bi[i].to.map;
589 al->sym = bi[i].to.sym;
590 al->addr = bi[i].to.addr;
591 return 1;
592}
593
594static int
595iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al)
596{
597 struct branch_info *bi;
598 struct perf_evsel *evsel = iter->evsel;
599 struct hist_entry *he = NULL;
600 int i = iter->curr;
601 int err = 0;
602
603 bi = iter->priv;
604
605 if (iter->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym))
606 goto out;
607
608 /*
609 * The report shows the percentage of total branches captured
610 * and not events sampled. Thus we use a pseudo period of 1.
611 */
612 he = __hists__add_entry(&evsel->hists, al, iter->parent, &bi[i], NULL,
613 1, 1, 0, true);
614 if (he == NULL)
615 return -ENOMEM;
616
617 hists__inc_nr_samples(&evsel->hists, he->filtered);
618
619out:
620 iter->he = he;
621 iter->curr++;
622 return err;
623}
624
625static int
626iter_finish_branch_entry(struct hist_entry_iter *iter,
627 struct addr_location *al __maybe_unused)
628{
629 zfree(&iter->priv);
630 iter->he = NULL;
631
632 return iter->curr >= iter->total ? 0 : -1;
633}
634
635static int
636iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused,
637 struct addr_location *al __maybe_unused)
638{
639 return 0;
640}
641
642static int
643iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al)
644{
645 struct perf_evsel *evsel = iter->evsel;
646 struct perf_sample *sample = iter->sample;
647 struct hist_entry *he;
648
649 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
650 sample->period, sample->weight,
651 sample->transaction, true);
652 if (he == NULL)
653 return -ENOMEM;
654
655 iter->he = he;
656 return 0;
657}
658
659static int
660iter_finish_normal_entry(struct hist_entry_iter *iter,
661 struct addr_location *al __maybe_unused)
662{
663 struct hist_entry *he = iter->he;
664 struct perf_evsel *evsel = iter->evsel;
665 struct perf_sample *sample = iter->sample;
666
667 if (he == NULL)
668 return 0;
669
670 iter->he = NULL;
671
672 hists__inc_nr_samples(&evsel->hists, he->filtered);
673
674 return hist_entry__append_callchain(he, sample);
675}
676
677static int
678iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
679 struct addr_location *al __maybe_unused)
680{
681 struct hist_entry **he_cache;
682
683 callchain_cursor_commit(&callchain_cursor);
684
685 /*
686 * This is for detecting cycles or recursions so that they're
687 * cumulated only one time to prevent entries more than 100%
688 * overhead.
689 */
690 he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1));
691 if (he_cache == NULL)
692 return -ENOMEM;
693
694 iter->priv = he_cache;
695 iter->curr = 0;
696
697 return 0;
698}
699
700static int
701iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
702 struct addr_location *al)
703{
704 struct perf_evsel *evsel = iter->evsel;
705 struct perf_sample *sample = iter->sample;
706 struct hist_entry **he_cache = iter->priv;
707 struct hist_entry *he;
708 int err = 0;
709
710 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
711 sample->period, sample->weight,
712 sample->transaction, true);
713 if (he == NULL)
714 return -ENOMEM;
715
716 iter->he = he;
717 he_cache[iter->curr++] = he;
718
719 callchain_append(he->callchain, &callchain_cursor, sample->period);
720
721 /*
722 * We need to re-initialize the cursor since callchain_append()
723 * advanced the cursor to the end.
724 */
725 callchain_cursor_commit(&callchain_cursor);
726
727 hists__inc_nr_samples(&evsel->hists, he->filtered);
728
729 return err;
730}
731
732static int
733iter_next_cumulative_entry(struct hist_entry_iter *iter,
734 struct addr_location *al)
735{
736 struct callchain_cursor_node *node;
737
738 node = callchain_cursor_current(&callchain_cursor);
739 if (node == NULL)
740 return 0;
741
742 return fill_callchain_info(al, node, iter->hide_unresolved);
743}
744
745static int
746iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
747 struct addr_location *al)
748{
749 struct perf_evsel *evsel = iter->evsel;
750 struct perf_sample *sample = iter->sample;
751 struct hist_entry **he_cache = iter->priv;
752 struct hist_entry *he;
753 struct hist_entry he_tmp = {
754 .cpu = al->cpu,
755 .thread = al->thread,
756 .comm = thread__comm(al->thread),
757 .ip = al->addr,
758 .ms = {
759 .map = al->map,
760 .sym = al->sym,
761 },
762 .parent = iter->parent,
763 };
764 int i;
765 struct callchain_cursor cursor;
766
767 callchain_cursor_snapshot(&cursor, &callchain_cursor);
768
769 callchain_cursor_advance(&callchain_cursor);
770
771 /*
772 * Check if there's duplicate entries in the callchain.
773 * It's possible that it has cycles or recursive calls.
774 */
775 for (i = 0; i < iter->curr; i++) {
776 if (hist_entry__cmp(he_cache[i], &he_tmp) == 0) {
777 /* to avoid calling callback function */
778 iter->he = NULL;
779 return 0;
780 }
781 }
782
783 he = __hists__add_entry(&evsel->hists, al, iter->parent, NULL, NULL,
784 sample->period, sample->weight,
785 sample->transaction, false);
786 if (he == NULL)
787 return -ENOMEM;
788
789 iter->he = he;
790 he_cache[iter->curr++] = he;
791
792 callchain_append(he->callchain, &cursor, sample->period);
793 return 0;
794}
795
796static int
797iter_finish_cumulative_entry(struct hist_entry_iter *iter,
798 struct addr_location *al __maybe_unused)
799{
800 zfree(&iter->priv);
801 iter->he = NULL;
802
803 return 0;
804}
805
806const struct hist_iter_ops hist_iter_mem = {
807 .prepare_entry = iter_prepare_mem_entry,
808 .add_single_entry = iter_add_single_mem_entry,
809 .next_entry = iter_next_nop_entry,
810 .add_next_entry = iter_add_next_nop_entry,
811 .finish_entry = iter_finish_mem_entry,
812};
813
814const struct hist_iter_ops hist_iter_branch = {
815 .prepare_entry = iter_prepare_branch_entry,
816 .add_single_entry = iter_add_single_branch_entry,
817 .next_entry = iter_next_branch_entry,
818 .add_next_entry = iter_add_next_branch_entry,
819 .finish_entry = iter_finish_branch_entry,
820};
821
822const struct hist_iter_ops hist_iter_normal = {
823 .prepare_entry = iter_prepare_normal_entry,
824 .add_single_entry = iter_add_single_normal_entry,
825 .next_entry = iter_next_nop_entry,
826 .add_next_entry = iter_add_next_nop_entry,
827 .finish_entry = iter_finish_normal_entry,
828};
829
830const struct hist_iter_ops hist_iter_cumulative = {
831 .prepare_entry = iter_prepare_cumulative_entry,
832 .add_single_entry = iter_add_single_cumulative_entry,
833 .next_entry = iter_next_cumulative_entry,
834 .add_next_entry = iter_add_next_cumulative_entry,
835 .finish_entry = iter_finish_cumulative_entry,
836};
837
838int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
839 struct perf_evsel *evsel, struct perf_sample *sample,
840 int max_stack_depth, void *arg)
841{
842 int err, err2;
843
844 err = sample__resolve_callchain(sample, &iter->parent, evsel, al,
845 max_stack_depth);
846 if (err)
847 return err;
848
849 iter->evsel = evsel;
850 iter->sample = sample;
851
852 err = iter->ops->prepare_entry(iter, al);
853 if (err)
854 goto out;
855
856 err = iter->ops->add_single_entry(iter, al);
857 if (err)
858 goto out;
859
860 if (iter->he && iter->add_entry_cb) {
861 err = iter->add_entry_cb(iter, al, true, arg);
862 if (err)
863 goto out;
864 }
865
866 while (iter->ops->next_entry(iter, al)) {
867 err = iter->ops->add_next_entry(iter, al);
868 if (err)
869 break;
870
871 if (iter->he && iter->add_entry_cb) {
872 err = iter->add_entry_cb(iter, al, false, arg);
873 if (err)
874 goto out;
875 }
876 }
877
878out:
879 err2 = iter->ops->finish_entry(iter, al);
880 if (!err)
881 err = err2;
882
883 return err;
433} 884}
434 885
435int64_t 886int64_t
436hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 887hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
437{ 888{
438 struct sort_entry *se; 889 struct perf_hpp_fmt *fmt;
439 int64_t cmp = 0; 890 int64_t cmp = 0;
440 891
441 list_for_each_entry(se, &hist_entry__sort_list, list) { 892 perf_hpp__for_each_sort_list(fmt) {
442 cmp = se->se_cmp(left, right); 893 if (perf_hpp__should_skip(fmt))
894 continue;
895
896 cmp = fmt->cmp(left, right);
443 if (cmp) 897 if (cmp)
444 break; 898 break;
445 } 899 }
@@ -450,15 +904,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
450int64_t 904int64_t
451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 905hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
452{ 906{
453 struct sort_entry *se; 907 struct perf_hpp_fmt *fmt;
454 int64_t cmp = 0; 908 int64_t cmp = 0;
455 909
456 list_for_each_entry(se, &hist_entry__sort_list, list) { 910 perf_hpp__for_each_sort_list(fmt) {
457 int64_t (*f)(struct hist_entry *, struct hist_entry *); 911 if (perf_hpp__should_skip(fmt))
458 912 continue;
459 f = se->se_collapse ?: se->se_cmp;
460 913
461 cmp = f(left, right); 914 cmp = fmt->collapse(left, right);
462 if (cmp) 915 if (cmp)
463 break; 916 break;
464 } 917 }
@@ -470,6 +923,7 @@ void hist_entry__free(struct hist_entry *he)
470{ 923{
471 zfree(&he->branch_info); 924 zfree(&he->branch_info);
472 zfree(&he->mem_info); 925 zfree(&he->mem_info);
926 zfree(&he->stat_acc);
473 free_srcline(he->srcline); 927 free_srcline(he->srcline);
474 free(he); 928 free(he);
475} 929}
@@ -495,6 +949,8 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
495 949
496 if (!cmp) { 950 if (!cmp) {
497 he_stat__add_stat(&iter->stat, &he->stat); 951 he_stat__add_stat(&iter->stat, &he->stat);
952 if (symbol_conf.cumulate_callchain)
953 he_stat__add_stat(iter->stat_acc, he->stat_acc);
498 954
499 if (symbol_conf.use_callchain) { 955 if (symbol_conf.use_callchain) {
500 callchain_cursor_reset(&callchain_cursor); 956 callchain_cursor_reset(&callchain_cursor);
@@ -571,64 +1027,50 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
571 } 1027 }
572} 1028}
573 1029
574/* 1030static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
575 * reverse the map, sort on period.
576 */
577
578static int period_cmp(u64 period_a, u64 period_b)
579{
580 if (period_a > period_b)
581 return 1;
582 if (period_a < period_b)
583 return -1;
584 return 0;
585}
586
587static int hist_entry__sort_on_period(struct hist_entry *a,
588 struct hist_entry *b)
589{ 1031{
590 int ret; 1032 struct perf_hpp_fmt *fmt;
591 int i, nr_members; 1033 int64_t cmp = 0;
592 struct perf_evsel *evsel;
593 struct hist_entry *pair;
594 u64 *periods_a, *periods_b;
595 1034
596 ret = period_cmp(a->stat.period, b->stat.period); 1035 perf_hpp__for_each_sort_list(fmt) {
597 if (ret || !symbol_conf.event_group) 1036 if (perf_hpp__should_skip(fmt))
598 return ret; 1037 continue;
599 1038
600 evsel = hists_to_evsel(a->hists); 1039 cmp = fmt->sort(a, b);
601 nr_members = evsel->nr_members; 1040 if (cmp)
602 if (nr_members <= 1) 1041 break;
603 return ret; 1042 }
604 1043
605 periods_a = zalloc(sizeof(periods_a) * nr_members); 1044 return cmp;
606 periods_b = zalloc(sizeof(periods_b) * nr_members); 1045}
607 1046
608 if (!periods_a || !periods_b) 1047static void hists__reset_filter_stats(struct hists *hists)
609 goto out; 1048{
1049 hists->nr_non_filtered_entries = 0;
1050 hists->stats.total_non_filtered_period = 0;
1051}
610 1052
611 list_for_each_entry(pair, &a->pairs.head, pairs.node) { 1053void hists__reset_stats(struct hists *hists)
612 evsel = hists_to_evsel(pair->hists); 1054{
613 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; 1055 hists->nr_entries = 0;
614 } 1056 hists->stats.total_period = 0;
615 1057
616 list_for_each_entry(pair, &b->pairs.head, pairs.node) { 1058 hists__reset_filter_stats(hists);
617 evsel = hists_to_evsel(pair->hists); 1059}
618 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
619 }
620 1060
621 for (i = 1; i < nr_members; i++) { 1061static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
622 ret = period_cmp(periods_a[i], periods_b[i]); 1062{
623 if (ret) 1063 hists->nr_non_filtered_entries++;
624 break; 1064 hists->stats.total_non_filtered_period += h->stat.period;
625 } 1065}
626 1066
627out: 1067void hists__inc_stats(struct hists *hists, struct hist_entry *h)
628 free(periods_a); 1068{
629 free(periods_b); 1069 if (!h->filtered)
1070 hists__inc_filter_stats(hists, h);
630 1071
631 return ret; 1072 hists->nr_entries++;
1073 hists->stats.total_period += h->stat.period;
632} 1074}
633 1075
634static void __hists__insert_output_entry(struct rb_root *entries, 1076static void __hists__insert_output_entry(struct rb_root *entries,
@@ -647,7 +1089,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
647 parent = *p; 1089 parent = *p;
648 iter = rb_entry(parent, struct hist_entry, rb_node); 1090 iter = rb_entry(parent, struct hist_entry, rb_node);
649 1091
650 if (hist_entry__sort_on_period(he, iter) > 0) 1092 if (hist_entry__sort(he, iter) > 0)
651 p = &(*p)->rb_left; 1093 p = &(*p)->rb_left;
652 else 1094 else
653 p = &(*p)->rb_right; 1095 p = &(*p)->rb_right;
@@ -674,8 +1116,7 @@ void hists__output_resort(struct hists *hists)
674 next = rb_first(root); 1116 next = rb_first(root);
675 hists->entries = RB_ROOT; 1117 hists->entries = RB_ROOT;
676 1118
677 hists->nr_entries = 0; 1119 hists__reset_stats(hists);
678 hists->stats.total_period = 0;
679 hists__reset_col_len(hists); 1120 hists__reset_col_len(hists);
680 1121
681 while (next) { 1122 while (next) {
@@ -683,7 +1124,10 @@ void hists__output_resort(struct hists *hists)
683 next = rb_next(&n->rb_node_in); 1124 next = rb_next(&n->rb_node_in);
684 1125
685 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 1126 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
686 hists__inc_nr_entries(hists, n); 1127 hists__inc_stats(hists, n);
1128
1129 if (!n->filtered)
1130 hists__calc_col_len(hists, n);
687 } 1131 }
688} 1132}
689 1133
@@ -694,13 +1138,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
694 if (h->filtered) 1138 if (h->filtered)
695 return; 1139 return;
696 1140
697 ++hists->nr_entries; 1141 /* force fold unfiltered entry for simplicity */
698 if (h->ms.unfolded) 1142 h->ms.unfolded = false;
699 hists->nr_entries += h->nr_rows;
700 h->row_offset = 0; 1143 h->row_offset = 0;
701 hists->stats.total_period += h->stat.period;
702 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
703 1144
1145 hists->stats.nr_non_filtered_samples += h->stat.nr_events;
1146
1147 hists__inc_filter_stats(hists, h);
704 hists__calc_col_len(hists, h); 1148 hists__calc_col_len(hists, h);
705} 1149}
706 1150
@@ -721,8 +1165,9 @@ void hists__filter_by_dso(struct hists *hists)
721{ 1165{
722 struct rb_node *nd; 1166 struct rb_node *nd;
723 1167
724 hists->nr_entries = hists->stats.total_period = 0; 1168 hists->stats.nr_non_filtered_samples = 0;
725 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1169
1170 hists__reset_filter_stats(hists);
726 hists__reset_col_len(hists); 1171 hists__reset_col_len(hists);
727 1172
728 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1173 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -754,8 +1199,9 @@ void hists__filter_by_thread(struct hists *hists)
754{ 1199{
755 struct rb_node *nd; 1200 struct rb_node *nd;
756 1201
757 hists->nr_entries = hists->stats.total_period = 0; 1202 hists->stats.nr_non_filtered_samples = 0;
758 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1203
1204 hists__reset_filter_stats(hists);
759 hists__reset_col_len(hists); 1205 hists__reset_col_len(hists);
760 1206
761 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1207 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -785,8 +1231,9 @@ void hists__filter_by_symbol(struct hists *hists)
785{ 1231{
786 struct rb_node *nd; 1232 struct rb_node *nd;
787 1233
788 hists->nr_entries = hists->stats.total_period = 0; 1234 hists->stats.nr_non_filtered_samples = 0;
789 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1235
1236 hists__reset_filter_stats(hists);
790 hists__reset_col_len(hists); 1237 hists__reset_col_len(hists);
791 1238
792 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1239 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -810,6 +1257,13 @@ void hists__inc_nr_events(struct hists *hists, u32 type)
810 events_stats__inc(&hists->stats, type); 1257 events_stats__inc(&hists->stats, type);
811} 1258}
812 1259
1260void hists__inc_nr_samples(struct hists *hists, bool filtered)
1261{
1262 events_stats__inc(&hists->stats, PERF_RECORD_SAMPLE);
1263 if (!filtered)
1264 hists->stats.nr_non_filtered_samples++;
1265}
1266
813static struct hist_entry *hists__add_dummy_entry(struct hists *hists, 1267static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
814 struct hist_entry *pair) 1268 struct hist_entry *pair)
815{ 1269{
@@ -841,13 +1295,13 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
841 p = &(*p)->rb_right; 1295 p = &(*p)->rb_right;
842 } 1296 }
843 1297
844 he = hist_entry__new(pair); 1298 he = hist_entry__new(pair, true);
845 if (he) { 1299 if (he) {
846 memset(&he->stat, 0, sizeof(he->stat)); 1300 memset(&he->stat, 0, sizeof(he->stat));
847 he->hists = hists; 1301 he->hists = hists;
848 rb_link_node(&he->rb_node_in, parent, p); 1302 rb_link_node(&he->rb_node_in, parent, p);
849 rb_insert_color(&he->rb_node_in, root); 1303 rb_insert_color(&he->rb_node_in, root);
850 hists__inc_nr_entries(hists, he); 1304 hists__inc_stats(hists, he);
851 he->dummy = true; 1305 he->dummy = true;
852 } 1306 }
853out: 1307out:
@@ -931,3 +1385,30 @@ int hists__link(struct hists *leader, struct hists *other)
931 1385
932 return 0; 1386 return 0;
933} 1387}
1388
1389u64 hists__total_period(struct hists *hists)
1390{
1391 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
1392 hists->stats.total_period;
1393}
1394
1395int parse_filter_percentage(const struct option *opt __maybe_unused,
1396 const char *arg, int unset __maybe_unused)
1397{
1398 if (!strcmp(arg, "relative"))
1399 symbol_conf.filter_relative = true;
1400 else if (!strcmp(arg, "absolute"))
1401 symbol_conf.filter_relative = false;
1402 else
1403 return -1;
1404
1405 return 0;
1406}
1407
1408int perf_hist_config(const char *var, const char *value)
1409{
1410 if (!strcmp(var, "hist.percentage"))
1411 return parse_filter_percentage(NULL, value, 0);
1412
1413 return 0;
1414}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1f1f513dfe7f..742f49a85725 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -37,9 +37,11 @@ enum hist_filter {
37 */ 37 */
38struct events_stats { 38struct events_stats {
39 u64 total_period; 39 u64 total_period;
40 u64 total_non_filtered_period;
40 u64 total_lost; 41 u64 total_lost;
41 u64 total_invalid_chains; 42 u64 total_invalid_chains;
42 u32 nr_events[PERF_RECORD_HEADER_MAX]; 43 u32 nr_events[PERF_RECORD_HEADER_MAX];
44 u32 nr_non_filtered_samples;
43 u32 nr_lost_warned; 45 u32 nr_lost_warned;
44 u32 nr_unknown_events; 46 u32 nr_unknown_events;
45 u32 nr_invalid_chains; 47 u32 nr_invalid_chains;
@@ -70,6 +72,7 @@ enum hist_column {
70 HISTC_MEM_TLB, 72 HISTC_MEM_TLB,
71 HISTC_MEM_LVL, 73 HISTC_MEM_LVL,
72 HISTC_MEM_SNOOP, 74 HISTC_MEM_SNOOP,
75 HISTC_MEM_DCACHELINE,
73 HISTC_TRANSACTION, 76 HISTC_TRANSACTION,
74 HISTC_NR_COLS, /* Last entry */ 77 HISTC_NR_COLS, /* Last entry */
75}; 78};
@@ -83,6 +86,7 @@ struct hists {
83 struct rb_root entries; 86 struct rb_root entries;
84 struct rb_root entries_collapsed; 87 struct rb_root entries_collapsed;
85 u64 nr_entries; 88 u64 nr_entries;
89 u64 nr_non_filtered_entries;
86 const struct thread *thread_filter; 90 const struct thread *thread_filter;
87 const struct dso *dso_filter; 91 const struct dso *dso_filter;
88 const char *uid_filter_str; 92 const char *uid_filter_str;
@@ -93,12 +97,50 @@ struct hists {
93 u16 col_len[HISTC_NR_COLS]; 97 u16 col_len[HISTC_NR_COLS];
94}; 98};
95 99
100struct hist_entry_iter;
101
102struct hist_iter_ops {
103 int (*prepare_entry)(struct hist_entry_iter *, struct addr_location *);
104 int (*add_single_entry)(struct hist_entry_iter *, struct addr_location *);
105 int (*next_entry)(struct hist_entry_iter *, struct addr_location *);
106 int (*add_next_entry)(struct hist_entry_iter *, struct addr_location *);
107 int (*finish_entry)(struct hist_entry_iter *, struct addr_location *);
108};
109
110struct hist_entry_iter {
111 int total;
112 int curr;
113
114 bool hide_unresolved;
115
116 struct perf_evsel *evsel;
117 struct perf_sample *sample;
118 struct hist_entry *he;
119 struct symbol *parent;
120 void *priv;
121
122 const struct hist_iter_ops *ops;
123 /* user-defined callback function (optional) */
124 int (*add_entry_cb)(struct hist_entry_iter *iter,
125 struct addr_location *al, bool single, void *arg);
126};
127
128extern const struct hist_iter_ops hist_iter_normal;
129extern const struct hist_iter_ops hist_iter_branch;
130extern const struct hist_iter_ops hist_iter_mem;
131extern const struct hist_iter_ops hist_iter_cumulative;
132
96struct hist_entry *__hists__add_entry(struct hists *hists, 133struct hist_entry *__hists__add_entry(struct hists *hists,
97 struct addr_location *al, 134 struct addr_location *al,
98 struct symbol *parent, 135 struct symbol *parent,
99 struct branch_info *bi, 136 struct branch_info *bi,
100 struct mem_info *mi, u64 period, 137 struct mem_info *mi, u64 period,
101 u64 weight, u64 transaction); 138 u64 weight, u64 transaction,
139 bool sample_self);
140int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
141 struct perf_evsel *evsel, struct perf_sample *sample,
142 int max_stack_depth, void *arg);
143
102int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 144int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
103int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 145int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
104int hist_entry__transaction_len(void); 146int hist_entry__transaction_len(void);
@@ -112,8 +154,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
112void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 154void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
113void hists__output_recalc_col_len(struct hists *hists, int max_rows); 155void hists__output_recalc_col_len(struct hists *hists, int max_rows);
114 156
115void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 157u64 hists__total_period(struct hists *hists);
158void hists__reset_stats(struct hists *hists);
159void hists__inc_stats(struct hists *hists, struct hist_entry *h);
116void hists__inc_nr_events(struct hists *hists, u32 type); 160void hists__inc_nr_events(struct hists *hists, u32 type);
161void hists__inc_nr_samples(struct hists *hists, bool filtered);
117void events_stats__inc(struct events_stats *stats, u32 type); 162void events_stats__inc(struct events_stats *stats, u32 type);
118size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 163size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
119 164
@@ -124,6 +169,12 @@ void hists__filter_by_dso(struct hists *hists);
124void hists__filter_by_thread(struct hists *hists); 169void hists__filter_by_thread(struct hists *hists);
125void hists__filter_by_symbol(struct hists *hists); 170void hists__filter_by_symbol(struct hists *hists);
126 171
172static inline bool hists__has_filter(struct hists *hists)
173{
174 return hists->thread_filter || hists->dso_filter ||
175 hists->symbol_filter_str;
176}
177
127u16 hists__col_len(struct hists *hists, enum hist_column col); 178u16 hists__col_len(struct hists *hists, enum hist_column col);
128void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len); 179void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len);
129bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len); 180bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len);
@@ -149,15 +200,30 @@ struct perf_hpp_fmt {
149 struct hist_entry *he); 200 struct hist_entry *he);
150 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 201 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
151 struct hist_entry *he); 202 struct hist_entry *he);
203 int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b);
204 int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b);
205 int64_t (*sort)(struct hist_entry *a, struct hist_entry *b);
152 206
153 struct list_head list; 207 struct list_head list;
208 struct list_head sort_list;
209 bool elide;
154}; 210};
155 211
156extern struct list_head perf_hpp__list; 212extern struct list_head perf_hpp__list;
213extern struct list_head perf_hpp__sort_list;
157 214
158#define perf_hpp__for_each_format(format) \ 215#define perf_hpp__for_each_format(format) \
159 list_for_each_entry(format, &perf_hpp__list, list) 216 list_for_each_entry(format, &perf_hpp__list, list)
160 217
218#define perf_hpp__for_each_format_safe(format, tmp) \
219 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list)
220
221#define perf_hpp__for_each_sort_list(format) \
222 list_for_each_entry(format, &perf_hpp__sort_list, sort_list)
223
224#define perf_hpp__for_each_sort_list_safe(format, tmp) \
225 list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list)
226
161extern struct perf_hpp_fmt perf_hpp__format[]; 227extern struct perf_hpp_fmt perf_hpp__format[];
162 228
163enum { 229enum {
@@ -167,6 +233,7 @@ enum {
167 PERF_HPP__OVERHEAD_US, 233 PERF_HPP__OVERHEAD_US,
168 PERF_HPP__OVERHEAD_GUEST_SYS, 234 PERF_HPP__OVERHEAD_GUEST_SYS,
169 PERF_HPP__OVERHEAD_GUEST_US, 235 PERF_HPP__OVERHEAD_GUEST_US,
236 PERF_HPP__OVERHEAD_ACC,
170 PERF_HPP__SAMPLES, 237 PERF_HPP__SAMPLES,
171 PERF_HPP__PERIOD, 238 PERF_HPP__PERIOD,
172 239
@@ -175,15 +242,36 @@ enum {
175 242
176void perf_hpp__init(void); 243void perf_hpp__init(void);
177void perf_hpp__column_register(struct perf_hpp_fmt *format); 244void perf_hpp__column_register(struct perf_hpp_fmt *format);
245void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
178void perf_hpp__column_enable(unsigned col); 246void perf_hpp__column_enable(unsigned col);
247void perf_hpp__column_disable(unsigned col);
248void perf_hpp__cancel_cumulate(void);
249
250void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
251void perf_hpp__setup_output_field(void);
252void perf_hpp__reset_output_field(void);
253void perf_hpp__append_sort_keys(void);
254
255bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
256bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
257
258static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
259{
260 return format->elide;
261}
262
263void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
179 264
180typedef u64 (*hpp_field_fn)(struct hist_entry *he); 265typedef u64 (*hpp_field_fn)(struct hist_entry *he);
181typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); 266typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
182typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); 267typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
183 268
184int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 269int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
185 hpp_field_fn get_field, hpp_callback_fn callback, 270 hpp_field_fn get_field, const char *fmt,
186 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent); 271 hpp_snprint_fn print_fn, bool fmt_percent);
272int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
273 hpp_field_fn get_field, const char *fmt,
274 hpp_snprint_fn print_fn, bool fmt_percent);
187 275
188static inline void advance_hpp(struct perf_hpp *hpp, int inc) 276static inline void advance_hpp(struct perf_hpp *hpp, int inc)
189{ 277{
@@ -250,4 +338,10 @@ static inline int script_browse(const char *script_opt __maybe_unused)
250#endif 338#endif
251 339
252unsigned int hists__sort_list_width(struct hists *hists); 340unsigned int hists__sort_list_width(struct hists *hists);
341
342struct option;
343int parse_filter_percentage(const struct option *opt __maybe_unused,
344 const char *arg, int unset __maybe_unused);
345int perf_hist_config(const char *var, const char *value);
346
253#endif /* __PERF_HIST_H */ 347#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index bb162e40c76c..01ffd12dc791 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -4,6 +4,9 @@
4#include <string.h> 4#include <string.h>
5#include <linux/bitops.h> 5#include <linux/bitops.h>
6 6
7#define DECLARE_BITMAP(name,bits) \
8 unsigned long name[BITS_TO_LONGS(bits)]
9
7int __bitmap_weight(const unsigned long *bitmap, int bits); 10int __bitmap_weight(const unsigned long *bitmap, int bits);
8void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, 11void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
9 const unsigned long *bitmap2, int bits); 12 const unsigned long *bitmap2, int bits);
diff --git a/tools/perf/util/include/linux/export.h b/tools/perf/util/include/linux/export.h
deleted file mode 100644
index b43e2dc21e04..000000000000
--- a/tools/perf/util/include/linux/export.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef PERF_LINUX_MODULE_H
2#define PERF_LINUX_MODULE_H
3
4#define EXPORT_SYMBOL(name)
5
6#endif
diff --git a/tools/perf/util/include/linux/list.h b/tools/perf/util/include/linux/list.h
index bfe0a2afd0d2..76ddbc726343 100644
--- a/tools/perf/util/include/linux/list.h
+++ b/tools/perf/util/include/linux/list.h
@@ -1,4 +1,5 @@
1#include <linux/kernel.h> 1#include <linux/kernel.h>
2#include <linux/types.h>
2 3
3#include "../../../../include/linux/list.h" 4#include "../../../../include/linux/list.h"
4 5
diff --git a/tools/perf/util/include/linux/types.h b/tools/perf/util/include/linux/types.h
deleted file mode 100644
index eb464786c084..000000000000
--- a/tools/perf/util/include/linux/types.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef _PERF_LINUX_TYPES_H_
2#define _PERF_LINUX_TYPES_H_
3
4#include <asm/types.h>
5
6#ifndef __bitwise
7#define __bitwise
8#endif
9
10#ifndef __le32
11typedef __u32 __bitwise __le32;
12#endif
13
14#define DECLARE_BITMAP(name,bits) \
15 unsigned long name[BITS_TO_LONGS(bits)]
16
17struct list_head {
18 struct list_head *next, *prev;
19};
20
21struct hlist_head {
22 struct hlist_node *first;
23};
24
25struct hlist_node {
26 struct hlist_node *next, **pprev;
27};
28
29#endif
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 27c2a5efe450..c73e1fc12e53 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -316,6 +316,17 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
316 rb_link_node(&th->rb_node, parent, p); 316 rb_link_node(&th->rb_node, parent, p);
317 rb_insert_color(&th->rb_node, &machine->threads); 317 rb_insert_color(&th->rb_node, &machine->threads);
318 machine->last_match = th; 318 machine->last_match = th;
319
320 /*
321 * We have to initialize map_groups separately
322 * after rb tree is updated.
323 *
324 * The reason is that we call machine__findnew_thread
325 * within thread__init_map_groups to find the thread
326 * leader and that would screwed the rb tree.
327 */
328 if (thread__init_map_groups(th, machine))
329 return NULL;
319 } 330 }
320 331
321 return th; 332 return th;
@@ -485,18 +496,6 @@ struct process_args {
485 u64 start; 496 u64 start;
486}; 497};
487 498
488static int symbol__in_kernel(void *arg, const char *name,
489 char type __maybe_unused, u64 start)
490{
491 struct process_args *args = arg;
492
493 if (strchr(name, '['))
494 return 0;
495
496 args->start = start;
497 return 1;
498}
499
500static void machine__get_kallsyms_filename(struct machine *machine, char *buf, 499static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
501 size_t bufsz) 500 size_t bufsz)
502{ 501{
@@ -506,27 +505,41 @@ static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
506 scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); 505 scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir);
507} 506}
508 507
509/* Figure out the start address of kernel map from /proc/kallsyms */ 508const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
510static u64 machine__get_kernel_start_addr(struct machine *machine) 509
510/* Figure out the start address of kernel map from /proc/kallsyms.
511 * Returns the name of the start symbol in *symbol_name. Pass in NULL as
512 * symbol_name if it's not that important.
513 */
514static u64 machine__get_kernel_start_addr(struct machine *machine,
515 const char **symbol_name)
511{ 516{
512 char filename[PATH_MAX]; 517 char filename[PATH_MAX];
513 struct process_args args; 518 int i;
519 const char *name;
520 u64 addr = 0;
514 521
515 machine__get_kallsyms_filename(machine, filename, PATH_MAX); 522 machine__get_kallsyms_filename(machine, filename, PATH_MAX);
516 523
517 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 524 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
518 return 0; 525 return 0;
519 526
520 if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) 527 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
521 return 0; 528 addr = kallsyms__get_function_start(filename, name);
529 if (addr)
530 break;
531 }
522 532
523 return args.start; 533 if (symbol_name)
534 *symbol_name = name;
535
536 return addr;
524} 537}
525 538
526int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 539int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
527{ 540{
528 enum map_type type; 541 enum map_type type;
529 u64 start = machine__get_kernel_start_addr(machine); 542 u64 start = machine__get_kernel_start_addr(machine, NULL);
530 543
531 for (type = 0; type < MAP__NR_TYPES; ++type) { 544 for (type = 0; type < MAP__NR_TYPES; ++type) {
532 struct kmap *kmap; 545 struct kmap *kmap;
@@ -841,23 +854,11 @@ static int machine__create_modules(struct machine *machine)
841 return 0; 854 return 0;
842} 855}
843 856
844const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
845
846int machine__create_kernel_maps(struct machine *machine) 857int machine__create_kernel_maps(struct machine *machine)
847{ 858{
848 struct dso *kernel = machine__get_kernel(machine); 859 struct dso *kernel = machine__get_kernel(machine);
849 char filename[PATH_MAX];
850 const char *name; 860 const char *name;
851 u64 addr = 0; 861 u64 addr = machine__get_kernel_start_addr(machine, &name);
852 int i;
853
854 machine__get_kallsyms_filename(machine, filename, PATH_MAX);
855
856 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
857 addr = kallsyms__get_function_start(filename, name);
858 if (addr)
859 break;
860 }
861 if (!addr) 862 if (!addr)
862 return -1; 863 return -1;
863 864
@@ -1049,6 +1050,8 @@ int machine__process_mmap2_event(struct machine *machine,
1049 event->mmap2.pid, event->mmap2.maj, 1050 event->mmap2.pid, event->mmap2.maj,
1050 event->mmap2.min, event->mmap2.ino, 1051 event->mmap2.min, event->mmap2.ino,
1051 event->mmap2.ino_generation, 1052 event->mmap2.ino_generation,
1053 event->mmap2.prot,
1054 event->mmap2.flags,
1052 event->mmap2.filename, type); 1055 event->mmap2.filename, type);
1053 1056
1054 if (map == NULL) 1057 if (map == NULL)
@@ -1094,7 +1097,7 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1094 1097
1095 map = map__new(&machine->user_dsos, event->mmap.start, 1098 map = map__new(&machine->user_dsos, event->mmap.start,
1096 event->mmap.len, event->mmap.pgoff, 1099 event->mmap.len, event->mmap.pgoff,
1097 event->mmap.pid, 0, 0, 0, 0, 1100 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1098 event->mmap.filename, 1101 event->mmap.filename,
1099 type); 1102 type);
1100 1103
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 39cd2d0faff6..25c571f4cba6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -32,6 +32,93 @@ static inline int is_no_dso_memory(const char *filename)
32 !strcmp(filename, "[heap]"); 32 !strcmp(filename, "[heap]");
33} 33}
34 34
35static inline int is_android_lib(const char *filename)
36{
37 return !strncmp(filename, "/data/app-lib", 13) ||
38 !strncmp(filename, "/system/lib", 11);
39}
40
41static inline bool replace_android_lib(const char *filename, char *newfilename)
42{
43 const char *libname;
44 char *app_abi;
45 size_t app_abi_length, new_length;
46 size_t lib_length = 0;
47
48 libname = strrchr(filename, '/');
49 if (libname)
50 lib_length = strlen(libname);
51
52 app_abi = getenv("APP_ABI");
53 if (!app_abi)
54 return false;
55
56 app_abi_length = strlen(app_abi);
57
58 if (!strncmp(filename, "/data/app-lib", 13)) {
59 char *apk_path;
60
61 if (!app_abi_length)
62 return false;
63
64 new_length = 7 + app_abi_length + lib_length;
65
66 apk_path = getenv("APK_PATH");
67 if (apk_path) {
68 new_length += strlen(apk_path) + 1;
69 if (new_length > PATH_MAX)
70 return false;
71 snprintf(newfilename, new_length,
72 "%s/libs/%s/%s", apk_path, app_abi, libname);
73 } else {
74 if (new_length > PATH_MAX)
75 return false;
76 snprintf(newfilename, new_length,
77 "libs/%s/%s", app_abi, libname);
78 }
79 return true;
80 }
81
82 if (!strncmp(filename, "/system/lib/", 11)) {
83 char *ndk, *app;
84 const char *arch;
85 size_t ndk_length;
86 size_t app_length;
87
88 ndk = getenv("NDK_ROOT");
89 app = getenv("APP_PLATFORM");
90
91 if (!(ndk && app))
92 return false;
93
94 ndk_length = strlen(ndk);
95 app_length = strlen(app);
96
97 if (!(ndk_length && app_length && app_abi_length))
98 return false;
99
100 arch = !strncmp(app_abi, "arm", 3) ? "arm" :
101 !strncmp(app_abi, "mips", 4) ? "mips" :
102 !strncmp(app_abi, "x86", 3) ? "x86" : NULL;
103
104 if (!arch)
105 return false;
106
107 new_length = 27 + ndk_length +
108 app_length + lib_length
109 + strlen(arch);
110
111 if (new_length > PATH_MAX)
112 return false;
113 snprintf(newfilename, new_length,
114 "%s/platforms/%s/arch-%s/usr/lib/%s",
115 ndk, app, arch, libname);
116
117 return true;
118 }
119 return false;
120}
121
35void map__init(struct map *map, enum map_type type, 122void map__init(struct map *map, enum map_type type,
36 u64 start, u64 end, u64 pgoff, struct dso *dso) 123 u64 start, u64 end, u64 pgoff, struct dso *dso)
37{ 124{
@@ -51,7 +138,7 @@ void map__init(struct map *map, enum map_type type,
51 138
52struct 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,
53 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,
54 u64 ino_gen, char *filename, 141 u64 ino_gen, u32 prot, u32 flags, char *filename,
55 enum map_type type) 142 enum map_type type)
56{ 143{
57 struct map *map = malloc(sizeof(*map)); 144 struct map *map = malloc(sizeof(*map));
@@ -59,8 +146,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
59 if (map != NULL) { 146 if (map != NULL) {
60 char newfilename[PATH_MAX]; 147 char newfilename[PATH_MAX];
61 struct dso *dso; 148 struct dso *dso;
62 int anon, no_dso, vdso; 149 int anon, no_dso, vdso, android;
63 150
151 android = is_android_lib(filename);
64 anon = is_anon_memory(filename); 152 anon = is_anon_memory(filename);
65 vdso = is_vdso_map(filename); 153 vdso = is_vdso_map(filename);
66 no_dso = is_no_dso_memory(filename); 154 no_dso = is_no_dso_memory(filename);
@@ -69,12 +157,19 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
69 map->min = d_min; 157 map->min = d_min;
70 map->ino = ino; 158 map->ino = ino;
71 map->ino_generation = ino_gen; 159 map->ino_generation = ino_gen;
160 map->prot = prot;
161 map->flags = flags;
72 162
73 if ((anon || no_dso) && type == MAP__FUNCTION) { 163 if ((anon || no_dso) && type == MAP__FUNCTION) {
74 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid); 164 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
75 filename = newfilename; 165 filename = newfilename;
76 } 166 }
77 167
168 if (android) {
169 if (replace_android_lib(filename, newfilename))
170 filename = newfilename;
171 }
172
78 if (vdso) { 173 if (vdso) {
79 pgoff = 0; 174 pgoff = 0;
80 dso = vdso__dso_findnew(dsos__list); 175 dso = vdso__dso_findnew(dsos__list);
@@ -323,6 +418,7 @@ void map_groups__init(struct map_groups *mg)
323 INIT_LIST_HEAD(&mg->removed_maps[i]); 418 INIT_LIST_HEAD(&mg->removed_maps[i]);
324 } 419 }
325 mg->machine = NULL; 420 mg->machine = NULL;
421 mg->refcnt = 1;
326} 422}
327 423
328static void maps__delete(struct rb_root *maps) 424static void maps__delete(struct rb_root *maps)
@@ -358,6 +454,28 @@ void map_groups__exit(struct map_groups *mg)
358 } 454 }
359} 455}
360 456
457struct map_groups *map_groups__new(void)
458{
459 struct map_groups *mg = malloc(sizeof(*mg));
460
461 if (mg != NULL)
462 map_groups__init(mg);
463
464 return mg;
465}
466
467void map_groups__delete(struct map_groups *mg)
468{
469 map_groups__exit(mg);
470 free(mg);
471}
472
473void map_groups__put(struct map_groups *mg)
474{
475 if (--mg->refcnt == 0)
476 map_groups__delete(mg);
477}
478
361void map_groups__flush(struct map_groups *mg) 479void map_groups__flush(struct map_groups *mg)
362{ 480{
363 int type; 481 int type;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f00f058afb3b..7758c72522ef 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -6,7 +6,7 @@
6#include <linux/rbtree.h> 6#include <linux/rbtree.h>
7#include <stdio.h> 7#include <stdio.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include <linux/types.h>
10 10
11enum map_type { 11enum map_type {
12 MAP__FUNCTION = 0, 12 MAP__FUNCTION = 0,
@@ -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 */
@@ -59,8 +61,20 @@ struct map_groups {
59 struct rb_root maps[MAP__NR_TYPES]; 61 struct rb_root maps[MAP__NR_TYPES];
60 struct list_head removed_maps[MAP__NR_TYPES]; 62 struct list_head removed_maps[MAP__NR_TYPES];
61 struct machine *machine; 63 struct machine *machine;
64 int refcnt;
62}; 65};
63 66
67struct map_groups *map_groups__new(void);
68void map_groups__delete(struct map_groups *mg);
69
70static inline struct map_groups *map_groups__get(struct map_groups *mg)
71{
72 ++mg->refcnt;
73 return mg;
74}
75
76void map_groups__put(struct map_groups *mg);
77
64static inline struct kmap *map__kmap(struct map *map) 78static inline struct kmap *map__kmap(struct map *map)
65{ 79{
66 return (struct kmap *)(map + 1); 80 return (struct kmap *)(map + 1);
@@ -106,7 +120,7 @@ void map__init(struct map *map, enum map_type type,
106 u64 start, u64 end, u64 pgoff, struct dso *dso); 120 u64 start, u64 end, u64 pgoff, struct dso *dso);
107struct 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,
108 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,
109 u64 ino_gen, 123 u64 ino_gen, u32 prot, u32 flags,
110 char *filename, enum map_type type); 124 char *filename, enum map_type type);
111struct 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);
112void map__delete(struct map *map); 126void map__delete(struct map *map);
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index 3322b8446e89..31ee02d4e988 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -57,13 +57,13 @@ void setup_pager(void)
57 } 57 }
58 if (!pager) 58 if (!pager)
59 pager = getenv("PAGER"); 59 pager = getenv("PAGER");
60 if (!pager) { 60 if (!(pager || access("/usr/bin/pager", X_OK)))
61 if (!access("/usr/bin/pager", X_OK)) 61 pager = "/usr/bin/pager";
62 pager = "/usr/bin/pager"; 62 if (!(pager || access("/usr/bin/less", X_OK)))
63 } 63 pager = "/usr/bin/less";
64 if (!pager) 64 if (!pager)
65 pager = "less"; 65 pager = "cat";
66 else if (!*pager || !strcmp(pager, "cat")) 66 if (!*pager || !strcmp(pager, "cat"))
67 return; 67 return;
68 68
69 spawned_pager = 1; /* means we are emitting to terminal */ 69 spawned_pager = 1; /* means we are emitting to terminal */
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index f1cb4c4b3c70..df094b4ed5ed 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -6,9 +6,8 @@
6 6
7#include <linux/list.h> 7#include <linux/list.h>
8#include <stdbool.h> 8#include <stdbool.h>
9#include "types.h" 9#include <linux/types.h>
10#include <linux/perf_event.h> 10#include <linux/perf_event.h>
11#include "types.h"
12 11
13struct list_head; 12struct list_head;
14struct perf_evsel; 13struct perf_evsel;
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 4eb67ec333f1..0bc87ba46bf3 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -9,7 +9,7 @@
9 9
10#include <linux/compiler.h> 10#include <linux/compiler.h>
11#include <linux/list.h> 11#include <linux/list.h>
12#include "types.h" 12#include <linux/types.h>
13#include "util.h" 13#include "util.h"
14#include "parse-events.h" 14#include "parse-events.h"
15#include "parse-events-bison.h" 15#include "parse-events-bison.h"
@@ -299,6 +299,18 @@ PE_PREFIX_MEM PE_VALUE sep_dc
299} 299}
300 300
301event_legacy_tracepoint: 301event_legacy_tracepoint:
302PE_NAME '-' PE_NAME ':' PE_NAME
303{
304 struct parse_events_evlist *data = _data;
305 struct list_head *list;
306 char sys_name[128];
307 snprintf(&sys_name, 128, "%s-%s", $1, $3);
308
309 ALLOC_LIST(list);
310 ABORT_ON(parse_events_add_tracepoint(list, &data->idx, &sys_name, $5));
311 $$ = list;
312}
313|
302PE_NAME ':' PE_NAME 314PE_NAME ':' PE_NAME
303{ 315{
304 struct parse_events_evlist *data = _data; 316 struct parse_events_evlist *data = _data;
diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c
index a3539ef30b15..43168fb0d9a2 100644
--- a/tools/perf/util/perf_regs.c
+++ b/tools/perf/util/perf_regs.c
@@ -1,11 +1,15 @@
1#include <errno.h> 1#include <errno.h>
2#include "perf_regs.h" 2#include "perf_regs.h"
3#include "event.h"
3 4
4int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) 5int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
5{ 6{
6 int i, idx = 0; 7 int i, idx = 0;
7 u64 mask = regs->mask; 8 u64 mask = regs->mask;
8 9
10 if (regs->cache_mask & (1 << id))
11 goto out;
12
9 if (!(mask & (1 << id))) 13 if (!(mask & (1 << id)))
10 return -EINVAL; 14 return -EINVAL;
11 15
@@ -14,6 +18,10 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id)
14 idx++; 18 idx++;
15 } 19 }
16 20
17 *valp = regs->regs[idx]; 21 regs->cache_mask |= (1 << id);
22 regs->cache_regs[id] = regs->regs[idx];
23
24out:
25 *valp = regs->cache_regs[id];
18 return 0; 26 return 0;
19} 27}
diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h
index d6e8b6a8d7f3..980dbf76bc98 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,8 +1,9 @@
1#ifndef __PERF_REGS_H 1#ifndef __PERF_REGS_H
2#define __PERF_REGS_H 2#define __PERF_REGS_H
3 3
4#include "types.h" 4#include <linux/types.h>
5#include "event.h" 5
6struct regs_dump;
6 7
7#ifdef HAVE_PERF_REGS_SUPPORT 8#ifdef HAVE_PERF_REGS_SUPPORT
8#include <perf_regs.h> 9#include <perf_regs.h>
@@ -11,6 +12,7 @@ int perf_reg_value(u64 *valp, struct regs_dump *regs, int id);
11 12
12#else 13#else
13#define PERF_REGS_MASK 0 14#define PERF_REGS_MASK 0
15#define PERF_REGS_MAX 0
14 16
15static inline const char *perf_reg_name(int id __maybe_unused) 17static inline const char *perf_reg_name(int id __maybe_unused)
16{ 18{
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 00a7dcb2f55c..7a811eb61f75 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -284,17 +284,17 @@ static int pmu_aliases(const char *name, struct list_head *head)
284static int pmu_alias_terms(struct perf_pmu_alias *alias, 284static int pmu_alias_terms(struct perf_pmu_alias *alias,
285 struct list_head *terms) 285 struct list_head *terms)
286{ 286{
287 struct parse_events_term *term, *clone; 287 struct parse_events_term *term, *cloned;
288 LIST_HEAD(list); 288 LIST_HEAD(list);
289 int ret; 289 int ret;
290 290
291 list_for_each_entry(term, &alias->terms, list) { 291 list_for_each_entry(term, &alias->terms, list) {
292 ret = parse_events_term__clone(&clone, term); 292 ret = parse_events_term__clone(&cloned, term);
293 if (ret) { 293 if (ret) {
294 parse_events__free_terms(&list); 294 parse_events__free_terms(&list);
295 return ret; 295 return ret;
296 } 296 }
297 list_add_tail(&clone->list, &list); 297 list_add_tail(&cloned->list, &list);
298 } 298 }
299 list_splice(&list, terms); 299 list_splice(&list, terms);
300 return 0; 300 return 0;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 8b64125a9281..c14a543ce1f3 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -1,7 +1,7 @@
1#ifndef __PMU_H 1#ifndef __PMU_H
2#define __PMU_H 2#define __PMU_H
3 3
4#include <linux/bitops.h> 4#include <linux/bitmap.h>
5#include <linux/perf_event.h> 5#include <linux/perf_event.h>
6#include <stdbool.h> 6#include <stdbool.h>
7 7
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 0d1542f33d87..9a0a1839a377 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -628,11 +628,11 @@ static int __show_line_range(struct line_range *lr, const char *module)
628 628
629 ret = debuginfo__find_line_range(dinfo, lr); 629 ret = debuginfo__find_line_range(dinfo, lr);
630 debuginfo__delete(dinfo); 630 debuginfo__delete(dinfo);
631 if (ret == 0) { 631 if (ret == 0 || ret == -ENOENT) {
632 pr_warning("Specified source line is not found.\n"); 632 pr_warning("Specified source line is not found.\n");
633 return -ENOENT; 633 return -ENOENT;
634 } else if (ret < 0) { 634 } else if (ret < 0) {
635 pr_warning("Debuginfo analysis failed. (%d)\n", ret); 635 pr_warning("Debuginfo analysis failed.\n");
636 return ret; 636 return ret;
637 } 637 }
638 638
@@ -641,7 +641,7 @@ static int __show_line_range(struct line_range *lr, const char *module)
641 ret = get_real_path(tmp, lr->comp_dir, &lr->path); 641 ret = get_real_path(tmp, lr->comp_dir, &lr->path);
642 free(tmp); /* Free old path */ 642 free(tmp); /* Free old path */
643 if (ret < 0) { 643 if (ret < 0) {
644 pr_warning("Failed to find source file. (%d)\n", ret); 644 pr_warning("Failed to find source file path.\n");
645 return ret; 645 return ret;
646 } 646 }
647 647
@@ -721,9 +721,14 @@ static int show_available_vars_at(struct debuginfo *dinfo,
721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 721 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
722 max_vls, externs); 722 max_vls, externs);
723 if (ret <= 0) { 723 if (ret <= 0) {
724 pr_err("Failed to find variables at %s (%d)\n", buf, ret); 724 if (ret == 0 || ret == -ENOENT) {
725 pr_err("Failed to find the address of %s\n", buf);
726 ret = -ENOENT;
727 } else
728 pr_warning("Debuginfo analysis failed.\n");
725 goto end; 729 goto end;
726 } 730 }
731
727 /* Some variables are found */ 732 /* Some variables are found */
728 fprintf(stdout, "Available variables at %s\n", buf); 733 fprintf(stdout, "Available variables at %s\n", buf);
729 for (i = 0; i < ret; i++) { 734 for (i = 0; i < ret; i++) {
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 562762117639..98e304766416 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -511,12 +511,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
511 511
512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, 512 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
513 &pf->sp_die, pf->tvar); 513 &pf->sp_die, pf->tvar);
514 if (ret == -ENOENT) 514 if (ret == -ENOENT || ret == -EINVAL)
515 pr_err("Failed to find the location of %s at this address.\n" 515 pr_err("Failed to find the location of %s at this address.\n"
516 " Perhaps, it has been optimized out.\n", pf->pvar->var); 516 " Perhaps, it has been optimized out.\n", pf->pvar->var);
517 else if (ret == -ENOTSUP) 517 else if (ret == -ENOTSUP)
518 pr_err("Sorry, we don't support this variable location yet.\n"); 518 pr_err("Sorry, we don't support this variable location yet.\n");
519 else if (pf->pvar->field) { 519 else if (ret == 0 && pf->pvar->field) {
520 ret = convert_variable_fields(vr_die, pf->pvar->var, 520 ret = convert_variable_fields(vr_die, pf->pvar->var,
521 pf->pvar->field, &pf->tvar->ref, 521 pf->pvar->field, &pf->tvar->ref,
522 &die_mem); 522 &die_mem);
@@ -573,14 +573,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { 573 if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) {
574 /* Search again in global variables */ 574 /* Search again in global variables */
575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) 575 if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die))
576 pr_warning("Failed to find '%s' in this function.\n",
577 pf->pvar->var);
576 ret = -ENOENT; 578 ret = -ENOENT;
577 } 579 }
578 if (ret >= 0) 580 if (ret >= 0)
579 ret = convert_variable(&vr_die, pf); 581 ret = convert_variable(&vr_die, pf);
580 582
581 if (ret < 0)
582 pr_warning("Failed to find '%s' in this function.\n",
583 pf->pvar->var);
584 return ret; 583 return ret;
585} 584}
586 585
@@ -1281,7 +1280,11 @@ out:
1281 return ret; 1280 return ret;
1282} 1281}
1283 1282
1284/* Find available variables at given probe point */ 1283/*
1284 * Find available variables at given probe point
1285 * Return the number of found probe points. Return 0 if there is no
1286 * matched probe point. Return <0 if an error occurs.
1287 */
1285int debuginfo__find_available_vars_at(struct debuginfo *dbg, 1288int debuginfo__find_available_vars_at(struct debuginfo *dbg,
1286 struct perf_probe_event *pev, 1289 struct perf_probe_event *pev,
1287 struct variable_list **vls, 1290 struct variable_list **vls,
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/session.c b/tools/perf/util/session.c
index 55960f22233c..64a186edc7be 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -1625,13 +1625,14 @@ out_delete_map:
1625void perf_session__fprintf_info(struct perf_session *session, FILE *fp, 1625void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
1626 bool full) 1626 bool full)
1627{ 1627{
1628 int fd = perf_data_file__fd(session->file);
1629 struct stat st; 1628 struct stat st;
1630 int ret; 1629 int fd, ret;
1631 1630
1632 if (session == NULL || fp == NULL) 1631 if (session == NULL || fp == NULL)
1633 return; 1632 return;
1634 1633
1634 fd = perf_data_file__fd(session->file);
1635
1635 ret = fstat(fd, &st); 1636 ret = fstat(fd, &st);
1636 if (ret == -1) 1637 if (ret == -1)
1637 return; 1638 return;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 635cd8f8b22e..1ec57dd82284 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1,13 +1,20 @@
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"
4#include "symbol.h" 5#include "symbol.h"
6#include "evsel.h"
5 7
6regex_t parent_regex; 8regex_t parent_regex;
7const char default_parent_pattern[] = "^sys_|^do_page_fault"; 9const char default_parent_pattern[] = "^sys_|^do_page_fault";
8const char *parent_pattern = default_parent_pattern; 10const char *parent_pattern = default_parent_pattern;
9const char default_sort_order[] = "comm,dso,symbol"; 11const char default_sort_order[] = "comm,dso,symbol";
10const char *sort_order = default_sort_order; 12const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
13const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
14const char default_top_sort_order[] = "dso,symbol";
15const char default_diff_sort_order[] = "dso,symbol";
16const char *sort_order;
17const char *field_order;
11regex_t ignore_callees_regex; 18regex_t ignore_callees_regex;
12int have_ignore_callees = 0; 19int have_ignore_callees = 0;
13int sort__need_collapse = 0; 20int sort__need_collapse = 0;
@@ -16,9 +23,6 @@ int sort__has_sym = 0;
16int sort__has_dso = 0; 23int sort__has_dso = 0;
17enum sort_mode sort__mode = SORT_MODE__NORMAL; 24enum sort_mode sort__mode = SORT_MODE__NORMAL;
18 25
19enum sort_type sort__first_dimension;
20
21LIST_HEAD(hist_entry__sort_list);
22 26
23static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 27static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
24{ 28{
@@ -93,6 +97,12 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
93 return comm__str(right->comm) - comm__str(left->comm); 97 return comm__str(right->comm) - comm__str(left->comm);
94} 98}
95 99
100static int64_t
101sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
102{
103 return strcmp(comm__str(right->comm), comm__str(left->comm));
104}
105
96static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 106static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
97 size_t size, unsigned int width) 107 size_t size, unsigned int width)
98{ 108{
@@ -103,6 +113,7 @@ struct sort_entry sort_comm = {
103 .se_header = "Command", 113 .se_header = "Command",
104 .se_cmp = sort__comm_cmp, 114 .se_cmp = sort__comm_cmp,
105 .se_collapse = sort__comm_collapse, 115 .se_collapse = sort__comm_collapse,
116 .se_sort = sort__comm_sort,
106 .se_snprintf = hist_entry__comm_snprintf, 117 .se_snprintf = hist_entry__comm_snprintf,
107 .se_width_idx = HISTC_COMM, 118 .se_width_idx = HISTC_COMM,
108}; 119};
@@ -116,7 +127,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
116 const char *dso_name_l, *dso_name_r; 127 const char *dso_name_l, *dso_name_r;
117 128
118 if (!dso_l || !dso_r) 129 if (!dso_l || !dso_r)
119 return cmp_null(dso_l, dso_r); 130 return cmp_null(dso_r, dso_l);
120 131
121 if (verbose) { 132 if (verbose) {
122 dso_name_l = dso_l->long_name; 133 dso_name_l = dso_l->long_name;
@@ -132,7 +143,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
132static int64_t 143static int64_t
133sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 144sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
134{ 145{
135 return _sort__dso_cmp(left->ms.map, right->ms.map); 146 return _sort__dso_cmp(right->ms.map, left->ms.map);
136} 147}
137 148
138static int _hist_entry__dso_snprintf(struct map *map, char *bf, 149static int _hist_entry__dso_snprintf(struct map *map, char *bf,
@@ -204,6 +215,15 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
204 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 215 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
205} 216}
206 217
218static int64_t
219sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
220{
221 if (!left->ms.sym || !right->ms.sym)
222 return cmp_null(left->ms.sym, right->ms.sym);
223
224 return strcmp(right->ms.sym->name, left->ms.sym->name);
225}
226
207static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 227static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
208 u64 ip, char level, char *bf, size_t size, 228 u64 ip, char level, char *bf, size_t size,
209 unsigned int width) 229 unsigned int width)
@@ -250,6 +270,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
250struct sort_entry sort_sym = { 270struct sort_entry sort_sym = {
251 .se_header = "Symbol", 271 .se_header = "Symbol",
252 .se_cmp = sort__sym_cmp, 272 .se_cmp = sort__sym_cmp,
273 .se_sort = sort__sym_sort,
253 .se_snprintf = hist_entry__sym_snprintf, 274 .se_snprintf = hist_entry__sym_snprintf,
254 .se_width_idx = HISTC_SYMBOL, 275 .se_width_idx = HISTC_SYMBOL,
255}; 276};
@@ -277,7 +298,7 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
277 map__rip_2objdump(map, right->ip)); 298 map__rip_2objdump(map, right->ip));
278 } 299 }
279 } 300 }
280 return strcmp(left->srcline, right->srcline); 301 return strcmp(right->srcline, left->srcline);
281} 302}
282 303
283static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 304static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
@@ -305,7 +326,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
305 if (!sym_l || !sym_r) 326 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r); 327 return cmp_null(sym_l, sym_r);
307 328
308 return strcmp(sym_l->name, sym_r->name); 329 return strcmp(sym_r->name, sym_l->name);
309} 330}
310 331
311static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 332static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
@@ -764,6 +785,104 @@ static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
764 return repsep_snprintf(bf, size, "%-*s", width, out); 785 return repsep_snprintf(bf, size, "%-*s", width, out);
765} 786}
766 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
767struct sort_entry sort_mispredict = { 886struct sort_entry sort_mispredict = {
768 .se_header = "Branch Mispredicted", 887 .se_header = "Branch Mispredicted",
769 .se_cmp = sort__mispredict_cmp, 888 .se_cmp = sort__mispredict_cmp,
@@ -856,6 +975,13 @@ struct sort_entry sort_mem_snoop = {
856 .se_width_idx = HISTC_MEM_SNOOP, 975 .se_width_idx = HISTC_MEM_SNOOP,
857}; 976};
858 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
859static int64_t 985static int64_t
860sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 986sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
861{ 987{
@@ -1023,23 +1149,199 @@ static struct sort_dimension memory_sort_dimensions[] = {
1023 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1149 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1024 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1150 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1025 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),
1153};
1154
1155#undef DIM
1156
1157struct hpp_dimension {
1158 const char *name;
1159 struct perf_hpp_fmt *fmt;
1160 int taken;
1161};
1162
1163#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1164
1165static struct hpp_dimension hpp_sort_dimensions[] = {
1166 DIM(PERF_HPP__OVERHEAD, "overhead"),
1167 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1168 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1169 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1170 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1171 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1172 DIM(PERF_HPP__SAMPLES, "sample"),
1173 DIM(PERF_HPP__PERIOD, "period"),
1026}; 1174};
1027 1175
1028#undef DIM 1176#undef DIM
1029 1177
1030static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx) 1178struct hpp_sort_entry {
1179 struct perf_hpp_fmt hpp;
1180 struct sort_entry *se;
1181};
1182
1183bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1031{ 1184{
1032 if (sd->taken) 1185 struct hpp_sort_entry *hse_a;
1186 struct hpp_sort_entry *hse_b;
1187
1188 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1189 return false;
1190
1191 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1192 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1193
1194 return hse_a->se == hse_b->se;
1195}
1196
1197void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1198{
1199 struct hpp_sort_entry *hse;
1200
1201 if (!perf_hpp__is_sort_entry(fmt))
1033 return; 1202 return;
1034 1203
1204 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1205 hists__new_col_len(hists, hse->se->se_width_idx,
1206 strlen(hse->se->se_header));
1207}
1208
1209static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1210 struct perf_evsel *evsel)
1211{
1212 struct hpp_sort_entry *hse;
1213 size_t len;
1214
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1219}
1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1222 struct perf_hpp *hpp __maybe_unused,
1223 struct perf_evsel *evsel)
1224{
1225 struct hpp_sort_entry *hse;
1226
1227 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1228
1229 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1230}
1231
1232static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1233 struct hist_entry *he)
1234{
1235 struct hpp_sort_entry *hse;
1236 size_t len;
1237
1238 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1239 len = hists__col_len(he->hists, hse->se->se_width_idx);
1240
1241 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1242}
1243
1244static struct hpp_sort_entry *
1245__sort_dimension__alloc_hpp(struct sort_dimension *sd)
1246{
1247 struct hpp_sort_entry *hse;
1248
1249 hse = malloc(sizeof(*hse));
1250 if (hse == NULL) {
1251 pr_err("Memory allocation failed\n");
1252 return NULL;
1253 }
1254
1255 hse->se = sd->entry;
1256 hse->hpp.header = __sort__hpp_header;
1257 hse->hpp.width = __sort__hpp_width;
1258 hse->hpp.entry = __sort__hpp_entry;
1259 hse->hpp.color = NULL;
1260
1261 hse->hpp.cmp = sd->entry->se_cmp;
1262 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1263 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
1264
1265 INIT_LIST_HEAD(&hse->hpp.list);
1266 INIT_LIST_HEAD(&hse->hpp.sort_list);
1267 hse->hpp.elide = false;
1268
1269 return hse;
1270}
1271
1272bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1273{
1274 return format->header == __sort__hpp_header;
1275}
1276
1277static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1278{
1279 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1280
1281 if (hse == NULL)
1282 return -1;
1283
1284 perf_hpp__register_sort_field(&hse->hpp);
1285 return 0;
1286}
1287
1288static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1289{
1290 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1291
1292 if (hse == NULL)
1293 return -1;
1294
1295 perf_hpp__column_register(&hse->hpp);
1296 return 0;
1297}
1298
1299static int __sort_dimension__add(struct sort_dimension *sd)
1300{
1301 if (sd->taken)
1302 return 0;
1303
1304 if (__sort_dimension__add_hpp_sort(sd) < 0)
1305 return -1;
1306
1035 if (sd->entry->se_collapse) 1307 if (sd->entry->se_collapse)
1036 sort__need_collapse = 1; 1308 sort__need_collapse = 1;
1037 1309
1038 if (list_empty(&hist_entry__sort_list)) 1310 sd->taken = 1;
1039 sort__first_dimension = idx; 1311
1312 return 0;
1313}
1314
1315static int __hpp_dimension__add(struct hpp_dimension *hd)
1316{
1317 if (!hd->taken) {
1318 hd->taken = 1;
1319
1320 perf_hpp__register_sort_field(hd->fmt);
1321 }
1322 return 0;
1323}
1324
1325static int __sort_dimension__add_output(struct sort_dimension *sd)
1326{
1327 if (sd->taken)
1328 return 0;
1329
1330 if (__sort_dimension__add_hpp_output(sd) < 0)
1331 return -1;
1040 1332
1041 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1042 sd->taken = 1; 1333 sd->taken = 1;
1334 return 0;
1335}
1336
1337static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1338{
1339 if (!hd->taken) {
1340 hd->taken = 1;
1341
1342 perf_hpp__column_register(hd->fmt);
1343 }
1344 return 0;
1043} 1345}
1044 1346
1045int sort_dimension__add(const char *tok) 1347int sort_dimension__add(const char *tok)
@@ -1068,8 +1370,16 @@ int sort_dimension__add(const char *tok)
1068 sort__has_dso = 1; 1370 sort__has_dso = 1;
1069 } 1371 }
1070 1372
1071 __sort_dimension__add(sd, i); 1373 return __sort_dimension__add(sd);
1072 return 0; 1374 }
1375
1376 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1377 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1378
1379 if (strncasecmp(tok, hd->name, strlen(tok)))
1380 continue;
1381
1382 return __hpp_dimension__add(hd);
1073 } 1383 }
1074 1384
1075 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1385 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -1084,7 +1394,7 @@ int sort_dimension__add(const char *tok)
1084 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 1394 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1085 sort__has_sym = 1; 1395 sort__has_sym = 1;
1086 1396
1087 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK); 1397 __sort_dimension__add(sd);
1088 return 0; 1398 return 0;
1089 } 1399 }
1090 1400
@@ -1100,18 +1410,47 @@ int sort_dimension__add(const char *tok)
1100 if (sd->entry == &sort_mem_daddr_sym) 1410 if (sd->entry == &sort_mem_daddr_sym)
1101 sort__has_sym = 1; 1411 sort__has_sym = 1;
1102 1412
1103 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE); 1413 __sort_dimension__add(sd);
1104 return 0; 1414 return 0;
1105 } 1415 }
1106 1416
1107 return -ESRCH; 1417 return -ESRCH;
1108} 1418}
1109 1419
1110int setup_sorting(void) 1420static const char *get_default_sort_order(void)
1421{
1422 const char *default_sort_orders[] = {
1423 default_sort_order,
1424 default_branch_sort_order,
1425 default_mem_sort_order,
1426 default_top_sort_order,
1427 default_diff_sort_order,
1428 };
1429
1430 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1431
1432 return default_sort_orders[sort__mode];
1433}
1434
1435static int __setup_sorting(void)
1111{ 1436{
1112 char *tmp, *tok, *str = strdup(sort_order); 1437 char *tmp, *tok, *str;
1438 const char *sort_keys = sort_order;
1113 int ret = 0; 1439 int ret = 0;
1114 1440
1441 if (sort_keys == NULL) {
1442 if (field_order) {
1443 /*
1444 * If user specified field order but no sort order,
1445 * we'll honor it and not add default sort orders.
1446 */
1447 return 0;
1448 }
1449
1450 sort_keys = get_default_sort_order();
1451 }
1452
1453 str = strdup(sort_keys);
1115 if (str == NULL) { 1454 if (str == NULL) {
1116 error("Not enough memory to setup sort keys"); 1455 error("Not enough memory to setup sort keys");
1117 return -ENOMEM; 1456 return -ENOMEM;
@@ -1133,66 +1472,235 @@ int setup_sorting(void)
1133 return ret; 1472 return ret;
1134} 1473}
1135 1474
1136static void sort_entry__setup_elide(struct sort_entry *se, 1475void perf_hpp__set_elide(int idx, bool elide)
1137 struct strlist *list, 1476{
1138 const char *list_name, FILE *fp) 1477 struct perf_hpp_fmt *fmt;
1478 struct hpp_sort_entry *hse;
1479
1480 perf_hpp__for_each_format(fmt) {
1481 if (!perf_hpp__is_sort_entry(fmt))
1482 continue;
1483
1484 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1485 if (hse->se->se_width_idx == idx) {
1486 fmt->elide = elide;
1487 break;
1488 }
1489 }
1490}
1491
1492static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
1139{ 1493{
1140 if (list && strlist__nr_entries(list) == 1) { 1494 if (list && strlist__nr_entries(list) == 1) {
1141 if (fp != NULL) 1495 if (fp != NULL)
1142 fprintf(fp, "# %s: %s\n", list_name, 1496 fprintf(fp, "# %s: %s\n", list_name,
1143 strlist__entry(list, 0)->s); 1497 strlist__entry(list, 0)->s);
1144 se->elide = true; 1498 return true;
1145 } 1499 }
1500 return false;
1501}
1502
1503static bool get_elide(int idx, FILE *output)
1504{
1505 switch (idx) {
1506 case HISTC_SYMBOL:
1507 return __get_elide(symbol_conf.sym_list, "symbol", output);
1508 case HISTC_DSO:
1509 return __get_elide(symbol_conf.dso_list, "dso", output);
1510 case HISTC_COMM:
1511 return __get_elide(symbol_conf.comm_list, "comm", output);
1512 default:
1513 break;
1514 }
1515
1516 if (sort__mode != SORT_MODE__BRANCH)
1517 return false;
1518
1519 switch (idx) {
1520 case HISTC_SYMBOL_FROM:
1521 return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
1522 case HISTC_SYMBOL_TO:
1523 return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
1524 case HISTC_DSO_FROM:
1525 return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
1526 case HISTC_DSO_TO:
1527 return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
1528 default:
1529 break;
1530 }
1531
1532 return false;
1146} 1533}
1147 1534
1148void sort__setup_elide(FILE *output) 1535void sort__setup_elide(FILE *output)
1149{ 1536{
1150 struct sort_entry *se; 1537 struct perf_hpp_fmt *fmt;
1538 struct hpp_sort_entry *hse;
1539
1540 perf_hpp__for_each_format(fmt) {
1541 if (!perf_hpp__is_sort_entry(fmt))
1542 continue;
1151 1543
1152 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1544 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1153 "dso", output); 1545 fmt->elide = get_elide(hse->se->se_width_idx, output);
1154 sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list,
1155 "comm", output);
1156 sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list,
1157 "symbol", output);
1158
1159 if (sort__mode == SORT_MODE__BRANCH) {
1160 sort_entry__setup_elide(&sort_dso_from,
1161 symbol_conf.dso_from_list,
1162 "dso_from", output);
1163 sort_entry__setup_elide(&sort_dso_to,
1164 symbol_conf.dso_to_list,
1165 "dso_to", output);
1166 sort_entry__setup_elide(&sort_sym_from,
1167 symbol_conf.sym_from_list,
1168 "sym_from", output);
1169 sort_entry__setup_elide(&sort_sym_to,
1170 symbol_conf.sym_to_list,
1171 "sym_to", output);
1172 } else if (sort__mode == SORT_MODE__MEMORY) {
1173 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1174 "symbol_daddr", output);
1175 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1176 "dso_daddr", output);
1177 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1178 "mem", output);
1179 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1180 "local_weight", output);
1181 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1182 "tlb", output);
1183 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1184 "snoop", output);
1185 } 1546 }
1186 1547
1187 /* 1548 /*
1188 * It makes no sense to elide all of sort entries. 1549 * It makes no sense to elide all of sort entries.
1189 * Just revert them to show up again. 1550 * Just revert them to show up again.
1190 */ 1551 */
1191 list_for_each_entry(se, &hist_entry__sort_list, list) { 1552 perf_hpp__for_each_format(fmt) {
1192 if (!se->elide) 1553 if (!perf_hpp__is_sort_entry(fmt))
1554 continue;
1555
1556 if (!fmt->elide)
1193 return; 1557 return;
1194 } 1558 }
1195 1559
1196 list_for_each_entry(se, &hist_entry__sort_list, list) 1560 perf_hpp__for_each_format(fmt) {
1197 se->elide = false; 1561 if (!perf_hpp__is_sort_entry(fmt))
1562 continue;
1563
1564 fmt->elide = false;
1565 }
1566}
1567
1568static int output_field_add(char *tok)
1569{
1570 unsigned int i;
1571
1572 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1573 struct sort_dimension *sd = &common_sort_dimensions[i];
1574
1575 if (strncasecmp(tok, sd->name, strlen(tok)))
1576 continue;
1577
1578 return __sort_dimension__add_output(sd);
1579 }
1580
1581 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1582 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1583
1584 if (strncasecmp(tok, hd->name, strlen(tok)))
1585 continue;
1586
1587 return __hpp_dimension__add_output(hd);
1588 }
1589
1590 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1591 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1592
1593 if (strncasecmp(tok, sd->name, strlen(tok)))
1594 continue;
1595
1596 return __sort_dimension__add_output(sd);
1597 }
1598
1599 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1600 struct sort_dimension *sd = &memory_sort_dimensions[i];
1601
1602 if (strncasecmp(tok, sd->name, strlen(tok)))
1603 continue;
1604
1605 return __sort_dimension__add_output(sd);
1606 }
1607
1608 return -ESRCH;
1609}
1610
1611static void reset_dimensions(void)
1612{
1613 unsigned int i;
1614
1615 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1616 common_sort_dimensions[i].taken = 0;
1617
1618 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1619 hpp_sort_dimensions[i].taken = 0;
1620
1621 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1622 bstack_sort_dimensions[i].taken = 0;
1623
1624 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1625 memory_sort_dimensions[i].taken = 0;
1626}
1627
1628static int __setup_output_field(void)
1629{
1630 char *tmp, *tok, *str;
1631 int ret = 0;
1632
1633 if (field_order == NULL)
1634 return 0;
1635
1636 reset_dimensions();
1637
1638 str = strdup(field_order);
1639 if (str == NULL) {
1640 error("Not enough memory to setup output fields");
1641 return -ENOMEM;
1642 }
1643
1644 for (tok = strtok_r(str, ", ", &tmp);
1645 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1646 ret = output_field_add(tok);
1647 if (ret == -EINVAL) {
1648 error("Invalid --fields key: `%s'", tok);
1649 break;
1650 } else if (ret == -ESRCH) {
1651 error("Unknown --fields key: `%s'", tok);
1652 break;
1653 }
1654 }
1655
1656 free(str);
1657 return ret;
1658}
1659
1660int setup_sorting(void)
1661{
1662 int err;
1663
1664 err = __setup_sorting();
1665 if (err < 0)
1666 return err;
1667
1668 if (parent_pattern != default_parent_pattern) {
1669 err = sort_dimension__add("parent");
1670 if (err < 0)
1671 return err;
1672 }
1673
1674 reset_dimensions();
1675
1676 /*
1677 * perf diff doesn't use default hpp output fields.
1678 */
1679 if (sort__mode != SORT_MODE__DIFF)
1680 perf_hpp__init();
1681
1682 err = __setup_output_field();
1683 if (err < 0)
1684 return err;
1685
1686 /* copy sort keys to output fields */
1687 perf_hpp__setup_output_field();
1688 /* and then copy output fields to sort keys */
1689 perf_hpp__append_sort_keys();
1690
1691 return 0;
1692}
1693
1694void reset_output_field(void)
1695{
1696 sort__need_collapse = 0;
1697 sort__has_parent = 0;
1698 sort__has_sym = 0;
1699 sort__has_dso = 0;
1700
1701 field_order = NULL;
1702 sort_order = NULL;
1703
1704 reset_dimensions();
1705 perf_hpp__reset_output_field();
1198} 1706}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 43e5ff42a609..041f0c9cea2b 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -20,11 +20,12 @@
20 20
21#include "parse-options.h" 21#include "parse-options.h"
22#include "parse-events.h" 22#include "parse-events.h"
23 23#include "hist.h"
24#include "thread.h" 24#include "thread.h"
25 25
26extern regex_t parent_regex; 26extern regex_t parent_regex;
27extern const char *sort_order; 27extern const char *sort_order;
28extern const char *field_order;
28extern const char default_parent_pattern[]; 29extern const char default_parent_pattern[];
29extern const char *parent_pattern; 30extern const char *parent_pattern;
30extern const char default_sort_order[]; 31extern const char default_sort_order[];
@@ -81,12 +82,14 @@ struct hist_entry {
81 struct list_head head; 82 struct list_head head;
82 } pairs; 83 } pairs;
83 struct he_stat stat; 84 struct he_stat stat;
85 struct he_stat *stat_acc;
84 struct map_symbol ms; 86 struct map_symbol ms;
85 struct thread *thread; 87 struct thread *thread;
86 struct comm *comm; 88 struct comm *comm;
87 u64 ip; 89 u64 ip;
88 u64 transaction; 90 u64 transaction;
89 s32 cpu; 91 s32 cpu;
92 u8 cpumode;
90 93
91 struct hist_entry_diff diff; 94 struct hist_entry_diff diff;
92 95
@@ -129,10 +132,27 @@ static inline void hist_entry__add_pair(struct hist_entry *pair,
129 list_add_tail(&pair->pairs.node, &he->pairs.head); 132 list_add_tail(&pair->pairs.node, &he->pairs.head);
130} 133}
131 134
135static inline float hist_entry__get_percent_limit(struct hist_entry *he)
136{
137 u64 period = he->stat.period;
138 u64 total_period = hists__total_period(he->hists);
139
140 if (unlikely(total_period == 0))
141 return 0;
142
143 if (symbol_conf.cumulate_callchain)
144 period = he->stat_acc->period;
145
146 return period * 100.0 / total_period;
147}
148
149
132enum sort_mode { 150enum sort_mode {
133 SORT_MODE__NORMAL, 151 SORT_MODE__NORMAL,
134 SORT_MODE__BRANCH, 152 SORT_MODE__BRANCH,
135 SORT_MODE__MEMORY, 153 SORT_MODE__MEMORY,
154 SORT_MODE__TOP,
155 SORT_MODE__DIFF,
136}; 156};
137 157
138enum sort_type { 158enum sort_type {
@@ -166,6 +186,7 @@ enum sort_type {
166 SORT_MEM_TLB, 186 SORT_MEM_TLB,
167 SORT_MEM_LVL, 187 SORT_MEM_LVL,
168 SORT_MEM_SNOOP, 188 SORT_MEM_SNOOP,
189 SORT_MEM_DCACHELINE,
169}; 190};
170 191
171/* 192/*
@@ -179,18 +200,21 @@ struct sort_entry {
179 200
180 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 201 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
181 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 202 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
203 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
182 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 204 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
183 unsigned int width); 205 unsigned int width);
184 u8 se_width_idx; 206 u8 se_width_idx;
185 bool elide;
186}; 207};
187 208
188extern struct sort_entry sort_thread; 209extern struct sort_entry sort_thread;
189extern struct list_head hist_entry__sort_list; 210extern struct list_head hist_entry__sort_list;
190 211
191int setup_sorting(void); 212int setup_sorting(void);
213int setup_output_field(void);
214void reset_output_field(void);
192extern int sort_dimension__add(const char *); 215extern int sort_dimension__add(const char *);
193void sort__setup_elide(FILE *fp); 216void sort__setup_elide(FILE *fp);
217void perf_hpp__set_elide(int idx, bool elide);
194 218
195int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); 219int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
196 220
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index ae8ccd7227cf..5667fc3e39cf 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_STATS_H 1#ifndef __PERF_STATS_H
2#define __PERF_STATS_H 2#define __PERF_STATS_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6struct stats 6struct stats
7{ 7{
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 43262b83c541..6a0a13d07a28 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -17,7 +17,7 @@
17#include <stdlib.h> 17#include <stdlib.h>
18#include <unistd.h> 18#include <unistd.h>
19#include <string.h> 19#include <string.h>
20#include <linux/bitops.h> 20#include <linux/bitmap.h>
21 21
22#include "perf.h" 22#include "perf.h"
23#include "svghelper.h" 23#include "svghelper.h"
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index f7b4d6e699ea..e3aff5332e30 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_SVGHELPER_H 1#ifndef __PERF_SVGHELPER_H
2#define __PERF_SVGHELPER_H 2#define __PERF_SVGHELPER_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); 6extern void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 7extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 95e249779931..7b9096f29cdb 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -29,11 +29,12 @@ int vmlinux_path__nr_entries;
29char **vmlinux_path; 29char **vmlinux_path;
30 30
31struct symbol_conf symbol_conf = { 31struct symbol_conf symbol_conf = {
32 .use_modules = true, 32 .use_modules = true,
33 .try_vmlinux_path = true, 33 .try_vmlinux_path = true,
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .symfs = "", 36 .cumulate_callchain = true,
37 .symfs = "",
37}; 38};
38 39
39static enum dso_binary_type binary_type_symtab[] = { 40static enum dso_binary_type binary_type_symtab[] = {
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 501e4e722e8e..615c752dd767 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -12,6 +12,7 @@
12#include <byteswap.h> 12#include <byteswap.h>
13#include <libgen.h> 13#include <libgen.h>
14#include "build-id.h" 14#include "build-id.h"
15#include "event.h"
15 16
16#ifdef HAVE_LIBELF_SUPPORT 17#ifdef HAVE_LIBELF_SUPPORT
17#include <libelf.h> 18#include <libelf.h>
@@ -108,6 +109,7 @@ struct symbol_conf {
108 show_nr_samples, 109 show_nr_samples,
109 show_total_period, 110 show_total_period,
110 use_callchain, 111 use_callchain,
112 cumulate_callchain,
111 exclude_other, 113 exclude_other,
112 show_cpu_utilization, 114 show_cpu_utilization,
113 initialized, 115 initialized,
@@ -115,7 +117,8 @@ struct symbol_conf {
115 annotate_asm_raw, 117 annotate_asm_raw,
116 annotate_src, 118 annotate_src,
117 event_group, 119 event_group,
118 demangle; 120 demangle,
121 filter_relative;
119 const char *vmlinux_name, 122 const char *vmlinux_name,
120 *kallsyms_name, 123 *kallsyms_name,
121 *source_prefix, 124 *source_prefix,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 3ce0498bdae6..2fde0d5e40b5 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -8,6 +8,22 @@
8#include "debug.h" 8#include "debug.h"
9#include "comm.h" 9#include "comm.h"
10 10
11int thread__init_map_groups(struct thread *thread, struct machine *machine)
12{
13 struct thread *leader;
14 pid_t pid = thread->pid_;
15
16 if (pid == thread->tid) {
17 thread->mg = map_groups__new();
18 } else {
19 leader = machine__findnew_thread(machine, pid, pid);
20 if (leader)
21 thread->mg = map_groups__get(leader->mg);
22 }
23
24 return thread->mg ? 0 : -1;
25}
26
11struct thread *thread__new(pid_t pid, pid_t tid) 27struct thread *thread__new(pid_t pid, pid_t tid)
12{ 28{
13 char *comm_str; 29 char *comm_str;
@@ -15,7 +31,6 @@ struct thread *thread__new(pid_t pid, pid_t tid)
15 struct thread *thread = zalloc(sizeof(*thread)); 31 struct thread *thread = zalloc(sizeof(*thread));
16 32
17 if (thread != NULL) { 33 if (thread != NULL) {
18 map_groups__init(&thread->mg);
19 thread->pid_ = pid; 34 thread->pid_ = pid;
20 thread->tid = tid; 35 thread->tid = tid;
21 thread->ppid = -1; 36 thread->ppid = -1;
@@ -45,7 +60,8 @@ void thread__delete(struct thread *thread)
45{ 60{
46 struct comm *comm, *tmp; 61 struct comm *comm, *tmp;
47 62
48 map_groups__exit(&thread->mg); 63 map_groups__put(thread->mg);
64 thread->mg = NULL;
49 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 65 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
50 list_del(&comm->list); 66 list_del(&comm->list);
51 comm__free(comm); 67 comm__free(comm);
@@ -111,18 +127,35 @@ int thread__comm_len(struct thread *thread)
111size_t thread__fprintf(struct thread *thread, FILE *fp) 127size_t thread__fprintf(struct thread *thread, FILE *fp)
112{ 128{
113 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
114 map_groups__fprintf(&thread->mg, verbose, fp); 130 map_groups__fprintf(thread->mg, verbose, fp);
115} 131}
116 132
117void thread__insert_map(struct thread *thread, struct map *map) 133void thread__insert_map(struct thread *thread, struct map *map)
118{ 134{
119 map_groups__fixup_overlappings(&thread->mg, map, verbose, stderr); 135 map_groups__fixup_overlappings(thread->mg, map, verbose, stderr);
120 map_groups__insert(&thread->mg, map); 136 map_groups__insert(thread->mg, map);
137}
138
139static int thread__clone_map_groups(struct thread *thread,
140 struct thread *parent)
141{
142 int i;
143
144 /* This is new thread, we share map groups for process. */
145 if (thread->pid_ == parent->pid_)
146 return 0;
147
148 /* But this one is new process, copy maps. */
149 for (i = 0; i < MAP__NR_TYPES; ++i)
150 if (map_groups__clone(thread->mg, parent->mg, i) < 0)
151 return -ENOMEM;
152
153 return 0;
121} 154}
122 155
123int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp) 156int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
124{ 157{
125 int i, err; 158 int err;
126 159
127 if (parent->comm_set) { 160 if (parent->comm_set) {
128 const char *comm = thread__comm_str(parent); 161 const char *comm = thread__comm_str(parent);
@@ -134,13 +167,8 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
134 thread->comm_set = true; 167 thread->comm_set = true;
135 } 168 }
136 169
137 for (i = 0; i < MAP__NR_TYPES; ++i)
138 if (map_groups__clone(&thread->mg, &parent->mg, i) < 0)
139 return -ENOMEM;
140
141 thread->ppid = parent->tid; 170 thread->ppid = parent->tid;
142 171 return thread__clone_map_groups(thread, parent);
143 return 0;
144} 172}
145 173
146void thread__find_cpumode_addr_location(struct thread *thread, 174void thread__find_cpumode_addr_location(struct thread *thread,
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 9b29f085aede..3c0c2724f82c 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -13,7 +13,7 @@ struct thread {
13 struct rb_node rb_node; 13 struct rb_node rb_node;
14 struct list_head node; 14 struct list_head node;
15 }; 15 };
16 struct map_groups mg; 16 struct map_groups *mg;
17 pid_t pid_; /* Not all tools update this */ 17 pid_t pid_; /* Not all tools update this */
18 pid_t tid; 18 pid_t tid;
19 pid_t ppid; 19 pid_t ppid;
@@ -30,6 +30,7 @@ struct machine;
30struct comm; 30struct comm;
31 31
32struct thread *thread__new(pid_t pid, pid_t tid); 32struct thread *thread__new(pid_t pid, pid_t tid);
33int thread__init_map_groups(struct thread *thread, struct machine *machine);
33void thread__delete(struct thread *thread); 34void thread__delete(struct thread *thread);
34static inline void thread__exited(struct thread *thread) 35static inline void thread__exited(struct thread *thread)
35{ 36{
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index dab14d0ad3d0..f92c37abb0a8 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -2,7 +2,7 @@
2#define __PERF_TOP_H 1 2#define __PERF_TOP_H 1
3 3
4#include "tool.h" 4#include "tool.h"
5#include "types.h" 5#include <linux/types.h>
6#include <stddef.h> 6#include <stddef.h>
7#include <stdbool.h> 7#include <stdbool.h>
8#include <termios.h> 8#include <termios.h>
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
deleted file mode 100644
index c51fa6b70a28..000000000000
--- a/tools/perf/util/types.h
+++ /dev/null
@@ -1,24 +0,0 @@
1#ifndef __PERF_TYPES_H
2#define __PERF_TYPES_H
3
4#include <stdint.h>
5
6/*
7 * We define u64 as uint64_t for every architecture
8 * so that we can print it with "%"PRIx64 without getting warnings.
9 */
10typedef uint64_t u64;
11typedef int64_t s64;
12typedef unsigned int u32;
13typedef signed int s32;
14typedef unsigned short u16;
15typedef signed short s16;
16typedef unsigned char u8;
17typedef signed char s8;
18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
24#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 67db73ec3dab..5ec80a575b50 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -7,7 +7,7 @@
7#include "unwind-libdw.h" 7#include "unwind-libdw.h"
8#include "machine.h" 8#include "machine.h"
9#include "thread.h" 9#include "thread.h"
10#include "types.h" 10#include <linux/types.h>
11#include "event.h" 11#include "event.h"
12#include "perf_regs.h" 12#include "perf_regs.h"
13 13
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index bd5768d74f01..25578b98f5c5 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -250,7 +250,6 @@ static int read_unwind_spec_eh_frame(struct dso *dso, struct machine *machine,
250 250
251 /* Check the .eh_frame section for unwinding info */ 251 /* Check the .eh_frame section for unwinding info */
252 offset = elf_section_offset(fd, ".eh_frame_hdr"); 252 offset = elf_section_offset(fd, ".eh_frame_hdr");
253 close(fd);
254 253
255 if (offset) 254 if (offset)
256 ret = unwind_spec_ehframe(dso, machine, offset, 255 ret = unwind_spec_ehframe(dso, machine, offset,
@@ -271,7 +270,6 @@ static int read_unwind_spec_debug_frame(struct dso *dso,
271 270
272 /* Check the .debug_frame section for unwinding info */ 271 /* Check the .debug_frame section for unwinding info */
273 *offset = elf_section_offset(fd, ".debug_frame"); 272 *offset = elf_section_offset(fd, ".debug_frame");
274 close(fd);
275 273
276 if (*offset) 274 if (*offset)
277 return 0; 275 return 0;
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index b031316f221a..f03061260b4e 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -1,7 +1,7 @@
1#ifndef __UNWIND_H 1#ifndef __UNWIND_H
2#define __UNWIND_H 2#define __UNWIND_H
3 3
4#include "types.h" 4#include <linux/types.h>
5#include "event.h" 5#include "event.h"
6#include "symbol.h" 6#include "symbol.h"
7 7
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 9f66549562bd..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
@@ -166,6 +167,8 @@ static ssize_t ion(bool is_read, int fd, void *buf, size_t n)
166 ssize_t ret = is_read ? read(fd, buf, left) : 167 ssize_t ret = is_read ? read(fd, buf, left) :
167 write(fd, buf, left); 168 write(fd, buf, left);
168 169
170 if (ret < 0 && errno == EINTR)
171 continue;
169 if (ret <= 0) 172 if (ret <= 0)
170 return ret; 173 return ret;
171 174
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 6995d66f225c..66864364ccb4 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -69,7 +69,7 @@
69#include <sys/ioctl.h> 69#include <sys/ioctl.h>
70#include <inttypes.h> 70#include <inttypes.h>
71#include <linux/magic.h> 71#include <linux/magic.h>
72#include "types.h" 72#include <linux/types.h>
73#include <sys/ttydefaults.h> 73#include <sys/ttydefaults.h>
74#include <api/fs/debugfs.h> 74#include <api/fs/debugfs.h>
75#include <termios.h> 75#include <termios.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
diff --git a/tools/perf/util/values.h b/tools/perf/util/values.h
index 2fa967e1a88a..b21a80c6cf8d 100644
--- a/tools/perf/util/values.h
+++ b/tools/perf/util/values.h
@@ -1,7 +1,7 @@
1#ifndef __PERF_VALUES_H 1#ifndef __PERF_VALUES_H
2#define __PERF_VALUES_H 2#define __PERF_VALUES_H
3 3
4#include "types.h" 4#include <linux/types.h>
5 5
6struct perf_read_values { 6struct perf_read_values {
7 int threads; 7 int threads;