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 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJP9bEdAAoJENZQFvNTUqpAvGEP/AtaZBleXnhgmXWmbPNvlx2z 3qBI5vLn3iczITmnK4mTVqGAQ+PZRGX+m7h2rTqyJSMzzkLBHRtjt1Y/Ul5x4pRk 72xaZQh1OCEZCsqKyzYagaRFt3jaqYUElO+nVTaony+Xp8zeJBnG6Jd6C9l5KhKH OHwkQEXv49tnSG5P9JigTEstnPLckGsrdZch2uU8pHLdw1P+LHmKnLeO6+Jt0az7 m7Tr+fQgqIi530xazkg2ZJM/FXVZpwlwAtt8u2U7mUApfpI+eRILrhDyzyUudVWX Hpr9cPVPI/l0LQaWe82asdTMNm7CC9GPwxoaIkjN2DNSQfXKSym+ontrudFGS10O BZFQ595eCA3VUdvMFzqi8x5q4ia/dg+JUmi67GS7tz/IL34NmS6Nsu5FHhVreeRK oZmGZP4wpZ6/Fy1FjaQHBFOpPKD89AVpUN4MsILKh8N9IG74G1Vfia1/EfewKerD DX8UPr3CAbu5WVWq+CUDUVK9bq9PJzW8Zumi7m80WE0o1dCGvMB5lbJwOkwG6S4H rdyPrJ44jFPodmKOZv/jYTPcA68RpjYsRDoCmiI2TY2b99aM+jx4yzlh2fXeamG9 GzgRjg8MfV76PiCUYDCwLLLqHupqghqCIvecNhFKYKp+lzp8j8eiESXrqSlAe23P DVJrNFFK2YFrrbB9WJOO =vcUF -----END PGP SIGNATURE----- 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: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Коммит
387ef4e24a
|
@ -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
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
|
@ -467,8 +467,10 @@ int pevent_register_function(struct pevent *pevent, char *func,
|
||||||
item->mod = NULL;
|
item->mod = NULL;
|
||||||
item->addr = addr;
|
item->addr = addr;
|
||||||
|
|
||||||
pevent->funclist = item;
|
if (!item->func || (mod && !item->mod))
|
||||||
|
die("malloc func");
|
||||||
|
|
||||||
|
pevent->funclist = item;
|
||||||
pevent->func_count++;
|
pevent->func_count++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -511,12 +513,12 @@ struct printk_list {
|
||||||
|
|
||||||
static int printk_cmp(const void *a, const void *b)
|
static int printk_cmp(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
const struct func_map *fa = a;
|
const struct printk_map *pa = a;
|
||||||
const struct func_map *fb = b;
|
const struct printk_map *pb = b;
|
||||||
|
|
||||||
if (fa->addr < fb->addr)
|
if (pa->addr < pb->addr)
|
||||||
return -1;
|
return -1;
|
||||||
if (fa->addr > fb->addr)
|
if (pa->addr > pb->addr)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -583,10 +585,13 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
|
||||||
item = malloc_or_die(sizeof(*item));
|
item = malloc_or_die(sizeof(*item));
|
||||||
|
|
||||||
item->next = pevent->printklist;
|
item->next = pevent->printklist;
|
||||||
pevent->printklist = item;
|
|
||||||
item->printk = strdup(fmt);
|
item->printk = strdup(fmt);
|
||||||
item->addr = addr;
|
item->addr = addr;
|
||||||
|
|
||||||
|
if (!item->printk)
|
||||||
|
die("malloc fmt");
|
||||||
|
|
||||||
|
pevent->printklist = item;
|
||||||
pevent->printk_count++;
|
pevent->printk_count++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -616,7 +621,9 @@ static struct event_format *alloc_event(void)
|
||||||
{
|
{
|
||||||
struct event_format *event;
|
struct event_format *event;
|
||||||
|
|
||||||
event = malloc_or_die(sizeof(*event));
|
event = malloc(sizeof(*event));
|
||||||
|
if (!event)
|
||||||
|
return NULL;
|
||||||
memset(event, 0, sizeof(*event));
|
memset(event, 0, sizeof(*event));
|
||||||
|
|
||||||
return event;
|
return event;
|
||||||
|
@ -626,12 +633,8 @@ static void add_event(struct pevent *pevent, struct event_format *event)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!pevent->events)
|
pevent->events = realloc(pevent->events, sizeof(event) *
|
||||||
pevent->events = malloc_or_die(sizeof(event));
|
(pevent->nr_events + 1));
|
||||||
else
|
|
||||||
pevent->events =
|
|
||||||
realloc(pevent->events, sizeof(event) *
|
|
||||||
(pevent->nr_events + 1));
|
|
||||||
if (!pevent->events)
|
if (!pevent->events)
|
||||||
die("Can not allocate events");
|
die("Can not allocate events");
|
||||||
|
|
||||||
|
@ -697,6 +700,10 @@ static void free_arg(struct print_arg *arg)
|
||||||
free_arg(arg->symbol.field);
|
free_arg(arg->symbol.field);
|
||||||
free_flag_sym(arg->symbol.symbols);
|
free_flag_sym(arg->symbol.symbols);
|
||||||
break;
|
break;
|
||||||
|
case PRINT_HEX:
|
||||||
|
free_arg(arg->hex.field);
|
||||||
|
free_arg(arg->hex.size);
|
||||||
|
break;
|
||||||
case PRINT_TYPE:
|
case PRINT_TYPE:
|
||||||
free(arg->typecast.type);
|
free(arg->typecast.type);
|
||||||
free_arg(arg->typecast.item);
|
free_arg(arg->typecast.item);
|
||||||
|
@ -775,6 +782,25 @@ int pevent_peek_char(void)
|
||||||
return __peek_char();
|
return __peek_char();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int extend_token(char **tok, char *buf, int size)
|
||||||
|
{
|
||||||
|
char *newtok = realloc(*tok, size);
|
||||||
|
|
||||||
|
if (!newtok) {
|
||||||
|
free(*tok);
|
||||||
|
*tok = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*tok)
|
||||||
|
strcpy(newtok, buf);
|
||||||
|
else
|
||||||
|
strcat(newtok, buf);
|
||||||
|
*tok = newtok;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static enum event_type force_token(const char *str, char **tok);
|
static enum event_type force_token(const char *str, char **tok);
|
||||||
|
|
||||||
static enum event_type __read_token(char **tok)
|
static enum event_type __read_token(char **tok)
|
||||||
|
@ -859,17 +885,10 @@ static enum event_type __read_token(char **tok)
|
||||||
do {
|
do {
|
||||||
if (i == (BUFSIZ - 1)) {
|
if (i == (BUFSIZ - 1)) {
|
||||||
buf[i] = 0;
|
buf[i] = 0;
|
||||||
if (*tok) {
|
|
||||||
*tok = realloc(*tok, tok_size + BUFSIZ);
|
|
||||||
if (!*tok)
|
|
||||||
return EVENT_NONE;
|
|
||||||
strcat(*tok, buf);
|
|
||||||
} else
|
|
||||||
*tok = strdup(buf);
|
|
||||||
|
|
||||||
if (!*tok)
|
|
||||||
return EVENT_NONE;
|
|
||||||
tok_size += BUFSIZ;
|
tok_size += BUFSIZ;
|
||||||
|
|
||||||
|
if (extend_token(tok, buf, tok_size) < 0)
|
||||||
|
return EVENT_NONE;
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
last_ch = ch;
|
last_ch = ch;
|
||||||
|
@ -908,17 +927,10 @@ static enum event_type __read_token(char **tok)
|
||||||
while (get_type(__peek_char()) == type) {
|
while (get_type(__peek_char()) == type) {
|
||||||
if (i == (BUFSIZ - 1)) {
|
if (i == (BUFSIZ - 1)) {
|
||||||
buf[i] = 0;
|
buf[i] = 0;
|
||||||
if (*tok) {
|
|
||||||
*tok = realloc(*tok, tok_size + BUFSIZ);
|
|
||||||
if (!*tok)
|
|
||||||
return EVENT_NONE;
|
|
||||||
strcat(*tok, buf);
|
|
||||||
} else
|
|
||||||
*tok = strdup(buf);
|
|
||||||
|
|
||||||
if (!*tok)
|
|
||||||
return EVENT_NONE;
|
|
||||||
tok_size += BUFSIZ;
|
tok_size += BUFSIZ;
|
||||||
|
|
||||||
|
if (extend_token(tok, buf, tok_size) < 0)
|
||||||
|
return EVENT_NONE;
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
ch = __read_char();
|
ch = __read_char();
|
||||||
|
@ -927,14 +939,7 @@ static enum event_type __read_token(char **tok)
|
||||||
|
|
||||||
out:
|
out:
|
||||||
buf[i] = 0;
|
buf[i] = 0;
|
||||||
if (*tok) {
|
if (extend_token(tok, buf, tok_size + i + 1) < 0)
|
||||||
*tok = realloc(*tok, tok_size + i);
|
|
||||||
if (!*tok)
|
|
||||||
return EVENT_NONE;
|
|
||||||
strcat(*tok, buf);
|
|
||||||
} else
|
|
||||||
*tok = strdup(buf);
|
|
||||||
if (!*tok)
|
|
||||||
return EVENT_NONE;
|
return EVENT_NONE;
|
||||||
|
|
||||||
if (type == EVENT_ITEM) {
|
if (type == EVENT_ITEM) {
|
||||||
|
@ -1255,9 +1260,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||||
field->flags |= FIELD_IS_POINTER;
|
field->flags |= FIELD_IS_POINTER;
|
||||||
|
|
||||||
if (field->type) {
|
if (field->type) {
|
||||||
field->type = realloc(field->type,
|
char *new_type;
|
||||||
strlen(field->type) +
|
new_type = realloc(field->type,
|
||||||
strlen(last_token) + 2);
|
strlen(field->type) +
|
||||||
|
strlen(last_token) + 2);
|
||||||
|
if (!new_type) {
|
||||||
|
free(last_token);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
field->type = new_type;
|
||||||
strcat(field->type, " ");
|
strcat(field->type, " ");
|
||||||
strcat(field->type, last_token);
|
strcat(field->type, last_token);
|
||||||
free(last_token);
|
free(last_token);
|
||||||
|
@ -1282,6 +1293,7 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||||
if (strcmp(token, "[") == 0) {
|
if (strcmp(token, "[") == 0) {
|
||||||
enum event_type last_type = type;
|
enum event_type last_type = type;
|
||||||
char *brackets = token;
|
char *brackets = token;
|
||||||
|
char *new_brackets;
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
field->flags |= FIELD_IS_ARRAY;
|
field->flags |= FIELD_IS_ARRAY;
|
||||||
|
@ -1301,9 +1313,14 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||||
len = 1;
|
len = 1;
|
||||||
last_type = type;
|
last_type = type;
|
||||||
|
|
||||||
brackets = realloc(brackets,
|
new_brackets = realloc(brackets,
|
||||||
strlen(brackets) +
|
strlen(brackets) +
|
||||||
strlen(token) + len);
|
strlen(token) + len);
|
||||||
|
if (!new_brackets) {
|
||||||
|
free(brackets);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
brackets = new_brackets;
|
||||||
if (len == 2)
|
if (len == 2)
|
||||||
strcat(brackets, " ");
|
strcat(brackets, " ");
|
||||||
strcat(brackets, token);
|
strcat(brackets, token);
|
||||||
|
@ -1319,7 +1336,12 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||||
|
|
||||||
free_token(token);
|
free_token(token);
|
||||||
|
|
||||||
brackets = realloc(brackets, strlen(brackets) + 2);
|
new_brackets = realloc(brackets, strlen(brackets) + 2);
|
||||||
|
if (!new_brackets) {
|
||||||
|
free(brackets);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
brackets = new_brackets;
|
||||||
strcat(brackets, "]");
|
strcat(brackets, "]");
|
||||||
|
|
||||||
/* add brackets to type */
|
/* add brackets to type */
|
||||||
|
@ -1330,10 +1352,16 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||||
* the format: type [] item;
|
* the format: type [] item;
|
||||||
*/
|
*/
|
||||||
if (type == EVENT_ITEM) {
|
if (type == EVENT_ITEM) {
|
||||||
field->type = realloc(field->type,
|
char *new_type;
|
||||||
strlen(field->type) +
|
new_type = realloc(field->type,
|
||||||
strlen(field->name) +
|
strlen(field->type) +
|
||||||
strlen(brackets) + 2);
|
strlen(field->name) +
|
||||||
|
strlen(brackets) + 2);
|
||||||
|
if (!new_type) {
|
||||||
|
free(brackets);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
field->type = new_type;
|
||||||
strcat(field->type, " ");
|
strcat(field->type, " ");
|
||||||
strcat(field->type, field->name);
|
strcat(field->type, field->name);
|
||||||
free_token(field->name);
|
free_token(field->name);
|
||||||
|
@ -1341,9 +1369,15 @@ static int event_read_fields(struct event_format *event, struct format_field **f
|
||||||
field->name = token;
|
field->name = token;
|
||||||
type = read_token(&token);
|
type = read_token(&token);
|
||||||
} else {
|
} else {
|
||||||
field->type = realloc(field->type,
|
char *new_type;
|
||||||
strlen(field->type) +
|
new_type = realloc(field->type,
|
||||||
strlen(brackets) + 1);
|
strlen(field->type) +
|
||||||
|
strlen(brackets) + 1);
|
||||||
|
if (!new_type) {
|
||||||
|
free(brackets);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
field->type = new_type;
|
||||||
strcat(field->type, brackets);
|
strcat(field->type, brackets);
|
||||||
}
|
}
|
||||||
free(brackets);
|
free(brackets);
|
||||||
|
@ -1726,10 +1760,16 @@ process_op(struct event_format *event, struct print_arg *arg, char **tok)
|
||||||
/* could just be a type pointer */
|
/* could just be a type pointer */
|
||||||
if ((strcmp(arg->op.op, "*") == 0) &&
|
if ((strcmp(arg->op.op, "*") == 0) &&
|
||||||
type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
|
type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
|
||||||
|
char *new_atom;
|
||||||
|
|
||||||
if (left->type != PRINT_ATOM)
|
if (left->type != PRINT_ATOM)
|
||||||
die("bad pointer type");
|
die("bad pointer type");
|
||||||
left->atom.atom = realloc(left->atom.atom,
|
new_atom = realloc(left->atom.atom,
|
||||||
strlen(left->atom.atom) + 3);
|
strlen(left->atom.atom) + 3);
|
||||||
|
if (!new_atom)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
left->atom.atom = new_atom;
|
||||||
strcat(left->atom.atom, " *");
|
strcat(left->atom.atom, " *");
|
||||||
free(arg->op.op);
|
free(arg->op.op);
|
||||||
*arg = *left;
|
*arg = *left;
|
||||||
|
@ -2146,6 +2186,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
field->value = strdup(value);
|
field->value = strdup(value);
|
||||||
|
if (field->value == NULL)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
free_arg(arg);
|
free_arg(arg);
|
||||||
arg = alloc_arg();
|
arg = alloc_arg();
|
||||||
|
@ -2159,6 +2201,8 @@ process_fields(struct event_format *event, struct print_flag_sym **list, char **
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
field->str = strdup(value);
|
field->str = strdup(value);
|
||||||
|
if (field->str == NULL)
|
||||||
|
goto out_free;
|
||||||
free_arg(arg);
|
free_arg(arg);
|
||||||
arg = NULL;
|
arg = NULL;
|
||||||
|
|
||||||
|
@ -2259,6 +2303,45 @@ process_symbols(struct event_format *event, struct print_arg *arg, char **tok)
|
||||||
return EVENT_ERROR;
|
return EVENT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum event_type
|
||||||
|
process_hex(struct event_format *event, struct print_arg *arg, char **tok)
|
||||||
|
{
|
||||||
|
struct print_arg *field;
|
||||||
|
enum event_type type;
|
||||||
|
char *token;
|
||||||
|
|
||||||
|
memset(arg, 0, sizeof(*arg));
|
||||||
|
arg->type = PRINT_HEX;
|
||||||
|
|
||||||
|
field = alloc_arg();
|
||||||
|
type = process_arg(event, field, &token);
|
||||||
|
|
||||||
|
if (test_type_token(type, token, EVENT_DELIM, ","))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
arg->hex.field = field;
|
||||||
|
|
||||||
|
free_token(token);
|
||||||
|
|
||||||
|
field = alloc_arg();
|
||||||
|
type = process_arg(event, field, &token);
|
||||||
|
|
||||||
|
if (test_type_token(type, token, EVENT_DELIM, ")"))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
arg->hex.size = field;
|
||||||
|
|
||||||
|
free_token(token);
|
||||||
|
type = read_token_item(tok);
|
||||||
|
return type;
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
free_arg(field);
|
||||||
|
free_token(token);
|
||||||
|
*tok = NULL;
|
||||||
|
return EVENT_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
static enum event_type
|
static enum event_type
|
||||||
process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
|
process_dynamic_array(struct event_format *event, struct print_arg *arg, char **tok)
|
||||||
{
|
{
|
||||||
|
@ -2488,6 +2571,10 @@ process_function(struct event_format *event, struct print_arg *arg,
|
||||||
is_symbolic_field = 1;
|
is_symbolic_field = 1;
|
||||||
return process_symbols(event, arg, tok);
|
return process_symbols(event, arg, tok);
|
||||||
}
|
}
|
||||||
|
if (strcmp(token, "__print_hex") == 0) {
|
||||||
|
free_token(token);
|
||||||
|
return process_hex(event, arg, tok);
|
||||||
|
}
|
||||||
if (strcmp(token, "__get_str") == 0) {
|
if (strcmp(token, "__get_str") == 0) {
|
||||||
free_token(token);
|
free_token(token);
|
||||||
return process_str(event, arg, tok);
|
return process_str(event, arg, tok);
|
||||||
|
@ -2541,7 +2628,16 @@ process_arg_token(struct event_format *event, struct print_arg *arg,
|
||||||
}
|
}
|
||||||
/* atoms can be more than one token long */
|
/* atoms can be more than one token long */
|
||||||
while (type == EVENT_ITEM) {
|
while (type == EVENT_ITEM) {
|
||||||
atom = realloc(atom, strlen(atom) + strlen(token) + 2);
|
char *new_atom;
|
||||||
|
new_atom = realloc(atom,
|
||||||
|
strlen(atom) + strlen(token) + 2);
|
||||||
|
if (!new_atom) {
|
||||||
|
free(atom);
|
||||||
|
*tok = NULL;
|
||||||
|
free_token(token);
|
||||||
|
return EVENT_ERROR;
|
||||||
|
}
|
||||||
|
atom = new_atom;
|
||||||
strcat(atom, " ");
|
strcat(atom, " ");
|
||||||
strcat(atom, token);
|
strcat(atom, token);
|
||||||
free_token(token);
|
free_token(token);
|
||||||
|
@ -2835,7 +2931,7 @@ static int get_common_info(struct pevent *pevent,
|
||||||
event = pevent->events[0];
|
event = pevent->events[0];
|
||||||
field = pevent_find_common_field(event, type);
|
field = pevent_find_common_field(event, type);
|
||||||
if (!field)
|
if (!field)
|
||||||
die("field '%s' not found", type);
|
return -1;
|
||||||
|
|
||||||
*offset = field->offset;
|
*offset = field->offset;
|
||||||
*size = field->size;
|
*size = field->size;
|
||||||
|
@ -2886,15 +2982,16 @@ static int parse_common_flags(struct pevent *pevent, void *data)
|
||||||
|
|
||||||
static int parse_common_lock_depth(struct pevent *pevent, void *data)
|
static int parse_common_lock_depth(struct pevent *pevent, void *data)
|
||||||
{
|
{
|
||||||
int ret;
|
return __parse_common(pevent, data,
|
||||||
|
&pevent->ld_size, &pevent->ld_offset,
|
||||||
|
"common_lock_depth");
|
||||||
|
}
|
||||||
|
|
||||||
ret = __parse_common(pevent, data,
|
static int parse_common_migrate_disable(struct pevent *pevent, void *data)
|
||||||
&pevent->ld_size, &pevent->ld_offset,
|
{
|
||||||
"common_lock_depth");
|
return __parse_common(pevent, data,
|
||||||
if (ret < 0)
|
&pevent->ld_size, &pevent->ld_offset,
|
||||||
return -1;
|
"common_migrate_disable");
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int events_id_cmp(const void *a, const void *b);
|
static int events_id_cmp(const void *a, const void *b);
|
||||||
|
@ -2995,6 +3092,7 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg
|
||||||
break;
|
break;
|
||||||
case PRINT_FLAGS:
|
case PRINT_FLAGS:
|
||||||
case PRINT_SYMBOL:
|
case PRINT_SYMBOL:
|
||||||
|
case PRINT_HEX:
|
||||||
break;
|
break;
|
||||||
case PRINT_TYPE:
|
case PRINT_TYPE:
|
||||||
val = eval_num_arg(data, size, event, arg->typecast.item);
|
val = eval_num_arg(data, size, event, arg->typecast.item);
|
||||||
|
@ -3214,11 +3312,13 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||||
{
|
{
|
||||||
struct pevent *pevent = event->pevent;
|
struct pevent *pevent = event->pevent;
|
||||||
struct print_flag_sym *flag;
|
struct print_flag_sym *flag;
|
||||||
|
struct format_field *field;
|
||||||
unsigned long long val, fval;
|
unsigned long long val, fval;
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
char *str;
|
char *str;
|
||||||
|
unsigned char *hex;
|
||||||
int print;
|
int print;
|
||||||
int len;
|
int i, len;
|
||||||
|
|
||||||
switch (arg->type) {
|
switch (arg->type) {
|
||||||
case PRINT_NULL:
|
case PRINT_NULL:
|
||||||
|
@ -3228,27 +3328,29 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||||
print_str_to_seq(s, format, len_arg, arg->atom.atom);
|
print_str_to_seq(s, format, len_arg, arg->atom.atom);
|
||||||
return;
|
return;
|
||||||
case PRINT_FIELD:
|
case PRINT_FIELD:
|
||||||
if (!arg->field.field) {
|
field = arg->field.field;
|
||||||
arg->field.field = pevent_find_any_field(event, arg->field.name);
|
if (!field) {
|
||||||
if (!arg->field.field)
|
field = pevent_find_any_field(event, arg->field.name);
|
||||||
|
if (!field)
|
||||||
die("field %s not found", arg->field.name);
|
die("field %s not found", arg->field.name);
|
||||||
|
arg->field.field = field;
|
||||||
}
|
}
|
||||||
/* Zero sized fields, mean the rest of the data */
|
/* Zero sized fields, mean the rest of the data */
|
||||||
len = arg->field.field->size ? : size - arg->field.field->offset;
|
len = field->size ? : size - field->offset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some events pass in pointers. If this is not an array
|
* Some events pass in pointers. If this is not an array
|
||||||
* and the size is the same as long_size, assume that it
|
* and the size is the same as long_size, assume that it
|
||||||
* is a pointer.
|
* is a pointer.
|
||||||
*/
|
*/
|
||||||
if (!(arg->field.field->flags & FIELD_IS_ARRAY) &&
|
if (!(field->flags & FIELD_IS_ARRAY) &&
|
||||||
arg->field.field->size == pevent->long_size) {
|
field->size == pevent->long_size) {
|
||||||
addr = *(unsigned long *)(data + arg->field.field->offset);
|
addr = *(unsigned long *)(data + field->offset);
|
||||||
trace_seq_printf(s, "%lx", addr);
|
trace_seq_printf(s, "%lx", addr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
str = malloc_or_die(len + 1);
|
str = malloc_or_die(len + 1);
|
||||||
memcpy(str, data + arg->field.field->offset, len);
|
memcpy(str, data + field->offset, len);
|
||||||
str[len] = 0;
|
str[len] = 0;
|
||||||
print_str_to_seq(s, format, len_arg, str);
|
print_str_to_seq(s, format, len_arg, str);
|
||||||
free(str);
|
free(str);
|
||||||
|
@ -3281,6 +3383,23 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case PRINT_HEX:
|
||||||
|
field = arg->hex.field->field.field;
|
||||||
|
if (!field) {
|
||||||
|
str = arg->hex.field->field.name;
|
||||||
|
field = pevent_find_any_field(event, str);
|
||||||
|
if (!field)
|
||||||
|
die("field %s not found", str);
|
||||||
|
arg->hex.field->field.field = field;
|
||||||
|
}
|
||||||
|
hex = data + field->offset;
|
||||||
|
len = eval_num_arg(data, size, event, arg->hex.size);
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (i)
|
||||||
|
trace_seq_putc(s, ' ');
|
||||||
|
trace_seq_printf(s, "%02x", hex[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case PRINT_TYPE:
|
case PRINT_TYPE:
|
||||||
break;
|
break;
|
||||||
|
@ -3299,7 +3418,7 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PRINT_BSTRING:
|
case PRINT_BSTRING:
|
||||||
trace_seq_printf(s, format, arg->string.string);
|
print_str_to_seq(s, format, len_arg, arg->string.string);
|
||||||
break;
|
break;
|
||||||
case PRINT_OP:
|
case PRINT_OP:
|
||||||
/*
|
/*
|
||||||
|
@ -3363,6 +3482,10 @@ process_defined_func(struct trace_seq *s, void *data, int size,
|
||||||
string = malloc_or_die(sizeof(*string));
|
string = malloc_or_die(sizeof(*string));
|
||||||
string->next = strings;
|
string->next = strings;
|
||||||
string->str = strdup(str.buffer);
|
string->str = strdup(str.buffer);
|
||||||
|
if (!string->str)
|
||||||
|
die("malloc str");
|
||||||
|
|
||||||
|
args[i] = (unsigned long long)string->str;
|
||||||
strings = string;
|
strings = string;
|
||||||
trace_seq_destroy(&str);
|
trace_seq_destroy(&str);
|
||||||
break;
|
break;
|
||||||
|
@ -3400,6 +3523,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||||
unsigned long long ip, val;
|
unsigned long long ip, val;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
void *bptr;
|
void *bptr;
|
||||||
|
int vsize;
|
||||||
|
|
||||||
field = pevent->bprint_buf_field;
|
field = pevent->bprint_buf_field;
|
||||||
ip_field = pevent->bprint_ip_field;
|
ip_field = pevent->bprint_ip_field;
|
||||||
|
@ -3448,6 +3572,8 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||||
goto process_again;
|
goto process_again;
|
||||||
case '0' ... '9':
|
case '0' ... '9':
|
||||||
goto process_again;
|
goto process_again;
|
||||||
|
case '.':
|
||||||
|
goto process_again;
|
||||||
case 'p':
|
case 'p':
|
||||||
ls = 1;
|
ls = 1;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
|
@ -3455,23 +3581,30 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||||
case 'u':
|
case 'u':
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'i':
|
case 'i':
|
||||||
|
switch (ls) {
|
||||||
|
case 0:
|
||||||
|
vsize = 4;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
vsize = pevent->long_size;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
vsize = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vsize = ls; /* ? */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case '*':
|
||||||
|
if (*ptr == '*')
|
||||||
|
vsize = 4;
|
||||||
|
|
||||||
/* the pointers are always 4 bytes aligned */
|
/* the pointers are always 4 bytes aligned */
|
||||||
bptr = (void *)(((unsigned long)bptr + 3) &
|
bptr = (void *)(((unsigned long)bptr + 3) &
|
||||||
~3);
|
~3);
|
||||||
switch (ls) {
|
val = pevent_read_number(pevent, bptr, vsize);
|
||||||
case 0:
|
bptr += vsize;
|
||||||
ls = 4;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
ls = pevent->long_size;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
ls = 8;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val = pevent_read_number(pevent, bptr, ls);
|
|
||||||
bptr += ls;
|
|
||||||
arg = alloc_arg();
|
arg = alloc_arg();
|
||||||
arg->next = NULL;
|
arg->next = NULL;
|
||||||
arg->type = PRINT_ATOM;
|
arg->type = PRINT_ATOM;
|
||||||
|
@ -3479,12 +3612,21 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
|
||||||
sprintf(arg->atom.atom, "%lld", val);
|
sprintf(arg->atom.atom, "%lld", val);
|
||||||
*next = arg;
|
*next = arg;
|
||||||
next = &arg->next;
|
next = &arg->next;
|
||||||
|
/*
|
||||||
|
* The '*' case means that an arg is used as the length.
|
||||||
|
* We need to continue to figure out for what.
|
||||||
|
*/
|
||||||
|
if (*ptr == '*')
|
||||||
|
goto process_again;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
arg = alloc_arg();
|
arg = alloc_arg();
|
||||||
arg->next = NULL;
|
arg->next = NULL;
|
||||||
arg->type = PRINT_BSTRING;
|
arg->type = PRINT_BSTRING;
|
||||||
arg->string.string = strdup(bptr);
|
arg->string.string = strdup(bptr);
|
||||||
|
if (!arg->string.string)
|
||||||
|
break;
|
||||||
bptr += strlen(bptr) + 1;
|
bptr += strlen(bptr) + 1;
|
||||||
*next = arg;
|
*next = arg;
|
||||||
next = &arg->next;
|
next = &arg->next;
|
||||||
|
@ -3589,6 +3731,16 @@ static void print_mac_arg(struct trace_seq *s, int mac, void *data, int size,
|
||||||
trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
trace_seq_printf(s, fmt, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_printable_array(char *p, unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < len && p[i]; i++)
|
||||||
|
if (!isprint(p[i]))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void print_event_fields(struct trace_seq *s, void *data, int size,
|
static void print_event_fields(struct trace_seq *s, void *data, int size,
|
||||||
struct event_format *event)
|
struct event_format *event)
|
||||||
{
|
{
|
||||||
|
@ -3608,7 +3760,8 @@ static void print_event_fields(struct trace_seq *s, void *data, int size,
|
||||||
len = offset >> 16;
|
len = offset >> 16;
|
||||||
offset &= 0xffff;
|
offset &= 0xffff;
|
||||||
}
|
}
|
||||||
if (field->flags & FIELD_IS_STRING) {
|
if (field->flags & FIELD_IS_STRING &&
|
||||||
|
is_printable_array(data + offset, len)) {
|
||||||
trace_seq_printf(s, "%s", (char *)data + offset);
|
trace_seq_printf(s, "%s", (char *)data + offset);
|
||||||
} else {
|
} else {
|
||||||
trace_seq_puts(s, "ARRAY[");
|
trace_seq_puts(s, "ARRAY[");
|
||||||
|
@ -3619,6 +3772,7 @@ static void print_event_fields(struct trace_seq *s, void *data, int size,
|
||||||
*((unsigned char *)data + offset + i));
|
*((unsigned char *)data + offset + i));
|
||||||
}
|
}
|
||||||
trace_seq_putc(s, ']');
|
trace_seq_putc(s, ']');
|
||||||
|
field->flags &= ~FIELD_IS_STRING;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val = pevent_read_number(event->pevent, data + field->offset,
|
val = pevent_read_number(event->pevent, data + field->offset,
|
||||||
|
@ -3758,6 +3912,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||||
} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
|
} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
|
||||||
print_mac_arg(s, *(ptr+1), data, size, event, arg);
|
print_mac_arg(s, *(ptr+1), data, size, event, arg);
|
||||||
ptr++;
|
ptr++;
|
||||||
|
arg = arg->next;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3794,14 +3949,15 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pevent->long_size == 8 && ls) {
|
if (pevent->long_size == 8 && ls &&
|
||||||
|
sizeof(long) != 8) {
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
ls = 2;
|
ls = 2;
|
||||||
/* make %l into %ll */
|
/* make %l into %ll */
|
||||||
p = strchr(format, 'l');
|
p = strchr(format, 'l');
|
||||||
if (p)
|
if (p)
|
||||||
memmove(p, p+1, strlen(p)+1);
|
memmove(p+1, p, strlen(p)+1);
|
||||||
else if (strcmp(format, "%p") == 0)
|
else if (strcmp(format, "%p") == 0)
|
||||||
strcpy(format, "0x%llx");
|
strcpy(format, "0x%llx");
|
||||||
}
|
}
|
||||||
|
@ -3878,8 +4034,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||||
* pevent_data_lat_fmt - parse the data for the latency format
|
* pevent_data_lat_fmt - parse the data for the latency format
|
||||||
* @pevent: a handle to the pevent
|
* @pevent: a handle to the pevent
|
||||||
* @s: the trace_seq to write to
|
* @s: the trace_seq to write to
|
||||||
* @data: the raw data to read from
|
* @record: the record to read from
|
||||||
* @size: currently unused.
|
|
||||||
*
|
*
|
||||||
* This parses out the Latency format (interrupts disabled,
|
* This parses out the Latency format (interrupts disabled,
|
||||||
* need rescheduling, in hard/soft interrupt, preempt count
|
* need rescheduling, in hard/soft interrupt, preempt count
|
||||||
|
@ -3889,10 +4044,13 @@ void pevent_data_lat_fmt(struct pevent *pevent,
|
||||||
struct trace_seq *s, struct pevent_record *record)
|
struct trace_seq *s, struct pevent_record *record)
|
||||||
{
|
{
|
||||||
static int check_lock_depth = 1;
|
static int check_lock_depth = 1;
|
||||||
|
static int check_migrate_disable = 1;
|
||||||
static int lock_depth_exists;
|
static int lock_depth_exists;
|
||||||
|
static int migrate_disable_exists;
|
||||||
unsigned int lat_flags;
|
unsigned int lat_flags;
|
||||||
unsigned int pc;
|
unsigned int pc;
|
||||||
int lock_depth;
|
int lock_depth;
|
||||||
|
int migrate_disable;
|
||||||
int hardirq;
|
int hardirq;
|
||||||
int softirq;
|
int softirq;
|
||||||
void *data = record->data;
|
void *data = record->data;
|
||||||
|
@ -3900,18 +4058,26 @@ void pevent_data_lat_fmt(struct pevent *pevent,
|
||||||
lat_flags = parse_common_flags(pevent, data);
|
lat_flags = parse_common_flags(pevent, data);
|
||||||
pc = parse_common_pc(pevent, data);
|
pc = parse_common_pc(pevent, data);
|
||||||
/* lock_depth may not always exist */
|
/* lock_depth may not always exist */
|
||||||
if (check_lock_depth) {
|
|
||||||
struct format_field *field;
|
|
||||||
struct event_format *event;
|
|
||||||
|
|
||||||
check_lock_depth = 0;
|
|
||||||
event = pevent->events[0];
|
|
||||||
field = pevent_find_common_field(event, "common_lock_depth");
|
|
||||||
if (field)
|
|
||||||
lock_depth_exists = 1;
|
|
||||||
}
|
|
||||||
if (lock_depth_exists)
|
if (lock_depth_exists)
|
||||||
lock_depth = parse_common_lock_depth(pevent, data);
|
lock_depth = parse_common_lock_depth(pevent, data);
|
||||||
|
else if (check_lock_depth) {
|
||||||
|
lock_depth = parse_common_lock_depth(pevent, data);
|
||||||
|
if (lock_depth < 0)
|
||||||
|
check_lock_depth = 0;
|
||||||
|
else
|
||||||
|
lock_depth_exists = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* migrate_disable may not always exist */
|
||||||
|
if (migrate_disable_exists)
|
||||||
|
migrate_disable = parse_common_migrate_disable(pevent, data);
|
||||||
|
else if (check_migrate_disable) {
|
||||||
|
migrate_disable = parse_common_migrate_disable(pevent, data);
|
||||||
|
if (migrate_disable < 0)
|
||||||
|
check_migrate_disable = 0;
|
||||||
|
else
|
||||||
|
migrate_disable_exists = 1;
|
||||||
|
}
|
||||||
|
|
||||||
hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
|
hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
|
||||||
softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
|
softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
|
||||||
|
@ -3930,6 +4096,13 @@ void pevent_data_lat_fmt(struct pevent *pevent,
|
||||||
else
|
else
|
||||||
trace_seq_putc(s, '.');
|
trace_seq_putc(s, '.');
|
||||||
|
|
||||||
|
if (migrate_disable_exists) {
|
||||||
|
if (migrate_disable < 0)
|
||||||
|
trace_seq_putc(s, '.');
|
||||||
|
else
|
||||||
|
trace_seq_printf(s, "%d", migrate_disable);
|
||||||
|
}
|
||||||
|
|
||||||
if (lock_depth_exists) {
|
if (lock_depth_exists) {
|
||||||
if (lock_depth < 0)
|
if (lock_depth < 0)
|
||||||
trace_seq_putc(s, '.');
|
trace_seq_putc(s, '.');
|
||||||
|
@ -3996,10 +4169,7 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
|
||||||
* pevent_data_comm_from_pid - parse the data into the print format
|
* pevent_data_comm_from_pid - parse the data into the print format
|
||||||
* @s: the trace_seq to write to
|
* @s: the trace_seq to write to
|
||||||
* @event: the handle to the event
|
* @event: the handle to the event
|
||||||
* @cpu: the cpu the event was recorded on
|
* @record: the record to read from
|
||||||
* @data: the raw data
|
|
||||||
* @size: the size of the raw data
|
|
||||||
* @nsecs: the timestamp of the event
|
|
||||||
*
|
*
|
||||||
* This parses the raw @data using the given @event information and
|
* This parses the raw @data using the given @event information and
|
||||||
* writes the print format into the trace_seq.
|
* writes the print format into the trace_seq.
|
||||||
|
@ -4279,6 +4449,13 @@ static void print_args(struct print_arg *args)
|
||||||
trace_seq_destroy(&s);
|
trace_seq_destroy(&s);
|
||||||
printf(")");
|
printf(")");
|
||||||
break;
|
break;
|
||||||
|
case PRINT_HEX:
|
||||||
|
printf("__print_hex(");
|
||||||
|
print_args(args->hex.field);
|
||||||
|
printf(", ");
|
||||||
|
print_args(args->hex.size);
|
||||||
|
printf(")");
|
||||||
|
break;
|
||||||
case PRINT_STRING:
|
case PRINT_STRING:
|
||||||
case PRINT_BSTRING:
|
case PRINT_BSTRING:
|
||||||
printf("__get_str(%s)", args->string.string);
|
printf("__get_str(%s)", args->string.string);
|
||||||
|
@ -4541,6 +4718,8 @@ int pevent_parse_event(struct pevent *pevent,
|
||||||
die("failed to read event id");
|
die("failed to read event id");
|
||||||
|
|
||||||
event->system = strdup(sys);
|
event->system = strdup(sys);
|
||||||
|
if (!event->system)
|
||||||
|
die("failed to allocate system");
|
||||||
|
|
||||||
/* Add pevent to event so that it can be referenced */
|
/* Add pevent to event so that it can be referenced */
|
||||||
event->pevent = pevent;
|
event->pevent = pevent;
|
||||||
|
@ -4582,6 +4761,11 @@ int pevent_parse_event(struct pevent *pevent,
|
||||||
list = &arg->next;
|
list = &arg->next;
|
||||||
arg->type = PRINT_FIELD;
|
arg->type = PRINT_FIELD;
|
||||||
arg->field.name = strdup(field->name);
|
arg->field.name = strdup(field->name);
|
||||||
|
if (!arg->field.name) {
|
||||||
|
do_warning("failed to allocate field name");
|
||||||
|
event->flags |= EVENT_FL_FAILED;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
arg->field.field = field;
|
arg->field.field = field;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -4753,7 +4937,7 @@ int pevent_get_any_field_val(struct trace_seq *s, struct event_format *event,
|
||||||
* @record: The record with the field name.
|
* @record: The record with the field name.
|
||||||
* @err: print default error if failed.
|
* @err: print default error if failed.
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -1 field not fould, or 1 if buffer is full.
|
* Returns: 0 on success, -1 field not found, or 1 if buffer is full.
|
||||||
*/
|
*/
|
||||||
int pevent_print_num_field(struct trace_seq *s, const char *fmt,
|
int pevent_print_num_field(struct trace_seq *s, const char *fmt,
|
||||||
struct event_format *event, const char *name,
|
struct event_format *event, const char *name,
|
||||||
|
@ -4795,11 +4979,12 @@ static void free_func_handle(struct pevent_function_handler *func)
|
||||||
* pevent_register_print_function - register a helper function
|
* pevent_register_print_function - register a helper function
|
||||||
* @pevent: the handle to the pevent
|
* @pevent: the handle to the pevent
|
||||||
* @func: the function to process the helper function
|
* @func: the function to process the helper function
|
||||||
|
* @ret_type: the return type of the helper function
|
||||||
* @name: the name of the helper function
|
* @name: the name of the helper function
|
||||||
* @parameters: A list of enum pevent_func_arg_type
|
* @parameters: A list of enum pevent_func_arg_type
|
||||||
*
|
*
|
||||||
* Some events may have helper functions in the print format arguments.
|
* Some events may have helper functions in the print format arguments.
|
||||||
* This allows a plugin to dynmically create a way to process one
|
* This allows a plugin to dynamically create a way to process one
|
||||||
* of these functions.
|
* of these functions.
|
||||||
*
|
*
|
||||||
* The @parameters is a variable list of pevent_func_arg_type enums that
|
* The @parameters is a variable list of pevent_func_arg_type enums that
|
||||||
|
@ -4870,12 +5055,13 @@ int pevent_register_print_function(struct pevent *pevent,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pevent_register_event_handle - register a way to parse an event
|
* pevent_register_event_handler - register a way to parse an event
|
||||||
* @pevent: the handle to the pevent
|
* @pevent: the handle to the pevent
|
||||||
* @id: the id of the event to register
|
* @id: the id of the event to register
|
||||||
* @sys_name: the system name the event belongs to
|
* @sys_name: the system name the event belongs to
|
||||||
* @event_name: the name of the event
|
* @event_name: the name of the event
|
||||||
* @func: the function to call to parse the event information
|
* @func: the function to call to parse the event information
|
||||||
|
* @context: the data to be passed to @func
|
||||||
*
|
*
|
||||||
* This function allows a developer to override the parsing of
|
* This function allows a developer to override the parsing of
|
||||||
* a given event. If for some reason the default print format
|
* a given event. If for some reason the default print format
|
||||||
|
@ -4925,6 +5111,11 @@ int pevent_register_event_handler(struct pevent *pevent,
|
||||||
if (sys_name)
|
if (sys_name)
|
||||||
handle->sys_name = strdup(sys_name);
|
handle->sys_name = strdup(sys_name);
|
||||||
|
|
||||||
|
if ((event_name && !handle->event_name) ||
|
||||||
|
(sys_name && !handle->sys_name)) {
|
||||||
|
die("Failed to allocate event/sys name");
|
||||||
|
}
|
||||||
|
|
||||||
handle->func = func;
|
handle->func = func;
|
||||||
handle->next = pevent->handlers;
|
handle->next = pevent->handlers;
|
||||||
pevent->handlers = handle;
|
pevent->handlers = handle;
|
||||||
|
|
|
@ -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 {
|
||||||
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 {
|
||||||
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)
|
||||||
(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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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
|
||||||
/* 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.
|
||||||
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.
|
||||||
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 @@
|
||||||
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[] = {
|
||||||
"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[] = {
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 @@
|
||||||
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[] = {
|
||||||
"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[] = {
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
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,
|
||||||
#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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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[] = {
|
||||||
.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[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#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)
|
||||||
{
|
{
|
||||||
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; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
if (test_pmu()) {
|
TEST_EVENTS(test__events);
|
||||||
ret = test_events(test__events_pmu,
|
|
||||||
TEST__EVENTS_PMU_CNT);
|
|
||||||
if (ret)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = test_terms(test__terms, TEST__TERMS_CNT);
|
if (test_pmu())
|
||||||
|
TEST_EVENTS(test__events_pmu);
|
||||||
|
|
||||||
} while (0);
|
return test_terms(test__terms, ARRAY_SIZE(test__terms));
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
#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",
|
||||||
|
.alias = "cycles",
|
||||||
|
},
|
||||||
|
[PERF_COUNT_HW_INSTRUCTIONS] = {
|
||||||
|
.symbol = "instructions",
|
||||||
|
.alias = "",
|
||||||
|
},
|
||||||
|
[PERF_COUNT_HW_CACHE_REFERENCES] = {
|
||||||
|
.symbol = "cache-references",
|
||||||
|
.alias = "",
|
||||||
|
},
|
||||||
|
[PERF_COUNT_HW_CACHE_MISSES] = {
|
||||||
|
.symbol = "cache-misses",
|
||||||
|
.alias = "",
|
||||||
|
},
|
||||||
|
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = {
|
||||||
|
.symbol = "branch-instructions",
|
||||||
|
.alias = "branches",
|
||||||
|
},
|
||||||
|
[PERF_COUNT_HW_BRANCH_MISSES] = {
|
||||||
|
.symbol = "branch-misses",
|
||||||
|
.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[] = {
|
static struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
|
||||||
{ CHW(CPU_CYCLES), "cpu-cycles", "cycles" },
|
[PERF_COUNT_SW_CPU_CLOCK] = {
|
||||||
{ CHW(STALLED_CYCLES_FRONTEND), "stalled-cycles-frontend", "idle-cycles-frontend" },
|
.symbol = "cpu-clock",
|
||||||
{ CHW(STALLED_CYCLES_BACKEND), "stalled-cycles-backend", "idle-cycles-backend" },
|
.alias = "",
|
||||||
{ CHW(INSTRUCTIONS), "instructions", "" },
|
},
|
||||||
{ CHW(CACHE_REFERENCES), "cache-references", "" },
|
[PERF_COUNT_SW_TASK_CLOCK] = {
|
||||||
{ CHW(CACHE_MISSES), "cache-misses", "" },
|
.symbol = "task-clock",
|
||||||
{ CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" },
|
.alias = "",
|
||||||
{ CHW(BRANCH_MISSES), "branch-misses", "" },
|
},
|
||||||
{ CHW(BUS_CYCLES), "bus-cycles", "" },
|
[PERF_COUNT_SW_PAGE_FAULTS] = {
|
||||||
{ CHW(REF_CPU_CYCLES), "ref-cycles", "" },
|
.symbol = "page-faults",
|
||||||
|
.alias = "faults",
|
||||||
{ CSW(CPU_CLOCK), "cpu-clock", "" },
|
},
|
||||||
{ CSW(TASK_CLOCK), "task-clock", "" },
|
[PERF_COUNT_SW_CONTEXT_SWITCHES] = {
|
||||||
{ CSW(PAGE_FAULTS), "page-faults", "faults" },
|
.symbol = "context-switches",
|
||||||
{ CSW(PAGE_FAULTS_MIN), "minor-faults", "" },
|
.alias = "cs",
|
||||||
{ CSW(PAGE_FAULTS_MAJ), "major-faults", "" },
|
},
|
||||||
{ CSW(CONTEXT_SWITCHES), "context-switches", "cs" },
|
[PERF_COUNT_SW_CPU_MIGRATIONS] = {
|
||||||
{ CSW(CPU_MIGRATIONS), "cpu-migrations", "migrations" },
|
.symbol = "cpu-migrations",
|
||||||
{ CSW(ALIGNMENT_FAULTS), "alignment-faults", "" },
|
.alias = "migrations",
|
||||||
{ CSW(EMULATION_FAULTS), "emulation-faults", "" },
|
},
|
||||||
|
[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)
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
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)
|
||||||
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)
|
||||||
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]+
|
||||||
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); }
|
||||||
, { 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 { \
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%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 { \
|
||||||
%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 '/'
|
||||||
$$ = 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 '/'
|
||||||
$$ = 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)
|
||||||
"%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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче