aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2018-01-17 11:20:24 -0500
committerIngo Molnar <mingo@kernel.org>2018-01-17 11:20:24 -0500
commita72594ca5c70ef4a94fab8ad541beda0d0a94139 (patch)
tree2f08d90934e65ea60f73e2bdaf7408fb36f1aecf /tools
parent7a7368a5f22d13a7ff6654204de92c08ce5d8fea (diff)
parent81fccd6ca507d3b2012eaf1edeb9b1dbf4bd22db (diff)
Merge tag 'perf-core-for-mingo-4.16-20180117' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: - Fix various per event 'max-stack' and 'call-graph=dwarf' issues, mostly in 'perf trace', allowing to use 'perf trace --call-graph' with 'dwarf' and 'fp' to setup the callgraph details for the syscall events and make that apply to other events, whilhe allowing to override that on a per-event basis, using '-e sched:*switch/call-graph=dwarf/' for instance (Arnaldo Carvalho de Melo) - Improve the --time percent support in record/report/script (Jin Yao) - Fix copyfile_offset update of output offset (Jiri Olsa) - Add python script to profile and resolve physical mem type (Kan Liang) - Add ARM Statistical Profiling Extensions (SPE) support (Kim Phillips) - Remove trailing semicolon in the evlist code (Luis de Bethencourt) - Fix incorrect handling of type _TERM_DRV_CFG (Mathieu Poirier) - Use asprintf when possible in libtraceevent (Federico Vaga) - Fix bad force_token escape sequence in libtraceevent (Michael Sartain) - Add UL suffix to MISSING_EVENTS in libtraceevent (Michael Sartain) - value of unknown symbolic fields in libtraceevent (Jan Kiszka) - libtraceevent updates: (Steven Rostedt) o Show value of flags that have not been parsed o Simplify pointer print logic and fix %pF o Handle new pointer processing of bprint strings o Show contents (in hex) of data of unrecognized type records o Fix get_field_str() for dynamic strings - Add missing break in FALSE case of pevent_filter_clear_trivial() (Taeung Song) - Fix failed memory allocation for get_cpuid_str (Thomas Richter) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/lib/traceevent/event-parse.c62
-rw-r--r--tools/lib/traceevent/event-plugin.c24
-rw-r--r--tools/lib/traceevent/kbuffer-parse.c4
-rw-r--r--tools/lib/traceevent/parse-filter.c22
-rw-r--r--tools/perf/Documentation/perf-report.txt2
-rw-r--r--tools/perf/Documentation/perf-script.txt10
-rw-r--r--tools/perf/arch/arm/util/auxtrace.c77
-rw-r--r--tools/perf/arch/arm/util/pmu.c6
-rw-r--r--tools/perf/arch/arm64/util/Build3
-rw-r--r--tools/perf/arch/arm64/util/arm-spe.c225
-rw-r--r--tools/perf/arch/x86/util/header.c2
-rw-r--r--tools/perf/builtin-c2c.c5
-rw-r--r--tools/perf/builtin-report.c34
-rw-r--r--tools/perf/builtin-script.c25
-rw-r--r--tools/perf/builtin-trace.c62
-rw-r--r--tools/perf/scripts/python/bin/mem-phys-addr-record19
-rw-r--r--tools/perf/scripts/python/bin/mem-phys-addr-report3
-rw-r--r--tools/perf/scripts/python/mem-phys-addr.py95
-rw-r--r--tools/perf/tests/dwarf-unwind.c1
-rw-r--r--tools/perf/util/Build2
-rw-r--r--tools/perf/util/arm-spe-pkt-decoder.c462
-rw-r--r--tools/perf/util/arm-spe-pkt-decoder.h43
-rw-r--r--tools/perf/util/arm-spe.c231
-rw-r--r--tools/perf/util/arm-spe.h31
-rw-r--r--tools/perf/util/auxtrace.c3
-rw-r--r--tools/perf/util/auxtrace.h1
-rw-r--r--tools/perf/util/callchain.c10
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/evlist.c2
-rw-r--r--tools/perf/util/evsel.c40
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c2
-rw-r--r--tools/perf/util/time-utils.c72
-rw-r--r--tools/perf/util/time-utils.h2
-rw-r--r--tools/perf/util/unwind-libunwind-local.c9
-rw-r--r--tools/perf/util/util.c2
35 files changed, 1465 insertions, 130 deletions
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 7ce724fc0544..e5f2acbb70cc 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -1094,7 +1094,7 @@ static enum event_type __read_token(char **tok)
1094 if (strcmp(*tok, "LOCAL_PR_FMT") == 0) { 1094 if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
1095 free(*tok); 1095 free(*tok);
1096 *tok = NULL; 1096 *tok = NULL;
1097 return force_token("\"\%s\" ", tok); 1097 return force_token("\"%s\" ", tok);
1098 } else if (strcmp(*tok, "STA_PR_FMT") == 0) { 1098 } else if (strcmp(*tok, "STA_PR_FMT") == 0) {
1099 free(*tok); 1099 free(*tok);
1100 *tok = NULL; 1100 *tok = NULL;
@@ -3970,6 +3970,11 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3970 val &= ~fval; 3970 val &= ~fval;
3971 } 3971 }
3972 } 3972 }
3973 if (val) {
3974 if (print && arg->flags.delim)
3975 trace_seq_puts(s, arg->flags.delim);
3976 trace_seq_printf(s, "0x%llx", val);
3977 }
3973 break; 3978 break;
3974 case PRINT_SYMBOL: 3979 case PRINT_SYMBOL:
3975 val = eval_num_arg(data, size, event, arg->symbol.field); 3980 val = eval_num_arg(data, size, event, arg->symbol.field);
@@ -3980,6 +3985,8 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
3980 break; 3985 break;
3981 } 3986 }
3982 } 3987 }
3988 if (!flag)
3989 trace_seq_printf(s, "0x%llx", val);
3983 break; 3990 break;
3984 case PRINT_HEX: 3991 case PRINT_HEX:
3985 case PRINT_HEX_STR: 3992 case PRINT_HEX_STR:
@@ -4293,6 +4300,26 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
4293 goto process_again; 4300 goto process_again;
4294 case 'p': 4301 case 'p':
4295 ls = 1; 4302 ls = 1;
4303 if (isalnum(ptr[1])) {
4304 ptr++;
4305 /* Check for special pointers */
4306 switch (*ptr) {
4307 case 's':
4308 case 'S':
4309 case 'f':
4310 case 'F':
4311 break;
4312 default:
4313 /*
4314 * Older kernels do not process
4315 * dereferenced pointers.
4316 * Only process if the pointer
4317 * value is a printable.
4318 */
4319 if (isprint(*(char *)bptr))
4320 goto process_string;
4321 }
4322 }
4296 /* fall through */ 4323 /* fall through */
4297 case 'd': 4324 case 'd':
4298 case 'u': 4325 case 'u':
@@ -4345,6 +4372,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
4345 4372
4346 break; 4373 break;
4347 case 's': 4374 case 's':
4375 process_string:
4348 arg = alloc_arg(); 4376 arg = alloc_arg();
4349 if (!arg) { 4377 if (!arg) {
4350 do_warning_event(event, "%s(%d): not enough memory!", 4378 do_warning_event(event, "%s(%d): not enough memory!",
@@ -4949,21 +4977,27 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
4949 else 4977 else
4950 ls = 2; 4978 ls = 2;
4951 4979
4952 if (*(ptr+1) == 'F' || *(ptr+1) == 'f' || 4980 if (isalnum(ptr[1]))
4953 *(ptr+1) == 'S' || *(ptr+1) == 's') {
4954 ptr++; 4981 ptr++;
4982
4983 if (arg->type == PRINT_BSTRING) {
4984 trace_seq_puts(s, arg->string.string);
4985 break;
4986 }
4987
4988 if (*ptr == 'F' || *ptr == 'f' ||
4989 *ptr == 'S' || *ptr == 's') {
4955 show_func = *ptr; 4990 show_func = *ptr;
4956 } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { 4991 } else if (*ptr == 'M' || *ptr == 'm') {
4957 print_mac_arg(s, *(ptr+1), data, size, event, arg); 4992 print_mac_arg(s, *ptr, data, size, event, arg);
4958 ptr++;
4959 arg = arg->next; 4993 arg = arg->next;
4960 break; 4994 break;
4961 } else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') { 4995 } else if (*ptr == 'I' || *ptr == 'i') {
4962 int n; 4996 int n;
4963 4997
4964 n = print_ip_arg(s, ptr+1, data, size, event, arg); 4998 n = print_ip_arg(s, ptr, data, size, event, arg);
4965 if (n > 0) { 4999 if (n > 0) {
4966 ptr += n; 5000 ptr += n - 1;
4967 arg = arg->next; 5001 arg = arg->next;
4968 break; 5002 break;
4969 } 5003 }
@@ -5532,8 +5566,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
5532 5566
5533 event = pevent_find_event_by_record(pevent, record); 5567 event = pevent_find_event_by_record(pevent, record);
5534 if (!event) { 5568 if (!event) {
5535 do_warning("ug! no event found for type %d", 5569 int i;
5536 trace_parse_common_type(pevent, record->data)); 5570 int type = trace_parse_common_type(pevent, record->data);
5571
5572 do_warning("ug! no event found for type %d", type);
5573 trace_seq_printf(s, "[UNKNOWN TYPE %d]", type);
5574 for (i = 0; i < record->size; i++)
5575 trace_seq_printf(s, " %02x",
5576 ((unsigned char *)record->data)[i]);
5537 return; 5577 return;
5538 } 5578 }
5539 5579
diff --git a/tools/lib/traceevent/event-plugin.c b/tools/lib/traceevent/event-plugin.c
index a16756ae3526..d542cb60ca1a 100644
--- a/tools/lib/traceevent/event-plugin.c
+++ b/tools/lib/traceevent/event-plugin.c
@@ -120,12 +120,12 @@ char **traceevent_plugin_list_options(void)
120 for (op = reg->options; op->name; op++) { 120 for (op = reg->options; op->name; op++) {
121 char *alias = op->plugin_alias ? op->plugin_alias : op->file; 121 char *alias = op->plugin_alias ? op->plugin_alias : op->file;
122 char **temp = list; 122 char **temp = list;
123 int ret;
123 124
124 name = malloc(strlen(op->name) + strlen(alias) + 2); 125 ret = asprintf(&name, "%s:%s", alias, op->name);
125 if (!name) 126 if (ret < 0)
126 goto err; 127 goto err;
127 128
128 sprintf(name, "%s:%s", alias, op->name);
129 list = realloc(list, count + 2); 129 list = realloc(list, count + 2);
130 if (!list) { 130 if (!list) {
131 list = temp; 131 list = temp;
@@ -290,17 +290,14 @@ load_plugin(struct pevent *pevent, const char *path,
290 const char *alias; 290 const char *alias;
291 char *plugin; 291 char *plugin;
292 void *handle; 292 void *handle;
293 int ret;
293 294
294 plugin = malloc(strlen(path) + strlen(file) + 2); 295 ret = asprintf(&plugin, "%s/%s", path, file);
295 if (!plugin) { 296 if (ret < 0) {
296 warning("could not allocate plugin memory\n"); 297 warning("could not allocate plugin memory\n");
297 return; 298 return;
298 } 299 }
299 300
300 strcpy(plugin, path);
301 strcat(plugin, "/");
302 strcat(plugin, file);
303
304 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL); 301 handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
305 if (!handle) { 302 if (!handle) {
306 warning("could not load plugin '%s'\n%s\n", 303 warning("could not load plugin '%s'\n%s\n",
@@ -391,6 +388,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
391 char *home; 388 char *home;
392 char *path; 389 char *path;
393 char *envdir; 390 char *envdir;
391 int ret;
394 392
395 if (pevent->flags & PEVENT_DISABLE_PLUGINS) 393 if (pevent->flags & PEVENT_DISABLE_PLUGINS)
396 return; 394 return;
@@ -421,16 +419,12 @@ load_plugins(struct pevent *pevent, const char *suffix,
421 if (!home) 419 if (!home)
422 return; 420 return;
423 421
424 path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2); 422 ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
425 if (!path) { 423 if (ret < 0) {
426 warning("could not allocate plugin memory\n"); 424 warning("could not allocate plugin memory\n");
427 return; 425 return;
428 } 426 }
429 427
430 strcpy(path, home);
431 strcat(path, "/");
432 strcat(path, LOCAL_PLUGIN_DIR);
433
434 load_plugins_dir(pevent, suffix, path, load_plugin, data); 428 load_plugins_dir(pevent, suffix, path, load_plugin, data);
435 429
436 free(path); 430 free(path);
diff --git a/tools/lib/traceevent/kbuffer-parse.c b/tools/lib/traceevent/kbuffer-parse.c
index c94e3641b046..ca424b157e46 100644
--- a/tools/lib/traceevent/kbuffer-parse.c
+++ b/tools/lib/traceevent/kbuffer-parse.c
@@ -24,8 +24,8 @@
24 24
25#include "kbuffer.h" 25#include "kbuffer.h"
26 26
27#define MISSING_EVENTS (1 << 31) 27#define MISSING_EVENTS (1UL << 31)
28#define MISSING_STORED (1 << 30) 28#define MISSING_STORED (1UL << 30)
29 29
30#define COMMIT_MASK ((1 << 27) - 1) 30#define COMMIT_MASK ((1 << 27) - 1)
31 31
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c
index 315df0a70265..431e8b309f6e 100644
--- a/tools/lib/traceevent/parse-filter.c
+++ b/tools/lib/traceevent/parse-filter.c
@@ -287,12 +287,10 @@ find_event(struct pevent *pevent, struct event_list **events,
287 sys_name = NULL; 287 sys_name = NULL;
288 } 288 }
289 289
290 reg = malloc(strlen(event_name) + 3); 290 ret = asprintf(&reg, "^%s$", event_name);
291 if (reg == NULL) 291 if (ret < 0)
292 return PEVENT_ERRNO__MEM_ALLOC_FAILED; 292 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
293 293
294 sprintf(reg, "^%s$", event_name);
295
296 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB); 294 ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
297 free(reg); 295 free(reg);
298 296
@@ -300,13 +298,12 @@ find_event(struct pevent *pevent, struct event_list **events,
300 return PEVENT_ERRNO__INVALID_EVENT_NAME; 298 return PEVENT_ERRNO__INVALID_EVENT_NAME;
301 299
302 if (sys_name) { 300 if (sys_name) {
303 reg = malloc(strlen(sys_name) + 3); 301 ret = asprintf(&reg, "^%s$", sys_name);
304 if (reg == NULL) { 302 if (ret < 0) {
305 regfree(&ereg); 303 regfree(&ereg);
306 return PEVENT_ERRNO__MEM_ALLOC_FAILED; 304 return PEVENT_ERRNO__MEM_ALLOC_FAILED;
307 } 305 }
308 306
309 sprintf(reg, "^%s$", sys_name);
310 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB); 307 ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
311 free(reg); 308 free(reg);
312 if (ret) { 309 if (ret) {
@@ -1634,6 +1631,7 @@ int pevent_filter_clear_trivial(struct event_filter *filter,
1634 case FILTER_TRIVIAL_FALSE: 1631 case FILTER_TRIVIAL_FALSE:
1635 if (filter_type->filter->boolean.value) 1632 if (filter_type->filter->boolean.value)
1636 continue; 1633 continue;
1634 break;
1637 case FILTER_TRIVIAL_TRUE: 1635 case FILTER_TRIVIAL_TRUE:
1638 if (!filter_type->filter->boolean.value) 1636 if (!filter_type->filter->boolean.value)
1639 continue; 1637 continue;
@@ -1879,17 +1877,25 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
1879 struct pevent *pevent; 1877 struct pevent *pevent;
1880 unsigned long long addr; 1878 unsigned long long addr;
1881 const char *val = NULL; 1879 const char *val = NULL;
1880 unsigned int size;
1882 char hex[64]; 1881 char hex[64];
1883 1882
1884 /* If the field is not a string convert it */ 1883 /* If the field is not a string convert it */
1885 if (arg->str.field->flags & FIELD_IS_STRING) { 1884 if (arg->str.field->flags & FIELD_IS_STRING) {
1886 val = record->data + arg->str.field->offset; 1885 val = record->data + arg->str.field->offset;
1886 size = arg->str.field->size;
1887
1888 if (arg->str.field->flags & FIELD_IS_DYNAMIC) {
1889 addr = *(unsigned int *)val;
1890 val = record->data + (addr & 0xffff);
1891 size = addr >> 16;
1892 }
1887 1893
1888 /* 1894 /*
1889 * We need to copy the data since we can't be sure the field 1895 * We need to copy the data since we can't be sure the field
1890 * is null terminated. 1896 * is null terminated.
1891 */ 1897 */
1892 if (*(val + arg->str.field->size - 1)) { 1898 if (*(val + size - 1)) {
1893 /* copy it */ 1899 /* copy it */
1894 memcpy(arg->str.buffer, val, arg->str.field->size); 1900 memcpy(arg->str.buffer, val, arg->str.field->size);
1895 /* the buffer is already NULL terminated */ 1901 /* the buffer is already NULL terminated */
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 63d0db3184c9..907e505b6309 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -403,7 +403,7 @@ OPTIONS
403 to end of file. 403 to end of file.
404 404
405 Also support time percent with multiple time range. Time string is 405 Also support time percent with multiple time range. Time string is
406 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. The maximum number of slices is 10. 406 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
407 407
408 For example: 408 For example:
409 Select the second 10% time slice: 409 Select the second 10% time slice:
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index 806ec6391fd6..7730c1d2b5d3 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -351,19 +351,19 @@ include::itrace.txt[]
351 to end of file. 351 to end of file.
352 352
353 Also support time percent with multipe time range. Time string is 353 Also support time percent with multipe time range. Time string is
354 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. The maximum number of slices is 10. 354 'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.
355 355
356 For example: 356 For example:
357 Select the second 10% time slice 357 Select the second 10% time slice:
358 perf script --time 10%/2 358 perf script --time 10%/2
359 359
360 Select from 0% to 10% time slice 360 Select from 0% to 10% time slice:
361 perf script --time 0%-10% 361 perf script --time 0%-10%
362 362
363 Select the first and second 10% time slices 363 Select the first and second 10% time slices:
364 perf script --time 10%/1,10%/2 364 perf script --time 10%/1,10%/2
365 365
366 Select from 0% to 10% and 30% to 40% slices 366 Select from 0% to 10% and 30% to 40% slices:
367 perf script --time 0%-10%,30%-40% 367 perf script --time 0%-10%,30%-40%
368 368
369--max-blocks:: 369--max-blocks::
diff --git a/tools/perf/arch/arm/util/auxtrace.c b/tools/perf/arch/arm/util/auxtrace.c
index 8edf2cb71564..2323581b157d 100644
--- a/tools/perf/arch/arm/util/auxtrace.c
+++ b/tools/perf/arch/arm/util/auxtrace.c
@@ -22,6 +22,42 @@
22#include "../../util/evlist.h" 22#include "../../util/evlist.h"
23#include "../../util/pmu.h" 23#include "../../util/pmu.h"
24#include "cs-etm.h" 24#include "cs-etm.h"
25#include "arm-spe.h"
26
27static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
28{
29 struct perf_pmu **arm_spe_pmus = NULL;
30 int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
31 /* arm_spe_xxxxxxxxx\0 */
32 char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10];
33
34 arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);
35 if (!arm_spe_pmus) {
36 pr_err("spes alloc failed\n");
37 *err = -ENOMEM;
38 return NULL;
39 }
40
41 for (i = 0; i < nr_cpus; i++) {
42 ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);
43 if (ret < 0) {
44 pr_err("sprintf failed\n");
45 *err = -ENOMEM;
46 return NULL;
47 }
48
49 arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
50 if (arm_spe_pmus[*nr_spes]) {
51 pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
52 __func__, __LINE__, *nr_spes,
53 arm_spe_pmus[*nr_spes]->type,
54 arm_spe_pmus[*nr_spes]->name);
55 (*nr_spes)++;
56 }
57 }
58
59 return arm_spe_pmus;
60}
25 61
26struct auxtrace_record 62struct auxtrace_record
27*auxtrace_record__init(struct perf_evlist *evlist, int *err) 63*auxtrace_record__init(struct perf_evlist *evlist, int *err)
@@ -29,22 +65,51 @@ struct auxtrace_record
29 struct perf_pmu *cs_etm_pmu; 65 struct perf_pmu *cs_etm_pmu;
30 struct perf_evsel *evsel; 66 struct perf_evsel *evsel;
31 bool found_etm = false; 67 bool found_etm = false;
68 bool found_spe = false;
69 static struct perf_pmu **arm_spe_pmus = NULL;
70 static int nr_spes = 0;
71 int i;
72
73 if (!evlist)
74 return NULL;
32 75
33 cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME); 76 cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);
34 77
35 if (evlist) { 78 if (!arm_spe_pmus)
36 evlist__for_each_entry(evlist, evsel) { 79 arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);
37 if (cs_etm_pmu && 80
38 evsel->attr.type == cs_etm_pmu->type) 81 evlist__for_each_entry(evlist, evsel) {
39 found_etm = true; 82 if (cs_etm_pmu &&
83 evsel->attr.type == cs_etm_pmu->type)
84 found_etm = true;
85
86 if (!nr_spes)
87 continue;
88
89 for (i = 0; i < nr_spes; i++) {
90 if (evsel->attr.type == arm_spe_pmus[i]->type) {
91 found_spe = true;
92 break;
93 }
40 } 94 }
41 } 95 }
42 96
97 if (found_etm && found_spe) {
98 pr_err("Concurrent ARM Coresight ETM and SPE operation not currently supported\n");
99 *err = -EOPNOTSUPP;
100 return NULL;
101 }
102
43 if (found_etm) 103 if (found_etm)
44 return cs_etm_record_init(err); 104 return cs_etm_record_init(err);
45 105
106#if defined(__aarch64__)
107 if (found_spe)
108 return arm_spe_recording_init(err, arm_spe_pmus[i]);
109#endif
110
46 /* 111 /*
47 * Clear 'err' even if we haven't found a cs_etm event - that way perf 112 * Clear 'err' even if we haven't found an event - that way perf
48 * record can still be used even if tracers aren't present. The NULL 113 * record can still be used even if tracers aren't present. The NULL
49 * return value will take care of telling the infrastructure HW tracing 114 * return value will take care of telling the infrastructure HW tracing
50 * isn't available. 115 * isn't available.
diff --git a/tools/perf/arch/arm/util/pmu.c b/tools/perf/arch/arm/util/pmu.c
index 98d67399a0d6..ac4dffc807b8 100644
--- a/tools/perf/arch/arm/util/pmu.c
+++ b/tools/perf/arch/arm/util/pmu.c
@@ -20,6 +20,7 @@
20#include <linux/perf_event.h> 20#include <linux/perf_event.h>
21 21
22#include "cs-etm.h" 22#include "cs-etm.h"
23#include "arm-spe.h"
23#include "../../util/pmu.h" 24#include "../../util/pmu.h"
24 25
25struct perf_event_attr 26struct perf_event_attr
@@ -30,7 +31,12 @@ struct perf_event_attr
30 /* add ETM default config here */ 31 /* add ETM default config here */
31 pmu->selectable = true; 32 pmu->selectable = true;
32 pmu->set_drv_config = cs_etm_set_drv_config; 33 pmu->set_drv_config = cs_etm_set_drv_config;
34#if defined(__aarch64__)
35 } else if (strstarts(pmu->name, ARM_SPE_PMU_NAME)) {
36 return arm_spe_pmu_default_config(pmu);
37#endif
33 } 38 }
39
34#endif 40#endif
35 return NULL; 41 return NULL;
36} 42}
diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/Build
index e04f6cdd6f32..c0b8dfef98ba 100644
--- a/tools/perf/arch/arm64/util/Build
+++ b/tools/perf/arch/arm64/util/Build
@@ -5,4 +5,5 @@ libperf-$(CONFIG_LOCAL_LIBUNWIND) += unwind-libunwind.o
5 5
6libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \ 6libperf-$(CONFIG_AUXTRACE) += ../../arm/util/pmu.o \
7 ../../arm/util/auxtrace.o \ 7 ../../arm/util/auxtrace.o \
8 ../../arm/util/cs-etm.o 8 ../../arm/util/cs-etm.o \
9 arm-spe.o
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c
new file mode 100644
index 000000000000..1120e39c1b00
--- /dev/null
+++ b/tools/perf/arch/arm64/util/arm-spe.c
@@ -0,0 +1,225 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#include <linux/kernel.h>
8#include <linux/types.h>
9#include <linux/bitops.h>
10#include <linux/log2.h>
11#include <time.h>
12
13#include "../../util/cpumap.h"
14#include "../../util/evsel.h"
15#include "../../util/evlist.h"
16#include "../../util/session.h"
17#include "../../util/util.h"
18#include "../../util/pmu.h"
19#include "../../util/debug.h"
20#include "../../util/auxtrace.h"
21#include "../../util/arm-spe.h"
22
23#define KiB(x) ((x) * 1024)
24#define MiB(x) ((x) * 1024 * 1024)
25
26struct arm_spe_recording {
27 struct auxtrace_record itr;
28 struct perf_pmu *arm_spe_pmu;
29 struct perf_evlist *evlist;
30};
31
32static size_t
33arm_spe_info_priv_size(struct auxtrace_record *itr __maybe_unused,
34 struct perf_evlist *evlist __maybe_unused)
35{
36 return ARM_SPE_AUXTRACE_PRIV_SIZE;
37}
38
39static int arm_spe_info_fill(struct auxtrace_record *itr,
40 struct perf_session *session,
41 struct auxtrace_info_event *auxtrace_info,
42 size_t priv_size)
43{
44 struct arm_spe_recording *sper =
45 container_of(itr, struct arm_spe_recording, itr);
46 struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
47
48 if (priv_size != ARM_SPE_AUXTRACE_PRIV_SIZE)
49 return -EINVAL;
50
51 if (!session->evlist->nr_mmaps)
52 return -EINVAL;
53
54 auxtrace_info->type = PERF_AUXTRACE_ARM_SPE;
55 auxtrace_info->priv[ARM_SPE_PMU_TYPE] = arm_spe_pmu->type;
56
57 return 0;
58}
59
60static int arm_spe_recording_options(struct auxtrace_record *itr,
61 struct perf_evlist *evlist,
62 struct record_opts *opts)
63{
64 struct arm_spe_recording *sper =
65 container_of(itr, struct arm_spe_recording, itr);
66 struct perf_pmu *arm_spe_pmu = sper->arm_spe_pmu;
67 struct perf_evsel *evsel, *arm_spe_evsel = NULL;
68 bool privileged = geteuid() == 0 || perf_event_paranoid() < 0;
69 struct perf_evsel *tracking_evsel;
70 int err;
71
72 sper->evlist = evlist;
73
74 evlist__for_each_entry(evlist, evsel) {
75 if (evsel->attr.type == arm_spe_pmu->type) {
76 if (arm_spe_evsel) {
77 pr_err("There may be only one " ARM_SPE_PMU_NAME "x event\n");
78 return -EINVAL;
79 }
80 evsel->attr.freq = 0;
81 evsel->attr.sample_period = 1;
82 arm_spe_evsel = evsel;
83 opts->full_auxtrace = true;
84 }
85 }
86
87 if (!opts->full_auxtrace)
88 return 0;
89
90 /* We are in full trace mode but '-m,xyz' wasn't specified */
91 if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
92 if (privileged) {
93 opts->auxtrace_mmap_pages = MiB(4) / page_size;
94 } else {
95 opts->auxtrace_mmap_pages = KiB(128) / page_size;
96 if (opts->mmap_pages == UINT_MAX)
97 opts->mmap_pages = KiB(256) / page_size;
98 }
99 }
100
101 /* Validate auxtrace_mmap_pages */
102 if (opts->auxtrace_mmap_pages) {
103 size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
104 size_t min_sz = KiB(8);
105
106 if (sz < min_sz || !is_power_of_2(sz)) {
107 pr_err("Invalid mmap size for ARM SPE: must be at least %zuKiB and a power of 2\n",
108 min_sz / 1024);
109 return -EINVAL;
110 }
111 }
112
113
114 /*
115 * To obtain the auxtrace buffer file descriptor, the auxtrace event
116 * must come first.
117 */
118 perf_evlist__to_front(evlist, arm_spe_evsel);
119
120 perf_evsel__set_sample_bit(arm_spe_evsel, CPU);
121 perf_evsel__set_sample_bit(arm_spe_evsel, TIME);
122 perf_evsel__set_sample_bit(arm_spe_evsel, TID);
123
124 /* Add dummy event to keep tracking */
125 err = parse_events(evlist, "dummy:u", NULL);
126 if (err)
127 return err;
128
129 tracking_evsel = perf_evlist__last(evlist);
130 perf_evlist__set_tracking_event(evlist, tracking_evsel);
131
132 tracking_evsel->attr.freq = 0;
133 tracking_evsel->attr.sample_period = 1;
134 perf_evsel__set_sample_bit(tracking_evsel, TIME);
135 perf_evsel__set_sample_bit(tracking_evsel, CPU);
136 perf_evsel__reset_sample_bit(tracking_evsel, BRANCH_STACK);
137
138 return 0;
139}
140
141static u64 arm_spe_reference(struct auxtrace_record *itr __maybe_unused)
142{
143 struct timespec ts;
144
145 clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
146
147 return ts.tv_sec ^ ts.tv_nsec;
148}
149
150static void arm_spe_recording_free(struct auxtrace_record *itr)
151{
152 struct arm_spe_recording *sper =
153 container_of(itr, struct arm_spe_recording, itr);
154
155 free(sper);
156}
157
158static int arm_spe_read_finish(struct auxtrace_record *itr, int idx)
159{
160 struct arm_spe_recording *sper =
161 container_of(itr, struct arm_spe_recording, itr);
162 struct perf_evsel *evsel;
163
164 evlist__for_each_entry(sper->evlist, evsel) {
165 if (evsel->attr.type == sper->arm_spe_pmu->type)
166 return perf_evlist__enable_event_idx(sper->evlist,
167 evsel, idx);
168 }
169 return -EINVAL;
170}
171
172struct auxtrace_record *arm_spe_recording_init(int *err,
173 struct perf_pmu *arm_spe_pmu)
174{
175 struct arm_spe_recording *sper;
176
177 if (!arm_spe_pmu) {
178 *err = -ENODEV;
179 return NULL;
180 }
181
182 sper = zalloc(sizeof(struct arm_spe_recording));
183 if (!sper) {
184 *err = -ENOMEM;
185 return NULL;
186 }
187
188 sper->arm_spe_pmu = arm_spe_pmu;
189 sper->itr.recording_options = arm_spe_recording_options;
190 sper->itr.info_priv_size = arm_spe_info_priv_size;
191 sper->itr.info_fill = arm_spe_info_fill;
192 sper->itr.free = arm_spe_recording_free;
193 sper->itr.reference = arm_spe_reference;
194 sper->itr.read_finish = arm_spe_read_finish;
195 sper->itr.alignment = 0;
196
197 return &sper->itr;
198}
199
200struct perf_event_attr
201*arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu)
202{
203 struct perf_event_attr *attr;
204
205 attr = zalloc(sizeof(struct perf_event_attr));
206 if (!attr) {
207 pr_err("arm_spe default config cannot allocate a perf_event_attr\n");
208 return NULL;
209 }
210
211 /*
212 * If kernel driver doesn't advertise a minimum,
213 * use max allowable by PMSIDR_EL1.INTERVAL
214 */
215 if (perf_pmu__scan_file(arm_spe_pmu, "caps/min_interval", "%llu",
216 &attr->sample_period) != 1) {
217 pr_debug("arm_spe driver doesn't advertise a min. interval. Using 4096\n");
218 attr->sample_period = 4096;
219 }
220
221 arm_spe_pmu->selectable = true;
222 arm_spe_pmu->is_uncore = false;
223
224 return attr;
225}
diff --git a/tools/perf/arch/x86/util/header.c b/tools/perf/arch/x86/util/header.c
index b626d2bad9f1..fb0d71afee8b 100644
--- a/tools/perf/arch/x86/util/header.c
+++ b/tools/perf/arch/x86/util/header.c
@@ -70,7 +70,7 @@ get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
70{ 70{
71 char *buf = malloc(128); 71 char *buf = malloc(128);
72 72
73 if (__get_cpuid(buf, 128, "%s-%u-%X$") < 0) { 73 if (buf && __get_cpuid(buf, 128, "%s-%u-%X$") < 0) {
74 free(buf); 74 free(buf);
75 return NULL; 75 return NULL;
76 } 76 }
diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c
index c0debc3f79b6..c0815a37fdb5 100644
--- a/tools/perf/builtin-c2c.c
+++ b/tools/perf/builtin-c2c.c
@@ -2390,9 +2390,10 @@ static int setup_callchain(struct perf_evlist *evlist)
2390 enum perf_call_graph_mode mode = CALLCHAIN_NONE; 2390 enum perf_call_graph_mode mode = CALLCHAIN_NONE;
2391 2391
2392 if ((sample_type & PERF_SAMPLE_REGS_USER) && 2392 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
2393 (sample_type & PERF_SAMPLE_STACK_USER)) 2393 (sample_type & PERF_SAMPLE_STACK_USER)) {
2394 mode = CALLCHAIN_DWARF; 2394 mode = CALLCHAIN_DWARF;
2395 else if (sample_type & PERF_SAMPLE_BRANCH_STACK) 2395 dwarf_callchain_users = true;
2396 } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
2396 mode = CALLCHAIN_LBR; 2397 mode = CALLCHAIN_LBR;
2397 else if (sample_type & PERF_SAMPLE_CALLCHAIN) 2398 else if (sample_type & PERF_SAMPLE_CALLCHAIN)
2398 mode = CALLCHAIN_FP; 2399 mode = CALLCHAIN_FP;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index dd4df9a5cd06..42a52dcc41cd 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -54,8 +54,6 @@
54#include <unistd.h> 54#include <unistd.h>
55#include <linux/mman.h> 55#include <linux/mman.h>
56 56
57#define PTIME_RANGE_MAX 10
58
59struct report { 57struct report {
60 struct perf_tool tool; 58 struct perf_tool tool;
61 struct perf_session *session; 59 struct perf_session *session;
@@ -76,7 +74,8 @@ struct report {
76 const char *cpu_list; 74 const char *cpu_list;
77 const char *symbol_filter_str; 75 const char *symbol_filter_str;
78 const char *time_str; 76 const char *time_str;
79 struct perf_time_interval ptime_range[PTIME_RANGE_MAX]; 77 struct perf_time_interval *ptime_range;
78 int range_size;
80 int range_num; 79 int range_num;
81 float min_percent; 80 float min_percent;
82 u64 nr_entries; 81 u64 nr_entries;
@@ -338,9 +337,10 @@ static int report__setup_sample_type(struct report *rep)
338 337
339 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { 338 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
340 if ((sample_type & PERF_SAMPLE_REGS_USER) && 339 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
341 (sample_type & PERF_SAMPLE_STACK_USER)) 340 (sample_type & PERF_SAMPLE_STACK_USER)) {
342 callchain_param.record_mode = CALLCHAIN_DWARF; 341 callchain_param.record_mode = CALLCHAIN_DWARF;
343 else if (sample_type & PERF_SAMPLE_BRANCH_STACK) 342 dwarf_callchain_users = true;
343 } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
344 callchain_param.record_mode = CALLCHAIN_LBR; 344 callchain_param.record_mode = CALLCHAIN_LBR;
345 else 345 else
346 callchain_param.record_mode = CALLCHAIN_FP; 346 callchain_param.record_mode = CALLCHAIN_FP;
@@ -403,6 +403,9 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
403 if (evname != NULL) 403 if (evname != NULL)
404 ret += fprintf(fp, " of event '%s'", evname); 404 ret += fprintf(fp, " of event '%s'", evname);
405 405
406 if (rep->time_str)
407 ret += fprintf(fp, " (time slices: %s)", rep->time_str);
408
406 if (symbol_conf.show_ref_callgraph && 409 if (symbol_conf.show_ref_callgraph &&
407 strstr(evname, "call-graph=no")) { 410 strstr(evname, "call-graph=no")) {
408 ret += fprintf(fp, ", show reference callgraph"); 411 ret += fprintf(fp, ", show reference callgraph");
@@ -1296,22 +1299,33 @@ repeat:
1296 if (symbol__init(&session->header.env) < 0) 1299 if (symbol__init(&session->header.env) < 0)
1297 goto error; 1300 goto error;
1298 1301
1302 report.ptime_range = perf_time__range_alloc(report.time_str,
1303 &report.range_size);
1304 if (!report.ptime_range) {
1305 ret = -ENOMEM;
1306 goto error;
1307 }
1308
1299 if (perf_time__parse_str(report.ptime_range, report.time_str) != 0) { 1309 if (perf_time__parse_str(report.ptime_range, report.time_str) != 0) {
1300 if (session->evlist->first_sample_time == 0 && 1310 if (session->evlist->first_sample_time == 0 &&
1301 session->evlist->last_sample_time == 0) { 1311 session->evlist->last_sample_time == 0) {
1302 pr_err("No first/last sample time in perf data\n"); 1312 pr_err("HINT: no first/last sample time found in perf data.\n"
1303 return -EINVAL; 1313 "Please use latest perf binary to execute 'perf record'\n"
1314 "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
1315 ret = -EINVAL;
1316 goto error;
1304 } 1317 }
1305 1318
1306 report.range_num = perf_time__percent_parse_str( 1319 report.range_num = perf_time__percent_parse_str(
1307 report.ptime_range, PTIME_RANGE_MAX, 1320 report.ptime_range, report.range_size,
1308 report.time_str, 1321 report.time_str,
1309 session->evlist->first_sample_time, 1322 session->evlist->first_sample_time,
1310 session->evlist->last_sample_time); 1323 session->evlist->last_sample_time);
1311 1324
1312 if (report.range_num < 0) { 1325 if (report.range_num < 0) {
1313 pr_err("Invalid time string\n"); 1326 pr_err("Invalid time string\n");
1314 return -EINVAL; 1327 ret = -EINVAL;
1328 goto error;
1315 } 1329 }
1316 } else { 1330 } else {
1317 report.range_num = 1; 1331 report.range_num = 1;
@@ -1327,6 +1341,8 @@ repeat:
1327 ret = 0; 1341 ret = 0;
1328 1342
1329error: 1343error:
1344 zfree(&report.ptime_range);
1345
1330 perf_session__delete(session); 1346 perf_session__delete(session);
1331 return ret; 1347 return ret;
1332} 1348}
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c1cce474c0f1..3499d68e1d70 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1480,8 +1480,6 @@ static int perf_sample__fprintf_synth(struct perf_sample *sample,
1480 return 0; 1480 return 0;
1481} 1481}
1482 1482
1483#define PTIME_RANGE_MAX 10
1484
1485struct perf_script { 1483struct perf_script {
1486 struct perf_tool tool; 1484 struct perf_tool tool;
1487 struct perf_session *session; 1485 struct perf_session *session;
@@ -1496,7 +1494,8 @@ struct perf_script {
1496 struct thread_map *threads; 1494 struct thread_map *threads;
1497 int name_width; 1495 int name_width;
1498 const char *time_str; 1496 const char *time_str;
1499 struct perf_time_interval ptime_range[PTIME_RANGE_MAX]; 1497 struct perf_time_interval *ptime_range;
1498 int range_size;
1500 int range_num; 1499 int range_num;
1501}; 1500};
1502 1501
@@ -2919,9 +2918,10 @@ static void script__setup_sample_type(struct perf_script *script)
2919 2918
2920 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { 2919 if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) {
2921 if ((sample_type & PERF_SAMPLE_REGS_USER) && 2920 if ((sample_type & PERF_SAMPLE_REGS_USER) &&
2922 (sample_type & PERF_SAMPLE_STACK_USER)) 2921 (sample_type & PERF_SAMPLE_STACK_USER)) {
2923 callchain_param.record_mode = CALLCHAIN_DWARF; 2922 callchain_param.record_mode = CALLCHAIN_DWARF;
2924 else if (sample_type & PERF_SAMPLE_BRANCH_STACK) 2923 dwarf_callchain_users = true;
2924 } else if (sample_type & PERF_SAMPLE_BRANCH_STACK)
2925 callchain_param.record_mode = CALLCHAIN_LBR; 2925 callchain_param.record_mode = CALLCHAIN_LBR;
2926 else 2926 else
2927 callchain_param.record_mode = CALLCHAIN_FP; 2927 callchain_param.record_mode = CALLCHAIN_FP;
@@ -3444,17 +3444,26 @@ int cmd_script(int argc, const char **argv)
3444 if (err < 0) 3444 if (err < 0)
3445 goto out_delete; 3445 goto out_delete;
3446 3446
3447 script.ptime_range = perf_time__range_alloc(script.time_str,
3448 &script.range_size);
3449 if (!script.ptime_range) {
3450 err = -ENOMEM;
3451 goto out_delete;
3452 }
3453
3447 /* needs to be parsed after looking up reference time */ 3454 /* needs to be parsed after looking up reference time */
3448 if (perf_time__parse_str(script.ptime_range, script.time_str) != 0) { 3455 if (perf_time__parse_str(script.ptime_range, script.time_str) != 0) {
3449 if (session->evlist->first_sample_time == 0 && 3456 if (session->evlist->first_sample_time == 0 &&
3450 session->evlist->last_sample_time == 0) { 3457 session->evlist->last_sample_time == 0) {
3451 pr_err("No first/last sample time in perf data\n"); 3458 pr_err("HINT: no first/last sample time found in perf data.\n"
3459 "Please use latest perf binary to execute 'perf record'\n"
3460 "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n");
3452 err = -EINVAL; 3461 err = -EINVAL;
3453 goto out_delete; 3462 goto out_delete;
3454 } 3463 }
3455 3464
3456 script.range_num = perf_time__percent_parse_str( 3465 script.range_num = perf_time__percent_parse_str(
3457 script.ptime_range, PTIME_RANGE_MAX, 3466 script.ptime_range, script.range_size,
3458 script.time_str, 3467 script.time_str,
3459 session->evlist->first_sample_time, 3468 session->evlist->first_sample_time,
3460 session->evlist->last_sample_time); 3469 session->evlist->last_sample_time);
@@ -3473,6 +3482,8 @@ int cmd_script(int argc, const char **argv)
3473 flush_scripting(); 3482 flush_scripting();
3474 3483
3475out_delete: 3484out_delete:
3485 zfree(&script.ptime_range);
3486
3476 perf_evlist__free_stats(session->evlist); 3487 perf_evlist__free_stats(session->evlist);
3477 perf_session__delete(session); 3488 perf_session__delete(session);
3478 3489
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 71e64bdca86f..531d43bf57e1 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1644,7 +1644,7 @@ static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evse
1644 struct addr_location al; 1644 struct addr_location al;
1645 1645
1646 if (machine__resolve(trace->host, &al, sample) < 0 || 1646 if (machine__resolve(trace->host, &al, sample) < 0 ||
1647 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack)) 1647 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, evsel->attr.sample_max_stack))
1648 return -1; 1648 return -1;
1649 1649
1650 return 0; 1650 return 0;
@@ -2222,6 +2222,9 @@ static int trace__add_syscall_newtp(struct trace *trace)
2222 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret)) 2222 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2223 goto out_delete_sys_exit; 2223 goto out_delete_sys_exit;
2224 2224
2225 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2226 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2227
2225 perf_evlist__add(evlist, sys_enter); 2228 perf_evlist__add(evlist, sys_enter);
2226 perf_evlist__add(evlist, sys_exit); 2229 perf_evlist__add(evlist, sys_exit);
2227 2230
@@ -2318,6 +2321,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2318 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ); 2321 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2319 if (pgfault_maj == NULL) 2322 if (pgfault_maj == NULL)
2320 goto out_error_mem; 2323 goto out_error_mem;
2324 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2321 perf_evlist__add(evlist, pgfault_maj); 2325 perf_evlist__add(evlist, pgfault_maj);
2322 } 2326 }
2323 2327
@@ -2325,6 +2329,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2325 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN); 2329 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2326 if (pgfault_min == NULL) 2330 if (pgfault_min == NULL)
2327 goto out_error_mem; 2331 goto out_error_mem;
2332 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2328 perf_evlist__add(evlist, pgfault_min); 2333 perf_evlist__add(evlist, pgfault_min);
2329 } 2334 }
2330 2335
@@ -2345,45 +2350,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2345 goto out_delete_evlist; 2350 goto out_delete_evlist;
2346 } 2351 }
2347 2352
2348 perf_evlist__config(evlist, &trace->opts, NULL); 2353 perf_evlist__config(evlist, &trace->opts, &callchain_param);
2349
2350 if (callchain_param.enabled) {
2351 bool use_identifier = false;
2352
2353 if (trace->syscalls.events.sys_exit) {
2354 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2355 &trace->opts, &callchain_param);
2356 use_identifier = true;
2357 }
2358
2359 if (pgfault_maj) {
2360 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2361 use_identifier = true;
2362 }
2363
2364 if (pgfault_min) {
2365 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2366 use_identifier = true;
2367 }
2368
2369 if (use_identifier) {
2370 /*
2371 * Now we have evsels with different sample_ids, use
2372 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2373 * from a fixed position in each ring buffer record.
2374 *
2375 * As of this the changeset introducing this comment, this
2376 * isn't strictly needed, as the fields that can come before
2377 * PERF_SAMPLE_ID are all used, but we'll probably disable
2378 * some of those for things like copying the payload of
2379 * pointer syscall arguments, and for vfs_getname we don't
2380 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2381 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2382 */
2383 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2384 perf_evlist__reset_sample_bit(evlist, ID);
2385 }
2386 }
2387 2354
2388 signal(SIGCHLD, sig_handler); 2355 signal(SIGCHLD, sig_handler);
2389 signal(SIGINT, sig_handler); 2356 signal(SIGINT, sig_handler);
@@ -2456,6 +2423,18 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
2456 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 || 2423 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
2457 evlist->threads->nr > 1 || 2424 evlist->threads->nr > 1 ||
2458 perf_evlist__first(evlist)->attr.inherit; 2425 perf_evlist__first(evlist)->attr.inherit;
2426
2427 /*
2428 * Now that we already used evsel->attr to ask the kernel to setup the
2429 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2430 * trace__resolve_callchain(), allowing per-event max-stack settings
2431 * to override an explicitely set --max-stack global setting.
2432 */
2433 evlist__for_each_entry(evlist, evsel) {
2434 if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
2435 evsel->attr.sample_max_stack == 0)
2436 evsel->attr.sample_max_stack = trace->max_stack;
2437 }
2459again: 2438again:
2460 before = trace->nr_events; 2439 before = trace->nr_events;
2461 2440
@@ -3098,8 +3077,9 @@ int cmd_trace(int argc, const char **argv)
3098 } 3077 }
3099 3078
3100#ifdef HAVE_DWARF_UNWIND_SUPPORT 3079#ifdef HAVE_DWARF_UNWIND_SUPPORT
3101 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls) 3080 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
3102 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false); 3081 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3082 }
3103#endif 3083#endif
3104 3084
3105 if (callchain_param.enabled) { 3085 if (callchain_param.enabled) {
diff --git a/tools/perf/scripts/python/bin/mem-phys-addr-record b/tools/perf/scripts/python/bin/mem-phys-addr-record
new file mode 100644
index 000000000000..5a875122a904
--- /dev/null
+++ b/tools/perf/scripts/python/bin/mem-phys-addr-record
@@ -0,0 +1,19 @@
1#!/bin/bash
2
3#
4# Profiling physical memory by all retired load instructions/uops event
5# MEM_INST_RETIRED.ALL_LOADS or MEM_UOPS_RETIRED.ALL_LOADS
6#
7
8load=`perf list | grep mem_inst_retired.all_loads`
9if [ -z "$load" ]; then
10 load=`perf list | grep mem_uops_retired.all_loads`
11fi
12if [ -z "$load" ]; then
13 echo "There is no event to count all retired load instructions/uops."
14 exit 1
15fi
16
17arg=$(echo $load | tr -d ' ')
18arg="$arg:P"
19perf record --phys-data -e $arg $@
diff --git a/tools/perf/scripts/python/bin/mem-phys-addr-report b/tools/perf/scripts/python/bin/mem-phys-addr-report
new file mode 100644
index 000000000000..3f2b847e2eab
--- /dev/null
+++ b/tools/perf/scripts/python/bin/mem-phys-addr-report
@@ -0,0 +1,3 @@
1#!/bin/bash
2# description: resolve physical address samples
3perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/mem-phys-addr.py
diff --git a/tools/perf/scripts/python/mem-phys-addr.py b/tools/perf/scripts/python/mem-phys-addr.py
new file mode 100644
index 000000000000..ebee2c5ae496
--- /dev/null
+++ b/tools/perf/scripts/python/mem-phys-addr.py
@@ -0,0 +1,95 @@
1# mem-phys-addr.py: Resolve physical address samples
2# SPDX-License-Identifier: GPL-2.0
3#
4# Copyright (c) 2018, Intel Corporation.
5
6from __future__ import division
7import os
8import sys
9import struct
10import re
11import bisect
12import collections
13
14sys.path.append(os.environ['PERF_EXEC_PATH'] + \
15 '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
16
17#physical address ranges for System RAM
18system_ram = []
19#physical address ranges for Persistent Memory
20pmem = []
21#file object for proc iomem
22f = None
23#Count for each type of memory
24load_mem_type_cnt = collections.Counter()
25#perf event name
26event_name = None
27
28def parse_iomem():
29 global f
30 f = open('/proc/iomem', 'r')
31 for i, j in enumerate(f):
32 m = re.split('-|:',j,2)
33 if m[2].strip() == 'System RAM':
34 system_ram.append(long(m[0], 16))
35 system_ram.append(long(m[1], 16))
36 if m[2].strip() == 'Persistent Memory':
37 pmem.append(long(m[0], 16))
38 pmem.append(long(m[1], 16))
39
40def print_memory_type():
41 print "Event: %s" % (event_name)
42 print "%-40s %10s %10s\n" % ("Memory type", "count", "percentage"),
43 print "%-40s %10s %10s\n" % ("----------------------------------------", \
44 "-----------", "-----------"),
45 total = sum(load_mem_type_cnt.values())
46 for mem_type, count in sorted(load_mem_type_cnt.most_common(), \
47 key = lambda(k, v): (v, k), reverse = True):
48 print "%-40s %10d %10.1f%%\n" % (mem_type, count, 100 * count / total),
49
50def trace_begin():
51 parse_iomem()
52
53def trace_end():
54 print_memory_type()
55 f.close()
56
57def is_system_ram(phys_addr):
58 #/proc/iomem is sorted
59 position = bisect.bisect(system_ram, phys_addr)
60 if position % 2 == 0:
61 return False
62 return True
63
64def is_persistent_mem(phys_addr):
65 position = bisect.bisect(pmem, phys_addr)
66 if position % 2 == 0:
67 return False
68 return True
69
70def find_memory_type(phys_addr):
71 if phys_addr == 0:
72 return "N/A"
73 if is_system_ram(phys_addr):
74 return "System RAM"
75
76 if is_persistent_mem(phys_addr):
77 return "Persistent Memory"
78
79 #slow path, search all
80 f.seek(0, 0)
81 for j in f:
82 m = re.split('-|:',j,2)
83 if long(m[0], 16) <= phys_addr <= long(m[1], 16):
84 return m[2]
85 return "N/A"
86
87def process_event(param_dict):
88 name = param_dict["ev_name"]
89 sample = param_dict["sample"]
90 phys_addr = sample["phys_addr"]
91
92 global event_name
93 if event_name == None:
94 event_name = name
95 load_mem_type_cnt[find_memory_type(phys_addr)] += 1
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index ac40e05bcab4..260418969120 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -173,6 +173,7 @@ int test__dwarf_unwind(struct test *test __maybe_unused, int subtest __maybe_unu
173 } 173 }
174 174
175 callchain_param.record_mode = CALLCHAIN_DWARF; 175 callchain_param.record_mode = CALLCHAIN_DWARF;
176 dwarf_callchain_users = true;
176 177
177 if (init_live_machine(machine)) { 178 if (init_live_machine(machine)) {
178 pr_err("Could not init machine\n"); 179 pr_err("Could not init machine\n");
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index a3de7916fe63..7c6a8b461e24 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -86,6 +86,8 @@ libperf-$(CONFIG_AUXTRACE) += auxtrace.o
86libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ 86libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
87libperf-$(CONFIG_AUXTRACE) += intel-pt.o 87libperf-$(CONFIG_AUXTRACE) += intel-pt.o
88libperf-$(CONFIG_AUXTRACE) += intel-bts.o 88libperf-$(CONFIG_AUXTRACE) += intel-bts.o
89libperf-$(CONFIG_AUXTRACE) += arm-spe.o
90libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o
89libperf-y += parse-branch-options.o 91libperf-y += parse-branch-options.o
90libperf-y += dump-insn.o 92libperf-y += dump-insn.o
91libperf-y += parse-regs-options.o 93libperf-y += parse-regs-options.o
diff --git a/tools/perf/util/arm-spe-pkt-decoder.c b/tools/perf/util/arm-spe-pkt-decoder.c
new file mode 100644
index 000000000000..b94001b756c7
--- /dev/null
+++ b/tools/perf/util/arm-spe-pkt-decoder.c
@@ -0,0 +1,462 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#include <stdio.h>
8#include <string.h>
9#include <endian.h>
10#include <byteswap.h>
11
12#include "arm-spe-pkt-decoder.h"
13
14#define BIT(n) (1ULL << (n))
15
16#define NS_FLAG BIT(63)
17#define EL_FLAG (BIT(62) | BIT(61))
18
19#define SPE_HEADER0_PAD 0x0
20#define SPE_HEADER0_END 0x1
21#define SPE_HEADER0_ADDRESS 0x30 /* address packet (short) */
22#define SPE_HEADER0_ADDRESS_MASK 0x38
23#define SPE_HEADER0_COUNTER 0x18 /* counter packet (short) */
24#define SPE_HEADER0_COUNTER_MASK 0x38
25#define SPE_HEADER0_TIMESTAMP 0x71
26#define SPE_HEADER0_TIMESTAMP 0x71
27#define SPE_HEADER0_EVENTS 0x2
28#define SPE_HEADER0_EVENTS_MASK 0xf
29#define SPE_HEADER0_SOURCE 0x3
30#define SPE_HEADER0_SOURCE_MASK 0xf
31#define SPE_HEADER0_CONTEXT 0x24
32#define SPE_HEADER0_CONTEXT_MASK 0x3c
33#define SPE_HEADER0_OP_TYPE 0x8
34#define SPE_HEADER0_OP_TYPE_MASK 0x3c
35#define SPE_HEADER1_ALIGNMENT 0x0
36#define SPE_HEADER1_ADDRESS 0xb0 /* address packet (extended) */
37#define SPE_HEADER1_ADDRESS_MASK 0xf8
38#define SPE_HEADER1_COUNTER 0x98 /* counter packet (extended) */
39#define SPE_HEADER1_COUNTER_MASK 0xf8
40
41#if __BYTE_ORDER == __BIG_ENDIAN
42#define le16_to_cpu bswap_16
43#define le32_to_cpu bswap_32
44#define le64_to_cpu bswap_64
45#define memcpy_le64(d, s, n) do { \
46 memcpy((d), (s), (n)); \
47 *(d) = le64_to_cpu(*(d)); \
48} while (0)
49#else
50#define le16_to_cpu
51#define le32_to_cpu
52#define le64_to_cpu
53#define memcpy_le64 memcpy
54#endif
55
56static const char * const arm_spe_packet_name[] = {
57 [ARM_SPE_PAD] = "PAD",
58 [ARM_SPE_END] = "END",
59 [ARM_SPE_TIMESTAMP] = "TS",
60 [ARM_SPE_ADDRESS] = "ADDR",
61 [ARM_SPE_COUNTER] = "LAT",
62 [ARM_SPE_CONTEXT] = "CONTEXT",
63 [ARM_SPE_OP_TYPE] = "OP-TYPE",
64 [ARM_SPE_EVENTS] = "EVENTS",
65 [ARM_SPE_DATA_SOURCE] = "DATA-SOURCE",
66};
67
68const char *arm_spe_pkt_name(enum arm_spe_pkt_type type)
69{
70 return arm_spe_packet_name[type];
71}
72
73/* return ARM SPE payload size from its encoding,
74 * which is in bits 5:4 of the byte.
75 * 00 : byte
76 * 01 : halfword (2)
77 * 10 : word (4)
78 * 11 : doubleword (8)
79 */
80static int payloadlen(unsigned char byte)
81{
82 return 1 << ((byte & 0x30) >> 4);
83}
84
85static int arm_spe_get_payload(const unsigned char *buf, size_t len,
86 struct arm_spe_pkt *packet)
87{
88 size_t payload_len = payloadlen(buf[0]);
89
90 if (len < 1 + payload_len)
91 return ARM_SPE_NEED_MORE_BYTES;
92
93 buf++;
94
95 switch (payload_len) {
96 case 1: packet->payload = *(uint8_t *)buf; break;
97 case 2: packet->payload = le16_to_cpu(*(uint16_t *)buf); break;
98 case 4: packet->payload = le32_to_cpu(*(uint32_t *)buf); break;
99 case 8: packet->payload = le64_to_cpu(*(uint64_t *)buf); break;
100 default: return ARM_SPE_BAD_PACKET;
101 }
102
103 return 1 + payload_len;
104}
105
106static int arm_spe_get_pad(struct arm_spe_pkt *packet)
107{
108 packet->type = ARM_SPE_PAD;
109 return 1;
110}
111
112static int arm_spe_get_alignment(const unsigned char *buf, size_t len,
113 struct arm_spe_pkt *packet)
114{
115 unsigned int alignment = 1 << ((buf[0] & 0xf) + 1);
116
117 if (len < alignment)
118 return ARM_SPE_NEED_MORE_BYTES;
119
120 packet->type = ARM_SPE_PAD;
121 return alignment - (((uintptr_t)buf) & (alignment - 1));
122}
123
124static int arm_spe_get_end(struct arm_spe_pkt *packet)
125{
126 packet->type = ARM_SPE_END;
127 return 1;
128}
129
130static int arm_spe_get_timestamp(const unsigned char *buf, size_t len,
131 struct arm_spe_pkt *packet)
132{
133 packet->type = ARM_SPE_TIMESTAMP;
134 return arm_spe_get_payload(buf, len, packet);
135}
136
137static int arm_spe_get_events(const unsigned char *buf, size_t len,
138 struct arm_spe_pkt *packet)
139{
140 int ret = arm_spe_get_payload(buf, len, packet);
141
142 packet->type = ARM_SPE_EVENTS;
143
144 /* we use index to identify Events with a less number of
145 * comparisons in arm_spe_pkt_desc(): E.g., the LLC-ACCESS,
146 * LLC-REFILL, and REMOTE-ACCESS events are identified iff
147 * index > 1.
148 */
149 packet->index = ret - 1;
150
151 return ret;
152}
153
154static int arm_spe_get_data_source(const unsigned char *buf, size_t len,
155 struct arm_spe_pkt *packet)
156{
157 packet->type = ARM_SPE_DATA_SOURCE;
158 return arm_spe_get_payload(buf, len, packet);
159}
160
161static int arm_spe_get_context(const unsigned char *buf, size_t len,
162 struct arm_spe_pkt *packet)
163{
164 packet->type = ARM_SPE_CONTEXT;
165 packet->index = buf[0] & 0x3;
166
167 return arm_spe_get_payload(buf, len, packet);
168}
169
170static int arm_spe_get_op_type(const unsigned char *buf, size_t len,
171 struct arm_spe_pkt *packet)
172{
173 packet->type = ARM_SPE_OP_TYPE;
174 packet->index = buf[0] & 0x3;
175 return arm_spe_get_payload(buf, len, packet);
176}
177
178static int arm_spe_get_counter(const unsigned char *buf, size_t len,
179 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
180{
181 if (len < 2)
182 return ARM_SPE_NEED_MORE_BYTES;
183
184 packet->type = ARM_SPE_COUNTER;
185 if (ext_hdr)
186 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
187 else
188 packet->index = buf[0] & 0x7;
189
190 packet->payload = le16_to_cpu(*(uint16_t *)(buf + 1));
191
192 return 1 + ext_hdr + 2;
193}
194
195static int arm_spe_get_addr(const unsigned char *buf, size_t len,
196 const unsigned char ext_hdr, struct arm_spe_pkt *packet)
197{
198 if (len < 8)
199 return ARM_SPE_NEED_MORE_BYTES;
200
201 packet->type = ARM_SPE_ADDRESS;
202 if (ext_hdr)
203 packet->index = ((buf[0] & 0x3) << 3) | (buf[1] & 0x7);
204 else
205 packet->index = buf[0] & 0x7;
206
207 memcpy_le64(&packet->payload, buf + 1, 8);
208
209 return 1 + ext_hdr + 8;
210}
211
212static int arm_spe_do_get_packet(const unsigned char *buf, size_t len,
213 struct arm_spe_pkt *packet)
214{
215 unsigned int byte;
216
217 memset(packet, 0, sizeof(struct arm_spe_pkt));
218
219 if (!len)
220 return ARM_SPE_NEED_MORE_BYTES;
221
222 byte = buf[0];
223 if (byte == SPE_HEADER0_PAD)
224 return arm_spe_get_pad(packet);
225 else if (byte == SPE_HEADER0_END) /* no timestamp at end of record */
226 return arm_spe_get_end(packet);
227 else if (byte & 0xc0 /* 0y11xxxxxx */) {
228 if (byte & 0x80) {
229 if ((byte & SPE_HEADER0_ADDRESS_MASK) == SPE_HEADER0_ADDRESS)
230 return arm_spe_get_addr(buf, len, 0, packet);
231 if ((byte & SPE_HEADER0_COUNTER_MASK) == SPE_HEADER0_COUNTER)
232 return arm_spe_get_counter(buf, len, 0, packet);
233 } else
234 if (byte == SPE_HEADER0_TIMESTAMP)
235 return arm_spe_get_timestamp(buf, len, packet);
236 else if ((byte & SPE_HEADER0_EVENTS_MASK) == SPE_HEADER0_EVENTS)
237 return arm_spe_get_events(buf, len, packet);
238 else if ((byte & SPE_HEADER0_SOURCE_MASK) == SPE_HEADER0_SOURCE)
239 return arm_spe_get_data_source(buf, len, packet);
240 else if ((byte & SPE_HEADER0_CONTEXT_MASK) == SPE_HEADER0_CONTEXT)
241 return arm_spe_get_context(buf, len, packet);
242 else if ((byte & SPE_HEADER0_OP_TYPE_MASK) == SPE_HEADER0_OP_TYPE)
243 return arm_spe_get_op_type(buf, len, packet);
244 } else if ((byte & 0xe0) == 0x20 /* 0y001xxxxx */) {
245 /* 16-bit header */
246 byte = buf[1];
247 if (byte == SPE_HEADER1_ALIGNMENT)
248 return arm_spe_get_alignment(buf, len, packet);
249 else if ((byte & SPE_HEADER1_ADDRESS_MASK) == SPE_HEADER1_ADDRESS)
250 return arm_spe_get_addr(buf, len, 1, packet);
251 else if ((byte & SPE_HEADER1_COUNTER_MASK) == SPE_HEADER1_COUNTER)
252 return arm_spe_get_counter(buf, len, 1, packet);
253 }
254
255 return ARM_SPE_BAD_PACKET;
256}
257
258int arm_spe_get_packet(const unsigned char *buf, size_t len,
259 struct arm_spe_pkt *packet)
260{
261 int ret;
262
263 ret = arm_spe_do_get_packet(buf, len, packet);
264 /* put multiple consecutive PADs on the same line, up to
265 * the fixed-width output format of 16 bytes per line.
266 */
267 if (ret > 0 && packet->type == ARM_SPE_PAD) {
268 while (ret < 16 && len > (size_t)ret && !buf[ret])
269 ret += 1;
270 }
271 return ret;
272}
273
274int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf,
275 size_t buf_len)
276{
277 int ret, ns, el, idx = packet->index;
278 unsigned long long payload = packet->payload;
279 const char *name = arm_spe_pkt_name(packet->type);
280
281 switch (packet->type) {
282 case ARM_SPE_BAD:
283 case ARM_SPE_PAD:
284 case ARM_SPE_END:
285 return snprintf(buf, buf_len, "%s", name);
286 case ARM_SPE_EVENTS: {
287 size_t blen = buf_len;
288
289 ret = 0;
290 ret = snprintf(buf, buf_len, "EV");
291 buf += ret;
292 blen -= ret;
293 if (payload & 0x1) {
294 ret = snprintf(buf, buf_len, " EXCEPTION-GEN");
295 buf += ret;
296 blen -= ret;
297 }
298 if (payload & 0x2) {
299 ret = snprintf(buf, buf_len, " RETIRED");
300 buf += ret;
301 blen -= ret;
302 }
303 if (payload & 0x4) {
304 ret = snprintf(buf, buf_len, " L1D-ACCESS");
305 buf += ret;
306 blen -= ret;
307 }
308 if (payload & 0x8) {
309 ret = snprintf(buf, buf_len, " L1D-REFILL");
310 buf += ret;
311 blen -= ret;
312 }
313 if (payload & 0x10) {
314 ret = snprintf(buf, buf_len, " TLB-ACCESS");
315 buf += ret;
316 blen -= ret;
317 }
318 if (payload & 0x20) {
319 ret = snprintf(buf, buf_len, " TLB-REFILL");
320 buf += ret;
321 blen -= ret;
322 }
323 if (payload & 0x40) {
324 ret = snprintf(buf, buf_len, " NOT-TAKEN");
325 buf += ret;
326 blen -= ret;
327 }
328 if (payload & 0x80) {
329 ret = snprintf(buf, buf_len, " MISPRED");
330 buf += ret;
331 blen -= ret;
332 }
333 if (idx > 1) {
334 if (payload & 0x100) {
335 ret = snprintf(buf, buf_len, " LLC-ACCESS");
336 buf += ret;
337 blen -= ret;
338 }
339 if (payload & 0x200) {
340 ret = snprintf(buf, buf_len, " LLC-REFILL");
341 buf += ret;
342 blen -= ret;
343 }
344 if (payload & 0x400) {
345 ret = snprintf(buf, buf_len, " REMOTE-ACCESS");
346 buf += ret;
347 blen -= ret;
348 }
349 }
350 if (ret < 0)
351 return ret;
352 blen -= ret;
353 return buf_len - blen;
354 }
355 case ARM_SPE_OP_TYPE:
356 switch (idx) {
357 case 0: return snprintf(buf, buf_len, "%s", payload & 0x1 ?
358 "COND-SELECT" : "INSN-OTHER");
359 case 1: {
360 size_t blen = buf_len;
361
362 if (payload & 0x1)
363 ret = snprintf(buf, buf_len, "ST");
364 else
365 ret = snprintf(buf, buf_len, "LD");
366 buf += ret;
367 blen -= ret;
368 if (payload & 0x2) {
369 if (payload & 0x4) {
370 ret = snprintf(buf, buf_len, " AT");
371 buf += ret;
372 blen -= ret;
373 }
374 if (payload & 0x8) {
375 ret = snprintf(buf, buf_len, " EXCL");
376 buf += ret;
377 blen -= ret;
378 }
379 if (payload & 0x10) {
380 ret = snprintf(buf, buf_len, " AR");
381 buf += ret;
382 blen -= ret;
383 }
384 } else if (payload & 0x4) {
385 ret = snprintf(buf, buf_len, " SIMD-FP");
386 buf += ret;
387 blen -= ret;
388 }
389 if (ret < 0)
390 return ret;
391 blen -= ret;
392 return buf_len - blen;
393 }
394 case 2: {
395 size_t blen = buf_len;
396
397 ret = snprintf(buf, buf_len, "B");
398 buf += ret;
399 blen -= ret;
400 if (payload & 0x1) {
401 ret = snprintf(buf, buf_len, " COND");
402 buf += ret;
403 blen -= ret;
404 }
405 if (payload & 0x2) {
406 ret = snprintf(buf, buf_len, " IND");
407 buf += ret;
408 blen -= ret;
409 }
410 if (ret < 0)
411 return ret;
412 blen -= ret;
413 return buf_len - blen;
414 }
415 default: return 0;
416 }
417 case ARM_SPE_DATA_SOURCE:
418 case ARM_SPE_TIMESTAMP:
419 return snprintf(buf, buf_len, "%s %lld", name, payload);
420 case ARM_SPE_ADDRESS:
421 switch (idx) {
422 case 0:
423 case 1: ns = !!(packet->payload & NS_FLAG);
424 el = (packet->payload & EL_FLAG) >> 61;
425 payload &= ~(0xffULL << 56);
426 return snprintf(buf, buf_len, "%s 0x%llx el%d ns=%d",
427 (idx == 1) ? "TGT" : "PC", payload, el, ns);
428 case 2: return snprintf(buf, buf_len, "VA 0x%llx", payload);
429 case 3: ns = !!(packet->payload & NS_FLAG);
430 payload &= ~(0xffULL << 56);
431 return snprintf(buf, buf_len, "PA 0x%llx ns=%d",
432 payload, ns);
433 default: return 0;
434 }
435 case ARM_SPE_CONTEXT:
436 return snprintf(buf, buf_len, "%s 0x%lx el%d", name,
437 (unsigned long)payload, idx + 1);
438 case ARM_SPE_COUNTER: {
439 size_t blen = buf_len;
440
441 ret = snprintf(buf, buf_len, "%s %d ", name,
442 (unsigned short)payload);
443 buf += ret;
444 blen -= ret;
445 switch (idx) {
446 case 0: ret = snprintf(buf, buf_len, "TOT"); break;
447 case 1: ret = snprintf(buf, buf_len, "ISSUE"); break;
448 case 2: ret = snprintf(buf, buf_len, "XLAT"); break;
449 default: ret = 0;
450 }
451 if (ret < 0)
452 return ret;
453 blen -= ret;
454 return buf_len - blen;
455 }
456 default:
457 break;
458 }
459
460 return snprintf(buf, buf_len, "%s 0x%llx (%d)",
461 name, payload, packet->index);
462}
diff --git a/tools/perf/util/arm-spe-pkt-decoder.h b/tools/perf/util/arm-spe-pkt-decoder.h
new file mode 100644
index 000000000000..d786ef65113f
--- /dev/null
+++ b/tools/perf/util/arm-spe-pkt-decoder.h
@@ -0,0 +1,43 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#ifndef INCLUDE__ARM_SPE_PKT_DECODER_H__
8#define INCLUDE__ARM_SPE_PKT_DECODER_H__
9
10#include <stddef.h>
11#include <stdint.h>
12
13#define ARM_SPE_PKT_DESC_MAX 256
14
15#define ARM_SPE_NEED_MORE_BYTES -1
16#define ARM_SPE_BAD_PACKET -2
17
18enum arm_spe_pkt_type {
19 ARM_SPE_BAD,
20 ARM_SPE_PAD,
21 ARM_SPE_END,
22 ARM_SPE_TIMESTAMP,
23 ARM_SPE_ADDRESS,
24 ARM_SPE_COUNTER,
25 ARM_SPE_CONTEXT,
26 ARM_SPE_OP_TYPE,
27 ARM_SPE_EVENTS,
28 ARM_SPE_DATA_SOURCE,
29};
30
31struct arm_spe_pkt {
32 enum arm_spe_pkt_type type;
33 unsigned char index;
34 uint64_t payload;
35};
36
37const char *arm_spe_pkt_name(enum arm_spe_pkt_type);
38
39int arm_spe_get_packet(const unsigned char *buf, size_t len,
40 struct arm_spe_pkt *packet);
41
42int arm_spe_pkt_desc(const struct arm_spe_pkt *packet, char *buf, size_t len);
43#endif
diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
new file mode 100644
index 000000000000..6067267cc76c
--- /dev/null
+++ b/tools/perf/util/arm-spe.c
@@ -0,0 +1,231 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#include <endian.h>
8#include <errno.h>
9#include <byteswap.h>
10#include <inttypes.h>
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/bitops.h>
14#include <linux/log2.h>
15
16#include "cpumap.h"
17#include "color.h"
18#include "evsel.h"
19#include "evlist.h"
20#include "machine.h"
21#include "session.h"
22#include "util.h"
23#include "thread.h"
24#include "debug.h"
25#include "auxtrace.h"
26#include "arm-spe.h"
27#include "arm-spe-pkt-decoder.h"
28
29struct arm_spe {
30 struct auxtrace auxtrace;
31 struct auxtrace_queues queues;
32 struct auxtrace_heap heap;
33 u32 auxtrace_type;
34 struct perf_session *session;
35 struct machine *machine;
36 u32 pmu_type;
37};
38
39struct arm_spe_queue {
40 struct arm_spe *spe;
41 unsigned int queue_nr;
42 struct auxtrace_buffer *buffer;
43 bool on_heap;
44 bool done;
45 pid_t pid;
46 pid_t tid;
47 int cpu;
48};
49
50static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
51 unsigned char *buf, size_t len)
52{
53 struct arm_spe_pkt packet;
54 size_t pos = 0;
55 int ret, pkt_len, i;
56 char desc[ARM_SPE_PKT_DESC_MAX];
57 const char *color = PERF_COLOR_BLUE;
58
59 color_fprintf(stdout, color,
60 ". ... ARM SPE data: size %zu bytes\n",
61 len);
62
63 while (len) {
64 ret = arm_spe_get_packet(buf, len, &packet);
65 if (ret > 0)
66 pkt_len = ret;
67 else
68 pkt_len = 1;
69 printf(".");
70 color_fprintf(stdout, color, " %08x: ", pos);
71 for (i = 0; i < pkt_len; i++)
72 color_fprintf(stdout, color, " %02x", buf[i]);
73 for (; i < 16; i++)
74 color_fprintf(stdout, color, " ");
75 if (ret > 0) {
76 ret = arm_spe_pkt_desc(&packet, desc,
77 ARM_SPE_PKT_DESC_MAX);
78 if (ret > 0)
79 color_fprintf(stdout, color, " %s\n", desc);
80 } else {
81 color_fprintf(stdout, color, " Bad packet!\n");
82 }
83 pos += pkt_len;
84 buf += pkt_len;
85 len -= pkt_len;
86 }
87}
88
89static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
90 size_t len)
91{
92 printf(".\n");
93 arm_spe_dump(spe, buf, len);
94}
95
96static int arm_spe_process_event(struct perf_session *session __maybe_unused,
97 union perf_event *event __maybe_unused,
98 struct perf_sample *sample __maybe_unused,
99 struct perf_tool *tool __maybe_unused)
100{
101 return 0;
102}
103
104static int arm_spe_process_auxtrace_event(struct perf_session *session,
105 union perf_event *event,
106 struct perf_tool *tool __maybe_unused)
107{
108 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
109 auxtrace);
110 struct auxtrace_buffer *buffer;
111 off_t data_offset;
112 int fd = perf_data__fd(session->data);
113 int err;
114
115 if (perf_data__is_pipe(session->data)) {
116 data_offset = 0;
117 } else {
118 data_offset = lseek(fd, 0, SEEK_CUR);
119 if (data_offset == -1)
120 return -errno;
121 }
122
123 err = auxtrace_queues__add_event(&spe->queues, session, event,
124 data_offset, &buffer);
125 if (err)
126 return err;
127
128 /* Dump here now we have copied a piped trace out of the pipe */
129 if (dump_trace) {
130 if (auxtrace_buffer__get_data(buffer, fd)) {
131 arm_spe_dump_event(spe, buffer->data,
132 buffer->size);
133 auxtrace_buffer__put_data(buffer);
134 }
135 }
136
137 return 0;
138}
139
140static int arm_spe_flush(struct perf_session *session __maybe_unused,
141 struct perf_tool *tool __maybe_unused)
142{
143 return 0;
144}
145
146static void arm_spe_free_queue(void *priv)
147{
148 struct arm_spe_queue *speq = priv;
149
150 if (!speq)
151 return;
152 free(speq);
153}
154
155static void arm_spe_free_events(struct perf_session *session)
156{
157 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
158 auxtrace);
159 struct auxtrace_queues *queues = &spe->queues;
160 unsigned int i;
161
162 for (i = 0; i < queues->nr_queues; i++) {
163 arm_spe_free_queue(queues->queue_array[i].priv);
164 queues->queue_array[i].priv = NULL;
165 }
166 auxtrace_queues__free(queues);
167}
168
169static void arm_spe_free(struct perf_session *session)
170{
171 struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
172 auxtrace);
173
174 auxtrace_heap__free(&spe->heap);
175 arm_spe_free_events(session);
176 session->auxtrace = NULL;
177 free(spe);
178}
179
180static const char * const arm_spe_info_fmts[] = {
181 [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n",
182};
183
184static void arm_spe_print_info(u64 *arr)
185{
186 if (!dump_trace)
187 return;
188
189 fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
190}
191
192int arm_spe_process_auxtrace_info(union perf_event *event,
193 struct perf_session *session)
194{
195 struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
196 size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
197 struct arm_spe *spe;
198 int err;
199
200 if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
201 min_sz)
202 return -EINVAL;
203
204 spe = zalloc(sizeof(struct arm_spe));
205 if (!spe)
206 return -ENOMEM;
207
208 err = auxtrace_queues__init(&spe->queues);
209 if (err)
210 goto err_free;
211
212 spe->session = session;
213 spe->machine = &session->machines.host; /* No kvm support */
214 spe->auxtrace_type = auxtrace_info->type;
215 spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
216
217 spe->auxtrace.process_event = arm_spe_process_event;
218 spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
219 spe->auxtrace.flush_events = arm_spe_flush;
220 spe->auxtrace.free_events = arm_spe_free_events;
221 spe->auxtrace.free = arm_spe_free;
222 session->auxtrace = &spe->auxtrace;
223
224 arm_spe_print_info(&auxtrace_info->priv[0]);
225
226 return 0;
227
228err_free:
229 free(spe);
230 return err;
231}
diff --git a/tools/perf/util/arm-spe.h b/tools/perf/util/arm-spe.h
new file mode 100644
index 000000000000..98d3235781c3
--- /dev/null
+++ b/tools/perf/util/arm-spe.h
@@ -0,0 +1,31 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Arm Statistical Profiling Extensions (SPE) support
4 * Copyright (c) 2017-2018, Arm Ltd.
5 */
6
7#ifndef INCLUDE__PERF_ARM_SPE_H__
8#define INCLUDE__PERF_ARM_SPE_H__
9
10#define ARM_SPE_PMU_NAME "arm_spe_"
11
12enum {
13 ARM_SPE_PMU_TYPE,
14 ARM_SPE_PER_CPU_MMAPS,
15 ARM_SPE_AUXTRACE_PRIV_MAX,
16};
17
18#define ARM_SPE_AUXTRACE_PRIV_SIZE (ARM_SPE_AUXTRACE_PRIV_MAX * sizeof(u64))
19
20union perf_event;
21struct perf_session;
22struct perf_pmu;
23
24struct auxtrace_record *arm_spe_recording_init(int *err,
25 struct perf_pmu *arm_spe_pmu);
26
27int arm_spe_process_auxtrace_info(union perf_event *event,
28 struct perf_session *session);
29
30struct perf_event_attr *arm_spe_pmu_default_config(struct perf_pmu *arm_spe_pmu);
31#endif
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index c76687e42344..3bba9947ab7f 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -54,6 +54,7 @@
54 54
55#include "intel-pt.h" 55#include "intel-pt.h"
56#include "intel-bts.h" 56#include "intel-bts.h"
57#include "arm-spe.h"
57 58
58#include "sane_ctype.h" 59#include "sane_ctype.h"
59#include "symbol/kallsyms.h" 60#include "symbol/kallsyms.h"
@@ -910,6 +911,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
910 return intel_pt_process_auxtrace_info(event, session); 911 return intel_pt_process_auxtrace_info(event, session);
911 case PERF_AUXTRACE_INTEL_BTS: 912 case PERF_AUXTRACE_INTEL_BTS:
912 return intel_bts_process_auxtrace_info(event, session); 913 return intel_bts_process_auxtrace_info(event, session);
914 case PERF_AUXTRACE_ARM_SPE:
915 return arm_spe_process_auxtrace_info(event, session);
913 case PERF_AUXTRACE_CS_ETM: 916 case PERF_AUXTRACE_CS_ETM:
914 case PERF_AUXTRACE_UNKNOWN: 917 case PERF_AUXTRACE_UNKNOWN:
915 default: 918 default:
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
index d19e11b68de7..453c148d2158 100644
--- a/tools/perf/util/auxtrace.h
+++ b/tools/perf/util/auxtrace.h
@@ -43,6 +43,7 @@ enum auxtrace_type {
43 PERF_AUXTRACE_INTEL_PT, 43 PERF_AUXTRACE_INTEL_PT,
44 PERF_AUXTRACE_INTEL_BTS, 44 PERF_AUXTRACE_INTEL_BTS,
45 PERF_AUXTRACE_CS_ETM, 45 PERF_AUXTRACE_CS_ETM,
46 PERF_AUXTRACE_ARM_SPE,
46}; 47};
47 48
48enum itrace_period_type { 49enum itrace_period_type {
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 082505d08d72..32ef7bdca1cf 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -37,6 +37,15 @@ struct callchain_param callchain_param = {
37 CALLCHAIN_PARAM_DEFAULT 37 CALLCHAIN_PARAM_DEFAULT
38}; 38};
39 39
40/*
41 * Are there any events usind DWARF callchains?
42 *
43 * I.e.
44 *
45 * -e cycles/call-graph=dwarf/
46 */
47bool dwarf_callchain_users;
48
40struct callchain_param callchain_param_default = { 49struct callchain_param callchain_param_default = {
41 CALLCHAIN_PARAM_DEFAULT 50 CALLCHAIN_PARAM_DEFAULT
42}; 51};
@@ -265,6 +274,7 @@ int parse_callchain_record(const char *arg, struct callchain_param *param)
265 ret = 0; 274 ret = 0;
266 param->record_mode = CALLCHAIN_DWARF; 275 param->record_mode = CALLCHAIN_DWARF;
267 param->dump_size = default_stack_dump_size; 276 param->dump_size = default_stack_dump_size;
277 dwarf_callchain_users = true;
268 278
269 tok = strtok_r(NULL, ",", &saveptr); 279 tok = strtok_r(NULL, ",", &saveptr);
270 if (tok) { 280 if (tok) {
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index b79ef2478a57..154560b1eb65 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -89,6 +89,8 @@ enum chain_value {
89 CCVAL_COUNT, 89 CCVAL_COUNT,
90}; 90};
91 91
92extern bool dwarf_callchain_users;
93
92struct callchain_param { 94struct callchain_param {
93 bool enabled; 95 bool enabled;
94 enum perf_call_graph_mode record_mode; 96 enum perf_call_graph_mode record_mode;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f0a5e09c4071..120efd85f2c8 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1760,7 +1760,7 @@ void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist,
1760 switch (old_state) { 1760 switch (old_state) {
1761 case BKW_MMAP_NOTREADY: { 1761 case BKW_MMAP_NOTREADY: {
1762 if (state != BKW_MMAP_RUNNING) 1762 if (state != BKW_MMAP_RUNNING)
1763 goto state_err;; 1763 goto state_err;
1764 break; 1764 break;
1765 } 1765 }
1766 case BKW_MMAP_RUNNING: { 1766 case BKW_MMAP_RUNNING: {
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index d934f04e3110..85eb84dfdf91 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -651,9 +651,9 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size)
651 return ret; 651 return ret;
652} 652}
653 653
654void perf_evsel__config_callchain(struct perf_evsel *evsel, 654static void __perf_evsel__config_callchain(struct perf_evsel *evsel,
655 struct record_opts *opts, 655 struct record_opts *opts,
656 struct callchain_param *param) 656 struct callchain_param *param)
657{ 657{
658 bool function = perf_evsel__is_function_event(evsel); 658 bool function = perf_evsel__is_function_event(evsel);
659 struct perf_event_attr *attr = &evsel->attr; 659 struct perf_event_attr *attr = &evsel->attr;
@@ -699,6 +699,14 @@ void perf_evsel__config_callchain(struct perf_evsel *evsel,
699 } 699 }
700} 700}
701 701
702void perf_evsel__config_callchain(struct perf_evsel *evsel,
703 struct record_opts *opts,
704 struct callchain_param *param)
705{
706 if (param->enabled)
707 return __perf_evsel__config_callchain(evsel, opts, param);
708}
709
702static void 710static void
703perf_evsel__reset_callgraph(struct perf_evsel *evsel, 711perf_evsel__reset_callgraph(struct perf_evsel *evsel,
704 struct callchain_param *param) 712 struct callchain_param *param)
@@ -718,19 +726,19 @@ perf_evsel__reset_callgraph(struct perf_evsel *evsel,
718} 726}
719 727
720static void apply_config_terms(struct perf_evsel *evsel, 728static void apply_config_terms(struct perf_evsel *evsel,
721 struct record_opts *opts) 729 struct record_opts *opts, bool track)
722{ 730{
723 struct perf_evsel_config_term *term; 731 struct perf_evsel_config_term *term;
724 struct list_head *config_terms = &evsel->config_terms; 732 struct list_head *config_terms = &evsel->config_terms;
725 struct perf_event_attr *attr = &evsel->attr; 733 struct perf_event_attr *attr = &evsel->attr;
726 struct callchain_param param; 734 /* callgraph default */
735 struct callchain_param param = {
736 .record_mode = callchain_param.record_mode,
737 };
727 u32 dump_size = 0; 738 u32 dump_size = 0;
728 int max_stack = 0; 739 int max_stack = 0;
729 const char *callgraph_buf = NULL; 740 const char *callgraph_buf = NULL;
730 741
731 /* callgraph default */
732 param.record_mode = callchain_param.record_mode;
733
734 list_for_each_entry(term, config_terms, list) { 742 list_for_each_entry(term, config_terms, list) {
735 switch (term->type) { 743 switch (term->type) {
736 case PERF_EVSEL__CONFIG_TERM_PERIOD: 744 case PERF_EVSEL__CONFIG_TERM_PERIOD:
@@ -781,7 +789,7 @@ static void apply_config_terms(struct perf_evsel *evsel,
781 attr->write_backward = term->val.overwrite ? 1 : 0; 789 attr->write_backward = term->val.overwrite ? 1 : 0;
782 break; 790 break;
783 case PERF_EVSEL__CONFIG_TERM_DRV_CFG: 791 case PERF_EVSEL__CONFIG_TERM_DRV_CFG:
784 BUG_ON(1); 792 break;
785 default: 793 default:
786 break; 794 break;
787 } 795 }
@@ -789,6 +797,8 @@ static void apply_config_terms(struct perf_evsel *evsel,
789 797
790 /* User explicitly set per-event callgraph, clear the old setting and reset. */ 798 /* User explicitly set per-event callgraph, clear the old setting and reset. */
791 if ((callgraph_buf != NULL) || (dump_size > 0) || max_stack) { 799 if ((callgraph_buf != NULL) || (dump_size > 0) || max_stack) {
800 bool sample_address = false;
801
792 if (max_stack) { 802 if (max_stack) {
793 param.max_stack = max_stack; 803 param.max_stack = max_stack;
794 if (callgraph_buf == NULL) 804 if (callgraph_buf == NULL)
@@ -808,6 +818,8 @@ static void apply_config_terms(struct perf_evsel *evsel,
808 evsel->name); 818 evsel->name);
809 return; 819 return;
810 } 820 }
821 if (param.record_mode == CALLCHAIN_DWARF)
822 sample_address = true;
811 } 823 }
812 } 824 }
813 if (dump_size > 0) { 825 if (dump_size > 0) {
@@ -820,8 +832,14 @@ static void apply_config_terms(struct perf_evsel *evsel,
820 perf_evsel__reset_callgraph(evsel, &callchain_param); 832 perf_evsel__reset_callgraph(evsel, &callchain_param);
821 833
822 /* set perf-event callgraph */ 834 /* set perf-event callgraph */
823 if (param.enabled) 835 if (param.enabled) {
836 if (sample_address) {
837 perf_evsel__set_sample_bit(evsel, ADDR);
838 perf_evsel__set_sample_bit(evsel, DATA_SRC);
839 evsel->attr.mmap_data = track;
840 }
824 perf_evsel__config_callchain(evsel, opts, &param); 841 perf_evsel__config_callchain(evsel, opts, &param);
842 }
825 } 843 }
826} 844}
827 845
@@ -1052,7 +1070,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts,
1052 * Apply event specific term settings, 1070 * Apply event specific term settings,
1053 * it overloads any global configuration. 1071 * it overloads any global configuration.
1054 */ 1072 */
1055 apply_config_terms(evsel, opts); 1073 apply_config_terms(evsel, opts, track);
1056 1074
1057 evsel->ignore_missing_thread = opts->ignore_missing_thread; 1075 evsel->ignore_missing_thread = opts->ignore_missing_thread;
1058} 1076}
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c1848b543f27..ea070883c593 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -499,6 +499,8 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample,
499 PyLong_FromUnsignedLongLong(sample->time)); 499 PyLong_FromUnsignedLongLong(sample->time));
500 pydict_set_item_string_decref(dict_sample, "period", 500 pydict_set_item_string_decref(dict_sample, "period",
501 PyLong_FromUnsignedLongLong(sample->period)); 501 PyLong_FromUnsignedLongLong(sample->period));
502 pydict_set_item_string_decref(dict_sample, "phys_addr",
503 PyLong_FromUnsignedLongLong(sample->phys_addr));
502 set_sample_read_in_dict(dict_sample, sample, evsel); 504 set_sample_read_in_dict(dict_sample, sample, evsel);
503 pydict_set_item_string_decref(dict, "sample", dict_sample); 505 pydict_set_item_string_decref(dict, "sample", dict_sample);
504 506
diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c
index 3f7f18f06982..6193b46050a5 100644
--- a/tools/perf/util/time-utils.c
+++ b/tools/perf/util/time-utils.c
@@ -116,7 +116,8 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr)
116 116
117static int parse_percent(double *pcnt, char *str) 117static int parse_percent(double *pcnt, char *str)
118{ 118{
119 char *c; 119 char *c, *endptr;
120 double d;
120 121
121 c = strchr(str, '%'); 122 c = strchr(str, '%');
122 if (c) 123 if (c)
@@ -124,8 +125,11 @@ static int parse_percent(double *pcnt, char *str)
124 else 125 else
125 return -1; 126 return -1;
126 127
127 *pcnt = atof(str) / 100.0; 128 d = strtod(str, &endptr);
129 if (endptr != str + strlen(str))
130 return -1;
128 131
132 *pcnt = d / 100.0;
129 return 0; 133 return 0;
130} 134}
131 135
@@ -257,6 +261,37 @@ static int percent_comma_split(struct perf_time_interval *ptime_buf, int num,
257 return i; 261 return i;
258} 262}
259 263
264static int one_percent_convert(struct perf_time_interval *ptime_buf,
265 const char *ostr, u64 start, u64 end, char *c)
266{
267 char *str;
268 int len = strlen(ostr), ret;
269
270 /*
271 * c points to '%'.
272 * '%' should be the last character
273 */
274 if (ostr + len - 1 != c)
275 return -1;
276
277 /*
278 * Construct a string like "xx%/1"
279 */
280 str = malloc(len + 3);
281 if (str == NULL)
282 return -ENOMEM;
283
284 memcpy(str, ostr, len);
285 strcpy(str + len, "/1");
286
287 ret = percent_slash_split(str, ptime_buf, start, end);
288 if (ret == 0)
289 ret = 1;
290
291 free(str);
292 return ret;
293}
294
260int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num, 295int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
261 const char *ostr, u64 start, u64 end) 296 const char *ostr, u64 start, u64 end)
262{ 297{
@@ -266,6 +301,7 @@ int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
266 * ostr example: 301 * ostr example:
267 * 10%/2,10%/3: select the second 10% slice and the third 10% slice 302 * 10%/2,10%/3: select the second 10% slice and the third 10% slice
268 * 0%-10%,30%-40%: multiple time range 303 * 0%-10%,30%-40%: multiple time range
304 * 50%: just one percent
269 */ 305 */
270 306
271 memset(ptime_buf, 0, sizeof(*ptime_buf) * num); 307 memset(ptime_buf, 0, sizeof(*ptime_buf) * num);
@@ -282,9 +318,41 @@ int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
282 end, percent_dash_split); 318 end, percent_dash_split);
283 } 319 }
284 320
321 c = strchr(ostr, '%');
322 if (c)
323 return one_percent_convert(ptime_buf, ostr, start, end, c);
324
285 return -1; 325 return -1;
286} 326}
287 327
328struct perf_time_interval *perf_time__range_alloc(const char *ostr, int *size)
329{
330 const char *p1, *p2;
331 int i = 1;
332 struct perf_time_interval *ptime;
333
334 /*
335 * At least allocate one time range.
336 */
337 if (!ostr)
338 goto alloc;
339
340 p1 = ostr;
341 while (p1 < ostr + strlen(ostr)) {
342 p2 = strchr(p1, ',');
343 if (!p2)
344 break;
345
346 p1 = p2 + 1;
347 i++;
348 }
349
350alloc:
351 *size = i;
352 ptime = calloc(i, sizeof(*ptime));
353 return ptime;
354}
355
288bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp) 356bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp)
289{ 357{
290 /* if time is not set don't drop sample */ 358 /* if time is not set don't drop sample */
diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h
index 34d5eba26bf5..70b177d2b98c 100644
--- a/tools/perf/util/time-utils.h
+++ b/tools/perf/util/time-utils.h
@@ -16,6 +16,8 @@ int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr);
16int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num, 16int perf_time__percent_parse_str(struct perf_time_interval *ptime_buf, int num,
17 const char *ostr, u64 start, u64 end); 17 const char *ostr, u64 start, u64 end);
18 18
19struct perf_time_interval *perf_time__range_alloc(const char *ostr, int *size);
20
19bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp); 21bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp);
20 22
21bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, 23bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf,
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 7a42f703e858..af873044d33a 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -631,9 +631,8 @@ static unw_accessors_t accessors = {
631 631
632static int _unwind__prepare_access(struct thread *thread) 632static int _unwind__prepare_access(struct thread *thread)
633{ 633{
634 if (callchain_param.record_mode != CALLCHAIN_DWARF) 634 if (!dwarf_callchain_users)
635 return 0; 635 return 0;
636
637 thread->addr_space = unw_create_addr_space(&accessors, 0); 636 thread->addr_space = unw_create_addr_space(&accessors, 0);
638 if (!thread->addr_space) { 637 if (!thread->addr_space) {
639 pr_err("unwind: Can't create unwind address space.\n"); 638 pr_err("unwind: Can't create unwind address space.\n");
@@ -646,17 +645,15 @@ static int _unwind__prepare_access(struct thread *thread)
646 645
647static void _unwind__flush_access(struct thread *thread) 646static void _unwind__flush_access(struct thread *thread)
648{ 647{
649 if (callchain_param.record_mode != CALLCHAIN_DWARF) 648 if (!dwarf_callchain_users)
650 return; 649 return;
651
652 unw_flush_cache(thread->addr_space, 0, 0); 650 unw_flush_cache(thread->addr_space, 0, 0);
653} 651}
654 652
655static void _unwind__finish_access(struct thread *thread) 653static void _unwind__finish_access(struct thread *thread)
656{ 654{
657 if (callchain_param.record_mode != CALLCHAIN_DWARF) 655 if (!dwarf_callchain_users)
658 return; 656 return;
659
660 unw_destroy_addr_space(thread->addr_space); 657 unw_destroy_addr_space(thread->addr_space);
661} 658}
662 659
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index a789f952b3e9..443892dabedb 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -210,7 +210,7 @@ static int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64
210 210
211 size -= ret; 211 size -= ret;
212 off_in += ret; 212 off_in += ret;
213 off_out -= ret; 213 off_out += ret;
214 } 214 }
215 munmap(ptr, off_in + size); 215 munmap(ptr, off_in + size);
216 216