Commit 387ef4e2 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

perf/core improvements and fixes:

 - Preparatory patches to use hw events in PMU syntax, from Jiri Olsa

 - Remaining backport of trace-cmd's libparseevent, from Namhyung Kim

 - Fix libtraceevent 'clean' make target, from Namhyung Kim

 - Teach ctags about libtraceevent error codes, from Namhyung Kim

 - Fix libtraceevent dependency files usage, from Namhyung Kim

 - Support hex number pretty printing in libtraceevent, fixing
   kvm output, from Namhyung Kim

 - Kill some die() usage in libtraceevent, from Namhyung Kim

 - Improve support for hw breakpoints parsing/pretty printing/testing,
  from Jiri Olsa

 - Clarify perf bench option naming, from Hitoshi Mitake

 - Look for ".note" ELF notes too, used in the kernel vdso, from Jiri Olsa

 - Fix internal PMU list usage, removing leak, from Robert Richter
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 6a67943a 81e9b994
...@@ -250,8 +250,12 @@ endef ...@@ -250,8 +250,12 @@ endef
all_objs := $(sort $(ALL_OBJS)) all_objs := $(sort $(ALL_OBJS))
all_deps := $(all_objs:%.o=.%.d) all_deps := $(all_objs:%.o=.%.d)
# let .d file also depends on the source and header files
define check_deps define check_deps
$(CC) -M $(CFLAGS) $< > $@; @set -e; $(RM) $@; \
$(CC) -M $(CFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
$(RM) $@.$$$$
endef endef
$(gui_deps): ks_version.h $(gui_deps): ks_version.h
...@@ -270,11 +274,13 @@ endif ...@@ -270,11 +274,13 @@ endif
tags: force tags: force
$(RM) tags $(RM) tags
find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \
--regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/'
TAGS: force TAGS: force
$(RM) TAGS $(RM) TAGS
find . -name '*.[ch]' | xargs etags find . -name '*.[ch]' | xargs etags \
--regex='/_PE(\([^,)]*\).*/PEVENT_ERRNO__\1/'
define do_install define do_install
$(print_install) \ $(print_install) \
...@@ -290,7 +296,7 @@ install_lib: all_cmd install_plugins install_python ...@@ -290,7 +296,7 @@ install_lib: all_cmd install_plugins install_python
install: install_lib install: install_lib
clean: clean:
$(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES).*.d $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d
$(RM) tags TAGS $(RM) tags TAGS
endif # skip-makefile endif # skip-makefile
......
This diff is collapsed.
...@@ -226,6 +226,11 @@ struct print_arg_symbol { ...@@ -226,6 +226,11 @@ struct print_arg_symbol {
struct print_flag_sym *symbols; struct print_flag_sym *symbols;
}; };
struct print_arg_hex {
struct print_arg *field;
struct print_arg *size;
};
struct print_arg_dynarray { struct print_arg_dynarray {
struct format_field *field; struct format_field *field;
struct print_arg *index; struct print_arg *index;
...@@ -253,6 +258,7 @@ enum print_arg_type { ...@@ -253,6 +258,7 @@ enum print_arg_type {
PRINT_FIELD, PRINT_FIELD,
PRINT_FLAGS, PRINT_FLAGS,
PRINT_SYMBOL, PRINT_SYMBOL,
PRINT_HEX,
PRINT_TYPE, PRINT_TYPE,
PRINT_STRING, PRINT_STRING,
PRINT_BSTRING, PRINT_BSTRING,
...@@ -270,6 +276,7 @@ struct print_arg { ...@@ -270,6 +276,7 @@ struct print_arg {
struct print_arg_typecast typecast; struct print_arg_typecast typecast;
struct print_arg_flags flags; struct print_arg_flags flags;
struct print_arg_symbol symbol; struct print_arg_symbol symbol;
struct print_arg_hex hex;
struct print_arg_func func; struct print_arg_func func;
struct print_arg_string string; struct print_arg_string string;
struct print_arg_op op; struct print_arg_op op;
......
...@@ -96,7 +96,7 @@ static enum event_type read_token(char **tok) ...@@ -96,7 +96,7 @@ static enum event_type read_token(char **tok)
(strcmp(token, "=") == 0 || strcmp(token, "!") == 0) && (strcmp(token, "=") == 0 || strcmp(token, "!") == 0) &&
pevent_peek_char() == '~') { pevent_peek_char() == '~') {
/* append it */ /* append it */
*tok = malloc(3); *tok = malloc_or_die(3);
sprintf(*tok, "%c%c", *token, '~'); sprintf(*tok, "%c%c", *token, '~');
free_token(token); free_token(token);
/* Now remove the '~' from the buffer */ /* Now remove the '~' from the buffer */
...@@ -148,17 +148,11 @@ add_filter_type(struct event_filter *filter, int id) ...@@ -148,17 +148,11 @@ add_filter_type(struct event_filter *filter, int id)
if (filter_type) if (filter_type)
return filter_type; return filter_type;
if (!filter->filters) filter->event_filters = realloc(filter->event_filters,
filter->event_filters = sizeof(*filter->event_filters) *
malloc_or_die(sizeof(*filter->event_filters)); (filter->filters + 1));
else { if (!filter->event_filters)
filter->event_filters = die("Could not allocate filter");
realloc(filter->event_filters,
sizeof(*filter->event_filters) *
(filter->filters + 1));
if (!filter->event_filters)
die("Could not allocate filter");
}
for (i = 0; i < filter->filters; i++) { for (i = 0; i < filter->filters; i++) {
if (filter->event_filters[i].event_id > id) if (filter->event_filters[i].event_id > id)
...@@ -1480,7 +1474,7 @@ void pevent_filter_clear_trivial(struct event_filter *filter, ...@@ -1480,7 +1474,7 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
{ {
struct filter_type *filter_type; struct filter_type *filter_type;
int count = 0; int count = 0;
int *ids; int *ids = NULL;
int i; int i;
if (!filter->filters) if (!filter->filters)
...@@ -1504,10 +1498,8 @@ void pevent_filter_clear_trivial(struct event_filter *filter, ...@@ -1504,10 +1498,8 @@ void pevent_filter_clear_trivial(struct event_filter *filter,
default: default:
break; break;
} }
if (count)
ids = realloc(ids, sizeof(*ids) * (count + 1)); ids = realloc(ids, sizeof(*ids) * (count + 1));
else
ids = malloc(sizeof(*ids));
if (!ids) if (!ids)
die("Can't allocate ids"); die("Can't allocate ids");
ids[count++] = filter_type->event_id; ids[count++] = filter_type->event_id;
...@@ -1710,18 +1702,43 @@ static int test_num(struct event_format *event, ...@@ -1710,18 +1702,43 @@ static int test_num(struct event_format *event,
static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record) static const char *get_field_str(struct filter_arg *arg, struct pevent_record *record)
{ {
const char *val = record->data + arg->str.field->offset; struct event_format *event;
struct pevent *pevent;
unsigned long long addr;
const char *val = NULL;
char hex[64];
/* /* If the field is not a string convert it */
* We need to copy the data since we can't be sure the field if (arg->str.field->flags & FIELD_IS_STRING) {
* is null terminated. val = record->data + arg->str.field->offset;
*/
if (*(val + arg->str.field->size - 1)) { /*
/* copy it */ * We need to copy the data since we can't be sure the field
memcpy(arg->str.buffer, val, arg->str.field->size); * is null terminated.
/* the buffer is already NULL terminated */ */
val = arg->str.buffer; if (*(val + arg->str.field->size - 1)) {
/* copy it */
memcpy(arg->str.buffer, val, arg->str.field->size);
/* the buffer is already NULL terminated */
val = arg->str.buffer;
}
} else {
event = arg->str.field->event;
pevent = event->pevent;
addr = get_value(event, arg->str.field, record);
if (arg->str.field->flags & (FIELD_IS_POINTER | FIELD_IS_LONG))
/* convert to a kernel symbol */
val = pevent_find_function(pevent, addr);
if (val == NULL) {
/* just use the hex of the string name */
snprintf(hex, 64, "0x%llx", addr);
val = hex;
}
} }
return val; return val;
} }
...@@ -2001,11 +2018,13 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) ...@@ -2001,11 +2018,13 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
char *lstr; char *lstr;
char *rstr; char *rstr;
char *op; char *op;
char *str; char *str = NULL;
int len; int len;
lstr = arg_to_str(filter, arg->exp.left); lstr = arg_to_str(filter, arg->exp.left);
rstr = arg_to_str(filter, arg->exp.right); rstr = arg_to_str(filter, arg->exp.right);
if (!lstr || !rstr)
goto out;
switch (arg->exp.type) { switch (arg->exp.type) {
case FILTER_EXP_ADD: case FILTER_EXP_ADD:
...@@ -2045,6 +2064,7 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg) ...@@ -2045,6 +2064,7 @@ static char *exp_to_str(struct event_filter *filter, struct filter_arg *arg)
len = strlen(op) + strlen(lstr) + strlen(rstr) + 4; len = strlen(op) + strlen(lstr) + strlen(rstr) + 4;
str = malloc_or_die(len); str = malloc_or_die(len);
snprintf(str, len, "%s %s %s", lstr, op, rstr); snprintf(str, len, "%s %s %s", lstr, op, rstr);
out:
free(lstr); free(lstr);
free(rstr); free(rstr);
...@@ -2061,6 +2081,8 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) ...@@ -2061,6 +2081,8 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
lstr = arg_to_str(filter, arg->num.left); lstr = arg_to_str(filter, arg->num.left);
rstr = arg_to_str(filter, arg->num.right); rstr = arg_to_str(filter, arg->num.right);
if (!lstr || !rstr)
goto out;
switch (arg->num.type) { switch (arg->num.type) {
case FILTER_CMP_EQ: case FILTER_CMP_EQ:
...@@ -2097,6 +2119,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg) ...@@ -2097,6 +2119,7 @@ static char *num_to_str(struct event_filter *filter, struct filter_arg *arg)
break; break;
} }
out:
free(lstr); free(lstr);
free(rstr); free(rstr);
return str; return str;
...@@ -2247,7 +2270,12 @@ int pevent_filter_compare(struct event_filter *filter1, struct event_filter *fil ...@@ -2247,7 +2270,12 @@ int pevent_filter_compare(struct event_filter *filter1, struct event_filter *fil
/* The best way to compare complex filters is with strings */ /* The best way to compare complex filters is with strings */
str1 = arg_to_str(filter1, filter_type1->filter); str1 = arg_to_str(filter1, filter_type1->filter);
str2 = arg_to_str(filter2, filter_type2->filter); str2 = arg_to_str(filter2, filter_type2->filter);
result = strcmp(str1, str2) != 0; if (str1 && str2)
result = strcmp(str1, str2) != 0;
else
/* bail out if allocation fails */
result = 1;
free(str1); free(str1);
free(str2); free(str2);
if (result) if (result)
......
...@@ -144,7 +144,7 @@ On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported. ...@@ -144,7 +144,7 @@ On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported.
Repeat memcpy invocation this number of times. Repeat memcpy invocation this number of times.
-c:: -c::
--clock:: --cycle::
Use perf's cpu-cycles event instead of gettimeofday syscall. Use perf's cpu-cycles event instead of gettimeofday syscall.
-o:: -o::
...@@ -176,7 +176,7 @@ On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported. ...@@ -176,7 +176,7 @@ On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported.
Repeat memset invocation this number of times. Repeat memset invocation this number of times.
-c:: -c::
--clock:: --cycle::
Use perf's cpu-cycles event instead of gettimeofday syscall. Use perf's cpu-cycles event instead of gettimeofday syscall.
-o:: -o::
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
static const char *length_str = "1MB"; static const char *length_str = "1MB";
static const char *routine = "default"; static const char *routine = "default";
static int iterations = 1; static int iterations = 1;
static bool use_clock; static bool use_cycle;
static int clock_fd; static int cycle_fd;
static bool only_prefault; static bool only_prefault;
static bool no_prefault; static bool no_prefault;
...@@ -37,7 +37,7 @@ static const struct option options[] = { ...@@ -37,7 +37,7 @@ static const struct option options[] = {
"Specify routine to copy"), "Specify routine to copy"),
OPT_INTEGER('i', "iterations", &iterations, OPT_INTEGER('i', "iterations", &iterations,
"repeat memcpy() invocation this number of times"), "repeat memcpy() invocation this number of times"),
OPT_BOOLEAN('c', "clock", &use_clock, OPT_BOOLEAN('c', "cycle", &use_cycle,
"Use cycles event instead of gettimeofday() for measuring"), "Use cycles event instead of gettimeofday() for measuring"),
OPT_BOOLEAN('o', "only-prefault", &only_prefault, OPT_BOOLEAN('o', "only-prefault", &only_prefault,
"Show only the result with page faults before memcpy()"), "Show only the result with page faults before memcpy()"),
...@@ -76,27 +76,27 @@ static const char * const bench_mem_memcpy_usage[] = { ...@@ -76,27 +76,27 @@ static const char * const bench_mem_memcpy_usage[] = {
NULL NULL
}; };
static struct perf_event_attr clock_attr = { static struct perf_event_attr cycle_attr = {
.type = PERF_TYPE_HARDWARE, .type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES .config = PERF_COUNT_HW_CPU_CYCLES
}; };
static void init_clock(void) static void init_cycle(void)
{ {
clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
if (clock_fd < 0 && errno == ENOSYS) if (cycle_fd < 0 && errno == ENOSYS)
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
else else
BUG_ON(clock_fd < 0); BUG_ON(cycle_fd < 0);
} }
static u64 get_clock(void) static u64 get_cycle(void)
{ {
int ret; int ret;
u64 clk; u64 clk;
ret = read(clock_fd, &clk, sizeof(u64)); ret = read(cycle_fd, &clk, sizeof(u64));
BUG_ON(ret != sizeof(u64)); BUG_ON(ret != sizeof(u64));
return clk; return clk;
...@@ -119,9 +119,9 @@ static void alloc_mem(void **dst, void **src, size_t length) ...@@ -119,9 +119,9 @@ static void alloc_mem(void **dst, void **src, size_t length)
die("memory allocation failed - maybe length is too large?\n"); die("memory allocation failed - maybe length is too large?\n");
} }
static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault) static u64 do_memcpy_cycle(memcpy_t fn, size_t len, bool prefault)
{ {
u64 clock_start = 0ULL, clock_end = 0ULL; u64 cycle_start = 0ULL, cycle_end = 0ULL;
void *src = NULL, *dst = NULL; void *src = NULL, *dst = NULL;
int i; int i;
...@@ -130,14 +130,14 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault) ...@@ -130,14 +130,14 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
if (prefault) if (prefault)
fn(dst, src, len); fn(dst, src, len);
clock_start = get_clock(); cycle_start = get_cycle();
for (i = 0; i < iterations; ++i) for (i = 0; i < iterations; ++i)
fn(dst, src, len); fn(dst, src, len);
clock_end = get_clock(); cycle_end = get_cycle();
free(src); free(src);
free(dst); free(dst);
return clock_end - clock_start; return cycle_end - cycle_start;
} }
static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault) static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
...@@ -182,17 +182,17 @@ int bench_mem_memcpy(int argc, const char **argv, ...@@ -182,17 +182,17 @@ int bench_mem_memcpy(int argc, const char **argv,
int i; int i;
size_t len; size_t len;
double result_bps[2]; double result_bps[2];
u64 result_clock[2]; u64 result_cycle[2];
argc = parse_options(argc, argv, options, argc = parse_options(argc, argv, options,
bench_mem_memcpy_usage, 0); bench_mem_memcpy_usage, 0);
if (use_clock) if (use_cycle)
init_clock(); init_cycle();
len = (size_t)perf_atoll((char *)length_str); len = (size_t)perf_atoll((char *)length_str);
result_clock[0] = result_clock[1] = 0ULL; result_cycle[0] = result_cycle[1] = 0ULL;
result_bps[0] = result_bps[1] = 0.0; result_bps[0] = result_bps[1] = 0.0;
if ((s64)len <= 0) { if ((s64)len <= 0) {
...@@ -223,11 +223,11 @@ int bench_mem_memcpy(int argc, const char **argv, ...@@ -223,11 +223,11 @@ int bench_mem_memcpy(int argc, const char **argv,
if (!only_prefault && !no_prefault) { if (!only_prefault && !no_prefault) {
/* show both of results */ /* show both of results */
if (use_clock) { if (use_cycle) {
result_clock[0] = result_cycle[0] =
do_memcpy_clock(routines[i].fn, len, false); do_memcpy_cycle(routines[i].fn, len, false);
result_clock[1] = result_cycle[1] =
do_memcpy_clock(routines[i].fn, len, true); do_memcpy_cycle(routines[i].fn, len, true);
} else { } else {
result_bps[0] = result_bps[0] =
do_memcpy_gettimeofday(routines[i].fn, do_memcpy_gettimeofday(routines[i].fn,
...@@ -237,9 +237,9 @@ int bench_mem_memcpy(int argc, const char **argv, ...@@ -237,9 +237,9 @@ int bench_mem_memcpy(int argc, const char **argv,
len, true); len, true);
} }
} else { } else {
if (use_clock) { if (use_cycle) {
result_clock[pf] = result_cycle[pf] =
do_memcpy_clock(routines[i].fn, do_memcpy_cycle(routines[i].fn,
len, only_prefault); len, only_prefault);
} else { } else {
result_bps[pf] = result_bps[pf] =
...@@ -251,12 +251,12 @@ int bench_mem_memcpy(int argc, const char **argv, ...@@ -251,12 +251,12 @@ int bench_mem_memcpy(int argc, const char **argv,
switch (bench_format) { switch (bench_format) {
case BENCH_FORMAT_DEFAULT: case BENCH_FORMAT_DEFAULT:
if (!only_prefault && !no_prefault) { if (!only_prefault && !no_prefault) {
if (use_clock) { if (use_cycle) {
printf(" %14lf Clock/Byte\n", printf(" %14lf Cycle/Byte\n",
(double)result_clock[0] (double)result_cycle[0]
/ (double)len); / (double)len);
printf(" %14lf Clock/Byte (with prefault)\n", printf(" %14lf Cycle/Byte (with prefault)\n",
(double)result_clock[1] (double)result_cycle[1]
/ (double)len); / (double)len);
} else { } else {
print_bps(result_bps[0]); print_bps(result_bps[0]);
...@@ -265,9 +265,9 @@ int bench_mem_memcpy(int argc, const char **argv, ...@@ -265,9 +265,9 @@ int bench_mem_memcpy(int argc, const char **argv,
printf(" (with prefault)\n"); printf(" (with prefault)\n");
} }
} else { } else {
if (use_clock) { if (use_cycle) {
printf(" %14lf Clock/Byte", printf(" %14lf Cycle/Byte",
(double)result_clock[pf] (double)result_cycle[pf]
/ (double)len); / (double)len);
} else } else
print_bps(result_bps[pf]); print_bps(result_bps[pf]);
...@@ -277,17 +277,17 @@ int bench_mem_memcpy(int argc, const char **argv, ...@@ -277,17 +277,17 @@ int bench_mem_memcpy(int argc, const char **argv,
break; break;
case BENCH_FORMAT_SIMPLE: case BENCH_FORMAT_SIMPLE:
if (!only_prefault && !no_prefault) { if (!only_prefault && !no_prefault) {
if (use_clock) { if (use_cycle) {
printf("%lf %lf\n", printf("%lf %lf\n",
(double)result_clock[0] / (double)len, (double)result_cycle[0] / (double)len,
(double)result_clock[1] / (double)len); (double)result_cycle[1] / (double)len);
} else { } else {
printf("%lf %lf\n", printf("%lf %lf\n",
result_bps[0], result_bps[1]); result_bps[0], result_bps[1]);
} }
} else { } else {
if (use_clock) { if (use_cycle) {
printf("%lf\n", (double)result_clock[pf] printf("%lf\n", (double)result_cycle[pf]
/ (double)len); / (double)len);
} else } else
printf("%lf\n", result_bps[pf]); printf("%lf\n", result_bps[pf]);
......
...@@ -24,8 +24,8 @@ ...@@ -24,8 +24,8 @@
static const char *length_str = "1MB"; static const char *length_str = "1MB";
static const char *routine = "default"; static const char *routine = "default";
static int iterations = 1; static int iterations = 1;
static bool use_clock; static bool use_cycle;
static int clock_fd; static int cycle_fd;
static bool only_prefault; static bool only_prefault;
static bool no_prefault; static bool no_prefault;
...@@ -37,7 +37,7 @@ static const struct option options[] = { ...@@ -37,7 +37,7 @@ static const struct option options[] = {
"Specify routine to set"), "Specify routine to set"),
OPT_INTEGER('i', "iterations", &iterations, OPT_INTEGER('i', "iterations", &iterations,
"repeat memset() invocation this number of times"), "repeat memset() invocation this number of times"),
OPT_BOOLEAN('c', "clock", &use_clock, OPT_BOOLEAN('c', "cycle", &use_cycle,
"Use cycles event instead of gettimeofday() for measuring"), "Use cycles event instead of gettimeofday() for measuring"),
OPT_BOOLEAN('o', "only-prefault", &only_prefault, OPT_BOOLEAN('o', "only-prefault", &only_prefault,
"Show only the result with page faults before memset()"), "Show only the result with page faults before memset()"),
...@@ -76,27 +76,27 @@ static const char * const bench_mem_memset_usage[] = { ...@@ -76,27 +76,27 @@ static const char * const bench_mem_memset_usage[] = {
NULL NULL
}; };
static struct perf_event_attr clock_attr = { static struct perf_event_attr cycle_attr = {
.type = PERF_TYPE_HARDWARE, .type = PERF_TYPE_HARDWARE,
.config = PERF_COUNT_HW_CPU_CYCLES .config = PERF_COUNT_HW_CPU_CYCLES
}; };
static void init_clock(void) static void init_cycle(void)
{ {
clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0); cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, 0);
if (clock_fd < 0 && errno == ENOSYS) if (cycle_fd < 0 && errno == ENOSYS)
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
else else
BUG_ON(clock_fd < 0); BUG_ON(cycle_fd < 0);
} }
static u64 get_clock(void) static u64 get_cycle(void)
{ {
int ret; int ret;
u64 clk; u64 clk;
ret = read(clock_fd, &clk, sizeof(u64)); ret = read(cycle_fd, &clk, sizeof(u64));
BUG_ON(ret != sizeof(u64)); BUG_ON(ret != sizeof(u64));
return clk; return clk;
...@@ -115,9 +115,9 @@ static void alloc_mem(void **dst, size_t length) ...@@ -115,9 +115,9 @@ static void alloc_mem(void **dst, size_t length)
die("memory allocation failed - maybe length is too large?\n"); die("memory allocation failed - maybe length is too large?\n");
} }
static u64 do_memset_clock(memset_t fn, size_t len, bool prefault) static u64 do_memset_cycle(memset_t fn, size_t len, bool prefault)
{ {
u64 clock_start = 0ULL, clock_end = 0ULL; u64 cycle_start = 0ULL, cycle_end = 0ULL;
void *dst = NULL; void *dst = NULL;
int i; int i;
...@@ -126,13 +126,13 @@ static u64 do_memset_clock(memset_t fn, size_t len, bool prefault) ...@@ -126,13 +126,13 @@ static u64 do_memset_clock(memset_t fn, size_t len, bool prefault)
if (prefault) if (prefault)
fn(dst, -1, len); fn(dst, -1, len);
clock_start = get_clock(); cycle_start = get_cycle();
for (i = 0; i < iterations; ++i) for (i = 0; i < iterations; ++i)
fn(dst, i, len); fn(dst, i, len);
clock_end = get_clock(); cycle_end = get_cycle();
free(dst); free(dst);
return clock_end - clock_start; return cycle_end - cycle_start;
} }
static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault) static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
...@@ -176,17 +176,17 @@ int bench_mem_memset(int argc, const char **argv, ...@@ -176,17 +176,17 @@ int bench_mem_memset(int argc, const char **argv,
int i; int i;
size_t len; size_t len;
double result_bps[2]; double result_bps[2];
u64 result_clock[2]; u64 result_cycle[2];
argc = parse_options(argc, argv, options, argc = parse_options(argc, argv, options,
bench_mem_memset_usage, 0); bench_mem_memset_usage, 0);
if (use_clock) if (use_cycle)
init_clock(); init_cycle();
len = (size_t)perf_atoll((char *)length_str); len = (size_t)perf_atoll((char *)length_str);
result_clock[0] = result_clock[1] = 0ULL; result_cycle[0] = result_cycle[1] = 0ULL;
result_bps[0] = result_bps[1] = 0.0; result_bps[0] = result_bps[1] = 0.0;
if ((s64)len <= 0) { if ((s64)len <= 0) {
...@@ -217,11 +217,11 @@ int bench_mem_memset(int argc, const char **argv, ...@@ -217,11 +217,11 @@ int bench_mem_memset(int argc, const char **argv,
if (!only_prefault && !no_prefault) { if (!only_prefault && !no_prefault) {
/* show both of results */ /* show both of results */
if (use_clock) { if (use_cycle) {
result_clock[0] = result_cycle[0] =
do_memset_clock(routines[i].fn, len, false); do_memset_cycle(routines[i].fn, len, false);
result_clock[1] = result_cycle[1] =
do_memset_clock(routines[i].fn, len, true); do_memset_cycle(routines[i].fn, len, true);
} else { } else {
result_bps[0] = result_bps[0] =
do_memset_gettimeofday(routines[i].fn, do_memset_gettimeofday(routines[i].fn,
...@@ -231,9 +231,9 @@ int bench_mem_memset(int argc, const char **argv, ...@@ -231,9 +231,9 @@ int bench_mem_memset(int argc, const char **argv,
len, true); len, true);
} }
} else { } else {
if (use_clock) { if (use_cycle) {
result_clock[pf] = result_cycle[pf] =
do_memset_clock(routines[i].fn, do_memset_cycle(routines[i].fn,
len, only_prefault); len, only_prefault);
} else { } else {
result_bps[pf] = result_bps[pf] =
...@@ -245,12 +245,12 @@ int bench_mem_memset(int argc, const char **argv, ...@@ -245,12 +245,12 @@ int bench_mem_memset(int argc, const char **argv,
switch (bench_format) { switch (bench_format) {
case BENCH_FORMAT_DEFAULT: case BENCH_FORMAT_DEFAULT:
if (!only_prefault && !no_prefault) { if (!only_prefault && !no_prefault) {
if (use_clock) { if (use_cycle) {
printf(" %14lf Clock/Byte\n", printf(" %14lf Cycle/Byte\n",
(double)result_clock[0] (double)result_cycle[0]
/ (double)len); / (double)len);
printf(" %14lf Clock/Byte (with prefault)\n ", printf(" %14lf Cycle/Byte (with prefault)\n ",
(double)result_clock[1] (double)result_cycle[1]
/ (double)len); / (double)len);
} else { } else {
print_bps(result_bps[0]); print_bps(result_bps[0]);
...@@ -259,9 +259,9 @@ int bench_mem_memset(int argc, const char **argv, ...@@ -259,9 +259,9 @@ int bench_mem_memset(int argc, const char **argv,
printf(" (with prefault)\n"); printf(" (with prefault)\n");
} }
} else { } else {
if (use_clock) { if (use_cycle) {
printf(" %14lf Clock/Byte", printf(" %14lf Cycle/Byte",
(double)result_clock[pf] (double)result_cycle[pf]
/ (double)len); / (double)len);
} else } else
print_bps(result_bps[pf]); print_bps(result_bps[pf]);
...@@ -271,17 +271,17 @@ int bench_mem_memset(int argc, const char **argv, ...@@ -271,17 +271,17 @@ int bench_mem_memset(int argc, const char **argv,
break; break;
case BENCH_FORMAT_SIMPLE: case BENCH_FORMAT_SIMPLE:
if (!only_prefault && !no_prefault) { if (!only_prefault && !no_prefault) {
if (use_clock) { if (use_cycle) {
printf("%lf %lf\n", printf("%lf %lf\n",
(double)result_clock[0] / (double)len, (double)result_cycle[0] / (double)len,
(double)result_clock[1] / (double)len); (double)result_cycle[1] / (double)len);
} else { } else {
printf("%lf %lf\n", printf("%lf %lf\n",
result_bps[0], result_bps[1]); result_bps[0], result_bps[1]);
} }
} else { } else {
if (use_clock) { if (use_cycle) {
printf("%lf\n", (double)result_clock[pf] printf("%lf\n", (double)result_cycle[pf]
/ (double)len); / (double)len);
} else } else
printf("%lf\n", result_bps[pf]); printf("%lf\n", result_bps[pf]);
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "cpumap.h" #include "cpumap.h"
#include "thread_map.h" #include "thread_map.h"
#include "target.h" #include "target.h"
#include "../../../include/linux/hw_breakpoint.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
...@@ -152,6 +153,31 @@ static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) ...@@ -152,6 +153,31 @@ static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size)
return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
} }
static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type)
{
int r;
r = scnprintf(bf, size, "mem:0x%" PRIx64 ":", addr);
if (type & HW_BREAKPOINT_R)
r += scnprintf(bf + r, size - r, "r");
if (type & HW_BREAKPOINT_W)
r += scnprintf(bf + r, size - r, "w");
if (type & HW_BREAKPOINT_X)
r += scnprintf(bf + r, size - r, "x");
return r;
}
static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size)
{
struct perf_event_attr *attr = &evsel->attr;
int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type);
return r + perf_evsel__add_modifiers(evsel, bf + r, size - r);
}
const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX] const char *perf_evsel__hw_cache[PERF_COUNT_HW_CACHE_MAX]
[PERF_EVSEL__MAX_ALIASES] = { [PERF_EVSEL__MAX_ALIASES] = {
{ "L1-dcache", "l1-d", "l1d", "L1-data", }, { "L1-dcache", "l1-d", "l1d", "L1-data", },
...@@ -285,6 +311,10 @@ const char *perf_evsel__name(struct perf_evsel *evsel) ...@@ -285,6 +311,10 @@ const char *perf_evsel__name(struct perf_evsel *evsel)
scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint"); scnprintf(bf, sizeof(bf), "%s", "unknown tracepoint");
break; break;
case PERF_TYPE_BREAKPOINT:
perf_evsel__bp_name(evsel, bf, sizeof(bf));
break;
default: default:
scnprintf(bf, sizeof(bf), "%s", "unknown attr type"); scnprintf(bf, sizeof(bf), "%s", "unknown attr type");
break; break;
......
...@@ -108,4 +108,14 @@ int eprintf(int level, ...@@ -108,4 +108,14 @@ int eprintf(int level,
#define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__) #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
/*
* This looks more complex than it should be. But we need to
* get the type for the ~ right in round_down (it needs to be
* as wide as the result!), and we want to evaluate the macro
* arguments just once each.
*/
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
#define round_down(x, y) ((x) & ~__round_mask(x, y))
#endif #endif
...@@ -181,6 +181,22 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) ...@@ -181,6 +181,22 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
return 0; return 0;
} }
static int test__checkevent_breakpoint_rw(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = list_entry(evlist->entries.next,
struct perf_evsel, node);
TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong type",
PERF_TYPE_BREAKPOINT == evsel->attr.type);
TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
TEST_ASSERT_VAL("wrong bp_type",
(HW_BREAKPOINT_R|HW_BREAKPOINT_W) == evsel->attr.bp_type);
TEST_ASSERT_VAL("wrong bp_len",
HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
return 0;
}
static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
{ {
struct perf_evsel *evsel = list_entry(evlist->entries.next, struct perf_evsel *evsel = list_entry(evlist->entries.next,
...@@ -309,6 +325,8 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) ...@@ -309,6 +325,8 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
!strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u"));
return test__checkevent_breakpoint(evlist); return test__checkevent_breakpoint(evlist);
} }
...@@ -322,6 +340,8 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) ...@@ -322,6 +340,8 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
!strcmp(perf_evsel__name(evsel), "mem:0x0:x:k"));
return test__checkevent_breakpoint_x(evlist); return test__checkevent_breakpoint_x(evlist);
} }
...@@ -335,6 +355,8 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) ...@@ -335,6 +355,8 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
!strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp"));
return test__checkevent_breakpoint_r(evlist); return test__checkevent_breakpoint_r(evlist);
} }
...@@ -348,10 +370,27 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) ...@@ -348,10 +370,27 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
!strcmp(perf_evsel__name(evsel), "mem:0x0:w:up"));
return test__checkevent_breakpoint_w(evlist); return test__checkevent_breakpoint_w(evlist);
} }
static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist)
{
struct perf_evsel *evsel = list_entry(evlist->entries.next,
struct perf_evsel, node);
TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong name",
!strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp"));
return test__checkevent_breakpoint_rw(evlist);
}
static int test__checkevent_pmu(struct perf_evlist *evlist) static int test__checkevent_pmu(struct perf_evlist *evlist)
{ {
...@@ -585,10 +624,16 @@ static struct test__event_st test__events[] = { ...@@ -585,10 +624,16 @@ static struct test__event_st test__events[] = {
.name = "instructions:H", .name = "instructions:H",
.check = test__checkevent_exclude_guest_modifier, .check = test__checkevent_exclude_guest_modifier,
}, },
[26] = {
.name = "mem:0:rw",
.check = test__checkevent_breakpoint_rw,
},
[27] = {
.name = "mem:0:rw:kp",
.check = test__checkevent_breakpoint_rw_modifier,
},
}; };
#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
static struct test__event_st test__events_pmu[] = { static struct test__event_st test__events_pmu[] = {
[0] = { [0] = {
.name = "cpu/config=10,config1,config2=3,period=1000/u", .name = "cpu/config=10,config1,config2=3,period=1000/u",
...@@ -600,9 +645,6 @@ static struct test__event_st test__events_pmu[] = { ...@@ -600,9 +645,6 @@ static struct test__event_st test__events_pmu[] = {
}, },
}; };
#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
sizeof(struct test__event_st))
struct test__term { struct test__term {
const char *str; const char *str;
__u32 type; __u32 type;
...@@ -718,21 +760,17 @@ int parse_events__test(void) ...@@ -718,21 +760,17 @@ int parse_events__test(void)
{ {
int ret; int ret;
do { #define TEST_EVENTS(tests) \
ret = test_events(test__events, TEST__EVENTS_CNT); do { \
if (ret) ret = test_events(tests, ARRAY_SIZE(tests)); \
break; if (ret) \
return ret; \
if (test_pmu()) { } while (0)
ret = test_events(test__events_pmu,
TEST__EVENTS_PMU_CNT);
if (ret)
break;
}
ret = test_terms(test__terms, TEST__TERMS_CNT); TEST_EVENTS(test__events);
} while (0); if (test_pmu())
TEST_EVENTS(test__events_pmu);
return ret; return test_terms(test__terms, ARRAY_SIZE(test__terms));
} }
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#define MAX_NAME_LEN 100 #define MAX_NAME_LEN 100
struct event_symbol { struct event_symbol {
u8 type;
u64 config;
const char *symbol; const char *symbol;
const char *alias; const char *alias;
}; };
...@@ -30,30 +28,86 @@ extern int parse_events_debug; ...@@ -30,30 +28,86 @@ extern int parse_events_debug;
#endif #endif
int parse_events_parse(void *data, void *scanner); int parse_events_parse(void *data, void *scanner);
#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x static struct event_symbol event_symbols_hw[PERF_COUNT_HW_MAX] = {
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x [PERF_COUNT_HW_CPU_CYCLES] = {
.symbol = "cpu-cycles",
static struct event_symbol event_symbols[] = { .alias = "cycles",
{ CHW(CPU_CYCLES), "cpu-cycles", "cycles" }, },
{ CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" }, [PERF_COUNT_HW_INSTRUCTIONS] = {
{ CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" }, .symbol = "instructions",
{ CHW(INSTRUCTIONS), "instructions", "" }, .alias = "",
{ CHW(CACHE_REFERENCES), "cache-references", "" }, },
{ CHW(CACHE_MISSES), "cache-misses", "" }, [PERF_COUNT_HW_CACHE_REFERENCES] = {
{ CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, .symbol = "cache-references",
{ CHW(BRANCH_MISSES), "branch-misses", "" }, .alias = "",
{ CHW(BUS_CYCLES), "bus-cycles", "" }, },
{ CHW(REF_CPU_CYCLES), "ref-cycles", "" }, [PERF_COUNT_HW_CACHE_MISSES] = {
.symbol = "cache-misses",
{ CSW(CPU_CLOCK), "cpu-clock", "" }, .alias = "",
{ CSW(TASK_CLOCK), "task-clock", "" }, },
{ CSW(PAGE_FAULTS), "page-faults", "faults" }, [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = {
{ CSW(PAGE_FAULTS_MIN), "minor-faults", "" }, .symbol = "branch-instructions",
{ CSW(PAGE_FAULTS_MAJ), "major-faults", "" }, .alias = "branches",
{ CSW(CONTEXT_SWITCHES), "context-switches", "cs" }, },
{ CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" }, [PERF_COUNT_HW_BRANCH_MISSES] = {
{ CSW(ALIGNMENT_FAULTS), "alignment-faults", "" }, .symbol = "branch-misses",
{ CSW(EMULATION_FAULTS), "emulation-faults", "" }, .alias = "",
},
[PERF_COUNT_HW_BUS_CYCLES] = {
.symbol = "bus-cycles",
.alias = "",
},
[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = {
.symbol = "stalled-cycles-frontend",
.alias = "idle-cycles-frontend",
},
[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = {
.symbol = "stalled-cycles-backend",
.alias = "idle-cycles-backend",
},
[PERF_COUNT_HW_REF_CPU_CYCLES] = {
.symbol = "ref-cycles",
.alias = "",
},
};
static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
[PERF_COUNT_SW_CPU_CLOCK] = {
.symbol = "cpu-clock",
.alias = "",
},
[PERF_COUNT_SW_TASK_CLOCK] = {
.symbol = "task-clock",
.alias = "",
},
[PERF_COUNT_SW_PAGE_FAULTS] = {
.symbol = "page-faults",
.alias = "faults",
},
[PERF_COUNT_SW_CONTEXT_SWITCHES] = {
.symbol = "context-switches",
.alias = "cs",
},
[PERF_COUNT_SW_CPU_MIGRATIONS] = {
.symbol = "cpu-migrations",
.alias = "migrations",
},
[PERF_COUNT_SW_PAGE_FAULTS_MIN] = {
.symbol = "minor-faults",
.alias = "",
},
[PERF_COUNT_SW_PAGE_FAULTS_MAJ] = {
.symbol = "major-faults",
.alias = "",
},
[PERF_COUNT_SW_ALIGNMENT_FAULTS] = {
.symbol = "alignment-faults",
.alias = "",
},
[PERF_COUNT_SW_EMULATION_FAULTS] = {
.symbol = "emulation-faults",
.alias = "",
},
}; };
#define __PERF_EVENT_FIELD(config, name) \ #define __PERF_EVENT_FIELD(config, name) \
...@@ -383,21 +437,31 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr) ...@@ -383,21 +437,31 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
if (!type || !type[i]) if (!type || !type[i])
break; break;
#define CHECK_SET_TYPE(bit) \
do { \
if (attr->bp_type & bit) \
return -EINVAL; \
else \
attr->bp_type |= bit; \
} while (0)
switch (type[i]) { switch (type[i]) {
case 'r': case 'r':
attr->bp_type |= HW_BREAKPOINT_R; CHECK_SET_TYPE(HW_BREAKPOINT_R);
break; break;
case 'w': case 'w':
attr->bp_type |= HW_BREAKPOINT_W; CHECK_SET_TYPE(HW_BREAKPOINT_W);
break; break;
case 'x': case 'x':
attr->bp_type |= HW_BREAKPOINT_X; CHECK_SET_TYPE(HW_BREAKPOINT_X);
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
} }
#undef CHECK_SET_TYPE
if (!attr->bp_type) /* Default */ if (!attr->bp_type) /* Default */
attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W; attr->bp_type = HW_BREAKPOINT_R | HW_BREAKPOINT_W;
...@@ -408,7 +472,6 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, ...@@ -408,7 +472,6 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
void *ptr, char *type) void *ptr, char *type)
{ {
struct perf_event_attr attr; struct perf_event_attr attr;
char name[MAX_NAME_LEN];
memset(&attr, 0, sizeof(attr)); memset(&attr, 0, sizeof(attr));
attr.bp_addr = (unsigned long) ptr; attr.bp_addr = (unsigned long) ptr;
...@@ -427,8 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, ...@@ -427,8 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx,
attr.type = PERF_TYPE_BREAKPOINT; attr.type = PERF_TYPE_BREAKPOINT;
snprintf(name, MAX_NAME_LEN, "mem:%p:%s", ptr, type ? type : "rw"); return add_event(list, idx, &attr, NULL);
return add_event(list, idx, &attr, name);
} }
static int config_term(struct perf_event_attr *attr, static int config_term(struct perf_event_attr *attr,
...@@ -816,16 +878,13 @@ int is_valid_tracepoint(const char *event_string) ...@@ -816,16 +878,13 @@ int is_valid_tracepoint(const char *event_string)
return 0; return 0;
} }
void print_events_type(u8 type) static void __print_events_type(u8 type, struct event_symbol *syms,
unsigned max)
{ {
struct event_symbol *syms = event_symbols;
unsigned int i;
char name[64]; char name[64];
unsigned i;
for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { for (i = 0; i < max ; i++, syms++) {
if (type != syms->type)
continue;
if (strlen(syms->alias)) if (strlen(syms->alias))
snprintf(name, sizeof(name), "%s OR %s", snprintf(name, sizeof(name), "%s OR %s",
syms->symbol, syms->alias); syms->symbol, syms->alias);
...@@ -837,6 +896,14 @@ void print_events_type(u8 type) ...@@ -837,6 +896,14 @@ void print_events_type(u8 type)
} }
} }
void print_events_type(u8 type)
{
if (type == PERF_TYPE_SOFTWARE)
__print_events_type(type, event_symbols_sw, PERF_COUNT_SW_MAX);
else
__print_events_type(type, event_symbols_hw, PERF_COUNT_HW_MAX);
}
int print_hwcache_events(const char *event_glob) int print_hwcache_events(const char *event_glob)
{ {
unsigned int type, op, i, printed = 0; unsigned int type, op, i, printed = 0;
...@@ -864,26 +931,13 @@ int print_hwcache_events(const char *event_glob) ...@@ -864,26 +931,13 @@ int print_hwcache_events(const char *event_glob)
return printed; return printed;
} }
/* static void print_symbol_events(const char *event_glob, unsigned type,
* Print the help text for the event symbols: struct event_symbol *syms, unsigned max)
*/
void print_events(const char *event_glob)
{ {
unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; unsigned i, printed = 0;
struct event_symbol *syms = event_symbols;
char name[MAX_NAME_LEN]; char name[MAX_NAME_LEN];
printf("\n"); for (i = 0; i < max; i++, syms++) {
printf("List of pre-defined events (to be used in -e):\n");
for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
type = syms->type;
if (type != prev_type && printed) {
printf("\n");
printed = 0;
ntypes_printed++;
}
if (event_glob != NULL && if (event_glob != NULL &&
!(strglobmatch(syms->symbol, event_glob) || !(strglobmatch(syms->symbol, event_glob) ||
...@@ -894,17 +948,31 @@ void print_events(const char *event_glob) ...@@ -894,17 +948,31 @@ void print_events(const char *event_glob)
snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias); snprintf(name, MAX_NAME_LEN, "%s OR %s", syms->symbol, syms->alias);
else else
strncpy(name, syms->symbol, MAX_NAME_LEN); strncpy(name, syms->symbol, MAX_NAME_LEN);
printf(" %-50s [%s]\n", name,
event_type_descriptors[type]);
prev_type = type; printf(" %-50s [%s]\n", name, event_type_descriptors[type]);
++printed;
printed++;
} }
if (ntypes_printed) { if (printed)
printed = 0;
printf("\n"); printf("\n");
} }
/*
* Print the help text for the event symbols:
*/
void print_events(const char *event_glob)
{
printf("\n");
printf("List of pre-defined events (to be used in -e):\n");
print_symbol_events(event_glob, PERF_TYPE_HARDWARE,
event_symbols_hw, PERF_COUNT_HW_MAX);
print_symbol_events(event_glob, PERF_TYPE_SOFTWARE,
event_symbols_sw, PERF_COUNT_SW_MAX);
print_hwcache_events(event_glob); print_hwcache_events(event_glob);
if (event_glob != NULL) if (event_glob != NULL)
......
...@@ -56,7 +56,7 @@ static int sym(yyscan_t scanner, int type, int config) ...@@ -56,7 +56,7 @@ static int sym(yyscan_t scanner, int type, int config)
YYSTYPE *yylval = parse_events_get_lval(scanner); YYSTYPE *yylval = parse_events_get_lval(scanner);
yylval->num = (type << 16) + config; yylval->num = (type << 16) + config;
return PE_VALUE_SYM; return type == PERF_TYPE_HARDWARE ? PE_VALUE_SYM_HW : PE_VALUE_SYM_SW;
} }
static int term(yyscan_t scanner, int type) static int term(yyscan_t scanner, int type)
...@@ -76,7 +76,7 @@ num_hex 0x[a-fA-F0-9]+ ...@@ -76,7 +76,7 @@ num_hex 0x[a-fA-F0-9]+
num_raw_hex [a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+
name [a-zA-Z_*?][a-zA-Z0-9_*?]* name [a-zA-Z_*?][a-zA-Z0-9_*?]*
modifier_event [ukhpGH]{1,8} modifier_event [ukhpGH]{1,8}
modifier_bp [rwx] modifier_bp [rwx]{1,3}
%% %%
...@@ -152,6 +152,7 @@ r{num_raw_hex} { return raw(yyscanner); } ...@@ -152,6 +152,7 @@ r{num_raw_hex} { return raw(yyscanner); }
, { return ','; } , { return ','; }
: { return ':'; } : { return ':'; }
= { return '='; } = { return '='; }
\n { }
<mem>{ <mem>{
{modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); } {modifier_bp} { return str(yyscanner, PE_MODIFIER_BP); }
......
...@@ -26,14 +26,15 @@ do { \ ...@@ -26,14 +26,15 @@ do { \
%} %}
%token PE_START_EVENTS PE_START_TERMS %token PE_START_EVENTS PE_START_TERMS
%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
%token PE_NAME %token PE_NAME
%token PE_MODIFIER_EVENT PE_MODIFIER_BP %token PE_MODIFIER_EVENT PE_MODIFIER_BP
%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
%token PE_PREFIX_MEM PE_PREFIX_RAW %token PE_PREFIX_MEM PE_PREFIX_RAW
%token PE_ERROR %token PE_ERROR
%type <num> PE_VALUE %type <num> PE_VALUE
%type <num> PE_VALUE_SYM %type <num> PE_VALUE_SYM_HW
%type <num> PE_VALUE_SYM_SW
%type <num> PE_RAW %type <num> PE_RAW
%type <num> PE_TERM %type <num> PE_TERM
%type <str> PE_NAME %type <str> PE_NAME
...@@ -41,6 +42,7 @@ do { \ ...@@ -41,6 +42,7 @@ do { \
%type <str> PE_NAME_CACHE_OP_RESULT %type <str> PE_NAME_CACHE_OP_RESULT
%type <str> PE_MODIFIER_EVENT %type <str> PE_MODIFIER_EVENT
%type <str> PE_MODIFIER_BP %type <str> PE_MODIFIER_BP
%type <num> value_sym
%type <head> event_config %type <head> event_config
%type <term> event_term %type <term> event_term
%type <head> event_pmu %type <head> event_pmu
...@@ -109,8 +111,13 @@ PE_NAME '/' event_config '/' ...@@ -109,8 +111,13 @@ PE_NAME '/' event_config '/'
$$ = list; $$ = list;
} }
value_sym:
PE_VALUE_SYM_HW
|
PE_VALUE_SYM_SW
event_legacy_symbol: event_legacy_symbol:
PE_VALUE_SYM '/' event_config '/' value_sym '/' event_config '/'
{ {
struct parse_events_data__events *data = _data; struct parse_events_data__events *data = _data;
struct list_head *list = NULL; struct list_head *list = NULL;
...@@ -123,7 +130,7 @@ PE_VALUE_SYM '/' event_config '/' ...@@ -123,7 +130,7 @@ PE_VALUE_SYM '/' event_config '/'
$$ = list; $$ = list;
} }
| |
PE_VALUE_SYM sep_slash_dc value_sym sep_slash_dc
{ {
struct parse_events_data__events *data = _data; struct parse_events_data__events *data = _data;
struct list_head *list = NULL; struct list_head *list = NULL;
......
...@@ -72,7 +72,7 @@ static int pmu_format(char *name, struct list_head *format) ...@@ -72,7 +72,7 @@ static int pmu_format(char *name, struct list_head *format)
"%s/bus/event_source/devices/%s/format", sysfs, name); "%s/bus/event_source/devices/%s/format", sysfs, name);
if (stat(path, &st) < 0) if (stat(path, &st) < 0)
return -1; return 0; /* no error if format does not exist */
if (pmu_format_parse(path, format)) if (pmu_format_parse(path, format))
return -1; return -1;
...@@ -252,6 +252,7 @@ static struct perf_pmu *pmu_lookup(char *name) ...@@ -252,6 +252,7 @@ static struct perf_pmu *pmu_lookup(char *name)
list_splice(&aliases, &pmu->aliases); list_splice(&aliases, &pmu->aliases);
pmu->name = strdup(name); pmu->name = strdup(name);
pmu->type = type; pmu->type = type;
list_add_tail(&pmu->list, &pmus);
return pmu; return pmu;
} }
......
...@@ -209,6 +209,10 @@ static void define_event_symbols(struct event_format *event, ...@@ -209,6 +209,10 @@ static void define_event_symbols(struct event_format *event,
define_symbolic_values(args->symbol.symbols, ev_name, define_symbolic_values(args->symbol.symbols, ev_name,
cur_field_name); cur_field_name);
break; break;
case PRINT_HEX:
define_event_symbols(event, ev_name, args->hex.field);
define_event_symbols(event, ev_name, args->hex.size);
break;
case PRINT_BSTRING: case PRINT_BSTRING:
case PRINT_DYNAMIC_ARRAY: case PRINT_DYNAMIC_ARRAY:
case PRINT_STRING: case PRINT_STRING:
......
...@@ -166,6 +166,10 @@ static void define_event_symbols(struct event_format *event, ...@@ -166,6 +166,10 @@ static void define_event_symbols(struct event_format *event,
define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name, define_values(PRINT_SYMBOL, args->symbol.symbols, ev_name,
cur_field_name); cur_field_name);
break; break;
case PRINT_HEX:
define_event_symbols(event, ev_name, args->hex.field);
define_event_symbols(event, ev_name, args->hex.size);
break;
case PRINT_STRING: case PRINT_STRING:
break; break;
case PRINT_TYPE: case PRINT_TYPE:
......
...@@ -1478,14 +1478,31 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) ...@@ -1478,14 +1478,31 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
goto out; goto out;
} }
sec = elf_section_by_name(elf, &ehdr, &shdr, /*
".note.gnu.build-id", NULL); * Check following sections for notes:
if (sec == NULL) { * '.note.gnu.build-id'
* '.notes'
* '.note' (VDSO specific)
*/
do {
sec = elf_section_by_name(elf, &ehdr, &shdr,
".note.gnu.build-id", NULL);
if (sec)
break;
sec = elf_section_by_name(elf, &ehdr, &shdr, sec = elf_section_by_name(elf, &ehdr, &shdr,
".notes", NULL); ".notes", NULL);
if (sec == NULL) if (sec)
goto out; break;
}
sec = elf_section_by_name(elf, &ehdr, &shdr,
".note", NULL);
if (sec)
break;
return err;
} while (0);
data = elf_getdata(sec, NULL); data = elf_getdata(sec, NULL);
if (data == NULL) if (data == NULL)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment