aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h13
-rw-r--r--tools/perf/util/cloexec.c57
-rw-r--r--tools/perf/util/cloexec.h6
-rw-r--r--tools/perf/util/config.c13
-rw-r--r--tools/perf/util/data.c3
-rw-r--r--tools/perf/util/debug.c56
-rw-r--r--tools/perf/util/debug.h22
-rw-r--r--tools/perf/util/dso.c71
-rw-r--r--tools/perf/util/dso.h26
-rw-r--r--tools/perf/util/event.c52
-rw-r--r--tools/perf/util/event.h10
-rw-r--r--tools/perf/util/evlist.c51
-rw-r--r--tools/perf/util/evsel.c26
-rw-r--r--tools/perf/util/evsel.h2
-rw-r--r--tools/perf/util/header.c51
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/linux/kernel.h21
-rw-r--r--tools/perf/util/kvm-stat.h140
-rw-r--r--tools/perf/util/machine.c139
-rw-r--r--tools/perf/util/machine.h8
-rw-r--r--tools/perf/util/map.c47
-rw-r--r--tools/perf/util/map.h15
-rw-r--r--tools/perf/util/parse-options.h5
-rw-r--r--tools/perf/util/probe-finder.c1
-rw-r--r--tools/perf/util/pstack.c1
-rw-r--r--tools/perf/util/python.c4
-rw-r--r--tools/perf/util/record.c27
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c1
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c197
-rw-r--r--tools/perf/util/session.c39
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c2
-rw-r--r--tools/perf/util/svghelper.c168
-rw-r--r--tools/perf/util/svghelper.h6
-rw-r--r--tools/perf/util/symbol-elf.c41
-rw-r--r--tools/perf/util/symbol-minimal.c43
-rw-r--r--tools/perf/util/symbol.c21
-rw-r--r--tools/perf/util/symbol.h9
-rw-r--r--tools/perf/util/thread.c13
-rw-r--r--tools/perf/util/thread.h1
-rw-r--r--tools/perf/util/trace-event-info.c13
-rw-r--r--tools/perf/util/trace-event-read.c2
-rw-r--r--tools/perf/util/tsc.c30
-rw-r--r--tools/perf/util/tsc.h12
-rw-r--r--tools/perf/util/unwind-libdw.c1
-rw-r--r--tools/perf/util/unwind-libunwind.c1
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/vdso.c97
-rw-r--r--tools/perf/util/vdso.h13
50 files changed, 1352 insertions, 242 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 48b6d3f50012..437ee09727e6 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -626,7 +626,7 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
626 626
627int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample) 627int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample)
628{ 628{
629 if (!symbol_conf.use_callchain) 629 if (!symbol_conf.use_callchain || sample->callchain == NULL)
630 return 0; 630 return 0;
631 return callchain_append(he->callchain, &callchain_cursor, sample->period); 631 return callchain_append(he->callchain, &callchain_cursor, sample->period);
632} 632}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 8f84423a75da..da43619d6173 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -176,4 +176,17 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
176 dest->first = src->curr; 176 dest->first = src->curr;
177 dest->nr -= src->pos; 177 dest->nr -= src->pos;
178} 178}
179
180#ifdef HAVE_SKIP_CALLCHAIN_IDX
181extern int arch_skip_callchain_idx(struct machine *machine,
182 struct thread *thread, struct ip_callchain *chain);
183#else
184static inline int arch_skip_callchain_idx(struct machine *machine __maybe_unused,
185 struct thread *thread __maybe_unused,
186 struct ip_callchain *chain __maybe_unused)
187{
188 return -1;
189}
190#endif
191
179#endif /* __PERF_CALLCHAIN_H */ 192#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c
new file mode 100644
index 000000000000..c5d05ec17220
--- /dev/null
+++ b/tools/perf/util/cloexec.c
@@ -0,0 +1,57 @@
1#include "util.h"
2#include "../perf.h"
3#include "cloexec.h"
4#include "asm/bug.h"
5
6static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
7
8static int perf_flag_probe(void)
9{
10 /* use 'safest' configuration as used in perf_evsel__fallback() */
11 struct perf_event_attr attr = {
12 .type = PERF_COUNT_SW_CPU_CLOCK,
13 .config = PERF_COUNT_SW_CPU_CLOCK,
14 };
15 int fd;
16 int err;
17
18 /* check cloexec flag */
19 fd = sys_perf_event_open(&attr, 0, -1, -1,
20 PERF_FLAG_FD_CLOEXEC);
21 err = errno;
22
23 if (fd >= 0) {
24 close(fd);
25 return 1;
26 }
27
28 WARN_ONCE(err != EINVAL,
29 "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
30 err, strerror(err));
31
32 /* not supported, confirm error related to PERF_FLAG_FD_CLOEXEC */
33 fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
34 err = errno;
35
36 if (WARN_ONCE(fd < 0,
37 "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
38 err, strerror(err)))
39 return -1;
40
41 close(fd);
42
43 return 0;
44}
45
46unsigned long perf_event_open_cloexec_flag(void)
47{
48 static bool probed;
49
50 if (!probed) {
51 if (perf_flag_probe() <= 0)
52 flag = 0;
53 probed = true;
54 }
55
56 return flag;
57}
diff --git a/tools/perf/util/cloexec.h b/tools/perf/util/cloexec.h
new file mode 100644
index 000000000000..94a5a7d829d5
--- /dev/null
+++ b/tools/perf/util/cloexec.h
@@ -0,0 +1,6 @@
1#ifndef __PERF_CLOEXEC_H
2#define __PERF_CLOEXEC_H
3
4unsigned long perf_event_open_cloexec_flag(void);
5
6#endif /* __PERF_CLOEXEC_H */
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 24519e14ac56..1e5e2e5af6b1 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -350,6 +350,16 @@ static int perf_default_core_config(const char *var __maybe_unused,
350 return 0; 350 return 0;
351} 351}
352 352
353static int perf_ui_config(const char *var, const char *value)
354{
355 /* Add other config variables here. */
356 if (!strcmp(var, "ui.show-headers")) {
357 symbol_conf.show_hist_headers = perf_config_bool(var, value);
358 return 0;
359 }
360 return 0;
361}
362
353int perf_default_config(const char *var, const char *value, 363int perf_default_config(const char *var, const char *value,
354 void *dummy __maybe_unused) 364 void *dummy __maybe_unused)
355{ 365{
@@ -359,6 +369,9 @@ int perf_default_config(const char *var, const char *value,
359 if (!prefixcmp(var, "hist.")) 369 if (!prefixcmp(var, "hist."))
360 return perf_hist_config(var, value); 370 return perf_hist_config(var, value);
361 371
372 if (!prefixcmp(var, "ui."))
373 return perf_ui_config(var, value);
374
362 /* Add other config variables here. */ 375 /* Add other config variables here. */
363 return 0; 376 return 0;
364} 377}
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c
index 55de44ecebef..29d720cf5844 100644
--- a/tools/perf/util/data.c
+++ b/tools/perf/util/data.c
@@ -7,6 +7,7 @@
7 7
8#include "data.h" 8#include "data.h"
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static bool check_pipe(struct perf_data_file *file) 12static bool check_pipe(struct perf_data_file *file)
12{ 13{
@@ -65,7 +66,7 @@ static int open_file_read(struct perf_data_file *file)
65 goto out_close; 66 goto out_close;
66 67
67 if (!file->force && st.st_uid && (st.st_uid != geteuid())) { 68 if (!file->force && st.st_uid && (st.st_uid != geteuid())) {
68 pr_err("file %s not owned by current user or root\n", 69 pr_err("File %s not owned by current user or root (use -f to override)\n",
69 file->path); 70 file->path);
70 goto out_close; 71 goto out_close;
71 } 72 }
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 299b55586502..71d419362634 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -16,11 +16,11 @@
16int verbose; 16int verbose;
17bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
18 18
19static int _eprintf(int level, const char *fmt, va_list args) 19static int _eprintf(int level, int var, const char *fmt, va_list args)
20{ 20{
21 int ret = 0; 21 int ret = 0;
22 22
23 if (verbose >= level) { 23 if (var >= level) {
24 if (use_browser >= 1) 24 if (use_browser >= 1)
25 ui_helpline__vshow(fmt, args); 25 ui_helpline__vshow(fmt, args);
26 else 26 else
@@ -30,13 +30,13 @@ static int _eprintf(int level, const char *fmt, va_list args)
30 return ret; 30 return ret;
31} 31}
32 32
33int eprintf(int level, const char *fmt, ...) 33int eprintf(int level, int var, const char *fmt, ...)
34{ 34{
35 va_list args; 35 va_list args;
36 int ret; 36 int ret;
37 37
38 va_start(args, fmt); 38 va_start(args, fmt);
39 ret = _eprintf(level, fmt, args); 39 ret = _eprintf(level, var, fmt, args);
40 va_end(args); 40 va_end(args);
41 41
42 return ret; 42 return ret;
@@ -51,9 +51,9 @@ void pr_stat(const char *fmt, ...)
51 va_list args; 51 va_list args;
52 52
53 va_start(args, fmt); 53 va_start(args, fmt);
54 _eprintf(1, fmt, args); 54 _eprintf(1, verbose, fmt, args);
55 va_end(args); 55 va_end(args);
56 eprintf(1, "\n"); 56 eprintf(1, verbose, "\n");
57} 57}
58 58
59int dump_printf(const char *fmt, ...) 59int dump_printf(const char *fmt, ...)
@@ -105,3 +105,47 @@ void trace_event(union perf_event *event)
105 } 105 }
106 printf(".\n"); 106 printf(".\n");
107} 107}
108
109static struct debug_variable {
110 const char *name;
111 int *ptr;
112} debug_variables[] = {
113 { .name = "verbose", .ptr = &verbose },
114 { .name = NULL, }
115};
116
117int perf_debug_option(const char *str)
118{
119 struct debug_variable *var = &debug_variables[0];
120 char *vstr, *s = strdup(str);
121 int v = 1;
122
123 vstr = strchr(s, '=');
124 if (vstr)
125 *vstr++ = 0;
126
127 while (var->name) {
128 if (!strcmp(s, var->name))
129 break;
130 var++;
131 }
132
133 if (!var->name) {
134 pr_err("Unknown debug variable name '%s'\n", s);
135 free(s);
136 return -1;
137 }
138
139 if (vstr) {
140 v = atoi(vstr);
141 /*
142 * Allow only values in range (0, 10),
143 * otherwise set 0.
144 */
145 v = (v < 0) || (v > 10) ? 0 : v;
146 }
147
148 *var->ptr = v;
149 free(s);
150 return 0;
151}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index 443694c36b03..89fb6b0f7ab2 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -11,6 +11,24 @@
11extern int verbose; 11extern int verbose;
12extern bool quiet, dump_trace; 12extern bool quiet, dump_trace;
13 13
14#ifndef pr_fmt
15#define pr_fmt(fmt) fmt
16#endif
17
18#define pr_err(fmt, ...) \
19 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
20#define pr_warning(fmt, ...) \
21 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
22#define pr_info(fmt, ...) \
23 eprintf(0, verbose, pr_fmt(fmt), ##__VA_ARGS__)
24#define pr_debug(fmt, ...) \
25 eprintf(1, verbose, pr_fmt(fmt), ##__VA_ARGS__)
26#define pr_debugN(n, fmt, ...) \
27 eprintf(n, verbose, pr_fmt(fmt), ##__VA_ARGS__)
28#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
29#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
30#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
31
14int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 32int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
15void trace_event(union perf_event *event); 33void trace_event(union perf_event *event);
16 34
@@ -19,4 +37,8 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
19 37
20void pr_stat(const char *fmt, ...); 38void pr_stat(const char *fmt, ...);
21 39
40int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
41
42int perf_debug_option(const char *str);
43
22#endif /* __PERF_DEBUG_H */ 44#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 819f10414f08..90d02c661dd4 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -216,7 +216,7 @@ static int open_dso(struct dso *dso, struct machine *machine)
216{ 216{
217 int fd = __open_dso(dso, machine); 217 int fd = __open_dso(dso, machine);
218 218
219 if (fd > 0) { 219 if (fd >= 0) {
220 dso__list_add(dso); 220 dso__list_add(dso);
221 /* 221 /*
222 * Check if we crossed the allowed number 222 * Check if we crossed the allowed number
@@ -331,26 +331,44 @@ int dso__data_fd(struct dso *dso, struct machine *machine)
331 }; 331 };
332 int i = 0; 332 int i = 0;
333 333
334 if (dso->data.status == DSO_DATA_STATUS_ERROR)
335 return -1;
336
334 if (dso->data.fd >= 0) 337 if (dso->data.fd >= 0)
335 return dso->data.fd; 338 goto out;
336 339
337 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) { 340 if (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND) {
338 dso->data.fd = open_dso(dso, machine); 341 dso->data.fd = open_dso(dso, machine);
339 return dso->data.fd; 342 goto out;
340 } 343 }
341 344
342 do { 345 do {
343 int fd;
344
345 dso->binary_type = binary_type_data[i++]; 346 dso->binary_type = binary_type_data[i++];
346 347
347 fd = open_dso(dso, machine); 348 dso->data.fd = open_dso(dso, machine);
348 if (fd >= 0) 349 if (dso->data.fd >= 0)
349 return dso->data.fd = fd; 350 goto out;
350 351
351 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND); 352 } while (dso->binary_type != DSO_BINARY_TYPE__NOT_FOUND);
353out:
354 if (dso->data.fd >= 0)
355 dso->data.status = DSO_DATA_STATUS_OK;
356 else
357 dso->data.status = DSO_DATA_STATUS_ERROR;
352 358
353 return -EINVAL; 359 return dso->data.fd;
360}
361
362bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by)
363{
364 u32 flag = 1 << by;
365
366 if (dso->data.status_seen & flag)
367 return true;
368
369 dso->data.status_seen |= flag;
370
371 return false;
354} 372}
355 373
356static void 374static void
@@ -526,6 +544,28 @@ static int data_file_size(struct dso *dso)
526 return 0; 544 return 0;
527} 545}
528 546
547/**
548 * dso__data_size - Return dso data size
549 * @dso: dso object
550 * @machine: machine object
551 *
552 * Return: dso data size
553 */
554off_t dso__data_size(struct dso *dso, struct machine *machine)
555{
556 int fd;
557
558 fd = dso__data_fd(dso, machine);
559 if (fd < 0)
560 return fd;
561
562 if (data_file_size(dso))
563 return -1;
564
565 /* For now just estimate dso data size is close to file size */
566 return dso->data.file_size;
567}
568
529static ssize_t data_read_offset(struct dso *dso, u64 offset, 569static ssize_t data_read_offset(struct dso *dso, u64 offset,
530 u8 *data, ssize_t size) 570 u8 *data, ssize_t size)
531{ 571{
@@ -701,8 +741,10 @@ struct dso *dso__new(const char *name)
701 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; 741 dso->symbols[i] = dso->symbol_names[i] = RB_ROOT;
702 dso->data.cache = RB_ROOT; 742 dso->data.cache = RB_ROOT;
703 dso->data.fd = -1; 743 dso->data.fd = -1;
744 dso->data.status = DSO_DATA_STATUS_UNKNOWN;
704 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; 745 dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
705 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND; 746 dso->binary_type = DSO_BINARY_TYPE__NOT_FOUND;
747 dso->is_64_bit = (sizeof(void *) == 8);
706 dso->loaded = 0; 748 dso->loaded = 0;
707 dso->rel = 0; 749 dso->rel = 0;
708 dso->sorted_by_name = 0; 750 dso->sorted_by_name = 0;
@@ -898,3 +940,14 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp)
898 940
899 return ret; 941 return ret;
900} 942}
943
944enum dso_type dso__type(struct dso *dso, struct machine *machine)
945{
946 int fd;
947
948 fd = dso__data_fd(dso, machine);
949 if (fd < 0)
950 return DSO__TYPE_UNKNOWN;
951
952 return dso__type_fd(fd);
953}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index ad553ba257bf..5e463c0964d4 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -5,6 +5,7 @@
5#include <linux/rbtree.h> 5#include <linux/rbtree.h>
6#include <stdbool.h> 6#include <stdbool.h>
7#include <linux/types.h> 7#include <linux/types.h>
8#include <linux/bitops.h>
8#include "map.h" 9#include "map.h"
9#include "build-id.h" 10#include "build-id.h"
10 11
@@ -40,6 +41,23 @@ enum dso_swap_type {
40 DSO_SWAP__YES, 41 DSO_SWAP__YES,
41}; 42};
42 43
44enum dso_data_status {
45 DSO_DATA_STATUS_ERROR = -1,
46 DSO_DATA_STATUS_UNKNOWN = 0,
47 DSO_DATA_STATUS_OK = 1,
48};
49
50enum dso_data_status_seen {
51 DSO_DATA_STATUS_SEEN_ITRACE,
52};
53
54enum dso_type {
55 DSO__TYPE_UNKNOWN,
56 DSO__TYPE_64BIT,
57 DSO__TYPE_32BIT,
58 DSO__TYPE_X32BIT,
59};
60
43#define DSO__SWAP(dso, type, val) \ 61#define DSO__SWAP(dso, type, val) \
44({ \ 62({ \
45 type ____r = val; \ 63 type ____r = val; \
@@ -90,6 +108,7 @@ struct dso {
90 u8 annotate_warned:1; 108 u8 annotate_warned:1;
91 u8 short_name_allocated:1; 109 u8 short_name_allocated:1;
92 u8 long_name_allocated:1; 110 u8 long_name_allocated:1;
111 u8 is_64_bit:1;
93 u8 sorted_by_name; 112 u8 sorted_by_name;
94 u8 loaded; 113 u8 loaded;
95 u8 rel; 114 u8 rel;
@@ -103,6 +122,8 @@ struct dso {
103 struct { 122 struct {
104 struct rb_root cache; 123 struct rb_root cache;
105 int fd; 124 int fd;
125 int status;
126 u32 status_seen;
106 size_t file_size; 127 size_t file_size;
107 struct list_head open_entry; 128 struct list_head open_entry;
108 } data; 129 } data;
@@ -153,6 +174,7 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
153 * The dso__data_* external interface provides following functions: 174 * The dso__data_* external interface provides following functions:
154 * dso__data_fd 175 * dso__data_fd
155 * dso__data_close 176 * dso__data_close
177 * dso__data_size
156 * dso__data_read_offset 178 * dso__data_read_offset
157 * dso__data_read_addr 179 * dso__data_read_addr
158 * 180 *
@@ -190,11 +212,13 @@ int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type t
190int dso__data_fd(struct dso *dso, struct machine *machine); 212int dso__data_fd(struct dso *dso, struct machine *machine);
191void dso__data_close(struct dso *dso); 213void dso__data_close(struct dso *dso);
192 214
215off_t dso__data_size(struct dso *dso, struct machine *machine);
193ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, 216ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine,
194 u64 offset, u8 *data, ssize_t size); 217 u64 offset, u8 *data, ssize_t size);
195ssize_t dso__data_read_addr(struct dso *dso, struct map *map, 218ssize_t dso__data_read_addr(struct dso *dso, struct map *map,
196 struct machine *machine, u64 addr, 219 struct machine *machine, u64 addr,
197 u8 *data, ssize_t size); 220 u8 *data, ssize_t size);
221bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by);
198 222
199struct map *dso__new_map(const char *name); 223struct map *dso__new_map(const char *name);
200struct dso *dso__kernel_findnew(struct machine *machine, const char *name, 224struct dso *dso__kernel_findnew(struct machine *machine, const char *name,
@@ -229,4 +253,6 @@ static inline bool dso__is_kcore(struct dso *dso)
229 253
230void dso__free_a2l(struct dso *dso); 254void dso__free_a2l(struct dso *dso);
231 255
256enum dso_type dso__type(struct dso *dso, struct machine *machine);
257
232#endif /* __PERF_DSO */ 258#endif /* __PERF_DSO */
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index d0281bdfa582..1398c83d896d 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -603,7 +603,14 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
603 603
604size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 604size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
605{ 605{
606 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); 606 const char *s;
607
608 if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC)
609 s = " exec";
610 else
611 s = "";
612
613 return fprintf(fp, "%s: %s:%d\n", s, event->comm.comm, event->comm.tid);
607} 614}
608 615
609int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 616int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
@@ -781,6 +788,7 @@ try_again:
781 cpumode == PERF_RECORD_MISC_USER && 788 cpumode == PERF_RECORD_MISC_USER &&
782 machine && mg != &machine->kmaps) { 789 machine && mg != &machine->kmaps) {
783 mg = &machine->kmaps; 790 mg = &machine->kmaps;
791 load_map = true;
784 goto try_again; 792 goto try_again;
785 } 793 }
786 } else { 794 } else {
@@ -866,3 +874,45 @@ int perf_event__preprocess_sample(const union perf_event *event,
866 874
867 return 0; 875 return 0;
868} 876}
877
878bool is_bts_event(struct perf_event_attr *attr)
879{
880 return attr->type == PERF_TYPE_HARDWARE &&
881 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
882 attr->sample_period == 1;
883}
884
885bool sample_addr_correlates_sym(struct perf_event_attr *attr)
886{
887 if (attr->type == PERF_TYPE_SOFTWARE &&
888 (attr->config == PERF_COUNT_SW_PAGE_FAULTS ||
889 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
890 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))
891 return true;
892
893 if (is_bts_event(attr))
894 return true;
895
896 return false;
897}
898
899void perf_event__preprocess_sample_addr(union perf_event *event,
900 struct perf_sample *sample,
901 struct machine *machine,
902 struct thread *thread,
903 struct addr_location *al)
904{
905 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
906
907 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
908 sample->addr, al);
909 if (!al->map)
910 thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
911 sample->addr, al);
912
913 al->cpu = sample->cpu;
914 al->sym = NULL;
915
916 if (al->map)
917 al->sym = map__find_symbol(al->map, al->addr, NULL);
918}
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index e5dd40addb30..94d6976180da 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -288,6 +288,16 @@ int perf_event__preprocess_sample(const union perf_event *event,
288 struct addr_location *al, 288 struct addr_location *al,
289 struct perf_sample *sample); 289 struct perf_sample *sample);
290 290
291struct thread;
292
293bool is_bts_event(struct perf_event_attr *attr);
294bool sample_addr_correlates_sym(struct perf_event_attr *attr);
295void perf_event__preprocess_sample_addr(union perf_event *event,
296 struct perf_sample *sample,
297 struct machine *machine,
298 struct thread *thread,
299 struct addr_location *al);
300
291const char *perf_event__name(unsigned int id); 301const char *perf_event__name(unsigned int id);
292 302
293size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, 303size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 59ef2802fcf6..814e954c1318 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -606,12 +606,17 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
606 return evlist->mmap != NULL ? 0 : -ENOMEM; 606 return evlist->mmap != NULL ? 0 : -ENOMEM;
607} 607}
608 608
609static int __perf_evlist__mmap(struct perf_evlist *evlist, 609struct mmap_params {
610 int idx, int prot, int mask, int fd) 610 int prot;
611 int mask;
612};
613
614static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
615 struct mmap_params *mp, int fd)
611{ 616{
612 evlist->mmap[idx].prev = 0; 617 evlist->mmap[idx].prev = 0;
613 evlist->mmap[idx].mask = mask; 618 evlist->mmap[idx].mask = mp->mask;
614 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, 619 evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, mp->prot,
615 MAP_SHARED, fd, 0); 620 MAP_SHARED, fd, 0);
616 if (evlist->mmap[idx].base == MAP_FAILED) { 621 if (evlist->mmap[idx].base == MAP_FAILED) {
617 pr_debug2("failed to mmap perf event ring buffer, error %d\n", 622 pr_debug2("failed to mmap perf event ring buffer, error %d\n",
@@ -625,8 +630,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist,
625} 630}
626 631
627static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, 632static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
628 int prot, int mask, int cpu, int thread, 633 struct mmap_params *mp, int cpu,
629 int *output) 634 int thread, int *output)
630{ 635{
631 struct perf_evsel *evsel; 636 struct perf_evsel *evsel;
632 637
@@ -635,8 +640,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
635 640
636 if (*output == -1) { 641 if (*output == -1) {
637 *output = fd; 642 *output = fd;
638 if (__perf_evlist__mmap(evlist, idx, prot, mask, 643 if (__perf_evlist__mmap(evlist, idx, mp, *output) < 0)
639 *output) < 0)
640 return -1; 644 return -1;
641 } else { 645 } else {
642 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) 646 if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0)
@@ -651,8 +655,8 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
651 return 0; 655 return 0;
652} 656}
653 657
654static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, 658static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
655 int mask) 659 struct mmap_params *mp)
656{ 660{
657 int cpu, thread; 661 int cpu, thread;
658 int nr_cpus = cpu_map__nr(evlist->cpus); 662 int nr_cpus = cpu_map__nr(evlist->cpus);
@@ -663,8 +667,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot,
663 int output = -1; 667 int output = -1;
664 668
665 for (thread = 0; thread < nr_threads; thread++) { 669 for (thread = 0; thread < nr_threads; thread++) {
666 if (perf_evlist__mmap_per_evsel(evlist, cpu, prot, mask, 670 if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
667 cpu, thread, &output)) 671 thread, &output))
668 goto out_unmap; 672 goto out_unmap;
669 } 673 }
670 } 674 }
@@ -677,8 +681,8 @@ out_unmap:
677 return -1; 681 return -1;
678} 682}
679 683
680static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, 684static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
681 int mask) 685 struct mmap_params *mp)
682{ 686{
683 int thread; 687 int thread;
684 int nr_threads = thread_map__nr(evlist->threads); 688 int nr_threads = thread_map__nr(evlist->threads);
@@ -687,8 +691,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot,
687 for (thread = 0; thread < nr_threads; thread++) { 691 for (thread = 0; thread < nr_threads; thread++) {
688 int output = -1; 692 int output = -1;
689 693
690 if (perf_evlist__mmap_per_evsel(evlist, thread, prot, mask, 0, 694 if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
691 thread, &output)) 695 &output))
692 goto out_unmap; 696 goto out_unmap;
693 } 697 }
694 698
@@ -793,7 +797,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
793 struct perf_evsel *evsel; 797 struct perf_evsel *evsel;
794 const struct cpu_map *cpus = evlist->cpus; 798 const struct cpu_map *cpus = evlist->cpus;
795 const struct thread_map *threads = evlist->threads; 799 const struct thread_map *threads = evlist->threads;
796 int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; 800 struct mmap_params mp = {
801 .prot = PROT_READ | (overwrite ? 0 : PROT_WRITE),
802 };
797 803
798 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) 804 if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0)
799 return -ENOMEM; 805 return -ENOMEM;
@@ -804,7 +810,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
804 evlist->overwrite = overwrite; 810 evlist->overwrite = overwrite;
805 evlist->mmap_len = perf_evlist__mmap_size(pages); 811 evlist->mmap_len = perf_evlist__mmap_size(pages);
806 pr_debug("mmap size %zuB\n", evlist->mmap_len); 812 pr_debug("mmap size %zuB\n", evlist->mmap_len);
807 mask = evlist->mmap_len - page_size - 1; 813 mp.mask = evlist->mmap_len - page_size - 1;
808 814
809 evlist__for_each(evlist, evsel) { 815 evlist__for_each(evlist, evsel) {
810 if ((evsel->attr.read_format & PERF_FORMAT_ID) && 816 if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
@@ -814,9 +820,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
814 } 820 }
815 821
816 if (cpu_map__empty(cpus)) 822 if (cpu_map__empty(cpus))
817 return perf_evlist__mmap_per_thread(evlist, prot, mask); 823 return perf_evlist__mmap_per_thread(evlist, &mp);
818 824
819 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 825 return perf_evlist__mmap_per_cpu(evlist, &mp);
820} 826}
821 827
822int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) 828int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
@@ -1214,10 +1220,11 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused,
1214 "For your workloads it needs to be <= 1\nHint:\t"); 1220 "For your workloads it needs to be <= 1\nHint:\t");
1215 } 1221 }
1216 printed += scnprintf(buf + printed, size - printed, 1222 printed += scnprintf(buf + printed, size - printed,
1217 "For system wide tracing it needs to be set to -1"); 1223 "For system wide tracing it needs to be set to -1.\n");
1218 1224
1219 printed += scnprintf(buf + printed, size - printed, 1225 printed += scnprintf(buf + printed, size - printed,
1220 ".\nHint:\tThe current value is %d.", value); 1226 "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
1227 "Hint:\tThe current value is %d.", value);
1221 break; 1228 break;
1222 default: 1229 default:
1223 scnprintf(buf, size, "%s", emsg); 1230 scnprintf(buf, size, "%s", emsg);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8606175fe1e8..21a373ebea22 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -29,6 +29,7 @@ static struct {
29 bool sample_id_all; 29 bool sample_id_all;
30 bool exclude_guest; 30 bool exclude_guest;
31 bool mmap2; 31 bool mmap2;
32 bool cloexec;
32} perf_missing_features; 33} perf_missing_features;
33 34
34#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 35#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -623,7 +624,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
623 attr->mmap_data = track; 624 attr->mmap_data = track;
624 } 625 }
625 626
626 if (opts->call_graph_enabled) 627 if (opts->call_graph_enabled && !evsel->no_aux_samples)
627 perf_evsel__config_callgraph(evsel, opts); 628 perf_evsel__config_callgraph(evsel, opts);
628 629
629 if (target__has_cpu(&opts->target)) 630 if (target__has_cpu(&opts->target))
@@ -637,7 +638,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
637 target__has_cpu(&opts->target) || per_cpu)) 638 target__has_cpu(&opts->target) || per_cpu))
638 perf_evsel__set_sample_bit(evsel, TIME); 639 perf_evsel__set_sample_bit(evsel, TIME);
639 640
640 if (opts->raw_samples) { 641 if (opts->raw_samples && !evsel->no_aux_samples) {
641 perf_evsel__set_sample_bit(evsel, TIME); 642 perf_evsel__set_sample_bit(evsel, TIME);
642 perf_evsel__set_sample_bit(evsel, RAW); 643 perf_evsel__set_sample_bit(evsel, RAW);
643 perf_evsel__set_sample_bit(evsel, CPU); 644 perf_evsel__set_sample_bit(evsel, CPU);
@@ -650,7 +651,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
650 attr->watermark = 0; 651 attr->watermark = 0;
651 attr->wakeup_events = 1; 652 attr->wakeup_events = 1;
652 } 653 }
653 if (opts->branch_stack) { 654 if (opts->branch_stack && !evsel->no_aux_samples) {
654 perf_evsel__set_sample_bit(evsel, BRANCH_STACK); 655 perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
655 attr->branch_sample_type = opts->branch_stack; 656 attr->branch_sample_type = opts->branch_stack;
656 } 657 }
@@ -681,6 +682,11 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
681 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && 682 if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) &&
682 !opts->initial_delay) 683 !opts->initial_delay)
683 attr->enable_on_exec = 1; 684 attr->enable_on_exec = 1;
685
686 if (evsel->immediate) {
687 attr->disabled = 0;
688 attr->enable_on_exec = 0;
689 }
684} 690}
685 691
686int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) 692int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
@@ -960,6 +966,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
960 ret += PRINT_ATTR2(exclude_user, exclude_kernel); 966 ret += PRINT_ATTR2(exclude_user, exclude_kernel);
961 ret += PRINT_ATTR2(exclude_hv, exclude_idle); 967 ret += PRINT_ATTR2(exclude_hv, exclude_idle);
962 ret += PRINT_ATTR2(mmap, comm); 968 ret += PRINT_ATTR2(mmap, comm);
969 ret += PRINT_ATTR2(mmap2, comm_exec);
963 ret += PRINT_ATTR2(freq, inherit_stat); 970 ret += PRINT_ATTR2(freq, inherit_stat);
964 ret += PRINT_ATTR2(enable_on_exec, task); 971 ret += PRINT_ATTR2(enable_on_exec, task);
965 ret += PRINT_ATTR2(watermark, precise_ip); 972 ret += PRINT_ATTR2(watermark, precise_ip);
@@ -967,7 +974,6 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
967 ret += PRINT_ATTR2(exclude_host, exclude_guest); 974 ret += PRINT_ATTR2(exclude_host, exclude_guest);
968 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, 975 ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel,
969 "excl.callchain_user", exclude_callchain_user); 976 "excl.callchain_user", exclude_callchain_user);
970 ret += PRINT_ATTR_U32(mmap2);
971 977
972 ret += PRINT_ATTR_U32(wakeup_events); 978 ret += PRINT_ATTR_U32(wakeup_events);
973 ret += PRINT_ATTR_U32(wakeup_watermark); 979 ret += PRINT_ATTR_U32(wakeup_watermark);
@@ -989,7 +995,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
989 struct thread_map *threads) 995 struct thread_map *threads)
990{ 996{
991 int cpu, thread; 997 int cpu, thread;
992 unsigned long flags = 0; 998 unsigned long flags = PERF_FLAG_FD_CLOEXEC;
993 int pid = -1, err; 999 int pid = -1, err;
994 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; 1000 enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE;
995 1001
@@ -998,11 +1004,13 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
998 return -ENOMEM; 1004 return -ENOMEM;
999 1005
1000 if (evsel->cgrp) { 1006 if (evsel->cgrp) {
1001 flags = PERF_FLAG_PID_CGROUP; 1007 flags |= PERF_FLAG_PID_CGROUP;
1002 pid = evsel->cgrp->fd; 1008 pid = evsel->cgrp->fd;
1003 } 1009 }
1004 1010
1005fallback_missing_features: 1011fallback_missing_features:
1012 if (perf_missing_features.cloexec)
1013 flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC;
1006 if (perf_missing_features.mmap2) 1014 if (perf_missing_features.mmap2)
1007 evsel->attr.mmap2 = 0; 1015 evsel->attr.mmap2 = 0;
1008 if (perf_missing_features.exclude_guest) 1016 if (perf_missing_features.exclude_guest)
@@ -1071,7 +1079,10 @@ try_fallback:
1071 if (err != -EINVAL || cpu > 0 || thread > 0) 1079 if (err != -EINVAL || cpu > 0 || thread > 0)
1072 goto out_close; 1080 goto out_close;
1073 1081
1074 if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { 1082 if (!perf_missing_features.cloexec && (flags & PERF_FLAG_FD_CLOEXEC)) {
1083 perf_missing_features.cloexec = true;
1084 goto fallback_missing_features;
1085 } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
1075 perf_missing_features.mmap2 = true; 1086 perf_missing_features.mmap2 = true;
1076 goto fallback_missing_features; 1087 goto fallback_missing_features;
1077 } else if (!perf_missing_features.exclude_guest && 1088 } else if (!perf_missing_features.exclude_guest &&
@@ -1940,6 +1951,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
1940 if_print(mmap); 1951 if_print(mmap);
1941 if_print(mmap2); 1952 if_print(mmap2);
1942 if_print(comm); 1953 if_print(comm);
1954 if_print(comm_exec);
1943 if_print(freq); 1955 if_print(freq);
1944 if_print(inherit_stat); 1956 if_print(inherit_stat);
1945 if_print(enable_on_exec); 1957 if_print(enable_on_exec);
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index a52e9a5bb2d0..d7f93ce0ebc1 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,6 +83,8 @@ struct perf_evsel {
83 int is_pos; 83 int is_pos;
84 bool supported; 84 bool supported;
85 bool needs_swap; 85 bool needs_swap;
86 bool no_aux_samples;
87 bool immediate;
86 /* parse modifier helper */ 88 /* parse modifier helper */
87 int exclude_GH; 89 int exclude_GH;
88 int nr_members; 90 int nr_members;
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 893f8e2df928..158c787ce0c4 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -200,6 +200,47 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id,
200 return write_padded(fd, name, name_len + 1, len); 200 return write_padded(fd, name, name_len + 1, len);
201} 201}
202 202
203static int __dsos__hit_all(struct list_head *head)
204{
205 struct dso *pos;
206
207 list_for_each_entry(pos, head, node)
208 pos->hit = true;
209
210 return 0;
211}
212
213static int machine__hit_all_dsos(struct machine *machine)
214{
215 int err;
216
217 err = __dsos__hit_all(&machine->kernel_dsos);
218 if (err)
219 return err;
220
221 return __dsos__hit_all(&machine->user_dsos);
222}
223
224int dsos__hit_all(struct perf_session *session)
225{
226 struct rb_node *nd;
227 int err;
228
229 err = machine__hit_all_dsos(&session->machines.host);
230 if (err)
231 return err;
232
233 for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
234 struct machine *pos = rb_entry(nd, struct machine, rb_node);
235
236 err = machine__hit_all_dsos(pos);
237 if (err)
238 return err;
239 }
240
241 return 0;
242}
243
203static int __dsos__write_buildid_table(struct list_head *head, 244static int __dsos__write_buildid_table(struct list_head *head,
204 struct machine *machine, 245 struct machine *machine,
205 pid_t pid, u16 misc, int fd) 246 pid_t pid, u16 misc, int fd)
@@ -215,9 +256,9 @@ static int __dsos__write_buildid_table(struct list_head *head,
215 if (!pos->hit) 256 if (!pos->hit)
216 continue; 257 continue;
217 258
218 if (is_vdso_map(pos->short_name)) { 259 if (dso__is_vdso(pos)) {
219 name = (char *) VDSO__MAP_NAME; 260 name = pos->short_name;
220 name_len = sizeof(VDSO__MAP_NAME) + 1; 261 name_len = pos->short_name_len + 1;
221 } else if (dso__is_kcore(pos)) { 262 } else if (dso__is_kcore(pos)) {
222 machine__mmap_name(machine, nm, sizeof(nm)); 263 machine__mmap_name(machine, nm, sizeof(nm));
223 name = nm; 264 name = nm;
@@ -298,7 +339,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
298 339
299 len = scnprintf(filename, size, "%s%s%s", 340 len = scnprintf(filename, size, "%s%s%s",
300 debugdir, slash ? "/" : "", 341 debugdir, slash ? "/" : "",
301 is_vdso ? VDSO__MAP_NAME : realname); 342 is_vdso ? DSO__NAME_VDSO : realname);
302 if (mkdir_p(filename, 0755)) 343 if (mkdir_p(filename, 0755))
303 goto out_free; 344 goto out_free;
304 345
@@ -386,7 +427,7 @@ static int dso__cache_build_id(struct dso *dso, struct machine *machine,
386 const char *debugdir) 427 const char *debugdir)
387{ 428{
388 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; 429 bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
389 bool is_vdso = is_vdso_map(dso->short_name); 430 bool is_vdso = dso__is_vdso(dso);
390 const char *name = dso->long_name; 431 const char *name = dso->long_name;
391 char nm[PATH_MAX]; 432 char nm[PATH_MAX];
392 433
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index d08cfe499404..8f5cbaea64a5 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -151,6 +151,8 @@ int perf_event__process_build_id(struct perf_tool *tool,
151 struct perf_session *session); 151 struct perf_session *session);
152bool is_perf_magic(u64 magic); 152bool is_perf_magic(u64 magic);
153 153
154int dsos__hit_all(struct perf_session *session);
155
154/* 156/*
155 * arch specific callback 157 * arch specific callback
156 */ 158 */
diff --git a/tools/perf/util/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index 9844c31b7c2b..09e8e7aea7c6 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -94,27 +94,6 @@ static inline int scnprintf(char * buf, size_t size, const char * fmt, ...)
94 return (i >= ssize) ? (ssize - 1) : i; 94 return (i >= ssize) ? (ssize - 1) : i;
95} 95}
96 96
97int eprintf(int level,
98 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
99
100#ifndef pr_fmt
101#define pr_fmt(fmt) fmt
102#endif
103
104#define pr_err(fmt, ...) \
105 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
106#define pr_warning(fmt, ...) \
107 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
108#define pr_info(fmt, ...) \
109 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
110#define pr_debug(fmt, ...) \
111 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
112#define pr_debugN(n, fmt, ...) \
113 eprintf(n, pr_fmt(fmt), ##__VA_ARGS__)
114#define pr_debug2(fmt, ...) pr_debugN(2, pr_fmt(fmt), ##__VA_ARGS__)
115#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
116#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
117
118/* 97/*
119 * This looks more complex than it should be. But we need to 98 * This looks more complex than it should be. But we need to
120 * get the type for the ~ right in round_down (it needs to be 99 * get the type for the ~ right in round_down (it needs to be
diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h
new file mode 100644
index 000000000000..0b5a8cd2ee79
--- /dev/null
+++ b/tools/perf/util/kvm-stat.h
@@ -0,0 +1,140 @@
1#ifndef __PERF_KVM_STAT_H
2#define __PERF_KVM_STAT_H
3
4#include "../perf.h"
5#include "evsel.h"
6#include "evlist.h"
7#include "session.h"
8#include "tool.h"
9#include "stat.h"
10
11struct event_key {
12 #define INVALID_KEY (~0ULL)
13 u64 key;
14 int info;
15 struct exit_reasons_table *exit_reasons;
16};
17
18struct kvm_event_stats {
19 u64 time;
20 struct stats stats;
21};
22
23struct kvm_event {
24 struct list_head hash_entry;
25 struct rb_node rb;
26
27 struct event_key key;
28
29 struct kvm_event_stats total;
30
31 #define DEFAULT_VCPU_NUM 8
32 int max_vcpu;
33 struct kvm_event_stats *vcpu;
34};
35
36typedef int (*key_cmp_fun)(struct kvm_event*, struct kvm_event*, int);
37
38struct kvm_event_key {
39 const char *name;
40 key_cmp_fun key;
41};
42
43struct perf_kvm_stat;
44
45struct child_event_ops {
46 void (*get_key)(struct perf_evsel *evsel,
47 struct perf_sample *sample,
48 struct event_key *key);
49 const char *name;
50};
51
52struct kvm_events_ops {
53 bool (*is_begin_event)(struct perf_evsel *evsel,
54 struct perf_sample *sample,
55 struct event_key *key);
56 bool (*is_end_event)(struct perf_evsel *evsel,
57 struct perf_sample *sample, struct event_key *key);
58 struct child_event_ops *child_ops;
59 void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
60 char *decode);
61 const char *name;
62};
63
64struct exit_reasons_table {
65 unsigned long exit_code;
66 const char *reason;
67};
68
69#define EVENTS_BITS 12
70#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
71
72struct perf_kvm_stat {
73 struct perf_tool tool;
74 struct record_opts opts;
75 struct perf_evlist *evlist;
76 struct perf_session *session;
77
78 const char *file_name;
79 const char *report_event;
80 const char *sort_key;
81 int trace_vcpu;
82
83 struct exit_reasons_table *exit_reasons;
84 const char *exit_reasons_isa;
85
86 struct kvm_events_ops *events_ops;
87 key_cmp_fun compare;
88 struct list_head kvm_events_cache[EVENTS_CACHE_SIZE];
89
90 u64 total_time;
91 u64 total_count;
92 u64 lost_events;
93 u64 duration;
94
95 const char *pid_str;
96 struct intlist *pid_list;
97
98 struct rb_root result;
99
100 int timerfd;
101 unsigned int display_time;
102 bool live;
103};
104
105struct kvm_reg_events_ops {
106 const char *name;
107 struct kvm_events_ops *ops;
108};
109
110void exit_event_get_key(struct perf_evsel *evsel,
111 struct perf_sample *sample,
112 struct event_key *key);
113bool exit_event_begin(struct perf_evsel *evsel,
114 struct perf_sample *sample,
115 struct event_key *key);
116bool exit_event_end(struct perf_evsel *evsel,
117 struct perf_sample *sample,
118 struct event_key *key);
119void exit_event_decode_key(struct perf_kvm_stat *kvm,
120 struct event_key *key,
121 char *decode);
122
123bool kvm_exit_event(struct perf_evsel *evsel);
124bool kvm_entry_event(struct perf_evsel *evsel);
125
126#define define_exit_reasons_table(name, symbols) \
127 static struct exit_reasons_table name[] = { \
128 symbols, { -1, NULL } \
129 }
130
131/*
132 * arch specific callbacks and data structures
133 */
134int cpu_isa_init(struct perf_kvm_stat *kvm, const char *cpuid);
135
136extern const char * const kvm_events_tp[];
137extern struct kvm_reg_events_ops kvm_reg_events_ops[];
138extern const char * const kvm_skip_events[];
139
140#endif /* __PERF_KVM_STAT_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index c73e1fc12e53..16bba9fff2c8 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -8,6 +8,7 @@
8#include "sort.h" 8#include "sort.h"
9#include "strlist.h" 9#include "strlist.h"
10#include "thread.h" 10#include "thread.h"
11#include "vdso.h"
11#include <stdbool.h> 12#include <stdbool.h>
12#include <symbol/kallsyms.h> 13#include <symbol/kallsyms.h>
13#include "unwind.h" 14#include "unwind.h"
@@ -23,6 +24,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
23 INIT_LIST_HEAD(&machine->dead_threads); 24 INIT_LIST_HEAD(&machine->dead_threads);
24 machine->last_match = NULL; 25 machine->last_match = NULL;
25 26
27 machine->vdso_info = NULL;
28
26 machine->kmaps.machine = machine; 29 machine->kmaps.machine = machine;
27 machine->pid = pid; 30 machine->pid = pid;
28 31
@@ -34,7 +37,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
34 return -ENOMEM; 37 return -ENOMEM;
35 38
36 if (pid != HOST_KERNEL_ID) { 39 if (pid != HOST_KERNEL_ID) {
37 struct thread *thread = machine__findnew_thread(machine, 0, 40 struct thread *thread = machine__findnew_thread(machine, -1,
38 pid); 41 pid);
39 char comm[64]; 42 char comm[64];
40 43
@@ -45,6 +48,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
45 thread__set_comm(thread, comm, 0); 48 thread__set_comm(thread, comm, 0);
46 } 49 }
47 50
51 machine->current_tid = NULL;
52
48 return 0; 53 return 0;
49} 54}
50 55
@@ -103,7 +108,9 @@ void machine__exit(struct machine *machine)
103 map_groups__exit(&machine->kmaps); 108 map_groups__exit(&machine->kmaps);
104 dsos__delete(&machine->user_dsos); 109 dsos__delete(&machine->user_dsos);
105 dsos__delete(&machine->kernel_dsos); 110 dsos__delete(&machine->kernel_dsos);
111 vdso__exit(machine);
106 zfree(&machine->root_dir); 112 zfree(&machine->root_dir);
113 zfree(&machine->current_tid);
107} 114}
108 115
109void machine__delete(struct machine *machine) 116void machine__delete(struct machine *machine)
@@ -272,6 +279,52 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
272 return; 279 return;
273} 280}
274 281
282static void machine__update_thread_pid(struct machine *machine,
283 struct thread *th, pid_t pid)
284{
285 struct thread *leader;
286
287 if (pid == th->pid_ || pid == -1 || th->pid_ != -1)
288 return;
289
290 th->pid_ = pid;
291
292 if (th->pid_ == th->tid)
293 return;
294
295 leader = machine__findnew_thread(machine, th->pid_, th->pid_);
296 if (!leader)
297 goto out_err;
298
299 if (!leader->mg)
300 leader->mg = map_groups__new();
301
302 if (!leader->mg)
303 goto out_err;
304
305 if (th->mg == leader->mg)
306 return;
307
308 if (th->mg) {
309 /*
310 * Maps are created from MMAP events which provide the pid and
311 * tid. Consequently there never should be any maps on a thread
312 * with an unknown pid. Just print an error if there are.
313 */
314 if (!map_groups__empty(th->mg))
315 pr_err("Discarding thread maps for %d:%d\n",
316 th->pid_, th->tid);
317 map_groups__delete(th->mg);
318 }
319
320 th->mg = map_groups__get(leader->mg);
321
322 return;
323
324out_err:
325 pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
326}
327
275static struct thread *__machine__findnew_thread(struct machine *machine, 328static struct thread *__machine__findnew_thread(struct machine *machine,
276 pid_t pid, pid_t tid, 329 pid_t pid, pid_t tid,
277 bool create) 330 bool create)
@@ -285,10 +338,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
285 * so most of the time we dont have to look up 338 * so most of the time we dont have to look up
286 * the full rbtree: 339 * the full rbtree:
287 */ 340 */
288 if (machine->last_match && machine->last_match->tid == tid) { 341 th = machine->last_match;
289 if (pid && pid != machine->last_match->pid_) 342 if (th && th->tid == tid) {
290 machine->last_match->pid_ = pid; 343 machine__update_thread_pid(machine, th, pid);
291 return machine->last_match; 344 return th;
292 } 345 }
293 346
294 while (*p != NULL) { 347 while (*p != NULL) {
@@ -297,8 +350,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
297 350
298 if (th->tid == tid) { 351 if (th->tid == tid) {
299 machine->last_match = th; 352 machine->last_match = th;
300 if (pid && pid != th->pid_) 353 machine__update_thread_pid(machine, th, pid);
301 th->pid_ = pid;
302 return th; 354 return th;
303 } 355 }
304 356
@@ -325,8 +377,10 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
325 * within thread__init_map_groups to find the thread 377 * within thread__init_map_groups to find the thread
326 * leader and that would screwed the rb tree. 378 * leader and that would screwed the rb tree.
327 */ 379 */
328 if (thread__init_map_groups(th, machine)) 380 if (thread__init_map_groups(th, machine)) {
381 thread__delete(th);
329 return NULL; 382 return NULL;
383 }
330 } 384 }
331 385
332 return th; 386 return th;
@@ -1045,14 +1099,14 @@ int machine__process_mmap2_event(struct machine *machine,
1045 else 1099 else
1046 type = MAP__FUNCTION; 1100 type = MAP__FUNCTION;
1047 1101
1048 map = map__new(&machine->user_dsos, event->mmap2.start, 1102 map = map__new(machine, event->mmap2.start,
1049 event->mmap2.len, event->mmap2.pgoff, 1103 event->mmap2.len, event->mmap2.pgoff,
1050 event->mmap2.pid, event->mmap2.maj, 1104 event->mmap2.pid, event->mmap2.maj,
1051 event->mmap2.min, event->mmap2.ino, 1105 event->mmap2.min, event->mmap2.ino,
1052 event->mmap2.ino_generation, 1106 event->mmap2.ino_generation,
1053 event->mmap2.prot, 1107 event->mmap2.prot,
1054 event->mmap2.flags, 1108 event->mmap2.flags,
1055 event->mmap2.filename, type); 1109 event->mmap2.filename, type, thread);
1056 1110
1057 if (map == NULL) 1111 if (map == NULL)
1058 goto out_problem; 1112 goto out_problem;
@@ -1095,11 +1149,11 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
1095 else 1149 else
1096 type = MAP__FUNCTION; 1150 type = MAP__FUNCTION;
1097 1151
1098 map = map__new(&machine->user_dsos, event->mmap.start, 1152 map = map__new(machine, event->mmap.start,
1099 event->mmap.len, event->mmap.pgoff, 1153 event->mmap.len, event->mmap.pgoff,
1100 event->mmap.pid, 0, 0, 0, 0, 0, 0, 1154 event->mmap.pid, 0, 0, 0, 0, 0, 0,
1101 event->mmap.filename, 1155 event->mmap.filename,
1102 type); 1156 type, thread);
1103 1157
1104 if (map == NULL) 1158 if (map == NULL)
1105 goto out_problem; 1159 goto out_problem;
@@ -1281,7 +1335,9 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1281 u8 cpumode = PERF_RECORD_MISC_USER; 1335 u8 cpumode = PERF_RECORD_MISC_USER;
1282 int chain_nr = min(max_stack, (int)chain->nr); 1336 int chain_nr = min(max_stack, (int)chain->nr);
1283 int i; 1337 int i;
1338 int j;
1284 int err; 1339 int err;
1340 int skip_idx __maybe_unused;
1285 1341
1286 callchain_cursor_reset(&callchain_cursor); 1342 callchain_cursor_reset(&callchain_cursor);
1287 1343
@@ -1290,14 +1346,26 @@ static int machine__resolve_callchain_sample(struct machine *machine,
1290 return 0; 1346 return 0;
1291 } 1347 }
1292 1348
1349 /*
1350 * Based on DWARF debug information, some architectures skip
1351 * a callchain entry saved by the kernel.
1352 */
1353 skip_idx = arch_skip_callchain_idx(machine, thread, chain);
1354
1293 for (i = 0; i < chain_nr; i++) { 1355 for (i = 0; i < chain_nr; i++) {
1294 u64 ip; 1356 u64 ip;
1295 struct addr_location al; 1357 struct addr_location al;
1296 1358
1297 if (callchain_param.order == ORDER_CALLEE) 1359 if (callchain_param.order == ORDER_CALLEE)
1298 ip = chain->ips[i]; 1360 j = i;
1299 else 1361 else
1300 ip = chain->ips[chain->nr - i - 1]; 1362 j = chain->nr - i - 1;
1363
1364#ifdef HAVE_SKIP_CALLCHAIN_IDX
1365 if (j == skip_idx)
1366 continue;
1367#endif
1368 ip = chain->ips[j];
1301 1369
1302 if (ip >= PERF_CONTEXT_MAX) { 1370 if (ip >= PERF_CONTEXT_MAX) {
1303 switch (ip) { 1371 switch (ip) {
@@ -1420,3 +1488,46 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too
1420 /* command specified */ 1488 /* command specified */
1421 return 0; 1489 return 0;
1422} 1490}
1491
1492pid_t machine__get_current_tid(struct machine *machine, int cpu)
1493{
1494 if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid)
1495 return -1;
1496
1497 return machine->current_tid[cpu];
1498}
1499
1500int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
1501 pid_t tid)
1502{
1503 struct thread *thread;
1504
1505 if (cpu < 0)
1506 return -EINVAL;
1507
1508 if (!machine->current_tid) {
1509 int i;
1510
1511 machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t));
1512 if (!machine->current_tid)
1513 return -ENOMEM;
1514 for (i = 0; i < MAX_NR_CPUS; i++)
1515 machine->current_tid[i] = -1;
1516 }
1517
1518 if (cpu >= MAX_NR_CPUS) {
1519 pr_err("Requested CPU %d too large. ", cpu);
1520 pr_err("Consider raising MAX_NR_CPUS\n");
1521 return -EINVAL;
1522 }
1523
1524 machine->current_tid[cpu] = tid;
1525
1526 thread = machine__findnew_thread(machine, pid, tid);
1527 if (!thread)
1528 return -ENOMEM;
1529
1530 thread->cpu = cpu;
1531
1532 return 0;
1533}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index c8c74a119398..b972824e6294 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -20,6 +20,8 @@ union perf_event;
20 20
21extern const char *ref_reloc_sym_names[]; 21extern const char *ref_reloc_sym_names[];
22 22
23struct vdso_info;
24
23struct machine { 25struct machine {
24 struct rb_node rb_node; 26 struct rb_node rb_node;
25 pid_t pid; 27 pid_t pid;
@@ -28,11 +30,13 @@ struct machine {
28 struct rb_root threads; 30 struct rb_root threads;
29 struct list_head dead_threads; 31 struct list_head dead_threads;
30 struct thread *last_match; 32 struct thread *last_match;
33 struct vdso_info *vdso_info;
31 struct list_head user_dsos; 34 struct list_head user_dsos;
32 struct list_head kernel_dsos; 35 struct list_head kernel_dsos;
33 struct map_groups kmaps; 36 struct map_groups kmaps;
34 struct map *vmlinux_maps[MAP__NR_TYPES]; 37 struct map *vmlinux_maps[MAP__NR_TYPES];
35 symbol_filter_t symbol_filter; 38 symbol_filter_t symbol_filter;
39 pid_t *current_tid;
36}; 40};
37 41
38static inline 42static inline
@@ -191,4 +195,8 @@ int machine__synthesize_threads(struct machine *machine, struct target *target,
191 perf_event__process, data_mmap); 195 perf_event__process, data_mmap);
192} 196}
193 197
198pid_t machine__get_current_tid(struct machine *machine, int cpu);
199int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
200 pid_t tid);
201
194#endif /* __PERF_MACHINE_H */ 202#endif /* __PERF_MACHINE_H */
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 25c571f4cba6..31b8905dd863 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -12,6 +12,8 @@
12#include "vdso.h" 12#include "vdso.h"
13#include "build-id.h" 13#include "build-id.h"
14#include "util.h" 14#include "util.h"
15#include "debug.h"
16#include "machine.h"
15#include <linux/string.h> 17#include <linux/string.h>
16 18
17const char *map_type__name[MAP__NR_TYPES] = { 19const char *map_type__name[MAP__NR_TYPES] = {
@@ -136,10 +138,10 @@ void map__init(struct map *map, enum map_type type,
136 map->erange_warned = false; 138 map->erange_warned = false;
137} 139}
138 140
139struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 141struct map *map__new(struct machine *machine, u64 start, u64 len,
140 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 142 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
141 u64 ino_gen, u32 prot, u32 flags, char *filename, 143 u64 ino_gen, u32 prot, u32 flags, char *filename,
142 enum map_type type) 144 enum map_type type, struct thread *thread)
143{ 145{
144 struct map *map = malloc(sizeof(*map)); 146 struct map *map = malloc(sizeof(*map));
145 147
@@ -172,9 +174,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
172 174
173 if (vdso) { 175 if (vdso) {
174 pgoff = 0; 176 pgoff = 0;
175 dso = vdso__dso_findnew(dsos__list); 177 dso = vdso__dso_findnew(machine, thread);
176 } else 178 } else
177 dso = __dsos__findnew(dsos__list, filename); 179 dso = __dsos__findnew(&machine->user_dsos, filename);
178 180
179 if (dso == NULL) 181 if (dso == NULL)
180 goto out_delete; 182 goto out_delete;
@@ -454,6 +456,20 @@ void map_groups__exit(struct map_groups *mg)
454 } 456 }
455} 457}
456 458
459bool map_groups__empty(struct map_groups *mg)
460{
461 int i;
462
463 for (i = 0; i < MAP__NR_TYPES; ++i) {
464 if (maps__first(&mg->maps[i]))
465 return false;
466 if (!list_empty(&mg->removed_maps[i]))
467 return false;
468 }
469
470 return true;
471}
472
457struct map_groups *map_groups__new(void) 473struct map_groups *map_groups__new(void)
458{ 474{
459 struct map_groups *mg = malloc(sizeof(*mg)); 475 struct map_groups *mg = malloc(sizeof(*mg));
@@ -554,8 +570,8 @@ int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter)
554 return ams->sym ? 0 : -1; 570 return ams->sym ? 0 : -1;
555} 571}
556 572
557size_t __map_groups__fprintf_maps(struct map_groups *mg, 573size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
558 enum map_type type, int verbose, FILE *fp) 574 FILE *fp)
559{ 575{
560 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); 576 size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
561 struct rb_node *nd; 577 struct rb_node *nd;
@@ -573,17 +589,16 @@ size_t __map_groups__fprintf_maps(struct map_groups *mg,
573 return printed; 589 return printed;
574} 590}
575 591
576size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp) 592static size_t map_groups__fprintf_maps(struct map_groups *mg, FILE *fp)
577{ 593{
578 size_t printed = 0, i; 594 size_t printed = 0, i;
579 for (i = 0; i < MAP__NR_TYPES; ++i) 595 for (i = 0; i < MAP__NR_TYPES; ++i)
580 printed += __map_groups__fprintf_maps(mg, i, verbose, fp); 596 printed += __map_groups__fprintf_maps(mg, i, fp);
581 return printed; 597 return printed;
582} 598}
583 599
584static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg, 600static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
585 enum map_type type, 601 enum map_type type, FILE *fp)
586 int verbose, FILE *fp)
587{ 602{
588 struct map *pos; 603 struct map *pos;
589 size_t printed = 0; 604 size_t printed = 0;
@@ -600,23 +615,23 @@ static size_t __map_groups__fprintf_removed_maps(struct map_groups *mg,
600} 615}
601 616
602static size_t map_groups__fprintf_removed_maps(struct map_groups *mg, 617static size_t map_groups__fprintf_removed_maps(struct map_groups *mg,
603 int verbose, FILE *fp) 618 FILE *fp)
604{ 619{
605 size_t printed = 0, i; 620 size_t printed = 0, i;
606 for (i = 0; i < MAP__NR_TYPES; ++i) 621 for (i = 0; i < MAP__NR_TYPES; ++i)
607 printed += __map_groups__fprintf_removed_maps(mg, i, verbose, fp); 622 printed += __map_groups__fprintf_removed_maps(mg, i, fp);
608 return printed; 623 return printed;
609} 624}
610 625
611size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp) 626size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
612{ 627{
613 size_t printed = map_groups__fprintf_maps(mg, verbose, fp); 628 size_t printed = map_groups__fprintf_maps(mg, fp);
614 printed += fprintf(fp, "Removed maps:\n"); 629 printed += fprintf(fp, "Removed maps:\n");
615 return printed + map_groups__fprintf_removed_maps(mg, verbose, fp); 630 return printed + map_groups__fprintf_removed_maps(mg, fp);
616} 631}
617 632
618int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 633int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
619 int verbose, FILE *fp) 634 FILE *fp)
620{ 635{
621 struct rb_root *root = &mg->maps[map->type]; 636 struct rb_root *root = &mg->maps[map->type];
622 struct rb_node *next = rb_first(root); 637 struct rb_node *next = rb_first(root);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 7758c72522ef..2f83954af050 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -66,6 +66,7 @@ struct map_groups {
66 66
67struct map_groups *map_groups__new(void); 67struct map_groups *map_groups__new(void);
68void map_groups__delete(struct map_groups *mg); 68void map_groups__delete(struct map_groups *mg);
69bool map_groups__empty(struct map_groups *mg);
69 70
70static inline struct map_groups *map_groups__get(struct map_groups *mg) 71static inline struct map_groups *map_groups__get(struct map_groups *mg)
71{ 72{
@@ -103,6 +104,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip);
103u64 map__objdump_2mem(struct map *map, u64 ip); 104u64 map__objdump_2mem(struct map *map, u64 ip);
104 105
105struct symbol; 106struct symbol;
107struct thread;
106 108
107/* map__for_each_symbol - iterate over the symbols in the given map 109/* map__for_each_symbol - iterate over the symbols in the given map
108 * 110 *
@@ -118,10 +120,10 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
118 120
119void map__init(struct map *map, enum map_type type, 121void map__init(struct map *map, enum map_type type,
120 u64 start, u64 end, u64 pgoff, struct dso *dso); 122 u64 start, u64 end, u64 pgoff, struct dso *dso);
121struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, 123struct map *map__new(struct machine *machine, u64 start, u64 len,
122 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino, 124 u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
123 u64 ino_gen, u32 prot, u32 flags, 125 u64 ino_gen, u32 prot, u32 flags,
124 char *filename, enum map_type type); 126 char *filename, enum map_type type, struct thread *thread);
125struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 127struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
126void map__delete(struct map *map); 128void map__delete(struct map *map);
127struct map *map__clone(struct map *map); 129struct map *map__clone(struct map *map);
@@ -141,8 +143,8 @@ void map__fixup_end(struct map *map);
141 143
142void map__reloc_vmlinux(struct map *map); 144void map__reloc_vmlinux(struct map *map);
143 145
144size_t __map_groups__fprintf_maps(struct map_groups *mg, 146size_t __map_groups__fprintf_maps(struct map_groups *mg, enum map_type type,
145 enum map_type type, int verbose, FILE *fp); 147 FILE *fp);
146void maps__insert(struct rb_root *maps, struct map *map); 148void maps__insert(struct rb_root *maps, struct map *map);
147void maps__remove(struct rb_root *maps, struct map *map); 149void maps__remove(struct rb_root *maps, struct map *map);
148struct map *maps__find(struct rb_root *maps, u64 addr); 150struct map *maps__find(struct rb_root *maps, u64 addr);
@@ -152,8 +154,7 @@ void map_groups__init(struct map_groups *mg);
152void map_groups__exit(struct map_groups *mg); 154void map_groups__exit(struct map_groups *mg);
153int map_groups__clone(struct map_groups *mg, 155int map_groups__clone(struct map_groups *mg,
154 struct map_groups *parent, enum map_type type); 156 struct map_groups *parent, enum map_type type);
155size_t map_groups__fprintf(struct map_groups *mg, int verbose, FILE *fp); 157size_t map_groups__fprintf(struct map_groups *mg, FILE *fp);
156size_t map_groups__fprintf_maps(struct map_groups *mg, int verbose, FILE *fp);
157 158
158int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, 159int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name,
159 u64 addr); 160 u64 addr);
@@ -210,7 +211,7 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *mg,
210} 211}
211 212
212int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map, 213int map_groups__fixup_overlappings(struct map_groups *mg, struct map *map,
213 int verbose, FILE *fp); 214 FILE *fp);
214 215
215struct map *map_groups__find_by_name(struct map_groups *mg, 216struct map *map_groups__find_by_name(struct map_groups *mg,
216 enum map_type type, const char *name); 217 enum map_type type, const char *name);
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index d8dac8ac5f37..b59ba858e73d 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -98,6 +98,7 @@ struct option {
98 parse_opt_cb *callback; 98 parse_opt_cb *callback;
99 intptr_t defval; 99 intptr_t defval;
100 bool *set; 100 bool *set;
101 void *data;
101}; 102};
102 103
103#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v ) 104#define check_vtype(v, type) ( BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v )
@@ -131,6 +132,10 @@ struct option {
131 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\ 132 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l),\
132 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\ 133 .value = (v), (a), .help = (h), .callback = (f), .defval = (intptr_t)d,\
133 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG} 134 .flags = PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NOARG}
135#define OPT_CALLBACK_OPTARG(s, l, v, d, a, h, f) \
136 { .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), \
137 .value = (v), (a), .help = (h), .callback = (f), \
138 .flags = PARSE_OPT_OPTARG, .data = (d) }
134 139
135/* parse_options() will filter out the processed options and leave the 140/* parse_options() will filter out the processed options and leave the
136 * non-option argments in argv[]. 141 * non-option argments in argv[].
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 98e304766416..dca9145d704c 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -26,7 +26,6 @@
26#include <errno.h> 26#include <errno.h>
27#include <stdio.h> 27#include <stdio.h>
28#include <unistd.h> 28#include <unistd.h>
29#include <getopt.h>
30#include <stdlib.h> 29#include <stdlib.h>
31#include <string.h> 30#include <string.h>
32#include <stdarg.h> 31#include <stdarg.h>
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c
index daa17aeb6c63..a126e6cc6e73 100644
--- a/tools/perf/util/pstack.c
+++ b/tools/perf/util/pstack.c
@@ -6,6 +6,7 @@
6 6
7#include "util.h" 7#include "util.h"
8#include "pstack.h" 8#include "pstack.h"
9#include "debug.h"
9#include <linux/kernel.h> 10#include <linux/kernel.h>
10#include <stdlib.h> 11#include <stdlib.h>
11 12
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 122669c18ff4..12aa9b0d0ba1 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -14,12 +14,12 @@
14 */ 14 */
15int verbose; 15int verbose;
16 16
17int eprintf(int level, const char *fmt, ...) 17int eprintf(int level, int var, const char *fmt, ...)
18{ 18{
19 va_list args; 19 va_list args;
20 int ret = 0; 20 int ret = 0;
21 21
22 if (verbose >= level) { 22 if (var >= level) {
23 va_start(args, fmt); 23 va_start(args, fmt);
24 ret = vfprintf(stderr, fmt, args); 24 ret = vfprintf(stderr, fmt, args);
25 va_end(args); 25 va_end(args);
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 049e0a09ccd3..fe8079edbdc1 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -4,6 +4,7 @@
4#include "parse-events.h" 4#include "parse-events.h"
5#include <api/fs/fs.h> 5#include <api/fs/fs.h>
6#include "util.h" 6#include "util.h"
7#include "cloexec.h"
7 8
8typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
9 10
@@ -11,6 +12,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
11{ 12{
12 struct perf_evlist *evlist; 13 struct perf_evlist *evlist;
13 struct perf_evsel *evsel; 14 struct perf_evsel *evsel;
15 unsigned long flags = perf_event_open_cloexec_flag();
14 int err = -EAGAIN, fd; 16 int err = -EAGAIN, fd;
15 17
16 evlist = perf_evlist__new(); 18 evlist = perf_evlist__new();
@@ -22,14 +24,14 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
22 24
23 evsel = perf_evlist__first(evlist); 25 evsel = perf_evlist__first(evlist);
24 26
25 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 27 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
26 if (fd < 0) 28 if (fd < 0)
27 goto out_delete; 29 goto out_delete;
28 close(fd); 30 close(fd);
29 31
30 fn(evsel); 32 fn(evsel);
31 33
32 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 34 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, flags);
33 if (fd < 0) { 35 if (fd < 0) {
34 if (errno == EINVAL) 36 if (errno == EINVAL)
35 err = -EINVAL; 37 err = -EINVAL;
@@ -69,15 +71,26 @@ static void perf_probe_sample_identifier(struct perf_evsel *evsel)
69 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 71 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
70} 72}
71 73
74static void perf_probe_comm_exec(struct perf_evsel *evsel)
75{
76 evsel->attr.comm_exec = 1;
77}
78
72bool perf_can_sample_identifier(void) 79bool perf_can_sample_identifier(void)
73{ 80{
74 return perf_probe_api(perf_probe_sample_identifier); 81 return perf_probe_api(perf_probe_sample_identifier);
75} 82}
76 83
84static bool perf_can_comm_exec(void)
85{
86 return perf_probe_api(perf_probe_comm_exec);
87}
88
77void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) 89void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
78{ 90{
79 struct perf_evsel *evsel; 91 struct perf_evsel *evsel;
80 bool use_sample_identifier = false; 92 bool use_sample_identifier = false;
93 bool use_comm_exec;
81 94
82 /* 95 /*
83 * Set the evsel leader links before we configure attributes, 96 * Set the evsel leader links before we configure attributes,
@@ -89,8 +102,13 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
89 if (evlist->cpus->map[0] < 0) 102 if (evlist->cpus->map[0] < 0)
90 opts->no_inherit = true; 103 opts->no_inherit = true;
91 104
92 evlist__for_each(evlist, evsel) 105 use_comm_exec = perf_can_comm_exec();
106
107 evlist__for_each(evlist, evsel) {
93 perf_evsel__config(evsel, opts); 108 perf_evsel__config(evsel, opts);
109 if (!evsel->idx && use_comm_exec)
110 evsel->attr.comm_exec = 1;
111 }
94 112
95 if (evlist->nr_entries > 1) { 113 if (evlist->nr_entries > 1) {
96 struct perf_evsel *first = perf_evlist__first(evlist); 114 struct perf_evsel *first = perf_evlist__first(evlist);
@@ -203,7 +221,8 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
203 cpu = evlist->cpus->map[0]; 221 cpu = evlist->cpus->map[0];
204 } 222 }
205 223
206 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 224 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1,
225 perf_event_open_cloexec_flag());
207 if (fd >= 0) { 226 if (fd >= 0) {
208 close(fd); 227 close(fd);
209 ret = true; 228 ret = true;
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index af7da565a750..b2dba9c0a3a1 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -34,6 +34,7 @@
34#include "../event.h" 34#include "../event.h"
35#include "../trace-event.h" 35#include "../trace-event.h"
36#include "../evsel.h" 36#include "../evsel.h"
37#include "../debug.h"
37 38
38void boot_Perf__Trace__Context(pTHX_ CV *cv); 39void boot_Perf__Trace__Context(pTHX_ CV *cv);
39void boot_DynaLoader(pTHX_ CV *cv); 40void boot_DynaLoader(pTHX_ CV *cv);
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 1c419321f707..cbce2545da45 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -27,11 +27,13 @@
27#include <errno.h> 27#include <errno.h>
28 28
29#include "../../perf.h" 29#include "../../perf.h"
30#include "../debug.h"
30#include "../evsel.h" 31#include "../evsel.h"
31#include "../util.h" 32#include "../util.h"
32#include "../event.h" 33#include "../event.h"
33#include "../thread.h" 34#include "../thread.h"
34#include "../trace-event.h" 35#include "../trace-event.h"
36#include "../machine.h"
35 37
36PyMODINIT_FUNC initperf_trace_context(void); 38PyMODINIT_FUNC initperf_trace_context(void);
37 39
@@ -50,10 +52,14 @@ static int zero_flag_atom;
50 52
51static PyObject *main_module, *main_dict; 53static PyObject *main_module, *main_dict;
52 54
55static void handler_call_die(const char *handler_name) NORETURN;
53static void handler_call_die(const char *handler_name) 56static void handler_call_die(const char *handler_name)
54{ 57{
55 PyErr_Print(); 58 PyErr_Print();
56 Py_FatalError("problem in Python trace event handler"); 59 Py_FatalError("problem in Python trace event handler");
60 // Py_FatalError does not return
61 // but we have to make the compiler happy
62 abort();
57} 63}
58 64
59/* 65/*
@@ -97,6 +103,7 @@ static void define_value(enum print_arg_type field_type,
97 retval = PyObject_CallObject(handler, t); 103 retval = PyObject_CallObject(handler, t);
98 if (retval == NULL) 104 if (retval == NULL)
99 handler_call_die(handler_name); 105 handler_call_die(handler_name);
106 Py_DECREF(retval);
100 } 107 }
101 108
102 Py_DECREF(t); 109 Py_DECREF(t);
@@ -143,6 +150,7 @@ static void define_field(enum print_arg_type field_type,
143 retval = PyObject_CallObject(handler, t); 150 retval = PyObject_CallObject(handler, t);
144 if (retval == NULL) 151 if (retval == NULL)
145 handler_call_die(handler_name); 152 handler_call_die(handler_name);
153 Py_DECREF(retval);
146 } 154 }
147 155
148 Py_DECREF(t); 156 Py_DECREF(t);
@@ -231,15 +239,133 @@ static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
231 return event; 239 return event;
232} 240}
233 241
242static PyObject *get_field_numeric_entry(struct event_format *event,
243 struct format_field *field, void *data)
244{
245 bool is_array = field->flags & FIELD_IS_ARRAY;
246 PyObject *obj, *list = NULL;
247 unsigned long long val;
248 unsigned int item_size, n_items, i;
249
250 if (is_array) {
251 list = PyList_New(field->arraylen);
252 item_size = field->size / field->arraylen;
253 n_items = field->arraylen;
254 } else {
255 item_size = field->size;
256 n_items = 1;
257 }
258
259 for (i = 0; i < n_items; i++) {
260
261 val = read_size(event, data + field->offset + i * item_size,
262 item_size);
263 if (field->flags & FIELD_IS_SIGNED) {
264 if ((long long)val >= LONG_MIN &&
265 (long long)val <= LONG_MAX)
266 obj = PyInt_FromLong(val);
267 else
268 obj = PyLong_FromLongLong(val);
269 } else {
270 if (val <= LONG_MAX)
271 obj = PyInt_FromLong(val);
272 else
273 obj = PyLong_FromUnsignedLongLong(val);
274 }
275 if (is_array)
276 PyList_SET_ITEM(list, i, obj);
277 }
278 if (is_array)
279 obj = list;
280 return obj;
281}
282
283
284static PyObject *python_process_callchain(struct perf_sample *sample,
285 struct perf_evsel *evsel,
286 struct addr_location *al)
287{
288 PyObject *pylist;
289
290 pylist = PyList_New(0);
291 if (!pylist)
292 Py_FatalError("couldn't create Python list");
293
294 if (!symbol_conf.use_callchain || !sample->callchain)
295 goto exit;
296
297 if (machine__resolve_callchain(al->machine, evsel, al->thread,
298 sample, NULL, NULL,
299 PERF_MAX_STACK_DEPTH) != 0) {
300 pr_err("Failed to resolve callchain. Skipping\n");
301 goto exit;
302 }
303 callchain_cursor_commit(&callchain_cursor);
304
305
306 while (1) {
307 PyObject *pyelem;
308 struct callchain_cursor_node *node;
309 node = callchain_cursor_current(&callchain_cursor);
310 if (!node)
311 break;
312
313 pyelem = PyDict_New();
314 if (!pyelem)
315 Py_FatalError("couldn't create Python dictionary");
316
317
318 pydict_set_item_string_decref(pyelem, "ip",
319 PyLong_FromUnsignedLongLong(node->ip));
320
321 if (node->sym) {
322 PyObject *pysym = PyDict_New();
323 if (!pysym)
324 Py_FatalError("couldn't create Python dictionary");
325 pydict_set_item_string_decref(pysym, "start",
326 PyLong_FromUnsignedLongLong(node->sym->start));
327 pydict_set_item_string_decref(pysym, "end",
328 PyLong_FromUnsignedLongLong(node->sym->end));
329 pydict_set_item_string_decref(pysym, "binding",
330 PyInt_FromLong(node->sym->binding));
331 pydict_set_item_string_decref(pysym, "name",
332 PyString_FromStringAndSize(node->sym->name,
333 node->sym->namelen));
334 pydict_set_item_string_decref(pyelem, "sym", pysym);
335 }
336
337 if (node->map) {
338 struct map *map = node->map;
339 const char *dsoname = "[unknown]";
340 if (map && map->dso && (map->dso->name || map->dso->long_name)) {
341 if (symbol_conf.show_kernel_path && map->dso->long_name)
342 dsoname = map->dso->long_name;
343 else if (map->dso->name)
344 dsoname = map->dso->name;
345 }
346 pydict_set_item_string_decref(pyelem, "dso",
347 PyString_FromString(dsoname));
348 }
349
350 callchain_cursor_advance(&callchain_cursor);
351 PyList_Append(pylist, pyelem);
352 Py_DECREF(pyelem);
353 }
354
355exit:
356 return pylist;
357}
358
359
234static void python_process_tracepoint(struct perf_sample *sample, 360static void python_process_tracepoint(struct perf_sample *sample,
235 struct perf_evsel *evsel, 361 struct perf_evsel *evsel,
236 struct thread *thread, 362 struct thread *thread,
237 struct addr_location *al) 363 struct addr_location *al)
238{ 364{
239 PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; 365 PyObject *handler, *retval, *context, *t, *obj, *callchain;
366 PyObject *dict = NULL;
240 static char handler_name[256]; 367 static char handler_name[256];
241 struct format_field *field; 368 struct format_field *field;
242 unsigned long long val;
243 unsigned long s, ns; 369 unsigned long s, ns;
244 struct event_format *event; 370 struct event_format *event;
245 unsigned n = 0; 371 unsigned n = 0;
@@ -280,18 +406,23 @@ static void python_process_tracepoint(struct perf_sample *sample,
280 PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); 406 PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
281 PyTuple_SetItem(t, n++, context); 407 PyTuple_SetItem(t, n++, context);
282 408
409 /* ip unwinding */
410 callchain = python_process_callchain(sample, evsel, al);
411
283 if (handler) { 412 if (handler) {
284 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); 413 PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
285 PyTuple_SetItem(t, n++, PyInt_FromLong(s)); 414 PyTuple_SetItem(t, n++, PyInt_FromLong(s));
286 PyTuple_SetItem(t, n++, PyInt_FromLong(ns)); 415 PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
287 PyTuple_SetItem(t, n++, PyInt_FromLong(pid)); 416 PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
288 PyTuple_SetItem(t, n++, PyString_FromString(comm)); 417 PyTuple_SetItem(t, n++, PyString_FromString(comm));
418 PyTuple_SetItem(t, n++, callchain);
289 } else { 419 } else {
290 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu)); 420 pydict_set_item_string_decref(dict, "common_cpu", PyInt_FromLong(cpu));
291 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s)); 421 pydict_set_item_string_decref(dict, "common_s", PyInt_FromLong(s));
292 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns)); 422 pydict_set_item_string_decref(dict, "common_ns", PyInt_FromLong(ns));
293 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid)); 423 pydict_set_item_string_decref(dict, "common_pid", PyInt_FromLong(pid));
294 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm)); 424 pydict_set_item_string_decref(dict, "common_comm", PyString_FromString(comm));
425 pydict_set_item_string_decref(dict, "common_callchain", callchain);
295 } 426 }
296 for (field = event->format.fields; field; field = field->next) { 427 for (field = event->format.fields; field; field = field->next) {
297 if (field->flags & FIELD_IS_STRING) { 428 if (field->flags & FIELD_IS_STRING) {
@@ -303,20 +434,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
303 offset = field->offset; 434 offset = field->offset;
304 obj = PyString_FromString((char *)data + offset); 435 obj = PyString_FromString((char *)data + offset);
305 } else { /* FIELD_IS_NUMERIC */ 436 } else { /* FIELD_IS_NUMERIC */
306 val = read_size(event, data + field->offset, 437 obj = get_field_numeric_entry(event, field, data);
307 field->size);
308 if (field->flags & FIELD_IS_SIGNED) {
309 if ((long long)val >= LONG_MIN &&
310 (long long)val <= LONG_MAX)
311 obj = PyInt_FromLong(val);
312 else
313 obj = PyLong_FromLongLong(val);
314 } else {
315 if (val <= LONG_MAX)
316 obj = PyInt_FromLong(val);
317 else
318 obj = PyLong_FromUnsignedLongLong(val);
319 }
320 } 438 }
321 if (handler) 439 if (handler)
322 PyTuple_SetItem(t, n++, obj); 440 PyTuple_SetItem(t, n++, obj);
@@ -324,6 +442,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
324 pydict_set_item_string_decref(dict, field->name, obj); 442 pydict_set_item_string_decref(dict, field->name, obj);
325 443
326 } 444 }
445
327 if (!handler) 446 if (!handler)
328 PyTuple_SetItem(t, n++, dict); 447 PyTuple_SetItem(t, n++, dict);
329 448
@@ -334,6 +453,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
334 retval = PyObject_CallObject(handler, t); 453 retval = PyObject_CallObject(handler, t);
335 if (retval == NULL) 454 if (retval == NULL)
336 handler_call_die(handler_name); 455 handler_call_die(handler_name);
456 Py_DECREF(retval);
337 } else { 457 } else {
338 handler = PyDict_GetItemString(main_dict, "trace_unhandled"); 458 handler = PyDict_GetItemString(main_dict, "trace_unhandled");
339 if (handler && PyCallable_Check(handler)) { 459 if (handler && PyCallable_Check(handler)) {
@@ -341,6 +461,7 @@ static void python_process_tracepoint(struct perf_sample *sample,
341 retval = PyObject_CallObject(handler, t); 461 retval = PyObject_CallObject(handler, t);
342 if (retval == NULL) 462 if (retval == NULL)
343 handler_call_die("trace_unhandled"); 463 handler_call_die("trace_unhandled");
464 Py_DECREF(retval);
344 } 465 }
345 Py_DECREF(dict); 466 Py_DECREF(dict);
346 } 467 }
@@ -353,7 +474,7 @@ static void python_process_general_event(struct perf_sample *sample,
353 struct thread *thread, 474 struct thread *thread,
354 struct addr_location *al) 475 struct addr_location *al)
355{ 476{
356 PyObject *handler, *retval, *t, *dict; 477 PyObject *handler, *retval, *t, *dict, *callchain, *dict_sample;
357 static char handler_name[64]; 478 static char handler_name[64];
358 unsigned n = 0; 479 unsigned n = 0;
359 480
@@ -369,6 +490,10 @@ static void python_process_general_event(struct perf_sample *sample,
369 if (!dict) 490 if (!dict)
370 Py_FatalError("couldn't create Python dictionary"); 491 Py_FatalError("couldn't create Python dictionary");
371 492
493 dict_sample = PyDict_New();
494 if (!dict_sample)
495 Py_FatalError("couldn't create Python dictionary");
496
372 snprintf(handler_name, sizeof(handler_name), "%s", "process_event"); 497 snprintf(handler_name, sizeof(handler_name), "%s", "process_event");
373 498
374 handler = PyDict_GetItemString(main_dict, handler_name); 499 handler = PyDict_GetItemString(main_dict, handler_name);
@@ -378,8 +503,21 @@ static void python_process_general_event(struct perf_sample *sample,
378 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel))); 503 pydict_set_item_string_decref(dict, "ev_name", PyString_FromString(perf_evsel__name(evsel)));
379 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize( 504 pydict_set_item_string_decref(dict, "attr", PyString_FromStringAndSize(
380 (const char *)&evsel->attr, sizeof(evsel->attr))); 505 (const char *)&evsel->attr, sizeof(evsel->attr)));
381 pydict_set_item_string_decref(dict, "sample", PyString_FromStringAndSize( 506
382 (const char *)sample, sizeof(*sample))); 507 pydict_set_item_string_decref(dict_sample, "pid",
508 PyInt_FromLong(sample->pid));
509 pydict_set_item_string_decref(dict_sample, "tid",
510 PyInt_FromLong(sample->tid));
511 pydict_set_item_string_decref(dict_sample, "cpu",
512 PyInt_FromLong(sample->cpu));
513 pydict_set_item_string_decref(dict_sample, "ip",
514 PyLong_FromUnsignedLongLong(sample->ip));
515 pydict_set_item_string_decref(dict_sample, "time",
516 PyLong_FromUnsignedLongLong(sample->time));
517 pydict_set_item_string_decref(dict_sample, "period",
518 PyLong_FromUnsignedLongLong(sample->period));
519 pydict_set_item_string_decref(dict, "sample", dict_sample);
520
383 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize( 521 pydict_set_item_string_decref(dict, "raw_buf", PyString_FromStringAndSize(
384 (const char *)sample->raw_data, sample->raw_size)); 522 (const char *)sample->raw_data, sample->raw_size));
385 pydict_set_item_string_decref(dict, "comm", 523 pydict_set_item_string_decref(dict, "comm",
@@ -393,6 +531,10 @@ static void python_process_general_event(struct perf_sample *sample,
393 PyString_FromString(al->sym->name)); 531 PyString_FromString(al->sym->name));
394 } 532 }
395 533
534 /* ip unwinding */
535 callchain = python_process_callchain(sample, evsel, al);
536 pydict_set_item_string_decref(dict, "callchain", callchain);
537
396 PyTuple_SetItem(t, n++, dict); 538 PyTuple_SetItem(t, n++, dict);
397 if (_PyTuple_Resize(&t, n) == -1) 539 if (_PyTuple_Resize(&t, n) == -1)
398 Py_FatalError("error resizing Python tuple"); 540 Py_FatalError("error resizing Python tuple");
@@ -400,6 +542,7 @@ static void python_process_general_event(struct perf_sample *sample,
400 retval = PyObject_CallObject(handler, t); 542 retval = PyObject_CallObject(handler, t);
401 if (retval == NULL) 543 if (retval == NULL)
402 handler_call_die(handler_name); 544 handler_call_die(handler_name);
545 Py_DECREF(retval);
403exit: 546exit:
404 Py_DECREF(dict); 547 Py_DECREF(dict);
405 Py_DECREF(t); 548 Py_DECREF(t);
@@ -521,8 +664,7 @@ static int python_stop_script(void)
521 retval = PyObject_CallObject(handler, NULL); 664 retval = PyObject_CallObject(handler, NULL);
522 if (retval == NULL) 665 if (retval == NULL)
523 handler_call_die("trace_end"); 666 handler_call_die("trace_end");
524 else 667 Py_DECREF(retval);
525 Py_DECREF(retval);
526out: 668out:
527 Py_XDECREF(main_dict); 669 Py_XDECREF(main_dict);
528 Py_XDECREF(main_module); 670 Py_XDECREF(main_module);
@@ -589,6 +731,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
589 fprintf(ofp, "common_nsecs, "); 731 fprintf(ofp, "common_nsecs, ");
590 fprintf(ofp, "common_pid, "); 732 fprintf(ofp, "common_pid, ");
591 fprintf(ofp, "common_comm,\n\t"); 733 fprintf(ofp, "common_comm,\n\t");
734 fprintf(ofp, "common_callchain, ");
592 735
593 not_first = 0; 736 not_first = 0;
594 count = 0; 737 count = 0;
@@ -632,7 +775,7 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
632 fprintf(ofp, "%%u"); 775 fprintf(ofp, "%%u");
633 } 776 }
634 777
635 fprintf(ofp, "\\n\" %% \\\n\t\t("); 778 fprintf(ofp, "\" %% \\\n\t\t(");
636 779
637 not_first = 0; 780 not_first = 0;
638 count = 0; 781 count = 0;
@@ -668,7 +811,15 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
668 fprintf(ofp, "%s", f->name); 811 fprintf(ofp, "%s", f->name);
669 } 812 }
670 813
671 fprintf(ofp, "),\n\n"); 814 fprintf(ofp, ")\n\n");
815
816 fprintf(ofp, "\t\tfor node in common_callchain:");
817 fprintf(ofp, "\n\t\t\tif 'sym' in node:");
818 fprintf(ofp, "\n\t\t\t\tprint \"\\t[%%x] %%s\" %% (node['ip'], node['sym']['name'])");
819 fprintf(ofp, "\n\t\t\telse:");
820 fprintf(ofp, "\n\t\t\t\tprint \"\t[%%x]\" %% (node['ip'])\n\n");
821 fprintf(ofp, "\t\tprint \"\\n\"\n\n");
822
672 } 823 }
673 824
674 fprintf(ofp, "def trace_unhandled(event_name, context, " 825 fprintf(ofp, "def trace_unhandled(event_name, context, "
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 64a186edc7be..88dfef70c13d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -14,7 +14,6 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "perf_regs.h" 16#include "perf_regs.h"
17#include "vdso.h"
18 17
19static int perf_session__open(struct perf_session *session) 18static int perf_session__open(struct perf_session *session)
20{ 19{
@@ -156,7 +155,6 @@ void perf_session__delete(struct perf_session *session)
156 if (session->file) 155 if (session->file)
157 perf_data_file__close(session->file); 156 perf_data_file__close(session->file);
158 free(session); 157 free(session);
159 vdso__exit();
160} 158}
161 159
162static int process_event_synth_tracing_data_stub(struct perf_tool *tool 160static int process_event_synth_tracing_data_stub(struct perf_tool *tool
@@ -511,6 +509,7 @@ static int flush_sample_queue(struct perf_session *s,
511 os->last_flush = iter->timestamp; 509 os->last_flush = iter->timestamp;
512 list_del(&iter->list); 510 list_del(&iter->list);
513 list_add(&iter->list, &os->sample_cache); 511 list_add(&iter->list, &os->sample_cache);
512 os->nr_samples--;
514 513
515 if (show_progress) 514 if (show_progress)
516 ui_progress__update(&prog, 1); 515 ui_progress__update(&prog, 1);
@@ -523,8 +522,6 @@ static int flush_sample_queue(struct perf_session *s,
523 list_entry(head->prev, struct sample_queue, list); 522 list_entry(head->prev, struct sample_queue, list);
524 } 523 }
525 524
526 os->nr_samples = 0;
527
528 return 0; 525 return 0;
529} 526}
530 527
@@ -994,8 +991,10 @@ static int perf_session_deliver_event(struct perf_session *session,
994 } 991 }
995} 992}
996 993
997static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, 994static s64 perf_session__process_user_event(struct perf_session *session,
998 struct perf_tool *tool, u64 file_offset) 995 union perf_event *event,
996 struct perf_tool *tool,
997 u64 file_offset)
999{ 998{
1000 int fd = perf_data_file__fd(session->file); 999 int fd = perf_data_file__fd(session->file);
1001 int err; 1000 int err;
@@ -1037,7 +1036,7 @@ static void event_swap(union perf_event *event, bool sample_id_all)
1037 swap(event, sample_id_all); 1036 swap(event, sample_id_all);
1038} 1037}
1039 1038
1040static int perf_session__process_event(struct perf_session *session, 1039static s64 perf_session__process_event(struct perf_session *session,
1041 union perf_event *event, 1040 union perf_event *event,
1042 struct perf_tool *tool, 1041 struct perf_tool *tool,
1043 u64 file_offset) 1042 u64 file_offset)
@@ -1083,13 +1082,14 @@ void perf_event_header__bswap(struct perf_event_header *hdr)
1083 1082
1084struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) 1083struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
1085{ 1084{
1086 return machine__findnew_thread(&session->machines.host, 0, pid); 1085 return machine__findnew_thread(&session->machines.host, -1, pid);
1087} 1086}
1088 1087
1089static struct thread *perf_session__register_idle_thread(struct perf_session *session) 1088static struct thread *perf_session__register_idle_thread(struct perf_session *session)
1090{ 1089{
1091 struct thread *thread = perf_session__findnew(session, 0); 1090 struct thread *thread;
1092 1091
1092 thread = machine__findnew_thread(&session->machines.host, 0, 0);
1093 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) { 1093 if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
1094 pr_err("problem inserting idle task.\n"); 1094 pr_err("problem inserting idle task.\n");
1095 thread = NULL; 1095 thread = NULL;
@@ -1147,7 +1147,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session,
1147 union perf_event *event; 1147 union perf_event *event;
1148 uint32_t size, cur_size = 0; 1148 uint32_t size, cur_size = 0;
1149 void *buf = NULL; 1149 void *buf = NULL;
1150 int skip = 0; 1150 s64 skip = 0;
1151 u64 head; 1151 u64 head;
1152 ssize_t err; 1152 ssize_t err;
1153 void *p; 1153 void *p;
@@ -1276,13 +1276,13 @@ int __perf_session__process_events(struct perf_session *session,
1276 u64 file_size, struct perf_tool *tool) 1276 u64 file_size, struct perf_tool *tool)
1277{ 1277{
1278 int fd = perf_data_file__fd(session->file); 1278 int fd = perf_data_file__fd(session->file);
1279 u64 head, page_offset, file_offset, file_pos; 1279 u64 head, page_offset, file_offset, file_pos, size;
1280 int err, mmap_prot, mmap_flags, map_idx = 0; 1280 int err, mmap_prot, mmap_flags, map_idx = 0;
1281 size_t mmap_size; 1281 size_t mmap_size;
1282 char *buf, *mmaps[NUM_MMAPS]; 1282 char *buf, *mmaps[NUM_MMAPS];
1283 union perf_event *event; 1283 union perf_event *event;
1284 uint32_t size;
1285 struct ui_progress prog; 1284 struct ui_progress prog;
1285 s64 skip;
1286 1286
1287 perf_tool__fill_defaults(tool); 1287 perf_tool__fill_defaults(tool);
1288 1288
@@ -1296,8 +1296,10 @@ int __perf_session__process_events(struct perf_session *session,
1296 ui_progress__init(&prog, file_size, "Processing events..."); 1296 ui_progress__init(&prog, file_size, "Processing events...");
1297 1297
1298 mmap_size = MMAP_SIZE; 1298 mmap_size = MMAP_SIZE;
1299 if (mmap_size > file_size) 1299 if (mmap_size > file_size) {
1300 mmap_size = file_size; 1300 mmap_size = file_size;
1301 session->one_mmap = true;
1302 }
1301 1303
1302 memset(mmaps, 0, sizeof(mmaps)); 1304 memset(mmaps, 0, sizeof(mmaps));
1303 1305
@@ -1319,6 +1321,10 @@ remap:
1319 mmaps[map_idx] = buf; 1321 mmaps[map_idx] = buf;
1320 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1); 1322 map_idx = (map_idx + 1) & (ARRAY_SIZE(mmaps) - 1);
1321 file_pos = file_offset + head; 1323 file_pos = file_offset + head;
1324 if (session->one_mmap) {
1325 session->one_mmap_addr = buf;
1326 session->one_mmap_offset = file_offset;
1327 }
1322 1328
1323more: 1329more:
1324 event = fetch_mmaped_event(session, head, mmap_size, buf); 1330 event = fetch_mmaped_event(session, head, mmap_size, buf);
@@ -1337,7 +1343,8 @@ more:
1337 size = event->header.size; 1343 size = event->header.size;
1338 1344
1339 if (size < sizeof(struct perf_event_header) || 1345 if (size < sizeof(struct perf_event_header) ||
1340 perf_session__process_event(session, event, tool, file_pos) < 0) { 1346 (skip = perf_session__process_event(session, event, tool, file_pos))
1347 < 0) {
1341 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n", 1348 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1342 file_offset + head, event->header.size, 1349 file_offset + head, event->header.size,
1343 event->header.type); 1350 event->header.type);
@@ -1345,6 +1352,9 @@ more:
1345 goto out_err; 1352 goto out_err;
1346 } 1353 }
1347 1354
1355 if (skip)
1356 size += skip;
1357
1348 head += size; 1358 head += size;
1349 file_pos += size; 1359 file_pos += size;
1350 1360
@@ -1364,6 +1374,7 @@ out_err:
1364 ui_progress__finish(); 1374 ui_progress__finish();
1365 perf_session__warn_about_errors(session, tool); 1375 perf_session__warn_about_errors(session, tool);
1366 perf_session_free_sample_buffers(session); 1376 perf_session_free_sample_buffers(session);
1377 session->one_mmap = false;
1367 return err; 1378 return err;
1368} 1379}
1369 1380
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3140f8ae6148..0321013bd9fd 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -36,6 +36,9 @@ struct perf_session {
36 struct trace_event tevent; 36 struct trace_event tevent;
37 struct events_stats stats; 37 struct events_stats stats;
38 bool repipe; 38 bool repipe;
39 bool one_mmap;
40 void *one_mmap_addr;
41 u64 one_mmap_offset;
39 struct ordered_samples ordered_samples; 42 struct ordered_samples ordered_samples;
40 struct perf_data_file *file; 43 struct perf_data_file *file;
41}; 44};
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 1ec57dd82284..14e5a039bc45 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1215,7 +1215,7 @@ static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1215 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1215 hse = container_of(fmt, struct hpp_sort_entry, hpp);
1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx); 1216 len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
1217 1217
1218 return scnprintf(hpp->buf, hpp->size, "%*s", len, hse->se->se_header); 1218 return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
1219} 1219}
1220 1220
1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1221static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index 6a0a13d07a28..283d3e73e2f2 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -30,6 +30,7 @@ static u64 turbo_frequency, max_freq;
30 30
31#define SLOT_MULT 30.0 31#define SLOT_MULT 30.0
32#define SLOT_HEIGHT 25.0 32#define SLOT_HEIGHT 25.0
33#define SLOT_HALF (SLOT_HEIGHT / 2)
33 34
34int svg_page_width = 1000; 35int svg_page_width = 1000;
35u64 svg_highlight; 36u64 svg_highlight;
@@ -114,8 +115,14 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
114 fprintf(svgfile, " rect { stroke-width: 1; }\n"); 115 fprintf(svgfile, " rect { stroke-width: 1; }\n");
115 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n"); 116 fprintf(svgfile, " rect.process { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:1; stroke:rgb( 0, 0, 0); } \n");
116 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 117 fprintf(svgfile, " rect.process2 { fill:rgb(180,180,180); fill-opacity:0.9; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.process3 { fill:rgb(180,180,180); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
117 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 119 fprintf(svgfile, " rect.sample { fill:rgb( 0, 0,255); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
118 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 120 fprintf(svgfile, " rect.sample_hi{ fill:rgb(255,128, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.error { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
122 fprintf(svgfile, " rect.net { fill:rgb( 0,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
123 fprintf(svgfile, " rect.disk { fill:rgb( 0, 0,255); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
124 fprintf(svgfile, " rect.sync { fill:rgb(128,128, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
125 fprintf(svgfile, " rect.poll { fill:rgb( 0,128,128); fill-opacity:0.2; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
119 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 126 fprintf(svgfile, " rect.blocked { fill:rgb(255, 0, 0); fill-opacity:0.5; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
120 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 127 fprintf(svgfile, " rect.waiting { fill:rgb(224,214, 0); fill-opacity:0.8; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
121 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n"); 128 fprintf(svgfile, " rect.WAITING { fill:rgb(255,214, 48); fill-opacity:0.6; stroke-width:0; stroke:rgb( 0, 0, 0); } \n");
@@ -132,12 +139,81 @@ void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end)
132 fprintf(svgfile, " ]]>\n </style>\n</defs>\n"); 139 fprintf(svgfile, " ]]>\n </style>\n</defs>\n");
133} 140}
134 141
142static double normalize_height(double height)
143{
144 if (height < 0.25)
145 return 0.25;
146 else if (height < 0.50)
147 return 0.50;
148 else if (height < 0.75)
149 return 0.75;
150 else
151 return 0.100;
152}
153
154void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
155{
156 double w = time2pixels(end) - time2pixels(start);
157 height = normalize_height(height);
158
159 if (!svgfile)
160 return;
161
162 fprintf(svgfile, "<g>\n");
163 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
164 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
165 time2pixels(start),
166 w,
167 Yslot * SLOT_MULT,
168 SLOT_HALF * height,
169 type);
170 fprintf(svgfile, "</g>\n");
171}
172
173void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
174{
175 double w = time2pixels(end) - time2pixels(start);
176 height = normalize_height(height);
177
178 if (!svgfile)
179 return;
180
181 fprintf(svgfile, "<g>\n");
182 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
183 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
184 time2pixels(start),
185 w,
186 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HALF * height,
187 SLOT_HALF * height,
188 type);
189 fprintf(svgfile, "</g>\n");
190}
191
192void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges)
193{
194 double w = time2pixels(end) - time2pixels(start);
195 height = normalize_height(height);
196
197 if (!svgfile)
198 return;
199
200 fprintf(svgfile, "<g>\n");
201 fprintf(svgfile, "<title>fd=%d error=%d merges=%d</title>\n", fd, err, merges);
202 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
203 time2pixels(start),
204 w,
205 Yslot * SLOT_MULT + SLOT_HEIGHT - SLOT_HEIGHT * height,
206 SLOT_HEIGHT * height,
207 type);
208 fprintf(svgfile, "</g>\n");
209}
210
135void svg_box(int Yslot, u64 start, u64 end, const char *type) 211void svg_box(int Yslot, u64 start, u64 end, const char *type)
136{ 212{
137 if (!svgfile) 213 if (!svgfile)
138 return; 214 return;
139 215
140 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 216 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
141 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type); 217 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, type);
142} 218}
143 219
@@ -174,7 +250,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
174 cpu, time_to_string(end - start)); 250 cpu, time_to_string(end - start));
175 if (backtrace) 251 if (backtrace)
176 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 252 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
177 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"%s\"/>\n", 253 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"%s\"/>\n",
178 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT, 254 time2pixels(start), time2pixels(end)-time2pixels(start), Yslot * SLOT_MULT, SLOT_HEIGHT,
179 type); 255 type);
180 256
@@ -186,7 +262,7 @@ void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
186 text_size = round_text_size(text_size); 262 text_size = round_text_size(text_size);
187 263
188 if (text_size > MIN_TEXT_SIZE) 264 if (text_size > MIN_TEXT_SIZE)
189 fprintf(svgfile, "<text x=\"%1.8f\" y=\"%1.8f\" font-size=\"%1.8fpt\">%i</text>\n", 265 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">%i</text>\n",
190 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1); 266 time2pixels(start), Yslot * SLOT_MULT + SLOT_HEIGHT - 1, text_size, cpu + 1);
191 267
192 fprintf(svgfile, "</g>\n"); 268 fprintf(svgfile, "</g>\n");
@@ -202,10 +278,10 @@ static char *time_to_string(u64 duration)
202 return text; 278 return text;
203 279
204 if (duration < 1000 * 1000) { /* less than 1 msec */ 280 if (duration < 1000 * 1000) { /* less than 1 msec */
205 sprintf(text, "%4.1f us", duration / 1000.0); 281 sprintf(text, "%.1f us", duration / 1000.0);
206 return text; 282 return text;
207 } 283 }
208 sprintf(text, "%4.1f ms", duration / 1000.0 / 1000); 284 sprintf(text, "%.1f ms", duration / 1000.0 / 1000);
209 285
210 return text; 286 return text;
211} 287}
@@ -233,14 +309,14 @@ void svg_waiting(int Yslot, int cpu, u64 start, u64 end, const char *backtrace)
233 309
234 font_size = round_text_size(font_size); 310 font_size = round_text_size(font_size);
235 311
236 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT); 312 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), Yslot * SLOT_MULT);
237 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start)); 313 fprintf(svgfile, "<title>#%d waiting %s</title>\n", cpu, time_to_string(end - start));
238 if (backtrace) 314 if (backtrace)
239 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace); 315 fprintf(svgfile, "<desc>Waiting on:\n%s</desc>\n", backtrace);
240 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 316 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
241 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style); 317 time2pixels(end)-time2pixels(start), SLOT_HEIGHT, style);
242 if (font_size > MIN_TEXT_SIZE) 318 if (font_size > MIN_TEXT_SIZE)
243 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%1.8fpt\"> %s</text>\n", 319 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\"> %s</text>\n",
244 font_size, text); 320 font_size, text);
245 fprintf(svgfile, "</g>\n"); 321 fprintf(svgfile, "</g>\n");
246} 322}
@@ -289,16 +365,16 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
289 365
290 fprintf(svgfile, "<g>\n"); 366 fprintf(svgfile, "<g>\n");
291 367
292 fprintf(svgfile, "<rect x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\" class=\"cpu\"/>\n", 368 fprintf(svgfile, "<rect x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\" class=\"cpu\"/>\n",
293 time2pixels(first_time), 369 time2pixels(first_time),
294 time2pixels(last_time)-time2pixels(first_time), 370 time2pixels(last_time)-time2pixels(first_time),
295 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 371 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
296 372
297 sprintf(cpu_string, "CPU %i", (int)cpu); 373 sprintf(cpu_string, "CPU %i", (int)cpu);
298 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 374 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
299 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string); 375 10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);
300 376
301 fprintf(svgfile, "<text transform=\"translate(%4.8f,%4.8f)\" font-size=\"1.25pt\">%s</text>\n", 377 fprintf(svgfile, "<text transform=\"translate(%.8f,%.8f)\" font-size=\"1.25pt\">%s</text>\n",
302 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model()); 378 10+time2pixels(first_time), cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - 4, cpu_model());
303 379
304 fprintf(svgfile, "</g>\n"); 380 fprintf(svgfile, "</g>\n");
@@ -319,11 +395,11 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
319 else 395 else
320 type = "sample"; 396 type = "sample";
321 397
322 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\">\n", time2pixels(start), cpu2y(cpu)); 398 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\">\n", time2pixels(start), cpu2y(cpu));
323 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start)); 399 fprintf(svgfile, "<title>%d %s running %s</title>\n", pid, name, time_to_string(end - start));
324 if (backtrace) 400 if (backtrace)
325 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace); 401 fprintf(svgfile, "<desc>Switched because:\n%s</desc>\n", backtrace);
326 fprintf(svgfile, "<rect x=\"0\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 402 fprintf(svgfile, "<rect x=\"0\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
327 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type); 403 time2pixels(end)-time2pixels(start), SLOT_MULT+SLOT_HEIGHT, type);
328 width = time2pixels(end)-time2pixels(start); 404 width = time2pixels(end)-time2pixels(start);
329 if (width > 6) 405 if (width > 6)
@@ -332,7 +408,7 @@ void svg_process(int cpu, u64 start, u64 end, int pid, const char *name, const c
332 width = round_text_size(width); 408 width = round_text_size(width);
333 409
334 if (width > MIN_TEXT_SIZE) 410 if (width > MIN_TEXT_SIZE)
335 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%3.8fpt\">%s</text>\n", 411 fprintf(svgfile, "<text transform=\"rotate(90)\" font-size=\"%.8fpt\">%s</text>\n",
336 width, name); 412 width, name);
337 413
338 fprintf(svgfile, "</g>\n"); 414 fprintf(svgfile, "</g>\n");
@@ -353,7 +429,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
353 type = 6; 429 type = 6;
354 sprintf(style, "c%i", type); 430 sprintf(style, "c%i", type);
355 431
356 fprintf(svgfile, "<rect class=\"%s\" x=\"%4.8f\" width=\"%4.8f\" y=\"%4.1f\" height=\"%4.1f\"/>\n", 432 fprintf(svgfile, "<rect class=\"%s\" x=\"%.8f\" width=\"%.8f\" y=\"%.1f\" height=\"%.1f\"/>\n",
357 style, 433 style,
358 time2pixels(start), time2pixels(end)-time2pixels(start), 434 time2pixels(start), time2pixels(end)-time2pixels(start),
359 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT); 435 cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);
@@ -365,7 +441,7 @@ void svg_cstate(int cpu, u64 start, u64 end, int type)
365 width = round_text_size(width); 441 width = round_text_size(width);
366 442
367 if (width > MIN_TEXT_SIZE) 443 if (width > MIN_TEXT_SIZE)
368 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"%3.8fpt\">C%i</text>\n", 444 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"%.8fpt\">C%i</text>\n",
369 time2pixels(start), cpu2y(cpu)+width, width, type); 445 time2pixels(start), cpu2y(cpu)+width, width, type);
370 446
371 fprintf(svgfile, "</g>\n"); 447 fprintf(svgfile, "</g>\n");
@@ -407,9 +483,9 @@ void svg_pstate(int cpu, u64 start, u64 end, u64 freq)
407 if (max_freq) 483 if (max_freq)
408 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT); 484 height = freq * 1.0 / max_freq * (SLOT_HEIGHT + SLOT_MULT);
409 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height; 485 height = 1 + cpu2y(cpu) + SLOT_MULT + SLOT_HEIGHT - height;
410 fprintf(svgfile, "<line x1=\"%4.8f\" x2=\"%4.8f\" y1=\"%4.1f\" y2=\"%4.1f\" class=\"pstate\"/>\n", 486 fprintf(svgfile, "<line x1=\"%.8f\" x2=\"%.8f\" y1=\"%.1f\" y2=\"%.1f\" class=\"pstate\"/>\n",
411 time2pixels(start), time2pixels(end), height, height); 487 time2pixels(start), time2pixels(end), height, height);
412 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\" font-size=\"0.25pt\">%s</text>\n", 488 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\" font-size=\"0.25pt\">%s</text>\n",
413 time2pixels(start), height+0.9, HzToHuman(freq)); 489 time2pixels(start), height+0.9, HzToHuman(freq));
414 490
415 fprintf(svgfile, "</g>\n"); 491 fprintf(svgfile, "</g>\n");
@@ -435,32 +511,32 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
435 511
436 if (row1 < row2) { 512 if (row1 < row2) {
437 if (row1) { 513 if (row1) {
438 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 514 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
439 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 515 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
440 if (desc2) 516 if (desc2)
441 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 517 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
442 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2); 518 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT + SLOT_HEIGHT/48, desc2);
443 } 519 }
444 if (row2) { 520 if (row2) {
445 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 521 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
446 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT); 522 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row2 * SLOT_MULT);
447 if (desc1) 523 if (desc1)
448 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n", 524 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &gt;</text></g>\n",
449 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1); 525 time2pixels(start), row2 * SLOT_MULT - SLOT_MULT/32, desc1);
450 } 526 }
451 } else { 527 } else {
452 if (row2) { 528 if (row2) {
453 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 529 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
454 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32); 530 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/32);
455 if (desc1) 531 if (desc1)
456 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 532 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
457 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1); 533 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT + SLOT_MULT/48, desc1);
458 } 534 }
459 if (row1) { 535 if (row1) {
460 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 536 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
461 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT); 537 time2pixels(start), row1 * SLOT_MULT - SLOT_MULT/32, time2pixels(start), row1 * SLOT_MULT);
462 if (desc2) 538 if (desc2)
463 fprintf(svgfile, "<g transform=\"translate(%4.8f,%4.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n", 539 fprintf(svgfile, "<g transform=\"translate(%.8f,%.8f)\"><text transform=\"rotate(90)\" font-size=\"0.02pt\">%s &lt;</text></g>\n",
464 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2); 540 time2pixels(start), row1 * SLOT_MULT - SLOT_HEIGHT/32, desc2);
465 } 541 }
466 } 542 }
@@ -468,7 +544,7 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc
468 if (row2 > row1) 544 if (row2 > row1)
469 height += SLOT_HEIGHT; 545 height += SLOT_HEIGHT;
470 if (row1) 546 if (row1)
471 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 547 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
472 time2pixels(start), height); 548 time2pixels(start), height);
473 549
474 fprintf(svgfile, "</g>\n"); 550 fprintf(svgfile, "</g>\n");
@@ -488,16 +564,16 @@ void svg_wakeline(u64 start, int row1, int row2, const char *backtrace)
488 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 564 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
489 565
490 if (row1 < row2) 566 if (row1 < row2)
491 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 567 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
492 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT); 568 time2pixels(start), row1 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row2 * SLOT_MULT);
493 else 569 else
494 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%4.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n", 570 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%.2f\" style=\"stroke:rgb(32,255,32);stroke-width:0.009\"/>\n",
495 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT); 571 time2pixels(start), row2 * SLOT_MULT + SLOT_HEIGHT, time2pixels(start), row1 * SLOT_MULT);
496 572
497 height = row1 * SLOT_MULT; 573 height = row1 * SLOT_MULT;
498 if (row2 > row1) 574 if (row2 > row1)
499 height += SLOT_HEIGHT; 575 height += SLOT_HEIGHT;
500 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n", 576 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(32,255,32)\"/>\n",
501 time2pixels(start), height); 577 time2pixels(start), height);
502 578
503 fprintf(svgfile, "</g>\n"); 579 fprintf(svgfile, "</g>\n");
@@ -515,9 +591,9 @@ void svg_interrupt(u64 start, int row, const char *backtrace)
515 if (backtrace) 591 if (backtrace)
516 fprintf(svgfile, "<desc>%s</desc>\n", backtrace); 592 fprintf(svgfile, "<desc>%s</desc>\n", backtrace);
517 593
518 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 594 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
519 time2pixels(start), row * SLOT_MULT); 595 time2pixels(start), row * SLOT_MULT);
520 fprintf(svgfile, "<circle cx=\"%4.8f\" cy=\"%4.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n", 596 fprintf(svgfile, "<circle cx=\"%.8f\" cy=\"%.2f\" r = \"0.01\" style=\"fill:rgb(255,128,128)\"/>\n",
521 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT); 597 time2pixels(start), row * SLOT_MULT + SLOT_HEIGHT);
522 598
523 fprintf(svgfile, "</g>\n"); 599 fprintf(svgfile, "</g>\n");
@@ -528,7 +604,7 @@ void svg_text(int Yslot, u64 start, const char *text)
528 if (!svgfile) 604 if (!svgfile)
529 return; 605 return;
530 606
531 fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n", 607 fprintf(svgfile, "<text x=\"%.8f\" y=\"%.8f\">%s</text>\n",
532 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text); 608 time2pixels(start), Yslot * SLOT_MULT+SLOT_HEIGHT/2, text);
533} 609}
534 610
@@ -537,12 +613,26 @@ static void svg_legenda_box(int X, const char *text, const char *style)
537 double boxsize; 613 double boxsize;
538 boxsize = SLOT_HEIGHT / 2; 614 boxsize = SLOT_HEIGHT / 2;
539 615
540 fprintf(svgfile, "<rect x=\"%i\" width=\"%4.8f\" y=\"0\" height=\"%4.1f\" class=\"%s\"/>\n", 616 fprintf(svgfile, "<rect x=\"%i\" width=\"%.8f\" y=\"0\" height=\"%.1f\" class=\"%s\"/>\n",
541 X, boxsize, boxsize, style); 617 X, boxsize, boxsize, style);
542 fprintf(svgfile, "<text transform=\"translate(%4.8f, %4.8f)\" font-size=\"%4.8fpt\">%s</text>\n", 618 fprintf(svgfile, "<text transform=\"translate(%.8f, %.8f)\" font-size=\"%.8fpt\">%s</text>\n",
543 X + boxsize + 5, boxsize, 0.8 * boxsize, text); 619 X + boxsize + 5, boxsize, 0.8 * boxsize, text);
544} 620}
545 621
622void svg_io_legenda(void)
623{
624 if (!svgfile)
625 return;
626
627 fprintf(svgfile, "<g>\n");
628 svg_legenda_box(0, "Disk", "disk");
629 svg_legenda_box(100, "Network", "net");
630 svg_legenda_box(200, "Sync", "sync");
631 svg_legenda_box(300, "Poll", "poll");
632 svg_legenda_box(400, "Error", "error");
633 fprintf(svgfile, "</g>\n");
634}
635
546void svg_legenda(void) 636void svg_legenda(void)
547{ 637{
548 if (!svgfile) 638 if (!svgfile)
@@ -559,7 +649,7 @@ void svg_legenda(void)
559 fprintf(svgfile, "</g>\n"); 649 fprintf(svgfile, "</g>\n");
560} 650}
561 651
562void svg_time_grid(void) 652void svg_time_grid(double min_thickness)
563{ 653{
564 u64 i; 654 u64 i;
565 655
@@ -579,8 +669,10 @@ void svg_time_grid(void)
579 color = 128; 669 color = 128;
580 } 670 }
581 671
582 fprintf(svgfile, "<line x1=\"%4.8f\" y1=\"%4.2f\" x2=\"%4.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%1.3f\"/>\n", 672 if (thickness >= min_thickness)
583 time2pixels(i), SLOT_MULT/2, time2pixels(i), total_height, color, color, color, thickness); 673 fprintf(svgfile, "<line x1=\"%.8f\" y1=\"%.2f\" x2=\"%.8f\" y2=\"%" PRIu64 "\" style=\"stroke:rgb(%i,%i,%i);stroke-width:%.3f\"/>\n",
674 time2pixels(i), SLOT_MULT/2, time2pixels(i),
675 total_height, color, color, color, thickness);
584 676
585 i += 10000000; 677 i += 10000000;
586 } 678 }
diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h
index e3aff5332e30..9292a5291445 100644
--- a/tools/perf/util/svghelper.h
+++ b/tools/perf/util/svghelper.h
@@ -4,6 +4,9 @@
4#include <linux/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_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
8extern void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
9extern void svg_fbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges);
7extern void svg_box(int Yslot, u64 start, u64 end, const char *type); 10extern void svg_box(int Yslot, u64 start, u64 end, const char *type);
8extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 11extern void svg_blocked(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
9extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace); 12extern void svg_running(int Yslot, int cpu, u64 start, u64 end, const char *backtrace);
@@ -16,7 +19,8 @@ extern void svg_cstate(int cpu, u64 start, u64 end, int type);
16extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq); 19extern void svg_pstate(int cpu, u64 start, u64 end, u64 freq);
17 20
18 21
19extern void svg_time_grid(void); 22extern void svg_time_grid(double min_thickness);
23extern void svg_io_legenda(void);
20extern void svg_legenda(void); 24extern void svg_legenda(void);
21extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace); 25extern void svg_wakeline(u64 start, int row1, int row2, const char *backtrace);
22extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace); 26extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc2, const char *backtrace);
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 6864661a79dd..d75349979e65 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -49,7 +49,8 @@ static inline uint8_t elf_sym__type(const GElf_Sym *sym)
49 49
50static inline int elf_sym__is_function(const GElf_Sym *sym) 50static inline int elf_sym__is_function(const GElf_Sym *sym)
51{ 51{
52 return elf_sym__type(sym) == STT_FUNC && 52 return (elf_sym__type(sym) == STT_FUNC ||
53 elf_sym__type(sym) == STT_GNU_IFUNC) &&
53 sym->st_name != 0 && 54 sym->st_name != 0 &&
54 sym->st_shndx != SHN_UNDEF; 55 sym->st_shndx != SHN_UNDEF;
55} 56}
@@ -598,6 +599,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
598 goto out_elf_end; 599 goto out_elf_end;
599 } 600 }
600 601
602 ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
603
601 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab", 604 ss->symtab = elf_section_by_name(elf, &ehdr, &ss->symshdr, ".symtab",
602 NULL); 605 NULL);
603 if (ss->symshdr.sh_type != SHT_SYMTAB) 606 if (ss->symshdr.sh_type != SHT_SYMTAB)
@@ -619,7 +622,7 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
619 GElf_Shdr shdr; 622 GElf_Shdr shdr;
620 ss->adjust_symbols = (ehdr.e_type == ET_EXEC || 623 ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
621 ehdr.e_type == ET_REL || 624 ehdr.e_type == ET_REL ||
622 is_vdso_map(dso->short_name) || 625 dso__is_vdso(dso) ||
623 elf_section_by_name(elf, &ehdr, &shdr, 626 elf_section_by_name(elf, &ehdr, &shdr,
624 ".gnu.prelink_undo", 627 ".gnu.prelink_undo",
625 NULL) != NULL); 628 NULL) != NULL);
@@ -698,6 +701,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
698 bool remap_kernel = false, adjust_kernel_syms = false; 701 bool remap_kernel = false, adjust_kernel_syms = false;
699 702
700 dso->symtab_type = syms_ss->type; 703 dso->symtab_type = syms_ss->type;
704 dso->is_64_bit = syms_ss->is_64_bit;
701 dso->rel = syms_ss->ehdr.e_type == ET_REL; 705 dso->rel = syms_ss->ehdr.e_type == ET_REL;
702 706
703 /* 707 /*
@@ -1024,6 +1028,39 @@ int file__read_maps(int fd, bool exe, mapfn_t mapfn, void *data,
1024 return err; 1028 return err;
1025} 1029}
1026 1030
1031enum dso_type dso__type_fd(int fd)
1032{
1033 enum dso_type dso_type = DSO__TYPE_UNKNOWN;
1034 GElf_Ehdr ehdr;
1035 Elf_Kind ek;
1036 Elf *elf;
1037
1038 elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
1039 if (elf == NULL)
1040 goto out;
1041
1042 ek = elf_kind(elf);
1043 if (ek != ELF_K_ELF)
1044 goto out_end;
1045
1046 if (gelf_getclass(elf) == ELFCLASS64) {
1047 dso_type = DSO__TYPE_64BIT;
1048 goto out_end;
1049 }
1050
1051 if (gelf_getehdr(elf, &ehdr) == NULL)
1052 goto out_end;
1053
1054 if (ehdr.e_machine == EM_X86_64)
1055 dso_type = DSO__TYPE_X32BIT;
1056 else
1057 dso_type = DSO__TYPE_32BIT;
1058out_end:
1059 elf_end(elf);
1060out:
1061 return dso_type;
1062}
1063
1027static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len) 1064static int copy_bytes(int from, off_t from_offs, int to, off_t to_offs, u64 len)
1028{ 1065{
1029 ssize_t r; 1066 ssize_t r;
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index bd15f490d04f..c9541fea9514 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -288,6 +288,44 @@ int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
288 return 0; 288 return 0;
289} 289}
290 290
291static int fd__is_64_bit(int fd)
292{
293 u8 e_ident[EI_NIDENT];
294
295 if (lseek(fd, 0, SEEK_SET))
296 return -1;
297
298 if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
299 return -1;
300
301 if (memcmp(e_ident, ELFMAG, SELFMAG) ||
302 e_ident[EI_VERSION] != EV_CURRENT)
303 return -1;
304
305 return e_ident[EI_CLASS] == ELFCLASS64;
306}
307
308enum dso_type dso__type_fd(int fd)
309{
310 Elf64_Ehdr ehdr;
311 int ret;
312
313 ret = fd__is_64_bit(fd);
314 if (ret < 0)
315 return DSO__TYPE_UNKNOWN;
316
317 if (ret)
318 return DSO__TYPE_64BIT;
319
320 if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
321 return DSO__TYPE_UNKNOWN;
322
323 if (ehdr.e_machine == EM_X86_64)
324 return DSO__TYPE_X32BIT;
325
326 return DSO__TYPE_32BIT;
327}
328
291int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, 329int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
292 struct symsrc *ss, 330 struct symsrc *ss,
293 struct symsrc *runtime_ss __maybe_unused, 331 struct symsrc *runtime_ss __maybe_unused,
@@ -295,6 +333,11 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
295 int kmodule __maybe_unused) 333 int kmodule __maybe_unused)
296{ 334{
297 unsigned char *build_id[BUILD_ID_SIZE]; 335 unsigned char *build_id[BUILD_ID_SIZE];
336 int ret;
337
338 ret = fd__is_64_bit(ss->fd);
339 if (ret >= 0)
340 dso->is_64_bit = ret;
298 341
299 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) { 342 if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
300 dso__set_build_id(dso, build_id); 343 dso__set_build_id(dso, build_id);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7b9096f29cdb..eb06746b06b2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -34,6 +34,7 @@ struct symbol_conf symbol_conf = {
34 .annotate_src = true, 34 .annotate_src = true,
35 .demangle = true, 35 .demangle = true,
36 .cumulate_callchain = true, 36 .cumulate_callchain = true,
37 .show_hist_headers = true,
37 .symfs = "", 38 .symfs = "",
38}; 39};
39 40
@@ -341,6 +342,16 @@ static struct symbol *symbols__first(struct rb_root *symbols)
341 return NULL; 342 return NULL;
342} 343}
343 344
345static struct symbol *symbols__next(struct symbol *sym)
346{
347 struct rb_node *n = rb_next(&sym->rb_node);
348
349 if (n)
350 return rb_entry(n, struct symbol, rb_node);
351
352 return NULL;
353}
354
344struct symbol_name_rb_node { 355struct symbol_name_rb_node {
345 struct rb_node rb_node; 356 struct rb_node rb_node;
346 struct symbol sym; 357 struct symbol sym;
@@ -411,11 +422,16 @@ struct symbol *dso__find_symbol(struct dso *dso,
411 return symbols__find(&dso->symbols[type], addr); 422 return symbols__find(&dso->symbols[type], addr);
412} 423}
413 424
414static struct symbol *dso__first_symbol(struct dso *dso, enum map_type type) 425struct symbol *dso__first_symbol(struct dso *dso, enum map_type type)
415{ 426{
416 return symbols__first(&dso->symbols[type]); 427 return symbols__first(&dso->symbols[type]);
417} 428}
418 429
430struct symbol *dso__next_symbol(struct symbol *sym)
431{
432 return symbols__next(sym);
433}
434
419struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 435struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
420 const char *name) 436 const char *name)
421{ 437{
@@ -1064,6 +1080,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1064 &is_64_bit); 1080 &is_64_bit);
1065 if (err) 1081 if (err)
1066 goto out_err; 1082 goto out_err;
1083 dso->is_64_bit = is_64_bit;
1067 1084
1068 if (list_empty(&md.maps)) { 1085 if (list_empty(&md.maps)) {
1069 err = -EINVAL; 1086 err = -EINVAL;
@@ -1662,6 +1679,7 @@ do_kallsyms:
1662 free(kallsyms_allocated_filename); 1679 free(kallsyms_allocated_filename);
1663 1680
1664 if (err > 0 && !dso__is_kcore(dso)) { 1681 if (err > 0 && !dso__is_kcore(dso)) {
1682 dso->binary_type = DSO_BINARY_TYPE__KALLSYMS;
1665 dso__set_long_name(dso, "[kernel.kallsyms]", false); 1683 dso__set_long_name(dso, "[kernel.kallsyms]", false);
1666 map__fixup_start(map); 1684 map__fixup_start(map);
1667 map__fixup_end(map); 1685 map__fixup_end(map);
@@ -1709,6 +1727,7 @@ static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map,
1709 if (err > 0) 1727 if (err > 0)
1710 pr_debug("Using %s for symbols\n", kallsyms_filename); 1728 pr_debug("Using %s for symbols\n", kallsyms_filename);
1711 if (err > 0 && !dso__is_kcore(dso)) { 1729 if (err > 0 && !dso__is_kcore(dso)) {
1730 dso->binary_type = DSO_BINARY_TYPE__GUEST_KALLSYMS;
1712 machine__mmap_name(machine, path, sizeof(path)); 1731 machine__mmap_name(machine, path, sizeof(path));
1713 dso__set_long_name(dso, strdup(path), true); 1732 dso__set_long_name(dso, strdup(path), true);
1714 map__fixup_start(map); 1733 map__fixup_start(map);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 615c752dd767..e7295e93cff9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -118,7 +118,8 @@ struct symbol_conf {
118 annotate_src, 118 annotate_src,
119 event_group, 119 event_group,
120 demangle, 120 demangle,
121 filter_relative; 121 filter_relative,
122 show_hist_headers;
122 const char *vmlinux_name, 123 const char *vmlinux_name,
123 *kallsyms_name, 124 *kallsyms_name,
124 *source_prefix, 125 *source_prefix,
@@ -215,6 +216,7 @@ struct symsrc {
215 GElf_Shdr dynshdr; 216 GElf_Shdr dynshdr;
216 217
217 bool adjust_symbols; 218 bool adjust_symbols;
219 bool is_64_bit;
218#endif 220#endif
219}; 221};
220 222
@@ -238,6 +240,11 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
238struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 240struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
239 const char *name); 241 const char *name);
240 242
243struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
244struct symbol *dso__next_symbol(struct symbol *sym);
245
246enum dso_type dso__type_fd(int fd);
247
241int filename__read_build_id(const char *filename, void *bf, size_t size); 248int filename__read_build_id(const char *filename, void *bf, size_t size);
242int sysfs__read_build_id(const char *filename, void *bf, size_t size); 249int sysfs__read_build_id(const char *filename, void *bf, size_t size);
243int modules__parse(const char *filename, void *arg, 250int modules__parse(const char *filename, void *arg,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 2fde0d5e40b5..12c7a253a63c 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -13,7 +13,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
13 struct thread *leader; 13 struct thread *leader;
14 pid_t pid = thread->pid_; 14 pid_t pid = thread->pid_;
15 15
16 if (pid == thread->tid) { 16 if (pid == thread->tid || pid == -1) {
17 thread->mg = map_groups__new(); 17 thread->mg = map_groups__new();
18 } else { 18 } else {
19 leader = machine__findnew_thread(machine, pid, pid); 19 leader = machine__findnew_thread(machine, pid, pid);
@@ -34,6 +34,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
34 thread->pid_ = pid; 34 thread->pid_ = pid;
35 thread->tid = tid; 35 thread->tid = tid;
36 thread->ppid = -1; 36 thread->ppid = -1;
37 thread->cpu = -1;
37 INIT_LIST_HEAD(&thread->comm_list); 38 INIT_LIST_HEAD(&thread->comm_list);
38 39
39 comm_str = malloc(32); 40 comm_str = malloc(32);
@@ -60,8 +61,10 @@ void thread__delete(struct thread *thread)
60{ 61{
61 struct comm *comm, *tmp; 62 struct comm *comm, *tmp;
62 63
63 map_groups__put(thread->mg); 64 if (thread->mg) {
64 thread->mg = NULL; 65 map_groups__put(thread->mg);
66 thread->mg = NULL;
67 }
65 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) { 68 list_for_each_entry_safe(comm, tmp, &thread->comm_list, list) {
66 list_del(&comm->list); 69 list_del(&comm->list);
67 comm__free(comm); 70 comm__free(comm);
@@ -127,12 +130,12 @@ int thread__comm_len(struct thread *thread)
127size_t thread__fprintf(struct thread *thread, FILE *fp) 130size_t thread__fprintf(struct thread *thread, FILE *fp)
128{ 131{
129 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) + 132 return fprintf(fp, "Thread %d %s\n", thread->tid, thread__comm_str(thread)) +
130 map_groups__fprintf(thread->mg, verbose, fp); 133 map_groups__fprintf(thread->mg, fp);
131} 134}
132 135
133void thread__insert_map(struct thread *thread, struct map *map) 136void thread__insert_map(struct thread *thread, struct map *map)
134{ 137{
135 map_groups__fixup_overlappings(thread->mg, map, verbose, stderr); 138 map_groups__fixup_overlappings(thread->mg, map, stderr);
136 map_groups__insert(thread->mg, map); 139 map_groups__insert(thread->mg, map);
137} 140}
138 141
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 3c0c2724f82c..716b7723cce2 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -17,6 +17,7 @@ struct thread {
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;
20 int cpu;
20 char shortname[3]; 21 char shortname[3];
21 bool comm_set; 22 bool comm_set;
22 bool dead; /* if set thread has exited */ 23 bool dead; /* if set thread has exited */
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 7e6fcfe8b438..eb72716017ac 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -40,6 +40,7 @@
40#include "trace-event.h" 40#include "trace-event.h"
41#include <api/fs/debugfs.h> 41#include <api/fs/debugfs.h>
42#include "evsel.h" 42#include "evsel.h"
43#include "debug.h"
43 44
44#define VERSION "0.5" 45#define VERSION "0.5"
45 46
@@ -191,12 +192,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
191 strcmp(dent->d_name, "..") == 0 || 192 strcmp(dent->d_name, "..") == 0 ||
192 !name_in_tp_list(dent->d_name, tps)) 193 !name_in_tp_list(dent->d_name, tps))
193 continue; 194 continue;
194 format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 195 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
195 if (!format) {
196 err = -ENOMEM; 196 err = -ENOMEM;
197 goto out; 197 goto out;
198 } 198 }
199 sprintf(format, "%s/%s/format", sys, dent->d_name);
200 ret = stat(format, &st); 199 ret = stat(format, &st);
201 free(format); 200 free(format);
202 if (ret < 0) 201 if (ret < 0)
@@ -217,12 +216,10 @@ static int copy_event_system(const char *sys, struct tracepoint_path *tps)
217 strcmp(dent->d_name, "..") == 0 || 216 strcmp(dent->d_name, "..") == 0 ||
218 !name_in_tp_list(dent->d_name, tps)) 217 !name_in_tp_list(dent->d_name, tps))
219 continue; 218 continue;
220 format = malloc(strlen(sys) + strlen(dent->d_name) + 10); 219 if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
221 if (!format) {
222 err = -ENOMEM; 220 err = -ENOMEM;
223 goto out; 221 goto out;
224 } 222 }
225 sprintf(format, "%s/%s/format", sys, dent->d_name);
226 ret = stat(format, &st); 223 ret = stat(format, &st);
227 224
228 if (ret >= 0) { 225 if (ret >= 0) {
@@ -317,12 +314,10 @@ static int record_event_files(struct tracepoint_path *tps)
317 strcmp(dent->d_name, "ftrace") == 0 || 314 strcmp(dent->d_name, "ftrace") == 0 ||
318 !system_in_tp_list(dent->d_name, tps)) 315 !system_in_tp_list(dent->d_name, tps))
319 continue; 316 continue;
320 sys = malloc(strlen(path) + strlen(dent->d_name) + 2); 317 if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
321 if (!sys) {
322 err = -ENOMEM; 318 err = -ENOMEM;
323 goto out; 319 goto out;
324 } 320 }
325 sprintf(sys, "%s/%s", path, dent->d_name);
326 ret = stat(sys, &st); 321 ret = stat(sys, &st);
327 if (ret >= 0) { 322 if (ret >= 0) {
328 ssize_t size = strlen(dent->d_name) + 1; 323 ssize_t size = strlen(dent->d_name) + 1;
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index e113e180c48f..54d9e9b548a8 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -22,7 +22,6 @@
22#include <stdio.h> 22#include <stdio.h>
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <getopt.h>
26#include <stdarg.h> 25#include <stdarg.h>
27#include <sys/types.h> 26#include <sys/types.h>
28#include <sys/stat.h> 27#include <sys/stat.h>
@@ -36,6 +35,7 @@
36#include "../perf.h" 35#include "../perf.h"
37#include "util.h" 36#include "util.h"
38#include "trace-event.h" 37#include "trace-event.h"
38#include "debug.h"
39 39
40static int input_fd; 40static int input_fd;
41 41
diff --git a/tools/perf/util/tsc.c b/tools/perf/util/tsc.c
new file mode 100644
index 000000000000..4d4210d4e13d
--- /dev/null
+++ b/tools/perf/util/tsc.c
@@ -0,0 +1,30 @@
1#include <linux/compiler.h>
2#include <linux/types.h>
3
4#include "tsc.h"
5
6u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc)
7{
8 u64 t, quot, rem;
9
10 t = ns - tc->time_zero;
11 quot = t / tc->time_mult;
12 rem = t % tc->time_mult;
13 return (quot << tc->time_shift) +
14 (rem << tc->time_shift) / tc->time_mult;
15}
16
17u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
18{
19 u64 quot, rem;
20
21 quot = cyc >> tc->time_shift;
22 rem = cyc & ((1 << tc->time_shift) - 1);
23 return tc->time_zero + quot * tc->time_mult +
24 ((rem * tc->time_mult) >> tc->time_shift);
25}
26
27u64 __weak rdtsc(void)
28{
29 return 0;
30}
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h
new file mode 100644
index 000000000000..a8b78f1b3243
--- /dev/null
+++ b/tools/perf/util/tsc.h
@@ -0,0 +1,12 @@
1#ifndef __PERF_TSC_H
2#define __PERF_TSC_H
3
4#include <linux/types.h>
5
6#include "../arch/x86/util/tsc.h"
7
8u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
9u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
10u64 rdtsc(void);
11
12#endif
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 5ec80a575b50..7419768c38b1 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -3,6 +3,7 @@
3#include <elfutils/libdwfl.h> 3#include <elfutils/libdwfl.h>
4#include <inttypes.h> 4#include <inttypes.h>
5#include <errno.h> 5#include <errno.h>
6#include "debug.h"
6#include "unwind.h" 7#include "unwind.h"
7#include "unwind-libdw.h" 8#include "unwind-libdw.h"
8#include "machine.h" 9#include "machine.h"
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 25578b98f5c5..92b56db52471 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -30,6 +30,7 @@
30#include "unwind.h" 30#include "unwind.h"
31#include "symbol.h" 31#include "symbol.h"
32#include "util.h" 32#include "util.h"
33#include "debug.h"
33 34
34extern int 35extern int
35UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, 36UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 95aefa78bb07..e52e7461911b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -1,5 +1,6 @@
1#include "../perf.h" 1#include "../perf.h"
2#include "util.h" 2#include "util.h"
3#include "debug.h"
3#include <api/fs/fs.h> 4#include <api/fs/fs.h>
4#include <sys/mman.h> 5#include <sys/mman.h>
5#ifdef HAVE_BACKTRACE_SUPPORT 6#ifdef HAVE_BACKTRACE_SUPPORT
@@ -333,12 +334,9 @@ const char *find_tracing_dir(void)
333 if (!debugfs) 334 if (!debugfs)
334 return NULL; 335 return NULL;
335 336
336 tracing = malloc(strlen(debugfs) + 9); 337 if (asprintf(&tracing, "%s/tracing", debugfs) < 0)
337 if (!tracing)
338 return NULL; 338 return NULL;
339 339
340 sprintf(tracing, "%s/tracing", debugfs);
341
342 tracing_found = 1; 340 tracing_found = 1;
343 return tracing; 341 return tracing;
344} 342}
@@ -352,11 +350,9 @@ char *get_tracing_file(const char *name)
352 if (!tracing) 350 if (!tracing)
353 return NULL; 351 return NULL;
354 352
355 file = malloc(strlen(tracing) + strlen(name) + 2); 353 if (asprintf(&file, "%s/%s", tracing, name) < 0)
356 if (!file)
357 return NULL; 354 return NULL;
358 355
359 sprintf(file, "%s/%s", tracing, name);
360 return file; 356 return file;
361} 357}
362 358
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index 0ddb3b8a89ec..adca69384fcc 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -11,10 +11,34 @@
11#include "vdso.h" 11#include "vdso.h"
12#include "util.h" 12#include "util.h"
13#include "symbol.h" 13#include "symbol.h"
14#include "machine.h"
14#include "linux/string.h" 15#include "linux/string.h"
16#include "debug.h"
15 17
16static bool vdso_found; 18#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
17static char vdso_file[] = "/tmp/perf-vdso.so-XXXXXX"; 19
20struct vdso_file {
21 bool found;
22 bool error;
23 char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
24 const char *dso_name;
25};
26
27struct vdso_info {
28 struct vdso_file vdso;
29};
30
31static struct vdso_info *vdso_info__new(void)
32{
33 static const struct vdso_info vdso_info_init = {
34 .vdso = {
35 .temp_file_name = VDSO__TEMP_FILE_NAME,
36 .dso_name = DSO__NAME_VDSO,
37 },
38 };
39
40 return memdup(&vdso_info_init, sizeof(vdso_info_init));
41}
18 42
19static int find_vdso_map(void **start, void **end) 43static int find_vdso_map(void **start, void **end)
20{ 44{
@@ -47,7 +71,7 @@ static int find_vdso_map(void **start, void **end)
47 return !found; 71 return !found;
48} 72}
49 73
50static char *get_file(void) 74static char *get_file(struct vdso_file *vdso_file)
51{ 75{
52 char *vdso = NULL; 76 char *vdso = NULL;
53 char *buf = NULL; 77 char *buf = NULL;
@@ -55,10 +79,10 @@ static char *get_file(void)
55 size_t size; 79 size_t size;
56 int fd; 80 int fd;
57 81
58 if (vdso_found) 82 if (vdso_file->found)
59 return vdso_file; 83 return vdso_file->temp_file_name;
60 84
61 if (find_vdso_map(&start, &end)) 85 if (vdso_file->error || find_vdso_map(&start, &end))
62 return NULL; 86 return NULL;
63 87
64 size = end - start; 88 size = end - start;
@@ -67,45 +91,78 @@ static char *get_file(void)
67 if (!buf) 91 if (!buf)
68 return NULL; 92 return NULL;
69 93
70 fd = mkstemp(vdso_file); 94 fd = mkstemp(vdso_file->temp_file_name);
71 if (fd < 0) 95 if (fd < 0)
72 goto out; 96 goto out;
73 97
74 if (size == (size_t) write(fd, buf, size)) 98 if (size == (size_t) write(fd, buf, size))
75 vdso = vdso_file; 99 vdso = vdso_file->temp_file_name;
76 100
77 close(fd); 101 close(fd);
78 102
79 out: 103 out:
80 free(buf); 104 free(buf);
81 105
82 vdso_found = (vdso != NULL); 106 vdso_file->found = (vdso != NULL);
107 vdso_file->error = !vdso_file->found;
83 return vdso; 108 return vdso;
84} 109}
85 110
86void vdso__exit(void) 111void vdso__exit(struct machine *machine)
87{ 112{
88 if (vdso_found) 113 struct vdso_info *vdso_info = machine->vdso_info;
89 unlink(vdso_file); 114
115 if (!vdso_info)
116 return;
117
118 if (vdso_info->vdso.found)
119 unlink(vdso_info->vdso.temp_file_name);
120
121 zfree(&machine->vdso_info);
90} 122}
91 123
92struct dso *vdso__dso_findnew(struct list_head *head) 124static struct dso *vdso__new(struct machine *machine, const char *short_name,
125 const char *long_name)
93{ 126{
94 struct dso *dso = dsos__find(head, VDSO__MAP_NAME, true); 127 struct dso *dso;
95 128
129 dso = dso__new(short_name);
130 if (dso != NULL) {
131 dsos__add(&machine->user_dsos, dso);
132 dso__set_long_name(dso, long_name, false);
133 }
134
135 return dso;
136}
137
138struct dso *vdso__dso_findnew(struct machine *machine,
139 struct thread *thread __maybe_unused)
140{
141 struct vdso_info *vdso_info;
142 struct dso *dso;
143
144 if (!machine->vdso_info)
145 machine->vdso_info = vdso_info__new();
146
147 vdso_info = machine->vdso_info;
148 if (!vdso_info)
149 return NULL;
150
151 dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
96 if (!dso) { 152 if (!dso) {
97 char *file; 153 char *file;
98 154
99 file = get_file(); 155 file = get_file(&vdso_info->vdso);
100 if (!file) 156 if (!file)
101 return NULL; 157 return NULL;
102 158
103 dso = dso__new(VDSO__MAP_NAME); 159 dso = vdso__new(machine, DSO__NAME_VDSO, file);
104 if (dso != NULL) {
105 dsos__add(head, dso);
106 dso__set_long_name(dso, file, false);
107 }
108 } 160 }
109 161
110 return dso; 162 return dso;
111} 163}
164
165bool dso__is_vdso(struct dso *dso)
166{
167 return !strcmp(dso->short_name, DSO__NAME_VDSO);
168}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
index 0f76e7caf6f8..af9d6929a215 100644
--- a/tools/perf/util/vdso.h
+++ b/tools/perf/util/vdso.h
@@ -7,12 +7,21 @@
7 7
8#define VDSO__MAP_NAME "[vdso]" 8#define VDSO__MAP_NAME "[vdso]"
9 9
10#define DSO__NAME_VDSO "[vdso]"
11
10static inline bool is_vdso_map(const char *filename) 12static inline bool is_vdso_map(const char *filename)
11{ 13{
12 return !strcmp(filename, VDSO__MAP_NAME); 14 return !strcmp(filename, VDSO__MAP_NAME);
13} 15}
14 16
15struct dso *vdso__dso_findnew(struct list_head *head); 17struct dso;
16void vdso__exit(void); 18
19bool dso__is_vdso(struct dso *dso);
20
21struct machine;
22struct thread;
23
24struct dso *vdso__dso_findnew(struct machine *machine, struct thread *thread);
25void vdso__exit(struct machine *machine);
17 26
18#endif /* __PERF_VDSO__ */ 27#endif /* __PERF_VDSO__ */