diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/Build | 3 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 7 | ||||
-rw-r--r-- | tools/perf/util/evsel_fprintf.c | 8 | ||||
-rw-r--r-- | tools/perf/util/perf-hooks-list.h | 3 | ||||
-rw-r--r-- | tools/perf/util/perf-hooks.c | 84 | ||||
-rw-r--r-- | tools/perf/util/perf-hooks.h | 37 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 8 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 6 | ||||
-rw-r--r-- | tools/perf/util/time-utils.c | 119 | ||||
-rw-r--r-- | tools/perf/util/time-utils.h | 14 | ||||
-rw-r--r-- | tools/perf/util/util.c | 33 | ||||
-rw-r--r-- | tools/perf/util/util.h | 2 |
12 files changed, 286 insertions, 38 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 1dc67efad634..bdad82a9812d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -87,6 +87,7 @@ libperf-y += help-unknown-cmd.o libperf-y += mem-events.o libperf-y += vsprintf.o libperf-y += drv_configs.o +libperf-y += time-utils.o libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o @@ -123,6 +124,8 @@ libperf-$(CONFIG_LIBELF) += genelf.o libperf-$(CONFIG_DWARF) += genelf_debug.o endif +libperf-y += perf-hooks.o + CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))" # avoid compiler warnings in 32-bit mode CFLAGS_genelf_debug.o += -Wno-packed diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 3e34ee0fde28..4012b1de2813 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -105,6 +105,7 @@ static int arch__associate_ins_ops(struct arch* arch, const char *name, struct i } #include "arch/arm/annotate/instructions.c" +#include "arch/arm64/annotate/instructions.c" #include "arch/x86/annotate/instructions.c" #include "arch/powerpc/annotate/instructions.c" @@ -114,6 +115,10 @@ static struct arch architectures[] = { .init = arm__annotate_init, }, { + .name = "arm64", + .init = arm64__annotate_init, + }, + { .name = "x86", .instructions = x86__instructions, .nr_instructions = ARRAY_SIZE(x86__instructions), @@ -408,7 +413,7 @@ static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops if (ops->target.raw == NULL) return -1; - comment = strchr(s, '#'); + comment = strchr(s, arch->objdump.comment_char); if (comment == NULL) return 0; diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 5a6f52284452..6b2925542c0a 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -166,6 +166,14 @@ int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, if (!print_oneline) printed += fprintf(fp, "\n"); + if (symbol_conf.bt_stop_list && + node->sym && + node->sym->name && + strlist__has_entry(symbol_conf.bt_stop_list, + node->sym->name)) { + break; + } + first = false; next: callchain_cursor_advance(cursor); diff --git a/tools/perf/util/perf-hooks-list.h b/tools/perf/util/perf-hooks-list.h new file mode 100644 index 000000000000..2867c07ee84e --- /dev/null +++ b/tools/perf/util/perf-hooks-list.h @@ -0,0 +1,3 @@ +PERF_HOOK(record_start) +PERF_HOOK(record_end) +PERF_HOOK(test) diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c new file mode 100644 index 000000000000..4ce88e37dd63 --- /dev/null +++ b/tools/perf/util/perf-hooks.c @@ -0,0 +1,84 @@ +/* + * perf_hooks.c + * + * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com> + * Copyright (C) 2016 Huawei Inc. + */ + +#include <errno.h> +#include <stdlib.h> +#include <setjmp.h> +#include <linux/err.h> +#include "util/util.h" +#include "util/debug.h" +#include "util/perf-hooks.h" + +static sigjmp_buf jmpbuf; +static const struct perf_hook_desc *current_perf_hook; + +void perf_hooks__invoke(const struct perf_hook_desc *desc) +{ + if (!(desc && desc->p_hook_func && *desc->p_hook_func)) + return; + + if (sigsetjmp(jmpbuf, 1)) { + pr_warning("Fatal error (SEGFAULT) in perf hook '%s'\n", + desc->hook_name); + *(current_perf_hook->p_hook_func) = NULL; + } else { + current_perf_hook = desc; + (**desc->p_hook_func)(); + } + current_perf_hook = NULL; +} + +void perf_hooks__recover(void) +{ + if (current_perf_hook) + siglongjmp(jmpbuf, 1); +} + +#define PERF_HOOK(name) \ +perf_hook_func_t __perf_hook_func_##name = NULL; \ +struct perf_hook_desc __perf_hook_desc_##name = \ + {.hook_name = #name, .p_hook_func = &__perf_hook_func_##name}; +#include "perf-hooks-list.h" +#undef PERF_HOOK + +#define PERF_HOOK(name) \ + &__perf_hook_desc_##name, + +static struct perf_hook_desc *perf_hooks[] = { +#include "perf-hooks-list.h" +}; +#undef PERF_HOOK + +int perf_hooks__set_hook(const char *hook_name, + perf_hook_func_t hook_func) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) { + if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0) + continue; + + if (*(perf_hooks[i]->p_hook_func)) + pr_warning("Overwrite existing hook: %s\n", hook_name); + *(perf_hooks[i]->p_hook_func) = hook_func; + return 0; + } + return -ENOENT; +} + +perf_hook_func_t perf_hooks__get_hook(const char *hook_name) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(perf_hooks); i++) { + if (strcmp(hook_name, perf_hooks[i]->hook_name) != 0) + continue; + + return *(perf_hooks[i]->p_hook_func); + } + return ERR_PTR(-ENOENT); +} diff --git a/tools/perf/util/perf-hooks.h b/tools/perf/util/perf-hooks.h new file mode 100644 index 000000000000..1d482b26b4b9 --- /dev/null +++ b/tools/perf/util/perf-hooks.h @@ -0,0 +1,37 @@ +#ifndef PERF_UTIL_PERF_HOOKS_H +#define PERF_UTIL_PERF_HOOKS_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*perf_hook_func_t)(void); +struct perf_hook_desc { + const char * const hook_name; + perf_hook_func_t * const p_hook_func; +}; + +extern void perf_hooks__invoke(const struct perf_hook_desc *); +extern void perf_hooks__recover(void); + +#define PERF_HOOK(name) \ +extern struct perf_hook_desc __perf_hook_desc_##name; \ +static inline void perf_hooks__invoke_##name(void) \ +{ \ + perf_hooks__invoke(&__perf_hook_desc_##name); \ +} + +#include "perf-hooks-list.h" +#undef PERF_HOOK + +extern int +perf_hooks__set_hook(const char *hook_name, + perf_hook_func_t hook_func); + +extern perf_hook_func_t +perf_hooks__get_hook(const char *hook_name); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 420ada9de22f..df2482b2ba45 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -2032,6 +2032,10 @@ int symbol__init(struct perf_env *env) symbol_conf.sym_list_str, "symbol") < 0) goto out_free_tid_list; + if (setup_list(&symbol_conf.bt_stop_list, + symbol_conf.bt_stop_list_str, "symbol") < 0) + goto out_free_sym_list; + /* * A path to symbols of "/" is identical to "" * reset here for simplicity. @@ -2049,6 +2053,8 @@ int symbol__init(struct perf_env *env) symbol_conf.initialized = true; return 0; +out_free_sym_list: + strlist__delete(symbol_conf.sym_list); out_free_tid_list: intlist__delete(symbol_conf.tid_list); out_free_pid_list: @@ -2064,6 +2070,7 @@ void symbol__exit(void) { if (!symbol_conf.initialized) return; + strlist__delete(symbol_conf.bt_stop_list); strlist__delete(symbol_conf.sym_list); strlist__delete(symbol_conf.dso_list); strlist__delete(symbol_conf.comm_list); @@ -2071,6 +2078,7 @@ void symbol__exit(void) intlist__delete(symbol_conf.pid_list); vmlinux_path__exit(); symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; + symbol_conf.bt_stop_list = NULL; symbol_conf.initialized = false; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1bcbefc0c325..6c358b7ed336 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -132,14 +132,16 @@ struct symbol_conf { *pid_list_str, *tid_list_str, *sym_list_str, - *col_width_list_str; + *col_width_list_str, + *bt_stop_list_str; struct strlist *dso_list, *comm_list, *sym_list, *dso_from_list, *dso_to_list, *sym_from_list, - *sym_to_list; + *sym_to_list, + *bt_stop_list; struct intlist *pid_list, *tid_list; const char *symfs; diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c new file mode 100644 index 000000000000..d1b21c72206d --- /dev/null +++ b/tools/perf/util/time-utils.c @@ -0,0 +1,119 @@ +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <linux/time64.h> +#include <time.h> +#include <errno.h> +#include <inttypes.h> + +#include "perf.h" +#include "debug.h" +#include "time-utils.h" + +int parse_nsec_time(const char *str, u64 *ptime) +{ + u64 time_sec, time_nsec; + char *end; + + time_sec = strtoul(str, &end, 10); + if (*end != '.' && *end != '\0') + return -1; + + if (*end == '.') { + int i; + char nsec_buf[10]; + + if (strlen(++end) > 9) + return -1; + + strncpy(nsec_buf, end, 9); + nsec_buf[9] = '\0'; + + /* make it nsec precision */ + for (i = strlen(nsec_buf); i < 9; i++) + nsec_buf[i] = '0'; + + time_nsec = strtoul(nsec_buf, &end, 10); + if (*end != '\0') + return -1; + } else + time_nsec = 0; + + *ptime = time_sec * NSEC_PER_SEC + time_nsec; + return 0; +} + +static int parse_timestr_sec_nsec(struct perf_time_interval *ptime, + char *start_str, char *end_str) +{ + if (start_str && (*start_str != '\0') && + (parse_nsec_time(start_str, &ptime->start) != 0)) { + return -1; + } + + if (end_str && (*end_str != '\0') && + (parse_nsec_time(end_str, &ptime->end) != 0)) { + return -1; + } + + return 0; +} + +int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr) +{ + char *start_str, *end_str; + char *d, *str; + int rc = 0; + + if (ostr == NULL || *ostr == '\0') + return 0; + + /* copy original string because we need to modify it */ + str = strdup(ostr); + if (str == NULL) + return -ENOMEM; + + ptime->start = 0; + ptime->end = 0; + + /* str has the format: <start>,<stop> + * variations: <start>, + * ,<stop> + * , + */ + start_str = str; + d = strchr(start_str, ','); + if (d) { + *d = '\0'; + ++d; + } + end_str = d; + + rc = parse_timestr_sec_nsec(ptime, start_str, end_str); + + free(str); + + /* make sure end time is after start time if it was given */ + if (rc == 0 && ptime->end && ptime->end < ptime->start) + return -EINVAL; + + pr_debug("start time %" PRIu64 ", ", ptime->start); + pr_debug("end time %" PRIu64 "\n", ptime->end); + + return rc; +} + +bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp) +{ + /* if time is not set don't drop sample */ + if (timestamp == 0) + return false; + + /* otherwise compare sample time to time window */ + if ((ptime->start && timestamp < ptime->start) || + (ptime->end && timestamp > ptime->end)) { + return true; + } + + return false; +} diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h new file mode 100644 index 000000000000..c1f197c4af6c --- /dev/null +++ b/tools/perf/util/time-utils.h @@ -0,0 +1,14 @@ +#ifndef _TIME_UTILS_H_ +#define _TIME_UTILS_H_ + +struct perf_time_interval { + u64 start, end; +}; + +int parse_nsec_time(const char *str, u64 *ptime); + +int perf_time__parse_str(struct perf_time_interval *ptime, const char *ostr); + +bool perf_time__skip_sample(struct perf_time_interval *ptime, u64 timestamp); + +#endif diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 67ac765da27a..9ddd98827d12 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -400,39 +400,6 @@ void sighandler_dump_stack(int sig) raise(sig); } -int parse_nsec_time(const char *str, u64 *ptime) -{ - u64 time_sec, time_nsec; - char *end; - - time_sec = strtoul(str, &end, 10); - if (*end != '.' && *end != '\0') - return -1; - - if (*end == '.') { - int i; - char nsec_buf[10]; - - if (strlen(++end) > 9) - return -1; - - strncpy(nsec_buf, end, 9); - nsec_buf[9] = '\0'; - - /* make it nsec precision */ - for (i = strlen(nsec_buf); i < 9; i++) - nsec_buf[i] = '0'; - - time_nsec = strtoul(nsec_buf, &end, 10); - if (*end != '\0') - return -1; - } else - time_nsec = 0; - - *ptime = time_sec * NSEC_PER_SEC + time_nsec; - return 0; -} - int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) { u64 sec = timestamp / NSEC_PER_SEC; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 79662d67891e..1d639e38aa82 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -179,8 +179,6 @@ static inline void *zalloc(size_t size) #undef tolower #undef toupper -int parse_nsec_time(const char *str, u64 *ptime); - extern unsigned char sane_ctype[256]; #define GIT_SPACE 0x01 #define GIT_DIGIT 0x02 |