summaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/Build1
-rw-r--r--tools/perf/util/evlist.c12
-rw-r--r--tools/perf/util/evsel.c41
-rw-r--r--tools/perf/util/evsel.h7
-rw-r--r--tools/perf/util/expr.h2
-rw-r--r--tools/perf/util/expr.y74
-rw-r--r--tools/perf/util/mem-events.c43
-rw-r--r--tools/perf/util/parse-events.l23
-rw-r--r--tools/perf/util/smt.c44
-rw-r--r--tools/perf/util/smt.h6
-rw-r--r--tools/perf/util/xyarray.c2
-rw-r--r--tools/perf/util/xyarray.h12
12 files changed, 214 insertions, 53 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 8d49a989f193..94518c1bf8b6 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -22,6 +22,7 @@ libperf-y += rbtree.o
libperf-y += libstring.o
libperf-y += bitmap.o
libperf-y += hweight.o
+libperf-y += smt.o
libperf-y += quote.o
libperf-y += strbuf.o
libperf-y += string.o
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 078b58511595..6a0d7ffbeba0 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1419,8 +1419,6 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e
{
struct perf_evsel *evsel;
int err = 0;
- const int ncpus = cpu_map__nr(evlist->cpus),
- nthreads = thread_map__nr(evlist->threads);
evlist__for_each_entry(evlist, evsel) {
if (evsel->filter == NULL)
@@ -1430,7 +1428,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e
* filters only work for tracepoint event, which doesn't have cpu limit.
* So evlist and evsel should always be same.
*/
- err = perf_evsel__apply_filter(evsel, ncpus, nthreads, evsel->filter);
+ err = perf_evsel__apply_filter(evsel, evsel->filter);
if (err) {
*err_evsel = evsel;
break;
@@ -1623,13 +1621,9 @@ void perf_evlist__set_selected(struct perf_evlist *evlist,
void perf_evlist__close(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
- int ncpus = cpu_map__nr(evlist->cpus);
- int nthreads = thread_map__nr(evlist->threads);
- evlist__for_each_entry_reverse(evlist, evsel) {
- int n = evsel->cpus ? evsel->cpus->nr : ncpus;
- perf_evsel__close(evsel, n, nthreads);
- }
+ evlist__for_each_entry_reverse(evlist, evsel)
+ perf_evsel__close(evsel);
}
static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 3735c9e0080d..a5888c704e01 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1051,16 +1051,13 @@ static int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthread
return evsel->fd != NULL ? 0 : -ENOMEM;
}
-static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthreads,
+static int perf_evsel__run_ioctl(struct perf_evsel *evsel,
int ioc, void *arg)
{
int cpu, thread;
- if (evsel->system_wide)
- nthreads = 1;
-
- for (cpu = 0; cpu < ncpus; cpu++) {
- for (thread = 0; thread < nthreads; thread++) {
+ for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) {
+ for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
int fd = FD(evsel, cpu, thread),
err = ioctl(fd, ioc, arg);
@@ -1072,10 +1069,9 @@ static int perf_evsel__run_ioctl(struct perf_evsel *evsel, int ncpus, int nthrea
return 0;
}
-int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
- const char *filter)
+int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
{
- return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+ return perf_evsel__run_ioctl(evsel,
PERF_EVENT_IOC_SET_FILTER,
(void *)filter);
}
@@ -1122,20 +1118,14 @@ int perf_evsel__append_addr_filter(struct perf_evsel *evsel, const char *filter)
int perf_evsel__enable(struct perf_evsel *evsel)
{
- int nthreads = thread_map__nr(evsel->threads);
- int ncpus = cpu_map__nr(evsel->cpus);
-
- return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+ return perf_evsel__run_ioctl(evsel,
PERF_EVENT_IOC_ENABLE,
0);
}
int perf_evsel__disable(struct perf_evsel *evsel)
{
- int nthreads = thread_map__nr(evsel->threads);
- int ncpus = cpu_map__nr(evsel->cpus);
-
- return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+ return perf_evsel__run_ioctl(evsel,
PERF_EVENT_IOC_DISABLE,
0);
}
@@ -1185,15 +1175,12 @@ static void perf_evsel__free_config_terms(struct perf_evsel *evsel)
}
}
-void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
+void perf_evsel__close_fd(struct perf_evsel *evsel)
{
int cpu, thread;
- if (evsel->system_wide)
- nthreads = 1;
-
- for (cpu = 0; cpu < ncpus; cpu++)
- for (thread = 0; thread < nthreads; ++thread) {
+ for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++)
+ for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
close(FD(evsel, cpu, thread));
FD(evsel, cpu, thread) = -1;
}
@@ -1854,12 +1841,12 @@ out_close:
return err;
}
-void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads)
+void perf_evsel__close(struct perf_evsel *evsel)
{
if (evsel->fd == NULL)
return;
- perf_evsel__close_fd(evsel, ncpus, nthreads);
+ perf_evsel__close_fd(evsel);
perf_evsel__free_fd(evsel);
}
@@ -2687,7 +2674,9 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
"unprivileged users (without CAP_SYS_ADMIN).\n\n"
"The current value is %d:\n\n"
" -1: Allow use of (almost) all events by all users\n"
- ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n"
+ " Ignore mlock limit after perf_event_mlock_kb without CAP_IPC_LOCK\n"
+ ">= 0: Disallow ftrace function tracepoint by users without CAP_SYS_ADMIN\n"
+ " Disallow raw tracepoint access by users without CAP_SYS_ADMIN\n"
">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n"
">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN\n\n"
"To make this setting permanent, edit /etc/sysctl.conf too, e.g.:\n\n"
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index de03c18daaf0..351d3b2d8887 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -226,7 +226,7 @@ const char *perf_evsel__group_name(struct perf_evsel *evsel);
int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size);
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
-void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
+void perf_evsel__close_fd(struct perf_evsel *evsel);
void __perf_evsel__set_sample_bit(struct perf_evsel *evsel,
enum perf_event_sample_format bit);
@@ -246,8 +246,7 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter);
int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter);
int perf_evsel__append_addr_filter(struct perf_evsel *evsel,
const char *filter);
-int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
- const char *filter);
+int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter);
int perf_evsel__enable(struct perf_evsel *evsel);
int perf_evsel__disable(struct perf_evsel *evsel);
@@ -257,7 +256,7 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel,
struct thread_map *threads);
int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
struct thread_map *threads);
-void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads);
+void perf_evsel__close(struct perf_evsel *evsel);
struct perf_sample;
diff --git a/tools/perf/util/expr.h b/tools/perf/util/expr.h
index 9c2760a1a96e..400ef9eab00a 100644
--- a/tools/perf/util/expr.h
+++ b/tools/perf/util/expr.h
@@ -1,7 +1,7 @@
#ifndef PARSE_CTX_H
#define PARSE_CTX_H 1
-#define EXPR_MAX_OTHER 8
+#define EXPR_MAX_OTHER 15
#define MAX_PARSE_ID EXPR_MAX_OTHER
struct parse_id {
diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y
index 953e65ba2cc7..432b8560cf51 100644
--- a/tools/perf/util/expr.y
+++ b/tools/perf/util/expr.y
@@ -4,6 +4,7 @@
#include "util/debug.h"
#define IN_EXPR_Y 1
#include "expr.h"
+#include "smt.h"
#include <string.h>
#define MAXIDLEN 256
@@ -22,13 +23,15 @@
%token <num> NUMBER
%token <id> ID
+%token MIN MAX IF ELSE SMT_ON
+%left MIN MAX IF
%left '|'
%left '^'
%left '&'
%left '-' '+'
%left '*' '/' '%'
%left NEG NOT
-%type <num> expr
+%type <num> expr if_expr
%{
static int expr__lex(YYSTYPE *res, const char **pp);
@@ -57,7 +60,12 @@ static int lookup_id(struct parse_ctx *ctx, char *id, double *val)
%}
%%
-all_expr: expr { *final_val = $1; }
+all_expr: if_expr { *final_val = $1; }
+ ;
+
+if_expr:
+ expr IF expr ELSE expr { $$ = $3 ? $1 : $5; }
+ | expr
;
expr: NUMBER
@@ -66,13 +74,19 @@ expr: NUMBER
YYABORT;
}
}
+ | expr '|' expr { $$ = (long)$1 | (long)$3; }
+ | expr '&' expr { $$ = (long)$1 & (long)$3; }
+ | expr '^' expr { $$ = (long)$1 ^ (long)$3; }
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { if ($3 == 0) YYABORT; $$ = $1 / $3; }
| expr '%' expr { if ((long)$3 == 0) YYABORT; $$ = (long)$1 % (long)$3; }
| '-' expr %prec NEG { $$ = -$2; }
- | '(' expr ')' { $$ = $2; }
+ | '(' if_expr ')' { $$ = $2; }
+ | MIN '(' expr ',' expr ')' { $$ = $3 < $5 ? $3 : $5; }
+ | MAX '(' expr ',' expr ')' { $$ = $3 > $5 ? $3 : $5; }
+ | SMT_ON { $$ = smt_on() > 0; }
;
%%
@@ -82,13 +96,47 @@ static int expr__symbol(YYSTYPE *res, const char *p, const char **pp)
char *dst = res->id;
const char *s = p;
- while (isalnum(*p) || *p == '_' || *p == '.') {
+ if (*p == '#')
+ *dst++ = *p++;
+
+ while (isalnum(*p) || *p == '_' || *p == '.' || *p == ':' || *p == '@' || *p == '\\') {
if (p - s >= MAXIDLEN)
return -1;
- *dst++ = *p++;
+ /*
+ * Allow @ instead of / to be able to specify pmu/event/ without
+ * conflicts with normal division.
+ */
+ if (*p == '@')
+ *dst++ = '/';
+ else if (*p == '\\')
+ *dst++ = *++p;
+ else
+ *dst++ = *p;
+ p++;
}
*dst = 0;
*pp = p;
+ dst = res->id;
+ switch (dst[0]) {
+ case 'm':
+ if (!strcmp(dst, "min"))
+ return MIN;
+ if (!strcmp(dst, "max"))
+ return MAX;
+ break;
+ case 'i':
+ if (!strcmp(dst, "if"))
+ return IF;
+ break;
+ case 'e':
+ if (!strcmp(dst, "else"))
+ return ELSE;
+ break;
+ case '#':
+ if (!strcasecmp(dst, "#smt_on"))
+ return SMT_ON;
+ break;
+ }
return ID;
}
@@ -102,6 +150,7 @@ static int expr__lex(YYSTYPE *res, const char **pp)
p++;
s = p;
switch (*p++) {
+ case '#':
case 'a' ... 'z':
case 'A' ... 'Z':
return expr__symbol(res, p - 1, pp);
@@ -132,6 +181,19 @@ void expr__ctx_init(struct parse_ctx *ctx)
ctx->num_ids = 0;
}
+static bool already_seen(const char *val, const char *one, const char **other,
+ int num_other)
+{
+ int i;
+
+ if (one && !strcasecmp(one, val))
+ return true;
+ for (i = 0; i < num_other; i++)
+ if (!strcasecmp(other[i], val))
+ return true;
+ return false;
+}
+
int expr__find_other(const char *p, const char *one, const char ***other,
int *num_otherp)
{
@@ -151,7 +213,7 @@ int expr__find_other(const char *p, const char *one, const char ***other,
err = 0;
break;
}
- if (tok == ID && strcasecmp(one, val.id)) {
+ if (tok == ID && !already_seen(val.id, one, *other, num_other)) {
if (num_other >= EXPR_MAX_OTHER - 1) {
pr_debug("Too many extra events in %s\n", orig);
break;
diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c
index 06f5a3a4295c..ced4f3fff035 100644
--- a/tools/perf/util/mem-events.c
+++ b/tools/perf/util/mem-events.c
@@ -166,11 +166,20 @@ static const char * const mem_lvl[] = {
"Uncached",
};
+static const char * const mem_lvlnum[] = {
+ [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
+ [PERF_MEM_LVLNUM_LFB] = "LFB",
+ [PERF_MEM_LVLNUM_RAM] = "RAM",
+ [PERF_MEM_LVLNUM_PMEM] = "PMEM",
+ [PERF_MEM_LVLNUM_NA] = "N/A",
+};
+
int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
{
size_t i, l = 0;
u64 m = PERF_MEM_LVL_NA;
u64 hit, miss;
+ int printed;
if (mem_info)
m = mem_info->data_src.mem_lvl;
@@ -184,17 +193,37 @@ int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
/* already taken care of */
m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
+
+ if (mem_info && mem_info->data_src.mem_remote) {
+ strcat(out, "Remote ");
+ l += 7;
+ }
+
+ printed = 0;
for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
if (!(m & 0x1))
continue;
- if (l) {
+ if (printed++) {
strcat(out, " or ");
l += 4;
}
l += scnprintf(out + l, sz - l, mem_lvl[i]);
}
- if (*out == '\0')
- l += scnprintf(out, sz - l, "N/A");
+
+ if (mem_info && mem_info->data_src.mem_lvl_num) {
+ int lvl = mem_info->data_src.mem_lvl_num;
+ if (printed++) {
+ strcat(out, " or ");
+ l += 4;
+ }
+ if (mem_lvlnum[lvl])
+ l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
+ else
+ l += scnprintf(out + l, sz - l, "L%d", lvl);
+ }
+
+ if (l == 0)
+ l += scnprintf(out + l, sz - l, "N/A");
if (hit)
l += scnprintf(out + l, sz - l, " hit");
if (miss)
@@ -231,6 +260,14 @@ int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
}
l += scnprintf(out + l, sz - l, snoop_access[i]);
}
+ if (mem_info &&
+ (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
+ if (l) {
+ strcat(out, " or ");
+ l += 4;
+ }
+ l += scnprintf(out + l, sz - l, "Fwd");
+ }
if (*out == '\0')
l += scnprintf(out, sz - l, "N/A");
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 660fca05bc93..c42edeac451f 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -53,6 +53,21 @@ static int str(yyscan_t scanner, int token)
return token;
}
+static bool isbpf(yyscan_t scanner)
+{
+ char *text = parse_events_get_text(scanner);
+ int len = strlen(text);
+
+ if (len < 2)
+ return false;
+ if ((text[len - 1] == 'c' || text[len - 1] == 'o') &&
+ text[len - 2] == '.')
+ return true;
+ if (len > 4 && !strcmp(text + len - 4, ".obj"))
+ return true;
+ return false;
+}
+
/*
* This function is called when the parser gets two kind of input:
*
@@ -136,8 +151,8 @@ do { \
group [^,{}/]*[{][^}]*[}][^,{}/]*
event_pmu [^,{}/]+[/][^/]*[/][^,{}/]*
event [^,{}/]+
-bpf_object [^,{}]+\.(o|bpf)
-bpf_source [^,{}]+\.c
+bpf_object [^,{}]+\.(o|bpf)[a-zA-Z0-9._]*
+bpf_source [^,{}]+\.c[a-zA-Z0-9._]*
num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+
@@ -307,8 +322,8 @@ r{num_raw_hex} { return raw(yyscanner); }
{num_hex} { return value(yyscanner, 16); }
{modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); }
-{bpf_object} { return str(yyscanner, PE_BPF_OBJECT); }
-{bpf_source} { return str(yyscanner, PE_BPF_SOURCE); }
+{bpf_object} { if (!isbpf(yyscanner)) REJECT; return str(yyscanner, PE_BPF_OBJECT); }
+{bpf_source} { if (!isbpf(yyscanner)) REJECT; return str(yyscanner, PE_BPF_SOURCE); }
{name} { return pmu_str_check(yyscanner); }
"/" { BEGIN(config); return '/'; }
- { return '-'; }
diff --git a/tools/perf/util/smt.c b/tools/perf/util/smt.c
new file mode 100644
index 000000000000..453f6f6f29f3
--- /dev/null
+++ b/tools/perf/util/smt.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/bitops.h>
+#include "api/fs/fs.h"
+#include "smt.h"
+
+int smt_on(void)
+{
+ static bool cached;
+ static int cached_result;
+ int cpu;
+ int ncpu;
+
+ if (cached)
+ return cached_result;
+
+ ncpu = sysconf(_SC_NPROCESSORS_CONF);
+ for (cpu = 0; cpu < ncpu; cpu++) {
+ unsigned long long siblings;
+ char *str;
+ size_t strlen;
+ char fn[256];
+
+ snprintf(fn, sizeof fn,
+ "devices/system/cpu/cpu%d/topology/thread_siblings",
+ cpu);
+ if (sysfs__read_str(fn, &str, &strlen) < 0)
+ continue;
+ /* Entry is hex, but does not have 0x, so need custom parser */
+ siblings = strtoull(str, NULL, 16);
+ free(str);
+ if (hweight64(siblings) > 1) {
+ cached_result = 1;
+ cached = true;
+ break;
+ }
+ }
+ if (!cached) {
+ cached_result = 0;
+ cached = true;
+ }
+ return cached_result;
+}
diff --git a/tools/perf/util/smt.h b/tools/perf/util/smt.h
new file mode 100644
index 000000000000..b8414b7bcbc8
--- /dev/null
+++ b/tools/perf/util/smt.h
@@ -0,0 +1,6 @@
+#ifndef SMT_H
+#define SMT_H 1
+
+int smt_on(void);
+
+#endif
diff --git a/tools/perf/util/xyarray.c b/tools/perf/util/xyarray.c
index 7251fdbabced..c8f415d9877b 100644
--- a/tools/perf/util/xyarray.c
+++ b/tools/perf/util/xyarray.c
@@ -12,6 +12,8 @@ struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size)
xy->entry_size = entry_size;
xy->row_size = row_size;
xy->entries = xlen * ylen;
+ xy->max_x = xlen;
+ xy->max_y = ylen;
}
return xy;
diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h
index 7f30af371b7e..4ba726c90870 100644
--- a/tools/perf/util/xyarray.h
+++ b/tools/perf/util/xyarray.h
@@ -7,6 +7,8 @@ struct xyarray {
size_t row_size;
size_t entry_size;
size_t entries;
+ size_t max_x;
+ size_t max_y;
char contents[];
};
@@ -19,4 +21,14 @@ static inline void *xyarray__entry(struct xyarray *xy, int x, int y)
return &xy->contents[x * xy->row_size + y * xy->entry_size];
}
+static inline int xyarray__max_y(struct xyarray *xy)
+{
+ return xy->max_x;
+}
+
+static inline int xyarray__max_x(struct xyarray *xy)
+{
+ return xy->max_y;
+}
+
#endif /* _PERF_XYARRAY_H_ */