aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 16:18:00 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-03 16:18:00 -0400
commit3d521f9151dacab566904d1f57dcb3e7080cdd8f (patch)
tree160d15ff955541c6ca27a69c8291a0269f105bb3 /tools/perf/util
parent776edb59317ada867dfcddde40b55648beeb0078 (diff)
parente450f90e8c7d0bf70519223c1b848446ae63f313 (diff)
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into next
Pull perf updates from Ingo Molnar: "The tooling changes maintained by Jiri Olsa until Arnaldo is on vacation: User visible changes: - Add -F option for specifying output fields (Namhyung Kim) - Propagate exit status of a command line workload for record command (Namhyung Kim) - Use tid for finding thread (Namhyung Kim) - Clarify the output of perf sched map plus small sched command fixes (Dongsheng Yang) - Wire up perf_regs and unwind support for ARM64 (Jean Pihet) - Factor hists statistics counts processing which in turn also fixes several bugs in TUI report command (Namhyung Kim) - Add --percentage option to control absolute/relative percentage output (Namhyung Kim) - Add --list-cmds to 'kmem', 'mem', 'lock' and 'sched', for use by completion scripts (Ramkumar Ramachandra) Development/infrastructure changes and fixes: - Android related fixes for pager and map dso resolving (Michael Lentine) - Add libdw DWARF post unwind support for ARM (Jean Pihet) - Consolidate types.h for ARM and ARM64 (Jean Pihet) - Fix possible null pointer dereference in session.c (Masanari Iida) - Cleanup, remove unused variables in map_switch_event() (Dongsheng Yang) - Remove nr_state_machine_bugs in perf latency (Dongsheng Yang) - Remove usage of trace_sched_wakeup(.success) (Peter Zijlstra) - Cleanups for perf.h header (Jiri Olsa) - Consolidate types.h and export.h within tools (Borislav Petkov) - Move u64_swap union to its single user's header, evsel.h (Borislav Petkov) - Fix for s390 to properly parse tracepoints plus test code (Alexander Yarygin) - Handle EINTR error for readn/writen (Namhyung Kim) - Add a test case for hists filtering (Namhyung Kim) - Share map_groups among threads of the same group (Arnaldo Carvalho de Melo, Jiri Olsa) - Making some code (cpu node map and report parse callchain callback) global to be usable by upcomming changes (Don Zickus) - Fix pmu object compilation error (Jiri Olsa) Kernel side changes: - intrusive uprobes fixes from Oleg Nesterov. Since the interface is admin-only, and the bug only affects user-space ("any probed jmp/call can kill the application"), we queued these fixes via the development tree, as a special exception. - more fuzzer motivated race fixes and related refactoring and robustization. - allow PMU drivers to be built as modules. (No actual module yet, because the x86 Intel uncore module wasn't ready in time for this)" * 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (114 commits) perf tools: Add automatic remapping of Android libraries perf tools: Add cat as fallback pager perf tests: Add a testcase for histogram output sorting perf tests: Factor out print_hists_*() perf tools: Introduce reset_output_field() perf tools: Get rid of obsolete hist_entry__sort_list perf hists: Reset width of output fields with header length perf tools: Skip elided sort entries perf top: Add --fields option to specify output fields perf report/tui: Fix a bug when --fields/sort is given perf tools: Add ->sort() member to struct sort_entry perf report: Add -F option to specify output fields perf tools: Call perf_hpp__init() before setting up GUI browsers perf tools: Consolidate management of default sort orders perf tools: Allow hpp fields to be sort keys perf ui: Get rid of callback from __hpp__fmt() perf tools: Consolidate output field handling to hpp format routines perf tools: Use hpp formats to sort final output perf tools: Support event grouping in hpp ->sort() perf tools: Use hpp formats to sort hist entries ...
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.c78
-rw-r--r--tools/perf/util/callchain.h8
-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.h2
-rw-r--r--tools/perf/util/event.c4
-rw-r--r--tools/perf/util/event.h24
-rw-r--r--tools/perf/util/evsel.h9
-rw-r--r--tools/perf/util/header.h4
-rw-r--r--tools/perf/util/hist.c187
-rw-r--r--tools/perf/util/hist.h46
-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.c11
-rw-r--r--tools/perf/util/map.c118
-rw-r--r--tools/perf/util/map.h14
-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.h2
-rw-r--r--tools/perf/util/pmu.c6
-rw-r--r--tools/perf/util/pmu.h2
-rw-r--r--tools/perf/util/session.c5
-rw-r--r--tools/perf/util/sort.c436
-rw-r--r--tools/perf/util/sort.h6
-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.h4
-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.h2
-rw-r--r--tools/perf/util/util.c2
-rw-r--r--tools/perf/util/util.h2
-rw-r--r--tools/perf/util/values.h2
44 files changed, 1115 insertions, 221 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..9a42382b3921 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)
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8ad97e9b119f..bde2b0cc24cf 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,
@@ -157,4 +164,5 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
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);
158 165
159extern const char record_callchain_help[]; 166extern const char record_callchain_help[];
167int parse_callchain_report_opt(const char *arg);
160#endif /* __PERF_CALLCHAIN_H */ 168#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.h b/tools/perf/util/dso.h
index ab06f1c03655..38efe95a7fdd 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
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 9d12aa6dd485..65795b835b39 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -699,7 +699,7 @@ void thread__find_addr_map(struct thread *thread,
699 enum map_type type, u64 addr, 699 enum map_type type, u64 addr,
700 struct addr_location *al) 700 struct addr_location *al)
701{ 701{
702 struct map_groups *mg = &thread->mg; 702 struct map_groups *mg = thread->mg;
703 bool load_map = false; 703 bool load_map = false;
704 704
705 al->machine = machine; 705 al->machine = machine;
@@ -788,7 +788,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
788{ 788{
789 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 789 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
790 struct thread *thread = machine__findnew_thread(machine, sample->pid, 790 struct thread *thread = machine__findnew_thread(machine, sample->pid,
791 sample->pid); 791 sample->tid);
792 792
793 if (thread == NULL) 793 if (thread == NULL)
794 return -1; 794 return -1;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 38457d447a13..d970232cb270 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -112,6 +112,30 @@ struct sample_read {
112 }; 112 };
113}; 113};
114 114
115struct ip_callchain {
116 u64 nr;
117 u64 ips[0];
118};
119
120struct branch_flags {
121 u64 mispred:1;
122 u64 predicted:1;
123 u64 in_tx:1;
124 u64 abort:1;
125 u64 reserved:60;
126};
127
128struct branch_entry {
129 u64 from;
130 u64 to;
131 struct branch_flags flags;
132};
133
134struct branch_stack {
135 u64 nr;
136 struct branch_entry entries[0];
137};
138
115struct perf_sample { 139struct perf_sample {
116 u64 ip; 140 u64 ip;
117 u32 pid, tid; 141 u32 pid, tid;
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..b262b44b7a65 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -225,14 +225,18 @@ static void he_stat__decay(struct he_stat *he_stat)
225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 225static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
226{ 226{
227 u64 prev_period = he->stat.period; 227 u64 prev_period = he->stat.period;
228 u64 diff;
228 229
229 if (prev_period == 0) 230 if (prev_period == 0)
230 return true; 231 return true;
231 232
232 he_stat__decay(&he->stat); 233 he_stat__decay(&he->stat);
233 234
235 diff = prev_period - he->stat.period;
236
237 hists->stats.total_period -= diff;
234 if (!he->filtered) 238 if (!he->filtered)
235 hists->stats.total_period -= prev_period - he->stat.period; 239 hists->stats.total_non_filtered_period -= diff;
236 240
237 return he->stat.period == 0; 241 return he->stat.period == 0;
238} 242}
@@ -259,8 +263,11 @@ void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
259 if (sort__need_collapse) 263 if (sort__need_collapse)
260 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 264 rb_erase(&n->rb_node_in, &hists->entries_collapsed);
261 265
262 hist_entry__free(n);
263 --hists->nr_entries; 266 --hists->nr_entries;
267 if (!n->filtered)
268 --hists->nr_non_filtered_entries;
269
270 hist_entry__free(n);
264 } 271 }
265 } 272 }
266} 273}
@@ -317,15 +324,6 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
317 return he; 324 return he;
318} 325}
319 326
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) 327static u8 symbol__parent_filter(const struct symbol *parent)
330{ 328{
331 if (symbol_conf.exclude_other && parent == NULL) 329 if (symbol_conf.exclude_other && parent == NULL)
@@ -391,7 +389,6 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
391 if (!he) 389 if (!he)
392 return NULL; 390 return NULL;
393 391
394 hists->nr_entries++;
395 rb_link_node(&he->rb_node_in, parent, p); 392 rb_link_node(&he->rb_node_in, parent, p);
396 rb_insert_color(&he->rb_node_in, hists->entries_in); 393 rb_insert_color(&he->rb_node_in, hists->entries_in);
397out: 394out:
@@ -435,11 +432,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
435int64_t 432int64_t
436hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 433hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
437{ 434{
438 struct sort_entry *se; 435 struct perf_hpp_fmt *fmt;
439 int64_t cmp = 0; 436 int64_t cmp = 0;
440 437
441 list_for_each_entry(se, &hist_entry__sort_list, list) { 438 perf_hpp__for_each_sort_list(fmt) {
442 cmp = se->se_cmp(left, right); 439 if (perf_hpp__should_skip(fmt))
440 continue;
441
442 cmp = fmt->cmp(left, right);
443 if (cmp) 443 if (cmp)
444 break; 444 break;
445 } 445 }
@@ -450,15 +450,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
450int64_t 450int64_t
451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 451hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
452{ 452{
453 struct sort_entry *se; 453 struct perf_hpp_fmt *fmt;
454 int64_t cmp = 0; 454 int64_t cmp = 0;
455 455
456 list_for_each_entry(se, &hist_entry__sort_list, list) { 456 perf_hpp__for_each_sort_list(fmt) {
457 int64_t (*f)(struct hist_entry *, struct hist_entry *); 457 if (perf_hpp__should_skip(fmt))
458 458 continue;
459 f = se->se_collapse ?: se->se_cmp;
460 459
461 cmp = f(left, right); 460 cmp = fmt->collapse(left, right);
462 if (cmp) 461 if (cmp)
463 break; 462 break;
464 } 463 }
@@ -571,64 +570,50 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
571 } 570 }
572} 571}
573 572
574/* 573static 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{ 574{
580 if (period_a > period_b) 575 struct perf_hpp_fmt *fmt;
581 return 1; 576 int64_t cmp = 0;
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{
590 int ret;
591 int i, nr_members;
592 struct perf_evsel *evsel;
593 struct hist_entry *pair;
594 u64 *periods_a, *periods_b;
595 577
596 ret = period_cmp(a->stat.period, b->stat.period); 578 perf_hpp__for_each_sort_list(fmt) {
597 if (ret || !symbol_conf.event_group) 579 if (perf_hpp__should_skip(fmt))
598 return ret; 580 continue;
599 581
600 evsel = hists_to_evsel(a->hists); 582 cmp = fmt->sort(a, b);
601 nr_members = evsel->nr_members; 583 if (cmp)
602 if (nr_members <= 1) 584 break;
603 return ret; 585 }
604 586
605 periods_a = zalloc(sizeof(periods_a) * nr_members); 587 return cmp;
606 periods_b = zalloc(sizeof(periods_b) * nr_members); 588}
607 589
608 if (!periods_a || !periods_b) 590static void hists__reset_filter_stats(struct hists *hists)
609 goto out; 591{
592 hists->nr_non_filtered_entries = 0;
593 hists->stats.total_non_filtered_period = 0;
594}
610 595
611 list_for_each_entry(pair, &a->pairs.head, pairs.node) { 596void hists__reset_stats(struct hists *hists)
612 evsel = hists_to_evsel(pair->hists); 597{
613 periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period; 598 hists->nr_entries = 0;
614 } 599 hists->stats.total_period = 0;
615 600
616 list_for_each_entry(pair, &b->pairs.head, pairs.node) { 601 hists__reset_filter_stats(hists);
617 evsel = hists_to_evsel(pair->hists); 602}
618 periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period;
619 }
620 603
621 for (i = 1; i < nr_members; i++) { 604static void hists__inc_filter_stats(struct hists *hists, struct hist_entry *h)
622 ret = period_cmp(periods_a[i], periods_b[i]); 605{
623 if (ret) 606 hists->nr_non_filtered_entries++;
624 break; 607 hists->stats.total_non_filtered_period += h->stat.period;
625 } 608}
626 609
627out: 610void hists__inc_stats(struct hists *hists, struct hist_entry *h)
628 free(periods_a); 611{
629 free(periods_b); 612 if (!h->filtered)
613 hists__inc_filter_stats(hists, h);
630 614
631 return ret; 615 hists->nr_entries++;
616 hists->stats.total_period += h->stat.period;
632} 617}
633 618
634static void __hists__insert_output_entry(struct rb_root *entries, 619static void __hists__insert_output_entry(struct rb_root *entries,
@@ -647,7 +632,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
647 parent = *p; 632 parent = *p;
648 iter = rb_entry(parent, struct hist_entry, rb_node); 633 iter = rb_entry(parent, struct hist_entry, rb_node);
649 634
650 if (hist_entry__sort_on_period(he, iter) > 0) 635 if (hist_entry__sort(he, iter) > 0)
651 p = &(*p)->rb_left; 636 p = &(*p)->rb_left;
652 else 637 else
653 p = &(*p)->rb_right; 638 p = &(*p)->rb_right;
@@ -674,8 +659,7 @@ void hists__output_resort(struct hists *hists)
674 next = rb_first(root); 659 next = rb_first(root);
675 hists->entries = RB_ROOT; 660 hists->entries = RB_ROOT;
676 661
677 hists->nr_entries = 0; 662 hists__reset_stats(hists);
678 hists->stats.total_period = 0;
679 hists__reset_col_len(hists); 663 hists__reset_col_len(hists);
680 664
681 while (next) { 665 while (next) {
@@ -683,7 +667,10 @@ void hists__output_resort(struct hists *hists)
683 next = rb_next(&n->rb_node_in); 667 next = rb_next(&n->rb_node_in);
684 668
685 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 669 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
686 hists__inc_nr_entries(hists, n); 670 hists__inc_stats(hists, n);
671
672 if (!n->filtered)
673 hists__calc_col_len(hists, n);
687 } 674 }
688} 675}
689 676
@@ -694,13 +681,13 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
694 if (h->filtered) 681 if (h->filtered)
695 return; 682 return;
696 683
697 ++hists->nr_entries; 684 /* force fold unfiltered entry for simplicity */
698 if (h->ms.unfolded) 685 h->ms.unfolded = false;
699 hists->nr_entries += h->nr_rows;
700 h->row_offset = 0; 686 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 687
688 hists->stats.nr_non_filtered_samples += h->stat.nr_events;
689
690 hists__inc_filter_stats(hists, h);
704 hists__calc_col_len(hists, h); 691 hists__calc_col_len(hists, h);
705} 692}
706 693
@@ -721,8 +708,9 @@ void hists__filter_by_dso(struct hists *hists)
721{ 708{
722 struct rb_node *nd; 709 struct rb_node *nd;
723 710
724 hists->nr_entries = hists->stats.total_period = 0; 711 hists->stats.nr_non_filtered_samples = 0;
725 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 712
713 hists__reset_filter_stats(hists);
726 hists__reset_col_len(hists); 714 hists__reset_col_len(hists);
727 715
728 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 716 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -754,8 +742,9 @@ void hists__filter_by_thread(struct hists *hists)
754{ 742{
755 struct rb_node *nd; 743 struct rb_node *nd;
756 744
757 hists->nr_entries = hists->stats.total_period = 0; 745 hists->stats.nr_non_filtered_samples = 0;
758 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 746
747 hists__reset_filter_stats(hists);
759 hists__reset_col_len(hists); 748 hists__reset_col_len(hists);
760 749
761 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 750 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -785,8 +774,9 @@ void hists__filter_by_symbol(struct hists *hists)
785{ 774{
786 struct rb_node *nd; 775 struct rb_node *nd;
787 776
788 hists->nr_entries = hists->stats.total_period = 0; 777 hists->stats.nr_non_filtered_samples = 0;
789 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 778
779 hists__reset_filter_stats(hists);
790 hists__reset_col_len(hists); 780 hists__reset_col_len(hists);
791 781
792 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 782 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
@@ -847,7 +837,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
847 he->hists = hists; 837 he->hists = hists;
848 rb_link_node(&he->rb_node_in, parent, p); 838 rb_link_node(&he->rb_node_in, parent, p);
849 rb_insert_color(&he->rb_node_in, root); 839 rb_insert_color(&he->rb_node_in, root);
850 hists__inc_nr_entries(hists, he); 840 hists__inc_stats(hists, he);
851 he->dummy = true; 841 he->dummy = true;
852 } 842 }
853out: 843out:
@@ -931,3 +921,30 @@ int hists__link(struct hists *leader, struct hists *other)
931 921
932 return 0; 922 return 0;
933} 923}
924
925u64 hists__total_period(struct hists *hists)
926{
927 return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
928 hists->stats.total_period;
929}
930
931int parse_filter_percentage(const struct option *opt __maybe_unused,
932 const char *arg, int unset __maybe_unused)
933{
934 if (!strcmp(arg, "relative"))
935 symbol_conf.filter_relative = true;
936 else if (!strcmp(arg, "absolute"))
937 symbol_conf.filter_relative = false;
938 else
939 return -1;
940
941 return 0;
942}
943
944int perf_hist_config(const char *var, const char *value)
945{
946 if (!strcmp(var, "hist.percentage"))
947 return parse_filter_percentage(NULL, value, 0);
948
949 return 0;
950}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1f1f513dfe7f..a8418d19808d 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;
@@ -83,6 +85,7 @@ struct hists {
83 struct rb_root entries; 85 struct rb_root entries;
84 struct rb_root entries_collapsed; 86 struct rb_root entries_collapsed;
85 u64 nr_entries; 87 u64 nr_entries;
88 u64 nr_non_filtered_entries;
86 const struct thread *thread_filter; 89 const struct thread *thread_filter;
87 const struct dso *dso_filter; 90 const struct dso *dso_filter;
88 const char *uid_filter_str; 91 const char *uid_filter_str;
@@ -112,7 +115,9 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
112void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); 115void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
113void hists__output_recalc_col_len(struct hists *hists, int max_rows); 116void hists__output_recalc_col_len(struct hists *hists, int max_rows);
114 117
115void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); 118u64 hists__total_period(struct hists *hists);
119void hists__reset_stats(struct hists *hists);
120void hists__inc_stats(struct hists *hists, struct hist_entry *h);
116void hists__inc_nr_events(struct hists *hists, u32 type); 121void hists__inc_nr_events(struct hists *hists, u32 type);
117void events_stats__inc(struct events_stats *stats, u32 type); 122void events_stats__inc(struct events_stats *stats, u32 type);
118size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); 123size_t events_stats__fprintf(struct events_stats *stats, FILE *fp);
@@ -124,6 +129,12 @@ void hists__filter_by_dso(struct hists *hists);
124void hists__filter_by_thread(struct hists *hists); 129void hists__filter_by_thread(struct hists *hists);
125void hists__filter_by_symbol(struct hists *hists); 130void hists__filter_by_symbol(struct hists *hists);
126 131
132static inline bool hists__has_filter(struct hists *hists)
133{
134 return hists->thread_filter || hists->dso_filter ||
135 hists->symbol_filter_str;
136}
137
127u16 hists__col_len(struct hists *hists, enum hist_column col); 138u16 hists__col_len(struct hists *hists, enum hist_column col);
128void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len); 139void 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); 140bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len);
@@ -149,15 +160,29 @@ struct perf_hpp_fmt {
149 struct hist_entry *he); 160 struct hist_entry *he);
150 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 161 int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
151 struct hist_entry *he); 162 struct hist_entry *he);
163 int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b);
164 int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b);
165 int64_t (*sort)(struct hist_entry *a, struct hist_entry *b);
152 166
153 struct list_head list; 167 struct list_head list;
168 struct list_head sort_list;
154}; 169};
155 170
156extern struct list_head perf_hpp__list; 171extern struct list_head perf_hpp__list;
172extern struct list_head perf_hpp__sort_list;
157 173
158#define perf_hpp__for_each_format(format) \ 174#define perf_hpp__for_each_format(format) \
159 list_for_each_entry(format, &perf_hpp__list, list) 175 list_for_each_entry(format, &perf_hpp__list, list)
160 176
177#define perf_hpp__for_each_format_safe(format, tmp) \
178 list_for_each_entry_safe(format, tmp, &perf_hpp__list, list)
179
180#define perf_hpp__for_each_sort_list(format) \
181 list_for_each_entry(format, &perf_hpp__sort_list, sort_list)
182
183#define perf_hpp__for_each_sort_list_safe(format, tmp) \
184 list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list)
185
161extern struct perf_hpp_fmt perf_hpp__format[]; 186extern struct perf_hpp_fmt perf_hpp__format[];
162 187
163enum { 188enum {
@@ -176,14 +201,23 @@ enum {
176void perf_hpp__init(void); 201void perf_hpp__init(void);
177void perf_hpp__column_register(struct perf_hpp_fmt *format); 202void perf_hpp__column_register(struct perf_hpp_fmt *format);
178void perf_hpp__column_enable(unsigned col); 203void perf_hpp__column_enable(unsigned col);
204void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
205void perf_hpp__setup_output_field(void);
206void perf_hpp__reset_output_field(void);
207void perf_hpp__append_sort_keys(void);
208
209bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
210bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
211bool perf_hpp__should_skip(struct perf_hpp_fmt *format);
212void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
179 213
180typedef u64 (*hpp_field_fn)(struct hist_entry *he); 214typedef u64 (*hpp_field_fn)(struct hist_entry *he);
181typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); 215typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
182typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); 216typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
183 217
184int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, 218int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
185 hpp_field_fn get_field, hpp_callback_fn callback, 219 hpp_field_fn get_field, const char *fmt,
186 const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent); 220 hpp_snprint_fn print_fn, bool fmt_percent);
187 221
188static inline void advance_hpp(struct perf_hpp *hpp, int inc) 222static inline void advance_hpp(struct perf_hpp *hpp, int inc)
189{ 223{
@@ -250,4 +284,10 @@ static inline int script_browse(const char *script_opt __maybe_unused)
250#endif 284#endif
251 285
252unsigned int hists__sort_list_width(struct hists *hists); 286unsigned int hists__sort_list_width(struct hists *hists);
287
288struct option;
289int parse_filter_percentage(const struct option *opt __maybe_unused,
290 const char *arg, int unset __maybe_unused);
291int perf_hist_config(const char *var, const char *value);
292
253#endif /* __PERF_HIST_H */ 293#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..7409ac8de51c 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;
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 39cd2d0faff6..8ccbb32eda25 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{
@@ -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);
@@ -75,6 +163,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
75 filename = newfilename; 163 filename = newfilename;
76 } 164 }
77 165
166 if (android) {
167 if (replace_android_lib(filename, newfilename))
168 filename = newfilename;
169 }
170
78 if (vdso) { 171 if (vdso) {
79 pgoff = 0; 172 pgoff = 0;
80 dso = vdso__dso_findnew(dsos__list); 173 dso = vdso__dso_findnew(dsos__list);
@@ -323,6 +416,7 @@ void map_groups__init(struct map_groups *mg)
323 INIT_LIST_HEAD(&mg->removed_maps[i]); 416 INIT_LIST_HEAD(&mg->removed_maps[i]);
324 } 417 }
325 mg->machine = NULL; 418 mg->machine = NULL;
419 mg->refcnt = 1;
326} 420}
327 421
328static void maps__delete(struct rb_root *maps) 422static void maps__delete(struct rb_root *maps)
@@ -358,6 +452,28 @@ void map_groups__exit(struct map_groups *mg)
358 } 452 }
359} 453}
360 454
455struct map_groups *map_groups__new(void)
456{
457 struct map_groups *mg = malloc(sizeof(*mg));
458
459 if (mg != NULL)
460 map_groups__init(mg);
461
462 return mg;
463}
464
465void map_groups__delete(struct map_groups *mg)
466{
467 map_groups__exit(mg);
468 free(mg);
469}
470
471void map_groups__put(struct map_groups *mg)
472{
473 if (--mg->refcnt == 0)
474 map_groups__delete(mg);
475}
476
361void map_groups__flush(struct map_groups *mg) 477void map_groups__flush(struct map_groups *mg)
362{ 478{
363 int type; 479 int type;
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index f00f058afb3b..ae2d45110588 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,
@@ -59,8 +59,20 @@ struct map_groups {
59 struct rb_root maps[MAP__NR_TYPES]; 59 struct rb_root maps[MAP__NR_TYPES];
60 struct list_head removed_maps[MAP__NR_TYPES]; 60 struct list_head removed_maps[MAP__NR_TYPES];
61 struct machine *machine; 61 struct machine *machine;
62 int refcnt;
62}; 63};
63 64
65struct map_groups *map_groups__new(void);
66void map_groups__delete(struct map_groups *mg);
67
68static inline struct map_groups *map_groups__get(struct map_groups *mg)
69{
70 ++mg->refcnt;
71 return mg;
72}
73
74void map_groups__put(struct map_groups *mg);
75
64static inline struct kmap *map__kmap(struct map *map) 76static inline struct kmap *map__kmap(struct map *map)
65{ 77{
66 return (struct kmap *)(map + 1); 78 return (struct kmap *)(map + 1);
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.h b/tools/perf/util/perf_regs.h
index d6e8b6a8d7f3..79c78f74e0cf 100644
--- a/tools/perf/util/perf_regs.h
+++ b/tools/perf/util/perf_regs.h
@@ -1,7 +1,7 @@
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#include "event.h"
6 6
7#ifdef HAVE_PERF_REGS_SUPPORT 7#ifdef HAVE_PERF_REGS_SUPPORT
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/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..901b9bece2ee 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -2,12 +2,18 @@
2#include "hist.h" 2#include "hist.h"
3#include "comm.h" 3#include "comm.h"
4#include "symbol.h" 4#include "symbol.h"
5#include "evsel.h"
5 6
6regex_t parent_regex; 7regex_t parent_regex;
7const char default_parent_pattern[] = "^sys_|^do_page_fault"; 8const char default_parent_pattern[] = "^sys_|^do_page_fault";
8const char *parent_pattern = default_parent_pattern; 9const char *parent_pattern = default_parent_pattern;
9const char default_sort_order[] = "comm,dso,symbol"; 10const char default_sort_order[] = "comm,dso,symbol";
10const char *sort_order = default_sort_order; 11const char default_branch_sort_order[] = "comm,dso_from,symbol_from,dso_to,symbol_to";
12const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
13const char default_top_sort_order[] = "dso,symbol";
14const char default_diff_sort_order[] = "dso,symbol";
15const char *sort_order;
16const char *field_order;
11regex_t ignore_callees_regex; 17regex_t ignore_callees_regex;
12int have_ignore_callees = 0; 18int have_ignore_callees = 0;
13int sort__need_collapse = 0; 19int sort__need_collapse = 0;
@@ -16,9 +22,6 @@ int sort__has_sym = 0;
16int sort__has_dso = 0; 22int sort__has_dso = 0;
17enum sort_mode sort__mode = SORT_MODE__NORMAL; 23enum sort_mode sort__mode = SORT_MODE__NORMAL;
18 24
19enum sort_type sort__first_dimension;
20
21LIST_HEAD(hist_entry__sort_list);
22 25
23static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 26static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
24{ 27{
@@ -93,6 +96,12 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
93 return comm__str(right->comm) - comm__str(left->comm); 96 return comm__str(right->comm) - comm__str(left->comm);
94} 97}
95 98
99static int64_t
100sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
101{
102 return strcmp(comm__str(right->comm), comm__str(left->comm));
103}
104
96static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 105static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
97 size_t size, unsigned int width) 106 size_t size, unsigned int width)
98{ 107{
@@ -103,6 +112,7 @@ struct sort_entry sort_comm = {
103 .se_header = "Command", 112 .se_header = "Command",
104 .se_cmp = sort__comm_cmp, 113 .se_cmp = sort__comm_cmp,
105 .se_collapse = sort__comm_collapse, 114 .se_collapse = sort__comm_collapse,
115 .se_sort = sort__comm_sort,
106 .se_snprintf = hist_entry__comm_snprintf, 116 .se_snprintf = hist_entry__comm_snprintf,
107 .se_width_idx = HISTC_COMM, 117 .se_width_idx = HISTC_COMM,
108}; 118};
@@ -116,7 +126,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
116 const char *dso_name_l, *dso_name_r; 126 const char *dso_name_l, *dso_name_r;
117 127
118 if (!dso_l || !dso_r) 128 if (!dso_l || !dso_r)
119 return cmp_null(dso_l, dso_r); 129 return cmp_null(dso_r, dso_l);
120 130
121 if (verbose) { 131 if (verbose) {
122 dso_name_l = dso_l->long_name; 132 dso_name_l = dso_l->long_name;
@@ -132,7 +142,7 @@ static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
132static int64_t 142static int64_t
133sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 143sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
134{ 144{
135 return _sort__dso_cmp(left->ms.map, right->ms.map); 145 return _sort__dso_cmp(right->ms.map, left->ms.map);
136} 146}
137 147
138static int _hist_entry__dso_snprintf(struct map *map, char *bf, 148static int _hist_entry__dso_snprintf(struct map *map, char *bf,
@@ -204,6 +214,15 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
204 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 214 return _sort__sym_cmp(left->ms.sym, right->ms.sym);
205} 215}
206 216
217static int64_t
218sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
219{
220 if (!left->ms.sym || !right->ms.sym)
221 return cmp_null(left->ms.sym, right->ms.sym);
222
223 return strcmp(right->ms.sym->name, left->ms.sym->name);
224}
225
207static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 226static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
208 u64 ip, char level, char *bf, size_t size, 227 u64 ip, char level, char *bf, size_t size,
209 unsigned int width) 228 unsigned int width)
@@ -250,6 +269,7 @@ static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
250struct sort_entry sort_sym = { 269struct sort_entry sort_sym = {
251 .se_header = "Symbol", 270 .se_header = "Symbol",
252 .se_cmp = sort__sym_cmp, 271 .se_cmp = sort__sym_cmp,
272 .se_sort = sort__sym_sort,
253 .se_snprintf = hist_entry__sym_snprintf, 273 .se_snprintf = hist_entry__sym_snprintf,
254 .se_width_idx = HISTC_SYMBOL, 274 .se_width_idx = HISTC_SYMBOL,
255}; 275};
@@ -277,7 +297,7 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
277 map__rip_2objdump(map, right->ip)); 297 map__rip_2objdump(map, right->ip));
278 } 298 }
279 } 299 }
280 return strcmp(left->srcline, right->srcline); 300 return strcmp(right->srcline, left->srcline);
281} 301}
282 302
283static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 303static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
@@ -305,7 +325,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
305 if (!sym_l || !sym_r) 325 if (!sym_l || !sym_r)
306 return cmp_null(sym_l, sym_r); 326 return cmp_null(sym_l, sym_r);
307 327
308 return strcmp(sym_l->name, sym_r->name); 328 return strcmp(sym_r->name, sym_l->name);
309} 329}
310 330
311static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 331static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
@@ -1027,19 +1047,192 @@ static struct sort_dimension memory_sort_dimensions[] = {
1027 1047
1028#undef DIM 1048#undef DIM
1029 1049
1030static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx) 1050struct hpp_dimension {
1051 const char *name;
1052 struct perf_hpp_fmt *fmt;
1053 int taken;
1054};
1055
1056#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1057
1058static struct hpp_dimension hpp_sort_dimensions[] = {
1059 DIM(PERF_HPP__OVERHEAD, "overhead"),
1060 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1061 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1062 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1063 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1064 DIM(PERF_HPP__SAMPLES, "sample"),
1065 DIM(PERF_HPP__PERIOD, "period"),
1066};
1067
1068#undef DIM
1069
1070struct hpp_sort_entry {
1071 struct perf_hpp_fmt hpp;
1072 struct sort_entry *se;
1073};
1074
1075bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1031{ 1076{
1032 if (sd->taken) 1077 struct hpp_sort_entry *hse_a;
1078 struct hpp_sort_entry *hse_b;
1079
1080 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1081 return false;
1082
1083 hse_a = container_of(a, struct hpp_sort_entry, hpp);
1084 hse_b = container_of(b, struct hpp_sort_entry, hpp);
1085
1086 return hse_a->se == hse_b->se;
1087}
1088
1089void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1090{
1091 struct hpp_sort_entry *hse;
1092
1093 if (!perf_hpp__is_sort_entry(fmt))
1033 return; 1094 return;
1034 1095
1096 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1097 hists__new_col_len(hists, hse->se->se_width_idx,
1098 strlen(hse->se->se_header));
1099}
1100
1101static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1102 struct perf_evsel *evsel)
1103{
1104 struct hpp_sort_entry *hse;
1105 size_t len;
1106
1107 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1108 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1109
1110 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header);
1111}
1112
1113static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1114 struct perf_hpp *hpp __maybe_unused,
1115 struct perf_evsel *evsel)
1116{
1117 struct hpp_sort_entry *hse;
1118
1119 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1120
1121 return hists__col_len(&evsel->hists, hse->se->se_width_idx);
1122}
1123
1124static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1125 struct hist_entry *he)
1126{
1127 struct hpp_sort_entry *hse;
1128 size_t len;
1129
1130 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1131 len = hists__col_len(he->hists, hse->se->se_width_idx);
1132
1133 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1134}
1135
1136static struct hpp_sort_entry *
1137__sort_dimension__alloc_hpp(struct sort_dimension *sd)
1138{
1139 struct hpp_sort_entry *hse;
1140
1141 hse = malloc(sizeof(*hse));
1142 if (hse == NULL) {
1143 pr_err("Memory allocation failed\n");
1144 return NULL;
1145 }
1146
1147 hse->se = sd->entry;
1148 hse->hpp.header = __sort__hpp_header;
1149 hse->hpp.width = __sort__hpp_width;
1150 hse->hpp.entry = __sort__hpp_entry;
1151 hse->hpp.color = NULL;
1152
1153 hse->hpp.cmp = sd->entry->se_cmp;
1154 hse->hpp.collapse = sd->entry->se_collapse ? : sd->entry->se_cmp;
1155 hse->hpp.sort = sd->entry->se_sort ? : hse->hpp.collapse;
1156
1157 INIT_LIST_HEAD(&hse->hpp.list);
1158 INIT_LIST_HEAD(&hse->hpp.sort_list);
1159
1160 return hse;
1161}
1162
1163bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1164{
1165 return format->header == __sort__hpp_header;
1166}
1167
1168static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
1169{
1170 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1171
1172 if (hse == NULL)
1173 return -1;
1174
1175 perf_hpp__register_sort_field(&hse->hpp);
1176 return 0;
1177}
1178
1179static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
1180{
1181 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
1182
1183 if (hse == NULL)
1184 return -1;
1185
1186 perf_hpp__column_register(&hse->hpp);
1187 return 0;
1188}
1189
1190static int __sort_dimension__add(struct sort_dimension *sd)
1191{
1192 if (sd->taken)
1193 return 0;
1194
1195 if (__sort_dimension__add_hpp_sort(sd) < 0)
1196 return -1;
1197
1035 if (sd->entry->se_collapse) 1198 if (sd->entry->se_collapse)
1036 sort__need_collapse = 1; 1199 sort__need_collapse = 1;
1037 1200
1038 if (list_empty(&hist_entry__sort_list)) 1201 sd->taken = 1;
1039 sort__first_dimension = idx; 1202
1203 return 0;
1204}
1205
1206static int __hpp_dimension__add(struct hpp_dimension *hd)
1207{
1208 if (!hd->taken) {
1209 hd->taken = 1;
1210
1211 perf_hpp__register_sort_field(hd->fmt);
1212 }
1213 return 0;
1214}
1215
1216static int __sort_dimension__add_output(struct sort_dimension *sd)
1217{
1218 if (sd->taken)
1219 return 0;
1220
1221 if (__sort_dimension__add_hpp_output(sd) < 0)
1222 return -1;
1040 1223
1041 list_add_tail(&sd->entry->list, &hist_entry__sort_list);
1042 sd->taken = 1; 1224 sd->taken = 1;
1225 return 0;
1226}
1227
1228static int __hpp_dimension__add_output(struct hpp_dimension *hd)
1229{
1230 if (!hd->taken) {
1231 hd->taken = 1;
1232
1233 perf_hpp__column_register(hd->fmt);
1234 }
1235 return 0;
1043} 1236}
1044 1237
1045int sort_dimension__add(const char *tok) 1238int sort_dimension__add(const char *tok)
@@ -1068,8 +1261,16 @@ int sort_dimension__add(const char *tok)
1068 sort__has_dso = 1; 1261 sort__has_dso = 1;
1069 } 1262 }
1070 1263
1071 __sort_dimension__add(sd, i); 1264 return __sort_dimension__add(sd);
1072 return 0; 1265 }
1266
1267 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1268 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1269
1270 if (strncasecmp(tok, hd->name, strlen(tok)))
1271 continue;
1272
1273 return __hpp_dimension__add(hd);
1073 } 1274 }
1074 1275
1075 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1276 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -1084,7 +1285,7 @@ int sort_dimension__add(const char *tok)
1084 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 1285 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
1085 sort__has_sym = 1; 1286 sort__has_sym = 1;
1086 1287
1087 __sort_dimension__add(sd, i + __SORT_BRANCH_STACK); 1288 __sort_dimension__add(sd);
1088 return 0; 1289 return 0;
1089 } 1290 }
1090 1291
@@ -1100,18 +1301,47 @@ int sort_dimension__add(const char *tok)
1100 if (sd->entry == &sort_mem_daddr_sym) 1301 if (sd->entry == &sort_mem_daddr_sym)
1101 sort__has_sym = 1; 1302 sort__has_sym = 1;
1102 1303
1103 __sort_dimension__add(sd, i + __SORT_MEMORY_MODE); 1304 __sort_dimension__add(sd);
1104 return 0; 1305 return 0;
1105 } 1306 }
1106 1307
1107 return -ESRCH; 1308 return -ESRCH;
1108} 1309}
1109 1310
1110int setup_sorting(void) 1311static const char *get_default_sort_order(void)
1111{ 1312{
1112 char *tmp, *tok, *str = strdup(sort_order); 1313 const char *default_sort_orders[] = {
1314 default_sort_order,
1315 default_branch_sort_order,
1316 default_mem_sort_order,
1317 default_top_sort_order,
1318 default_diff_sort_order,
1319 };
1320
1321 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
1322
1323 return default_sort_orders[sort__mode];
1324}
1325
1326static int __setup_sorting(void)
1327{
1328 char *tmp, *tok, *str;
1329 const char *sort_keys = sort_order;
1113 int ret = 0; 1330 int ret = 0;
1114 1331
1332 if (sort_keys == NULL) {
1333 if (field_order) {
1334 /*
1335 * If user specified field order but no sort order,
1336 * we'll honor it and not add default sort orders.
1337 */
1338 return 0;
1339 }
1340
1341 sort_keys = get_default_sort_order();
1342 }
1343
1344 str = strdup(sort_keys);
1115 if (str == NULL) { 1345 if (str == NULL) {
1116 error("Not enough memory to setup sort keys"); 1346 error("Not enough memory to setup sort keys");
1117 return -ENOMEM; 1347 return -ENOMEM;
@@ -1133,6 +1363,17 @@ int setup_sorting(void)
1133 return ret; 1363 return ret;
1134} 1364}
1135 1365
1366bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
1367{
1368 if (perf_hpp__is_sort_entry(format)) {
1369 struct hpp_sort_entry *hse;
1370
1371 hse = container_of(format, struct hpp_sort_entry, hpp);
1372 return hse->se->elide;
1373 }
1374 return false;
1375}
1376
1136static void sort_entry__setup_elide(struct sort_entry *se, 1377static void sort_entry__setup_elide(struct sort_entry *se,
1137 struct strlist *list, 1378 struct strlist *list,
1138 const char *list_name, FILE *fp) 1379 const char *list_name, FILE *fp)
@@ -1147,7 +1388,8 @@ static void sort_entry__setup_elide(struct sort_entry *se,
1147 1388
1148void sort__setup_elide(FILE *output) 1389void sort__setup_elide(FILE *output)
1149{ 1390{
1150 struct sort_entry *se; 1391 struct perf_hpp_fmt *fmt;
1392 struct hpp_sort_entry *hse;
1151 1393
1152 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, 1394 sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list,
1153 "dso", output); 1395 "dso", output);
@@ -1188,11 +1430,157 @@ void sort__setup_elide(FILE *output)
1188 * It makes no sense to elide all of sort entries. 1430 * It makes no sense to elide all of sort entries.
1189 * Just revert them to show up again. 1431 * Just revert them to show up again.
1190 */ 1432 */
1191 list_for_each_entry(se, &hist_entry__sort_list, list) { 1433 perf_hpp__for_each_format(fmt) {
1192 if (!se->elide) 1434 if (!perf_hpp__is_sort_entry(fmt))
1435 continue;
1436
1437 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1438 if (!hse->se->elide)
1193 return; 1439 return;
1194 } 1440 }
1195 1441
1196 list_for_each_entry(se, &hist_entry__sort_list, list) 1442 perf_hpp__for_each_format(fmt) {
1197 se->elide = false; 1443 if (!perf_hpp__is_sort_entry(fmt))
1444 continue;
1445
1446 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1447 hse->se->elide = false;
1448 }
1449}
1450
1451static int output_field_add(char *tok)
1452{
1453 unsigned int i;
1454
1455 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
1456 struct sort_dimension *sd = &common_sort_dimensions[i];
1457
1458 if (strncasecmp(tok, sd->name, strlen(tok)))
1459 continue;
1460
1461 return __sort_dimension__add_output(sd);
1462 }
1463
1464 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
1465 struct hpp_dimension *hd = &hpp_sort_dimensions[i];
1466
1467 if (strncasecmp(tok, hd->name, strlen(tok)))
1468 continue;
1469
1470 return __hpp_dimension__add_output(hd);
1471 }
1472
1473 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
1474 struct sort_dimension *sd = &bstack_sort_dimensions[i];
1475
1476 if (strncasecmp(tok, sd->name, strlen(tok)))
1477 continue;
1478
1479 return __sort_dimension__add_output(sd);
1480 }
1481
1482 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
1483 struct sort_dimension *sd = &memory_sort_dimensions[i];
1484
1485 if (strncasecmp(tok, sd->name, strlen(tok)))
1486 continue;
1487
1488 return __sort_dimension__add_output(sd);
1489 }
1490
1491 return -ESRCH;
1492}
1493
1494static void reset_dimensions(void)
1495{
1496 unsigned int i;
1497
1498 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
1499 common_sort_dimensions[i].taken = 0;
1500
1501 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
1502 hpp_sort_dimensions[i].taken = 0;
1503
1504 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
1505 bstack_sort_dimensions[i].taken = 0;
1506
1507 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
1508 memory_sort_dimensions[i].taken = 0;
1509}
1510
1511static int __setup_output_field(void)
1512{
1513 char *tmp, *tok, *str;
1514 int ret = 0;
1515
1516 if (field_order == NULL)
1517 return 0;
1518
1519 reset_dimensions();
1520
1521 str = strdup(field_order);
1522 if (str == NULL) {
1523 error("Not enough memory to setup output fields");
1524 return -ENOMEM;
1525 }
1526
1527 for (tok = strtok_r(str, ", ", &tmp);
1528 tok; tok = strtok_r(NULL, ", ", &tmp)) {
1529 ret = output_field_add(tok);
1530 if (ret == -EINVAL) {
1531 error("Invalid --fields key: `%s'", tok);
1532 break;
1533 } else if (ret == -ESRCH) {
1534 error("Unknown --fields key: `%s'", tok);
1535 break;
1536 }
1537 }
1538
1539 free(str);
1540 return ret;
1541}
1542
1543int setup_sorting(void)
1544{
1545 int err;
1546
1547 err = __setup_sorting();
1548 if (err < 0)
1549 return err;
1550
1551 if (parent_pattern != default_parent_pattern) {
1552 err = sort_dimension__add("parent");
1553 if (err < 0)
1554 return err;
1555 }
1556
1557 reset_dimensions();
1558
1559 /*
1560 * perf diff doesn't use default hpp output fields.
1561 */
1562 if (sort__mode != SORT_MODE__DIFF)
1563 perf_hpp__init();
1564
1565 err = __setup_output_field();
1566 if (err < 0)
1567 return err;
1568
1569 /* copy sort keys to output fields */
1570 perf_hpp__setup_output_field();
1571 /* and then copy output fields to sort keys */
1572 perf_hpp__append_sort_keys();
1573
1574 return 0;
1575}
1576
1577void reset_output_field(void)
1578{
1579 sort__need_collapse = 0;
1580 sort__has_parent = 0;
1581 sort__has_sym = 0;
1582 sort__has_dso = 0;
1583
1584 reset_dimensions();
1585 perf_hpp__reset_output_field();
1198} 1586}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 43e5ff42a609..5f38d925e92f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -25,6 +25,7 @@
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[];
@@ -133,6 +134,8 @@ enum sort_mode {
133 SORT_MODE__NORMAL, 134 SORT_MODE__NORMAL,
134 SORT_MODE__BRANCH, 135 SORT_MODE__BRANCH,
135 SORT_MODE__MEMORY, 136 SORT_MODE__MEMORY,
137 SORT_MODE__TOP,
138 SORT_MODE__DIFF,
136}; 139};
137 140
138enum sort_type { 141enum sort_type {
@@ -179,6 +182,7 @@ struct sort_entry {
179 182
180 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); 183 int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
181 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); 184 int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
185 int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
182 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, 186 int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
183 unsigned int width); 187 unsigned int width);
184 u8 se_width_idx; 188 u8 se_width_idx;
@@ -189,6 +193,8 @@ extern struct sort_entry sort_thread;
189extern struct list_head hist_entry__sort_list; 193extern struct list_head hist_entry__sort_list;
190 194
191int setup_sorting(void); 195int setup_sorting(void);
196int setup_output_field(void);
197void reset_output_field(void);
192extern int sort_dimension__add(const char *); 198extern int sort_dimension__add(const char *);
193void sort__setup_elide(FILE *fp); 199void sort__setup_elide(FILE *fp);
194 200
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.h b/tools/perf/util/symbol.h
index 501e4e722e8e..33ede53fa6b9 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>
@@ -115,7 +116,8 @@ struct symbol_conf {
115 annotate_asm_raw, 116 annotate_asm_raw,
116 annotate_src, 117 annotate_src,
117 event_group, 118 event_group,
118 demangle; 119 demangle,
120 filter_relative;
119 const char *vmlinux_name, 121 const char *vmlinux_name,
120 *kallsyms_name, 122 *kallsyms_name,
121 *source_prefix, 123 *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.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..7fff6be07f07 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -166,6 +166,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) : 166 ssize_t ret = is_read ? read(fd, buf, left) :
167 write(fd, buf, left); 167 write(fd, buf, left);
168 168
169 if (ret < 0 && errno == EINTR)
170 continue;
169 if (ret <= 0) 171 if (ret <= 0)
170 return ret; 172 return ret;
171 173
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 6995d66f225c..b03da44e94e4 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>
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;