From 2f84b42b28eed0f980200401077e51571202f868 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 1 Sep 2015 11:47:19 -0700 Subject: [PATCH 001/260] perf tools: Always use non inlined file name for 'srcfile' sort key When profiling the kernel with the 'srcfile' sort key it's common to "get stuck" in include. For example a lot of code uses current or other inlines, so they get accounted to some random include file. This is not very useful as a high level categorization. For example just profiling the idle loop usually shows mostly inlines, so you never see the actual cpuidle file. This patch changes the 'srcfile' sort key to always unwind the inline stack using BFD/DWARF. So we always account to the base function that called the inline. In a few cases include is still shown (for example for MSR accesses), but that is because they get inlining expanded as part of assigning to a global function pointer. For the majority it works fine though. v2: Use simpler while loop. Add maximum iteration count. Signed-off-by: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1441133239-31254-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 4 ++-- tools/perf/util/srcline.c | 29 ++++++++++++++++++++++++----- tools/perf/util/util.h | 2 ++ 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 7e3871606df3..a97bceeac0e7 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -328,8 +328,8 @@ static char *get_srcfile(struct hist_entry *e) char *sf, *p; struct map *map = e->ms.map; - sf = get_srcline(map->dso, map__rip_2objdump(map, e->ip), - e->ms.sym, true); + sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), + e->ms.sym, false, true); if (!strcmp(sf, SRCLINE_UNKNOWN)) return no_srcfile; p = strchr(sf, ':'); diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index fc08248f08ca..b4db3f48e3b0 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -149,8 +149,11 @@ static void addr2line_cleanup(struct a2l_data *a2l) free(a2l); } +#define MAX_INLINE_NEST 1024 + static int addr2line(const char *dso_name, u64 addr, - char **file, unsigned int *line, struct dso *dso) + char **file, unsigned int *line, struct dso *dso, + bool unwind_inlines) { int ret = 0; struct a2l_data *a2l = dso->a2l; @@ -170,6 +173,15 @@ static int addr2line(const char *dso_name, u64 addr, bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); + if (a2l->found && unwind_inlines) { + int cnt = 0; + + while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, + &a2l->funcname, &a2l->line) && + cnt++ < MAX_INLINE_NEST) + ; + } + if (a2l->found && a2l->filename) { *file = strdup(a2l->filename); *line = a2l->line; @@ -197,7 +209,8 @@ void dso__free_a2l(struct dso *dso) static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line_nr, - struct dso *dso __maybe_unused) + struct dso *dso __maybe_unused, + bool unwind_inlines __maybe_unused) { FILE *fp; char cmd[PATH_MAX]; @@ -254,8 +267,8 @@ void dso__free_a2l(struct dso *dso __maybe_unused) */ #define A2L_FAIL_LIMIT 123 -char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, - bool show_sym) +char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, + bool show_sym, bool unwind_inlines) { char *file = NULL; unsigned line = 0; @@ -276,7 +289,7 @@ char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, if (!strncmp(dso_name, "/tmp/perf-", 10)) goto out; - if (!addr2line(dso_name, addr, &file, &line, dso)) + if (!addr2line(dso_name, addr, &file, &line, dso, unwind_inlines)) goto out; if (asprintf(&srcline, "%s:%u", @@ -310,3 +323,9 @@ void free_srcline(char *srcline) if (srcline && strcmp(srcline, SRCLINE_UNKNOWN) != 0) free(srcline); } + +char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, + bool show_sym) +{ + return __get_srcline(dso, addr, sym, show_sym, false); +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 291be1d84bc3..09c1a8b7b4c2 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -321,6 +321,8 @@ struct symbol; extern bool srcline_full_filename; char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, bool show_sym); +char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym, + bool show_sym, bool unwind_inlines); void free_srcline(char *srcline); int filename__read_str(const char *filename, char **buf, size_t *sizep); From dabf626f7f0e5cbef0d1cfb5143e40213f079bb8 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Sat, 29 Aug 2015 04:21:55 +0000 Subject: [PATCH 002/260] perf tools: Copy linux/filter.h to tools/include This patch copies filter.h from include/linux/kernel.h to tools/include/linux/filter.h to enable other libraries to use macros in it, like libbpf which will be introduced by further patches. Currently, the filter.h copy only contains the useful macros needed by libbpf for not introducing too much dependence. tools/perf/MANIFEST is also updated for 'make perf-*-src-pkg'. One change: The 'imm' field of BPF_EMIT_CALL becomes ((FUNC) - BPF_FUNC_unspec) to suit user space code generator. Signed-off-by: He Kuang Cc: David Ahern Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Wang Nan Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1440822125-52691-22-git-send-email-wangnan0@huawei.com Signed-off-by: Wang Nan [ Removed stylistic changes, so that a diff to the original file gets reduced ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/filter.h | 231 +++++++++++++++++++++++++++++++++++ tools/perf/MANIFEST | 1 + 2 files changed, 232 insertions(+) create mode 100644 tools/include/linux/filter.h diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h new file mode 100644 index 000000000000..3276625595b2 --- /dev/null +++ b/tools/include/linux/filter.h @@ -0,0 +1,231 @@ +/* + * Linux Socket Filter Data Structures + */ +#ifndef __TOOLS_LINUX_FILTER_H +#define __TOOLS_LINUX_FILTER_H + +#include + +/* ArgX, context and stack frame pointer register positions. Note, + * Arg1, Arg2, Arg3, etc are used as argument mappings of function + * calls in BPF_CALL instruction. + */ +#define BPF_REG_ARG1 BPF_REG_1 +#define BPF_REG_ARG2 BPF_REG_2 +#define BPF_REG_ARG3 BPF_REG_3 +#define BPF_REG_ARG4 BPF_REG_4 +#define BPF_REG_ARG5 BPF_REG_5 +#define BPF_REG_CTX BPF_REG_6 +#define BPF_REG_FP BPF_REG_10 + +/* Additional register mappings for converted user programs. */ +#define BPF_REG_A BPF_REG_0 +#define BPF_REG_X BPF_REG_7 +#define BPF_REG_TMP BPF_REG_8 + +/* BPF program can access up to 512 bytes of stack space. */ +#define MAX_BPF_STACK 512 + +/* Helper macros for filter block array initializers. */ + +/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ + +#define BPF_ALU64_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + +#define BPF_ALU32_REG(OP, DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + +/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */ + +#define BPF_ALU64_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_ALU32_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */ + +#define BPF_ENDIAN(TYPE, DST, LEN) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_END | BPF_SRC(TYPE), \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = LEN }) + +/* Short form of mov, dst_reg = src_reg */ + +#define BPF_MOV64_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + +#define BPF_MOV32_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + +/* Short form of mov, dst_reg = imm32 */ + +#define BPF_MOV64_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_MOV32_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */ + +#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE), \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU | BPF_MOV | BPF_SRC(TYPE), \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = IMM }) + +/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */ + +#define BPF_LD_ABS(SIZE, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */ + +#define BPF_LD_IND(SIZE, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_SIZE(SIZE) | BPF_IND, \ + .dst_reg = 0, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = IMM }) + +/* Memory load, dst_reg = *(uint *) (src_reg + off16) */ + +#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) + +/* Memory store, *(uint *) (dst_reg + off16) = src_reg */ + +#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) + +/* Memory store, *(uint *) (dst_reg + off16) = imm32 */ + +#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) + +/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */ + +#define BPF_JMP_REG(OP, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_OP(OP) | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = 0 }) + +/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */ + +#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) + +/* Function call */ + +#define BPF_EMIT_CALL(FUNC) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_CALL, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((FUNC) - BPF_FUNC_unspec) }) + +/* Raw code statement block */ + +#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \ + ((struct bpf_insn) { \ + .code = CODE, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = IMM }) + +/* Program exit */ + +#define BPF_EXIT_INSN() \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_EXIT, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) + +#endif /* __TOOLS_LINUX_FILTER_H */ diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index af009bd6e6b7..2a958a80c763 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -41,6 +41,7 @@ tools/include/asm-generic/bitops.h tools/include/linux/atomic.h tools/include/linux/bitops.h tools/include/linux/compiler.h +tools/include/linux/filter.h tools/include/linux/hash.h tools/include/linux/kernel.h tools/include/linux/list.h From 76055940c1afc8d445992fb0278b80cf205bbf97 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Sat, 29 Aug 2015 04:22:05 +0000 Subject: [PATCH 003/260] tools lib traceevent: Support function __get_dynamic_array_len Support helper function __get_dynamic_array_len() in libtraceevent, this function is used accompany with __print_array() or __print_hex(), but currently it is not an available function in the function list of process_function(). The total allocated length of the dynamic array is embedded in the top half of __data_loc_##item field. This patch adds new arg type PRINT_DYNAMIC_ARRAY_LEN to return the length to eval_num_arg(), Signed-off-by: He Kuang Acked-by: Namhyung Kim Cc: Alexei Starovoitov Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Steven Rostedt Cc: Wang Nan Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1440822125-52691-32-git-send-email-wangnan0@huawei.com Signed-off-by: Wang Nan Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 56 ++++++++++++++++++- tools/lib/traceevent/event-parse.h | 1 + .../util/scripting-engines/trace-event-perl.c | 1 + .../scripting-engines/trace-event-python.c | 1 + 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 4d885934b919..12447978a921 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -848,6 +848,7 @@ static void free_arg(struct print_arg *arg) free(arg->bitmask.bitmask); break; case PRINT_DYNAMIC_ARRAY: + case PRINT_DYNAMIC_ARRAY_LEN: free(arg->dynarray.index); break; case PRINT_OP: @@ -2728,6 +2729,42 @@ process_dynamic_array(struct event_format *event, struct print_arg *arg, char ** return EVENT_ERROR; } +static enum event_type +process_dynamic_array_len(struct event_format *event, struct print_arg *arg, + char **tok) +{ + struct format_field *field; + enum event_type type; + char *token; + + if (read_expect_type(EVENT_ITEM, &token) < 0) + goto out_free; + + arg->type = PRINT_DYNAMIC_ARRAY_LEN; + + /* Find the field */ + field = pevent_find_field(event, token); + if (!field) + goto out_free; + + arg->dynarray.field = field; + arg->dynarray.index = 0; + + if (read_expected(EVENT_DELIM, ")") < 0) + goto out_err; + + type = read_token(&token); + *tok = token; + + return type; + + out_free: + free_token(token); + out_err: + *tok = NULL; + return EVENT_ERROR; +} + static enum event_type process_paren(struct event_format *event, struct print_arg *arg, char **tok) { @@ -2975,6 +3012,10 @@ process_function(struct event_format *event, struct print_arg *arg, free_token(token); return process_dynamic_array(event, arg, tok); } + if (strcmp(token, "__get_dynamic_array_len") == 0) { + free_token(token); + return process_dynamic_array_len(event, arg, tok); + } func = find_func_handler(event->pevent, token); if (func) { @@ -3655,14 +3696,25 @@ eval_num_arg(void *data, int size, struct event_format *event, struct print_arg goto out_warning_op; } break; + case PRINT_DYNAMIC_ARRAY_LEN: + offset = pevent_read_number(pevent, + data + arg->dynarray.field->offset, + arg->dynarray.field->size); + /* + * The total allocated length of the dynamic array is + * stored in the top half of the field, and the offset + * is in the bottom half of the 32 bit field. + */ + val = (unsigned long long)(offset >> 16); + break; case PRINT_DYNAMIC_ARRAY: /* Without [], we pass the address to the dynamic data */ offset = pevent_read_number(pevent, data + arg->dynarray.field->offset, arg->dynarray.field->size); /* - * The actual length of the dynamic array is stored - * in the top half of the field, and the offset + * The total allocated length of the dynamic array is + * stored in the top half of the field, and the offset * is in the bottom half of the 32 bit field. */ offset &= 0xffff; diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h index 204befb05a17..6fc83c7edbe9 100644 --- a/tools/lib/traceevent/event-parse.h +++ b/tools/lib/traceevent/event-parse.h @@ -294,6 +294,7 @@ enum print_arg_type { PRINT_OP, PRINT_FUNC, PRINT_BITMASK, + PRINT_DYNAMIC_ARRAY_LEN, }; struct print_arg { diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 1bd593bbf7a5..544509c159ce 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -221,6 +221,7 @@ static void define_event_symbols(struct event_format *event, break; case PRINT_BSTRING: case PRINT_DYNAMIC_ARRAY: + case PRINT_DYNAMIC_ARRAY_LEN: case PRINT_STRING: case PRINT_BITMASK: break; diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index ace2484985cb..aa9e1257c1ee 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -251,6 +251,7 @@ static void define_event_symbols(struct event_format *event, /* gcc warns for these? */ case PRINT_BSTRING: case PRINT_DYNAMIC_ARRAY: + case PRINT_DYNAMIC_ARRAY_LEN: case PRINT_FUNC: case PRINT_BITMASK: /* we should warn... */ From 193b6bd339ccb30c861a307a915d4532f443e0fb Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 1 Sep 2015 09:58:11 -0400 Subject: [PATCH 004/260] perf cpumap: Factor out functions to get core_id and socket_id This patch moves the code which reads core_id and socket_id into separate functions. Signed-off-by: Kan Liang Cc: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1441115893-22006-1-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 51 ++++++++++++++++++++++++++-------------- tools/perf/util/cpumap.h | 2 ++ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 3667e2123e5b..a05d76ab18d8 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -225,17 +225,12 @@ void cpu_map__put(struct cpu_map *map) cpu_map__delete(map); } -int cpu_map__get_socket(struct cpu_map *map, int idx) +int cpu_map__get_socket_id(int cpu) { FILE *fp; const char *mnt; char path[PATH_MAX]; - int cpu, ret; - - if (idx > map->nr) - return -1; - - cpu = map->map[idx]; + int socket_id, ret; mnt = sysfs__mountpoint(); if (!mnt) @@ -248,9 +243,22 @@ int cpu_map__get_socket(struct cpu_map *map, int idx) fp = fopen(path, "r"); if (!fp) return -1; - ret = fscanf(fp, "%d", &cpu); + ret = fscanf(fp, "%d", &socket_id); fclose(fp); - return ret == 1 ? cpu : -1; + + return ret == 1 ? socket_id : -1; +} + +int cpu_map__get_socket(struct cpu_map *map, int idx) +{ + int cpu; + + if (idx > map->nr) + return -1; + + cpu = map->map[idx]; + + return cpu_map__get_socket_id(cpu); } static int cmp_ids(const void *a, const void *b) @@ -289,17 +297,12 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, return 0; } -int cpu_map__get_core(struct cpu_map *map, int idx) +int cpu_map__get_core_id(int cpu) { FILE *fp; const char *mnt; char path[PATH_MAX]; - int cpu, ret, s; - - if (idx > map->nr) - return -1; - - cpu = map->map[idx]; + int core_id, ret; mnt = sysfs__mountpoint(); if (!mnt) @@ -312,11 +315,23 @@ int cpu_map__get_core(struct cpu_map *map, int idx) fp = fopen(path, "r"); if (!fp) return -1; - ret = fscanf(fp, "%d", &cpu); + ret = fscanf(fp, "%d", &core_id); fclose(fp); - if (ret != 1) + + return ret == 1 ? core_id : -1; +} + +int cpu_map__get_core(struct cpu_map *map, int idx) +{ + int cpu, s; + + if (idx > map->nr) return -1; + cpu = map->map[idx]; + + cpu = cpu_map__get_core_id(cpu); + s = cpu_map__get_socket(map, idx); if (s == -1) return -1; diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 0af9cecb4c51..8982d538da83 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -18,7 +18,9 @@ struct cpu_map *cpu_map__new(const char *cpu_list); struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); +int cpu_map__get_socket_id(int cpu); int cpu_map__get_socket(struct cpu_map *map, int idx); +int cpu_map__get_core_id(int cpu); int cpu_map__get_core(struct cpu_map *map, int idx); int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); From 2bb00d2f95193aea5bfa98392907273115c96920 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 1 Sep 2015 09:58:12 -0400 Subject: [PATCH 005/260] perf tools: Store the cpu socket and core ids in the perf.data header This patch stores the cpu socket_id and core_id in a perf.data header, and reads them into the perf_env struct when processing perf.data files. The changes modifies the CPU_TOPOLOGY section, making sure it is backward/forward compatible. The patch checks the section size before reading the core and socket ids. It never reads data crossing the section boundary. An old perf binary without this patch can also correctly read the perf.data from a new perf with this patch. Because the new info is added at the end of the cpu_topology section, an old perf tool ignores the extra data. Examples: 1. New perf with this patch read perf.data from an old perf without the patch: $ perf_new report -i perf_old.data --header-only -I ...... # sibling threads : 33 # sibling threads : 34 # sibling threads : 35 # Core ID and Socket ID information is not available # node0 meminfo : total = 32823872 kB, free = 29315548 kB # node0 cpu list : 0-17,36-53 ...... 2. Old perf without the patch reads perf.data from a new perf with the patch: $ perf_old report -i perf_new.data --header-only -I ...... # sibling threads : 33 # sibling threads : 34 # sibling threads : 35 # node0 meminfo : total = 32823872 kB, free = 29190932 kB # node0 cpu list : 0-17,36-53 ...... 3. New perf read new perf.data: $ perf_new report -i perf_new.data --header-only -I ...... # sibling threads : 33 # sibling threads : 34 # sibling threads : 35 # CPU 0: Core ID 0, Socket ID 0 # CPU 1: Core ID 1, Socket ID 0 ...... # CPU 61: Core ID 10, Socket ID 1 # CPU 62: Core ID 11, Socket ID 1 # CPU 63: Core ID 16, Socket ID 1 # node0 meminfo : total = 32823872 kB, free = 29190932 kB # node0 cpu list : 0-17,36-53 Signed-off-by: Kan Liang Cc: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1441115893-22006-2-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 94 ++++++++++++++++++++++++++++++++++++--- tools/perf/util/header.h | 6 +++ tools/perf/util/session.c | 1 + 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 41814547da15..8fd7b7de1acd 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -88,6 +88,9 @@ int write_padded(int fd, const void *bf, size_t count, size_t count_aligned) return err; } +#define string_size(str) \ + (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) + static int do_write_string(int fd, const char *str) { u32 len, olen; @@ -441,10 +444,13 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list" struct cpu_topo { + u32 cpu_nr; u32 core_sib; u32 thread_sib; char **core_siblings; char **thread_siblings; + int *core_id; + int *phy_pkg_id; }; static int build_cpu_topo(struct cpu_topo *tp, int cpu) @@ -507,6 +513,9 @@ try_threads: } ret = 0; done: + tp->core_id[cpu] = cpu_map__get_core_id(cpu); + tp->phy_pkg_id[cpu] = cpu_map__get_socket_id(cpu); + if(fp) fclose(fp); free(buf); @@ -534,7 +543,7 @@ static struct cpu_topo *build_cpu_topology(void) struct cpu_topo *tp; void *addr; u32 nr, i; - size_t sz; + size_t sz, sz_id; long ncpus; int ret = -1; @@ -545,17 +554,22 @@ static struct cpu_topo *build_cpu_topology(void) nr = (u32)(ncpus & UINT_MAX); sz = nr * sizeof(char *); + sz_id = nr * sizeof(int); - addr = calloc(1, sizeof(*tp) + 2 * sz); + addr = calloc(1, sizeof(*tp) + 2 * sz + 2 * sz_id); if (!addr) return NULL; tp = addr; - + tp->cpu_nr = nr; addr += sizeof(*tp); tp->core_siblings = addr; addr += sz; tp->thread_siblings = addr; + addr += sz; + tp->core_id = addr; + addr += sz_id; + tp->phy_pkg_id = addr; for (i = 0; i < nr; i++) { ret = build_cpu_topo(tp, i); @@ -598,6 +612,15 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, if (ret < 0) break; } + + for (i = 0; i < tp->cpu_nr; i++) { + ret = do_write(fd, &tp->core_id[i], sizeof(int)); + if (ret < 0) + return ret; + ret = do_write(fd, &tp->phy_pkg_id[i], sizeof(int)); + if (ret < 0) + return ret; + } done: free_cpu_topo(tp); return ret; @@ -938,6 +961,7 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused, { int nr, i; char *str; + int cpu_nr = ph->env.nr_cpus_online; nr = ph->env.nr_sibling_cores; str = ph->env.sibling_cores; @@ -954,6 +978,13 @@ static void print_cpu_topology(struct perf_header *ph, int fd __maybe_unused, fprintf(fp, "# sibling threads : %s\n", str); str += strlen(str) + 1; } + + if (ph->env.cpu != NULL) { + for (i = 0; i < cpu_nr; i++) + fprintf(fp, "# CPU %d: Core ID %d, Socket ID %d\n", i, + ph->env.cpu[i].core_id, ph->env.cpu[i].socket_id); + } else + fprintf(fp, "# Core ID and Socket ID information is not available\n"); } static void free_event_desc(struct perf_evsel *events) @@ -1582,7 +1613,7 @@ error: return -1; } -static int process_cpu_topology(struct perf_file_section *section __maybe_unused, +static int process_cpu_topology(struct perf_file_section *section, struct perf_header *ph, int fd, void *data __maybe_unused) { @@ -1590,15 +1621,22 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused u32 nr, i; char *str; struct strbuf sb; + int cpu_nr = ph->env.nr_cpus_online; + u64 size = 0; + + ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); + if (!ph->env.cpu) + return -1; ret = readn(fd, &nr, sizeof(nr)); if (ret != sizeof(nr)) - return -1; + goto free_cpu; if (ph->needs_swap) nr = bswap_32(nr); ph->env.nr_sibling_cores = nr; + size += sizeof(u32); strbuf_init(&sb, 128); for (i = 0; i < nr; i++) { @@ -1608,6 +1646,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused /* include a NULL character at the end */ strbuf_add(&sb, str, strlen(str) + 1); + size += string_size(str); free(str); } ph->env.sibling_cores = strbuf_detach(&sb, NULL); @@ -1620,6 +1659,7 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused nr = bswap_32(nr); ph->env.nr_sibling_threads = nr; + size += sizeof(u32); for (i = 0; i < nr; i++) { str = do_read_string(fd, ph); @@ -1628,13 +1668,57 @@ static int process_cpu_topology(struct perf_file_section *section __maybe_unused /* include a NULL character at the end */ strbuf_add(&sb, str, strlen(str) + 1); + size += string_size(str); free(str); } ph->env.sibling_threads = strbuf_detach(&sb, NULL); + + /* + * The header may be from old perf, + * which doesn't include core id and socket id information. + */ + if (section->size <= size) { + zfree(&ph->env.cpu); + return 0; + } + + for (i = 0; i < (u32)cpu_nr; i++) { + ret = readn(fd, &nr, sizeof(nr)); + if (ret != sizeof(nr)) + goto free_cpu; + + if (ph->needs_swap) + nr = bswap_32(nr); + + if (nr > (u32)cpu_nr) { + pr_debug("core_id number is too big." + "You may need to upgrade the perf tool.\n"); + goto free_cpu; + } + ph->env.cpu[i].core_id = nr; + + ret = readn(fd, &nr, sizeof(nr)); + if (ret != sizeof(nr)) + goto free_cpu; + + if (ph->needs_swap) + nr = bswap_32(nr); + + if (nr > (u32)cpu_nr) { + pr_debug("socket_id number is too big." + "You may need to upgrade the perf tool.\n"); + goto free_cpu; + } + + ph->env.cpu[i].socket_id = nr; + } + return 0; error: strbuf_release(&sb); +free_cpu: + zfree(&ph->env.cpu); return -1; } diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 396e4965f0c9..975d803f46c8 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -66,6 +66,11 @@ struct perf_header; int perf_file_header__read(struct perf_file_header *header, struct perf_header *ph, int fd); +struct cpu_topology_map { + int socket_id; + int core_id; +}; + struct perf_env { char *hostname; char *os_release; @@ -89,6 +94,7 @@ struct perf_env { char *sibling_threads; char *numa_nodes; char *pmu_mappings; + struct cpu_topology_map *cpu; }; struct perf_header { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8a4537ee9bc3..61669be15056 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -185,6 +185,7 @@ static void perf_session_env__exit(struct perf_env *env) zfree(&env->sibling_threads); zfree(&env->numa_nodes); zfree(&env->pmu_mappings); + zfree(&env->cpu); } void perf_session__delete(struct perf_session *session) From 245bad8eb45fca36638da53fb0a361397a707001 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 1 Sep 2015 15:52:46 -0700 Subject: [PATCH 006/260] perf stat: Quieten failed to read counter message Since 3b3eb0445 running perf stat on a system without backend-stalled-cycles spits out ugly warnings by default. Since that is quite common, make the message a debug message only. We know anyways that the counter wasn't read by the normal output. Signed-off-by: Andi Kleen Acked-by: Jiri Olsa Link: http://lkml.kernel.org/r/1441147966-14917-1-git-send-email-andi@firstfloor.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index d46dbb1bc65d..a96fb5c3bedb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -215,7 +215,7 @@ static void read_counters(bool close_counters) evlist__for_each(evsel_list, counter) { if (read_counter(counter)) - pr_warning("failed to read counter %s\n", counter->name); + pr_debug("failed to read counter %s\n", counter->name); if (perf_stat_process_counter(&stat_config, counter)) pr_warning("failed to process counter %s\n", counter->name); From f6a09af7de3b39b1e4fcff7374871f834498b7f0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:32 +0200 Subject: [PATCH 007/260] perf tools: Remove mountpoint arg from perf_debugfs_mount It's not used by any caller. We either detect the mountpoint or use hardcoded one. Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 2 +- tools/perf/util/util.c | 14 +++++++------- tools/perf/util/util.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 07dbff5c0e60..f500a4b40722 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -518,7 +518,7 @@ int main(int argc, const char **argv) if (!cmd) cmd = "perf-help"; /* get debugfs mount point from /proc/mounts */ - perf_debugfs_mount(NULL); + perf_debugfs_mount(); /* * "perf-xxxx" is the same as "perf xxxx", but we obviously: * diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 7acafb3c5592..74f71f8afcc2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -398,11 +398,11 @@ static void set_tracing_events_path(const char *tracing, const char *mountpoint) mountpoint, tracing, "events"); } -static const char *__perf_tracefs_mount(const char *mountpoint) +static const char *__perf_tracefs_mount(void) { const char *mnt; - mnt = tracefs_mount(mountpoint); + mnt = tracefs_mount(NULL); if (!mnt) return NULL; @@ -411,11 +411,11 @@ static const char *__perf_tracefs_mount(const char *mountpoint) return mnt; } -static const char *__perf_debugfs_mount(const char *mountpoint) +static const char *__perf_debugfs_mount(void) { const char *mnt; - mnt = debugfs_mount(mountpoint); + mnt = debugfs_mount(NULL); if (!mnt) return NULL; @@ -424,15 +424,15 @@ static const char *__perf_debugfs_mount(const char *mountpoint) return mnt; } -const char *perf_debugfs_mount(const char *mountpoint) +const char *perf_debugfs_mount(void) { const char *mnt; - mnt = __perf_tracefs_mount(mountpoint); + mnt = __perf_tracefs_mount(); if (mnt) return mnt; - mnt = __perf_debugfs_mount(mountpoint); + mnt = __perf_debugfs_mount(); return mnt; } diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 09c1a8b7b4c2..48ec232b6f66 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -86,7 +86,7 @@ extern char buildid_dir[]; extern char tracing_path[]; extern char tracing_events_path[]; extern void perf_debugfs_set_path(const char *mountpoint); -const char *perf_debugfs_mount(const char *mountpoint); +const char *perf_debugfs_mount(void); char *get_tracing_file(const char *name); void put_tracing_file(char *file); From 65d4b265103a3cb2f0993c946815157a38797421 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:33 +0200 Subject: [PATCH 008/260] perf tools: Move tracing_path stuff under same namespace Renaming all functions touching tracing_path under same namespace. New interface is: char tracing_path[]; - tracing mount path char tracing_events_path[]; - tracing mount/events path void tracing_path_set(const char *mountpoint); - setting directly tracing_path(_events), used by --debugfs-dir option const char *tracing_path_mount(void); - initial setup of tracing_(events)_path, called from perf.c mounts debugfs/tracefs if needed and possible char *get_tracing_file(const char *name); void put_tracing_file(char *file); - get/put tracing file path Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 10 ++++++---- tools/perf/util/util.c | 20 ++++++++++---------- tools/perf/util/util.h | 4 ++-- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index f500a4b40722..0e99cd1de9dd 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -214,7 +214,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "No directory given for --debugfs-dir.\n"); usage(perf_usage_string); } - perf_debugfs_set_path((*argv)[1]); + tracing_path_set((*argv)[1]); if (envchanged) *envchanged = 1; (*argv)++; @@ -230,7 +230,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) (*argv)++; (*argc)--; } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { - perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); + tracing_path_set(cmd + strlen(CMD_DEBUGFS_DIR)); fprintf(stderr, "dir: %s\n", tracing_path); if (envchanged) *envchanged = 1; @@ -517,8 +517,10 @@ int main(int argc, const char **argv) cmd = perf_extract_argv0_path(argv[0]); if (!cmd) cmd = "perf-help"; - /* get debugfs mount point from /proc/mounts */ - perf_debugfs_mount(); + + /* get debugfs/tracefs mount point from /proc/mounts */ + tracing_path_mount(); + /* * "perf-xxxx" is the same as "perf xxxx", but we obviously: * diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 74f71f8afcc2..b959f783f6cd 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -390,7 +390,7 @@ void set_term_quiet_input(struct termios *old) tcsetattr(0, TCSANOW, &tc); } -static void set_tracing_events_path(const char *tracing, const char *mountpoint) +static void __tracing_path_set(const char *tracing, const char *mountpoint) { snprintf(tracing_path, sizeof(tracing_path), "%s/%s", mountpoint, tracing); @@ -398,7 +398,7 @@ static void set_tracing_events_path(const char *tracing, const char *mountpoint) mountpoint, tracing, "events"); } -static const char *__perf_tracefs_mount(void) +static const char *tracing_path_tracefs_mount(void) { const char *mnt; @@ -406,12 +406,12 @@ static const char *__perf_tracefs_mount(void) if (!mnt) return NULL; - set_tracing_events_path("", mnt); + __tracing_path_set("", mnt); return mnt; } -static const char *__perf_debugfs_mount(void) +static const char *tracing_path_debugfs_mount(void) { const char *mnt; @@ -419,27 +419,27 @@ static const char *__perf_debugfs_mount(void) if (!mnt) return NULL; - set_tracing_events_path("tracing/", mnt); + __tracing_path_set("tracing/", mnt); return mnt; } -const char *perf_debugfs_mount(void) +const char *tracing_path_mount(void) { const char *mnt; - mnt = __perf_tracefs_mount(); + mnt = tracing_path_tracefs_mount(); if (mnt) return mnt; - mnt = __perf_debugfs_mount(); + mnt = tracing_path_debugfs_mount(); return mnt; } -void perf_debugfs_set_path(const char *mntpt) +void tracing_path_set(const char *mntpt) { - set_tracing_events_path("tracing/", mntpt); + __tracing_path_set("tracing/", mntpt); } char *get_tracing_file(const char *name) diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 48ec232b6f66..bbf8a937d780 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -85,8 +85,8 @@ extern const char *graph_dotted_line; extern char buildid_dir[]; extern char tracing_path[]; extern char tracing_events_path[]; -extern void perf_debugfs_set_path(const char *mountpoint); -const char *perf_debugfs_mount(void); +extern void tracing_path_set(const char *mountpoint); +const char *tracing_path_mount(void); char *get_tracing_file(const char *name); void put_tracing_file(char *file); From 592d5a6ba86a31681fa5e20a63a145b0a3b53c8a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:34 +0200 Subject: [PATCH 009/260] tools lib api fs: Move tracing_path interface into api/fs/tracing_path.c Moving tracing_path interface into api/fs/tracing_path.c out of util.c. It seems generic enough to be used by others, and I couldn't think of better place. Signed-off-by: Jiri Olsa Reviewed-by: Matt Fleming Reviewed-by: Raphael Beamonte Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/Build | 1 + tools/lib/api/fs/tracing_path.c | 83 ++++++++++++++++++++++++++++++ tools/lib/api/fs/tracing_path.h | 13 +++++ tools/perf/perf.c | 2 +- tools/perf/util/parse-events.c | 2 +- tools/perf/util/trace-event-info.c | 2 +- tools/perf/util/trace-event.c | 1 + tools/perf/util/util.c | 70 ------------------------- tools/perf/util/util.h | 6 --- 9 files changed, 101 insertions(+), 79 deletions(-) create mode 100644 tools/lib/api/fs/tracing_path.c create mode 100644 tools/lib/api/fs/tracing_path.h diff --git a/tools/lib/api/fs/Build b/tools/lib/api/fs/Build index 6de5a4f0b501..fa726f679b29 100644 --- a/tools/lib/api/fs/Build +++ b/tools/lib/api/fs/Build @@ -1,4 +1,5 @@ libapi-y += fs.o +libapi-y += tracing_path.o libapi-y += debugfs.o libapi-y += findfs.o libapi-y += tracefs.o diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c new file mode 100644 index 000000000000..1fd6e1f99234 --- /dev/null +++ b/tools/lib/api/fs/tracing_path.c @@ -0,0 +1,83 @@ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include +#include +#include +#include "debugfs.h" +#include "tracefs.h" + +#include "tracing_path.h" + + +char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing"; +char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; + + +static void __tracing_path_set(const char *tracing, const char *mountpoint) +{ + snprintf(tracing_path, sizeof(tracing_path), "%s/%s", + mountpoint, tracing); + snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s", + mountpoint, tracing, "events"); +} + +static const char *tracing_path_tracefs_mount(void) +{ + const char *mnt; + + mnt = tracefs_mount(NULL); + if (!mnt) + return NULL; + + __tracing_path_set("", mnt); + + return mnt; +} + +static const char *tracing_path_debugfs_mount(void) +{ + const char *mnt; + + mnt = debugfs_mount(NULL); + if (!mnt) + return NULL; + + __tracing_path_set("tracing/", mnt); + + return mnt; +} + +const char *tracing_path_mount(void) +{ + const char *mnt; + + mnt = tracing_path_tracefs_mount(); + if (mnt) + return mnt; + + mnt = tracing_path_debugfs_mount(); + + return mnt; +} + +void tracing_path_set(const char *mntpt) +{ + __tracing_path_set("tracing/", mntpt); +} + +char *get_tracing_file(const char *name) +{ + char *file; + + if (asprintf(&file, "%s/%s", tracing_path, name) < 0) + return NULL; + + return file; +} + +void put_tracing_file(char *file) +{ + free(file); +} diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h new file mode 100644 index 000000000000..b132dc599fe5 --- /dev/null +++ b/tools/lib/api/fs/tracing_path.h @@ -0,0 +1,13 @@ +#ifndef __API_FS_TRACING_PATH_H +#define __API_FS_TRACING_PATH_H + +extern char tracing_path[]; +extern char tracing_events_path[]; + +void tracing_path_set(const char *mountpoint); +const char *tracing_path_mount(void); + +char *get_tracing_file(const char *name); +void put_tracing_file(char *file); + +#endif /* __API_FS_TRACING_PATH_H */ diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 0e99cd1de9dd..f2fc019b3671 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -15,7 +15,7 @@ #include "util/parse-events.h" #include "util/parse-options.h" #include "util/debug.h" -#include +#include #include const char perf_usage_string[] = diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d826e6f515db..3840176642f8 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -11,7 +11,7 @@ #include "cache.h" #include "header.h" #include "debug.h" -#include +#include #include "parse-events-bison.h" #define YY_EXTRA_TYPE int #include "parse-events-flex.h" diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 22245986e59e..d995743cb673 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -38,7 +38,7 @@ #include "../perf.h" #include "trace-event.h" -#include +#include #include "evsel.h" #include "debug.h" diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index b90e646c7a91..2f4996ab313d 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "trace-event.h" #include "machine.h" #include "util.h" diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b959f783f6cd..49a5c6ad55f5 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -34,9 +34,6 @@ bool test_attr__enabled; bool perf_host = true; bool perf_guest = false; -char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing"; -char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; - void event_attr_init(struct perf_event_attr *attr) { if (!perf_host) @@ -390,73 +387,6 @@ void set_term_quiet_input(struct termios *old) tcsetattr(0, TCSANOW, &tc); } -static void __tracing_path_set(const char *tracing, const char *mountpoint) -{ - snprintf(tracing_path, sizeof(tracing_path), "%s/%s", - mountpoint, tracing); - snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s", - mountpoint, tracing, "events"); -} - -static const char *tracing_path_tracefs_mount(void) -{ - const char *mnt; - - mnt = tracefs_mount(NULL); - if (!mnt) - return NULL; - - __tracing_path_set("", mnt); - - return mnt; -} - -static const char *tracing_path_debugfs_mount(void) -{ - const char *mnt; - - mnt = debugfs_mount(NULL); - if (!mnt) - return NULL; - - __tracing_path_set("tracing/", mnt); - - return mnt; -} - -const char *tracing_path_mount(void) -{ - const char *mnt; - - mnt = tracing_path_tracefs_mount(); - if (mnt) - return mnt; - - mnt = tracing_path_debugfs_mount(); - - return mnt; -} - -void tracing_path_set(const char *mntpt) -{ - __tracing_path_set("tracing/", mntpt); -} - -char *get_tracing_file(const char *name) -{ - char *file; - - if (asprintf(&file, "%s/%s", tracing_path, name) < 0) - return NULL; - - return file; -} - -void put_tracing_file(char *file) -{ - free(file); -} - int parse_nsec_time(const char *str, u64 *ptime) { u64 time_sec, time_nsec; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index bbf8a937d780..495b99ccb588 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -83,12 +83,6 @@ extern const char *graph_line; extern const char *graph_dotted_line; extern char buildid_dir[]; -extern char tracing_path[]; -extern char tracing_events_path[]; -extern void tracing_path_set(const char *mountpoint); -const char *tracing_path_mount(void); -char *get_tracing_file(const char *name); -void put_tracing_file(char *file); /* On most systems would have given us this, but * not on some systems (e.g. GNU/Hurd). From 988bdb319246dea977a375beee39a5452e99b3ef Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:35 +0200 Subject: [PATCH 010/260] tools lib api fs: Move debugfs__strerror_open into tracing_path.c object Moving debugfs__strerror_open out of api/fs/debugfs.c, because it's not debugfs specific. It'll be changed to consider tracefs mount as well in following patches. Renaming it into tracing_path__strerror_open_tp to fit into the namespace. No functional change is intended. Signed-off-by: Jiri Olsa Reviewed-by: Matt Fleming Cc: Raphael Beamonte Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/debugfs.c | 52 ------------------------------- tools/lib/api/fs/tracing_path.c | 54 +++++++++++++++++++++++++++++++++ tools/lib/api/fs/tracing_path.h | 3 ++ tools/perf/builtin-trace.c | 5 +-- 4 files changed, 60 insertions(+), 54 deletions(-) diff --git a/tools/lib/api/fs/debugfs.c b/tools/lib/api/fs/debugfs.c index eb7cf4d18f8a..c707cfb32782 100644 --- a/tools/lib/api/fs/debugfs.c +++ b/tools/lib/api/fs/debugfs.c @@ -75,55 +75,3 @@ char *debugfs_mount(const char *mountpoint) out: return debugfs_mountpoint; } - -int debugfs__strerror_open(int err, char *buf, size_t size, const char *filename) -{ - char sbuf[128]; - - switch (err) { - case ENOENT: - if (debugfs_found) { - snprintf(buf, size, - "Error:\tFile %s/%s not found.\n" - "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", - debugfs_mountpoint, filename); - break; - } - snprintf(buf, size, "%s", - "Error:\tUnable to find debugfs\n" - "Hint:\tWas your kernel compiled with debugfs support?\n" - "Hint:\tIs the debugfs filesystem mounted?\n" - "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); - break; - case EACCES: { - const char *mountpoint = debugfs_mountpoint; - - if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { - const char *tracefs_mntpoint = tracefs_find_mountpoint(); - - if (tracefs_mntpoint) - mountpoint = tracefs_mntpoint; - } - - snprintf(buf, size, - "Error:\tNo permissions to read %s/%s\n" - "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", - debugfs_mountpoint, filename, mountpoint); - } - break; - default: - snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf))); - break; - } - - return 0; -} - -int debugfs__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) -{ - char path[PATH_MAX]; - - snprintf(path, PATH_MAX, "tracing/events/%s/%s", sys, name ?: "*"); - - return debugfs__strerror_open(err, buf, size, path); -} diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 1fd6e1f99234..3b3e4f5fc50b 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "debugfs.h" #include "tracefs.h" @@ -81,3 +83,55 @@ void put_tracing_file(char *file) { free(file); } + +static int strerror_open(int err, char *buf, size_t size, const char *filename) +{ + char sbuf[128]; + + switch (err) { + case ENOENT: + if (debugfs_configured()) { + snprintf(buf, size, + "Error:\tFile %s/%s not found.\n" + "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", + debugfs_mountpoint, filename); + break; + } + snprintf(buf, size, "%s", + "Error:\tUnable to find debugfs\n" + "Hint:\tWas your kernel compiled with debugfs support?\n" + "Hint:\tIs the debugfs filesystem mounted?\n" + "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); + break; + case EACCES: { + const char *mountpoint = debugfs_mountpoint; + + if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { + const char *tracefs_mntpoint = tracefs_find_mountpoint(); + + if (tracefs_mntpoint) + mountpoint = tracefs_mntpoint; + } + + snprintf(buf, size, + "Error:\tNo permissions to read %s/%s\n" + "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", + debugfs_mountpoint, filename, mountpoint); + } + break; + default: + snprintf(buf, size, "%s", strerror_r(err, sbuf, sizeof(sbuf))); + break; + } + + return 0; +} + +int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name) +{ + char path[PATH_MAX]; + + snprintf(path, PATH_MAX, "tracing/events/%s/%s", sys, name ?: "*"); + + return strerror_open(err, buf, size, path); +} diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h index b132dc599fe5..3f233ac70b6f 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -1,6 +1,8 @@ #ifndef __API_FS_TRACING_PATH_H #define __API_FS_TRACING_PATH_H +#include + extern char tracing_path[]; extern char tracing_events_path[]; @@ -10,4 +12,5 @@ const char *tracing_path_mount(void); char *get_tracing_file(const char *name); void put_tracing_file(char *file); +int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); #endif /* __API_FS_TRACING_PATH_H */ diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 4e3abba03062..215653274102 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -17,6 +17,7 @@ */ #include +#include #include "builtin.h" #include "util/color.h" #include "util/debug.h" @@ -2686,11 +2687,11 @@ out_delete_evlist: char errbuf[BUFSIZ]; out_error_sched_stat_runtime: - debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime"); + tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime"); goto out_error; out_error_raw_syscalls: - debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)"); + tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)"); goto out_error; out_error_mmap: From b86b0d3570273c6ddc16b1972e82bf7778346286 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:37 +0200 Subject: [PATCH 011/260] tools lib api fs: Add STR and PATH_MAX macros to fs object We're going to get rid of findfs.h in following patches, but we'll still need these macros. Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-8-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 3 +++ tools/lib/api/fs/fs.h | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 128ef6332a6b..5e838d3c419d 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -15,6 +15,9 @@ #include "debugfs.h" #include "fs.h" +#define _STR(x) #x +#define STR(x) _STR(x) + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 6caa2bbc6cec..fd6288d73383 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -1,6 +1,14 @@ #ifndef __API_FS__ #define __API_FS__ +/* + * On most systems would have given us this, but not on some systems + * (e.g. GNU/Hurd). + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + #ifndef SYSFS_MAGIC #define SYSFS_MAGIC 0x62656572 #endif From 41e3a1fece31d0b2383281e4a917ff4b16fa9223 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:38 +0200 Subject: [PATCH 012/260] tools lib api fs: Move SYSFS_MAGIC PROC_SUPER_MAGIC into fs.c There's no need to export SYSFS_MAGIC PROC_SUPER_MAGIC in fs.h. Leave them in the fs.c. Link: http://lkml.kernel.org/n/tip-b2cd1bb7yvbazq5oua24oz18@git.kernel.org Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 8 ++++++++ tools/lib/api/fs/fs.h | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 5e838d3c419d..0700eb953495 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -18,6 +18,14 @@ #define _STR(x) #x #define STR(x) _STR(x) +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif + +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index fd6288d73383..674efc8dfd9b 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -9,14 +9,6 @@ #define PATH_MAX 4096 #endif -#ifndef SYSFS_MAGIC -#define SYSFS_MAGIC 0x62656572 -#endif - -#ifndef PROC_SUPER_MAGIC -#define PROC_SUPER_MAGIC 0x9fa0 -#endif - const char *sysfs__mountpoint(void); const char *procfs__mountpoint(void); From 8ccfabdb873df2e18b235bfaf2722f7528d220f1 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:39 +0200 Subject: [PATCH 013/260] tools lib api fs: Add debugfs into fs.c object Adding debugfs support into fs.c framework. It'll replace the debugfs object functionality in following patches. Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-10-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 31 +++++++++++++++++++++++++------ tools/lib/api/fs/fs.h | 1 + 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 0700eb953495..798052cbc7c0 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -1,5 +1,3 @@ -/* TODO merge/factor in debugfs.c here */ - #include #include #include @@ -26,6 +24,10 @@ #define PROC_SUPER_MAGIC 0x9fa0 #endif +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, @@ -36,6 +38,16 @@ static const char * const procfs__known_mountpoints[] = { 0, }; +#ifndef DEBUGFS_DEFAULT_PATH +#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" +#endif + +static const char * const debugfs__known_mountpoints[] = { + DEBUGFS_DEFAULT_PATH, + "/debug", + 0, +}; + struct fs { const char *name; const char * const *mounts; @@ -45,8 +57,9 @@ struct fs { }; enum { - FS__SYSFS = 0, - FS__PROCFS = 1, + FS__SYSFS = 0, + FS__PROCFS = 1, + FS__DEBUGFS = 2, }; static struct fs fs__entries[] = { @@ -60,6 +73,11 @@ static struct fs fs__entries[] = { .mounts = procfs__known_mountpoints, .magic = PROC_SUPER_MAGIC, }, + [FS__DEBUGFS] = { + .name = "debugfs", + .mounts = debugfs__known_mountpoints, + .magic = DEBUGFS_MAGIC, + }, }; static bool fs__read_mounts(struct fs *fs) @@ -176,8 +194,9 @@ const char *name##__mountpoint(void) \ return fs__mountpoint(idx); \ } -FS__MOUNTPOINT(sysfs, FS__SYSFS); -FS__MOUNTPOINT(procfs, FS__PROCFS); +FS__MOUNTPOINT(sysfs, FS__SYSFS); +FS__MOUNTPOINT(procfs, FS__PROCFS); +FS__MOUNTPOINT(debugfs, FS__DEBUGFS); int filename__read_int(const char *filename, int *value) { diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 674efc8dfd9b..a4e6b1d93d2f 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -11,6 +11,7 @@ const char *sysfs__mountpoint(void); const char *procfs__mountpoint(void); +const char *debugfs__mountpoint(void); int filename__read_int(const char *filename, int *value); int sysctl__read_int(const char *sysctl, int *value); From c495afb4988dcbb8bae11b8f1bbb7e11f172672b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:40 +0200 Subject: [PATCH 014/260] tools lib api fs: Add tracefs into fs.c object Adding tracefs support into fs.c framework. It'll replace the tracefs object functionality in following patches. Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-11-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 28 ++++++++++++++++++++++++++++ tools/lib/api/fs/fs.h | 1 + 2 files changed, 29 insertions(+) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 798052cbc7c0..ef16d2a83a27 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -28,6 +28,10 @@ #define DEBUGFS_MAGIC 0x64626720 #endif +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + static const char * const sysfs__fs_known_mountpoints[] = { "/sys", 0, @@ -48,6 +52,19 @@ static const char * const debugfs__known_mountpoints[] = { 0, }; + +#ifndef TRACEFS_DEFAULT_PATH +#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" +#endif + +static const char * const tracefs__known_mountpoints[] = { + TRACEFS_DEFAULT_PATH, + "/sys/kernel/debug/tracing", + "/tracing", + "/trace", + 0, +}; + struct fs { const char *name; const char * const *mounts; @@ -60,8 +77,13 @@ enum { FS__SYSFS = 0, FS__PROCFS = 1, FS__DEBUGFS = 2, + FS__TRACEFS = 3, }; +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + static struct fs fs__entries[] = { [FS__SYSFS] = { .name = "sysfs", @@ -78,6 +100,11 @@ static struct fs fs__entries[] = { .mounts = debugfs__known_mountpoints, .magic = DEBUGFS_MAGIC, }, + [FS__TRACEFS] = { + .name = "tracefs", + .mounts = tracefs__known_mountpoints, + .magic = TRACEFS_MAGIC, + }, }; static bool fs__read_mounts(struct fs *fs) @@ -197,6 +224,7 @@ const char *name##__mountpoint(void) \ FS__MOUNTPOINT(sysfs, FS__SYSFS); FS__MOUNTPOINT(procfs, FS__PROCFS); FS__MOUNTPOINT(debugfs, FS__DEBUGFS); +FS__MOUNTPOINT(tracefs, FS__TRACEFS); int filename__read_int(const char *filename, int *value) { diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index a4e6b1d93d2f..9013227ae0d1 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -12,6 +12,7 @@ const char *sysfs__mountpoint(void); const char *procfs__mountpoint(void); const char *debugfs__mountpoint(void); +const char *tracefs__mountpoint(void); int filename__read_int(const char *filename, int *value); int sysctl__read_int(const char *sysctl, int *value); From 73ca85ad364769ffa312b1d892816d8fa23a02bf Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:41 +0200 Subject: [PATCH 015/260] tools lib api fs: Add FSTYPE__mount() method Adding FSTYPE__mount (where FSTYPE is, as of now, one of sysfs, procfs, debugfs, tracefs) method that tries to mount the filesystem in case no mount of FSTYPE is found. Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-12-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 44 ++++++++++++++++++++++++++++++++++++++----- tools/lib/api/fs/fs.h | 15 +++++++++++---- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index ef16d2a83a27..bc93baf33fff 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "debugfs.h" #include "fs.h" @@ -215,16 +216,49 @@ static const char *fs__mountpoint(int idx) return fs__get_mountpoint(fs); } -#define FS__MOUNTPOINT(name, idx) \ +static const char *mount_overload(struct fs *fs) +{ + size_t name_len = strlen(fs->name); + /* "PERF_" + name + "_ENVIRONMENT" + '\0' */ + char upper_name[5 + name_len + 12 + 1]; + + snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name); + mem_toupper(upper_name, name_len); + + return getenv(upper_name) ?: *fs->mounts; +} + +static const char *fs__mount(int idx) +{ + struct fs *fs = &fs__entries[idx]; + const char *mountpoint; + + if (fs__mountpoint(idx)) + return (const char *)fs->path; + + mountpoint = mount_overload(fs); + + if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0) + return NULL; + + return fs__check_mounts(fs) ? fs->path : NULL; +} + +#define FS(name, idx) \ const char *name##__mountpoint(void) \ { \ return fs__mountpoint(idx); \ +} \ + \ +const char *name##__mount(void) \ +{ \ + return fs__mount(idx); \ } -FS__MOUNTPOINT(sysfs, FS__SYSFS); -FS__MOUNTPOINT(procfs, FS__PROCFS); -FS__MOUNTPOINT(debugfs, FS__DEBUGFS); -FS__MOUNTPOINT(tracefs, FS__TRACEFS); +FS(sysfs, FS__SYSFS); +FS(procfs, FS__PROCFS); +FS(debugfs, FS__DEBUGFS); +FS(tracefs, FS__TRACEFS); int filename__read_int(const char *filename, int *value) { diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 9013227ae0d1..a9627ea5e6ae 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -9,10 +9,17 @@ #define PATH_MAX 4096 #endif -const char *sysfs__mountpoint(void); -const char *procfs__mountpoint(void); -const char *debugfs__mountpoint(void); -const char *tracefs__mountpoint(void); +#define FS(name) \ + const char *name##__mountpoint(void); \ + const char *name##__mount(void); + +FS(sysfs) +FS(procfs) +FS(debugfs) +FS(tracefs) + +#undef FS + int filename__read_int(const char *filename, int *value); int sysctl__read_int(const char *sysctl, int *value); From 709adcb33928b5bf965587b23ed6544e964584a3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:42 +0200 Subject: [PATCH 016/260] tools lib api fs: Add FSTYPE__configured() method Add FSTYPE__configured() (where FSTYPE is one of sysfs, procfs, debugfs, tracefs) interface that returns bool state of the filesystem mount: true - mounted, false - not mounted It will not try to mount the filesystem. Signed-off-by: Jiri Olsa Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-13-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 23 ++++++++++++++--------- tools/lib/api/fs/fs.h | 5 ++++- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index bc93baf33fff..8afe08a99bc6 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -244,15 +244,20 @@ static const char *fs__mount(int idx) return fs__check_mounts(fs) ? fs->path : NULL; } -#define FS(name, idx) \ -const char *name##__mountpoint(void) \ -{ \ - return fs__mountpoint(idx); \ -} \ - \ -const char *name##__mount(void) \ -{ \ - return fs__mount(idx); \ +#define FS(name, idx) \ +const char *name##__mountpoint(void) \ +{ \ + return fs__mountpoint(idx); \ +} \ + \ +const char *name##__mount(void) \ +{ \ + return fs__mount(idx); \ +} \ + \ +bool name##__configured(void) \ +{ \ + return name##__mountpoint() != NULL; \ } FS(sysfs, FS__SYSFS); diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index a9627ea5e6ae..f654bcb99d1e 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -1,6 +1,8 @@ #ifndef __API_FS__ #define __API_FS__ +#include + /* * On most systems would have given us this, but not on some systems * (e.g. GNU/Hurd). @@ -11,7 +13,8 @@ #define FS(name) \ const char *name##__mountpoint(void); \ - const char *name##__mount(void); + const char *name##__mount(void); \ + bool name##__configured(void); \ FS(sysfs) FS(procfs) From 3a9d7723145a6c1be6e9afbb661e3ad7768be2e0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:25 +0300 Subject: [PATCH 017/260] perf tools: Display build warning if x86 instruction decoder differs from kernel perf tools has a copy of the x86 instruction decoder used by the kernel. The expectation is that the copy will be kept more-or-less in-synch with the kernel version. Consequently it is helpful to know if there are differences. This patch adds a check into the perf tools build so that a diff is done on the sources, and a warning is printed if they are different. Note that the warning is not fatal and the build continues as normal. The check is done as part of building the instruction decoder, so, like a compiler warning, it is not seen unless the instruction decoder has to be re-compiled. e.g. $ make -C tools/perf >/dev/null $ echo "/* blah */" >> tools/perf/util/intel-pt-decoder/inat_types.h $ make -C tools/perf >/dev/null Warning: Intel PT: x86 instruction decoder differs from kernel $ make -C tools/perf >/dev/null $ Signed-off-by: Adrian Hunter Tested-by: Arnaldo Carvalho de Melo Acked-by: Masami Hiramatsu Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/Build | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build index 2386322ece4f..0611d619a42e 100644 --- a/tools/perf/util/intel-pt-decoder/Build +++ b/tools/perf/util/intel-pt-decoder/Build @@ -7,6 +7,17 @@ $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_table $(call rule_mkdir) @$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ || rm -f $@ -$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c +$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/intel-pt-insn-decoder.c util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c + @(test -d ../../kernel -a -d ../../tools -a -d ../perf && (( \ + diff -B -I'^#include' util/intel-pt-decoder/insn.c ../../arch/x86/lib/insn.c >/dev/null && \ + diff -B -I'^#include' util/intel-pt-decoder/inat.c ../../arch/x86/lib/inat.c >/dev/null && \ + diff -B util/intel-pt-decoder/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null && \ + diff -B util/intel-pt-decoder/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null && \ + diff -B -I'^#include' util/intel-pt-decoder/insn.h ../../arch/x86/include/asm/insn.h >/dev/null && \ + diff -B -I'^#include' util/intel-pt-decoder/inat.h ../../arch/x86/include/asm/inat.h >/dev/null && \ + diff -B -I'^#include' util/intel-pt-decoder/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) \ + || echo "Warning: Intel PT: x86 instruction decoder differs from kernel" >&2 )) || true + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) CFLAGS_intel-pt-insn-decoder.o += -I$(OUTPUT)util/intel-pt-decoder -Wno-override-init From 98e4619f2b2bb80d310feaac5589b44c000aecc1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:26 +0300 Subject: [PATCH 018/260] perf tools: Add a test for decoding of new x86 instructions Add a new test titled: Test x86 instruction decoder - new instructions The purpose of this test is to check the instruction decoder after new instructions have been added. Initially, MPX instructions are tested which are already supported, but the definitions in x86-opcode-map.txt will be tweaked in a subsequent patch, after which this test can be run to verify those changes. The data for the test comes from assembly language instructions in insn-x86-dat-src.c which is converted into bytes by the scripts gen-insn-x86-dat.sh and gen-insn-x86-dat.awk, and included into the test program insn-x86.c as insn-x86-dat-32.c and insn-x86-dat-64.c. The conversion is not done as part of the perf tools build because the test data must be under (git) change control in order for the test to be repeatably-correct. Also it may require a recent version of binutils. Commiter notes: Using it: # perf test decoder 39: Test x86 instruction decoder - new instructions : Ok # perf test -v decoder 39: Test x86 instruction decoder - new instructions : --- start --- test child forked, pid 21970 Decoded ok: 0f 31 rdtsc Decoded ok: f3 0f 1b 00 bndmk (%eax),%bnd0 Decoded ok: f3 0f 1b 05 78 56 34 12 bndmk 0x12345678,%bnd0 Decoded ok: f3 0f 1b 18 bndmk (%eax),%bnd3 Decoded ok: f2 e9 00 00 00 00 bnd jmpq 402 Decoded ok: f2 e9 00 00 00 00 bnd jmpq 408 Decoded ok: 67 f2 ff 21 bnd jmpq *(%ecx) Decoded ok: f2 0f 85 00 00 00 00 bnd jne 413 test child finished with 0 ---- end ---- Test x86 instruction decoder - new instructions: Ok # Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/Build | 3 + tools/perf/tests/builtin-test.c | 8 + tools/perf/tests/gen-insn-x86-dat.awk | 75 +++++ tools/perf/tests/gen-insn-x86-dat.sh | 43 +++ tools/perf/tests/insn-x86-dat-32.c | 324 ++++++++++++++++++++ tools/perf/tests/insn-x86-dat-64.c | 340 +++++++++++++++++++++ tools/perf/tests/insn-x86-dat-src.c | 416 ++++++++++++++++++++++++++ tools/perf/tests/insn-x86.c | 180 +++++++++++ tools/perf/tests/tests.h | 1 + 9 files changed, 1390 insertions(+) create mode 100644 tools/perf/tests/gen-insn-x86-dat.awk create mode 100755 tools/perf/tests/gen-insn-x86-dat.sh create mode 100644 tools/perf/tests/insn-x86-dat-32.c create mode 100644 tools/perf/tests/insn-x86-dat-64.c create mode 100644 tools/perf/tests/insn-x86-dat-src.c create mode 100644 tools/perf/tests/insn-x86.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index c1518bdd0f1b..51fb737f82fc 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -35,6 +35,9 @@ perf-y += thread-map.o perf-y += llvm.o perf-$(CONFIG_X86) += perf-time-to-tsc.o +ifdef CONFIG_AUXTRACE +perf-$(CONFIG_X86) += insn-x86.o +endif ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 136cd934be66..69a77f71d594 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -178,6 +178,14 @@ static struct test { .desc = "Test LLVM searching and compiling", .func = test__llvm, }, +#ifdef HAVE_AUXTRACE_SUPPORT +#if defined(__x86_64__) || defined(__i386__) + { + .desc = "Test x86 instruction decoder - new instructions", + .func = test__insn_x86, + }, +#endif +#endif { .func = NULL, }, diff --git a/tools/perf/tests/gen-insn-x86-dat.awk b/tools/perf/tests/gen-insn-x86-dat.awk new file mode 100644 index 000000000000..a21454835cd4 --- /dev/null +++ b/tools/perf/tests/gen-insn-x86-dat.awk @@ -0,0 +1,75 @@ +#!/bin/awk -f +# gen-insn-x86-dat.awk: script to convert data for the insn-x86 test +# Copyright (c) 2015, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. + +BEGIN { + print "/*" + print " * Generated by gen-insn-x86-dat.sh and gen-insn-x86-dat.awk" + print " * from insn-x86-dat-src.c for inclusion by insn-x86.c" + print " * Do not change this code." + print "*/\n" + op = "" + branch = "" + rel = 0 + going = 0 +} + +/ Start here / { + going = 1 +} + +/ Stop here / { + going = 0 +} + +/^\s*[0-9a-fA-F]+\:/ { + if (going) { + colon_pos = index($0, ":") + useful_line = substr($0, colon_pos + 1) + first_pos = match(useful_line, "[0-9a-fA-F]") + useful_line = substr(useful_line, first_pos) + gsub("\t", "\\t", useful_line) + printf "{{" + len = 0 + for (i = 2; i <= NF; i++) { + if (match($i, "^[0-9a-fA-F][0-9a-fA-F]$")) { + printf "0x%s, ", $i + len += 1 + } else { + break + } + } + printf "}, %d, %s, \"%s\", \"%s\",", len, rel, op, branch + printf "\n\"%s\",},\n", useful_line + op = "" + branch = "" + rel = 0 + } +} + +/ Expecting: / { + expecting_str = " Expecting: " + expecting_len = length(expecting_str) + expecting_pos = index($0, expecting_str) + useful_line = substr($0, expecting_pos + expecting_len) + for (i = 1; i <= NF; i++) { + if ($i == "Expecting:") { + i++ + op = $i + i++ + branch = $i + i++ + rel = $i + break + } + } +} diff --git a/tools/perf/tests/gen-insn-x86-dat.sh b/tools/perf/tests/gen-insn-x86-dat.sh new file mode 100755 index 000000000000..2d4ef94cff98 --- /dev/null +++ b/tools/perf/tests/gen-insn-x86-dat.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# gen-insn-x86-dat: generate data for the insn-x86 test +# Copyright (c) 2015, Intel Corporation. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. + +set -e + +if [ "$(uname -m)" != "x86_64" ]; then + echo "ERROR: This script only works on x86_64" + exit 1 +fi + +cd $(dirname $0) + +trap 'echo "Might need a more recent version of binutils"' EXIT + +echo "Compiling insn-x86-dat-src.c to 64-bit object" + +gcc -g -c insn-x86-dat-src.c + +objdump -dSw insn-x86-dat-src.o | awk -f gen-insn-x86-dat.awk > insn-x86-dat-64.c + +rm -f insn-x86-dat-src.o + +echo "Compiling insn-x86-dat-src.c to 32-bit object" + +gcc -g -c -m32 insn-x86-dat-src.c + +objdump -dSw insn-x86-dat-src.o | awk -f gen-insn-x86-dat.awk > insn-x86-dat-32.c + +rm -f insn-x86-dat-src.o + +trap - EXIT + +echo "Done (use git diff to see the changes)" diff --git a/tools/perf/tests/insn-x86-dat-32.c b/tools/perf/tests/insn-x86-dat-32.c new file mode 100644 index 000000000000..6a38a34a5a49 --- /dev/null +++ b/tools/perf/tests/insn-x86-dat-32.c @@ -0,0 +1,324 @@ +/* + * Generated by gen-insn-x86-dat.sh and gen-insn-x86-dat.awk + * from insn-x86-dat-src.c for inclusion by insn-x86.c + * Do not change this code. +*/ + +{{0x0f, 0x31, }, 2, 0, "", "", +"0f 31 \trdtsc ",}, +{{0xf3, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"f3 0f 1b 00 \tbndmk (%eax),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1b 05 78 56 34 12 \tbndmk 0x12345678,%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x18, }, 4, 0, "", "", +"f3 0f 1b 18 \tbndmk (%eax),%bnd3",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x01, }, 5, 0, "", "", +"f3 0f 1b 04 01 \tbndmk (%ecx,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 04 05 78 56 34 12 \tbndmk 0x12345678(,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x08, }, 5, 0, "", "", +"f3 0f 1b 04 08 \tbndmk (%eax,%ecx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0xc8, }, 5, 0, "", "", +"f3 0f 1b 04 c8 \tbndmk (%eax,%ecx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x40, 0x12, }, 5, 0, "", "", +"f3 0f 1b 40 12 \tbndmk 0x12(%eax),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x45, 0x12, }, 5, 0, "", "", +"f3 0f 1b 45 12 \tbndmk 0x12(%ebp),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 01 12 \tbndmk 0x12(%ecx,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 05 12 \tbndmk 0x12(%ebp,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 08 12 \tbndmk 0x12(%eax,%ecx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 c8 12 \tbndmk 0x12(%eax,%ecx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1b 80 78 56 34 12 \tbndmk 0x12345678(%eax),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1b 85 78 56 34 12 \tbndmk 0x12345678(%ebp),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 01 78 56 34 12 \tbndmk 0x12345678(%ecx,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 05 78 56 34 12 \tbndmk 0x12345678(%ebp,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 08 78 56 34 12 \tbndmk 0x12345678(%eax,%ecx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 c8 78 56 34 12 \tbndmk 0x12345678(%eax,%ecx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"f3 0f 1a 00 \tbndcl (%eax),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1a 05 78 56 34 12 \tbndcl 0x12345678,%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x18, }, 4, 0, "", "", +"f3 0f 1a 18 \tbndcl (%eax),%bnd3",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x01, }, 5, 0, "", "", +"f3 0f 1a 04 01 \tbndcl (%ecx,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 04 05 78 56 34 12 \tbndcl 0x12345678(,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x08, }, 5, 0, "", "", +"f3 0f 1a 04 08 \tbndcl (%eax,%ecx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0xc8, }, 5, 0, "", "", +"f3 0f 1a 04 c8 \tbndcl (%eax,%ecx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x40, 0x12, }, 5, 0, "", "", +"f3 0f 1a 40 12 \tbndcl 0x12(%eax),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x45, 0x12, }, 5, 0, "", "", +"f3 0f 1a 45 12 \tbndcl 0x12(%ebp),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 01 12 \tbndcl 0x12(%ecx,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 05 12 \tbndcl 0x12(%ebp,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 08 12 \tbndcl 0x12(%eax,%ecx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 c8 12 \tbndcl 0x12(%eax,%ecx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1a 80 78 56 34 12 \tbndcl 0x12345678(%eax),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1a 85 78 56 34 12 \tbndcl 0x12345678(%ebp),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 01 78 56 34 12 \tbndcl 0x12345678(%ecx,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 05 78 56 34 12 \tbndcl 0x12345678(%ebp,%eax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 08 78 56 34 12 \tbndcl 0x12345678(%eax,%ecx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 c8 78 56 34 12 \tbndcl 0x12345678(%eax,%ecx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0xc0, }, 4, 0, "", "", +"f3 0f 1a c0 \tbndcl %eax,%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"f2 0f 1a 00 \tbndcu (%eax),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1a 05 78 56 34 12 \tbndcu 0x12345678,%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x18, }, 4, 0, "", "", +"f2 0f 1a 18 \tbndcu (%eax),%bnd3",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x01, }, 5, 0, "", "", +"f2 0f 1a 04 01 \tbndcu (%ecx,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 04 05 78 56 34 12 \tbndcu 0x12345678(,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x08, }, 5, 0, "", "", +"f2 0f 1a 04 08 \tbndcu (%eax,%ecx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0xc8, }, 5, 0, "", "", +"f2 0f 1a 04 c8 \tbndcu (%eax,%ecx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x40, 0x12, }, 5, 0, "", "", +"f2 0f 1a 40 12 \tbndcu 0x12(%eax),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x45, 0x12, }, 5, 0, "", "", +"f2 0f 1a 45 12 \tbndcu 0x12(%ebp),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 01 12 \tbndcu 0x12(%ecx,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 05 12 \tbndcu 0x12(%ebp,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 08 12 \tbndcu 0x12(%eax,%ecx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 c8 12 \tbndcu 0x12(%eax,%ecx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1a 80 78 56 34 12 \tbndcu 0x12345678(%eax),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1a 85 78 56 34 12 \tbndcu 0x12345678(%ebp),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 01 78 56 34 12 \tbndcu 0x12345678(%ecx,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 05 78 56 34 12 \tbndcu 0x12345678(%ebp,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 08 78 56 34 12 \tbndcu 0x12345678(%eax,%ecx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 c8 78 56 34 12 \tbndcu 0x12345678(%eax,%ecx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0xc0, }, 4, 0, "", "", +"f2 0f 1a c0 \tbndcu %eax,%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"f2 0f 1b 00 \tbndcn (%eax),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1b 05 78 56 34 12 \tbndcn 0x12345678,%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x18, }, 4, 0, "", "", +"f2 0f 1b 18 \tbndcn (%eax),%bnd3",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x01, }, 5, 0, "", "", +"f2 0f 1b 04 01 \tbndcn (%ecx,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 04 05 78 56 34 12 \tbndcn 0x12345678(,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x08, }, 5, 0, "", "", +"f2 0f 1b 04 08 \tbndcn (%eax,%ecx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0xc8, }, 5, 0, "", "", +"f2 0f 1b 04 c8 \tbndcn (%eax,%ecx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x40, 0x12, }, 5, 0, "", "", +"f2 0f 1b 40 12 \tbndcn 0x12(%eax),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x45, 0x12, }, 5, 0, "", "", +"f2 0f 1b 45 12 \tbndcn 0x12(%ebp),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 01 12 \tbndcn 0x12(%ecx,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 05 12 \tbndcn 0x12(%ebp,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 08 12 \tbndcn 0x12(%eax,%ecx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 c8 12 \tbndcn 0x12(%eax,%ecx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1b 80 78 56 34 12 \tbndcn 0x12345678(%eax),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1b 85 78 56 34 12 \tbndcn 0x12345678(%ebp),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 01 78 56 34 12 \tbndcn 0x12345678(%ecx,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 05 78 56 34 12 \tbndcn 0x12345678(%ebp,%eax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 08 78 56 34 12 \tbndcn 0x12345678(%eax,%ecx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 c8 78 56 34 12 \tbndcn 0x12345678(%eax,%ecx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0xc0, }, 4, 0, "", "", +"f2 0f 1b c0 \tbndcn %eax,%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"66 0f 1a 00 \tbndmov (%eax),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1a 05 78 56 34 12 \tbndmov 0x12345678,%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x18, }, 4, 0, "", "", +"66 0f 1a 18 \tbndmov (%eax),%bnd3",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x01, }, 5, 0, "", "", +"66 0f 1a 04 01 \tbndmov (%ecx,%eax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 04 05 78 56 34 12 \tbndmov 0x12345678(,%eax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x08, }, 5, 0, "", "", +"66 0f 1a 04 08 \tbndmov (%eax,%ecx,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0xc8, }, 5, 0, "", "", +"66 0f 1a 04 c8 \tbndmov (%eax,%ecx,8),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x40, 0x12, }, 5, 0, "", "", +"66 0f 1a 40 12 \tbndmov 0x12(%eax),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x45, 0x12, }, 5, 0, "", "", +"66 0f 1a 45 12 \tbndmov 0x12(%ebp),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 01 12 \tbndmov 0x12(%ecx,%eax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 05 12 \tbndmov 0x12(%ebp,%eax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 08 12 \tbndmov 0x12(%eax,%ecx,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 c8 12 \tbndmov 0x12(%eax,%ecx,8),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1a 80 78 56 34 12 \tbndmov 0x12345678(%eax),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1a 85 78 56 34 12 \tbndmov 0x12345678(%ebp),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 01 78 56 34 12 \tbndmov 0x12345678(%ecx,%eax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 05 78 56 34 12 \tbndmov 0x12345678(%ebp,%eax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 08 78 56 34 12 \tbndmov 0x12345678(%eax,%ecx,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 c8 78 56 34 12 \tbndmov 0x12345678(%eax,%ecx,8),%bnd0",}, +{{0x66, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"66 0f 1b 00 \tbndmov %bnd0,(%eax)",}, +{{0x66, 0x0f, 0x1b, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1b 05 78 56 34 12 \tbndmov %bnd0,0x12345678",}, +{{0x66, 0x0f, 0x1b, 0x18, }, 4, 0, "", "", +"66 0f 1b 18 \tbndmov %bnd3,(%eax)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x01, }, 5, 0, "", "", +"66 0f 1b 04 01 \tbndmov %bnd0,(%ecx,%eax,1)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 04 05 78 56 34 12 \tbndmov %bnd0,0x12345678(,%eax,1)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x08, }, 5, 0, "", "", +"66 0f 1b 04 08 \tbndmov %bnd0,(%eax,%ecx,1)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0xc8, }, 5, 0, "", "", +"66 0f 1b 04 c8 \tbndmov %bnd0,(%eax,%ecx,8)",}, +{{0x66, 0x0f, 0x1b, 0x40, 0x12, }, 5, 0, "", "", +"66 0f 1b 40 12 \tbndmov %bnd0,0x12(%eax)",}, +{{0x66, 0x0f, 0x1b, 0x45, 0x12, }, 5, 0, "", "", +"66 0f 1b 45 12 \tbndmov %bnd0,0x12(%ebp)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 01 12 \tbndmov %bnd0,0x12(%ecx,%eax,1)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 05 12 \tbndmov %bnd0,0x12(%ebp,%eax,1)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 08 12 \tbndmov %bnd0,0x12(%eax,%ecx,1)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 c8 12 \tbndmov %bnd0,0x12(%eax,%ecx,8)",}, +{{0x66, 0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1b 80 78 56 34 12 \tbndmov %bnd0,0x12345678(%eax)",}, +{{0x66, 0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1b 85 78 56 34 12 \tbndmov %bnd0,0x12345678(%ebp)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 01 78 56 34 12 \tbndmov %bnd0,0x12345678(%ecx,%eax,1)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 05 78 56 34 12 \tbndmov %bnd0,0x12345678(%ebp,%eax,1)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 08 78 56 34 12 \tbndmov %bnd0,0x12345678(%eax,%ecx,1)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 c8 78 56 34 12 \tbndmov %bnd0,0x12345678(%eax,%ecx,8)",}, +{{0x66, 0x0f, 0x1a, 0xc8, }, 4, 0, "", "", +"66 0f 1a c8 \tbndmov %bnd0,%bnd1",}, +{{0x66, 0x0f, 0x1a, 0xc1, }, 4, 0, "", "", +"66 0f 1a c1 \tbndmov %bnd1,%bnd0",}, +{{0x0f, 0x1a, 0x00, }, 3, 0, "", "", +"0f 1a 00 \tbndldx (%eax),%bnd0",}, +{{0x0f, 0x1a, 0x05, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1a 05 78 56 34 12 \tbndldx 0x12345678,%bnd0",}, +{{0x0f, 0x1a, 0x18, }, 3, 0, "", "", +"0f 1a 18 \tbndldx (%eax),%bnd3",}, +{{0x0f, 0x1a, 0x04, 0x01, }, 4, 0, "", "", +"0f 1a 04 01 \tbndldx (%ecx,%eax,1),%bnd0",}, +{{0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 04 05 78 56 34 12 \tbndldx 0x12345678(,%eax,1),%bnd0",}, +{{0x0f, 0x1a, 0x04, 0x08, }, 4, 0, "", "", +"0f 1a 04 08 \tbndldx (%eax,%ecx,1),%bnd0",}, +{{0x0f, 0x1a, 0x40, 0x12, }, 4, 0, "", "", +"0f 1a 40 12 \tbndldx 0x12(%eax),%bnd0",}, +{{0x0f, 0x1a, 0x45, 0x12, }, 4, 0, "", "", +"0f 1a 45 12 \tbndldx 0x12(%ebp),%bnd0",}, +{{0x0f, 0x1a, 0x44, 0x01, 0x12, }, 5, 0, "", "", +"0f 1a 44 01 12 \tbndldx 0x12(%ecx,%eax,1),%bnd0",}, +{{0x0f, 0x1a, 0x44, 0x05, 0x12, }, 5, 0, "", "", +"0f 1a 44 05 12 \tbndldx 0x12(%ebp,%eax,1),%bnd0",}, +{{0x0f, 0x1a, 0x44, 0x08, 0x12, }, 5, 0, "", "", +"0f 1a 44 08 12 \tbndldx 0x12(%eax,%ecx,1),%bnd0",}, +{{0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1a 80 78 56 34 12 \tbndldx 0x12345678(%eax),%bnd0",}, +{{0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1a 85 78 56 34 12 \tbndldx 0x12345678(%ebp),%bnd0",}, +{{0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 84 01 78 56 34 12 \tbndldx 0x12345678(%ecx,%eax,1),%bnd0",}, +{{0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 84 05 78 56 34 12 \tbndldx 0x12345678(%ebp,%eax,1),%bnd0",}, +{{0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 84 08 78 56 34 12 \tbndldx 0x12345678(%eax,%ecx,1),%bnd0",}, +{{0x0f, 0x1b, 0x00, }, 3, 0, "", "", +"0f 1b 00 \tbndstx %bnd0,(%eax)",}, +{{0x0f, 0x1b, 0x05, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1b 05 78 56 34 12 \tbndstx %bnd0,0x12345678",}, +{{0x0f, 0x1b, 0x18, }, 3, 0, "", "", +"0f 1b 18 \tbndstx %bnd3,(%eax)",}, +{{0x0f, 0x1b, 0x04, 0x01, }, 4, 0, "", "", +"0f 1b 04 01 \tbndstx %bnd0,(%ecx,%eax,1)",}, +{{0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 04 05 78 56 34 12 \tbndstx %bnd0,0x12345678(,%eax,1)",}, +{{0x0f, 0x1b, 0x04, 0x08, }, 4, 0, "", "", +"0f 1b 04 08 \tbndstx %bnd0,(%eax,%ecx,1)",}, +{{0x0f, 0x1b, 0x40, 0x12, }, 4, 0, "", "", +"0f 1b 40 12 \tbndstx %bnd0,0x12(%eax)",}, +{{0x0f, 0x1b, 0x45, 0x12, }, 4, 0, "", "", +"0f 1b 45 12 \tbndstx %bnd0,0x12(%ebp)",}, +{{0x0f, 0x1b, 0x44, 0x01, 0x12, }, 5, 0, "", "", +"0f 1b 44 01 12 \tbndstx %bnd0,0x12(%ecx,%eax,1)",}, +{{0x0f, 0x1b, 0x44, 0x05, 0x12, }, 5, 0, "", "", +"0f 1b 44 05 12 \tbndstx %bnd0,0x12(%ebp,%eax,1)",}, +{{0x0f, 0x1b, 0x44, 0x08, 0x12, }, 5, 0, "", "", +"0f 1b 44 08 12 \tbndstx %bnd0,0x12(%eax,%ecx,1)",}, +{{0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1b 80 78 56 34 12 \tbndstx %bnd0,0x12345678(%eax)",}, +{{0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1b 85 78 56 34 12 \tbndstx %bnd0,0x12345678(%ebp)",}, +{{0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 84 01 78 56 34 12 \tbndstx %bnd0,0x12345678(%ecx,%eax,1)",}, +{{0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 84 05 78 56 34 12 \tbndstx %bnd0,0x12345678(%ebp,%eax,1)",}, +{{0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 84 08 78 56 34 12 \tbndstx %bnd0,0x12345678(%eax,%ecx,1)",}, +{{0xf2, 0xe8, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "call", "unconditional", +"f2 e8 fc ff ff ff \tbnd call 3c3 ",}, +{{0xf2, 0xff, 0x10, }, 3, 0, "call", "indirect", +"f2 ff 10 \tbnd call *(%eax)",}, +{{0xf2, 0xc3, }, 2, 0, "ret", "indirect", +"f2 c3 \tbnd ret ",}, +{{0xf2, 0xe9, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "jmp", "unconditional", +"f2 e9 fc ff ff ff \tbnd jmp 3ce ",}, +{{0xf2, 0xe9, 0xfc, 0xff, 0xff, 0xff, }, 6, 0xfffffffc, "jmp", "unconditional", +"f2 e9 fc ff ff ff \tbnd jmp 3d4 ",}, +{{0xf2, 0xff, 0x21, }, 3, 0, "jmp", "indirect", +"f2 ff 21 \tbnd jmp *(%ecx)",}, +{{0xf2, 0x0f, 0x85, 0xfc, 0xff, 0xff, 0xff, }, 7, 0xfffffffc, "jcc", "conditional", +"f2 0f 85 fc ff ff ff \tbnd jne 3de ",}, diff --git a/tools/perf/tests/insn-x86-dat-64.c b/tools/perf/tests/insn-x86-dat-64.c new file mode 100644 index 000000000000..01122421a776 --- /dev/null +++ b/tools/perf/tests/insn-x86-dat-64.c @@ -0,0 +1,340 @@ +/* + * Generated by gen-insn-x86-dat.sh and gen-insn-x86-dat.awk + * from insn-x86-dat-src.c for inclusion by insn-x86.c + * Do not change this code. +*/ + +{{0x0f, 0x31, }, 2, 0, "", "", +"0f 31 \trdtsc ",}, +{{0xf3, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"f3 0f 1b 00 \tbndmk (%rax),%bnd0",}, +{{0xf3, 0x41, 0x0f, 0x1b, 0x00, }, 5, 0, "", "", +"f3 41 0f 1b 00 \tbndmk (%r8),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 04 25 78 56 34 12 \tbndmk 0x12345678,%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x18, }, 4, 0, "", "", +"f3 0f 1b 18 \tbndmk (%rax),%bnd3",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x01, }, 5, 0, "", "", +"f3 0f 1b 04 01 \tbndmk (%rcx,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 04 05 78 56 34 12 \tbndmk 0x12345678(,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0x08, }, 5, 0, "", "", +"f3 0f 1b 04 08 \tbndmk (%rax,%rcx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x04, 0xc8, }, 5, 0, "", "", +"f3 0f 1b 04 c8 \tbndmk (%rax,%rcx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x40, 0x12, }, 5, 0, "", "", +"f3 0f 1b 40 12 \tbndmk 0x12(%rax),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x45, 0x12, }, 5, 0, "", "", +"f3 0f 1b 45 12 \tbndmk 0x12(%rbp),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 01 12 \tbndmk 0x12(%rcx,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 05 12 \tbndmk 0x12(%rbp,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 08 12 \tbndmk 0x12(%rax,%rcx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f3 0f 1b 44 c8 12 \tbndmk 0x12(%rax,%rcx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1b 80 78 56 34 12 \tbndmk 0x12345678(%rax),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1b 85 78 56 34 12 \tbndmk 0x12345678(%rbp),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 01 78 56 34 12 \tbndmk 0x12345678(%rcx,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 05 78 56 34 12 \tbndmk 0x12345678(%rbp,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 08 78 56 34 12 \tbndmk 0x12345678(%rax,%rcx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1b, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1b 84 c8 78 56 34 12 \tbndmk 0x12345678(%rax,%rcx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"f3 0f 1a 00 \tbndcl (%rax),%bnd0",}, +{{0xf3, 0x41, 0x0f, 0x1a, 0x00, }, 5, 0, "", "", +"f3 41 0f 1a 00 \tbndcl (%r8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 04 25 78 56 34 12 \tbndcl 0x12345678,%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x18, }, 4, 0, "", "", +"f3 0f 1a 18 \tbndcl (%rax),%bnd3",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x01, }, 5, 0, "", "", +"f3 0f 1a 04 01 \tbndcl (%rcx,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 04 05 78 56 34 12 \tbndcl 0x12345678(,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0x08, }, 5, 0, "", "", +"f3 0f 1a 04 08 \tbndcl (%rax,%rcx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x04, 0xc8, }, 5, 0, "", "", +"f3 0f 1a 04 c8 \tbndcl (%rax,%rcx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x40, 0x12, }, 5, 0, "", "", +"f3 0f 1a 40 12 \tbndcl 0x12(%rax),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x45, 0x12, }, 5, 0, "", "", +"f3 0f 1a 45 12 \tbndcl 0x12(%rbp),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 01 12 \tbndcl 0x12(%rcx,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 05 12 \tbndcl 0x12(%rbp,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 08 12 \tbndcl 0x12(%rax,%rcx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f3 0f 1a 44 c8 12 \tbndcl 0x12(%rax,%rcx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1a 80 78 56 34 12 \tbndcl 0x12345678(%rax),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f3 0f 1a 85 78 56 34 12 \tbndcl 0x12345678(%rbp),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 01 78 56 34 12 \tbndcl 0x12345678(%rcx,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 05 78 56 34 12 \tbndcl 0x12345678(%rbp,%rax,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 08 78 56 34 12 \tbndcl 0x12345678(%rax,%rcx,1),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f3 0f 1a 84 c8 78 56 34 12 \tbndcl 0x12345678(%rax,%rcx,8),%bnd0",}, +{{0xf3, 0x0f, 0x1a, 0xc0, }, 4, 0, "", "", +"f3 0f 1a c0 \tbndcl %rax,%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"f2 0f 1a 00 \tbndcu (%rax),%bnd0",}, +{{0xf2, 0x41, 0x0f, 0x1a, 0x00, }, 5, 0, "", "", +"f2 41 0f 1a 00 \tbndcu (%r8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 04 25 78 56 34 12 \tbndcu 0x12345678,%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x18, }, 4, 0, "", "", +"f2 0f 1a 18 \tbndcu (%rax),%bnd3",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x01, }, 5, 0, "", "", +"f2 0f 1a 04 01 \tbndcu (%rcx,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 04 05 78 56 34 12 \tbndcu 0x12345678(,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0x08, }, 5, 0, "", "", +"f2 0f 1a 04 08 \tbndcu (%rax,%rcx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x04, 0xc8, }, 5, 0, "", "", +"f2 0f 1a 04 c8 \tbndcu (%rax,%rcx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x40, 0x12, }, 5, 0, "", "", +"f2 0f 1a 40 12 \tbndcu 0x12(%rax),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x45, 0x12, }, 5, 0, "", "", +"f2 0f 1a 45 12 \tbndcu 0x12(%rbp),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 01 12 \tbndcu 0x12(%rcx,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 05 12 \tbndcu 0x12(%rbp,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 08 12 \tbndcu 0x12(%rax,%rcx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f2 0f 1a 44 c8 12 \tbndcu 0x12(%rax,%rcx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1a 80 78 56 34 12 \tbndcu 0x12345678(%rax),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1a 85 78 56 34 12 \tbndcu 0x12345678(%rbp),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 01 78 56 34 12 \tbndcu 0x12345678(%rcx,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 05 78 56 34 12 \tbndcu 0x12345678(%rbp,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 08 78 56 34 12 \tbndcu 0x12345678(%rax,%rcx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1a 84 c8 78 56 34 12 \tbndcu 0x12345678(%rax,%rcx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1a, 0xc0, }, 4, 0, "", "", +"f2 0f 1a c0 \tbndcu %rax,%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"f2 0f 1b 00 \tbndcn (%rax),%bnd0",}, +{{0xf2, 0x41, 0x0f, 0x1b, 0x00, }, 5, 0, "", "", +"f2 41 0f 1b 00 \tbndcn (%r8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 04 25 78 56 34 12 \tbndcn 0x12345678,%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x18, }, 4, 0, "", "", +"f2 0f 1b 18 \tbndcn (%rax),%bnd3",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x01, }, 5, 0, "", "", +"f2 0f 1b 04 01 \tbndcn (%rcx,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 04 05 78 56 34 12 \tbndcn 0x12345678(,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0x08, }, 5, 0, "", "", +"f2 0f 1b 04 08 \tbndcn (%rax,%rcx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x04, 0xc8, }, 5, 0, "", "", +"f2 0f 1b 04 c8 \tbndcn (%rax,%rcx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x40, 0x12, }, 5, 0, "", "", +"f2 0f 1b 40 12 \tbndcn 0x12(%rax),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x45, 0x12, }, 5, 0, "", "", +"f2 0f 1b 45 12 \tbndcn 0x12(%rbp),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 01 12 \tbndcn 0x12(%rcx,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 05 12 \tbndcn 0x12(%rbp,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 08 12 \tbndcn 0x12(%rax,%rcx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"f2 0f 1b 44 c8 12 \tbndcn 0x12(%rax,%rcx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1b 80 78 56 34 12 \tbndcn 0x12345678(%rax),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"f2 0f 1b 85 78 56 34 12 \tbndcn 0x12345678(%rbp),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 01 78 56 34 12 \tbndcn 0x12345678(%rcx,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 05 78 56 34 12 \tbndcn 0x12345678(%rbp,%rax,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 08 78 56 34 12 \tbndcn 0x12345678(%rax,%rcx,1),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"f2 0f 1b 84 c8 78 56 34 12 \tbndcn 0x12345678(%rax,%rcx,8),%bnd0",}, +{{0xf2, 0x0f, 0x1b, 0xc0, }, 4, 0, "", "", +"f2 0f 1b c0 \tbndcn %rax,%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"66 0f 1a 00 \tbndmov (%rax),%bnd0",}, +{{0x66, 0x41, 0x0f, 0x1a, 0x00, }, 5, 0, "", "", +"66 41 0f 1a 00 \tbndmov (%r8),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 04 25 78 56 34 12 \tbndmov 0x12345678,%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x18, }, 4, 0, "", "", +"66 0f 1a 18 \tbndmov (%rax),%bnd3",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x01, }, 5, 0, "", "", +"66 0f 1a 04 01 \tbndmov (%rcx,%rax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 04 05 78 56 34 12 \tbndmov 0x12345678(,%rax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0x08, }, 5, 0, "", "", +"66 0f 1a 04 08 \tbndmov (%rax,%rcx,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x04, 0xc8, }, 5, 0, "", "", +"66 0f 1a 04 c8 \tbndmov (%rax,%rcx,8),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x40, 0x12, }, 5, 0, "", "", +"66 0f 1a 40 12 \tbndmov 0x12(%rax),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x45, 0x12, }, 5, 0, "", "", +"66 0f 1a 45 12 \tbndmov 0x12(%rbp),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 01 12 \tbndmov 0x12(%rcx,%rax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 05 12 \tbndmov 0x12(%rbp,%rax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 08 12 \tbndmov 0x12(%rax,%rcx,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"66 0f 1a 44 c8 12 \tbndmov 0x12(%rax,%rcx,8),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1a 80 78 56 34 12 \tbndmov 0x12345678(%rax),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1a 85 78 56 34 12 \tbndmov 0x12345678(%rbp),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 01 78 56 34 12 \tbndmov 0x12345678(%rcx,%rax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 05 78 56 34 12 \tbndmov 0x12345678(%rbp,%rax,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 08 78 56 34 12 \tbndmov 0x12345678(%rax,%rcx,1),%bnd0",}, +{{0x66, 0x0f, 0x1a, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1a 84 c8 78 56 34 12 \tbndmov 0x12345678(%rax,%rcx,8),%bnd0",}, +{{0x66, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"66 0f 1b 00 \tbndmov %bnd0,(%rax)",}, +{{0x66, 0x41, 0x0f, 0x1b, 0x00, }, 5, 0, "", "", +"66 41 0f 1b 00 \tbndmov %bnd0,(%r8)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 04 25 78 56 34 12 \tbndmov %bnd0,0x12345678",}, +{{0x66, 0x0f, 0x1b, 0x18, }, 4, 0, "", "", +"66 0f 1b 18 \tbndmov %bnd3,(%rax)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x01, }, 5, 0, "", "", +"66 0f 1b 04 01 \tbndmov %bnd0,(%rcx,%rax,1)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 04 05 78 56 34 12 \tbndmov %bnd0,0x12345678(,%rax,1)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0x08, }, 5, 0, "", "", +"66 0f 1b 04 08 \tbndmov %bnd0,(%rax,%rcx,1)",}, +{{0x66, 0x0f, 0x1b, 0x04, 0xc8, }, 5, 0, "", "", +"66 0f 1b 04 c8 \tbndmov %bnd0,(%rax,%rcx,8)",}, +{{0x66, 0x0f, 0x1b, 0x40, 0x12, }, 5, 0, "", "", +"66 0f 1b 40 12 \tbndmov %bnd0,0x12(%rax)",}, +{{0x66, 0x0f, 0x1b, 0x45, 0x12, }, 5, 0, "", "", +"66 0f 1b 45 12 \tbndmov %bnd0,0x12(%rbp)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 01 12 \tbndmov %bnd0,0x12(%rcx,%rax,1)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 05 12 \tbndmov %bnd0,0x12(%rbp,%rax,1)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 08 12 \tbndmov %bnd0,0x12(%rax,%rcx,1)",}, +{{0x66, 0x0f, 0x1b, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"66 0f 1b 44 c8 12 \tbndmov %bnd0,0x12(%rax,%rcx,8)",}, +{{0x66, 0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1b 80 78 56 34 12 \tbndmov %bnd0,0x12345678(%rax)",}, +{{0x66, 0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f 1b 85 78 56 34 12 \tbndmov %bnd0,0x12345678(%rbp)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 01 78 56 34 12 \tbndmov %bnd0,0x12345678(%rcx,%rax,1)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 05 78 56 34 12 \tbndmov %bnd0,0x12345678(%rbp,%rax,1)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 08 78 56 34 12 \tbndmov %bnd0,0x12345678(%rax,%rcx,1)",}, +{{0x66, 0x0f, 0x1b, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f 1b 84 c8 78 56 34 12 \tbndmov %bnd0,0x12345678(%rax,%rcx,8)",}, +{{0x66, 0x0f, 0x1a, 0xc8, }, 4, 0, "", "", +"66 0f 1a c8 \tbndmov %bnd0,%bnd1",}, +{{0x66, 0x0f, 0x1a, 0xc1, }, 4, 0, "", "", +"66 0f 1a c1 \tbndmov %bnd1,%bnd0",}, +{{0x0f, 0x1a, 0x00, }, 3, 0, "", "", +"0f 1a 00 \tbndldx (%rax),%bnd0",}, +{{0x41, 0x0f, 0x1a, 0x00, }, 4, 0, "", "", +"41 0f 1a 00 \tbndldx (%r8),%bnd0",}, +{{0x0f, 0x1a, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 04 25 78 56 34 12 \tbndldx 0x12345678,%bnd0",}, +{{0x0f, 0x1a, 0x18, }, 3, 0, "", "", +"0f 1a 18 \tbndldx (%rax),%bnd3",}, +{{0x0f, 0x1a, 0x04, 0x01, }, 4, 0, "", "", +"0f 1a 04 01 \tbndldx (%rcx,%rax,1),%bnd0",}, +{{0x0f, 0x1a, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 04 05 78 56 34 12 \tbndldx 0x12345678(,%rax,1),%bnd0",}, +{{0x0f, 0x1a, 0x04, 0x08, }, 4, 0, "", "", +"0f 1a 04 08 \tbndldx (%rax,%rcx,1),%bnd0",}, +{{0x0f, 0x1a, 0x40, 0x12, }, 4, 0, "", "", +"0f 1a 40 12 \tbndldx 0x12(%rax),%bnd0",}, +{{0x0f, 0x1a, 0x45, 0x12, }, 4, 0, "", "", +"0f 1a 45 12 \tbndldx 0x12(%rbp),%bnd0",}, +{{0x0f, 0x1a, 0x44, 0x01, 0x12, }, 5, 0, "", "", +"0f 1a 44 01 12 \tbndldx 0x12(%rcx,%rax,1),%bnd0",}, +{{0x0f, 0x1a, 0x44, 0x05, 0x12, }, 5, 0, "", "", +"0f 1a 44 05 12 \tbndldx 0x12(%rbp,%rax,1),%bnd0",}, +{{0x0f, 0x1a, 0x44, 0x08, 0x12, }, 5, 0, "", "", +"0f 1a 44 08 12 \tbndldx 0x12(%rax,%rcx,1),%bnd0",}, +{{0x0f, 0x1a, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1a 80 78 56 34 12 \tbndldx 0x12345678(%rax),%bnd0",}, +{{0x0f, 0x1a, 0x85, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1a 85 78 56 34 12 \tbndldx 0x12345678(%rbp),%bnd0",}, +{{0x0f, 0x1a, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 84 01 78 56 34 12 \tbndldx 0x12345678(%rcx,%rax,1),%bnd0",}, +{{0x0f, 0x1a, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 84 05 78 56 34 12 \tbndldx 0x12345678(%rbp,%rax,1),%bnd0",}, +{{0x0f, 0x1a, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1a 84 08 78 56 34 12 \tbndldx 0x12345678(%rax,%rcx,1),%bnd0",}, +{{0x0f, 0x1b, 0x00, }, 3, 0, "", "", +"0f 1b 00 \tbndstx %bnd0,(%rax)",}, +{{0x41, 0x0f, 0x1b, 0x00, }, 4, 0, "", "", +"41 0f 1b 00 \tbndstx %bnd0,(%r8)",}, +{{0x0f, 0x1b, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 04 25 78 56 34 12 \tbndstx %bnd0,0x12345678",}, +{{0x0f, 0x1b, 0x18, }, 3, 0, "", "", +"0f 1b 18 \tbndstx %bnd3,(%rax)",}, +{{0x0f, 0x1b, 0x04, 0x01, }, 4, 0, "", "", +"0f 1b 04 01 \tbndstx %bnd0,(%rcx,%rax,1)",}, +{{0x0f, 0x1b, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 04 05 78 56 34 12 \tbndstx %bnd0,0x12345678(,%rax,1)",}, +{{0x0f, 0x1b, 0x04, 0x08, }, 4, 0, "", "", +"0f 1b 04 08 \tbndstx %bnd0,(%rax,%rcx,1)",}, +{{0x0f, 0x1b, 0x40, 0x12, }, 4, 0, "", "", +"0f 1b 40 12 \tbndstx %bnd0,0x12(%rax)",}, +{{0x0f, 0x1b, 0x45, 0x12, }, 4, 0, "", "", +"0f 1b 45 12 \tbndstx %bnd0,0x12(%rbp)",}, +{{0x0f, 0x1b, 0x44, 0x01, 0x12, }, 5, 0, "", "", +"0f 1b 44 01 12 \tbndstx %bnd0,0x12(%rcx,%rax,1)",}, +{{0x0f, 0x1b, 0x44, 0x05, 0x12, }, 5, 0, "", "", +"0f 1b 44 05 12 \tbndstx %bnd0,0x12(%rbp,%rax,1)",}, +{{0x0f, 0x1b, 0x44, 0x08, 0x12, }, 5, 0, "", "", +"0f 1b 44 08 12 \tbndstx %bnd0,0x12(%rax,%rcx,1)",}, +{{0x0f, 0x1b, 0x80, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1b 80 78 56 34 12 \tbndstx %bnd0,0x12345678(%rax)",}, +{{0x0f, 0x1b, 0x85, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f 1b 85 78 56 34 12 \tbndstx %bnd0,0x12345678(%rbp)",}, +{{0x0f, 0x1b, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 84 01 78 56 34 12 \tbndstx %bnd0,0x12345678(%rcx,%rax,1)",}, +{{0x0f, 0x1b, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 84 05 78 56 34 12 \tbndstx %bnd0,0x12345678(%rbp,%rax,1)",}, +{{0x0f, 0x1b, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 1b 84 08 78 56 34 12 \tbndstx %bnd0,0x12345678(%rax,%rcx,1)",}, +{{0xf2, 0xe8, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "call", "unconditional", +"f2 e8 00 00 00 00 \tbnd callq 3f6 ",}, +{{0x67, 0xf2, 0xff, 0x10, }, 4, 0, "call", "indirect", +"67 f2 ff 10 \tbnd callq *(%eax)",}, +{{0xf2, 0xc3, }, 2, 0, "ret", "indirect", +"f2 c3 \tbnd retq ",}, +{{0xf2, 0xe9, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "jmp", "unconditional", +"f2 e9 00 00 00 00 \tbnd jmpq 402 ",}, +{{0xf2, 0xe9, 0x00, 0x00, 0x00, 0x00, }, 6, 0, "jmp", "unconditional", +"f2 e9 00 00 00 00 \tbnd jmpq 408 ",}, +{{0x67, 0xf2, 0xff, 0x21, }, 4, 0, "jmp", "indirect", +"67 f2 ff 21 \tbnd jmpq *(%ecx)",}, +{{0xf2, 0x0f, 0x85, 0x00, 0x00, 0x00, 0x00, }, 7, 0, "jcc", "conditional", +"f2 0f 85 00 00 00 00 \tbnd jne 413 ",}, diff --git a/tools/perf/tests/insn-x86-dat-src.c b/tools/perf/tests/insn-x86-dat-src.c new file mode 100644 index 000000000000..b506830f33a8 --- /dev/null +++ b/tools/perf/tests/insn-x86-dat-src.c @@ -0,0 +1,416 @@ +/* + * This file contains instructions for testing by the test titled: + * + * "Test x86 instruction decoder - new instructions" + * + * Note that the 'Expecting' comment lines are consumed by the + * gen-insn-x86-dat.awk script and have the format: + * + * Expecting: + * + * If this file is changed, remember to run the gen-insn-x86-dat.sh + * script and commit the result. + * + * Refer to insn-x86.c for more details. + */ + +int main(void) +{ + /* Following line is a marker for the awk script - do not change */ + asm volatile("rdtsc"); /* Start here */ + +#ifdef __x86_64__ + + /* bndmk m64, bnd */ + + asm volatile("bndmk (%rax), %bnd0"); + asm volatile("bndmk (%r8), %bnd0"); + asm volatile("bndmk (0x12345678), %bnd0"); + asm volatile("bndmk (%rax), %bnd3"); + asm volatile("bndmk (%rcx,%rax,1), %bnd0"); + asm volatile("bndmk 0x12345678(,%rax,1), %bnd0"); + asm volatile("bndmk (%rax,%rcx,1), %bnd0"); + asm volatile("bndmk (%rax,%rcx,8), %bnd0"); + asm volatile("bndmk 0x12(%rax), %bnd0"); + asm volatile("bndmk 0x12(%rbp), %bnd0"); + asm volatile("bndmk 0x12(%rcx,%rax,1), %bnd0"); + asm volatile("bndmk 0x12(%rbp,%rax,1), %bnd0"); + asm volatile("bndmk 0x12(%rax,%rcx,1), %bnd0"); + asm volatile("bndmk 0x12(%rax,%rcx,8), %bnd0"); + asm volatile("bndmk 0x12345678(%rax), %bnd0"); + asm volatile("bndmk 0x12345678(%rbp), %bnd0"); + asm volatile("bndmk 0x12345678(%rcx,%rax,1), %bnd0"); + asm volatile("bndmk 0x12345678(%rbp,%rax,1), %bnd0"); + asm volatile("bndmk 0x12345678(%rax,%rcx,1), %bnd0"); + asm volatile("bndmk 0x12345678(%rax,%rcx,8), %bnd0"); + + /* bndcl r/m64, bnd */ + + asm volatile("bndcl (%rax), %bnd0"); + asm volatile("bndcl (%r8), %bnd0"); + asm volatile("bndcl (0x12345678), %bnd0"); + asm volatile("bndcl (%rax), %bnd3"); + asm volatile("bndcl (%rcx,%rax,1), %bnd0"); + asm volatile("bndcl 0x12345678(,%rax,1), %bnd0"); + asm volatile("bndcl (%rax,%rcx,1), %bnd0"); + asm volatile("bndcl (%rax,%rcx,8), %bnd0"); + asm volatile("bndcl 0x12(%rax), %bnd0"); + asm volatile("bndcl 0x12(%rbp), %bnd0"); + asm volatile("bndcl 0x12(%rcx,%rax,1), %bnd0"); + asm volatile("bndcl 0x12(%rbp,%rax,1), %bnd0"); + asm volatile("bndcl 0x12(%rax,%rcx,1), %bnd0"); + asm volatile("bndcl 0x12(%rax,%rcx,8), %bnd0"); + asm volatile("bndcl 0x12345678(%rax), %bnd0"); + asm volatile("bndcl 0x12345678(%rbp), %bnd0"); + asm volatile("bndcl 0x12345678(%rcx,%rax,1), %bnd0"); + asm volatile("bndcl 0x12345678(%rbp,%rax,1), %bnd0"); + asm volatile("bndcl 0x12345678(%rax,%rcx,1), %bnd0"); + asm volatile("bndcl 0x12345678(%rax,%rcx,8), %bnd0"); + asm volatile("bndcl %rax, %bnd0"); + + /* bndcu r/m64, bnd */ + + asm volatile("bndcu (%rax), %bnd0"); + asm volatile("bndcu (%r8), %bnd0"); + asm volatile("bndcu (0x12345678), %bnd0"); + asm volatile("bndcu (%rax), %bnd3"); + asm volatile("bndcu (%rcx,%rax,1), %bnd0"); + asm volatile("bndcu 0x12345678(,%rax,1), %bnd0"); + asm volatile("bndcu (%rax,%rcx,1), %bnd0"); + asm volatile("bndcu (%rax,%rcx,8), %bnd0"); + asm volatile("bndcu 0x12(%rax), %bnd0"); + asm volatile("bndcu 0x12(%rbp), %bnd0"); + asm volatile("bndcu 0x12(%rcx,%rax,1), %bnd0"); + asm volatile("bndcu 0x12(%rbp,%rax,1), %bnd0"); + asm volatile("bndcu 0x12(%rax,%rcx,1), %bnd0"); + asm volatile("bndcu 0x12(%rax,%rcx,8), %bnd0"); + asm volatile("bndcu 0x12345678(%rax), %bnd0"); + asm volatile("bndcu 0x12345678(%rbp), %bnd0"); + asm volatile("bndcu 0x12345678(%rcx,%rax,1), %bnd0"); + asm volatile("bndcu 0x12345678(%rbp,%rax,1), %bnd0"); + asm volatile("bndcu 0x12345678(%rax,%rcx,1), %bnd0"); + asm volatile("bndcu 0x12345678(%rax,%rcx,8), %bnd0"); + asm volatile("bndcu %rax, %bnd0"); + + /* bndcn r/m64, bnd */ + + asm volatile("bndcn (%rax), %bnd0"); + asm volatile("bndcn (%r8), %bnd0"); + asm volatile("bndcn (0x12345678), %bnd0"); + asm volatile("bndcn (%rax), %bnd3"); + asm volatile("bndcn (%rcx,%rax,1), %bnd0"); + asm volatile("bndcn 0x12345678(,%rax,1), %bnd0"); + asm volatile("bndcn (%rax,%rcx,1), %bnd0"); + asm volatile("bndcn (%rax,%rcx,8), %bnd0"); + asm volatile("bndcn 0x12(%rax), %bnd0"); + asm volatile("bndcn 0x12(%rbp), %bnd0"); + asm volatile("bndcn 0x12(%rcx,%rax,1), %bnd0"); + asm volatile("bndcn 0x12(%rbp,%rax,1), %bnd0"); + asm volatile("bndcn 0x12(%rax,%rcx,1), %bnd0"); + asm volatile("bndcn 0x12(%rax,%rcx,8), %bnd0"); + asm volatile("bndcn 0x12345678(%rax), %bnd0"); + asm volatile("bndcn 0x12345678(%rbp), %bnd0"); + asm volatile("bndcn 0x12345678(%rcx,%rax,1), %bnd0"); + asm volatile("bndcn 0x12345678(%rbp,%rax,1), %bnd0"); + asm volatile("bndcn 0x12345678(%rax,%rcx,1), %bnd0"); + asm volatile("bndcn 0x12345678(%rax,%rcx,8), %bnd0"); + asm volatile("bndcn %rax, %bnd0"); + + /* bndmov m128, bnd */ + + asm volatile("bndmov (%rax), %bnd0"); + asm volatile("bndmov (%r8), %bnd0"); + asm volatile("bndmov (0x12345678), %bnd0"); + asm volatile("bndmov (%rax), %bnd3"); + asm volatile("bndmov (%rcx,%rax,1), %bnd0"); + asm volatile("bndmov 0x12345678(,%rax,1), %bnd0"); + asm volatile("bndmov (%rax,%rcx,1), %bnd0"); + asm volatile("bndmov (%rax,%rcx,8), %bnd0"); + asm volatile("bndmov 0x12(%rax), %bnd0"); + asm volatile("bndmov 0x12(%rbp), %bnd0"); + asm volatile("bndmov 0x12(%rcx,%rax,1), %bnd0"); + asm volatile("bndmov 0x12(%rbp,%rax,1), %bnd0"); + asm volatile("bndmov 0x12(%rax,%rcx,1), %bnd0"); + asm volatile("bndmov 0x12(%rax,%rcx,8), %bnd0"); + asm volatile("bndmov 0x12345678(%rax), %bnd0"); + asm volatile("bndmov 0x12345678(%rbp), %bnd0"); + asm volatile("bndmov 0x12345678(%rcx,%rax,1), %bnd0"); + asm volatile("bndmov 0x12345678(%rbp,%rax,1), %bnd0"); + asm volatile("bndmov 0x12345678(%rax,%rcx,1), %bnd0"); + asm volatile("bndmov 0x12345678(%rax,%rcx,8), %bnd0"); + + /* bndmov bnd, m128 */ + + asm volatile("bndmov %bnd0, (%rax)"); + asm volatile("bndmov %bnd0, (%r8)"); + asm volatile("bndmov %bnd0, (0x12345678)"); + asm volatile("bndmov %bnd3, (%rax)"); + asm volatile("bndmov %bnd0, (%rcx,%rax,1)"); + asm volatile("bndmov %bnd0, 0x12345678(,%rax,1)"); + asm volatile("bndmov %bnd0, (%rax,%rcx,1)"); + asm volatile("bndmov %bnd0, (%rax,%rcx,8)"); + asm volatile("bndmov %bnd0, 0x12(%rax)"); + asm volatile("bndmov %bnd0, 0x12(%rbp)"); + asm volatile("bndmov %bnd0, 0x12(%rcx,%rax,1)"); + asm volatile("bndmov %bnd0, 0x12(%rbp,%rax,1)"); + asm volatile("bndmov %bnd0, 0x12(%rax,%rcx,1)"); + asm volatile("bndmov %bnd0, 0x12(%rax,%rcx,8)"); + asm volatile("bndmov %bnd0, 0x12345678(%rax)"); + asm volatile("bndmov %bnd0, 0x12345678(%rbp)"); + asm volatile("bndmov %bnd0, 0x12345678(%rcx,%rax,1)"); + asm volatile("bndmov %bnd0, 0x12345678(%rbp,%rax,1)"); + asm volatile("bndmov %bnd0, 0x12345678(%rax,%rcx,1)"); + asm volatile("bndmov %bnd0, 0x12345678(%rax,%rcx,8)"); + + /* bndmov bnd2, bnd1 */ + + asm volatile("bndmov %bnd0, %bnd1"); + asm volatile("bndmov %bnd1, %bnd0"); + + /* bndldx mib, bnd */ + + asm volatile("bndldx (%rax), %bnd0"); + asm volatile("bndldx (%r8), %bnd0"); + asm volatile("bndldx (0x12345678), %bnd0"); + asm volatile("bndldx (%rax), %bnd3"); + asm volatile("bndldx (%rcx,%rax,1), %bnd0"); + asm volatile("bndldx 0x12345678(,%rax,1), %bnd0"); + asm volatile("bndldx (%rax,%rcx,1), %bnd0"); + asm volatile("bndldx 0x12(%rax), %bnd0"); + asm volatile("bndldx 0x12(%rbp), %bnd0"); + asm volatile("bndldx 0x12(%rcx,%rax,1), %bnd0"); + asm volatile("bndldx 0x12(%rbp,%rax,1), %bnd0"); + asm volatile("bndldx 0x12(%rax,%rcx,1), %bnd0"); + asm volatile("bndldx 0x12345678(%rax), %bnd0"); + asm volatile("bndldx 0x12345678(%rbp), %bnd0"); + asm volatile("bndldx 0x12345678(%rcx,%rax,1), %bnd0"); + asm volatile("bndldx 0x12345678(%rbp,%rax,1), %bnd0"); + asm volatile("bndldx 0x12345678(%rax,%rcx,1), %bnd0"); + + /* bndstx bnd, mib */ + + asm volatile("bndstx %bnd0, (%rax)"); + asm volatile("bndstx %bnd0, (%r8)"); + asm volatile("bndstx %bnd0, (0x12345678)"); + asm volatile("bndstx %bnd3, (%rax)"); + asm volatile("bndstx %bnd0, (%rcx,%rax,1)"); + asm volatile("bndstx %bnd0, 0x12345678(,%rax,1)"); + asm volatile("bndstx %bnd0, (%rax,%rcx,1)"); + asm volatile("bndstx %bnd0, 0x12(%rax)"); + asm volatile("bndstx %bnd0, 0x12(%rbp)"); + asm volatile("bndstx %bnd0, 0x12(%rcx,%rax,1)"); + asm volatile("bndstx %bnd0, 0x12(%rbp,%rax,1)"); + asm volatile("bndstx %bnd0, 0x12(%rax,%rcx,1)"); + asm volatile("bndstx %bnd0, 0x12345678(%rax)"); + asm volatile("bndstx %bnd0, 0x12345678(%rbp)"); + asm volatile("bndstx %bnd0, 0x12345678(%rcx,%rax,1)"); + asm volatile("bndstx %bnd0, 0x12345678(%rbp,%rax,1)"); + asm volatile("bndstx %bnd0, 0x12345678(%rax,%rcx,1)"); + + /* bnd prefix on call, ret, jmp and all jcc */ + + asm volatile("bnd call label1"); /* Expecting: call unconditional 0 */ + asm volatile("bnd call *(%eax)"); /* Expecting: call indirect 0 */ + asm volatile("bnd ret"); /* Expecting: ret indirect 0 */ + asm volatile("bnd jmp label1"); /* Expecting: jmp unconditional 0 */ + asm volatile("bnd jmp label1"); /* Expecting: jmp unconditional 0 */ + asm volatile("bnd jmp *(%ecx)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jne label1"); /* Expecting: jcc conditional 0 */ + +#else /* #ifdef __x86_64__ */ + + /* bndmk m32, bnd */ + + asm volatile("bndmk (%eax), %bnd0"); + asm volatile("bndmk (0x12345678), %bnd0"); + asm volatile("bndmk (%eax), %bnd3"); + asm volatile("bndmk (%ecx,%eax,1), %bnd0"); + asm volatile("bndmk 0x12345678(,%eax,1), %bnd0"); + asm volatile("bndmk (%eax,%ecx,1), %bnd0"); + asm volatile("bndmk (%eax,%ecx,8), %bnd0"); + asm volatile("bndmk 0x12(%eax), %bnd0"); + asm volatile("bndmk 0x12(%ebp), %bnd0"); + asm volatile("bndmk 0x12(%ecx,%eax,1), %bnd0"); + asm volatile("bndmk 0x12(%ebp,%eax,1), %bnd0"); + asm volatile("bndmk 0x12(%eax,%ecx,1), %bnd0"); + asm volatile("bndmk 0x12(%eax,%ecx,8), %bnd0"); + asm volatile("bndmk 0x12345678(%eax), %bnd0"); + asm volatile("bndmk 0x12345678(%ebp), %bnd0"); + asm volatile("bndmk 0x12345678(%ecx,%eax,1), %bnd0"); + asm volatile("bndmk 0x12345678(%ebp,%eax,1), %bnd0"); + asm volatile("bndmk 0x12345678(%eax,%ecx,1), %bnd0"); + asm volatile("bndmk 0x12345678(%eax,%ecx,8), %bnd0"); + + /* bndcl r/m32, bnd */ + + asm volatile("bndcl (%eax), %bnd0"); + asm volatile("bndcl (0x12345678), %bnd0"); + asm volatile("bndcl (%eax), %bnd3"); + asm volatile("bndcl (%ecx,%eax,1), %bnd0"); + asm volatile("bndcl 0x12345678(,%eax,1), %bnd0"); + asm volatile("bndcl (%eax,%ecx,1), %bnd0"); + asm volatile("bndcl (%eax,%ecx,8), %bnd0"); + asm volatile("bndcl 0x12(%eax), %bnd0"); + asm volatile("bndcl 0x12(%ebp), %bnd0"); + asm volatile("bndcl 0x12(%ecx,%eax,1), %bnd0"); + asm volatile("bndcl 0x12(%ebp,%eax,1), %bnd0"); + asm volatile("bndcl 0x12(%eax,%ecx,1), %bnd0"); + asm volatile("bndcl 0x12(%eax,%ecx,8), %bnd0"); + asm volatile("bndcl 0x12345678(%eax), %bnd0"); + asm volatile("bndcl 0x12345678(%ebp), %bnd0"); + asm volatile("bndcl 0x12345678(%ecx,%eax,1), %bnd0"); + asm volatile("bndcl 0x12345678(%ebp,%eax,1), %bnd0"); + asm volatile("bndcl 0x12345678(%eax,%ecx,1), %bnd0"); + asm volatile("bndcl 0x12345678(%eax,%ecx,8), %bnd0"); + asm volatile("bndcl %eax, %bnd0"); + + /* bndcu r/m32, bnd */ + + asm volatile("bndcu (%eax), %bnd0"); + asm volatile("bndcu (0x12345678), %bnd0"); + asm volatile("bndcu (%eax), %bnd3"); + asm volatile("bndcu (%ecx,%eax,1), %bnd0"); + asm volatile("bndcu 0x12345678(,%eax,1), %bnd0"); + asm volatile("bndcu (%eax,%ecx,1), %bnd0"); + asm volatile("bndcu (%eax,%ecx,8), %bnd0"); + asm volatile("bndcu 0x12(%eax), %bnd0"); + asm volatile("bndcu 0x12(%ebp), %bnd0"); + asm volatile("bndcu 0x12(%ecx,%eax,1), %bnd0"); + asm volatile("bndcu 0x12(%ebp,%eax,1), %bnd0"); + asm volatile("bndcu 0x12(%eax,%ecx,1), %bnd0"); + asm volatile("bndcu 0x12(%eax,%ecx,8), %bnd0"); + asm volatile("bndcu 0x12345678(%eax), %bnd0"); + asm volatile("bndcu 0x12345678(%ebp), %bnd0"); + asm volatile("bndcu 0x12345678(%ecx,%eax,1), %bnd0"); + asm volatile("bndcu 0x12345678(%ebp,%eax,1), %bnd0"); + asm volatile("bndcu 0x12345678(%eax,%ecx,1), %bnd0"); + asm volatile("bndcu 0x12345678(%eax,%ecx,8), %bnd0"); + asm volatile("bndcu %eax, %bnd0"); + + /* bndcn r/m32, bnd */ + + asm volatile("bndcn (%eax), %bnd0"); + asm volatile("bndcn (0x12345678), %bnd0"); + asm volatile("bndcn (%eax), %bnd3"); + asm volatile("bndcn (%ecx,%eax,1), %bnd0"); + asm volatile("bndcn 0x12345678(,%eax,1), %bnd0"); + asm volatile("bndcn (%eax,%ecx,1), %bnd0"); + asm volatile("bndcn (%eax,%ecx,8), %bnd0"); + asm volatile("bndcn 0x12(%eax), %bnd0"); + asm volatile("bndcn 0x12(%ebp), %bnd0"); + asm volatile("bndcn 0x12(%ecx,%eax,1), %bnd0"); + asm volatile("bndcn 0x12(%ebp,%eax,1), %bnd0"); + asm volatile("bndcn 0x12(%eax,%ecx,1), %bnd0"); + asm volatile("bndcn 0x12(%eax,%ecx,8), %bnd0"); + asm volatile("bndcn 0x12345678(%eax), %bnd0"); + asm volatile("bndcn 0x12345678(%ebp), %bnd0"); + asm volatile("bndcn 0x12345678(%ecx,%eax,1), %bnd0"); + asm volatile("bndcn 0x12345678(%ebp,%eax,1), %bnd0"); + asm volatile("bndcn 0x12345678(%eax,%ecx,1), %bnd0"); + asm volatile("bndcn 0x12345678(%eax,%ecx,8), %bnd0"); + asm volatile("bndcn %eax, %bnd0"); + + /* bndmov m64, bnd */ + + asm volatile("bndmov (%eax), %bnd0"); + asm volatile("bndmov (0x12345678), %bnd0"); + asm volatile("bndmov (%eax), %bnd3"); + asm volatile("bndmov (%ecx,%eax,1), %bnd0"); + asm volatile("bndmov 0x12345678(,%eax,1), %bnd0"); + asm volatile("bndmov (%eax,%ecx,1), %bnd0"); + asm volatile("bndmov (%eax,%ecx,8), %bnd0"); + asm volatile("bndmov 0x12(%eax), %bnd0"); + asm volatile("bndmov 0x12(%ebp), %bnd0"); + asm volatile("bndmov 0x12(%ecx,%eax,1), %bnd0"); + asm volatile("bndmov 0x12(%ebp,%eax,1), %bnd0"); + asm volatile("bndmov 0x12(%eax,%ecx,1), %bnd0"); + asm volatile("bndmov 0x12(%eax,%ecx,8), %bnd0"); + asm volatile("bndmov 0x12345678(%eax), %bnd0"); + asm volatile("bndmov 0x12345678(%ebp), %bnd0"); + asm volatile("bndmov 0x12345678(%ecx,%eax,1), %bnd0"); + asm volatile("bndmov 0x12345678(%ebp,%eax,1), %bnd0"); + asm volatile("bndmov 0x12345678(%eax,%ecx,1), %bnd0"); + asm volatile("bndmov 0x12345678(%eax,%ecx,8), %bnd0"); + + /* bndmov bnd, m64 */ + + asm volatile("bndmov %bnd0, (%eax)"); + asm volatile("bndmov %bnd0, (0x12345678)"); + asm volatile("bndmov %bnd3, (%eax)"); + asm volatile("bndmov %bnd0, (%ecx,%eax,1)"); + asm volatile("bndmov %bnd0, 0x12345678(,%eax,1)"); + asm volatile("bndmov %bnd0, (%eax,%ecx,1)"); + asm volatile("bndmov %bnd0, (%eax,%ecx,8)"); + asm volatile("bndmov %bnd0, 0x12(%eax)"); + asm volatile("bndmov %bnd0, 0x12(%ebp)"); + asm volatile("bndmov %bnd0, 0x12(%ecx,%eax,1)"); + asm volatile("bndmov %bnd0, 0x12(%ebp,%eax,1)"); + asm volatile("bndmov %bnd0, 0x12(%eax,%ecx,1)"); + asm volatile("bndmov %bnd0, 0x12(%eax,%ecx,8)"); + asm volatile("bndmov %bnd0, 0x12345678(%eax)"); + asm volatile("bndmov %bnd0, 0x12345678(%ebp)"); + asm volatile("bndmov %bnd0, 0x12345678(%ecx,%eax,1)"); + asm volatile("bndmov %bnd0, 0x12345678(%ebp,%eax,1)"); + asm volatile("bndmov %bnd0, 0x12345678(%eax,%ecx,1)"); + asm volatile("bndmov %bnd0, 0x12345678(%eax,%ecx,8)"); + + /* bndmov bnd2, bnd1 */ + + asm volatile("bndmov %bnd0, %bnd1"); + asm volatile("bndmov %bnd1, %bnd0"); + + /* bndldx mib, bnd */ + + asm volatile("bndldx (%eax), %bnd0"); + asm volatile("bndldx (0x12345678), %bnd0"); + asm volatile("bndldx (%eax), %bnd3"); + asm volatile("bndldx (%ecx,%eax,1), %bnd0"); + asm volatile("bndldx 0x12345678(,%eax,1), %bnd0"); + asm volatile("bndldx (%eax,%ecx,1), %bnd0"); + asm volatile("bndldx 0x12(%eax), %bnd0"); + asm volatile("bndldx 0x12(%ebp), %bnd0"); + asm volatile("bndldx 0x12(%ecx,%eax,1), %bnd0"); + asm volatile("bndldx 0x12(%ebp,%eax,1), %bnd0"); + asm volatile("bndldx 0x12(%eax,%ecx,1), %bnd0"); + asm volatile("bndldx 0x12345678(%eax), %bnd0"); + asm volatile("bndldx 0x12345678(%ebp), %bnd0"); + asm volatile("bndldx 0x12345678(%ecx,%eax,1), %bnd0"); + asm volatile("bndldx 0x12345678(%ebp,%eax,1), %bnd0"); + asm volatile("bndldx 0x12345678(%eax,%ecx,1), %bnd0"); + + /* bndstx bnd, mib */ + + asm volatile("bndstx %bnd0, (%eax)"); + asm volatile("bndstx %bnd0, (0x12345678)"); + asm volatile("bndstx %bnd3, (%eax)"); + asm volatile("bndstx %bnd0, (%ecx,%eax,1)"); + asm volatile("bndstx %bnd0, 0x12345678(,%eax,1)"); + asm volatile("bndstx %bnd0, (%eax,%ecx,1)"); + asm volatile("bndstx %bnd0, 0x12(%eax)"); + asm volatile("bndstx %bnd0, 0x12(%ebp)"); + asm volatile("bndstx %bnd0, 0x12(%ecx,%eax,1)"); + asm volatile("bndstx %bnd0, 0x12(%ebp,%eax,1)"); + asm volatile("bndstx %bnd0, 0x12(%eax,%ecx,1)"); + asm volatile("bndstx %bnd0, 0x12345678(%eax)"); + asm volatile("bndstx %bnd0, 0x12345678(%ebp)"); + asm volatile("bndstx %bnd0, 0x12345678(%ecx,%eax,1)"); + asm volatile("bndstx %bnd0, 0x12345678(%ebp,%eax,1)"); + asm volatile("bndstx %bnd0, 0x12345678(%eax,%ecx,1)"); + + /* bnd prefix on call, ret, jmp and all jcc */ + + asm volatile("bnd call label1"); /* Expecting: call unconditional 0xfffffffc */ + asm volatile("bnd call *(%eax)"); /* Expecting: call indirect 0 */ + asm volatile("bnd ret"); /* Expecting: ret indirect 0 */ + asm volatile("bnd jmp label1"); /* Expecting: jmp unconditional 0xfffffffc */ + asm volatile("bnd jmp label1"); /* Expecting: jmp unconditional 0xfffffffc */ + asm volatile("bnd jmp *(%ecx)"); /* Expecting: jmp indirect 0 */ + asm volatile("bnd jne label1"); /* Expecting: jcc conditional 0xfffffffc */ + +#endif /* #ifndef __x86_64__ */ + + /* Following line is a marker for the awk script - do not change */ + asm volatile("rdtsc"); /* Stop here */ + + return 0; +} diff --git a/tools/perf/tests/insn-x86.c b/tools/perf/tests/insn-x86.c new file mode 100644 index 000000000000..0e126a099874 --- /dev/null +++ b/tools/perf/tests/insn-x86.c @@ -0,0 +1,180 @@ +#include + +#include "debug.h" +#include "tests.h" + +#include "intel-pt-decoder/insn.h" +#include "intel-pt-decoder/intel-pt-insn-decoder.h" + +struct test_data { + u8 data[MAX_INSN_SIZE]; + int expected_length; + int expected_rel; + const char *expected_op_str; + const char *expected_branch_str; + const char *asm_rep; +}; + +struct test_data test_data_32[] = { +#include "insn-x86-dat-32.c" + {{0}, 0, 0, NULL, NULL, NULL}, +}; + +struct test_data test_data_64[] = { +#include "insn-x86-dat-64.c" + {{0}, 0, 0, NULL, NULL, NULL}, +}; + +static int get_op(const char *op_str) +{ + struct val_data { + const char *name; + int val; + } vals[] = { + {"other", INTEL_PT_OP_OTHER}, + {"call", INTEL_PT_OP_CALL}, + {"ret", INTEL_PT_OP_RET}, + {"jcc", INTEL_PT_OP_JCC}, + {"jmp", INTEL_PT_OP_JMP}, + {"loop", INTEL_PT_OP_LOOP}, + {"iret", INTEL_PT_OP_IRET}, + {"int", INTEL_PT_OP_INT}, + {"syscall", INTEL_PT_OP_SYSCALL}, + {"sysret", INTEL_PT_OP_SYSRET}, + {NULL, 0}, + }; + struct val_data *val; + + if (!op_str || !strlen(op_str)) + return 0; + + for (val = vals; val->name; val++) { + if (!strcmp(val->name, op_str)) + return val->val; + } + + pr_debug("Failed to get op\n"); + + return -1; +} + +static int get_branch(const char *branch_str) +{ + struct val_data { + const char *name; + int val; + } vals[] = { + {"no_branch", INTEL_PT_BR_NO_BRANCH}, + {"indirect", INTEL_PT_BR_INDIRECT}, + {"conditional", INTEL_PT_BR_CONDITIONAL}, + {"unconditional", INTEL_PT_BR_UNCONDITIONAL}, + {NULL, 0}, + }; + struct val_data *val; + + if (!branch_str || !strlen(branch_str)) + return 0; + + for (val = vals; val->name; val++) { + if (!strcmp(val->name, branch_str)) + return val->val; + } + + pr_debug("Failed to get branch\n"); + + return -1; +} + +static int test_data_item(struct test_data *dat, int x86_64) +{ + struct intel_pt_insn intel_pt_insn; + struct insn insn; + int op, branch; + + insn_init(&insn, dat->data, MAX_INSN_SIZE, x86_64); + insn_get_length(&insn); + + if (!insn_complete(&insn)) { + pr_debug("Failed to decode: %s\n", dat->asm_rep); + return -1; + } + + if (insn.length != dat->expected_length) { + pr_debug("Failed to decode length (%d vs expected %d): %s\n", + insn.length, dat->expected_length, dat->asm_rep); + return -1; + } + + op = get_op(dat->expected_op_str); + branch = get_branch(dat->expected_branch_str); + + if (intel_pt_get_insn(dat->data, MAX_INSN_SIZE, x86_64, &intel_pt_insn)) { + pr_debug("Intel PT failed to decode: %s\n", dat->asm_rep); + return -1; + } + + if ((int)intel_pt_insn.op != op) { + pr_debug("Failed to decode 'op' value (%d vs expected %d): %s\n", + intel_pt_insn.op, op, dat->asm_rep); + return -1; + } + + if ((int)intel_pt_insn.branch != branch) { + pr_debug("Failed to decode 'branch' value (%d vs expected %d): %s\n", + intel_pt_insn.branch, branch, dat->asm_rep); + return -1; + } + + if (intel_pt_insn.rel != dat->expected_rel) { + pr_debug("Failed to decode 'rel' value (%#x vs expected %#x): %s\n", + intel_pt_insn.rel, dat->expected_rel, dat->asm_rep); + return -1; + } + + pr_debug("Decoded ok: %s\n", dat->asm_rep); + + return 0; +} + +static int test_data_set(struct test_data *dat_set, int x86_64) +{ + struct test_data *dat; + int ret = 0; + + for (dat = dat_set; dat->expected_length; dat++) { + if (test_data_item(dat, x86_64)) + ret = -1; + } + + return ret; +} + +/** + * test__insn_x86 - test x86 instruction decoder - new instructions. + * + * This function implements a test that decodes a selection of instructions and + * checks the results. The Intel PT function that further categorizes + * instructions (i.e. intel_pt_get_insn()) is also checked. + * + * The instructions are originally in insn-x86-dat-src.c which has been + * processed by scripts gen-insn-x86-dat.sh and gen-insn-x86-dat.awk to produce + * insn-x86-dat-32.c and insn-x86-dat-64.c which are included into this program. + * i.e. to add new instructions to the test, edit insn-x86-dat-src.c, run the + * gen-insn-x86-dat.sh script, make perf, and then run the test. + * + * If the test passes %0 is returned, otherwise %-1 is returned. Use the + * verbose (-v) option to see all the instructions and whether or not they + * decoded successfuly. + */ +int test__insn_x86(void) +{ + int ret = 0; + + if (test_data_set(test_data_32, 0)) + ret = -1; + + if (test_data_set(test_data_64, 1)) + ret = -1; + + return ret; +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index bf113a247987..4e2c5458269a 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -63,6 +63,7 @@ int test__fdarray__add(void); int test__kmod_path__parse(void); int test__thread_map(void); int test__llvm(void); +int test__insn_x86(void); #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT From 78173ec6311a22ca9f42cf949cf37754a8b71633 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:27 +0300 Subject: [PATCH 019/260] x86/insn: perf tools: Pedantically tweak opcode map for MPX instructions The MPX instructions are presently not described in the SDM opcode maps, and there are not encoding characters for bnd registers, address method or operand type. So the kernel opcode map is using 'Gv' for bnd registers and 'Ev' for everything else. That is fine because the instruction decoder does not use that information anyway, except as an indication that there is a ModR/M byte. Nevertheless, in some cases the 'Gv' and 'Ev' are the wrong way around, BNDLDX and BNDSTX have 2 operands not 3, and it wouldn't hurt to identify the mandatory prefixes. This has no effect on the decoding of valid instructions, but the addition of the mandatory prefixes will cause some invalid instructions to error out that wouldn't have previously. Note that perf tools has a copy of the instruction decoder and provides a test for new instructions which includes MPX instructions e.g. $ perf test "x86 ins" 39: Test x86 instruction decoder - new instructions : Ok Or to see the details: $ perf test -v "x86 ins" Commiter notes: And to see these MPX instructions specifically: $ perf test -v "x86 ins" 2>&1 | grep bndldx | head -3 Decoded ok: 0f 1a 00 bndldx (%eax),%bnd0 Decoded ok: 0f 1a 05 78 56 34 12 bndldx 0x12345678,%bnd0 Decoded ok: 0f 1a 18 bndldx (%eax),%bnd3 $ perf test -v "x86 ins" 2>&1 | grep bndstx | head -3 Decoded ok: 0f 1b 00 bndstx %bnd0,(%eax) Decoded ok: 0f 1b 05 78 56 34 12 bndstx %bnd0,0x12345678 Decoded ok: 0f 1b 18 bndstx %bnd3,(%eax) $ Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 8 ++++++-- tools/perf/util/intel-pt-decoder/x86-opcode-map.txt | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 816488c0b97e..a02a195d219c 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -353,8 +353,12 @@ AVXcode: 1 17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) 18: Grp16 (1A) 19: -1a: BNDCL Ev,Gv | BNDCU Ev,Gv | BNDMOV Gv,Ev | BNDLDX Gv,Ev,Gv -1b: BNDCN Ev,Gv | BNDMOV Ev,Gv | BNDMK Gv,Ev | BNDSTX Ev,GV,Gv +# Intel SDM opcode map does not list MPX instructions. For now using Gv for +# bnd registers and Ev for everything else is OK because the instruction +# decoder does not use the information except as an indication that there is +# a ModR/M byte. +1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev +1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv 1c: 1d: 1e: diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 816488c0b97e..a02a195d219c 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -353,8 +353,12 @@ AVXcode: 1 17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) 18: Grp16 (1A) 19: -1a: BNDCL Ev,Gv | BNDCU Ev,Gv | BNDMOV Gv,Ev | BNDLDX Gv,Ev,Gv -1b: BNDCN Ev,Gv | BNDMOV Ev,Gv | BNDMK Gv,Ev | BNDSTX Ev,GV,Gv +# Intel SDM opcode map does not list MPX instructions. For now using Gv for +# bnd registers and Ev for everything else is OK because the instruction +# decoder does not use the information except as an indication that there is +# a ModR/M byte. +1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev +1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv 1c: 1d: 1e: From 3fe78d6af9e2f08c4014fd3ccbf9e1ff312dedf1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:28 +0300 Subject: [PATCH 020/260] x86/insn: perf tools: Add new SHA instructions Intel SHA Extensions are explained in the Intel Architecture Instruction Set Extensions Programing Reference (Oct 2014). There are 7 new instructions. Add them to the op code map and the perf tools new instructions test. e.g. $ tools/perf/perf test "x86 ins" 39: Test x86 instruction decoder - new instructions : Ok Or to see the details: $ tools/perf/perf test -v "x86 ins" 2>&1 | grep sha Committer note: 3 lines of details, for the curious: $ perf test -v "x86 ins" 2>&1 | grep sha256msg1 | tail -3 Decoded ok: 0f 38 cc 84 08 78 56 34 12 sha256msg1 0x12345678(%rax,%rcx,1),%xmm0 Decoded ok: 0f 38 cc 84 c8 78 56 34 12 sha256msg1 0x12345678(%rax,%rcx,8),%xmm0 Decoded ok: 44 0f 38 cc bc c8 78 56 34 12 sha256msg1 0x12345678(%rax,%rcx,8),%xmm15 $ Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 7 + tools/perf/tests/insn-x86-dat-32.c | 294 ++++++++++++++ tools/perf/tests/insn-x86-dat-64.c | 364 +++++++++++++++++ tools/perf/tests/insn-x86-dat-src.c | 373 ++++++++++++++++++ .../util/intel-pt-decoder/x86-opcode-map.txt | 7 + 5 files changed, 1045 insertions(+) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index a02a195d219c..25dad388b371 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -736,6 +736,12 @@ bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) # 0x0f 0x38 0xc0-0xff +c8: sha1nexte Vdq,Wdq +c9: sha1msg1 Vdq,Wdq +ca: sha1msg2 Vdq,Wdq +cb: sha256rnds2 Vdq,Wdq +cc: sha256msg1 Vdq,Wdq +cd: sha256msg2 Vdq,Wdq db: VAESIMC Vdq,Wdq (66),(v1) dc: VAESENC Vdq,Hdq,Wdq (66),(v1) dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) @@ -794,6 +800,7 @@ AVXcode: 3 61: vpcmpestri Vdq,Wdq,Ib (66),(v1) 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) 63: vpcmpistri Vdq,Wdq,Ib (66),(v1) +cc: sha1rnds4 Vdq,Wdq,Ib df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) f0: RORX Gy,Ey,Ib (F2),(v) EndTable diff --git a/tools/perf/tests/insn-x86-dat-32.c b/tools/perf/tests/insn-x86-dat-32.c index 6a38a34a5a49..83f5078e74e1 100644 --- a/tools/perf/tests/insn-x86-dat-32.c +++ b/tools/perf/tests/insn-x86-dat-32.c @@ -322,3 +322,297 @@ "f2 ff 21 \tbnd jmp *(%ecx)",}, {{0xf2, 0x0f, 0x85, 0xfc, 0xff, 0xff, 0xff, }, 7, 0xfffffffc, "jcc", "conditional", "f2 0f 85 fc ff ff ff \tbnd jne 3de ",}, +{{0x0f, 0x3a, 0xcc, 0xc1, 0x00, }, 5, 0, "", "", +"0f 3a cc c1 00 \tsha1rnds4 $0x0,%xmm1,%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0xd7, 0x91, }, 5, 0, "", "", +"0f 3a cc d7 91 \tsha1rnds4 $0x91,%xmm7,%xmm2",}, +{{0x0f, 0x3a, 0xcc, 0x00, 0x91, }, 5, 0, "", "", +"0f 3a cc 00 91 \tsha1rnds4 $0x91,(%eax),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x05, 0x78, 0x56, 0x34, 0x12, 0x91, }, 9, 0, "", "", +"0f 3a cc 05 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678,%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x18, 0x91, }, 5, 0, "", "", +"0f 3a cc 18 91 \tsha1rnds4 $0x91,(%eax),%xmm3",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x01, 0x91, }, 6, 0, "", "", +"0f 3a cc 04 01 91 \tsha1rnds4 $0x91,(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 04 05 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(,%eax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x08, 0x91, }, 6, 0, "", "", +"0f 3a cc 04 08 91 \tsha1rnds4 $0x91,(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0xc8, 0x91, }, 6, 0, "", "", +"0f 3a cc 04 c8 91 \tsha1rnds4 $0x91,(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x40, 0x12, 0x91, }, 6, 0, "", "", +"0f 3a cc 40 12 91 \tsha1rnds4 $0x91,0x12(%eax),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x45, 0x12, 0x91, }, 6, 0, "", "", +"0f 3a cc 45 12 91 \tsha1rnds4 $0x91,0x12(%ebp),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0x01, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 01 12 91 \tsha1rnds4 $0x91,0x12(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0x05, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 05 12 91 \tsha1rnds4 $0x91,0x12(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0x08, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 08 12 91 \tsha1rnds4 $0x91,0x12(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0xc8, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 c8 12 91 \tsha1rnds4 $0x91,0x12(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x80, 0x78, 0x56, 0x34, 0x12, 0x91, }, 9, 0, "", "", +"0f 3a cc 80 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%eax),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x85, 0x78, 0x56, 0x34, 0x12, 0x91, }, 9, 0, "", "", +"0f 3a cc 85 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%ebp),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 01 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 05 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 08 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 c8 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0xc1, }, 4, 0, "", "", +"0f 38 c8 c1 \tsha1nexte %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xc8, 0xd7, }, 4, 0, "", "", +"0f 38 c8 d7 \tsha1nexte %xmm7,%xmm2",}, +{{0x0f, 0x38, 0xc8, 0x00, }, 4, 0, "", "", +"0f 38 c8 00 \tsha1nexte (%eax),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c8 05 78 56 34 12 \tsha1nexte 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x18, }, 4, 0, "", "", +"0f 38 c8 18 \tsha1nexte (%eax),%xmm3",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 c8 04 01 \tsha1nexte (%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 04 05 78 56 34 12 \tsha1nexte 0x12345678(,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 c8 04 08 \tsha1nexte (%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 c8 04 c8 \tsha1nexte (%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 c8 40 12 \tsha1nexte 0x12(%eax),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 c8 45 12 \tsha1nexte 0x12(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 01 12 \tsha1nexte 0x12(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 05 12 \tsha1nexte 0x12(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 08 12 \tsha1nexte 0x12(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 c8 12 \tsha1nexte 0x12(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c8 80 78 56 34 12 \tsha1nexte 0x12345678(%eax),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c8 85 78 56 34 12 \tsha1nexte 0x12345678(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 01 78 56 34 12 \tsha1nexte 0x12345678(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 05 78 56 34 12 \tsha1nexte 0x12345678(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 08 78 56 34 12 \tsha1nexte 0x12345678(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 c8 78 56 34 12 \tsha1nexte 0x12345678(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0xc1, }, 4, 0, "", "", +"0f 38 c9 c1 \tsha1msg1 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xc9, 0xd7, }, 4, 0, "", "", +"0f 38 c9 d7 \tsha1msg1 %xmm7,%xmm2",}, +{{0x0f, 0x38, 0xc9, 0x00, }, 4, 0, "", "", +"0f 38 c9 00 \tsha1msg1 (%eax),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c9 05 78 56 34 12 \tsha1msg1 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x18, }, 4, 0, "", "", +"0f 38 c9 18 \tsha1msg1 (%eax),%xmm3",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 c9 04 01 \tsha1msg1 (%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 04 05 78 56 34 12 \tsha1msg1 0x12345678(,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 c9 04 08 \tsha1msg1 (%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 c9 04 c8 \tsha1msg1 (%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 c9 40 12 \tsha1msg1 0x12(%eax),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 c9 45 12 \tsha1msg1 0x12(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 01 12 \tsha1msg1 0x12(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 05 12 \tsha1msg1 0x12(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 08 12 \tsha1msg1 0x12(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 c8 12 \tsha1msg1 0x12(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c9 80 78 56 34 12 \tsha1msg1 0x12345678(%eax),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c9 85 78 56 34 12 \tsha1msg1 0x12345678(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 01 78 56 34 12 \tsha1msg1 0x12345678(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 05 78 56 34 12 \tsha1msg1 0x12345678(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 08 78 56 34 12 \tsha1msg1 0x12345678(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 c8 78 56 34 12 \tsha1msg1 0x12345678(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xca, 0xc1, }, 4, 0, "", "", +"0f 38 ca c1 \tsha1msg2 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xca, 0xd7, }, 4, 0, "", "", +"0f 38 ca d7 \tsha1msg2 %xmm7,%xmm2",}, +{{0x0f, 0x38, 0xca, 0x00, }, 4, 0, "", "", +"0f 38 ca 00 \tsha1msg2 (%eax),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 ca 05 78 56 34 12 \tsha1msg2 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xca, 0x18, }, 4, 0, "", "", +"0f 38 ca 18 \tsha1msg2 (%eax),%xmm3",}, +{{0x0f, 0x38, 0xca, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 ca 04 01 \tsha1msg2 (%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 04 05 78 56 34 12 \tsha1msg2 0x12345678(,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 ca 04 08 \tsha1msg2 (%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 ca 04 c8 \tsha1msg2 (%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 ca 40 12 \tsha1msg2 0x12(%eax),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 ca 45 12 \tsha1msg2 0x12(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 01 12 \tsha1msg2 0x12(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 05 12 \tsha1msg2 0x12(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 08 12 \tsha1msg2 0x12(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 c8 12 \tsha1msg2 0x12(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 ca 80 78 56 34 12 \tsha1msg2 0x12345678(%eax),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 ca 85 78 56 34 12 \tsha1msg2 0x12345678(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 01 78 56 34 12 \tsha1msg2 0x12345678(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 05 78 56 34 12 \tsha1msg2 0x12345678(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 08 78 56 34 12 \tsha1msg2 0x12345678(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 c8 78 56 34 12 \tsha1msg2 0x12345678(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xcb, 0xcc, }, 4, 0, "", "", +"0f 38 cb cc \tsha256rnds2 %xmm0,%xmm4,%xmm1",}, +{{0x0f, 0x38, 0xcb, 0xd7, }, 4, 0, "", "", +"0f 38 cb d7 \tsha256rnds2 %xmm0,%xmm7,%xmm2",}, +{{0x0f, 0x38, 0xcb, 0x08, }, 4, 0, "", "", +"0f 38 cb 08 \tsha256rnds2 %xmm0,(%eax),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0d, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cb 0d 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678,%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x18, }, 4, 0, "", "", +"0f 38 cb 18 \tsha256rnds2 %xmm0,(%eax),%xmm3",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x01, }, 5, 0, "", "", +"0f 38 cb 0c 01 \tsha256rnds2 %xmm0,(%ecx,%eax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 0c 05 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(,%eax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x08, }, 5, 0, "", "", +"0f 38 cb 0c 08 \tsha256rnds2 %xmm0,(%eax,%ecx,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0xc8, }, 5, 0, "", "", +"0f 38 cb 0c c8 \tsha256rnds2 %xmm0,(%eax,%ecx,8),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x48, 0x12, }, 5, 0, "", "", +"0f 38 cb 48 12 \tsha256rnds2 %xmm0,0x12(%eax),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4d, 0x12, }, 5, 0, "", "", +"0f 38 cb 4d 12 \tsha256rnds2 %xmm0,0x12(%ebp),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c 01 12 \tsha256rnds2 %xmm0,0x12(%ecx,%eax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c 05 12 \tsha256rnds2 %xmm0,0x12(%ebp,%eax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c 08 12 \tsha256rnds2 %xmm0,0x12(%eax,%ecx,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c c8 12 \tsha256rnds2 %xmm0,0x12(%eax,%ecx,8),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cb 88 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%eax),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8d, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cb 8d 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%ebp),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c 01 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%ecx,%eax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c 05 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%ebp,%eax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c 08 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%eax,%ecx,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c c8 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%eax,%ecx,8),%xmm1",}, +{{0x0f, 0x38, 0xcc, 0xc1, }, 4, 0, "", "", +"0f 38 cc c1 \tsha256msg1 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xcc, 0xd7, }, 4, 0, "", "", +"0f 38 cc d7 \tsha256msg1 %xmm7,%xmm2",}, +{{0x0f, 0x38, 0xcc, 0x00, }, 4, 0, "", "", +"0f 38 cc 00 \tsha256msg1 (%eax),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cc 05 78 56 34 12 \tsha256msg1 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x18, }, 4, 0, "", "", +"0f 38 cc 18 \tsha256msg1 (%eax),%xmm3",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 cc 04 01 \tsha256msg1 (%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 04 05 78 56 34 12 \tsha256msg1 0x12345678(,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 cc 04 08 \tsha256msg1 (%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 cc 04 c8 \tsha256msg1 (%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 cc 40 12 \tsha256msg1 0x12(%eax),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 cc 45 12 \tsha256msg1 0x12(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 01 12 \tsha256msg1 0x12(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 05 12 \tsha256msg1 0x12(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 08 12 \tsha256msg1 0x12(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 c8 12 \tsha256msg1 0x12(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cc 80 78 56 34 12 \tsha256msg1 0x12345678(%eax),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cc 85 78 56 34 12 \tsha256msg1 0x12345678(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 01 78 56 34 12 \tsha256msg1 0x12345678(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 05 78 56 34 12 \tsha256msg1 0x12345678(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 08 78 56 34 12 \tsha256msg1 0x12345678(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 c8 78 56 34 12 \tsha256msg1 0x12345678(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0xc1, }, 4, 0, "", "", +"0f 38 cd c1 \tsha256msg2 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xcd, 0xd7, }, 4, 0, "", "", +"0f 38 cd d7 \tsha256msg2 %xmm7,%xmm2",}, +{{0x0f, 0x38, 0xcd, 0x00, }, 4, 0, "", "", +"0f 38 cd 00 \tsha256msg2 (%eax),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x05, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cd 05 78 56 34 12 \tsha256msg2 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x18, }, 4, 0, "", "", +"0f 38 cd 18 \tsha256msg2 (%eax),%xmm3",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 cd 04 01 \tsha256msg2 (%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 04 05 78 56 34 12 \tsha256msg2 0x12345678(,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 cd 04 08 \tsha256msg2 (%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 cd 04 c8 \tsha256msg2 (%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 cd 40 12 \tsha256msg2 0x12(%eax),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 cd 45 12 \tsha256msg2 0x12(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 01 12 \tsha256msg2 0x12(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 05 12 \tsha256msg2 0x12(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 08 12 \tsha256msg2 0x12(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 c8 12 \tsha256msg2 0x12(%eax,%ecx,8),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cd 80 78 56 34 12 \tsha256msg2 0x12345678(%eax),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cd 85 78 56 34 12 \tsha256msg2 0x12345678(%ebp),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 01 78 56 34 12 \tsha256msg2 0x12345678(%ecx,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 05 78 56 34 12 \tsha256msg2 0x12345678(%ebp,%eax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 08 78 56 34 12 \tsha256msg2 0x12345678(%eax,%ecx,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 c8 78 56 34 12 \tsha256msg2 0x12345678(%eax,%ecx,8),%xmm0",}, diff --git a/tools/perf/tests/insn-x86-dat-64.c b/tools/perf/tests/insn-x86-dat-64.c index 01122421a776..13f008588590 100644 --- a/tools/perf/tests/insn-x86-dat-64.c +++ b/tools/perf/tests/insn-x86-dat-64.c @@ -338,3 +338,367 @@ "67 f2 ff 21 \tbnd jmpq *(%ecx)",}, {{0xf2, 0x0f, 0x85, 0x00, 0x00, 0x00, 0x00, }, 7, 0, "jcc", "conditional", "f2 0f 85 00 00 00 00 \tbnd jne 413 ",}, +{{0x0f, 0x3a, 0xcc, 0xc1, 0x00, }, 5, 0, "", "", +"0f 3a cc c1 00 \tsha1rnds4 $0x0,%xmm1,%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0xd7, 0x91, }, 5, 0, "", "", +"0f 3a cc d7 91 \tsha1rnds4 $0x91,%xmm7,%xmm2",}, +{{0x41, 0x0f, 0x3a, 0xcc, 0xc0, 0x91, }, 6, 0, "", "", +"41 0f 3a cc c0 91 \tsha1rnds4 $0x91,%xmm8,%xmm0",}, +{{0x44, 0x0f, 0x3a, 0xcc, 0xc7, 0x91, }, 6, 0, "", "", +"44 0f 3a cc c7 91 \tsha1rnds4 $0x91,%xmm7,%xmm8",}, +{{0x45, 0x0f, 0x3a, 0xcc, 0xc7, 0x91, }, 6, 0, "", "", +"45 0f 3a cc c7 91 \tsha1rnds4 $0x91,%xmm15,%xmm8",}, +{{0x0f, 0x3a, 0xcc, 0x00, 0x91, }, 5, 0, "", "", +"0f 3a cc 00 91 \tsha1rnds4 $0x91,(%rax),%xmm0",}, +{{0x41, 0x0f, 0x3a, 0xcc, 0x00, 0x91, }, 6, 0, "", "", +"41 0f 3a cc 00 91 \tsha1rnds4 $0x91,(%r8),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 04 25 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678,%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x18, 0x91, }, 5, 0, "", "", +"0f 3a cc 18 91 \tsha1rnds4 $0x91,(%rax),%xmm3",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x01, 0x91, }, 6, 0, "", "", +"0f 3a cc 04 01 91 \tsha1rnds4 $0x91,(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 04 05 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(,%rax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0x08, 0x91, }, 6, 0, "", "", +"0f 3a cc 04 08 91 \tsha1rnds4 $0x91,(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x04, 0xc8, 0x91, }, 6, 0, "", "", +"0f 3a cc 04 c8 91 \tsha1rnds4 $0x91,(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x40, 0x12, 0x91, }, 6, 0, "", "", +"0f 3a cc 40 12 91 \tsha1rnds4 $0x91,0x12(%rax),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x45, 0x12, 0x91, }, 6, 0, "", "", +"0f 3a cc 45 12 91 \tsha1rnds4 $0x91,0x12(%rbp),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0x01, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 01 12 91 \tsha1rnds4 $0x91,0x12(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0x05, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 05 12 91 \tsha1rnds4 $0x91,0x12(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0x08, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 08 12 91 \tsha1rnds4 $0x91,0x12(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x44, 0xc8, 0x12, 0x91, }, 7, 0, "", "", +"0f 3a cc 44 c8 12 91 \tsha1rnds4 $0x91,0x12(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x80, 0x78, 0x56, 0x34, 0x12, 0x91, }, 9, 0, "", "", +"0f 3a cc 80 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rax),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x85, 0x78, 0x56, 0x34, 0x12, 0x91, }, 9, 0, "", "", +"0f 3a cc 85 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rbp),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 01 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 05 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 08 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x3a, 0xcc, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, 0x91, }, 10, 0, "", "", +"0f 3a cc 84 c8 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rax,%rcx,8),%xmm0",}, +{{0x44, 0x0f, 0x3a, 0xcc, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, 0x91, }, 11, 0, "", "", +"44 0f 3a cc bc c8 78 56 34 12 91 \tsha1rnds4 $0x91,0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x0f, 0x38, 0xc8, 0xc1, }, 4, 0, "", "", +"0f 38 c8 c1 \tsha1nexte %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xc8, 0xd7, }, 4, 0, "", "", +"0f 38 c8 d7 \tsha1nexte %xmm7,%xmm2",}, +{{0x41, 0x0f, 0x38, 0xc8, 0xc0, }, 5, 0, "", "", +"41 0f 38 c8 c0 \tsha1nexte %xmm8,%xmm0",}, +{{0x44, 0x0f, 0x38, 0xc8, 0xc7, }, 5, 0, "", "", +"44 0f 38 c8 c7 \tsha1nexte %xmm7,%xmm8",}, +{{0x45, 0x0f, 0x38, 0xc8, 0xc7, }, 5, 0, "", "", +"45 0f 38 c8 c7 \tsha1nexte %xmm15,%xmm8",}, +{{0x0f, 0x38, 0xc8, 0x00, }, 4, 0, "", "", +"0f 38 c8 00 \tsha1nexte (%rax),%xmm0",}, +{{0x41, 0x0f, 0x38, 0xc8, 0x00, }, 5, 0, "", "", +"41 0f 38 c8 00 \tsha1nexte (%r8),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 04 25 78 56 34 12 \tsha1nexte 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x18, }, 4, 0, "", "", +"0f 38 c8 18 \tsha1nexte (%rax),%xmm3",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 c8 04 01 \tsha1nexte (%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 04 05 78 56 34 12 \tsha1nexte 0x12345678(,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 c8 04 08 \tsha1nexte (%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 c8 04 c8 \tsha1nexte (%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 c8 40 12 \tsha1nexte 0x12(%rax),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 c8 45 12 \tsha1nexte 0x12(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 01 12 \tsha1nexte 0x12(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 05 12 \tsha1nexte 0x12(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 08 12 \tsha1nexte 0x12(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 c8 44 c8 12 \tsha1nexte 0x12(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c8 80 78 56 34 12 \tsha1nexte 0x12345678(%rax),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c8 85 78 56 34 12 \tsha1nexte 0x12345678(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 01 78 56 34 12 \tsha1nexte 0x12345678(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 05 78 56 34 12 \tsha1nexte 0x12345678(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 08 78 56 34 12 \tsha1nexte 0x12345678(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xc8, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c8 84 c8 78 56 34 12 \tsha1nexte 0x12345678(%rax,%rcx,8),%xmm0",}, +{{0x44, 0x0f, 0x38, 0xc8, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"44 0f 38 c8 bc c8 78 56 34 12 \tsha1nexte 0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x0f, 0x38, 0xc9, 0xc1, }, 4, 0, "", "", +"0f 38 c9 c1 \tsha1msg1 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xc9, 0xd7, }, 4, 0, "", "", +"0f 38 c9 d7 \tsha1msg1 %xmm7,%xmm2",}, +{{0x41, 0x0f, 0x38, 0xc9, 0xc0, }, 5, 0, "", "", +"41 0f 38 c9 c0 \tsha1msg1 %xmm8,%xmm0",}, +{{0x44, 0x0f, 0x38, 0xc9, 0xc7, }, 5, 0, "", "", +"44 0f 38 c9 c7 \tsha1msg1 %xmm7,%xmm8",}, +{{0x45, 0x0f, 0x38, 0xc9, 0xc7, }, 5, 0, "", "", +"45 0f 38 c9 c7 \tsha1msg1 %xmm15,%xmm8",}, +{{0x0f, 0x38, 0xc9, 0x00, }, 4, 0, "", "", +"0f 38 c9 00 \tsha1msg1 (%rax),%xmm0",}, +{{0x41, 0x0f, 0x38, 0xc9, 0x00, }, 5, 0, "", "", +"41 0f 38 c9 00 \tsha1msg1 (%r8),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 04 25 78 56 34 12 \tsha1msg1 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x18, }, 4, 0, "", "", +"0f 38 c9 18 \tsha1msg1 (%rax),%xmm3",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 c9 04 01 \tsha1msg1 (%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 04 05 78 56 34 12 \tsha1msg1 0x12345678(,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 c9 04 08 \tsha1msg1 (%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 c9 04 c8 \tsha1msg1 (%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 c9 40 12 \tsha1msg1 0x12(%rax),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 c9 45 12 \tsha1msg1 0x12(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 01 12 \tsha1msg1 0x12(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 05 12 \tsha1msg1 0x12(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 08 12 \tsha1msg1 0x12(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 c9 44 c8 12 \tsha1msg1 0x12(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c9 80 78 56 34 12 \tsha1msg1 0x12345678(%rax),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 c9 85 78 56 34 12 \tsha1msg1 0x12345678(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 01 78 56 34 12 \tsha1msg1 0x12345678(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 05 78 56 34 12 \tsha1msg1 0x12345678(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 08 78 56 34 12 \tsha1msg1 0x12345678(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xc9, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 c9 84 c8 78 56 34 12 \tsha1msg1 0x12345678(%rax,%rcx,8),%xmm0",}, +{{0x44, 0x0f, 0x38, 0xc9, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"44 0f 38 c9 bc c8 78 56 34 12 \tsha1msg1 0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x0f, 0x38, 0xca, 0xc1, }, 4, 0, "", "", +"0f 38 ca c1 \tsha1msg2 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xca, 0xd7, }, 4, 0, "", "", +"0f 38 ca d7 \tsha1msg2 %xmm7,%xmm2",}, +{{0x41, 0x0f, 0x38, 0xca, 0xc0, }, 5, 0, "", "", +"41 0f 38 ca c0 \tsha1msg2 %xmm8,%xmm0",}, +{{0x44, 0x0f, 0x38, 0xca, 0xc7, }, 5, 0, "", "", +"44 0f 38 ca c7 \tsha1msg2 %xmm7,%xmm8",}, +{{0x45, 0x0f, 0x38, 0xca, 0xc7, }, 5, 0, "", "", +"45 0f 38 ca c7 \tsha1msg2 %xmm15,%xmm8",}, +{{0x0f, 0x38, 0xca, 0x00, }, 4, 0, "", "", +"0f 38 ca 00 \tsha1msg2 (%rax),%xmm0",}, +{{0x41, 0x0f, 0x38, 0xca, 0x00, }, 5, 0, "", "", +"41 0f 38 ca 00 \tsha1msg2 (%r8),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 04 25 78 56 34 12 \tsha1msg2 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xca, 0x18, }, 4, 0, "", "", +"0f 38 ca 18 \tsha1msg2 (%rax),%xmm3",}, +{{0x0f, 0x38, 0xca, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 ca 04 01 \tsha1msg2 (%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 04 05 78 56 34 12 \tsha1msg2 0x12345678(,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 ca 04 08 \tsha1msg2 (%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 ca 04 c8 \tsha1msg2 (%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 ca 40 12 \tsha1msg2 0x12(%rax),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 ca 45 12 \tsha1msg2 0x12(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 01 12 \tsha1msg2 0x12(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 05 12 \tsha1msg2 0x12(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 08 12 \tsha1msg2 0x12(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 ca 44 c8 12 \tsha1msg2 0x12(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 ca 80 78 56 34 12 \tsha1msg2 0x12345678(%rax),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 ca 85 78 56 34 12 \tsha1msg2 0x12345678(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 01 78 56 34 12 \tsha1msg2 0x12345678(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 05 78 56 34 12 \tsha1msg2 0x12345678(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 08 78 56 34 12 \tsha1msg2 0x12345678(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xca, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 ca 84 c8 78 56 34 12 \tsha1msg2 0x12345678(%rax,%rcx,8),%xmm0",}, +{{0x44, 0x0f, 0x38, 0xca, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"44 0f 38 ca bc c8 78 56 34 12 \tsha1msg2 0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x0f, 0x38, 0xcb, 0xcc, }, 4, 0, "", "", +"0f 38 cb cc \tsha256rnds2 %xmm0,%xmm4,%xmm1",}, +{{0x0f, 0x38, 0xcb, 0xd7, }, 4, 0, "", "", +"0f 38 cb d7 \tsha256rnds2 %xmm0,%xmm7,%xmm2",}, +{{0x41, 0x0f, 0x38, 0xcb, 0xc8, }, 5, 0, "", "", +"41 0f 38 cb c8 \tsha256rnds2 %xmm0,%xmm8,%xmm1",}, +{{0x44, 0x0f, 0x38, 0xcb, 0xc7, }, 5, 0, "", "", +"44 0f 38 cb c7 \tsha256rnds2 %xmm0,%xmm7,%xmm8",}, +{{0x45, 0x0f, 0x38, 0xcb, 0xc7, }, 5, 0, "", "", +"45 0f 38 cb c7 \tsha256rnds2 %xmm0,%xmm15,%xmm8",}, +{{0x0f, 0x38, 0xcb, 0x08, }, 4, 0, "", "", +"0f 38 cb 08 \tsha256rnds2 %xmm0,(%rax),%xmm1",}, +{{0x41, 0x0f, 0x38, 0xcb, 0x08, }, 5, 0, "", "", +"41 0f 38 cb 08 \tsha256rnds2 %xmm0,(%r8),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 0c 25 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678,%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x18, }, 4, 0, "", "", +"0f 38 cb 18 \tsha256rnds2 %xmm0,(%rax),%xmm3",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x01, }, 5, 0, "", "", +"0f 38 cb 0c 01 \tsha256rnds2 %xmm0,(%rcx,%rax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 0c 05 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(,%rax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0x08, }, 5, 0, "", "", +"0f 38 cb 0c 08 \tsha256rnds2 %xmm0,(%rax,%rcx,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x0c, 0xc8, }, 5, 0, "", "", +"0f 38 cb 0c c8 \tsha256rnds2 %xmm0,(%rax,%rcx,8),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x48, 0x12, }, 5, 0, "", "", +"0f 38 cb 48 12 \tsha256rnds2 %xmm0,0x12(%rax),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4d, 0x12, }, 5, 0, "", "", +"0f 38 cb 4d 12 \tsha256rnds2 %xmm0,0x12(%rbp),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c 01 12 \tsha256rnds2 %xmm0,0x12(%rcx,%rax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c 05 12 \tsha256rnds2 %xmm0,0x12(%rbp,%rax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c 08 12 \tsha256rnds2 %xmm0,0x12(%rax,%rcx,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x4c, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 cb 4c c8 12 \tsha256rnds2 %xmm0,0x12(%rax,%rcx,8),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x88, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cb 88 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rax),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8d, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cb 8d 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rbp),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c 01 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rcx,%rax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c 05 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rbp,%rax,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c 08 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rax,%rcx,1),%xmm1",}, +{{0x0f, 0x38, 0xcb, 0x8c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cb 8c c8 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rax,%rcx,8),%xmm1",}, +{{0x44, 0x0f, 0x38, 0xcb, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"44 0f 38 cb bc c8 78 56 34 12 \tsha256rnds2 %xmm0,0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x0f, 0x38, 0xcc, 0xc1, }, 4, 0, "", "", +"0f 38 cc c1 \tsha256msg1 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xcc, 0xd7, }, 4, 0, "", "", +"0f 38 cc d7 \tsha256msg1 %xmm7,%xmm2",}, +{{0x41, 0x0f, 0x38, 0xcc, 0xc0, }, 5, 0, "", "", +"41 0f 38 cc c0 \tsha256msg1 %xmm8,%xmm0",}, +{{0x44, 0x0f, 0x38, 0xcc, 0xc7, }, 5, 0, "", "", +"44 0f 38 cc c7 \tsha256msg1 %xmm7,%xmm8",}, +{{0x45, 0x0f, 0x38, 0xcc, 0xc7, }, 5, 0, "", "", +"45 0f 38 cc c7 \tsha256msg1 %xmm15,%xmm8",}, +{{0x0f, 0x38, 0xcc, 0x00, }, 4, 0, "", "", +"0f 38 cc 00 \tsha256msg1 (%rax),%xmm0",}, +{{0x41, 0x0f, 0x38, 0xcc, 0x00, }, 5, 0, "", "", +"41 0f 38 cc 00 \tsha256msg1 (%r8),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 04 25 78 56 34 12 \tsha256msg1 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x18, }, 4, 0, "", "", +"0f 38 cc 18 \tsha256msg1 (%rax),%xmm3",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 cc 04 01 \tsha256msg1 (%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 04 05 78 56 34 12 \tsha256msg1 0x12345678(,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 cc 04 08 \tsha256msg1 (%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 cc 04 c8 \tsha256msg1 (%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 cc 40 12 \tsha256msg1 0x12(%rax),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 cc 45 12 \tsha256msg1 0x12(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 01 12 \tsha256msg1 0x12(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 05 12 \tsha256msg1 0x12(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 08 12 \tsha256msg1 0x12(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 cc 44 c8 12 \tsha256msg1 0x12(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cc 80 78 56 34 12 \tsha256msg1 0x12345678(%rax),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cc 85 78 56 34 12 \tsha256msg1 0x12345678(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 01 78 56 34 12 \tsha256msg1 0x12345678(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 05 78 56 34 12 \tsha256msg1 0x12345678(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 08 78 56 34 12 \tsha256msg1 0x12345678(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xcc, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cc 84 c8 78 56 34 12 \tsha256msg1 0x12345678(%rax,%rcx,8),%xmm0",}, +{{0x44, 0x0f, 0x38, 0xcc, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"44 0f 38 cc bc c8 78 56 34 12 \tsha256msg1 0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x0f, 0x38, 0xcd, 0xc1, }, 4, 0, "", "", +"0f 38 cd c1 \tsha256msg2 %xmm1,%xmm0",}, +{{0x0f, 0x38, 0xcd, 0xd7, }, 4, 0, "", "", +"0f 38 cd d7 \tsha256msg2 %xmm7,%xmm2",}, +{{0x41, 0x0f, 0x38, 0xcd, 0xc0, }, 5, 0, "", "", +"41 0f 38 cd c0 \tsha256msg2 %xmm8,%xmm0",}, +{{0x44, 0x0f, 0x38, 0xcd, 0xc7, }, 5, 0, "", "", +"44 0f 38 cd c7 \tsha256msg2 %xmm7,%xmm8",}, +{{0x45, 0x0f, 0x38, 0xcd, 0xc7, }, 5, 0, "", "", +"45 0f 38 cd c7 \tsha256msg2 %xmm15,%xmm8",}, +{{0x0f, 0x38, 0xcd, 0x00, }, 4, 0, "", "", +"0f 38 cd 00 \tsha256msg2 (%rax),%xmm0",}, +{{0x41, 0x0f, 0x38, 0xcd, 0x00, }, 5, 0, "", "", +"41 0f 38 cd 00 \tsha256msg2 (%r8),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 04 25 78 56 34 12 \tsha256msg2 0x12345678,%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x18, }, 4, 0, "", "", +"0f 38 cd 18 \tsha256msg2 (%rax),%xmm3",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x01, }, 5, 0, "", "", +"0f 38 cd 04 01 \tsha256msg2 (%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 04 05 78 56 34 12 \tsha256msg2 0x12345678(,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0x08, }, 5, 0, "", "", +"0f 38 cd 04 08 \tsha256msg2 (%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x04, 0xc8, }, 5, 0, "", "", +"0f 38 cd 04 c8 \tsha256msg2 (%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x40, 0x12, }, 5, 0, "", "", +"0f 38 cd 40 12 \tsha256msg2 0x12(%rax),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x45, 0x12, }, 5, 0, "", "", +"0f 38 cd 45 12 \tsha256msg2 0x12(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0x01, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 01 12 \tsha256msg2 0x12(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0x05, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 05 12 \tsha256msg2 0x12(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0x08, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 08 12 \tsha256msg2 0x12(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x44, 0xc8, 0x12, }, 6, 0, "", "", +"0f 38 cd 44 c8 12 \tsha256msg2 0x12(%rax,%rcx,8),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x80, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cd 80 78 56 34 12 \tsha256msg2 0x12345678(%rax),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x85, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f 38 cd 85 78 56 34 12 \tsha256msg2 0x12345678(%rbp),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0x01, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 01 78 56 34 12 \tsha256msg2 0x12345678(%rcx,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0x05, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 05 78 56 34 12 \tsha256msg2 0x12345678(%rbp,%rax,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0x08, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 08 78 56 34 12 \tsha256msg2 0x12345678(%rax,%rcx,1),%xmm0",}, +{{0x0f, 0x38, 0xcd, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"0f 38 cd 84 c8 78 56 34 12 \tsha256msg2 0x12345678(%rax,%rcx,8),%xmm0",}, +{{0x44, 0x0f, 0x38, 0xcd, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"44 0f 38 cd bc c8 78 56 34 12 \tsha256msg2 0x12345678(%rax,%rcx,8),%xmm15",}, diff --git a/tools/perf/tests/insn-x86-dat-src.c b/tools/perf/tests/insn-x86-dat-src.c index b506830f33a8..7d06c9b22070 100644 --- a/tools/perf/tests/insn-x86-dat-src.c +++ b/tools/perf/tests/insn-x86-dat-src.c @@ -217,6 +217,210 @@ int main(void) asm volatile("bnd jmp *(%ecx)"); /* Expecting: jmp indirect 0 */ asm volatile("bnd jne label1"); /* Expecting: jcc conditional 0 */ + /* sha1rnds4 imm8, xmm2/m128, xmm1 */ + + asm volatile("sha1rnds4 $0x0, %xmm1, %xmm0"); + asm volatile("sha1rnds4 $0x91, %xmm7, %xmm2"); + asm volatile("sha1rnds4 $0x91, %xmm8, %xmm0"); + asm volatile("sha1rnds4 $0x91, %xmm7, %xmm8"); + asm volatile("sha1rnds4 $0x91, %xmm15, %xmm8"); + asm volatile("sha1rnds4 $0x91, (%rax), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%r8), %xmm0"); + asm volatile("sha1rnds4 $0x91, (0x12345678), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%rax), %xmm3"); + asm volatile("sha1rnds4 $0x91, (%rcx,%rax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(,%rax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%rax,%rcx,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%rax,%rcx,8), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%rax), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%rbp), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%rcx,%rax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%rbp,%rax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%rax,%rcx,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%rax,%rcx,8), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rax), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rbp), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rcx,%rax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rbp,%rax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rax,%rcx,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rax,%rcx,8), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%rax,%rcx,8), %xmm15"); + + /* sha1nexte xmm2/m128, xmm1 */ + + asm volatile("sha1nexte %xmm1, %xmm0"); + asm volatile("sha1nexte %xmm7, %xmm2"); + asm volatile("sha1nexte %xmm8, %xmm0"); + asm volatile("sha1nexte %xmm7, %xmm8"); + asm volatile("sha1nexte %xmm15, %xmm8"); + asm volatile("sha1nexte (%rax), %xmm0"); + asm volatile("sha1nexte (%r8), %xmm0"); + asm volatile("sha1nexte (0x12345678), %xmm0"); + asm volatile("sha1nexte (%rax), %xmm3"); + asm volatile("sha1nexte (%rcx,%rax,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(,%rax,1), %xmm0"); + asm volatile("sha1nexte (%rax,%rcx,1), %xmm0"); + asm volatile("sha1nexte (%rax,%rcx,8), %xmm0"); + asm volatile("sha1nexte 0x12(%rax), %xmm0"); + asm volatile("sha1nexte 0x12(%rbp), %xmm0"); + asm volatile("sha1nexte 0x12(%rcx,%rax,1), %xmm0"); + asm volatile("sha1nexte 0x12(%rbp,%rax,1), %xmm0"); + asm volatile("sha1nexte 0x12(%rax,%rcx,1), %xmm0"); + asm volatile("sha1nexte 0x12(%rax,%rcx,8), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rax), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rbp), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rcx,%rax,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rbp,%rax,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rax,%rcx,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rax,%rcx,8), %xmm0"); + asm volatile("sha1nexte 0x12345678(%rax,%rcx,8), %xmm15"); + + /* sha1msg1 xmm2/m128, xmm1 */ + + asm volatile("sha1msg1 %xmm1, %xmm0"); + asm volatile("sha1msg1 %xmm7, %xmm2"); + asm volatile("sha1msg1 %xmm8, %xmm0"); + asm volatile("sha1msg1 %xmm7, %xmm8"); + asm volatile("sha1msg1 %xmm15, %xmm8"); + asm volatile("sha1msg1 (%rax), %xmm0"); + asm volatile("sha1msg1 (%r8), %xmm0"); + asm volatile("sha1msg1 (0x12345678), %xmm0"); + asm volatile("sha1msg1 (%rax), %xmm3"); + asm volatile("sha1msg1 (%rcx,%rax,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(,%rax,1), %xmm0"); + asm volatile("sha1msg1 (%rax,%rcx,1), %xmm0"); + asm volatile("sha1msg1 (%rax,%rcx,8), %xmm0"); + asm volatile("sha1msg1 0x12(%rax), %xmm0"); + asm volatile("sha1msg1 0x12(%rbp), %xmm0"); + asm volatile("sha1msg1 0x12(%rcx,%rax,1), %xmm0"); + asm volatile("sha1msg1 0x12(%rbp,%rax,1), %xmm0"); + asm volatile("sha1msg1 0x12(%rax,%rcx,1), %xmm0"); + asm volatile("sha1msg1 0x12(%rax,%rcx,8), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rax), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rbp), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rcx,%rax,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rbp,%rax,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rax,%rcx,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rax,%rcx,8), %xmm0"); + asm volatile("sha1msg1 0x12345678(%rax,%rcx,8), %xmm15"); + + /* sha1msg2 xmm2/m128, xmm1 */ + + asm volatile("sha1msg2 %xmm1, %xmm0"); + asm volatile("sha1msg2 %xmm7, %xmm2"); + asm volatile("sha1msg2 %xmm8, %xmm0"); + asm volatile("sha1msg2 %xmm7, %xmm8"); + asm volatile("sha1msg2 %xmm15, %xmm8"); + asm volatile("sha1msg2 (%rax), %xmm0"); + asm volatile("sha1msg2 (%r8), %xmm0"); + asm volatile("sha1msg2 (0x12345678), %xmm0"); + asm volatile("sha1msg2 (%rax), %xmm3"); + asm volatile("sha1msg2 (%rcx,%rax,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(,%rax,1), %xmm0"); + asm volatile("sha1msg2 (%rax,%rcx,1), %xmm0"); + asm volatile("sha1msg2 (%rax,%rcx,8), %xmm0"); + asm volatile("sha1msg2 0x12(%rax), %xmm0"); + asm volatile("sha1msg2 0x12(%rbp), %xmm0"); + asm volatile("sha1msg2 0x12(%rcx,%rax,1), %xmm0"); + asm volatile("sha1msg2 0x12(%rbp,%rax,1), %xmm0"); + asm volatile("sha1msg2 0x12(%rax,%rcx,1), %xmm0"); + asm volatile("sha1msg2 0x12(%rax,%rcx,8), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rax), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rbp), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rcx,%rax,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rbp,%rax,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rax,%rcx,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rax,%rcx,8), %xmm0"); + asm volatile("sha1msg2 0x12345678(%rax,%rcx,8), %xmm15"); + + /* sha256rnds2 , xmm2/m128, xmm1 */ + /* Note sha256rnds2 has an implicit operand 'xmm0' */ + + asm volatile("sha256rnds2 %xmm4, %xmm1"); + asm volatile("sha256rnds2 %xmm7, %xmm2"); + asm volatile("sha256rnds2 %xmm8, %xmm1"); + asm volatile("sha256rnds2 %xmm7, %xmm8"); + asm volatile("sha256rnds2 %xmm15, %xmm8"); + asm volatile("sha256rnds2 (%rax), %xmm1"); + asm volatile("sha256rnds2 (%r8), %xmm1"); + asm volatile("sha256rnds2 (0x12345678), %xmm1"); + asm volatile("sha256rnds2 (%rax), %xmm3"); + asm volatile("sha256rnds2 (%rcx,%rax,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(,%rax,1), %xmm1"); + asm volatile("sha256rnds2 (%rax,%rcx,1), %xmm1"); + asm volatile("sha256rnds2 (%rax,%rcx,8), %xmm1"); + asm volatile("sha256rnds2 0x12(%rax), %xmm1"); + asm volatile("sha256rnds2 0x12(%rbp), %xmm1"); + asm volatile("sha256rnds2 0x12(%rcx,%rax,1), %xmm1"); + asm volatile("sha256rnds2 0x12(%rbp,%rax,1), %xmm1"); + asm volatile("sha256rnds2 0x12(%rax,%rcx,1), %xmm1"); + asm volatile("sha256rnds2 0x12(%rax,%rcx,8), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rax), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rbp), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rcx,%rax,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rbp,%rax,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rax,%rcx,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rax,%rcx,8), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%rax,%rcx,8), %xmm15"); + + /* sha256msg1 xmm2/m128, xmm1 */ + + asm volatile("sha256msg1 %xmm1, %xmm0"); + asm volatile("sha256msg1 %xmm7, %xmm2"); + asm volatile("sha256msg1 %xmm8, %xmm0"); + asm volatile("sha256msg1 %xmm7, %xmm8"); + asm volatile("sha256msg1 %xmm15, %xmm8"); + asm volatile("sha256msg1 (%rax), %xmm0"); + asm volatile("sha256msg1 (%r8), %xmm0"); + asm volatile("sha256msg1 (0x12345678), %xmm0"); + asm volatile("sha256msg1 (%rax), %xmm3"); + asm volatile("sha256msg1 (%rcx,%rax,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(,%rax,1), %xmm0"); + asm volatile("sha256msg1 (%rax,%rcx,1), %xmm0"); + asm volatile("sha256msg1 (%rax,%rcx,8), %xmm0"); + asm volatile("sha256msg1 0x12(%rax), %xmm0"); + asm volatile("sha256msg1 0x12(%rbp), %xmm0"); + asm volatile("sha256msg1 0x12(%rcx,%rax,1), %xmm0"); + asm volatile("sha256msg1 0x12(%rbp,%rax,1), %xmm0"); + asm volatile("sha256msg1 0x12(%rax,%rcx,1), %xmm0"); + asm volatile("sha256msg1 0x12(%rax,%rcx,8), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rax), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rbp), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rcx,%rax,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rbp,%rax,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rax,%rcx,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rax,%rcx,8), %xmm0"); + asm volatile("sha256msg1 0x12345678(%rax,%rcx,8), %xmm15"); + + /* sha256msg2 xmm2/m128, xmm1 */ + + asm volatile("sha256msg2 %xmm1, %xmm0"); + asm volatile("sha256msg2 %xmm7, %xmm2"); + asm volatile("sha256msg2 %xmm8, %xmm0"); + asm volatile("sha256msg2 %xmm7, %xmm8"); + asm volatile("sha256msg2 %xmm15, %xmm8"); + asm volatile("sha256msg2 (%rax), %xmm0"); + asm volatile("sha256msg2 (%r8), %xmm0"); + asm volatile("sha256msg2 (0x12345678), %xmm0"); + asm volatile("sha256msg2 (%rax), %xmm3"); + asm volatile("sha256msg2 (%rcx,%rax,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(,%rax,1), %xmm0"); + asm volatile("sha256msg2 (%rax,%rcx,1), %xmm0"); + asm volatile("sha256msg2 (%rax,%rcx,8), %xmm0"); + asm volatile("sha256msg2 0x12(%rax), %xmm0"); + asm volatile("sha256msg2 0x12(%rbp), %xmm0"); + asm volatile("sha256msg2 0x12(%rcx,%rax,1), %xmm0"); + asm volatile("sha256msg2 0x12(%rbp,%rax,1), %xmm0"); + asm volatile("sha256msg2 0x12(%rax,%rcx,1), %xmm0"); + asm volatile("sha256msg2 0x12(%rax,%rcx,8), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rax), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rbp), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rcx,%rax,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rbp,%rax,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rax,%rcx,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rax,%rcx,8), %xmm0"); + asm volatile("sha256msg2 0x12345678(%rax,%rcx,8), %xmm15"); + #else /* #ifdef __x86_64__ */ /* bndmk m32, bnd */ @@ -407,6 +611,175 @@ int main(void) asm volatile("bnd jmp *(%ecx)"); /* Expecting: jmp indirect 0 */ asm volatile("bnd jne label1"); /* Expecting: jcc conditional 0xfffffffc */ + /* sha1rnds4 imm8, xmm2/m128, xmm1 */ + + asm volatile("sha1rnds4 $0x0, %xmm1, %xmm0"); + asm volatile("sha1rnds4 $0x91, %xmm7, %xmm2"); + asm volatile("sha1rnds4 $0x91, (%eax), %xmm0"); + asm volatile("sha1rnds4 $0x91, (0x12345678), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%eax), %xmm3"); + asm volatile("sha1rnds4 $0x91, (%ecx,%eax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(,%eax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%eax,%ecx,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, (%eax,%ecx,8), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%eax), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%ebp), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%ecx,%eax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%ebp,%eax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%eax,%ecx,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12(%eax,%ecx,8), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%eax), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%ebp), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%ecx,%eax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%ebp,%eax,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%eax,%ecx,1), %xmm0"); + asm volatile("sha1rnds4 $0x91, 0x12345678(%eax,%ecx,8), %xmm0"); + + /* sha1nexte xmm2/m128, xmm1 */ + + asm volatile("sha1nexte %xmm1, %xmm0"); + asm volatile("sha1nexte %xmm7, %xmm2"); + asm volatile("sha1nexte (%eax), %xmm0"); + asm volatile("sha1nexte (0x12345678), %xmm0"); + asm volatile("sha1nexte (%eax), %xmm3"); + asm volatile("sha1nexte (%ecx,%eax,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(,%eax,1), %xmm0"); + asm volatile("sha1nexte (%eax,%ecx,1), %xmm0"); + asm volatile("sha1nexte (%eax,%ecx,8), %xmm0"); + asm volatile("sha1nexte 0x12(%eax), %xmm0"); + asm volatile("sha1nexte 0x12(%ebp), %xmm0"); + asm volatile("sha1nexte 0x12(%ecx,%eax,1), %xmm0"); + asm volatile("sha1nexte 0x12(%ebp,%eax,1), %xmm0"); + asm volatile("sha1nexte 0x12(%eax,%ecx,1), %xmm0"); + asm volatile("sha1nexte 0x12(%eax,%ecx,8), %xmm0"); + asm volatile("sha1nexte 0x12345678(%eax), %xmm0"); + asm volatile("sha1nexte 0x12345678(%ebp), %xmm0"); + asm volatile("sha1nexte 0x12345678(%ecx,%eax,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(%ebp,%eax,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(%eax,%ecx,1), %xmm0"); + asm volatile("sha1nexte 0x12345678(%eax,%ecx,8), %xmm0"); + + /* sha1msg1 xmm2/m128, xmm1 */ + + asm volatile("sha1msg1 %xmm1, %xmm0"); + asm volatile("sha1msg1 %xmm7, %xmm2"); + asm volatile("sha1msg1 (%eax), %xmm0"); + asm volatile("sha1msg1 (0x12345678), %xmm0"); + asm volatile("sha1msg1 (%eax), %xmm3"); + asm volatile("sha1msg1 (%ecx,%eax,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(,%eax,1), %xmm0"); + asm volatile("sha1msg1 (%eax,%ecx,1), %xmm0"); + asm volatile("sha1msg1 (%eax,%ecx,8), %xmm0"); + asm volatile("sha1msg1 0x12(%eax), %xmm0"); + asm volatile("sha1msg1 0x12(%ebp), %xmm0"); + asm volatile("sha1msg1 0x12(%ecx,%eax,1), %xmm0"); + asm volatile("sha1msg1 0x12(%ebp,%eax,1), %xmm0"); + asm volatile("sha1msg1 0x12(%eax,%ecx,1), %xmm0"); + asm volatile("sha1msg1 0x12(%eax,%ecx,8), %xmm0"); + asm volatile("sha1msg1 0x12345678(%eax), %xmm0"); + asm volatile("sha1msg1 0x12345678(%ebp), %xmm0"); + asm volatile("sha1msg1 0x12345678(%ecx,%eax,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(%ebp,%eax,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(%eax,%ecx,1), %xmm0"); + asm volatile("sha1msg1 0x12345678(%eax,%ecx,8), %xmm0"); + + /* sha1msg2 xmm2/m128, xmm1 */ + + asm volatile("sha1msg2 %xmm1, %xmm0"); + asm volatile("sha1msg2 %xmm7, %xmm2"); + asm volatile("sha1msg2 (%eax), %xmm0"); + asm volatile("sha1msg2 (0x12345678), %xmm0"); + asm volatile("sha1msg2 (%eax), %xmm3"); + asm volatile("sha1msg2 (%ecx,%eax,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(,%eax,1), %xmm0"); + asm volatile("sha1msg2 (%eax,%ecx,1), %xmm0"); + asm volatile("sha1msg2 (%eax,%ecx,8), %xmm0"); + asm volatile("sha1msg2 0x12(%eax), %xmm0"); + asm volatile("sha1msg2 0x12(%ebp), %xmm0"); + asm volatile("sha1msg2 0x12(%ecx,%eax,1), %xmm0"); + asm volatile("sha1msg2 0x12(%ebp,%eax,1), %xmm0"); + asm volatile("sha1msg2 0x12(%eax,%ecx,1), %xmm0"); + asm volatile("sha1msg2 0x12(%eax,%ecx,8), %xmm0"); + asm volatile("sha1msg2 0x12345678(%eax), %xmm0"); + asm volatile("sha1msg2 0x12345678(%ebp), %xmm0"); + asm volatile("sha1msg2 0x12345678(%ecx,%eax,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(%ebp,%eax,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(%eax,%ecx,1), %xmm0"); + asm volatile("sha1msg2 0x12345678(%eax,%ecx,8), %xmm0"); + + /* sha256rnds2 , xmm2/m128, xmm1 */ + /* Note sha256rnds2 has an implicit operand 'xmm0' */ + + asm volatile("sha256rnds2 %xmm4, %xmm1"); + asm volatile("sha256rnds2 %xmm7, %xmm2"); + asm volatile("sha256rnds2 (%eax), %xmm1"); + asm volatile("sha256rnds2 (0x12345678), %xmm1"); + asm volatile("sha256rnds2 (%eax), %xmm3"); + asm volatile("sha256rnds2 (%ecx,%eax,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(,%eax,1), %xmm1"); + asm volatile("sha256rnds2 (%eax,%ecx,1), %xmm1"); + asm volatile("sha256rnds2 (%eax,%ecx,8), %xmm1"); + asm volatile("sha256rnds2 0x12(%eax), %xmm1"); + asm volatile("sha256rnds2 0x12(%ebp), %xmm1"); + asm volatile("sha256rnds2 0x12(%ecx,%eax,1), %xmm1"); + asm volatile("sha256rnds2 0x12(%ebp,%eax,1), %xmm1"); + asm volatile("sha256rnds2 0x12(%eax,%ecx,1), %xmm1"); + asm volatile("sha256rnds2 0x12(%eax,%ecx,8), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%eax), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%ebp), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%ecx,%eax,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%ebp,%eax,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%eax,%ecx,1), %xmm1"); + asm volatile("sha256rnds2 0x12345678(%eax,%ecx,8), %xmm1"); + + /* sha256msg1 xmm2/m128, xmm1 */ + + asm volatile("sha256msg1 %xmm1, %xmm0"); + asm volatile("sha256msg1 %xmm7, %xmm2"); + asm volatile("sha256msg1 (%eax), %xmm0"); + asm volatile("sha256msg1 (0x12345678), %xmm0"); + asm volatile("sha256msg1 (%eax), %xmm3"); + asm volatile("sha256msg1 (%ecx,%eax,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(,%eax,1), %xmm0"); + asm volatile("sha256msg1 (%eax,%ecx,1), %xmm0"); + asm volatile("sha256msg1 (%eax,%ecx,8), %xmm0"); + asm volatile("sha256msg1 0x12(%eax), %xmm0"); + asm volatile("sha256msg1 0x12(%ebp), %xmm0"); + asm volatile("sha256msg1 0x12(%ecx,%eax,1), %xmm0"); + asm volatile("sha256msg1 0x12(%ebp,%eax,1), %xmm0"); + asm volatile("sha256msg1 0x12(%eax,%ecx,1), %xmm0"); + asm volatile("sha256msg1 0x12(%eax,%ecx,8), %xmm0"); + asm volatile("sha256msg1 0x12345678(%eax), %xmm0"); + asm volatile("sha256msg1 0x12345678(%ebp), %xmm0"); + asm volatile("sha256msg1 0x12345678(%ecx,%eax,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(%ebp,%eax,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(%eax,%ecx,1), %xmm0"); + asm volatile("sha256msg1 0x12345678(%eax,%ecx,8), %xmm0"); + + /* sha256msg2 xmm2/m128, xmm1 */ + + asm volatile("sha256msg2 %xmm1, %xmm0"); + asm volatile("sha256msg2 %xmm7, %xmm2"); + asm volatile("sha256msg2 (%eax), %xmm0"); + asm volatile("sha256msg2 (0x12345678), %xmm0"); + asm volatile("sha256msg2 (%eax), %xmm3"); + asm volatile("sha256msg2 (%ecx,%eax,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(,%eax,1), %xmm0"); + asm volatile("sha256msg2 (%eax,%ecx,1), %xmm0"); + asm volatile("sha256msg2 (%eax,%ecx,8), %xmm0"); + asm volatile("sha256msg2 0x12(%eax), %xmm0"); + asm volatile("sha256msg2 0x12(%ebp), %xmm0"); + asm volatile("sha256msg2 0x12(%ecx,%eax,1), %xmm0"); + asm volatile("sha256msg2 0x12(%ebp,%eax,1), %xmm0"); + asm volatile("sha256msg2 0x12(%eax,%ecx,1), %xmm0"); + asm volatile("sha256msg2 0x12(%eax,%ecx,8), %xmm0"); + asm volatile("sha256msg2 0x12345678(%eax), %xmm0"); + asm volatile("sha256msg2 0x12345678(%ebp), %xmm0"); + asm volatile("sha256msg2 0x12345678(%ecx,%eax,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(%ebp,%eax,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(%eax,%ecx,1), %xmm0"); + asm volatile("sha256msg2 0x12345678(%eax,%ecx,8), %xmm0"); + #endif /* #ifndef __x86_64__ */ /* Following line is a marker for the awk script - do not change */ diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index a02a195d219c..25dad388b371 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -736,6 +736,12 @@ bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) # 0x0f 0x38 0xc0-0xff +c8: sha1nexte Vdq,Wdq +c9: sha1msg1 Vdq,Wdq +ca: sha1msg2 Vdq,Wdq +cb: sha256rnds2 Vdq,Wdq +cc: sha256msg1 Vdq,Wdq +cd: sha256msg2 Vdq,Wdq db: VAESIMC Vdq,Wdq (66),(v1) dc: VAESENC Vdq,Hdq,Wdq (66),(v1) dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) @@ -794,6 +800,7 @@ AVXcode: 3 61: vpcmpestri Vdq,Wdq,Ib (66),(v1) 62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) 63: vpcmpistri Vdq,Wdq,Ib (66),(v1) +cc: sha1rnds4 Vdq,Wdq,Ib df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) f0: RORX Gy,Ey,Ib (F2),(v) EndTable From ac1c8859a81e2fc45db1dbff30bdc572005734ca Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:29 +0300 Subject: [PATCH 021/260] x86/insn: perf tools: Add new memory instructions Intel Architecture Instruction Set Extensions Programing Reference (Oct 2014) describes 3 new memory instructions, namely clflushopt, clwb and pcommit. Add them to the op code map and the perf tools new instructions test. e.g. $ tools/perf/perf test "x86 ins" 39: Test x86 instruction decoder - new instructions : Ok Or to see the details: $ tools/perf/perf test -v "x86 ins" Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-6-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 4 +- tools/perf/tests/insn-x86-dat-32.c | 22 +++++++++ tools/perf/tests/insn-x86-dat-64.c | 34 ++++++++++++++ tools/perf/tests/insn-x86-dat-src.c | 46 +++++++++++++++++++ .../util/intel-pt-decoder/x86-opcode-map.txt | 4 +- 5 files changed, 106 insertions(+), 4 deletions(-) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 25dad388b371..f4f0451a301e 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -943,8 +943,8 @@ GrpTable: Grp15 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) 4: XSAVE 5: XRSTOR | lfence (11B) -6: XSAVEOPT | mfence (11B) -7: clflush | sfence (11B) +6: XSAVEOPT | clwb (66) | mfence (11B) +7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B) EndTable GrpTable: Grp16 diff --git a/tools/perf/tests/insn-x86-dat-32.c b/tools/perf/tests/insn-x86-dat-32.c index 83f5078e74e1..4b09b7e130a0 100644 --- a/tools/perf/tests/insn-x86-dat-32.c +++ b/tools/perf/tests/insn-x86-dat-32.c @@ -616,3 +616,25 @@ "0f 38 cd 84 08 78 56 34 12 \tsha256msg2 0x12345678(%eax,%ecx,1),%xmm0",}, {{0x0f, 0x38, 0xcd, 0x84, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", "0f 38 cd 84 c8 78 56 34 12 \tsha256msg2 0x12345678(%eax,%ecx,8),%xmm0",}, +{{0x66, 0x0f, 0xae, 0x38, }, 4, 0, "", "", +"66 0f ae 38 \tclflushopt (%eax)",}, +{{0x66, 0x0f, 0xae, 0x3d, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f ae 3d 78 56 34 12 \tclflushopt 0x12345678",}, +{{0x66, 0x0f, 0xae, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f ae bc c8 78 56 34 12 \tclflushopt 0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0xae, 0x38, }, 3, 0, "", "", +"0f ae 38 \tclflush (%eax)",}, +{{0x0f, 0xae, 0xf8, }, 3, 0, "", "", +"0f ae f8 \tsfence ",}, +{{0x66, 0x0f, 0xae, 0x30, }, 4, 0, "", "", +"66 0f ae 30 \tclwb (%eax)",}, +{{0x66, 0x0f, 0xae, 0x35, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"66 0f ae 35 78 56 34 12 \tclwb 0x12345678",}, +{{0x66, 0x0f, 0xae, 0xb4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f ae b4 c8 78 56 34 12 \tclwb 0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0xae, 0x30, }, 3, 0, "", "", +"0f ae 30 \txsaveopt (%eax)",}, +{{0x0f, 0xae, 0xf0, }, 3, 0, "", "", +"0f ae f0 \tmfence ",}, +{{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "", +"66 0f ae f8 \tpcommit ",}, diff --git a/tools/perf/tests/insn-x86-dat-64.c b/tools/perf/tests/insn-x86-dat-64.c index 13f008588590..5da235a4414f 100644 --- a/tools/perf/tests/insn-x86-dat-64.c +++ b/tools/perf/tests/insn-x86-dat-64.c @@ -702,3 +702,37 @@ "0f 38 cd 84 c8 78 56 34 12 \tsha256msg2 0x12345678(%rax,%rcx,8),%xmm0",}, {{0x44, 0x0f, 0x38, 0xcd, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", "44 0f 38 cd bc c8 78 56 34 12 \tsha256msg2 0x12345678(%rax,%rcx,8),%xmm15",}, +{{0x66, 0x0f, 0xae, 0x38, }, 4, 0, "", "", +"66 0f ae 38 \tclflushopt (%rax)",}, +{{0x66, 0x41, 0x0f, 0xae, 0x38, }, 5, 0, "", "", +"66 41 0f ae 38 \tclflushopt (%r8)",}, +{{0x66, 0x0f, 0xae, 0x3c, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f ae 3c 25 78 56 34 12 \tclflushopt 0x12345678",}, +{{0x66, 0x0f, 0xae, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f ae bc c8 78 56 34 12 \tclflushopt 0x12345678(%rax,%rcx,8)",}, +{{0x66, 0x41, 0x0f, 0xae, 0xbc, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"66 41 0f ae bc c8 78 56 34 12 \tclflushopt 0x12345678(%r8,%rcx,8)",}, +{{0x0f, 0xae, 0x38, }, 3, 0, "", "", +"0f ae 38 \tclflush (%rax)",}, +{{0x41, 0x0f, 0xae, 0x38, }, 4, 0, "", "", +"41 0f ae 38 \tclflush (%r8)",}, +{{0x0f, 0xae, 0xf8, }, 3, 0, "", "", +"0f ae f8 \tsfence ",}, +{{0x66, 0x0f, 0xae, 0x30, }, 4, 0, "", "", +"66 0f ae 30 \tclwb (%rax)",}, +{{0x66, 0x41, 0x0f, 0xae, 0x30, }, 5, 0, "", "", +"66 41 0f ae 30 \tclwb (%r8)",}, +{{0x66, 0x0f, 0xae, 0x34, 0x25, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f ae 34 25 78 56 34 12 \tclwb 0x12345678",}, +{{0x66, 0x0f, 0xae, 0xb4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"66 0f ae b4 c8 78 56 34 12 \tclwb 0x12345678(%rax,%rcx,8)",}, +{{0x66, 0x41, 0x0f, 0xae, 0xb4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 10, 0, "", "", +"66 41 0f ae b4 c8 78 56 34 12 \tclwb 0x12345678(%r8,%rcx,8)",}, +{{0x0f, 0xae, 0x30, }, 3, 0, "", "", +"0f ae 30 \txsaveopt (%rax)",}, +{{0x41, 0x0f, 0xae, 0x30, }, 4, 0, "", "", +"41 0f ae 30 \txsaveopt (%r8)",}, +{{0x0f, 0xae, 0xf0, }, 3, 0, "", "", +"0f ae f0 \tmfence ",}, +{{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "", +"66 0f ae f8 \tpcommit ",}, diff --git a/tools/perf/tests/insn-x86-dat-src.c b/tools/perf/tests/insn-x86-dat-src.c index 7d06c9b22070..482637f44245 100644 --- a/tools/perf/tests/insn-x86-dat-src.c +++ b/tools/perf/tests/insn-x86-dat-src.c @@ -421,6 +421,30 @@ int main(void) asm volatile("sha256msg2 0x12345678(%rax,%rcx,8), %xmm0"); asm volatile("sha256msg2 0x12345678(%rax,%rcx,8), %xmm15"); + /* clflushopt m8 */ + + asm volatile("clflushopt (%rax)"); + asm volatile("clflushopt (%r8)"); + asm volatile("clflushopt (0x12345678)"); + asm volatile("clflushopt 0x12345678(%rax,%rcx,8)"); + asm volatile("clflushopt 0x12345678(%r8,%rcx,8)"); + /* Also check instructions in the same group encoding as clflushopt */ + asm volatile("clflush (%rax)"); + asm volatile("clflush (%r8)"); + asm volatile("sfence"); + + /* clwb m8 */ + + asm volatile("clwb (%rax)"); + asm volatile("clwb (%r8)"); + asm volatile("clwb (0x12345678)"); + asm volatile("clwb 0x12345678(%rax,%rcx,8)"); + asm volatile("clwb 0x12345678(%r8,%rcx,8)"); + /* Also check instructions in the same group encoding as clwb */ + asm volatile("xsaveopt (%rax)"); + asm volatile("xsaveopt (%r8)"); + asm volatile("mfence"); + #else /* #ifdef __x86_64__ */ /* bndmk m32, bnd */ @@ -780,8 +804,30 @@ int main(void) asm volatile("sha256msg2 0x12345678(%eax,%ecx,1), %xmm0"); asm volatile("sha256msg2 0x12345678(%eax,%ecx,8), %xmm0"); + /* clflushopt m8 */ + + asm volatile("clflushopt (%eax)"); + asm volatile("clflushopt (0x12345678)"); + asm volatile("clflushopt 0x12345678(%eax,%ecx,8)"); + /* Also check instructions in the same group encoding as clflushopt */ + asm volatile("clflush (%eax)"); + asm volatile("sfence"); + + /* clwb m8 */ + + asm volatile("clwb (%eax)"); + asm volatile("clwb (0x12345678)"); + asm volatile("clwb 0x12345678(%eax,%ecx,8)"); + /* Also check instructions in the same group encoding as clwb */ + asm volatile("xsaveopt (%eax)"); + asm volatile("mfence"); + #endif /* #ifndef __x86_64__ */ + /* pcommit */ + + asm volatile("pcommit"); + /* Following line is a marker for the awk script - do not change */ asm volatile("rdtsc"); /* Stop here */ diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 25dad388b371..f4f0451a301e 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -943,8 +943,8 @@ GrpTable: Grp15 3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) 4: XSAVE 5: XRSTOR | lfence (11B) -6: XSAVEOPT | mfence (11B) -7: clflush | sfence (11B) +6: XSAVEOPT | clwb (66) | mfence (11B) +7: clflush | clflushopt (66) | sfence (11B) | pcommit (66),(11B) EndTable GrpTable: Grp16 From 978260cdbec3e34a3dfb2277ffc0aa1809457362 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:30 +0300 Subject: [PATCH 022/260] x86/insn: perf tools: Add new memory protection keys instructions Add rdpkru and wrpkru to the op code map and the perf tools new instructions test. In the case of the test, only the bytes can be tested at the moment since binutils doesn't support the instructions yet. To run the test: $ tools/perf/perf test "x86 ins" 39: Test x86 instruction decoder - new instructions : Ok Or to see the details: $ tools/perf/perf test -v "x86 ins" 2>&1 | grep pkru For information about rdpkru and wrpkru, refer the Intel SDM. Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 2 +- tools/perf/tests/insn-x86.c | 4 ++++ tools/perf/util/intel-pt-decoder/x86-opcode-map.txt | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index f4f0451a301e..5a9705ed9139 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -885,7 +885,7 @@ GrpTable: Grp7 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) 3: LIDT Ms 4: SMSW Mw/Rv -5: +5: rdpkru (110),(11B) | wrpkru (111),(11B) 6: LMSW Ew 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) EndTable diff --git a/tools/perf/tests/insn-x86.c b/tools/perf/tests/insn-x86.c index 0e126a099874..5c49eec81349 100644 --- a/tools/perf/tests/insn-x86.c +++ b/tools/perf/tests/insn-x86.c @@ -17,11 +17,15 @@ struct test_data { struct test_data test_data_32[] = { #include "insn-x86-dat-32.c" + {{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee \trdpkru"}, + {{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef \twrpkru"}, {{0}, 0, 0, NULL, NULL, NULL}, }; struct test_data test_data_64[] = { #include "insn-x86-dat-64.c" + {{0x0f, 0x01, 0xee}, 3, 0, NULL, NULL, "0f 01 ee \trdpkru"}, + {{0x0f, 0x01, 0xef}, 3, 0, NULL, NULL, "0f 01 ef \twrpkru"}, {{0}, 0, 0, NULL, NULL, NULL}, }; diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index f4f0451a301e..5a9705ed9139 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -885,7 +885,7 @@ GrpTable: Grp7 2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) 3: LIDT Ms 4: SMSW Mw/Rv -5: +5: rdpkru (110),(11B) | wrpkru (111),(11B) 6: LMSW Ew 7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) EndTable From f83b6b64eba155cfb43ab8a5d9c422c3e7f603e6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 2 Sep 2015 15:15:31 +0300 Subject: [PATCH 023/260] x86/insn: perf tools: Add new xsave instructions Add xsavec, xsaves and xrstors to the op code map and the perf tools new instructions test. To run the test: $ tools/perf/perf test "x86 ins" 39: Test x86 instruction decoder - new instructions : Ok Or to see the details: $ tools/perf/perf test -v "x86 ins" 2>&1 | grep 'xsave\|xrst' For information about xsavec, xsaves and xrstors, refer the Intel SDM. Signed-off-by: Adrian Hunter Acked-by: Masami Hiramatsu Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Denys Vlasenko Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Qiaowei Ren Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1441196131-20632-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- arch/x86/lib/x86-opcode-map.txt | 3 ++ tools/perf/tests/insn-x86-dat-32.c | 18 ++++++++ tools/perf/tests/insn-x86-dat-64.c | 30 +++++++++++++ tools/perf/tests/insn-x86-dat-src.c | 42 +++++++++++++++++++ .../util/intel-pt-decoder/x86-opcode-map.txt | 3 ++ 5 files changed, 96 insertions(+) diff --git a/arch/x86/lib/x86-opcode-map.txt b/arch/x86/lib/x86-opcode-map.txt index 5a9705ed9139..d388de72eaca 100644 --- a/arch/x86/lib/x86-opcode-map.txt +++ b/arch/x86/lib/x86-opcode-map.txt @@ -899,6 +899,9 @@ EndTable GrpTable: Grp9 1: CMPXCHG8B/16B Mq/Mdq +3: xrstors +4: xsavec +5: xsaves 6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) 7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) EndTable diff --git a/tools/perf/tests/insn-x86-dat-32.c b/tools/perf/tests/insn-x86-dat-32.c index 4b09b7e130a0..3b491cfe204e 100644 --- a/tools/perf/tests/insn-x86-dat-32.c +++ b/tools/perf/tests/insn-x86-dat-32.c @@ -636,5 +636,23 @@ "0f ae 30 \txsaveopt (%eax)",}, {{0x0f, 0xae, 0xf0, }, 3, 0, "", "", "0f ae f0 \tmfence ",}, +{{0x0f, 0xc7, 0x20, }, 3, 0, "", "", +"0f c7 20 \txsavec (%eax)",}, +{{0x0f, 0xc7, 0x25, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f c7 25 78 56 34 12 \txsavec 0x12345678",}, +{{0x0f, 0xc7, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 a4 c8 78 56 34 12 \txsavec 0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0xc7, 0x28, }, 3, 0, "", "", +"0f c7 28 \txsaves (%eax)",}, +{{0x0f, 0xc7, 0x2d, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f c7 2d 78 56 34 12 \txsaves 0x12345678",}, +{{0x0f, 0xc7, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 ac c8 78 56 34 12 \txsaves 0x12345678(%eax,%ecx,8)",}, +{{0x0f, 0xc7, 0x18, }, 3, 0, "", "", +"0f c7 18 \txrstors (%eax)",}, +{{0x0f, 0xc7, 0x1d, 0x78, 0x56, 0x34, 0x12, }, 7, 0, "", "", +"0f c7 1d 78 56 34 12 \txrstors 0x12345678",}, +{{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%eax,%ecx,8)",}, {{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "", "66 0f ae f8 \tpcommit ",}, diff --git a/tools/perf/tests/insn-x86-dat-64.c b/tools/perf/tests/insn-x86-dat-64.c index 5da235a4414f..4fe7cce179c4 100644 --- a/tools/perf/tests/insn-x86-dat-64.c +++ b/tools/perf/tests/insn-x86-dat-64.c @@ -734,5 +734,35 @@ "41 0f ae 30 \txsaveopt (%r8)",}, {{0x0f, 0xae, 0xf0, }, 3, 0, "", "", "0f ae f0 \tmfence ",}, +{{0x0f, 0xc7, 0x20, }, 3, 0, "", "", +"0f c7 20 \txsavec (%rax)",}, +{{0x41, 0x0f, 0xc7, 0x20, }, 4, 0, "", "", +"41 0f c7 20 \txsavec (%r8)",}, +{{0x0f, 0xc7, 0x24, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 24 25 78 56 34 12 \txsavec 0x12345678",}, +{{0x0f, 0xc7, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 a4 c8 78 56 34 12 \txsavec 0x12345678(%rax,%rcx,8)",}, +{{0x41, 0x0f, 0xc7, 0xa4, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"41 0f c7 a4 c8 78 56 34 12 \txsavec 0x12345678(%r8,%rcx,8)",}, +{{0x0f, 0xc7, 0x28, }, 3, 0, "", "", +"0f c7 28 \txsaves (%rax)",}, +{{0x41, 0x0f, 0xc7, 0x28, }, 4, 0, "", "", +"41 0f c7 28 \txsaves (%r8)",}, +{{0x0f, 0xc7, 0x2c, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 2c 25 78 56 34 12 \txsaves 0x12345678",}, +{{0x0f, 0xc7, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 ac c8 78 56 34 12 \txsaves 0x12345678(%rax,%rcx,8)",}, +{{0x41, 0x0f, 0xc7, 0xac, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"41 0f c7 ac c8 78 56 34 12 \txsaves 0x12345678(%r8,%rcx,8)",}, +{{0x0f, 0xc7, 0x18, }, 3, 0, "", "", +"0f c7 18 \txrstors (%rax)",}, +{{0x41, 0x0f, 0xc7, 0x18, }, 4, 0, "", "", +"41 0f c7 18 \txrstors (%r8)",}, +{{0x0f, 0xc7, 0x1c, 0x25, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 1c 25 78 56 34 12 \txrstors 0x12345678",}, +{{0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 8, 0, "", "", +"0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%rax,%rcx,8)",}, +{{0x41, 0x0f, 0xc7, 0x9c, 0xc8, 0x78, 0x56, 0x34, 0x12, }, 9, 0, "", "", +"41 0f c7 9c c8 78 56 34 12 \txrstors 0x12345678(%r8,%rcx,8)",}, {{0x66, 0x0f, 0xae, 0xf8, }, 4, 0, "", "", "66 0f ae f8 \tpcommit ",}, diff --git a/tools/perf/tests/insn-x86-dat-src.c b/tools/perf/tests/insn-x86-dat-src.c index 482637f44245..41b1b1c62660 100644 --- a/tools/perf/tests/insn-x86-dat-src.c +++ b/tools/perf/tests/insn-x86-dat-src.c @@ -445,6 +445,30 @@ int main(void) asm volatile("xsaveopt (%r8)"); asm volatile("mfence"); + /* xsavec mem */ + + asm volatile("xsavec (%rax)"); + asm volatile("xsavec (%r8)"); + asm volatile("xsavec (0x12345678)"); + asm volatile("xsavec 0x12345678(%rax,%rcx,8)"); + asm volatile("xsavec 0x12345678(%r8,%rcx,8)"); + + /* xsaves mem */ + + asm volatile("xsaves (%rax)"); + asm volatile("xsaves (%r8)"); + asm volatile("xsaves (0x12345678)"); + asm volatile("xsaves 0x12345678(%rax,%rcx,8)"); + asm volatile("xsaves 0x12345678(%r8,%rcx,8)"); + + /* xrstors mem */ + + asm volatile("xrstors (%rax)"); + asm volatile("xrstors (%r8)"); + asm volatile("xrstors (0x12345678)"); + asm volatile("xrstors 0x12345678(%rax,%rcx,8)"); + asm volatile("xrstors 0x12345678(%r8,%rcx,8)"); + #else /* #ifdef __x86_64__ */ /* bndmk m32, bnd */ @@ -822,6 +846,24 @@ int main(void) asm volatile("xsaveopt (%eax)"); asm volatile("mfence"); + /* xsavec mem */ + + asm volatile("xsavec (%eax)"); + asm volatile("xsavec (0x12345678)"); + asm volatile("xsavec 0x12345678(%eax,%ecx,8)"); + + /* xsaves mem */ + + asm volatile("xsaves (%eax)"); + asm volatile("xsaves (0x12345678)"); + asm volatile("xsaves 0x12345678(%eax,%ecx,8)"); + + /* xrstors mem */ + + asm volatile("xrstors (%eax)"); + asm volatile("xrstors (0x12345678)"); + asm volatile("xrstors 0x12345678(%eax,%ecx,8)"); + #endif /* #ifndef __x86_64__ */ /* pcommit */ diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt index 5a9705ed9139..d388de72eaca 100644 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt @@ -899,6 +899,9 @@ EndTable GrpTable: Grp9 1: CMPXCHG8B/16B Mq/Mdq +3: xrstors +4: xsavec +5: xsaves 6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) 7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) EndTable From 1b29ac59b1d692c06ec543a5f35e0d9ebb98e003 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Thu, 3 Sep 2015 08:31:00 -0400 Subject: [PATCH 024/260] perf session: Don't call dump_sample() when evsel is NULL Need to check evsel before passing it to dump_sample(). Signed-off-by: Kan Liang Cc: Adrian Hunter Cc: Andi Kleen Cc: Andy Lutomirski Cc: Jiri Olsa Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1441283463-51050-5-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 61669be15056..23fed17307ff 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1080,11 +1080,11 @@ static int machines__deliver_event(struct machines *machines, switch (event->header.type) { case PERF_RECORD_SAMPLE: - dump_sample(evsel, event, sample); if (evsel == NULL) { ++evlist->stats.nr_unknown_id; return 0; } + dump_sample(evsel, event, sample); if (machine == NULL) { ++evlist->stats.nr_unprocessable_samples; return 0; From 86c2786994bd7c0d4b525bbfbe42ac540d0b8166 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 13 Aug 2015 12:40:57 +0300 Subject: [PATCH 025/260] perf intel-pt: Add support for PERF_RECORD_SWITCH Add support for selecting and processing PERF_RECORD_SWITCH events for use by Intel PT. If they are available, they will be used in preference to sched_switch events. This enables an unprivileged user to trace multi-threaded or multi-process workloads with any level of perf_event_paranoid. However it depends on kernel support for PERF_RECORD_SWITCH. Without this patch, tracing a multi-threaded workload will decode without error but all the data will be attributed to the main thread. Without this patch, tracing a multi-process workload will result in decoder errors because the decoder will not know which executable is executing. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1439458857-30636-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/intel-pt.c | 55 ++++++++++-- tools/perf/util/intel-pt.c | 129 ++++++++++++++++++++++------ 2 files changed, 151 insertions(+), 33 deletions(-) diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index 2ca10d796c0b..b02af064f0f9 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c @@ -624,13 +624,49 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, * threads. */ if (have_timing_info && !cpu_map__empty(cpus)) { - err = intel_pt_track_switches(evlist); - if (err == -EPERM) - pr_debug2("Unable to select sched:sched_switch\n"); - else if (err) - return err; - else - ptr->have_sched_switch = 1; + if (perf_can_record_switch_events()) { + bool cpu_wide = !target__none(&opts->target) && + !target__has_task(&opts->target); + + if (!cpu_wide && perf_can_record_cpu_wide()) { + struct perf_evsel *switch_evsel; + + err = parse_events(evlist, "dummy:u", NULL); + if (err) + return err; + + switch_evsel = perf_evlist__last(evlist); + + switch_evsel->attr.freq = 0; + switch_evsel->attr.sample_period = 1; + switch_evsel->attr.context_switch = 1; + + switch_evsel->system_wide = true; + switch_evsel->no_aux_samples = true; + switch_evsel->immediate = true; + + perf_evsel__set_sample_bit(switch_evsel, TID); + perf_evsel__set_sample_bit(switch_evsel, TIME); + perf_evsel__set_sample_bit(switch_evsel, CPU); + + opts->record_switch_events = false; + ptr->have_sched_switch = 3; + } else { + opts->record_switch_events = true; + if (cpu_wide) + ptr->have_sched_switch = 3; + else + ptr->have_sched_switch = 2; + } + } else { + err = intel_pt_track_switches(evlist); + if (err == -EPERM) + pr_debug2("Unable to select sched:sched_switch\n"); + else if (err) + return err; + else + ptr->have_sched_switch = 1; + } } if (intel_pt_evsel) { @@ -663,8 +699,11 @@ static int intel_pt_recording_options(struct auxtrace_record *itr, tracking_evsel->attr.sample_period = 1; /* In per-cpu case, always need the time of mmap events etc */ - if (!cpu_map__empty(cpus)) + if (!cpu_map__empty(cpus)) { perf_evsel__set_sample_bit(tracking_evsel, TIME); + /* And the CPU for switch events */ + perf_evsel__set_sample_bit(tracking_evsel, CPU); + } } /* diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index bb41c20e6005..2968b37ed9b0 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1145,11 +1145,13 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) return 0; } -static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip) +static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) { + struct machine *machine = pt->machine; struct map *map; struct symbol *sym, *start; u64 ip, switch_ip = 0; + const char *ptss; if (ptss_ip) *ptss_ip = 0; @@ -1177,8 +1179,13 @@ static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip) if (!switch_ip || !ptss_ip) return 0; + if (pt->have_sched_switch == 1) + ptss = "perf_trace_sched_switch"; + else + ptss = "__perf_event_task_sched_out"; + for (sym = start; sym; sym = dso__next_symbol(sym)) { - if (!strcmp(sym->name, "perf_trace_sched_switch")) { + if (!strcmp(sym->name, ptss)) { ip = map->unmap_ip(map, sym->start); if (ip >= map->start && ip < map->end) { *ptss_ip = ip; @@ -1198,11 +1205,11 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) if (!pt->kernel_start) { pt->kernel_start = machine__kernel_start(pt->machine); - if (pt->per_cpu_mmaps && pt->have_sched_switch && + if (pt->per_cpu_mmaps && + (pt->have_sched_switch == 1 || pt->have_sched_switch == 3) && !pt->timeless_decoding && intel_pt_tracing_kernel(pt) && !pt->sampling_mode) { - pt->switch_ip = intel_pt_switch_ip(pt->machine, - &pt->ptss_ip); + pt->switch_ip = intel_pt_switch_ip(pt, &pt->ptss_ip); if (pt->switch_ip) { intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n", pt->switch_ip, pt->ptss_ip); @@ -1387,31 +1394,18 @@ static struct intel_pt_queue *intel_pt_cpu_to_ptq(struct intel_pt *pt, int cpu) return NULL; } -static int intel_pt_process_switch(struct intel_pt *pt, - struct perf_sample *sample) +static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid, + u64 timestamp) { struct intel_pt_queue *ptq; - struct perf_evsel *evsel; - pid_t tid; - int cpu, err; - - evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id); - if (evsel != pt->switch_evsel) - return 0; - - tid = perf_evsel__intval(evsel, sample, "next_pid"); - cpu = sample->cpu; - - intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n", - cpu, tid, sample->time, perf_time_to_tsc(sample->time, - &pt->tc)); + int err; if (!pt->sync_switch) - goto out; + return 1; ptq = intel_pt_cpu_to_ptq(pt, cpu); if (!ptq) - goto out; + return 1; switch (ptq->switch_state) { case INTEL_PT_SS_NOT_TRACING: @@ -1424,7 +1418,7 @@ static int intel_pt_process_switch(struct intel_pt *pt, return 0; case INTEL_PT_SS_EXPECTING_SWITCH_EVENT: if (!ptq->on_heap) { - ptq->timestamp = perf_time_to_tsc(sample->time, + ptq->timestamp = perf_time_to_tsc(timestamp, &pt->tc); err = auxtrace_heap__add(&pt->heap, ptq->queue_nr, ptq->timestamp); @@ -1441,10 +1435,76 @@ static int intel_pt_process_switch(struct intel_pt *pt, default: break; } -out: + + return 1; +} + +static int intel_pt_process_switch(struct intel_pt *pt, + struct perf_sample *sample) +{ + struct perf_evsel *evsel; + pid_t tid; + int cpu, ret; + + evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id); + if (evsel != pt->switch_evsel) + return 0; + + tid = perf_evsel__intval(evsel, sample, "next_pid"); + cpu = sample->cpu; + + intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n", + cpu, tid, sample->time, perf_time_to_tsc(sample->time, + &pt->tc)); + + ret = intel_pt_sync_switch(pt, cpu, tid, sample->time); + if (ret <= 0) + return ret; + return machine__set_current_tid(pt->machine, cpu, -1, tid); } +static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event, + struct perf_sample *sample) +{ + bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT; + pid_t pid, tid; + int cpu, ret; + + cpu = sample->cpu; + + if (pt->have_sched_switch == 3) { + if (!out) + return 0; + if (event->header.type != PERF_RECORD_SWITCH_CPU_WIDE) { + pr_err("Expecting CPU-wide context switch event\n"); + return -EINVAL; + } + pid = event->context_switch.next_prev_pid; + tid = event->context_switch.next_prev_tid; + } else { + if (out) + return 0; + pid = sample->pid; + tid = sample->tid; + } + + if (tid == -1) { + pr_err("context_switch event has no tid\n"); + return -EINVAL; + } + + intel_pt_log("context_switch: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n", + cpu, pid, tid, sample->time, perf_time_to_tsc(sample->time, + &pt->tc)); + + ret = intel_pt_sync_switch(pt, cpu, tid, sample->time); + if (ret <= 0) + return ret; + + return machine__set_current_tid(pt->machine, cpu, pid, tid); +} + static int intel_pt_process_itrace_start(struct intel_pt *pt, union perf_event *event, struct perf_sample *sample) @@ -1515,6 +1575,9 @@ static int intel_pt_process_event(struct perf_session *session, err = intel_pt_process_switch(pt, sample); else if (event->header.type == PERF_RECORD_ITRACE_START) err = intel_pt_process_itrace_start(pt, event, sample); + else if (event->header.type == PERF_RECORD_SWITCH || + event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) + err = intel_pt_context_switch(pt, event, sample); intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n", perf_event__name(event->header.type), event->header.type, @@ -1777,6 +1840,18 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) return NULL; } +static bool intel_pt_find_switch(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel; + + evlist__for_each(evlist, evsel) { + if (evsel->attr.context_switch) + return true; + } + + return false; +} + static const char * const intel_pt_info_fmts[] = { [INTEL_PT_PMU_TYPE] = " PMU Type %"PRId64"\n", [INTEL_PT_TIME_SHIFT] = " Time Shift %"PRIu64"\n", @@ -1888,6 +1963,10 @@ int intel_pt_process_auxtrace_info(union perf_event *event, pr_err("%s: missing sched_switch event\n", __func__); goto err_delete_thread; } + } else if (pt->have_sched_switch == 2 && + !intel_pt_find_switch(session->evlist)) { + pr_err("%s: missing context_switch attribute flag\n", __func__); + goto err_delete_thread; } if (session->itrace_synth_opts && session->itrace_synth_opts->set) { From 844dffa598b55fca6a83a856214fc0cfc3da24e5 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 4 Sep 2015 21:15:59 +0900 Subject: [PATCH 026/260] perf probe: Split add_perf_probe_events() The add_perf_probe_events() does 3 things: 1. convert all perf events to trace events 2. add all trace events to kernel 3. cleanup all trace events But sometimes we need to do something with the trace events. So split the funtion into three, so that it can access intermediate trace events via struct __event_package if needed. Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441368963-11565-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 39 +++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index eb5f18b75402..2c762f41e7a5 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2765,9 +2765,10 @@ struct __event_package { int ntevs; }; -int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) +static int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs, + struct __event_package **ppkgs) { - int i, j, ret; + int i, ret; struct __event_package *pkgs; ret = 0; @@ -2792,12 +2793,21 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) ret = convert_to_probe_trace_events(pkgs[i].pev, &pkgs[i].tevs); if (ret < 0) - goto end; + return ret; pkgs[i].ntevs = ret; } /* This just release blacklist only if allocated */ kprobe_blacklist__release(); + *ppkgs = pkgs; + + return 0; +} + +static int apply_perf_probe_events(struct __event_package *pkgs, int npevs) +{ + int i, ret = 0; + /* Loop 2: add all events */ for (i = 0; i < npevs; i++) { ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, @@ -2806,7 +2816,16 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) if (ret < 0) break; } -end: + return ret; +} + +static void cleanup_perf_probe_events(struct __event_package *pkgs, int npevs) +{ + int i, j; + + if (pkgs == NULL) + return; + /* Loop 3: cleanup and free trace events */ for (i = 0; i < npevs; i++) { for (j = 0; j < pkgs[i].ntevs; j++) @@ -2815,6 +2834,18 @@ end: } free(pkgs); exit_symbol_maps(); +} + +int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) +{ + int ret; + struct __event_package *pkgs = NULL; + + ret = convert_perf_probe_events(pevs, npevs, &pkgs); + if (ret == 0) + ret = apply_perf_probe_events(pkgs, npevs); + + cleanup_perf_probe_events(pkgs, npevs); return ret; } From 12fae5ef6dc6031ffcf4dffc6be5a16080e7dd7d Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Fri, 4 Sep 2015 21:16:00 +0900 Subject: [PATCH 027/260] perf probe: Link trace_probe_event into perf_probe_event This patch drops struct __event_package structure. Instead, it adds a 'struct trace_probe_event' pointer to 'struct perf_probe_event'. The trace_probe_event information gives further patches a chance to access actual probe points and actual arguments. Using them, 'perf probe' can get the whole list of added probes and print them at once. Other users like the upcoming bpf_loader will be able to attach one bpf program to different probing points of an inline function (which has multiple probing points) and glob functions. Moreover, by reading the arguments information, bpf code for reading those arguments can be generated. Signed-off-by: Wang Nan Acked-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441368963-11565-2-git-send-email-namhyung@kernel.org [namhyung: extract necessary part from the existing patch] Signed-off-by: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 57 +++++++++++------------------------ tools/perf/util/probe-event.h | 5 +++ 2 files changed, 22 insertions(+), 40 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 2c762f41e7a5..0d3a051b9202 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2759,59 +2759,39 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, return find_probe_trace_events_from_map(pev, tevs); } -struct __event_package { - struct perf_probe_event *pev; - struct probe_trace_event *tevs; - int ntevs; -}; - -static int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs, - struct __event_package **ppkgs) +int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, ret; - struct __event_package *pkgs; - - ret = 0; - pkgs = zalloc(sizeof(struct __event_package) * npevs); - - if (pkgs == NULL) - return -ENOMEM; ret = init_symbol_maps(pevs->uprobes); - if (ret < 0) { - free(pkgs); + if (ret < 0) return ret; - } /* Loop 1: convert all events */ for (i = 0; i < npevs; i++) { - pkgs[i].pev = &pevs[i]; /* Init kprobe blacklist if needed */ - if (!pkgs[i].pev->uprobes) + if (!pevs[i].uprobes) kprobe_blacklist__init(); /* Convert with or without debuginfo */ - ret = convert_to_probe_trace_events(pkgs[i].pev, - &pkgs[i].tevs); + ret = convert_to_probe_trace_events(&pevs[i], &pevs[i].tevs); if (ret < 0) return ret; - pkgs[i].ntevs = ret; + pevs[i].ntevs = ret; } /* This just release blacklist only if allocated */ kprobe_blacklist__release(); - *ppkgs = pkgs; - return 0; } -static int apply_perf_probe_events(struct __event_package *pkgs, int npevs) +int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, ret = 0; /* Loop 2: add all events */ for (i = 0; i < npevs; i++) { - ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, - pkgs[i].ntevs, + ret = __add_probe_trace_events(&pevs[i], pevs[i].tevs, + pevs[i].ntevs, probe_conf.force_add); if (ret < 0) break; @@ -2819,33 +2799,30 @@ static int apply_perf_probe_events(struct __event_package *pkgs, int npevs) return ret; } -static void cleanup_perf_probe_events(struct __event_package *pkgs, int npevs) +void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, j; - if (pkgs == NULL) - return; - /* Loop 3: cleanup and free trace events */ for (i = 0; i < npevs; i++) { - for (j = 0; j < pkgs[i].ntevs; j++) - clear_probe_trace_event(&pkgs[i].tevs[j]); - zfree(&pkgs[i].tevs); + for (j = 0; j < pevs[i].ntevs; j++) + clear_probe_trace_event(&pevs[i].tevs[j]); + zfree(&pevs[i].tevs); + pevs[i].ntevs = 0; } - free(pkgs); + exit_symbol_maps(); } int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int ret; - struct __event_package *pkgs = NULL; - ret = convert_perf_probe_events(pevs, npevs, &pkgs); + ret = convert_perf_probe_events(pevs, npevs); if (ret == 0) - ret = apply_perf_probe_events(pkgs, npevs); + ret = apply_perf_probe_events(pevs, npevs); - cleanup_perf_probe_events(pkgs, npevs); + cleanup_perf_probe_events(pevs, npevs); return ret; } diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 6e7ec68a4aa8..70c327bd61de 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -87,6 +87,8 @@ struct perf_probe_event { bool uprobes; /* Uprobe event flag */ char *target; /* Target binary */ struct perf_probe_arg *args; /* Arguments */ + struct probe_trace_event *tevs; + int ntevs; }; /* Line range */ @@ -138,6 +140,9 @@ extern void line_range__clear(struct line_range *lr); extern int line_range__init(struct line_range *lr); extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs); +extern int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); +extern int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); +extern void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern int del_perf_probe_events(struct strfilter *filter); extern int show_perf_probe_events(struct strfilter *filter); extern int show_line_range(struct line_range *lr, const char *module, From b02137cc6550c1fa28e9a7c943a79fe6e4c4378d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 4 Sep 2015 21:16:01 +0900 Subject: [PATCH 028/260] perf probe: Move print logic into cmd_probe() Showing actual trace event when adding perf events is only needed in perf probe command. But the add functionality itself can be used by other places. So move the printing code into the cmd_probe(). Also it combines the output if more than one event is added. Before: $ sudo perf probe -a do_fork -a do_exit Added new event: probe:do_fork (on do_fork) You can now use it in all perf tools, such as: perf record -e probe:do_fork -aR sleep 1 Added new events: probe:do_exit (on do_exit) probe:do_exit_1 (on do_exit) You can now use it in all perf tools, such as: perf record -e probe:do_exit_1 -aR sleep 1 After: $ sudo perf probe -a do_fork -a do_exit Added new events: probe:do_fork (on do_fork) probe:do_exit (on do_exit) probe:do_exit_1 (on do_exit) You can now use it in all perf tools, such as: perf record -e probe:do_exit_1 -aR sleep 1 Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Acked-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441368963-11565-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 48 ++++++++++++++++++++++++++++++++++- tools/perf/util/probe-event.c | 22 +++------------- tools/perf/util/probe-event.h | 3 +++ 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index b81cec33b4b2..b8cf6cb7e1bf 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -311,6 +311,52 @@ static void pr_err_with_code(const char *msg, int err) pr_err("\n"); } +static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs) +{ + int ret; + int i, k; + const char *event = NULL, *group = NULL; + + ret = convert_perf_probe_events(pevs, npevs); + if (ret < 0) + goto out_cleanup; + + ret = apply_perf_probe_events(pevs, npevs); + if (ret < 0) + goto out_cleanup; + + for (i = k = 0; i < npevs; i++) + k += pevs[i].ntevs; + + pr_info("Added new event%s\n", (k > 1) ? "s:" : ":"); + for (i = 0; i < npevs; i++) { + struct perf_probe_event *pev = &pevs[i]; + + for (k = 0; k < pev->ntevs; k++) { + struct probe_trace_event *tev = &pev->tevs[k]; + + /* We use tev's name for showing new events */ + show_perf_probe_event(tev->group, tev->event, pev, + tev->point.module, false); + + /* Save the last valid name */ + event = tev->event; + group = tev->group; + } + } + + /* Note that it is possible to skip all events because of blacklist */ + if (event) { + /* Show how to use the event. */ + pr_info("\nYou can now use it in all perf tools, such as:\n\n"); + pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); + } + +out_cleanup: + cleanup_perf_probe_events(pevs, npevs); + return ret; +} + static int __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -496,7 +542,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(probe_usage, options); } - ret = add_perf_probe_events(params.events, params.nevents); + ret = perf_add_probe_events(params.events, params.nevents); if (ret < 0) { pr_err_with_code(" Error: Failed to add events.", ret); return ret; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 0d3a051b9202..01b9a5bd9449 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2180,9 +2180,9 @@ out: } /* Show an event */ -static int show_perf_probe_event(const char *group, const char *event, - struct perf_probe_event *pev, - const char *module, bool use_stdout) +int show_perf_probe_event(const char *group, const char *event, + struct perf_probe_event *pev, + const char *module, bool use_stdout) { struct strbuf buf = STRBUF_INIT; int ret; @@ -2399,7 +2399,6 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, { int i, fd, ret; struct probe_trace_event *tev = NULL; - const char *event = NULL, *group = NULL; struct strlist *namelist; fd = probe_file__open(PF_FL_RW | (pev->uprobes ? PF_FL_UPROBE : 0)); @@ -2415,7 +2414,6 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, } ret = 0; - pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); for (i = 0; i < ntevs; i++) { tev = &tevs[i]; /* Skip if the symbol is out of .text or blacklisted */ @@ -2432,13 +2430,6 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, if (ret < 0) break; - /* We use tev's name for showing new events */ - show_perf_probe_event(tev->group, tev->event, pev, - tev->point.module, false); - /* Save the last valid name */ - event = tev->event; - group = tev->group; - /* * Probes after the first probe which comes from same * user input are always allowed to add suffix, because @@ -2450,13 +2441,6 @@ static int __add_probe_trace_events(struct perf_probe_event *pev, if (ret == -EINVAL && pev->uprobes) warn_uprobe_event_compat(tev); - /* Note that it is possible to skip all events because of blacklist */ - if (ret >= 0 && event) { - /* Show how to use the event. */ - pr_info("\nYou can now use it in all perf tools, such as:\n\n"); - pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); - } - strlist__delete(namelist); close_out: close(fd); diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 70c327bd61de..610f743671e1 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -144,6 +144,9 @@ extern int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern int del_perf_probe_events(struct strfilter *filter); +extern int show_perf_probe_event(const char *group, const char *event, + struct perf_probe_event *pev, + const char *module, bool use_stdout); extern int show_perf_probe_events(struct strfilter *filter); extern int show_line_range(struct line_range *lr, const char *module, bool user); From e7895e422e4da63daedacad0a2ed1a5a6b502d66 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 4 Sep 2015 21:16:02 +0900 Subject: [PATCH 029/260] perf probe: Split del_perf_probe_events() The del_perf_probe_events() does 2 things: 1. find existing events which match to filter 2. delete such trace events from kernel But sometimes we need to do something with the trace events. So split the funtion into two, so that it can access intermediate trace events name using strlist if needed. Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441368963-11565-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-file.c | 40 ++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index bbb243717ec8..f00b0df56dfe 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -275,7 +275,8 @@ error: return ret; } -int probe_file__del_events(int fd, struct strfilter *filter) +static int probe_file__get_events(int fd, struct strfilter *filter, + struct strlist *plist) { struct strlist *namelist; struct str_node *ent; @@ -290,12 +291,43 @@ int probe_file__del_events(int fd, struct strfilter *filter) p = strchr(ent->s, ':'); if ((p && strfilter__compare(filter, p + 1)) || strfilter__compare(filter, ent->s)) { - ret = __del_trace_probe_event(fd, ent); - if (ret < 0) - break; + strlist__add(plist, ent->s); + ret = 0; } } strlist__delete(namelist); return ret; } + +static int probe_file__del_strlist(int fd, struct strlist *namelist) +{ + int ret = 0; + struct str_node *ent; + + strlist__for_each(ent, namelist) { + ret = __del_trace_probe_event(fd, ent); + if (ret < 0) + break; + } + return ret; +} + +int probe_file__del_events(int fd, struct strfilter *filter) +{ + struct strlist *namelist; + int ret; + + namelist = strlist__new(NULL, NULL); + if (!namelist) + return -ENOMEM; + + ret = probe_file__get_events(fd, filter, namelist); + if (ret < 0) + return ret; + + ret = probe_file__del_strlist(fd, namelist); + strlist__delete(namelist); + + return ret; +} From e607f1426b584f2bd3f688a2d416baf963251e7a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 4 Sep 2015 21:16:03 +0900 Subject: [PATCH 030/260] perf probe: Print deleted events in cmd_probe() Showing actual trace event when deleteing perf events is only needed in perf probe command. But the add functionality itself can be used by other places. So move the printing code into the cmd_probe(). The output is not changed. Signed-off-by: Namhyung Kim Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441368963-11565-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 62 ++++++++++++++++++++++++++++++++++- tools/perf/util/probe-event.c | 5 --- tools/perf/util/probe-event.h | 1 + tools/perf/util/probe-file.c | 7 ++-- tools/perf/util/probe-file.h | 4 +++ 5 files changed, 69 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index b8cf6cb7e1bf..ee2c46d8353e 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -41,6 +41,7 @@ #include "util/parse-options.h" #include "util/probe-finder.h" #include "util/probe-event.h" +#include "util/probe-file.h" #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" #define DEFAULT_FUNC_FILTER "!_*" @@ -357,6 +358,65 @@ out_cleanup: return ret; } +static int perf_del_probe_events(struct strfilter *filter) +{ + int ret, ret2, ufd = -1, kfd = -1; + char *str = strfilter__string(filter); + struct strlist *klist = NULL, *ulist = NULL; + struct str_node *ent; + + if (!str) + return -EINVAL; + + pr_debug("Delete filter: \'%s\'\n", str); + + /* Get current event names */ + ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW); + if (ret < 0) + goto out; + + klist = strlist__new(NULL, NULL); + if (!klist) + return -ENOMEM; + + ret = probe_file__get_events(kfd, filter, klist); + if (ret == 0) { + strlist__for_each(ent, klist) + pr_info("Removed event: %s\n", ent->s); + + ret = probe_file__del_strlist(kfd, klist); + if (ret < 0) + goto error; + } + + ret2 = probe_file__get_events(ufd, filter, ulist); + if (ret2 == 0) { + strlist__for_each(ent, ulist) + pr_info("Removed event: %s\n", ent->s); + + ret2 = probe_file__del_strlist(ufd, ulist); + if (ret2 < 0) + goto error; + } + + if (ret == -ENOENT && ret2 == -ENOENT) + pr_debug("\"%s\" does not hit any event.\n", str); + /* Note that this is silently ignored */ + ret = 0; + +error: + if (kfd >= 0) + close(kfd); + if (ufd >= 0) + close(ufd); +out: + strlist__delete(klist); + strlist__delete(ulist); + free(str); + + return ret; +} + static int __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -529,7 +589,7 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) return ret; #endif case 'd': - ret = del_perf_probe_events(params.filter); + ret = perf_del_probe_events(params.filter); if (ret < 0) { pr_err_with_code(" Error: Failed to delete events.", ret); return ret; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 01b9a5bd9449..3da9e1c792fa 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2819,8 +2819,6 @@ int del_perf_probe_events(struct strfilter *filter) if (!str) return -EINVAL; - pr_debug("Delete filter: \'%s\'\n", str); - /* Get current event names */ ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW); if (ret < 0) @@ -2835,9 +2833,6 @@ int del_perf_probe_events(struct strfilter *filter) ret = ret2; goto error; } - if (ret == -ENOENT && ret2 == -ENOENT) - pr_debug("\"%s\" does not hit any event.\n", str); - /* Note that this is silently ignored */ ret = 0; error: diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 610f743671e1..9bcea36359f2 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -144,6 +144,7 @@ extern int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs); extern int del_perf_probe_events(struct strfilter *filter); + extern int show_perf_probe_event(const char *group, const char *event, struct perf_probe_event *pev, const char *module, bool use_stdout); diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index f00b0df56dfe..38c0a62039cc 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -267,7 +267,6 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) goto error; } - pr_info("Removed event: %s\n", ent->s); return 0; error: pr_warning("Failed to delete event: %s\n", @@ -275,8 +274,8 @@ error: return ret; } -static int probe_file__get_events(int fd, struct strfilter *filter, - struct strlist *plist) +int probe_file__get_events(int fd, struct strfilter *filter, + struct strlist *plist) { struct strlist *namelist; struct str_node *ent; @@ -300,7 +299,7 @@ static int probe_file__get_events(int fd, struct strfilter *filter, return ret; } -static int probe_file__del_strlist(int fd, struct strlist *namelist) +int probe_file__del_strlist(int fd, struct strlist *namelist) { int ret = 0; struct str_node *ent; diff --git a/tools/perf/util/probe-file.h b/tools/perf/util/probe-file.h index ada94a242a17..18ac9cf51c34 100644 --- a/tools/perf/util/probe-file.h +++ b/tools/perf/util/probe-file.h @@ -14,5 +14,9 @@ struct strlist *probe_file__get_namelist(int fd); struct strlist *probe_file__get_rawlist(int fd); int probe_file__add_event(int fd, struct probe_trace_event *tev); int probe_file__del_events(int fd, struct strfilter *filter); +int probe_file__get_events(int fd, struct strfilter *filter, + struct strlist *plist); +int probe_file__del_strlist(int fd, struct strlist *namelist); + #endif From cf2f33a4e54096f90652cca3511fd6a456ea5abe Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Sep 2015 13:22:06 -0300 Subject: [PATCH 031/260] perf trace: Add read/write to the file group Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-l6812iuai3g486z3mn8ufan8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/trace/strace/groups/file | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/trace/strace/groups/file b/tools/perf/trace/strace/groups/file index 62378a899d79..722e25d200bf 100644 --- a/tools/perf/trace/strace/groups/file +++ b/tools/perf/trace/strace/groups/file @@ -9,6 +9,7 @@ mkdir open openat quotactl +read readlink rename rmdir @@ -16,3 +17,4 @@ stat statfs symlink unlink +write From b20112edeadf0b8a1416de061caa4beb11539902 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 21 Aug 2015 12:05:18 +0300 Subject: [PATCH 032/260] perf/x86: Improve accuracy of perf/sched clock When TSC is stable perf/sched clock is based on it. However the conversion from cycles to nanoseconds is not as accurate as it could be. Because CYC2NS_SCALE_FACTOR is 10, the accuracy is +/- 1/2048 The change is to calculate the maximum shift that results in a multiplier that is still a 32-bit number. For example all frequencies over 1 GHz will have a shift of 32, making the accuracy of the conversion +/- 1/(2^33). That is achieved by using the 'clocks_calc_mult_shift()' function. Signed-off-by: Adrian Hunter Signed-off-by: Peter Zijlstra (Intel) Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1440147918-22250-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/tsc.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index c8d52cb4cb6e..39ec3d07affd 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -167,21 +167,20 @@ static void cyc2ns_write_end(int cpu, struct cyc2ns_data *data) * ns = cycles * cyc2ns_scale / SC * * And since SC is a constant power of two, we can convert the div - * into a shift. + * into a shift. The larger SC is, the more accurate the conversion, but + * cyc2ns_scale needs to be a 32-bit value so that 32-bit multiplication + * (64-bit result) can be used. * - * We can use khz divisor instead of mhz to keep a better precision, since - * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. + * We can use khz divisor instead of mhz to keep a better precision. * (mathieu.desnoyers@polymtl.ca) * * -johnstul@us.ibm.com "math is hard, lets go shopping!" */ -#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ - static void cyc2ns_data_init(struct cyc2ns_data *data) { data->cyc2ns_mul = 0; - data->cyc2ns_shift = CYC2NS_SCALE_FACTOR; + data->cyc2ns_shift = 0; data->cyc2ns_offset = 0; data->__count = 0; } @@ -215,14 +214,14 @@ static inline unsigned long long cycles_2_ns(unsigned long long cyc) if (likely(data == tail)) { ns = data->cyc2ns_offset; - ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, CYC2NS_SCALE_FACTOR); + ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, data->cyc2ns_shift); } else { data->__count++; barrier(); ns = data->cyc2ns_offset; - ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, CYC2NS_SCALE_FACTOR); + ns += mul_u64_u32_shr(cyc, data->cyc2ns_mul, data->cyc2ns_shift); barrier(); @@ -256,12 +255,11 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) * time function is continuous; see the comment near struct * cyc2ns_data. */ - data->cyc2ns_mul = - DIV_ROUND_CLOSEST(NSEC_PER_MSEC << CYC2NS_SCALE_FACTOR, - cpu_khz); - data->cyc2ns_shift = CYC2NS_SCALE_FACTOR; + clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, cpu_khz, + NSEC_PER_MSEC, 0); + data->cyc2ns_offset = ns_now - - mul_u64_u32_shr(tsc_now, data->cyc2ns_mul, CYC2NS_SCALE_FACTOR); + mul_u64_u32_shr(tsc_now, data->cyc2ns_mul, data->cyc2ns_shift); cyc2ns_write_end(cpu, data); From a09d31f45224c219a4d5c728fa40150dc9d3e3e5 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Mon, 31 Aug 2015 17:09:27 +0300 Subject: [PATCH 033/260] perf/x86/intel/ds: Work around BTS leaking kernel addresses BTS leaks kernel addresses even in userspace-only mode due to imprecise IP sampling, so sometimes syscall entry points or page fault handler addresses end up in a userspace trace. Since this driver uses a relatively small buffer for BTS records and it has to iterate through them anyway, it can also take on the additional job of filtering out the records that contain kernel addresses when kernel space tracing is not enabled. This patch changes the bts code to skip the offending records from perf output. In order to request the exact amount of space on the ring buffer, we need to do an extra pass through the records to know how many there are of the valid ones, but considering the small size of the buffer, this extra pass adds very little overhead to the nmi handler. This way we won't end up with awkward IP samples with zero IPs in the perf stream. Signed-off-by: Alexander Shishkin Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: hpa@zytor.com Link: http://lkml.kernel.org/r/1441030168-6853-2-git-send-email-alexander.shishkin@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_ds.c | 40 +++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index 84f236ab96b0..5db1c7755548 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -510,10 +510,11 @@ int intel_pmu_drain_bts_buffer(void) u64 flags; }; struct perf_event *event = cpuc->events[INTEL_PMC_IDX_FIXED_BTS]; - struct bts_record *at, *top; + struct bts_record *at, *base, *top; struct perf_output_handle handle; struct perf_event_header header; struct perf_sample_data data; + unsigned long skip = 0; struct pt_regs regs; if (!event) @@ -522,10 +523,10 @@ int intel_pmu_drain_bts_buffer(void) if (!x86_pmu.bts_active) return 0; - at = (struct bts_record *)(unsigned long)ds->bts_buffer_base; - top = (struct bts_record *)(unsigned long)ds->bts_index; + base = (struct bts_record *)(unsigned long)ds->bts_buffer_base; + top = (struct bts_record *)(unsigned long)ds->bts_index; - if (top <= at) + if (top <= base) return 0; memset(®s, 0, sizeof(regs)); @@ -534,6 +535,27 @@ int intel_pmu_drain_bts_buffer(void) perf_sample_data_init(&data, 0, event->hw.last_period); + /* + * BTS leaks kernel addresses in branches across the cpl boundary, + * such as traps or system calls, so unless the user is asking for + * kernel tracing (and right now it's not possible), we'd need to + * filter them out. But first we need to count how many of those we + * have in the current batch. This is an extra O(n) pass, however, + * it's much faster than the other one especially considering that + * n <= 2560 (BTS_BUFFER_SIZE / BTS_RECORD_SIZE * 15/16; see the + * alloc_bts_buffer()). + */ + for (at = base; at < top; at++) { + /* + * Note that right now *this* BTS code only works if + * attr::exclude_kernel is set, but let's keep this extra + * check here in case that changes. + */ + if (event->attr.exclude_kernel && + (kernel_ip(at->from) || kernel_ip(at->to))) + skip++; + } + /* * Prepare a generic sample, i.e. fill in the invariant fields. * We will overwrite the from and to address before we output @@ -541,10 +563,16 @@ int intel_pmu_drain_bts_buffer(void) */ perf_prepare_sample(&header, &data, event, ®s); - if (perf_output_begin(&handle, event, header.size * (top - at))) + if (perf_output_begin(&handle, event, header.size * + (top - base - skip))) return 1; - for (; at < top; at++) { + for (at = base; at < top; at++) { + /* Filter out any records that contain kernel addresses. */ + if (event->attr.exclude_kernel && + (kernel_ip(at->from) || kernel_ip(at->to))) + continue; + data.ip = at->from; data.addr = at->to; From d2878d642a4edd1d57c691dc3e4d7847cbf9d442 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Mon, 31 Aug 2015 17:09:28 +0300 Subject: [PATCH 034/260] perf/x86/intel/bts: Disallow use by unprivileged users on paranoid systems BTS leaks kernel addresses even in userspace-only mode due to imprecise IP sampling, so sometimes syscall entry points or page fault handler addresses end up in a userspace trace. Now, intel_bts driver exports trace data zero-copy, it does not scan through it to filter out the kernel addresses and it's would be a O(n) job. To work around this situation, this patch forbids the use of intel_bts driver by unprivileged users on systems with the paranoid setting above the (kernel's) default "1", which still allows kernel profiling. In other words, using intel_bts driver implies kernel tracing, regardless of the "exclude_kernel" attribute setting. Signed-off-by: Alexander Shishkin Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: hpa@zytor.com Link: http://lkml.kernel.org/r/1441030168-6853-3-git-send-email-alexander.shishkin@linux.intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_bts.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86/kernel/cpu/perf_event_intel_bts.c b/arch/x86/kernel/cpu/perf_event_intel_bts.c index d1c0f254afbe..2cad71d1b14c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_bts.c +++ b/arch/x86/kernel/cpu/perf_event_intel_bts.c @@ -495,6 +495,19 @@ static int bts_event_init(struct perf_event *event) if (x86_add_exclusive(x86_lbr_exclusive_bts)) return -EBUSY; + /* + * BTS leaks kernel addresses even when CPL0 tracing is + * disabled, so disallow intel_bts driver for unprivileged + * users on paranoid systems since it provides trace data + * to the user in a zero-copy fashion. + * + * Note that the default paranoia setting permits unprivileged + * users to profile the kernel. + */ + if (event->attr.exclude_kernel && perf_paranoid_kernel() && + !capable(CAP_SYS_ADMIN)) + return -EACCES; + ret = x86_reserve_hardware(); if (ret) { x86_del_exclusive(x86_lbr_exclusive_bts); From deb27519bf1f4b21a761c0675dbdf1196df7d72a Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Mon, 17 Aug 2015 08:37:31 -0400 Subject: [PATCH 035/260] perf/x86/intel: Fix LBR callstack issue caused by FREEZE_LBRS_ON_PMI This patch fixes an issue which introduced by commit 1a78d93750bb5f61abdc59a91fc3bd06a214542a ("perf/x86/intel: Streamline LBR MSR handling in PMI"). The old patch not only avoids writing LBR_SELECT MSR in PMI, but also avoids updating lbr_select variable. So in PMI, FREEZE_LBRS_ON_PMI bit is always mistakenly set for IA32_DEBUGCTLMSR MSR, which causes superfluous increase/decrease of LBR_TOS when collecting LBR callstack. Reported-by: Milian Wolff Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1439815051-8616-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index b2c9475b7ff2..a1d07c71d3b6 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -151,10 +151,9 @@ static void __intel_pmu_lbr_enable(bool pmi) * No need to reprogram LBR_SELECT in a PMI, as it * did not change. */ - if (cpuc->lbr_sel && !pmi) { - lbr_select = cpuc->lbr_sel->config; + lbr_select = cpuc->lbr_sel->config; + if (cpuc->lbr_sel && !pmi) wrmsrl(MSR_LBR_SELECT, lbr_select); - } rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); orig_debugctl = debugctl; From 516792e67c39d31701641ab355acdb9cbfec0643 Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 31 Aug 2015 15:12:56 +0300 Subject: [PATCH 036/260] perf/core: Delete PF_EXITING checks from perf_cgroup_exit() callback cgroup_exit() is not called from copy_process() after commit: e8604cb43690 ("cgroup: fix spurious lockdep warning in cgroup_exit()") from do_exit(). So this check is useless and the comment is obsolete. Signed-off-by: Kirill Tkhai Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/55E444C8.3020402@odin.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index f548f69c4299..76e64be9bfb5 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9297,14 +9297,6 @@ static void perf_cgroup_exit(struct cgroup_subsys_state *css, struct cgroup_subsys_state *old_css, struct task_struct *task) { - /* - * cgroup_exit() is called in the copy_process() failure path. - * Ignore this case since the task hasn't ran yet, this avoids - * trying to poke a half freed task state from generic code. - */ - if (!(task->flags & PF_EXITING)) - return; - task_function_call(task, __perf_cgroup_move, task); } From 73fdeb66592ee80dffb16fb8a9b7378a00c1a826 Mon Sep 17 00:00:00 2001 From: Huaitong Han Date: Mon, 31 Aug 2015 16:21:02 +0800 Subject: [PATCH 037/260] perf/x86/intel/pt: Fix KVM warning due to doing rdmsr() before the CPUID test If KVM does not support INTEL_PT, guest MSR_IA32_RTIT_CTL reading will produce host warning like "kvm [2469]: vcpu0 unhandled rdmsr: 0x570". Guest can determine whether the CPU supports Intel_PT according to CPUID, so test_cpu_cap function is added before rdmsr,and it is more in line with the code style. Signed-off-by: Huaitong Han Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: acme@kernel.org Link: http://lkml.kernel.org/r/1441009262-9792-1-git-send-email-huaitong.han@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_pt.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c index 42169283448b..868e1194337f 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_pt.c +++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c @@ -139,9 +139,6 @@ static int __init pt_pmu_hw_init(void) long i; attrs = NULL; - ret = -ENODEV; - if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT)) - goto fail; for (i = 0; i < PT_CPUID_LEAVES; i++) { cpuid_count(20, i, @@ -1130,6 +1127,10 @@ static __init int pt_init(void) int ret, cpu, prior_warn = 0; BUILD_BUG_ON(sizeof(struct topa) > PAGE_SIZE); + + if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_INTEL_PT)) + return -ENODEV; + get_online_cpus(); for_each_online_cpu(cpu) { u64 ctl; From b0e878759452314676fbdd71df4ac67e7d08de5d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 28 Aug 2015 14:06:07 +0200 Subject: [PATCH 038/260] perf/abi: Document some more aspects of the perf ABI Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 117 +++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 19 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 092a0e8a479a..d61ee4459eee 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -140,27 +140,60 @@ struct hw_perf_event { }; #endif }; + /* + * If the event is a per task event, this will point to the task in + * question. See the comment in perf_event_alloc(). + */ struct task_struct *target; - int state; - local64_t prev_count; - u64 sample_period; - u64 last_period; - local64_t period_left; - u64 interrupts_seq; - u64 interrupts; - - u64 freq_time_stamp; - u64 freq_count_stamp; -#endif -}; /* - * hw_perf_event::state flags + * hw_perf_event::state flags; used to track the PERF_EF_* state. */ #define PERF_HES_STOPPED 0x01 /* the counter is stopped */ #define PERF_HES_UPTODATE 0x02 /* event->count up-to-date */ #define PERF_HES_ARCH 0x04 + int state; + + /* + * The last observed hardware counter value, updated with a + * local64_cmpxchg() such that pmu::read() can be called nested. + */ + local64_t prev_count; + + /* + * The period to start the next sample with. + */ + u64 sample_period; + + /* + * The period we started this sample with. + */ + u64 last_period; + + /* + * However much is left of the current period; note that this is + * a full 64bit value and allows for generation of periods longer + * than hardware might allow. + */ + local64_t period_left; + + /* + * State for throttling the event, see __perf_event_overflow() and + * perf_adjust_freq_unthr_context(). + */ + u64 interrupts_seq; + u64 interrupts; + + /* + * State for freq target events, see __perf_event_overflow() and + * perf_adjust_freq_unthr_context(). + */ + u64 freq_time_stamp; + u64 freq_count_stamp; +#endif +}; + struct perf_event; /* @@ -210,7 +243,19 @@ struct pmu { /* * Try and initialize the event for this PMU. - * Should return -ENOENT when the @event doesn't match this PMU. + * + * Returns: + * -ENOENT -- @event is not for this PMU + * + * -ENODEV -- @event is for this PMU but PMU not present + * -EBUSY -- @event is for this PMU but PMU temporarily unavailable + * -EINVAL -- @event is for this PMU but @event is not valid + * -EOPNOTSUPP -- @event is for this PMU, @event is valid, but not supported + * -EACCESS -- @event is for this PMU, @event is valid, but no privilidges + * + * 0 -- @event is for this PMU and valid + * + * Other error return values are allowed. */ int (*event_init) (struct perf_event *event); @@ -221,27 +266,61 @@ struct pmu { void (*event_mapped) (struct perf_event *event); /*optional*/ void (*event_unmapped) (struct perf_event *event); /*optional*/ + /* + * Flags for ->add()/->del()/ ->start()/->stop(). There are + * matching hw_perf_event::state flags. + */ #define PERF_EF_START 0x01 /* start the counter when adding */ #define PERF_EF_RELOAD 0x02 /* reload the counter when starting */ #define PERF_EF_UPDATE 0x04 /* update the counter when stopping */ /* - * Adds/Removes a counter to/from the PMU, can be done inside - * a transaction, see the ->*_txn() methods. + * Adds/Removes a counter to/from the PMU, can be done inside a + * transaction, see the ->*_txn() methods. + * + * The add/del callbacks will reserve all hardware resources required + * to service the event, this includes any counter constraint + * scheduling etc. + * + * Called with IRQs disabled and the PMU disabled on the CPU the event + * is on. + * + * ->add() called without PERF_EF_START should result in the same state + * as ->add() followed by ->stop(). + * + * ->del() must always PERF_EF_UPDATE stop an event. If it calls + * ->stop() that must deal with already being stopped without + * PERF_EF_UPDATE. */ int (*add) (struct perf_event *event, int flags); void (*del) (struct perf_event *event, int flags); /* - * Starts/Stops a counter present on the PMU. The PMI handler - * should stop the counter when perf_event_overflow() returns - * !0. ->start() will be used to continue. + * Starts/Stops a counter present on the PMU. + * + * The PMI handler should stop the counter when perf_event_overflow() + * returns !0. ->start() will be used to continue. + * + * Also used to change the sample period. + * + * Called with IRQs disabled and the PMU disabled on the CPU the event + * is on -- will be called from NMI context with the PMU generates + * NMIs. + * + * ->stop() with PERF_EF_UPDATE will read the counter and update + * period/count values like ->read() would. + * + * ->start() with PERF_EF_RELOAD will reprogram the the counter + * value, must be preceded by a ->stop() with PERF_EF_UPDATE. */ void (*start) (struct perf_event *event, int flags); void (*stop) (struct perf_event *event, int flags); /* * Updates the counter value of the event. + * + * For sampling capable PMUs this will also update the software period + * hw_perf_event::period_left field. */ void (*read) (struct perf_event *event); From 845583767c306dac0290aab908c18b01772ea4b4 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:44 -0700 Subject: [PATCH 039/260] sparc, perf/sparc: Remove unnecessary assignment In ->commit_txn() 'cpuc' is already initialized when it is declared, so we can remove the duplicate assignment. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: David S. Miller Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: sparclinux@vger.kernel.org Link: http://lkml.kernel.org/r/1441336073-22750-2-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- arch/sparc/kernel/perf_event.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 689db65f8529..e3f89c7e5062 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -1528,7 +1528,6 @@ static int sparc_pmu_commit_txn(struct pmu *pmu) if (!sparc_pmu) return -EINVAL; - cpuc = this_cpu_ptr(&cpu_hw_events); n = cpuc->n_events; if (check_excludes(cpuc->event, 0, n)) return -EINVAL; From fbbe07011581990ef74dfac06dc8511b1a14badb Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:45 -0700 Subject: [PATCH 040/260] perf/core: Add a 'flags' parameter to the PMU transactional interfaces Currently, the PMU interface allows reading only one counter at a time. But some PMUs like the 24x7 counters in Power, support reading several counters at once. To leveage this functionality, extend the transaction interface to support a "transaction type". The first type, PERF_PMU_TXN_ADD, refers to the existing transactions, i.e. used to _schedule_ all the events on the PMU as a group. A second transaction type, PERF_PMU_TXN_READ, will be used in a follow-on patch, by the 24x7 counters to read several counters at once. Extend the transaction interfaces to the PMU to accept a 'txn_flags' parameter and use this parameter to ignore any transactions that are not of type PERF_PMU_TXN_ADD. Thanks to Peter Zijlstra for his input. Signed-off-by: Sukadev Bhattiprolu [peterz: s390 compile fix] Signed-off-by: Peter Zijlstra (Intel) Acked-by: Michael Ellerman Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-3-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- arch/powerpc/perf/core-book3s.c | 30 +++++++++++++++++++++++++++++- arch/s390/kernel/perf_cpum_cf.c | 30 +++++++++++++++++++++++++++++- arch/sparc/kernel/perf_event.c | 25 ++++++++++++++++++++++++- arch/x86/kernel/cpu/perf_event.c | 32 +++++++++++++++++++++++++++++++- arch/x86/kernel/cpu/perf_event.h | 1 + include/linux/perf_event.h | 14 +++++++++++--- kernel/events/core.c | 31 ++++++++++++++++++++++++++++--- 7 files changed, 153 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index b0382f3f1095..c84074185c80 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -49,6 +49,7 @@ struct cpu_hw_events { unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES]; unsigned int group_flag; + unsigned int txn_flags; int n_txn_start; /* BHRB bits */ @@ -1586,11 +1587,21 @@ static void power_pmu_stop(struct perf_event *event, int ef_flags) * Start group events scheduling transaction * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time + * + * We only support PERF_PMU_TXN_ADD transactions. Save the + * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD + * transactions. */ -static void power_pmu_start_txn(struct pmu *pmu) +static void power_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ + + cpuhw->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); cpuhw->group_flag |= PERF_EVENT_TXN; cpuhw->n_txn_start = cpuhw->n_events; @@ -1604,6 +1615,14 @@ static void power_pmu_start_txn(struct pmu *pmu) static void power_pmu_cancel_txn(struct pmu *pmu) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + unsigned int txn_flags; + + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + txn_flags = cpuhw->txn_flags; + cpuhw->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); @@ -1621,7 +1640,15 @@ static int power_pmu_commit_txn(struct pmu *pmu) if (!ppmu) return -EAGAIN; + cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + if (cpuhw->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuhw->txn_flags = 0; + return 0; + } + n = cpuhw->n_events; if (check_excludes(cpuhw->event, cpuhw->flags, 0, n)) return -EAGAIN; @@ -1633,6 +1660,7 @@ static int power_pmu_commit_txn(struct pmu *pmu) cpuhw->event[i]->hw.config = cpuhw->events[i]; cpuhw->group_flag &= ~PERF_EVENT_TXN; + cpuhw->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 56fdad479115..19138be412d6 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -72,6 +72,7 @@ struct cpu_hw_events { atomic_t ctr_set[CPUMF_CTR_SET_MAX]; u64 state, tx_state; unsigned int flags; + unsigned int txn_flags; }; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .ctr_set = { @@ -82,6 +83,7 @@ static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { }, .state = 0, .flags = 0, + .txn_flags = 0, }; static int get_counter_set(u64 event) @@ -572,11 +574,21 @@ static void cpumf_pmu_del(struct perf_event *event, int flags) /* * Start group events scheduling transaction. * Set flags to perform a single test at commit time. + * + * We only support PERF_PMU_TXN_ADD transactions. Save the + * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD + * transactions. */ -static void cpumf_pmu_start_txn(struct pmu *pmu) +static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ + + cpuhw->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); cpuhw->flags |= PERF_EVENT_TXN; cpuhw->tx_state = cpuhw->state; @@ -589,8 +601,16 @@ static void cpumf_pmu_start_txn(struct pmu *pmu) */ static void cpumf_pmu_cancel_txn(struct pmu *pmu) { + unsigned int txn_flags; struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + txn_flags = cpuhw->txn_flags; + cpuhw->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + WARN_ON(cpuhw->tx_state != cpuhw->state); cpuhw->flags &= ~PERF_EVENT_TXN; @@ -607,6 +627,13 @@ static int cpumf_pmu_commit_txn(struct pmu *pmu) struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); u64 state; + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + if (cpuhw->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuhw->txn_flags = 0; + return 0; + } + /* check if the updated state can be scheduled */ state = cpuhw->state & ~((1 << CPUMF_LCCTL_ENABLE_SHIFT) - 1); state >>= CPUMF_LCCTL_ENABLE_SHIFT; @@ -614,6 +641,7 @@ static int cpumf_pmu_commit_txn(struct pmu *pmu) return -EPERM; cpuhw->flags &= ~PERF_EVENT_TXN; + cpuhw->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index e3f89c7e5062..2c0984d146ec 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -109,6 +109,7 @@ struct cpu_hw_events { int enabled; unsigned int group_flag; + unsigned int txn_flags; }; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; @@ -1494,10 +1495,16 @@ static int sparc_pmu_event_init(struct perf_event *event) * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time */ -static void sparc_pmu_start_txn(struct pmu *pmu) +static void sparc_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + WARN_ON_ONCE(cpuhw->txn_flags); /* txn already in flight */ + + cpuhw->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); cpuhw->group_flag |= PERF_EVENT_TXN; } @@ -1510,6 +1517,14 @@ static void sparc_pmu_start_txn(struct pmu *pmu) static void sparc_pmu_cancel_txn(struct pmu *pmu) { struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events); + unsigned int txn_flags; + + WARN_ON_ONCE(!cpuhw->txn_flags); /* no txn in flight */ + + txn_flags = cpuhw->txn_flags; + cpuhw->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); @@ -1528,6 +1543,13 @@ static int sparc_pmu_commit_txn(struct pmu *pmu) if (!sparc_pmu) return -EINVAL; + WARN_ON_ONCE(!cpuc->txn_flags); /* no txn in flight */ + + if (cpuc->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuc->txn_flags = 0; + return 0; + } + n = cpuc->n_events; if (check_excludes(cpuc->event, 0, n)) return -EINVAL; @@ -1535,6 +1557,7 @@ static int sparc_pmu_commit_txn(struct pmu *pmu) return -EAGAIN; cpuc->group_flag &= ~PERF_EVENT_TXN; + cpuc->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index 66dd3fe99b82..dc77ef470e0e 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1748,9 +1748,21 @@ static inline void x86_pmu_read(struct perf_event *event) * Start group events scheduling transaction * Set the flag to make pmu::enable() not perform the * schedulability test, it will be performed at commit time + * + * We only support PERF_PMU_TXN_ADD transactions. Save the + * transaction flags but otherwise ignore non-PERF_PMU_TXN_ADD + * transactions. */ -static void x86_pmu_start_txn(struct pmu *pmu) +static void x86_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) { + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + WARN_ON_ONCE(cpuc->txn_flags); /* txn already in flight */ + + cpuc->txn_flags = txn_flags; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); __this_cpu_or(cpu_hw_events.group_flag, PERF_EVENT_TXN); __this_cpu_write(cpu_hw_events.n_txn, 0); @@ -1763,6 +1775,16 @@ static void x86_pmu_start_txn(struct pmu *pmu) */ static void x86_pmu_cancel_txn(struct pmu *pmu) { + unsigned int txn_flags; + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + + WARN_ON_ONCE(!cpuc->txn_flags); /* no txn in flight */ + + txn_flags = cpuc->txn_flags; + cpuc->txn_flags = 0; + if (txn_flags & ~PERF_PMU_TXN_ADD) + return; + __this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN); /* * Truncate collected array by the number of events added in this @@ -1786,6 +1808,13 @@ static int x86_pmu_commit_txn(struct pmu *pmu) int assign[X86_PMC_IDX_MAX]; int n, ret; + WARN_ON_ONCE(!cpuc->txn_flags); /* no txn in flight */ + + if (cpuc->txn_flags & ~PERF_PMU_TXN_ADD) { + cpuc->txn_flags = 0; + return 0; + } + n = cpuc->n_events; if (!x86_pmu_initialized()) @@ -1802,6 +1831,7 @@ static int x86_pmu_commit_txn(struct pmu *pmu) memcpy(cpuc->assign, assign, n*sizeof(int)); cpuc->group_flag &= ~PERF_EVENT_TXN; + cpuc->txn_flags = 0; perf_pmu_enable(pmu); return 0; } diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index 5edf6d868fc1..c99c93b9e348 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -196,6 +196,7 @@ struct cpu_hw_events { int n_excl; /* the number of exclusive events */ unsigned int group_flag; + unsigned int txn_flags; int is_fake; /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index d61ee4459eee..ea3b5dd21a4c 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -201,6 +201,8 @@ struct perf_event; */ #define PERF_EVENT_TXN 0x1 +#define PERF_PMU_TXN_ADD 0x1 /* txn to add/schedule event on PMU */ + /** * pmu::capabilities flags */ @@ -331,20 +333,26 @@ struct pmu { * * Start the transaction, after this ->add() doesn't need to * do schedulability tests. + * + * Optional. */ - void (*start_txn) (struct pmu *pmu); /* optional */ + void (*start_txn) (struct pmu *pmu, unsigned int txn_flags); /* * If ->start_txn() disabled the ->add() schedulability test * then ->commit_txn() is required to perform one. On success * the transaction is closed. On error the transaction is kept * open until ->cancel_txn() is called. + * + * Optional. */ - int (*commit_txn) (struct pmu *pmu); /* optional */ + int (*commit_txn) (struct pmu *pmu); /* * Will cancel the transaction, assumes ->del() is called * for each successful ->add() during the transaction. + * + * Optional. */ - void (*cancel_txn) (struct pmu *pmu); /* optional */ + void (*cancel_txn) (struct pmu *pmu); /* * Will return the value for perf_event_mmap_page::index for this event, diff --git a/kernel/events/core.c b/kernel/events/core.c index 76e64be9bfb5..c80cee82959f 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -1914,7 +1914,7 @@ group_sched_in(struct perf_event *group_event, if (group_event->state == PERF_EVENT_STATE_OFF) return 0; - pmu->start_txn(pmu); + pmu->start_txn(pmu, PERF_PMU_TXN_ADD); if (event_sched_in(group_event, cpuctx, ctx)) { pmu->cancel_txn(pmu); @@ -7267,24 +7267,49 @@ static void perf_pmu_nop_void(struct pmu *pmu) { } +static void perf_pmu_nop_txn(struct pmu *pmu, unsigned int flags) +{ +} + static int perf_pmu_nop_int(struct pmu *pmu) { return 0; } -static void perf_pmu_start_txn(struct pmu *pmu) +DEFINE_PER_CPU(unsigned int, nop_txn_flags); + +static void perf_pmu_start_txn(struct pmu *pmu, unsigned int flags) { + __this_cpu_write(nop_txn_flags, flags); + + if (flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_disable(pmu); } static int perf_pmu_commit_txn(struct pmu *pmu) { + unsigned int flags = __this_cpu_read(nop_txn_flags); + + __this_cpu_write(nop_txn_flags, 0); + + if (flags & ~PERF_PMU_TXN_ADD) + return 0; + perf_pmu_enable(pmu); return 0; } static void perf_pmu_cancel_txn(struct pmu *pmu) { + unsigned int flags = __this_cpu_read(nop_txn_flags); + + __this_cpu_write(nop_txn_flags, 0); + + if (flags & ~PERF_PMU_TXN_ADD) + return; + perf_pmu_enable(pmu); } @@ -7523,7 +7548,7 @@ got_cpu_context: pmu->commit_txn = perf_pmu_commit_txn; pmu->cancel_txn = perf_pmu_cancel_txn; } else { - pmu->start_txn = perf_pmu_nop_void; + pmu->start_txn = perf_pmu_nop_txn; pmu->commit_txn = perf_pmu_nop_int; pmu->cancel_txn = perf_pmu_nop_void; } From 01add3eaf1b25e497b14ca210f3bfe5f5dd2b112 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:46 -0700 Subject: [PATCH 041/260] perf/core: Split perf_event_read() and perf_event_count() perf_event_read() does two things: - call the PMU to read/update the counter value, and - compute the total count of the event and its children Not all callers need both. perf_event_reset() for instance needs the first piece but doesn't need the second. Similarly, when we implement the ability to read a group of events using the transaction interface, we would need the two pieces done independently. Break up perf_event_read() and have it just read/update the counter and have the callers compute the total count if necessary. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-4-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index c80cee82959f..260bf8cfed51 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3275,7 +3275,7 @@ u64 perf_event_read_local(struct perf_event *event) return val; } -static u64 perf_event_read(struct perf_event *event) +static void perf_event_read(struct perf_event *event) { /* * If event is enabled and currently active on a CPU, update the @@ -3301,8 +3301,6 @@ static u64 perf_event_read(struct perf_event *event) update_event_times(event); raw_spin_unlock_irqrestore(&ctx->lock, flags); } - - return perf_event_count(event); } /* @@ -3818,14 +3816,18 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) *running = 0; mutex_lock(&event->child_mutex); - total += perf_event_read(event); + + perf_event_read(event); + total += perf_event_count(event); + *enabled += event->total_time_enabled + atomic64_read(&event->child_total_time_enabled); *running += event->total_time_running + atomic64_read(&event->child_total_time_running); list_for_each_entry(child, &event->child_list, child_list) { - total += perf_event_read(child); + perf_event_read(child); + total += perf_event_count(child); *enabled += child->total_time_enabled; *running += child->total_time_running; } @@ -3985,7 +3987,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) static void _perf_event_reset(struct perf_event *event) { - (void)perf_event_read(event); + perf_event_read(event); local64_set(&event->count, 0); perf_event_update_userpage(event); } From b15f495b4e9295cf21065d8569835a2f18cfe41b Mon Sep 17 00:00:00 2001 From: "Peter Zijlstra (Intel)" Date: Thu, 3 Sep 2015 20:07:47 -0700 Subject: [PATCH 042/260] perf/core: Rename perf_event_read_{one,group}, perf_read_hw In order to free up the perf_event_read_group() name: s/perf_event_read_\(one\|group\)/perf_read_\1/g s/perf_read_hw/__perf_read/g Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-5-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 260bf8cfed51..67b7dba4f0b5 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3742,7 +3742,7 @@ static void put_event(struct perf_event *event) * see the comment there. * * 2) there is a lock-inversion with mmap_sem through - * perf_event_read_group(), which takes faults while + * perf_read_group(), which takes faults while * holding ctx->mutex, however this is called after * the last filedesc died, so there is no possibility * to trigger the AB-BA case. @@ -3837,7 +3837,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) } EXPORT_SYMBOL_GPL(perf_event_read_value); -static int perf_event_read_group(struct perf_event *event, +static int perf_read_group(struct perf_event *event, u64 read_format, char __user *buf) { struct perf_event *leader = event->group_leader, *sub; @@ -3885,7 +3885,7 @@ static int perf_event_read_group(struct perf_event *event, return ret; } -static int perf_event_read_one(struct perf_event *event, +static int perf_read_one(struct perf_event *event, u64 read_format, char __user *buf) { u64 enabled, running; @@ -3923,7 +3923,7 @@ static bool is_event_hup(struct perf_event *event) * Read the performance event - simple non blocking version for now */ static ssize_t -perf_read_hw(struct perf_event *event, char __user *buf, size_t count) +__perf_read(struct perf_event *event, char __user *buf, size_t count) { u64 read_format = event->attr.read_format; int ret; @@ -3941,9 +3941,9 @@ perf_read_hw(struct perf_event *event, char __user *buf, size_t count) WARN_ON_ONCE(event->ctx->parent_ctx); if (read_format & PERF_FORMAT_GROUP) - ret = perf_event_read_group(event, read_format, buf); + ret = perf_read_group(event, read_format, buf); else - ret = perf_event_read_one(event, read_format, buf); + ret = perf_read_one(event, read_format, buf); return ret; } @@ -3956,7 +3956,7 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) int ret; ctx = perf_event_ctx_lock(event); - ret = perf_read_hw(event, buf, count); + ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); return ret; From 0492d4c5b8c4dc3a7591bf6fa0e35d117812cc85 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 3 Sep 2015 20:07:48 -0700 Subject: [PATCH 043/260] perf/core: Add group reads to perf_event_read() Enable perf_event_read() to update entire groups at once, this will be useful for read transactions. Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Sukadev Bhattiprolu Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/20150723080435.GE25159@twins.programming.kicks-ass.net Signed-off-by: Ingo Molnar --- kernel/events/core.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 67b7dba4f0b5..4d89866edd4e 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3184,12 +3184,18 @@ void perf_event_exec(void) rcu_read_unlock(); } +struct perf_read_data { + struct perf_event *event; + bool group; +}; + /* * Cross CPU call to read the hardware event */ static void __perf_event_read(void *info) { - struct perf_event *event = info; + struct perf_read_data *data = info; + struct perf_event *sub, *event = data->event; struct perf_event_context *ctx = event->ctx; struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); @@ -3208,9 +3214,21 @@ static void __perf_event_read(void *info) update_context_time(ctx); update_cgrp_time_from_event(event); } + update_event_times(event); if (event->state == PERF_EVENT_STATE_ACTIVE) event->pmu->read(event); + + if (!data->group) + goto unlock; + + list_for_each_entry(sub, &event->sibling_list, group_entry) { + update_event_times(sub); + if (sub->state == PERF_EVENT_STATE_ACTIVE) + sub->pmu->read(sub); + } + +unlock: raw_spin_unlock(&ctx->lock); } @@ -3275,15 +3293,19 @@ u64 perf_event_read_local(struct perf_event *event) return val; } -static void perf_event_read(struct perf_event *event) +static void perf_event_read(struct perf_event *event, bool group) { /* * If event is enabled and currently active on a CPU, update the * value in the event structure: */ if (event->state == PERF_EVENT_STATE_ACTIVE) { + struct perf_read_data data = { + .event = event, + .group = group, + }; smp_call_function_single(event->oncpu, - __perf_event_read, event, 1); + __perf_event_read, &data, 1); } else if (event->state == PERF_EVENT_STATE_INACTIVE) { struct perf_event_context *ctx = event->ctx; unsigned long flags; @@ -3298,7 +3320,10 @@ static void perf_event_read(struct perf_event *event) update_context_time(ctx); update_cgrp_time_from_event(event); } - update_event_times(event); + if (group) + update_group_times(event); + else + update_event_times(event); raw_spin_unlock_irqrestore(&ctx->lock, flags); } } @@ -3817,7 +3842,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) mutex_lock(&event->child_mutex); - perf_event_read(event); + perf_event_read(event, false); total += perf_event_count(event); *enabled += event->total_time_enabled + @@ -3826,7 +3851,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) atomic64_read(&event->child_total_time_running); list_for_each_entry(child, &event->child_list, child_list) { - perf_event_read(child); + perf_event_read(child, false); total += perf_event_count(child); *enabled += child->total_time_enabled; *running += child->total_time_running; @@ -3987,7 +4012,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) static void _perf_event_reset(struct perf_event *event) { - perf_event_read(event); + perf_event_read(event, false); local64_set(&event->count, 0); perf_event_update_userpage(event); } From fa8c269353d560b7c28119ad7617029f92e40b15 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 3 Sep 2015 20:07:49 -0700 Subject: [PATCH 044/260] perf/core: Invert perf_read_group() loops In order to enable the use of perf_event_read(.group = true), we need to invert the sibling-child loop nesting of perf_read_group(). Currently we iterate the child list for each sibling, this precludes using group reads. Flip things around so we iterate each group for each child. Signed-off-by: Peter Zijlstra (Intel) [ Made the patch compile and things. ] Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-7-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 91 ++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 4d89866edd4e..dd2a0b84c400 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3862,50 +3862,75 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) } EXPORT_SYMBOL_GPL(perf_event_read_value); -static int perf_read_group(struct perf_event *event, - u64 read_format, char __user *buf) +static void __perf_read_group_add(struct perf_event *leader, + u64 read_format, u64 *values) { - struct perf_event *leader = event->group_leader, *sub; - struct perf_event_context *ctx = leader->ctx; - int n = 0, size = 0, ret; - u64 count, enabled, running; - u64 values[5]; + struct perf_event *sub; + int n = 1; /* skip @nr */ - lockdep_assert_held(&ctx->mutex); + perf_event_read(leader, true); - count = perf_event_read_value(leader, &enabled, &running); + /* + * Since we co-schedule groups, {enabled,running} times of siblings + * will be identical to those of the leader, so we only publish one + * set. + */ + if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) { + values[n++] += leader->total_time_enabled + + atomic64_read(&leader->child_total_time_enabled); + } - values[n++] = 1 + leader->nr_siblings; - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - values[n++] = enabled; - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - values[n++] = running; - values[n++] = count; + if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) { + values[n++] += leader->total_time_running + + atomic64_read(&leader->child_total_time_running); + } + + /* + * Write {count,id} tuples for every sibling. + */ + values[n++] += perf_event_count(leader); if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(leader); - size = n * sizeof(u64); - - if (copy_to_user(buf, values, size)) - return -EFAULT; - - ret = size; - list_for_each_entry(sub, &leader->sibling_list, group_entry) { - n = 0; - - values[n++] = perf_event_read_value(sub, &enabled, &running); + values[n++] += perf_event_count(sub); if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(sub); - - size = n * sizeof(u64); - - if (copy_to_user(buf + ret, values, size)) { - return -EFAULT; - } - - ret += size; } +} + +static int perf_read_group(struct perf_event *event, + u64 read_format, char __user *buf) +{ + struct perf_event *leader = event->group_leader, *child; + struct perf_event_context *ctx = leader->ctx; + int ret = event->read_size; + u64 *values; + + lockdep_assert_held(&ctx->mutex); + + values = kzalloc(event->read_size, GFP_KERNEL); + if (!values) + return -ENOMEM; + + values[0] = 1 + leader->nr_siblings; + + /* + * By locking the child_mutex of the leader we effectively + * lock the child list of all siblings.. XXX explain how. + */ + mutex_lock(&leader->child_mutex); + + __perf_read_group_add(leader, read_format, values); + list_for_each_entry(child, &leader->child_list, child_list) + __perf_read_group_add(child, read_format, values); + + mutex_unlock(&leader->child_mutex); + + if (copy_to_user(buf, values, event->read_size)) + ret = -EFAULT; + + kfree(values); return ret; } From 7d88962e230c8342080e7e2fe9dd5be43dc13b79 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:50 -0700 Subject: [PATCH 045/260] perf/core: Add return value for perf_event_read() When we implement the ability to read several counters at once (using the PERF_PMU_TXN_READ transaction interface), perf_event_read() can fail when the 'group' parameter is true (eg: trying to read too many events at once). For now, have perf_event_read() return an integer. Ignore the return value when the 'group' parameter is false. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-8-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- kernel/events/core.c | 45 +++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index dd2a0b84c400..ade04dfab368 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3187,6 +3187,7 @@ void perf_event_exec(void) struct perf_read_data { struct perf_event *event; bool group; + int ret; }; /* @@ -3227,6 +3228,7 @@ static void __perf_event_read(void *info) if (sub->state == PERF_EVENT_STATE_ACTIVE) sub->pmu->read(sub); } + data->ret = 0; unlock: raw_spin_unlock(&ctx->lock); @@ -3293,8 +3295,10 @@ u64 perf_event_read_local(struct perf_event *event) return val; } -static void perf_event_read(struct perf_event *event, bool group) +static int perf_event_read(struct perf_event *event, bool group) { + int ret = 0; + /* * If event is enabled and currently active on a CPU, update the * value in the event structure: @@ -3303,9 +3307,11 @@ static void perf_event_read(struct perf_event *event, bool group) struct perf_read_data data = { .event = event, .group = group, + .ret = 0, }; smp_call_function_single(event->oncpu, __perf_event_read, &data, 1); + ret = data.ret; } else if (event->state == PERF_EVENT_STATE_INACTIVE) { struct perf_event_context *ctx = event->ctx; unsigned long flags; @@ -3326,6 +3332,8 @@ static void perf_event_read(struct perf_event *event, bool group) update_event_times(event); raw_spin_unlock_irqrestore(&ctx->lock, flags); } + + return ret; } /* @@ -3842,7 +3850,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) mutex_lock(&event->child_mutex); - perf_event_read(event, false); + (void)perf_event_read(event, false); total += perf_event_count(event); *enabled += event->total_time_enabled + @@ -3851,7 +3859,7 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) atomic64_read(&event->child_total_time_running); list_for_each_entry(child, &event->child_list, child_list) { - perf_event_read(child, false); + (void)perf_event_read(child, false); total += perf_event_count(child); *enabled += child->total_time_enabled; *running += child->total_time_running; @@ -3862,13 +3870,16 @@ u64 perf_event_read_value(struct perf_event *event, u64 *enabled, u64 *running) } EXPORT_SYMBOL_GPL(perf_event_read_value); -static void __perf_read_group_add(struct perf_event *leader, +static int __perf_read_group_add(struct perf_event *leader, u64 read_format, u64 *values) { struct perf_event *sub; int n = 1; /* skip @nr */ + int ret; - perf_event_read(leader, true); + ret = perf_event_read(leader, true); + if (ret) + return ret; /* * Since we co-schedule groups, {enabled,running} times of siblings @@ -3897,6 +3908,8 @@ static void __perf_read_group_add(struct perf_event *leader, if (read_format & PERF_FORMAT_ID) values[n++] = primary_event_id(sub); } + + return 0; } static int perf_read_group(struct perf_event *event, @@ -3904,7 +3917,7 @@ static int perf_read_group(struct perf_event *event, { struct perf_event *leader = event->group_leader, *child; struct perf_event_context *ctx = leader->ctx; - int ret = event->read_size; + int ret; u64 *values; lockdep_assert_held(&ctx->mutex); @@ -3921,17 +3934,27 @@ static int perf_read_group(struct perf_event *event, */ mutex_lock(&leader->child_mutex); - __perf_read_group_add(leader, read_format, values); - list_for_each_entry(child, &leader->child_list, child_list) - __perf_read_group_add(child, read_format, values); + ret = __perf_read_group_add(leader, read_format, values); + if (ret) + goto unlock; + + list_for_each_entry(child, &leader->child_list, child_list) { + ret = __perf_read_group_add(child, read_format, values); + if (ret) + goto unlock; + } mutex_unlock(&leader->child_mutex); + ret = event->read_size; if (copy_to_user(buf, values, event->read_size)) ret = -EFAULT; + goto out; +unlock: + mutex_unlock(&leader->child_mutex); +out: kfree(values); - return ret; } @@ -4037,7 +4060,7 @@ static unsigned int perf_poll(struct file *file, poll_table *wait) static void _perf_event_reset(struct perf_event *event) { - perf_event_read(event, false); + (void)perf_event_read(event, false); local64_set(&event->count, 0); perf_event_update_userpage(event); } From 4a00c16e552ea5e71756cd29cd2df7557ec9cac4 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:51 -0700 Subject: [PATCH 046/260] perf/core: Define PERF_PMU_TXN_READ interface Define a new PERF_PMU_TXN_READ interface to read a group of counters at once. pmu->start_txn() // Initialize before first event for each event in group pmu->read(event); // Queue each event to be read rc = pmu->commit_txn() // Read/update all queued counters Note that we use this interface with all PMUs. PMUs that implement this interface use the ->read() operation to _queue_ the counters to be read and use ->commit_txn() to actually read all the queued counters at once. PMUs that don't implement PERF_PMU_TXN_READ ignore ->start_txn() and ->commit_txn() and continue to read counters one at a time. Thanks to input from Peter Zijlstra. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-9-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 1 + kernel/events/core.c | 26 ++++++++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index ea3b5dd21a4c..b83cea932f74 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -202,6 +202,7 @@ struct perf_event; #define PERF_EVENT_TXN 0x1 #define PERF_PMU_TXN_ADD 0x1 /* txn to add/schedule event on PMU */ +#define PERF_PMU_TXN_READ 0x2 /* txn to read event group from PMU */ /** * pmu::capabilities flags diff --git a/kernel/events/core.c b/kernel/events/core.c index ade04dfab368..55b0f7cf2614 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -3199,6 +3199,7 @@ static void __perf_event_read(void *info) struct perf_event *sub, *event = data->event; struct perf_event_context *ctx = event->ctx; struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + struct pmu *pmu = event->pmu; /* * If this is a task context, we need to check whether it is @@ -3217,18 +3218,31 @@ static void __perf_event_read(void *info) } update_event_times(event); - if (event->state == PERF_EVENT_STATE_ACTIVE) - event->pmu->read(event); - - if (!data->group) + if (event->state != PERF_EVENT_STATE_ACTIVE) goto unlock; + if (!data->group) { + pmu->read(event); + data->ret = 0; + goto unlock; + } + + pmu->start_txn(pmu, PERF_PMU_TXN_READ); + + pmu->read(event); + list_for_each_entry(sub, &event->sibling_list, group_entry) { update_event_times(sub); - if (sub->state == PERF_EVENT_STATE_ACTIVE) + if (sub->state == PERF_EVENT_STATE_ACTIVE) { + /* + * Use sibling's PMU rather than @event's since + * sibling could be on different (eg: software) PMU. + */ sub->pmu->read(sub); + } } - data->ret = 0; + + data->ret = pmu->commit_txn(pmu); unlock: raw_spin_unlock(&ctx->lock); From 88a486132dffeb010d659e00361c4d114de09972 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:52 -0700 Subject: [PATCH 047/260] powerpc, perf/powerpc/hv-24x7: Use PMU_TXN_READ interface The 24x7 counters in Powerpc allow monitoring a large number of counters simultaneously. They also allow reading several counters in a single HCALL so we can get a more consistent snapshot of the system. Use the PMU's transaction interface to monitor and read several event counters at once. The idea is that users can group several 24x7 events into a single group of events. We use the following logic to submit the group of events to the PMU and read the values: pmu->start_txn() // Initialize before first event for each event in group pmu->read(event); // Queue each event to be read pmu->commit_txn() // Read/update all queuedcounters The ->commit_txn() also updates the event counts in the respective perf_event objects. The perf subsystem can then directly get the event counts from the perf_event and can avoid submitting a new ->read() request to the PMU. Thanks to input from Peter Zijlstra. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Acked-by: Michael Ellerman Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-10-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- arch/powerpc/perf/hv-24x7.c | 166 +++++++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index 527c8b98e97e..9f9dfda9ed2c 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -142,6 +142,15 @@ static struct attribute_group event_long_desc_group = { static struct kmem_cache *hv_page_cache; +DEFINE_PER_CPU(int, hv_24x7_txn_flags); +DEFINE_PER_CPU(int, hv_24x7_txn_err); + +struct hv_24x7_hw { + struct perf_event *events[255]; +}; + +DEFINE_PER_CPU(struct hv_24x7_hw, hv_24x7_hw); + /* * request_buffer and result_buffer are not required to be 4k aligned, * but are not allowed to cross any 4k boundary. Aligning them to 4k is @@ -1231,9 +1240,48 @@ static void update_event_count(struct perf_event *event, u64 now) static void h_24x7_event_read(struct perf_event *event) { u64 now; + struct hv_24x7_request_buffer *request_buffer; + struct hv_24x7_hw *h24x7hw; + int txn_flags; - now = h_24x7_get_value(event); - update_event_count(event, now); + txn_flags = __this_cpu_read(hv_24x7_txn_flags); + + /* + * If in a READ transaction, add this counter to the list of + * counters to read during the next HCALL (i.e commit_txn()). + * If not in a READ transaction, go ahead and make the HCALL + * to read this counter by itself. + */ + + if (txn_flags & PERF_PMU_TXN_READ) { + int i; + int ret; + + if (__this_cpu_read(hv_24x7_txn_err)) + return; + + request_buffer = (void *)get_cpu_var(hv_24x7_reqb); + + ret = add_event_to_24x7_request(event, request_buffer); + if (ret) { + __this_cpu_write(hv_24x7_txn_err, ret); + } else { + /* + * Assoicate the event with the HCALL request index, + * so ->commit_txn() can quickly find/update count. + */ + i = request_buffer->num_requests - 1; + + h24x7hw = &get_cpu_var(hv_24x7_hw); + h24x7hw->events[i] = event; + put_cpu_var(h24x7hw); + } + + put_cpu_var(hv_24x7_reqb); + } else { + now = h_24x7_get_value(event); + update_event_count(event, now); + } } static void h_24x7_event_start(struct perf_event *event, int flags) @@ -1255,6 +1303,117 @@ static int h_24x7_event_add(struct perf_event *event, int flags) return 0; } +/* + * 24x7 counters only support READ transactions. They are + * always counting and dont need/support ADD transactions. + * Cache the flags, but otherwise ignore transactions that + * are not PERF_PMU_TXN_READ. + */ +static void h_24x7_event_start_txn(struct pmu *pmu, unsigned int flags) +{ + struct hv_24x7_request_buffer *request_buffer; + struct hv_24x7_data_result_buffer *result_buffer; + + /* We should not be called if we are already in a txn */ + WARN_ON_ONCE(__this_cpu_read(hv_24x7_txn_flags)); + + __this_cpu_write(hv_24x7_txn_flags, flags); + if (flags & ~PERF_PMU_TXN_READ) + return; + + request_buffer = (void *)get_cpu_var(hv_24x7_reqb); + result_buffer = (void *)get_cpu_var(hv_24x7_resb); + + init_24x7_request(request_buffer, result_buffer); + + put_cpu_var(hv_24x7_resb); + put_cpu_var(hv_24x7_reqb); +} + +/* + * Clean up transaction state. + * + * NOTE: Ignore state of request and result buffers for now. + * We will initialize them during the next read/txn. + */ +static void reset_txn(void) +{ + __this_cpu_write(hv_24x7_txn_flags, 0); + __this_cpu_write(hv_24x7_txn_err, 0); +} + +/* + * 24x7 counters only support READ transactions. They are always counting + * and dont need/support ADD transactions. Clear ->txn_flags but otherwise + * ignore transactions that are not of type PERF_PMU_TXN_READ. + * + * For READ transactions, submit all pending 24x7 requests (i.e requests + * that were queued by h_24x7_event_read()), to the hypervisor and update + * the event counts. + */ +static int h_24x7_event_commit_txn(struct pmu *pmu) +{ + struct hv_24x7_request_buffer *request_buffer; + struct hv_24x7_data_result_buffer *result_buffer; + struct hv_24x7_result *resb; + struct perf_event *event; + u64 count; + int i, ret, txn_flags; + struct hv_24x7_hw *h24x7hw; + + txn_flags = __this_cpu_read(hv_24x7_txn_flags); + WARN_ON_ONCE(!txn_flags); + + ret = 0; + if (txn_flags & ~PERF_PMU_TXN_READ) + goto out; + + ret = __this_cpu_read(hv_24x7_txn_err); + if (ret) + goto out; + + request_buffer = (void *)get_cpu_var(hv_24x7_reqb); + result_buffer = (void *)get_cpu_var(hv_24x7_resb); + + ret = make_24x7_request(request_buffer, result_buffer); + if (ret) { + log_24x7_hcall(request_buffer, result_buffer, ret); + goto put_reqb; + } + + h24x7hw = &get_cpu_var(hv_24x7_hw); + + /* Update event counts from hcall */ + for (i = 0; i < request_buffer->num_requests; i++) { + resb = &result_buffer->results[i]; + count = be64_to_cpu(resb->elements[0].element_data[0]); + event = h24x7hw->events[i]; + h24x7hw->events[i] = NULL; + update_event_count(event, count); + } + + put_cpu_var(hv_24x7_hw); + +put_reqb: + put_cpu_var(hv_24x7_resb); + put_cpu_var(hv_24x7_reqb); +out: + reset_txn(); + return ret; +} + +/* + * 24x7 counters only support READ transactions. They are always counting + * and dont need/support ADD transactions. However, regardless of type + * of transaction, all we need to do is cleanup, so we don't have to check + * the type of transaction. + */ +static void h_24x7_event_cancel_txn(struct pmu *pmu) +{ + WARN_ON_ONCE(!__this_cpu_read(hv_24x7_txn_flags)); + reset_txn(); +} + static struct pmu h_24x7_pmu = { .task_ctx_nr = perf_invalid_context, @@ -1266,6 +1425,9 @@ static struct pmu h_24x7_pmu = { .start = h_24x7_event_start, .stop = h_24x7_event_stop, .read = h_24x7_event_read, + .start_txn = h_24x7_event_start_txn, + .commit_txn = h_24x7_event_commit_txn, + .cancel_txn = h_24x7_event_cancel_txn, }; static int hv_24x7_init(void) From 8f3e5684d3fbd91ead283916676fa3dac22615e5 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 3 Sep 2015 20:07:53 -0700 Subject: [PATCH 048/260] perf/core: Drop PERF_EVENT_TXN We currently use PERF_EVENT_TXN flag to determine if we are in the middle of a transaction. If in a transaction, we defer the schedulability checks from pmu->add() operation to the pmu->commit() operation. Now that we have "transaction types" (PERF_PMU_TXN_ADD, PERF_PMU_TXN_READ) we can use the type to determine if we are in a transaction and drop the PERF_EVENT_TXN flag. When PERF_EVENT_TXN is dropped, the cpuhw->group_flag on some architectures becomes unused, so drop that field as well. This is an extension of the Powerpc patch from Peter Zijlstra to s390, Sparc and x86 architectures. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Michael Ellerman Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441336073-22750-11-git-send-email-sukadev@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- arch/powerpc/perf/core-book3s.c | 6 +----- arch/s390/kernel/perf_cpum_cf.c | 5 +---- arch/sparc/kernel/perf_event.c | 6 +----- arch/x86/kernel/cpu/perf_event.c | 7 ++----- arch/x86/kernel/cpu/perf_event.h | 1 - include/linux/perf_event.h | 2 -- 6 files changed, 5 insertions(+), 22 deletions(-) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index c84074185c80..d1e65ce545b3 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -48,7 +48,6 @@ struct cpu_hw_events { unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES]; unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES]; - unsigned int group_flag; unsigned int txn_flags; int n_txn_start; @@ -1442,7 +1441,7 @@ static int power_pmu_add(struct perf_event *event, int ef_flags) * skip the schedulability test here, it will be performed * at commit time(->commit_txn) as a whole */ - if (cpuhw->group_flag & PERF_EVENT_TXN) + if (cpuhw->txn_flags & PERF_PMU_TXN_ADD) goto nocheck; if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1)) @@ -1603,7 +1602,6 @@ static void power_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) return; perf_pmu_disable(pmu); - cpuhw->group_flag |= PERF_EVENT_TXN; cpuhw->n_txn_start = cpuhw->n_events; } @@ -1624,7 +1622,6 @@ static void power_pmu_cancel_txn(struct pmu *pmu) if (txn_flags & ~PERF_PMU_TXN_ADD) return; - cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); } @@ -1659,7 +1656,6 @@ static int power_pmu_commit_txn(struct pmu *pmu) for (i = cpuhw->n_txn_start; i < n; ++i) cpuhw->event[i]->hw.config = cpuhw->events[i]; - cpuhw->group_flag &= ~PERF_EVENT_TXN; cpuhw->txn_flags = 0; perf_pmu_enable(pmu); return 0; diff --git a/arch/s390/kernel/perf_cpum_cf.c b/arch/s390/kernel/perf_cpum_cf.c index 19138be412d6..cb774ff6e749 100644 --- a/arch/s390/kernel/perf_cpum_cf.c +++ b/arch/s390/kernel/perf_cpum_cf.c @@ -536,7 +536,7 @@ static int cpumf_pmu_add(struct perf_event *event, int flags) * For group events transaction, the authorization check is * done in cpumf_pmu_commit_txn(). */ - if (!(cpuhw->flags & PERF_EVENT_TXN)) + if (!(cpuhw->txn_flags & PERF_PMU_TXN_ADD)) if (validate_ctr_auth(&event->hw)) return -EPERM; @@ -590,7 +590,6 @@ static void cpumf_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) return; perf_pmu_disable(pmu); - cpuhw->flags |= PERF_EVENT_TXN; cpuhw->tx_state = cpuhw->state; } @@ -613,7 +612,6 @@ static void cpumf_pmu_cancel_txn(struct pmu *pmu) WARN_ON(cpuhw->tx_state != cpuhw->state); - cpuhw->flags &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); } @@ -640,7 +638,6 @@ static int cpumf_pmu_commit_txn(struct pmu *pmu) if ((state & cpuhw->info.auth_ctl) != state) return -EPERM; - cpuhw->flags &= ~PERF_EVENT_TXN; cpuhw->txn_flags = 0; perf_pmu_enable(pmu); return 0; diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c index 2c0984d146ec..b0da5aedb336 100644 --- a/arch/sparc/kernel/perf_event.c +++ b/arch/sparc/kernel/perf_event.c @@ -108,7 +108,6 @@ struct cpu_hw_events { /* Enabled/disable state. */ int enabled; - unsigned int group_flag; unsigned int txn_flags; }; static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, }; @@ -1380,7 +1379,7 @@ static int sparc_pmu_add(struct perf_event *event, int ef_flags) * skip the schedulability test here, it will be performed * at commit time(->commit_txn) as a whole */ - if (cpuc->group_flag & PERF_EVENT_TXN) + if (cpuc->txn_flags & PERF_PMU_TXN_ADD) goto nocheck; if (check_excludes(cpuc->event, n0, 1)) @@ -1506,7 +1505,6 @@ static void sparc_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) return; perf_pmu_disable(pmu); - cpuhw->group_flag |= PERF_EVENT_TXN; } /* @@ -1526,7 +1524,6 @@ static void sparc_pmu_cancel_txn(struct pmu *pmu) if (txn_flags & ~PERF_PMU_TXN_ADD) return; - cpuhw->group_flag &= ~PERF_EVENT_TXN; perf_pmu_enable(pmu); } @@ -1556,7 +1553,6 @@ static int sparc_pmu_commit_txn(struct pmu *pmu) if (sparc_check_constraints(cpuc->event, cpuc->events, n)) return -EAGAIN; - cpuc->group_flag &= ~PERF_EVENT_TXN; cpuc->txn_flags = 0; perf_pmu_enable(pmu); return 0; diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index dc77ef470e0e..4562cf070c27 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1175,7 +1175,7 @@ static int x86_pmu_add(struct perf_event *event, int flags) * skip the schedulability test here, it will be performed * at commit time (->commit_txn) as a whole. */ - if (cpuc->group_flag & PERF_EVENT_TXN) + if (cpuc->txn_flags & PERF_PMU_TXN_ADD) goto done_collect; ret = x86_pmu.schedule_events(cpuc, n, assign); @@ -1326,7 +1326,7 @@ static void x86_pmu_del(struct perf_event *event, int flags) * XXX assumes any ->del() called during a TXN will only be on * an event added during that same TXN. */ - if (cpuc->group_flag & PERF_EVENT_TXN) + if (cpuc->txn_flags & PERF_PMU_TXN_ADD) return; /* @@ -1764,7 +1764,6 @@ static void x86_pmu_start_txn(struct pmu *pmu, unsigned int txn_flags) return; perf_pmu_disable(pmu); - __this_cpu_or(cpu_hw_events.group_flag, PERF_EVENT_TXN); __this_cpu_write(cpu_hw_events.n_txn, 0); } @@ -1785,7 +1784,6 @@ static void x86_pmu_cancel_txn(struct pmu *pmu) if (txn_flags & ~PERF_PMU_TXN_ADD) return; - __this_cpu_and(cpu_hw_events.group_flag, ~PERF_EVENT_TXN); /* * Truncate collected array by the number of events added in this * transaction. See x86_pmu_add() and x86_pmu_*_txn(). @@ -1830,7 +1828,6 @@ static int x86_pmu_commit_txn(struct pmu *pmu) */ memcpy(cpuc->assign, assign, n*sizeof(int)); - cpuc->group_flag &= ~PERF_EVENT_TXN; cpuc->txn_flags = 0; perf_pmu_enable(pmu); return 0; diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h index c99c93b9e348..953a0e4e3284 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -195,7 +195,6 @@ struct cpu_hw_events { int n_excl; /* the number of exclusive events */ - unsigned int group_flag; unsigned int txn_flags; int is_fake; diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index b83cea932f74..d841d33bcdc9 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -199,8 +199,6 @@ struct perf_event; /* * Common implementation detail of pmu::{start,commit,cancel}_txn */ -#define PERF_EVENT_TXN 0x1 - #define PERF_PMU_TXN_ADD 0x1 /* txn to add/schedule event on PMU */ #define PERF_PMU_TXN_READ 0x2 /* txn to read event group from PMU */ From 729a7ed103ae1b04a5c87a5855885e0973161da4 Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Wed, 2 Sep 2015 10:19:14 +0200 Subject: [PATCH 049/260] perf tests: Take into account address of each objdump line objdump output can contain repeated bytes. At the moment test reads all output sequentially, assuming each address is represented in output only once: ffffffff8164efb3 : ffffffff8164efb3: c1 5d 00 eb rcrl $0xeb,0x0(%rbp) ffffffff8164efb7: 00 4c 8b 5c add %cl,0x5c(%rbx,%rcx,4) ffffffff8164efb8 : ffffffff8164efb8: 4c 8b 5c 24 30 mov 0x30(%rsp),%r11 ffffffff8164efbd: 4c 8b 54 24 38 mov 0x38(%rsp),%r10 Store objdump output to buffer according to offset calculated from address on each line. Signed-off-by: Jan Stancek Cc: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/ad13289a55d6350f7717757c7e32c2d4286402bd.1441181335.git.jstancek@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 51 ++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 39c784a100a9..38ee90bc2228 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -33,20 +33,20 @@ static unsigned int hex(char c) return c - 'A' + 10; } -static void read_objdump_line(const char *line, size_t line_len, void **buf, - size_t *len) +static size_t read_objdump_line(const char *line, size_t line_len, void *buf, + size_t len) { const char *p; - size_t i; + size_t i, j = 0; /* Skip to a colon */ p = strchr(line, ':'); if (!p) - return; + return 0; i = p + 1 - line; /* Read bytes */ - while (*len) { + while (j < len) { char c1, c2; /* Skip spaces */ @@ -65,20 +65,26 @@ static void read_objdump_line(const char *line, size_t line_len, void **buf, if (i < line_len && line[i] && !isspace(line[i])) break; /* Store byte */ - *(unsigned char *)*buf = (hex(c1) << 4) | hex(c2); - *buf += 1; - *len -= 1; + *(unsigned char *)buf = (hex(c1) << 4) | hex(c2); + buf += 1; + j++; } + /* return number of successfully read bytes */ + return j; } -static int read_objdump_output(FILE *f, void **buf, size_t *len) +static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) { char *line = NULL; - size_t line_len; + size_t line_len, off_last = 0; ssize_t ret; int err = 0; + u64 addr; + + while (off_last < *len) { + size_t off, read_bytes, written_bytes; + unsigned char tmp[BUFSZ]; - while (1) { ret = getline(&line, &line_len, f); if (feof(f)) break; @@ -87,9 +93,28 @@ static int read_objdump_output(FILE *f, void **buf, size_t *len) err = -1; break; } - read_objdump_line(line, ret, buf, len); + + /* read objdump data into temporary buffer */ + read_bytes = read_objdump_line(line, ret, tmp, sizeof(tmp)); + if (!read_bytes) + continue; + + if (sscanf(line, "%"PRIx64, &addr) != 1) + continue; + + /* copy it from temporary buffer to 'buf' according + * to address on current objdump line */ + off = addr - start_addr; + if (off >= *len) + break; + written_bytes = MIN(read_bytes, *len - off); + memcpy(buf + off, tmp, written_bytes); + off_last = off + written_bytes; } + /* len returns number of bytes that could not be read */ + *len -= off_last; + free(line); return err; @@ -120,7 +145,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, return -1; } - ret = read_objdump_output(f, &buf, &len); + ret = read_objdump_output(f, buf, &len, addr); if (len) { pr_debug("objdump read too few bytes\n"); if (!ret) From 06f679c18fcf414cc8462938466f8361315f18cb Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Thu, 3 Sep 2015 13:23:32 +0200 Subject: [PATCH 050/260] perf tests: Make objdump disassemble zero blocks Add -z parameter to avoid skipping zero blocks: ffffffff816704fe : ffffffff816704fe: 7b 34 jnp ffffffff81670534 ... ffffffff81670501 : ffffffff81670501: 0f ba e2 03 bt $0x3,%edx ffffffff81670505: 73 11 jae ffffffff81670518 Signed-off-by: Jan Stancek Acked-by: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/130c6267fbdb9af506633a9efa06f3269ff5bd2c.1441275982.git.jstancek@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 38ee90bc2228..c409409d7765 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -128,7 +128,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, FILE *f; int ret; - fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s"; + fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s"; ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len, filename); if (ret <= 0 || (size_t)ret >= sizeof(cmd)) From edfdb7eab0fe5f98f2951598dc679b71bdb3e16b Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Wed, 2 Sep 2015 10:19:16 +0200 Subject: [PATCH 051/260] perf tests: Stop reading if objdump output crossed sections objdump output can span across multiple sections: Disassembly of section .text: 0000000000000008 : 8: 48 89 e5 mov %rsp,%rbp b: 53 push %rbx c: 8b 01 mov (%rcx),%eax 6b: 90 nop Disassembly of section .init.text: 0000000000000008 : 8: 00 00 add %al,(%rax) a: 00 00 add %al,(%rax) c: 48 89 e5 Stop further reading if an address starts going backwards, assuming we crossed sections. Signed-off-by: Jan Stancek Acked-by: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/9d1ea95e5f9884fdff1be6f761a2feabef37412c.1441181335.git.jstancek@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index c409409d7765..8145c67fb43a 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -79,7 +79,7 @@ static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) size_t line_len, off_last = 0; ssize_t ret; int err = 0; - u64 addr; + u64 addr, last_addr = start_addr; while (off_last < *len) { size_t off, read_bytes, written_bytes; @@ -101,6 +101,11 @@ static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr) if (sscanf(line, "%"PRIx64, &addr) != 1) continue; + if (addr < last_addr) { + pr_debug("addr going backwards, read beyond section?\n"); + break; + } + last_addr = addr; /* copy it from temporary buffer to 'buf' according * to address on current objdump line */ From fd405cf6cfddd300377bd5fd9b93d2ff66fbc32d Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Wed, 2 Sep 2015 10:19:17 +0200 Subject: [PATCH 052/260] perf tests: Print objdump/dso buffers if they don't match Signed-off-by: Jan Stancek Acked-by: Adrian Hunter Cc: Corey Ashford Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/d0f42f786bc0e965918e0f422df25617a12a4021.1441181335.git.jstancek@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 8145c67fb43a..2d21183bd661 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -162,6 +162,18 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, return ret; } +static void dump_buf(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + pr_debug("0x%02x ", buf[i]); + if (i % 16 == 15) + pr_debug("\n"); + } + pr_debug("\n"); +} + static int read_object_code(u64 addr, size_t len, u8 cpumode, struct thread *thread, struct state *state) { @@ -264,6 +276,10 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, /* The results should be identical */ if (memcmp(buf1, buf2, len)) { pr_debug("Bytes read differ from those read by objdump\n"); + pr_debug("buf1 (dso):\n"); + dump_buf(buf1, len); + pr_debug("buf2 (objdump):\n"); + dump_buf(buf2, len); return -1; } pr_debug("Bytes read match those read by objdump\n"); From 4f234f06d608635a1cff936131285a91af213b37 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:36 +0200 Subject: [PATCH 053/260] tools lib api fs: Make tracing_path_strerror_open message generic Making tracing_path__strerror_open_tp message generic by mentioning both debugfs/tracefs words in error message plus the tracing_path instead of debugfs_mountpoint. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-7-git-send-email-jolsa@kernel.org [ Add comment for the ENOENT case out of this patch discussion thread ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 3b3e4f5fc50b..1e0bb0da5e4f 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -90,33 +90,39 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) switch (err) { case ENOENT: - if (debugfs_configured()) { + /* + * We will get here if we can't find the tracepoint, but one of + * debugfs or tracefs is configured, which means you probably + * want some tracepoint which wasn't compiled in your kernel. + * - jirka + */ + if (debugfs_configured() || tracefs_configured()) { snprintf(buf, size, "Error:\tFile %s/%s not found.\n" "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", - debugfs_mountpoint, filename); + tracing_events_path, filename); break; } snprintf(buf, size, "%s", - "Error:\tUnable to find debugfs\n" - "Hint:\tWas your kernel compiled with debugfs support?\n" - "Hint:\tIs the debugfs filesystem mounted?\n" + "Error:\tUnable to find debugfs/tracefs\n" + "Hint:\tWas your kernel compiled with debugfs/tracefs support?\n" + "Hint:\tIs the debugfs/tracefs filesystem mounted?\n" "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); break; case EACCES: { - const char *mountpoint = debugfs_mountpoint; + const char *mountpoint = debugfs_find_mountpoint(); - if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { + if (!access(mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { const char *tracefs_mntpoint = tracefs_find_mountpoint(); if (tracefs_mntpoint) - mountpoint = tracefs_mntpoint; + mountpoint = tracefs_find_mountpoint(); } snprintf(buf, size, "Error:\tNo permissions to read %s/%s\n" "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", - debugfs_mountpoint, filename, mountpoint); + tracing_events_path, filename, mountpoint); } break; default: @@ -131,7 +137,7 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char * { char path[PATH_MAX]; - snprintf(path, PATH_MAX, "tracing/events/%s/%s", sys, name ?: "*"); + snprintf(path, PATH_MAX, "%s/%s", sys, name ?: "*"); return strerror_open(err, buf, size, path); } From 4605eab3487dc818b1f3cbee2cd139cca3564be7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:43 +0200 Subject: [PATCH 054/260] tools lib api fs: Replace debugfs/tracefs objects interface with fs.c Switching to the fs.c related filesystem framework. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-14-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 1 - tools/lib/api/fs/tracing_path.c | 15 +++++++-------- tools/perf/builtin-kvm.c | 1 - tools/perf/builtin-probe.c | 1 - tools/perf/tests/openat-syscall-all-cpus.c | 5 +++-- tools/perf/tests/openat-syscall.c | 5 +++-- tools/perf/tests/parse-events.c | 7 +++---- tools/perf/util/evsel.c | 2 +- tools/perf/util/probe-event.c | 5 ++--- tools/perf/util/probe-file.c | 7 +++---- tools/perf/util/util.h | 3 +-- 11 files changed, 23 insertions(+), 29 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 8afe08a99bc6..791509346178 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -11,7 +11,6 @@ #include #include -#include "debugfs.h" #include "fs.h" #define _STR(x) #x diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 1e0bb0da5e4f..38aca2dd1946 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -7,8 +7,7 @@ #include #include #include -#include "debugfs.h" -#include "tracefs.h" +#include "fs.h" #include "tracing_path.h" @@ -29,7 +28,7 @@ static const char *tracing_path_tracefs_mount(void) { const char *mnt; - mnt = tracefs_mount(NULL); + mnt = tracefs__mount(); if (!mnt) return NULL; @@ -42,7 +41,7 @@ static const char *tracing_path_debugfs_mount(void) { const char *mnt; - mnt = debugfs_mount(NULL); + mnt = debugfs__mount(); if (!mnt) return NULL; @@ -96,7 +95,7 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) * want some tracepoint which wasn't compiled in your kernel. * - jirka */ - if (debugfs_configured() || tracefs_configured()) { + if (debugfs__configured() || tracefs__configured()) { snprintf(buf, size, "Error:\tFile %s/%s not found.\n" "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", @@ -110,13 +109,13 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); break; case EACCES: { - const char *mountpoint = debugfs_find_mountpoint(); + const char *mountpoint = debugfs__mountpoint(); if (!access(mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { - const char *tracefs_mntpoint = tracefs_find_mountpoint(); + const char *tracefs_mntpoint = tracefs__mountpoint(); if (tracefs_mntpoint) - mountpoint = tracefs_find_mountpoint(); + mountpoint = tracefs__mountpoint(); } snprintf(buf, size, diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index fc1cffb1b7a2..dd94b4ca2213 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -13,7 +13,6 @@ #include "util/parse-options.h" #include "util/trace-event.h" #include "util/debug.h" -#include #include "util/tool.h" #include "util/stat.h" #include "util/top.h" diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index ee2c46d8353e..2bec9c1ef2a3 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -37,7 +37,6 @@ #include "util/strfilter.h" #include "util/symbol.h" #include "util/debug.h" -#include #include "util/parse-options.h" #include "util/probe-finder.h" #include "util/probe-event.h" diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index a572f87e9c8d..a38adf94c731 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -1,3 +1,4 @@ +#include #include "evsel.h" #include "tests.h" #include "thread_map.h" @@ -30,9 +31,9 @@ int test__openat_syscall_event_on_all_cpus(void) evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); if (evsel == NULL) { - if (tracefs_configured()) + if (tracefs__configured()) pr_debug("is tracefs mounted on /sys/kernel/tracing?\n"); - else if (debugfs_configured()) + else if (debugfs__configured()) pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); else pr_debug("Neither tracefs or debugfs is enabled in this kernel\n"); diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index c9a37bc6b33a..8048c7d7cd67 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -1,3 +1,4 @@ +#include #include "thread_map.h" #include "evsel.h" #include "debug.h" @@ -18,9 +19,9 @@ int test__openat_syscall_event(void) evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); if (evsel == NULL) { - if (tracefs_configured()) + if (tracefs__configured()) pr_debug("is tracefs mounted on /sys/kernel/tracing?\n"); - else if (debugfs_configured()) + else if (debugfs__configured()) pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); else pr_debug("Neither tracefs or debugfs is enabled in this kernel\n"); diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 9b6b2b6324a1..91fbfd593c4a 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -3,11 +3,10 @@ #include "evsel.h" #include "evlist.h" #include -#include -#include #include "tests.h" #include "debug.h" #include +#include #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) @@ -1268,12 +1267,12 @@ static int count_tracepoints(void) DIR *events_dir; int cnt = 0; - mountpoint = tracefs_find_mountpoint(); + mountpoint = tracefs__mountpoint(); if (mountpoint) { scnprintf(events_path, PATH_MAX, "%s/events", mountpoint); } else { - mountpoint = debugfs_find_mountpoint(); + mountpoint = debugfs__mountpoint(); scnprintf(events_path, PATH_MAX, "%s/tracing/events", mountpoint); } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c53f79123b37..771ade4d5966 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3da9e1c792fa..5964eccbe94d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -40,8 +40,7 @@ #include "color.h" #include "symbol.h" #include "thread.h" -#include -#include +#include #include "trace-event.h" /* For __maybe_unused */ #include "probe-event.h" #include "probe-finder.h" @@ -2054,7 +2053,7 @@ static void kprobe_blacklist__delete(struct list_head *blacklist) static int kprobe_blacklist__load(struct list_head *blacklist) { struct kprobe_blacklist_node *node; - const char *__debugfs = debugfs_find_mountpoint(); + const char *__debugfs = debugfs__mountpoint(); char buf[PATH_MAX], *p; FILE *fp; int ret; diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 38c0a62039cc..499c83ccd44b 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -22,8 +22,7 @@ #include "color.h" #include "symbol.h" #include "thread.h" -#include -#include +#include #include "probe-event.h" #include "probe-file.h" #include "session.h" @@ -77,11 +76,11 @@ static int open_probe_events(const char *trace_file, bool readwrite) const char *tracing_dir = ""; int ret; - __debugfs = tracefs_find_mountpoint(); + __debugfs = tracefs__mountpoint(); if (__debugfs == NULL) { tracing_dir = "tracing/"; - __debugfs = debugfs_find_mountpoint(); + __debugfs = debugfs__mountpoint(); if (__debugfs == NULL) return -ENOTSUP; } diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 495b99ccb588..3d5b01e8978f 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -74,8 +74,7 @@ #include #include #include -#include -#include +#include #include #include #include From 60a1133a5b39738671eff1e4d77bedc1ee3fa528 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:44 +0200 Subject: [PATCH 055/260] tools lib api fs: Remove debugfs, tracefs and findfs objects We have all the functionality in fs.c, let's remove unneeded objects. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-15-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/Build | 3 -- tools/lib/api/fs/debugfs.c | 77 ------------------------------------- tools/lib/api/fs/debugfs.h | 23 ----------- tools/lib/api/fs/findfs.c | 63 ------------------------------ tools/lib/api/fs/findfs.h | 23 ----------- tools/lib/api/fs/tracefs.c | 78 -------------------------------------- tools/lib/api/fs/tracefs.h | 21 ---------- 7 files changed, 288 deletions(-) delete mode 100644 tools/lib/api/fs/debugfs.c delete mode 100644 tools/lib/api/fs/debugfs.h delete mode 100644 tools/lib/api/fs/findfs.c delete mode 100644 tools/lib/api/fs/findfs.h delete mode 100644 tools/lib/api/fs/tracefs.c delete mode 100644 tools/lib/api/fs/tracefs.h diff --git a/tools/lib/api/fs/Build b/tools/lib/api/fs/Build index fa726f679b29..f4ed9629ae85 100644 --- a/tools/lib/api/fs/Build +++ b/tools/lib/api/fs/Build @@ -1,5 +1,2 @@ libapi-y += fs.o libapi-y += tracing_path.o -libapi-y += debugfs.o -libapi-y += findfs.o -libapi-y += tracefs.o diff --git a/tools/lib/api/fs/debugfs.c b/tools/lib/api/fs/debugfs.c deleted file mode 100644 index c707cfb32782..000000000000 --- a/tools/lib/api/fs/debugfs.c +++ /dev/null @@ -1,77 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "debugfs.h" -#include "tracefs.h" - -#ifndef DEBUGFS_DEFAULT_PATH -#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" -#endif - -char debugfs_mountpoint[PATH_MAX + 1] = DEBUGFS_DEFAULT_PATH; - -static const char * const debugfs_known_mountpoints[] = { - DEBUGFS_DEFAULT_PATH, - "/debug", - 0, -}; - -static bool debugfs_found; - -bool debugfs_configured(void) -{ - return debugfs_find_mountpoint() != NULL; -} - -/* find the path to the mounted debugfs */ -const char *debugfs_find_mountpoint(void) -{ - const char *ret; - - if (debugfs_found) - return (const char *)debugfs_mountpoint; - - ret = find_mountpoint("debugfs", (long) DEBUGFS_MAGIC, - debugfs_mountpoint, PATH_MAX + 1, - debugfs_known_mountpoints); - if (ret) - debugfs_found = true; - - return ret; -} - -/* mount the debugfs somewhere if it's not mounted */ -char *debugfs_mount(const char *mountpoint) -{ - /* see if it's already mounted */ - if (debugfs_find_mountpoint()) - goto out; - - /* if not mounted and no argument */ - if (mountpoint == NULL) { - /* see if environment variable set */ - mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); - /* if no environment variable, use default */ - if (mountpoint == NULL) - mountpoint = DEBUGFS_DEFAULT_PATH; - } - - if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) - return NULL; - - /* save the mountpoint */ - debugfs_found = true; - strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); -out: - return debugfs_mountpoint; -} diff --git a/tools/lib/api/fs/debugfs.h b/tools/lib/api/fs/debugfs.h deleted file mode 100644 index 455023698d2b..000000000000 --- a/tools/lib/api/fs/debugfs.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __API_DEBUGFS_H__ -#define __API_DEBUGFS_H__ - -#include "findfs.h" - -#ifndef DEBUGFS_MAGIC -#define DEBUGFS_MAGIC 0x64626720 -#endif - -#ifndef PERF_DEBUGFS_ENVIRONMENT -#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR" -#endif - -bool debugfs_configured(void); -const char *debugfs_find_mountpoint(void); -char *debugfs_mount(const char *mountpoint); - -extern char debugfs_mountpoint[]; - -int debugfs__strerror_open(int err, char *buf, size_t size, const char *filename); -int debugfs__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); - -#endif /* __API_DEBUGFS_H__ */ diff --git a/tools/lib/api/fs/findfs.c b/tools/lib/api/fs/findfs.c deleted file mode 100644 index 49946cb6d7af..000000000000 --- a/tools/lib/api/fs/findfs.c +++ /dev/null @@ -1,63 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "findfs.h" - -/* verify that a mountpoint is actually the type we want */ - -int valid_mountpoint(const char *mount, long magic) -{ - struct statfs st_fs; - - if (statfs(mount, &st_fs) < 0) - return -ENOENT; - else if ((long)st_fs.f_type != magic) - return -ENOENT; - - return 0; -} - -/* find the path to a mounted file system */ -const char *find_mountpoint(const char *fstype, long magic, - char *mountpoint, int len, - const char * const *known_mountpoints) -{ - const char * const *ptr; - char format[128]; - char type[100]; - FILE *fp; - - if (known_mountpoints) { - ptr = known_mountpoints; - while (*ptr) { - if (valid_mountpoint(*ptr, magic) == 0) { - strncpy(mountpoint, *ptr, len - 1); - mountpoint[len-1] = 0; - return mountpoint; - } - ptr++; - } - } - - /* give up and parse /proc/mounts */ - fp = fopen("/proc/mounts", "r"); - if (fp == NULL) - return NULL; - - snprintf(format, 128, "%%*s %%%ds %%99s %%*s %%*d %%*d\n", len); - - while (fscanf(fp, format, mountpoint, type) == 2) { - if (strcmp(type, fstype) == 0) - break; - } - fclose(fp); - - if (strcmp(type, fstype) != 0) - return NULL; - - return mountpoint; -} diff --git a/tools/lib/api/fs/findfs.h b/tools/lib/api/fs/findfs.h deleted file mode 100644 index b6f5d05acc42..000000000000 --- a/tools/lib/api/fs/findfs.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __API_FINDFS_H__ -#define __API_FINDFS_H__ - -#include - -#define _STR(x) #x -#define STR(x) _STR(x) - -/* - * On most systems would have given us this, but not on some systems - * (e.g. GNU/Hurd). - */ -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -const char *find_mountpoint(const char *fstype, long magic, - char *mountpoint, int len, - const char * const *known_mountpoints); - -int valid_mountpoint(const char *mount, long magic); - -#endif /* __API_FINDFS_H__ */ diff --git a/tools/lib/api/fs/tracefs.c b/tools/lib/api/fs/tracefs.c deleted file mode 100644 index e4aa9688b71e..000000000000 --- a/tools/lib/api/fs/tracefs.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tracefs.h" - -#ifndef TRACEFS_DEFAULT_PATH -#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" -#endif - -char tracefs_mountpoint[PATH_MAX + 1] = TRACEFS_DEFAULT_PATH; - -static const char * const tracefs_known_mountpoints[] = { - TRACEFS_DEFAULT_PATH, - "/sys/kernel/debug/tracing", - "/tracing", - "/trace", - 0, -}; - -static bool tracefs_found; - -bool tracefs_configured(void) -{ - return tracefs_find_mountpoint() != NULL; -} - -/* find the path to the mounted tracefs */ -const char *tracefs_find_mountpoint(void) -{ - const char *ret; - - if (tracefs_found) - return (const char *)tracefs_mountpoint; - - ret = find_mountpoint("tracefs", (long) TRACEFS_MAGIC, - tracefs_mountpoint, PATH_MAX + 1, - tracefs_known_mountpoints); - - if (ret) - tracefs_found = true; - - return ret; -} - -/* mount the tracefs somewhere if it's not mounted */ -char *tracefs_mount(const char *mountpoint) -{ - /* see if it's already mounted */ - if (tracefs_find_mountpoint()) - goto out; - - /* if not mounted and no argument */ - if (mountpoint == NULL) { - /* see if environment variable set */ - mountpoint = getenv(PERF_TRACEFS_ENVIRONMENT); - /* if no environment variable, use default */ - if (mountpoint == NULL) - mountpoint = TRACEFS_DEFAULT_PATH; - } - - if (mount(NULL, mountpoint, "tracefs", 0, NULL) < 0) - return NULL; - - /* save the mountpoint */ - tracefs_found = true; - strncpy(tracefs_mountpoint, mountpoint, sizeof(tracefs_mountpoint)); -out: - return tracefs_mountpoint; -} diff --git a/tools/lib/api/fs/tracefs.h b/tools/lib/api/fs/tracefs.h deleted file mode 100644 index da780ac49acb..000000000000 --- a/tools/lib/api/fs/tracefs.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __API_TRACEFS_H__ -#define __API_TRACEFS_H__ - -#include "findfs.h" - -#ifndef TRACEFS_MAGIC -#define TRACEFS_MAGIC 0x74726163 -#endif - -#ifndef PERF_TRACEFS_ENVIRONMENT -#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR" -#endif - -bool tracefs_configured(void); -const char *tracefs_find_mountpoint(void); -int tracefs_valid_mountpoint(const char *debugfs); -char *tracefs_mount(const char *mountpoint); - -extern char tracefs_mountpoint[]; - -#endif /* __API_DEBUGFS_H__ */ From fbf99625b88fd8808bf2b80efac453d63cae08e8 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:45 +0200 Subject: [PATCH 056/260] perf tools: Switch to tracing_path interface on appropriate places Using tracing_path interface on several places, that more or less copy the functionality of tracing_path interface. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Cc: Steven Rostedt Link: http://lkml.kernel.org/r/1441180605-24737-16-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/openat-syscall-all-cpus.c | 9 +++------ tools/perf/tests/openat-syscall.c | 11 ++++------- tools/perf/tests/parse-events.c | 16 ++-------------- tools/perf/util/probe-file.c | 14 ++------------ 4 files changed, 11 insertions(+), 39 deletions(-) diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index a38adf94c731..495d8126b722 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -15,6 +15,7 @@ int test__openat_syscall_event_on_all_cpus(void) cpu_set_t cpu_set; struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); char sbuf[STRERR_BUFSIZE]; + char errbuf[BUFSIZ]; if (threads == NULL) { pr_debug("thread_map__new\n"); @@ -31,12 +32,8 @@ int test__openat_syscall_event_on_all_cpus(void) evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); if (evsel == NULL) { - if (tracefs__configured()) - pr_debug("is tracefs mounted on /sys/kernel/tracing?\n"); - else if (debugfs__configured()) - pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); - else - pr_debug("Neither tracefs or debugfs is enabled in this kernel\n"); + tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); + pr_err("%s\n", errbuf); goto out_thread_map_delete; } diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 8048c7d7cd67..08ac9d94a050 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -1,4 +1,4 @@ -#include +#include #include "thread_map.h" #include "evsel.h" #include "debug.h" @@ -11,6 +11,7 @@ int test__openat_syscall_event(void) unsigned int nr_openat_calls = 111, i; struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); char sbuf[STRERR_BUFSIZE]; + char errbuf[BUFSIZ]; if (threads == NULL) { pr_debug("thread_map__new\n"); @@ -19,12 +20,8 @@ int test__openat_syscall_event(void) evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); if (evsel == NULL) { - if (tracefs__configured()) - pr_debug("is tracefs mounted on /sys/kernel/tracing?\n"); - else if (debugfs__configured()) - pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); - else - pr_debug("Neither tracefs or debugfs is enabled in this kernel\n"); + tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); + pr_err("%s\n", errbuf); goto out_thread_map_delete; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 91fbfd593c4a..3a2ebe666192 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1261,23 +1261,11 @@ test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist) static int count_tracepoints(void) { - char events_path[PATH_MAX]; struct dirent *events_ent; - const char *mountpoint; DIR *events_dir; int cnt = 0; - mountpoint = tracefs__mountpoint(); - if (mountpoint) { - scnprintf(events_path, PATH_MAX, "%s/events", - mountpoint); - } else { - mountpoint = debugfs__mountpoint(); - scnprintf(events_path, PATH_MAX, "%s/tracing/events", - mountpoint); - } - - events_dir = opendir(events_path); + events_dir = opendir(tracing_events_path); TEST_ASSERT_VAL("Can't open events dir", events_dir); @@ -1294,7 +1282,7 @@ static int count_tracepoints(void) continue; scnprintf(sys_path, PATH_MAX, "%s/%s", - events_path, events_ent->d_name); + tracing_events_path, events_ent->d_name); sys_dir = opendir(sys_path); TEST_ASSERT_VAL("Can't open sys dir", sys_dir); diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 499c83ccd44b..89dbeb92c68e 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -22,7 +22,7 @@ #include "color.h" #include "symbol.h" #include "thread.h" -#include +#include #include "probe-event.h" #include "probe-file.h" #include "session.h" @@ -72,21 +72,11 @@ static void print_both_open_warning(int kerr, int uerr) static int open_probe_events(const char *trace_file, bool readwrite) { char buf[PATH_MAX]; - const char *__debugfs; const char *tracing_dir = ""; int ret; - __debugfs = tracefs__mountpoint(); - if (__debugfs == NULL) { - tracing_dir = "tracing/"; - - __debugfs = debugfs__mountpoint(); - if (__debugfs == NULL) - return -ENOTSUP; - } - ret = e_snprintf(buf, PATH_MAX, "%s/%s%s", - __debugfs, tracing_dir, trace_file); + tracing_path, tracing_dir, trace_file); if (ret >= 0) { pr_debug("Opening %s write=%d\n", buf, readwrite); if (readwrite && !probe_event_dry_run) From c84974ed9fb672930929e0d20ea3c366635a54aa Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 4 Sep 2015 04:58:31 -0400 Subject: [PATCH 057/260] perf test: Add entry to test cpu topology This patch test cpu core_id and socket_id which are stored in perf_env. Commiter note: # perf test topo 40: Test topology in session: Ok # perf test -v topo 40: Test topology in session: --- start --- test child forked, pid 31767 templ file: /tmp/perf-test-VTZ1PL CPU 0, core 0, socket 0 CPU 1, core 1, socket 0 CPU 2, core 0, socket 0 CPU 3, core 1, socket 0 test child finished with 0 ---- end ---- Test topology in session: Ok # Based-on-a-patch-by: Jiri Olsa Signed-off-by: Kan Liang Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1441357111-64522-1-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/Build | 1 + tools/perf/tests/builtin-test.c | 4 ++ tools/perf/tests/tests.h | 1 + tools/perf/tests/topology.c | 115 ++++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+) create mode 100644 tools/perf/tests/topology.c diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 51fb737f82fc..c6f198ae65fb 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -33,6 +33,7 @@ perf-y += parse-no-sample-id-all.o perf-y += kmod-path.o perf-y += thread-map.o perf-y += llvm.o +perf-y += topology.o perf-$(CONFIG_X86) += perf-time-to-tsc.o ifdef CONFIG_AUXTRACE diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 69a77f71d594..98b0b2486100 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -186,6 +186,10 @@ static struct test { }, #endif #endif + { + .desc = "Test topology in session", + .func = test_session_topology, + }, { .func = NULL, }, diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 4e2c5458269a..0b3549672c16 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -64,6 +64,7 @@ int test__kmod_path__parse(void); int test__thread_map(void); int test__llvm(void); int test__insn_x86(void); +int test_session_topology(void); #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c new file mode 100644 index 000000000000..c3aff53a976a --- /dev/null +++ b/tools/perf/tests/topology.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include "tests.h" +#include "util.h" +#include "session.h" +#include "evlist.h" +#include "debug.h" + +#define TEMPL "/tmp/perf-test-XXXXXX" +#define DATA_SIZE 10 + +static int get_temp(char *path) +{ + int fd; + + strcpy(path, TEMPL); + + fd = mkstemp(path); + if (fd < 0) { + perror("mkstemp failed"); + return -1; + } + + close(fd); + return 0; +} + +static int session_write_header(char *path) +{ + struct perf_session *session; + struct perf_data_file file = { + .path = path, + .mode = PERF_DATA_MODE_WRITE, + }; + + session = perf_session__new(&file, false, NULL); + TEST_ASSERT_VAL("can't get session", session); + + session->evlist = perf_evlist__new_default(); + TEST_ASSERT_VAL("can't get evlist", session->evlist); + + perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); + perf_header__set_feat(&session->header, HEADER_NRCPUS); + + session->header.data_size += DATA_SIZE; + + TEST_ASSERT_VAL("failed to write header", + !perf_session__write_header(session, session->evlist, file.fd, true)); + + perf_session__delete(session); + + return 0; +} + +static int check_cpu_topology(char *path, struct cpu_map *map) +{ + struct perf_session *session; + struct perf_data_file file = { + .path = path, + .mode = PERF_DATA_MODE_READ, + }; + int i; + + session = perf_session__new(&file, false, NULL); + TEST_ASSERT_VAL("can't get session", session); + + for (i = 0; i < session->header.env.nr_cpus_online; i++) { + pr_debug("CPU %d, core %d, socket %d\n", i, + session->header.env.cpu[i].core_id, + session->header.env.cpu[i].socket_id); + } + + for (i = 0; i < map->nr; i++) { + TEST_ASSERT_VAL("Core ID doesn't match", + (session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i) & 0xffff))); + + TEST_ASSERT_VAL("Socket ID doesn't match", + (session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i))); + } + + perf_session__delete(session); + + return 0; +} + +int test_session_topology(void) +{ + char path[PATH_MAX]; + struct cpu_map *map; + int ret = -1; + + TEST_ASSERT_VAL("can't get templ file", !get_temp(path)); + + pr_debug("templ file: %s\n", path); + + if (session_write_header(path)) + goto free_path; + + map = cpu_map__new(NULL); + if (map == NULL) { + pr_debug("failed to get system cpumap\n"); + goto free_path; + } + + if (check_cpu_topology(path, map)) + goto free_map; + ret = 0; + +free_map: + cpu_map__put(map); +free_path: + unlink(path); + return ret; +} From e8210cefb7e1ec0760a6fe581ad0727a2dcf8dd1 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Sat, 5 Sep 2015 20:02:20 +0100 Subject: [PATCH 058/260] perf tests: Introduce iterator function for tests In preparation for introducing more arrays of tests, e.g. "arch tests" (architecture-specific tests), abstract the code to iterate over the list of tests into a helper function. This way, code that uses a 'struct test' doesn't need to worry about how the tests are grouped together and changes to the list of tests doesn't require changes to the code using it. Signed-off-by: Matt Fleming Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Kanaka Juvva Cc: Peter Zijlstra Cc: Vikas Shivappa Cc: Vince Weaver Link: http://lkml.kernel.org/r/1441479742-15402-2-git-send-email-matt@codeblueprint.co.uk Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/builtin-test.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 98b0b2486100..d9bf51dc8cf5 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -195,7 +195,7 @@ static struct test { }, }; -static bool perf_test__matches(int curr, int argc, const char *argv[]) +static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[]) { int i; @@ -212,7 +212,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[]) continue; } - if (strstr(tests[curr].desc, argv[i])) + if (strstr(test->desc, argv[i])) return true; } @@ -249,27 +249,28 @@ static int run_test(struct test *test) return err; } +#define for_each_test(t) for (t = &tests[0]; t->func; t++) + static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) { + struct test *t; int i = 0; int width = 0; - while (tests[i].func) { - int len = strlen(tests[i].desc); + for_each_test(t) { + int len = strlen(t->desc); if (width < len) width = len; - ++i; } - i = 0; - while (tests[i].func) { + for_each_test(t) { int curr = i++, err; - if (!perf_test__matches(curr, argc, argv)) + if (!perf_test__matches(t, curr, argc, argv)) continue; - pr_info("%2d: %-*s:", i, width, tests[curr].desc); + pr_info("%2d: %-*s:", i, width, t->desc); if (intlist__find(skiplist, i)) { color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); @@ -277,8 +278,8 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) } pr_debug("\n--- start ---\n"); - err = run_test(&tests[curr]); - pr_debug("---- end ----\n%s:", tests[curr].desc); + err = run_test(t); + pr_debug("---- end ----\n%s:", t->desc); switch (err) { case TEST_OK: @@ -299,15 +300,14 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) static int perf_test__list(int argc, const char **argv) { + struct test *t; int i = 0; - while (tests[i].func) { - int curr = i++; - - if (argc > 1 && !strstr(tests[curr].desc, argv[1])) + for_each_test(t) { + if (argc > 1 && !strstr(t->desc, argv[1])) continue; - pr_info("%2d: %s\n", i, tests[curr].desc); + pr_info("%2d: %s\n", ++i, t->desc); } return 0; From f0ce888c064e07c73a103822f2ad8e77649fd107 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Sep 2015 13:30:00 -0300 Subject: [PATCH 059/260] perf env: Move perf_env out of header.h and session.c into separate object Since it can be used separately from 'perf_session' and 'perf_header', move it to separate include file and object, next csets will try to move a perf_env__init() routine. Tested-by: Wang Nan Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ff2rw99tsn670y1b6gxbwdsi@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 1 + tools/perf/util/env.c | 19 +++++++++++++++++++ tools/perf/util/env.h | 37 +++++++++++++++++++++++++++++++++++++ tools/perf/util/header.h | 33 +-------------------------------- tools/perf/util/session.c | 20 +------------------- 5 files changed, 59 insertions(+), 51 deletions(-) create mode 100644 tools/perf/util/env.c create mode 100644 tools/perf/util/env.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 349bc96ca1fe..4bc7a9ab45b1 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -5,6 +5,7 @@ libperf-y += build-id.o libperf-y += config.o libperf-y += ctype.o libperf-y += db-export.o +libperf-y += env.o libperf-y += environment.o libperf-y += event.o libperf-y += evlist.o diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c new file mode 100644 index 000000000000..0b3e1b2e5263 --- /dev/null +++ b/tools/perf/util/env.c @@ -0,0 +1,19 @@ +#include "env.h" +#include "util.h" + +void perf_env__exit(struct perf_env *env) +{ + zfree(&env->hostname); + zfree(&env->os_release); + zfree(&env->version); + zfree(&env->arch); + zfree(&env->cpu_desc); + zfree(&env->cpuid); + zfree(&env->cmdline); + zfree(&env->cmdline_argv); + zfree(&env->sibling_cores); + zfree(&env->sibling_threads); + zfree(&env->numa_nodes); + zfree(&env->pmu_mappings); + zfree(&env->cpu); +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h new file mode 100644 index 000000000000..b1370516d99a --- /dev/null +++ b/tools/perf/util/env.h @@ -0,0 +1,37 @@ +#ifndef __PERF_ENV_H +#define __PERF_ENV_H + +struct cpu_topology_map { + int socket_id; + int core_id; +}; + +struct perf_env { + char *hostname; + char *os_release; + char *version; + char *arch; + int nr_cpus_online; + int nr_cpus_avail; + char *cpu_desc; + char *cpuid; + unsigned long long total_mem; + + int nr_cmdline; + int nr_sibling_cores; + int nr_sibling_threads; + int nr_numa_nodes; + int nr_pmu_mappings; + int nr_groups; + char *cmdline; + const char **cmdline_argv; + char *sibling_cores; + char *sibling_threads; + char *numa_nodes; + char *pmu_mappings; + struct cpu_topology_map *cpu; +}; + +void perf_env__exit(struct perf_env *env); + +#endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 975d803f46c8..05f27cb6b7e3 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -7,7 +7,7 @@ #include #include #include "event.h" - +#include "env.h" enum { HEADER_RESERVED = 0, /* always cleared */ @@ -66,37 +66,6 @@ struct perf_header; int perf_file_header__read(struct perf_file_header *header, struct perf_header *ph, int fd); -struct cpu_topology_map { - int socket_id; - int core_id; -}; - -struct perf_env { - char *hostname; - char *os_release; - char *version; - char *arch; - int nr_cpus_online; - int nr_cpus_avail; - char *cpu_desc; - char *cpuid; - unsigned long long total_mem; - - int nr_cmdline; - int nr_sibling_cores; - int nr_sibling_threads; - int nr_numa_nodes; - int nr_pmu_mappings; - int nr_groups; - char *cmdline; - const char **cmdline_argv; - char *sibling_cores; - char *sibling_threads; - char *numa_nodes; - char *pmu_mappings; - struct cpu_topology_map *cpu; -}; - struct perf_header { enum perf_header_version version; bool needs_swap; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 23fed17307ff..728cb115fbb8 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -170,31 +170,13 @@ static void perf_session__delete_threads(struct perf_session *session) machine__delete_threads(&session->machines.host); } -static void perf_session_env__exit(struct perf_env *env) -{ - zfree(&env->hostname); - zfree(&env->os_release); - zfree(&env->version); - zfree(&env->arch); - zfree(&env->cpu_desc); - zfree(&env->cpuid); - - zfree(&env->cmdline); - zfree(&env->cmdline_argv); - zfree(&env->sibling_cores); - zfree(&env->sibling_threads); - zfree(&env->numa_nodes); - zfree(&env->pmu_mappings); - zfree(&env->cpu); -} - void perf_session__delete(struct perf_session *session) { auxtrace__free(session); auxtrace_index__free(&session->auxtrace_index); perf_session__destroy_kernel_maps(session); perf_session__delete_threads(session); - perf_session_env__exit(&session->header.env); + perf_env__exit(&session->header.env); machines__exit(&session->machines); if (session->file) perf_data_file__close(session->file); From eebd0bfca5cb83f6e1ef0d872a16d45af0422114 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Sep 2015 15:52:20 -0300 Subject: [PATCH 060/260] perf env: Rename some leftovers from rename to perf_env In ce80d3bef9ff ("perf tools: Rename perf_session_env to perf_env") we forgot to rename a few functions to the "perf_env" prefix, do it now. Tested-by: Wang Nan Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-b3ui3z6ock89z1814pu2er98@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/common.c | 10 ++++------ tools/perf/arch/common.h | 4 ++-- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/ui/browsers/hists.c | 2 +- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index b00dfd92ea73..e83c8ce24303 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -128,9 +128,8 @@ static const char *normalize_arch(char *arch) return arch; } -static int perf_session_env__lookup_binutils_path(struct perf_env *env, - const char *name, - const char **path) +static int perf_env__lookup_binutils_path(struct perf_env *env, + const char *name, const char **path) { int idx; const char *arch, *cross_env; @@ -206,7 +205,7 @@ out_error: return -1; } -int perf_session_env__lookup_objdump(struct perf_env *env) +int perf_env__lookup_objdump(struct perf_env *env) { /* * For live mode, env->arch will be NULL and we can use @@ -215,6 +214,5 @@ int perf_session_env__lookup_objdump(struct perf_env *env) if (env->arch == NULL) return 0; - return perf_session_env__lookup_binutils_path(env, "objdump", - &objdump_path); + return perf_env__lookup_binutils_path(env, "objdump", &objdump_path); } diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 20176df69fc8..7529cfb143ce 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -1,10 +1,10 @@ #ifndef ARCH_PERF_COMMON_H #define ARCH_PERF_COMMON_H -#include "../util/session.h" +#include "../util/env.h" extern const char *objdump_path; -int perf_session_env__lookup_objdump(struct perf_env *env); +int perf_env__lookup_objdump(struct perf_env *env); #endif /* ARCH_PERF_COMMON_H */ diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8edc205ff9a7..2bf9b3fd9e61 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -211,7 +211,7 @@ static int __cmd_annotate(struct perf_annotate *ann) } if (!objdump_path) { - ret = perf_session_env__lookup_objdump(&session->header.env); + ret = perf_env__lookup_objdump(&session->header.env); if (ret) goto out; } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 8c465c83aabf..e5ca6848f01d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -952,7 +952,7 @@ static int __cmd_top(struct perf_top *top) machines__set_symbol_filter(&top->session->machines, symbol_filter); if (!objdump_path) { - ret = perf_session_env__lookup_objdump(&top->session->header.env); + ret = perf_env__lookup_objdump(&top->session->header.env); if (ret) goto out_delete; } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index cf86f2d3a5e7..17d6c6dbb27f 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1437,7 +1437,7 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) struct hist_entry *he; int err; - if (!objdump_path && perf_session_env__lookup_objdump(browser->env)) + if (!objdump_path && perf_env__lookup_objdump(browser->env)) return 0; notes = symbol__annotation(act->ms.sym); From b699869285c4f6949f281ea57ac35ea9b9c6f467 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Sep 2015 16:58:20 -0300 Subject: [PATCH 061/260] perf env: Adopt perf_header__set_cmdline Move this from two globals to perf_env global, that eventually will be just perf_header->env or something else, to ease the refactoring series, leave it as a global and go on reading more of its fields, not as part of the header writing process but as a perf_env init one that will be used for perf.data-less situations. Tested-by: Wang Nan Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2j78tdf8zn1ci0y6ji15bifj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/env.c | 39 +++++++++++++++++++++++++++++ tools/perf/util/env.h | 4 +++ tools/perf/util/header.c | 44 ++++----------------------------- tools/perf/util/parse-options.c | 2 +- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 0b3e1b2e5263..ca1e33a2203e 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -1,6 +1,8 @@ #include "env.h" #include "util.h" +struct perf_env perf_env; + void perf_env__exit(struct perf_env *env) { zfree(&env->hostname); @@ -17,3 +19,40 @@ void perf_env__exit(struct perf_env *env) zfree(&env->pmu_mappings); zfree(&env->cpu); } + +int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]) +{ + int i; + + /* + * If env->cmdline_argv has already been set, do not override it. This allows + * a command to set the cmdline, parse args and then call another + * builtin function that implements a command -- e.g, cmd_kvm calling + * cmd_record. + */ + if (env->cmdline_argv != NULL) + return 0; + + /* do not include NULL termination */ + env->cmdline_argv = calloc(argc, sizeof(char *)); + if (env->cmdline_argv == NULL) + goto out_enomem; + + /* + * Must copy argv contents because it gets moved around during option + * parsing: + */ + for (i = 0; i < argc ; i++) { + env->cmdline_argv[i] = argv[i]; + if (env->cmdline_argv[i] == NULL) + goto out_free; + } + + env->nr_cmdline = argc; + + return 0; +out_free: + zfree(&env->cmdline_argv); +out_enomem: + return -ENOMEM; +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index b1370516d99a..70124d9a1624 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -32,6 +32,10 @@ struct perf_env { struct cpu_topology_map *cpu; }; +extern struct perf_env perf_env; + void perf_env__exit(struct perf_env *env); +int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); + #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 8fd7b7de1acd..151b8310ac70 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -24,9 +24,6 @@ #include "build-id.h" #include "data.h" -static u32 header_argc; -static const char **header_argv; - /* * magic2 = "PERFILE2" * must be a numerical value to let the endianness @@ -138,37 +135,6 @@ static char *do_read_string(int fd, struct perf_header *ph) return NULL; } -int -perf_header__set_cmdline(int argc, const char **argv) -{ - int i; - - /* - * If header_argv has already been set, do not override it. - * This allows a command to set the cmdline, parse args and - * then call another builtin function that implements a - * command -- e.g, cmd_kvm calling cmd_record. - */ - if (header_argv) - return 0; - - header_argc = (u32)argc; - - /* do not include NULL termination */ - header_argv = calloc(argc, sizeof(char *)); - if (!header_argv) - return -ENOMEM; - - /* - * must copy argv contents because it gets moved - * around during option parsing - */ - for (i = 0; i < argc ; i++) - header_argv[i] = argv[i]; - - return 0; -} - static int write_tracing_data(int fd, struct perf_header *h __maybe_unused, struct perf_evlist *evlist) { @@ -405,8 +371,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, { char buf[MAXPATHLEN]; char proc[32]; - u32 i, n; - int ret; + u32 n; + int i, ret; /* * actual atual path to perf binary @@ -420,7 +386,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, buf[ret] = '\0'; /* account for binary path */ - n = header_argc + 1; + n = perf_env.nr_cmdline + 1; ret = do_write(fd, &n, sizeof(n)); if (ret < 0) @@ -430,8 +396,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, if (ret < 0) return ret; - for (i = 0 ; i < header_argc; i++) { - ret = do_write_string(fd, header_argv[i]); + for (i = 0 ; i < perf_env.nr_cmdline; i++) { + ret = do_write_string(fd, perf_env.cmdline_argv[i]); if (ret < 0) return ret; } diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 01626be2a8eb..9a38b05f0273 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -496,7 +496,7 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o { struct parse_opt_ctx_t ctx; - perf_header__set_cmdline(argc, argv); + perf_env__set_cmdline(&perf_env, argc, argv); /* build usage string if it's not provided */ if (subcommands && !usagestr[0]) { From a4978eca684a3b471f3da862f427e419283e93a3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Sep 2015 12:14:00 -0300 Subject: [PATCH 062/260] perf hists browser: Fixup the "cpu" column width calculation Since we were not setting it to at least 3 chars ('CPU'), it was being reset to zero when recalculating the columns width when refreshing the screen, in 'perf top'. Fix it. Tested-by: Wang Nan Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-iqcdnkkqm6sew06x01fbijmy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 08b6cd945f1e..48d5906a3f9f 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -144,6 +144,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); } + hists__new_col_len(hists, HISTC_CPU, 3); hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); hists__new_col_len(hists, HISTC_MEM_TLB, 22); hists__new_col_len(hists, HISTC_MEM_SNOOP, 12); From 8168caded331a19302593a591f070136cb3a31c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Sep 2015 12:38:17 -0300 Subject: [PATCH 063/260] perf evsel: Remove forward declaration of 'struct perf_evlist' We have no use for it in evsel.h. Tested-by: Wang Nan Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-um03yjrgyi3bj1hzqiqs4dsu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.h | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 298e6bbca200..f164a149da82 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -129,7 +129,6 @@ union u64_swap { struct cpu_map; struct target; struct thread_map; -struct perf_evlist; struct record_opts; static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) From b60114067c656be572f0ca4030c3a2c560e7255c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 7 Sep 2015 10:38:04 +0200 Subject: [PATCH 064/260] perf tools: Add tools/include into tags directories Adding tools/include into tags directories, to have include definitions reachable via tags/cscope. Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Link: http://lkml.kernel.org/r/1441615087-13886-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index d9863cb96f59..6c5c699002cb 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -459,7 +459,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html $(DOC_TARGETS): $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) -TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol +TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include TAG_FILES= ../../include/uapi/linux/perf_event.h TAGS: From e0838e029f4f6f271d6172b18f5473558ebdea1b Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Thu, 10 Sep 2015 11:03:05 -0300 Subject: [PATCH 065/260] perf env: Read msr pmu type from header Get msr pmu type when processing pmu_mappings Signed-off-by: Kan Liang Acked-by: Jiri Olsa Link: http://lkml.kernel.org/n/tip-3ngei63gepydwxhvytl2wx89@git.kernel.org [ Fixed it up wrt moving perf_env from header.h ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/env.h | 1 + tools/perf/util/header.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 70124d9a1624..d0d1a9681531 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -16,6 +16,7 @@ struct perf_env { char *cpu_desc; char *cpuid; unsigned long long total_mem; + unsigned int msr_pmu_type; int nr_cmdline; int nr_sibling_cores; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 151b8310ac70..f307b17aa45e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1787,6 +1787,9 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused /* include a NULL character at the end */ strbuf_add(&sb, "", 1); + if (!strcmp(name, "msr")) + ph->env.msr_pmu_type = type; + free(name); pmu_num--; } From 2d729f6a8ac3edbf68de7239fab96c9736946af5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 10 Sep 2015 11:58:50 -0300 Subject: [PATCH 066/260] tools lib api fs: Introduce sysfs__read_{int,ull}() To read either an int or an unsigned long long value from the given file. E.g.: $ cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq 3200000 $ ./sysfs__read_ull devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq=3200000 $ Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-4a12m4d5k8m4qgc1vguocvei@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 45 +++++++++++++++++++++++++++++++++++++++++++ tools/lib/api/fs/fs.h | 4 ++++ 2 files changed, 49 insertions(+) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 791509346178..732dbef588b0 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -281,6 +282,50 @@ int filename__read_int(const char *filename, int *value) return err; } +int filename__read_ull(const char *filename, unsigned long long *value) +{ + char line[64]; + int fd = open(filename, O_RDONLY), err = -1; + + if (fd < 0) + return -1; + + if (read(fd, line, sizeof(line)) > 0) { + *value = strtoull(line, NULL, 10); + if (*value != ULLONG_MAX) + err = 0; + } + + close(fd); + return err; +} + +int sysfs__read_ull(const char *entry, unsigned long long *value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_ull(path, value); +} + +int sysfs__read_int(const char *entry, int *value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_int(path, value); +} + int sysctl__read_int(const char *sysctl, int *value) { char path[PATH_MAX]; diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index f654bcb99d1e..d024a7f682f6 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -25,5 +25,9 @@ FS(tracefs) int filename__read_int(const char *filename, int *value); +int filename__read_ull(const char *filename, unsigned long long *value); + int sysctl__read_int(const char *sysctl, int *value); +int sysfs__read_int(const char *entry, int *value); +int sysfs__read_ull(const char *entry, unsigned long long *value); #endif /* __API_FS__ */ From 09f6acf2eacad3a0f9a4b9f77e0b021f0cb45780 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 10 Sep 2015 12:20:14 -0300 Subject: [PATCH 067/260] tools lib api cpu: Introduce cpu.[ch] to obtain cpu related information E.g.: $ ./cpu__get_max_freq 3200000 It does that, as Kan's patch does, by looking at these files: $ cat /sys/devices/system/cpu/online 0-3 $ ./sysfs__read_ull devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq=3200000 $ I.e. find out the first online CPU, then read its cpufreq info. But do it in tools/lib/api/, so that other tools/ living code can use it, not just perf. Based-on-a-patch-by: Kan Liang Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-915v4cvxqplaub8qco66b9mv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/Build | 1 + tools/lib/api/cpu.c | 18 ++++++++++++++++++ tools/lib/api/cpu.h | 6 ++++++ 3 files changed, 25 insertions(+) create mode 100644 tools/lib/api/cpu.c create mode 100644 tools/lib/api/cpu.h diff --git a/tools/lib/api/Build b/tools/lib/api/Build index 3653965cf481..e8b8a23b9bf4 100644 --- a/tools/lib/api/Build +++ b/tools/lib/api/Build @@ -1,2 +1,3 @@ libapi-y += fd/ libapi-y += fs/ +libapi-y += cpu.o diff --git a/tools/lib/api/cpu.c b/tools/lib/api/cpu.c new file mode 100644 index 000000000000..8c6489356e3a --- /dev/null +++ b/tools/lib/api/cpu.c @@ -0,0 +1,18 @@ +#include + +#include "cpu.h" +#include "fs/fs.h" + +int cpu__get_max_freq(unsigned long long *freq) +{ + char entry[PATH_MAX]; + int cpu; + + if (sysfs__read_int("devices/system/cpu/online", &cpu) < 0) + return -1; + + snprintf(entry, sizeof(entry), + "devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu); + + return sysfs__read_ull(entry, freq); +} diff --git a/tools/lib/api/cpu.h b/tools/lib/api/cpu.h new file mode 100644 index 000000000000..81e9d3955961 --- /dev/null +++ b/tools/lib/api/cpu.h @@ -0,0 +1,6 @@ +#ifndef __API_CPU__ +#define __API_CPU__ + +int cpu__get_max_freq(unsigned long long *freq); + +#endif /* __API_CPU__ */ From 5d8cf721cb13be92e96f22846e5bcd31040d4d0b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Sep 2015 10:49:45 -0300 Subject: [PATCH 068/260] perf cpu_map: Use sysfs__read_int in get_{core,socket}_id() We have the tools/lib/ sysfs__read_int() for that, avoid code duplication. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-fqg6vt5ku72pbf54ljg6tmoy@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 46 +++++++++------------------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index a05d76ab18d8..c51c29fd0732 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -225,28 +225,20 @@ void cpu_map__put(struct cpu_map *map) cpu_map__delete(map); } -int cpu_map__get_socket_id(int cpu) +static int cpu__get_topology_int(int cpu, const char *name, int *value) { - FILE *fp; - const char *mnt; char path[PATH_MAX]; - int socket_id, ret; - - mnt = sysfs__mountpoint(); - if (!mnt) - return -1; snprintf(path, PATH_MAX, - "%s/devices/system/cpu/cpu%d/topology/physical_package_id", - mnt, cpu); + "devices/system/cpu/cpu%d/topology/%s", cpu, name); - fp = fopen(path, "r"); - if (!fp) - return -1; - ret = fscanf(fp, "%d", &socket_id); - fclose(fp); + return sysfs__read_int(path, value); +} - return ret == 1 ? socket_id : -1; +int cpu_map__get_socket_id(int cpu) +{ + int value, ret = cpu__get_topology_int(cpu, "physical_package_id", &value); + return ret ?: value; } int cpu_map__get_socket(struct cpu_map *map, int idx) @@ -299,26 +291,8 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, int cpu_map__get_core_id(int cpu) { - FILE *fp; - const char *mnt; - char path[PATH_MAX]; - int core_id, ret; - - mnt = sysfs__mountpoint(); - if (!mnt) - return -1; - - snprintf(path, PATH_MAX, - "%s/devices/system/cpu/cpu%d/topology/core_id", - mnt, cpu); - - fp = fopen(path, "r"); - if (!fp) - return -1; - ret = fscanf(fp, "%d", &core_id); - fclose(fp); - - return ret == 1 ? core_id : -1; + int value, ret = cpu__get_topology_int(cpu, "core_id", &value); + return ret ?: value; } int cpu_map__get_core(struct cpu_map *map, int idx) From aa36ddd7afbb0a3db216c1391e28cd6d80ed1706 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Sep 2015 10:37:01 -0300 Subject: [PATCH 069/260] perf env: Introduce read_cpu_topology_map() method Out of the code to write the cpu topology map in the perf.data file header. Now if one needs the CPU topology map for the running machine, one needs to call perf_env__read_cpu_topology_map(perf_env) and the info will be stored in perf_env.cpu. For now we're using a global perf_env variable, that will have its contents freed after we run a builtin. v2: Check perf_env__read_cpu_topology_map() return in write_cpu_topology() (Kan Liang) Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/1441828225-667-5-git-send-email-acme@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 2 ++ tools/perf/util/env.c | 28 ++++++++++++++++++++++++++++ tools/perf/util/env.h | 2 ++ tools/perf/util/header.c | 28 ++++++++++++---------------- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index f2fc019b3671..1fded922bcc8 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -8,6 +8,7 @@ */ #include "builtin.h" +#include "util/env.h" #include "util/exec_cmd.h" #include "util/cache.h" #include "util/quote.h" @@ -369,6 +370,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) status = p->fn(argc, argv, prefix); exit_browser(status); + perf_env__exit(&perf_env); if (status) return status & 0xff; diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index ca1e33a2203e..6af4f7c36820 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -1,3 +1,4 @@ +#include "cpumap.h" #include "env.h" #include "util.h" @@ -56,3 +57,30 @@ out_free: out_enomem: return -ENOMEM; } + +int perf_env__read_cpu_topology_map(struct perf_env *env) +{ + int cpu, nr_cpus; + + if (env->cpu != NULL) + return 0; + + if (env->nr_cpus_avail == 0) + env->nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF); + + nr_cpus = env->nr_cpus_avail; + if (nr_cpus == -1) + return -EINVAL; + + env->cpu = calloc(nr_cpus, sizeof(env->cpu[0])); + if (env->cpu == NULL) + return -ENOMEM; + + for (cpu = 0; cpu < nr_cpus; ++cpu) { + env->cpu[cpu].core_id = cpu_map__get_core_id(cpu); + env->cpu[cpu].socket_id = cpu_map__get_socket_id(cpu); + } + + env->nr_cpus_avail = nr_cpus; + return 0; +} diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index d0d1a9681531..0132b9557c02 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -39,4 +39,6 @@ void perf_env__exit(struct perf_env *env); int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); +int perf_env__read_cpu_topology_map(struct perf_env *env); + #endif /* __PERF_ENV_H */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index f307b17aa45e..46ec6c5ca47f 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -415,8 +415,6 @@ struct cpu_topo { u32 thread_sib; char **core_siblings; char **thread_siblings; - int *core_id; - int *phy_pkg_id; }; static int build_cpu_topo(struct cpu_topo *tp, int cpu) @@ -479,9 +477,6 @@ try_threads: } ret = 0; done: - tp->core_id[cpu] = cpu_map__get_core_id(cpu); - tp->phy_pkg_id[cpu] = cpu_map__get_socket_id(cpu); - if(fp) fclose(fp); free(buf); @@ -509,7 +504,7 @@ static struct cpu_topo *build_cpu_topology(void) struct cpu_topo *tp; void *addr; u32 nr, i; - size_t sz, sz_id; + size_t sz; long ncpus; int ret = -1; @@ -520,9 +515,8 @@ static struct cpu_topo *build_cpu_topology(void) nr = (u32)(ncpus & UINT_MAX); sz = nr * sizeof(char *); - sz_id = nr * sizeof(int); - addr = calloc(1, sizeof(*tp) + 2 * sz + 2 * sz_id); + addr = calloc(1, sizeof(*tp) + 2 * sz); if (!addr) return NULL; @@ -532,10 +526,6 @@ static struct cpu_topo *build_cpu_topology(void) tp->core_siblings = addr; addr += sz; tp->thread_siblings = addr; - addr += sz; - tp->core_id = addr; - addr += sz_id; - tp->phy_pkg_id = addr; for (i = 0; i < nr; i++) { ret = build_cpu_topo(tp, i); @@ -554,7 +544,7 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, { struct cpu_topo *tp; u32 i; - int ret; + int ret, j; tp = build_cpu_topology(); if (!tp) @@ -579,11 +569,17 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, break; } - for (i = 0; i < tp->cpu_nr; i++) { - ret = do_write(fd, &tp->core_id[i], sizeof(int)); + ret = perf_env__read_cpu_topology_map(&perf_env); + if (ret < 0) + goto done; + + for (j = 0; j < perf_env.nr_cpus_avail; j++) { + ret = do_write(fd, &perf_env.cpu[j].core_id, + sizeof(perf_env.cpu[j].core_id)); if (ret < 0) return ret; - ret = do_write(fd, &tp->phy_pkg_id[i], sizeof(int)); + ret = do_write(fd, &perf_env.cpu[j].socket_id, + sizeof(perf_env.cpu[j].socket_id)); if (ret < 0) return ret; } From 4cde998d205894705b534878122631142a3eefe4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 9 Sep 2015 12:25:00 -0300 Subject: [PATCH 070/260] perf machine: Add pointer to sample's environment The 'struct machine' represents the machine where the samples were/are being collected, and we also have a 'struct perf_env' with extra details about such machine, that we were collecting at 'perf.data' creation time but we also needed when no perf.data file is being used, such as in 'perf top'. So, get those structs closer together, as they provide a bigger picture of the sample's environment. In 'perf session', when the file argument is NULL, we can assume that the tool is sampling the running machine, so point machine->env to the global put in place in previous patches, while set it to the perf_header.env one when reading from a file. This paves the way for machine->env to be used in perf_event__preprocess_sample to populate addr_location.socket. Tested-by: Wang Nan Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-2ajotl0khscutm68exictoy9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 1 + tools/perf/util/machine.c | 1 + tools/perf/util/machine.h | 1 + tools/perf/util/session.c | 2 ++ 4 files changed, 5 insertions(+) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 46ec6c5ca47f..6d8fa543dcff 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2564,6 +2564,7 @@ int perf_session__read_header(struct perf_session *session) return -ENOMEM; session->evlist->env = &header->env; + session->machines.host.env = &header->env; if (perf_data_file__is_pipe(file)) return perf_header__read_pipe(session); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 6309f7ceb08f..fd1efeafb343 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -35,6 +35,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) machine->last_match = NULL; machine->vdso_info = NULL; + machine->env = NULL; machine->pid = pid; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index ea5cb4a621db..9dfc4281f940 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -34,6 +34,7 @@ struct machine { struct list_head dead_threads; struct thread *last_match; struct vdso_info *vdso_info; + struct perf_env *env; struct dsos dsos; struct map_groups kmaps; struct map *vmlinux_maps[MAP__NR_TYPES]; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 728cb115fbb8..d1a43a322f96 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -138,6 +138,8 @@ struct perf_session *perf_session__new(struct perf_data_file *file, perf_session__set_id_hdr_size(session); perf_session__set_comm_exec(session); } + } else { + session->machines.host.env = &perf_env; } if (!file || perf_data_file__is_write(file)) { From 0c4c4debb0adda4c18c158d95031dc2b9f637869 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 4 Sep 2015 10:45:42 -0400 Subject: [PATCH 071/260] perf tools: Add processor socket info to hist_entry and addr_location This information will come from perf.data files of from the current system, cached when needed, such as when the 'socket' sort order gets introduced. Signed-off-by: Kan Liang Cc: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/1441377946-44429-1-git-send-email-kan.liang@intel.com [ Don't blindly use env->cpu[al.cpu].socket_id & use machine->env, fixes by Jiri & Arnaldo ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 8 ++++++++ tools/perf/util/hist.c | 1 + tools/perf/util/sort.h | 1 + tools/perf/util/symbol.h | 1 + 4 files changed, 11 insertions(+) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 7ff61274ed57..497157affc9c 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1021,6 +1021,14 @@ int perf_event__preprocess_sample(const union perf_event *event, al->sym = NULL; al->cpu = sample->cpu; + al->socket = -1; + + if (al->cpu >= 0) { + struct perf_env *env = machine->env; + + if (env && env->cpu) + al->socket = env->cpu[al->cpu].socket_id; + } if (al->map) { struct dso *dso = al->map->dso; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 48d5906a3f9f..d2b94c4c8fec 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -453,6 +453,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, .map = al->map, .sym = al->sym, }, + .socket = al->socket, .cpu = al->cpu, .cpumode = al->cpumode, .ip = al->addr, diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 3c2a399f8f5b..7cf1cf7d2406 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -90,6 +90,7 @@ struct hist_entry { struct comm *comm; u64 ip; u64 transaction; + s32 socket; s32 cpu; u8 cpumode; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 440ba8ae888f..40073c60b83d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -191,6 +191,7 @@ struct addr_location { u8 filtered; u8 cpumode; s32 cpu; + s32 socket; }; struct symsrc { From 2e7ea3ab8282f6bb1d211d8af760a734c055f493 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 4 Sep 2015 10:45:43 -0400 Subject: [PATCH 072/260] perf tools: Introduce new sort type "socket" for the processor socket This patch enable perf report to sort by processor socket: $ perf report --stdio --sort socket,comm,dso,symbol # To display the perf.data header info, please use --header/--header-only options. # # Total Lost Samples: 0 # # Samples: 686 of event 'cycles' # Event count (approx.): 349215462 # # Overhead SOCKET Command Shared Object Symbol # ........ ...... ....... ................ ............................ # 97.05% 000 test test [.] plusB_c 0.98% 000 test test [.] plusA_c 0.93% 001 perf [kernel.vmlinux] [k] smp_call_function_single 0.19% 001 perf [kernel.vmlinux] [k] page_fault 0.19% 001 swapper [kernel.vmlinux] [k] pm_qos_request 0.16% 000 test [kernel.vmlinux] [k] add_mm_counter_fast Signed-off-by: Kan Liang Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1441377946-44429-2-git-send-email-kan.liang@intel.com [ Fix col calc, un-allcapsify col header & read the topology when not using perf.data ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 3 ++- tools/perf/builtin-top.c | 15 ++++++++++++++ tools/perf/util/hist.c | 1 + tools/perf/util/hist.h | 1 + tools/perf/util/sort.c | 25 ++++++++++++++++++++++++ tools/perf/util/sort.h | 2 ++ 6 files changed, 46 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 9c7981bfddad..92361a7771f4 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -68,7 +68,7 @@ OPTIONS --sort=:: Sort histogram entries by given key(s) - multiple keys can be specified in CSV format. Following sort keys are available: - pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight. + pid, comm, dso, symbol, parent, cpu, socket, srcline, weight, local_weight. Each key has following meaning: @@ -79,6 +79,7 @@ OPTIONS - parent: name of function matched to the parent regex filter. Unmatched entries are displayed as "[other]". - cpu: cpu number the task ran at the time of sample + - socket: processor socket number the task ran at the time of sample - srcline: filename and line number executed at the time of sample. The DWARF debugging info must be provided. - srcfile: file name of the source file of the same. Requires dwarf diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e5ca6848f01d..bdaf44f24d5d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -963,6 +963,13 @@ static int __cmd_top(struct perf_top *top) machine__synthesize_threads(&top->session->machines.host, &opts->target, top->evlist->threads, false, opts->proc_map_timeout); + + if (sort__has_socket) { + ret = perf_env__read_cpu_topology_map(&perf_env); + if (ret < 0) + goto out_err_cpu_topo; + } + ret = perf_top__start_counters(top); if (ret) goto out_delete; @@ -1020,6 +1027,14 @@ out_delete: top->session = NULL; return ret; + +out_err_cpu_topo: { + char errbuf[BUFSIZ]; + const char *err = strerror_r(-ret, errbuf, sizeof(errbuf)); + + ui__error("Could not read the CPU topology map: %s\n", err); + goto out_delete; +} } static int diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index d2b94c4c8fec..ba72a297676c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -145,6 +145,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) } hists__new_col_len(hists, HISTC_CPU, 3); + hists__new_col_len(hists, HISTC_SOCKET, 6); hists__new_col_len(hists, HISTC_MEM_LOCKED, 6); hists__new_col_len(hists, HISTC_MEM_TLB, 22); hists__new_col_len(hists, HISTC_MEM_SNOOP, 12); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index de6d58e7f0d5..5d04d28eedd7 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -29,6 +29,7 @@ enum hist_column { HISTC_COMM, HISTC_PARENT, HISTC_CPU, + HISTC_SOCKET, HISTC_SRCLINE, HISTC_SRCFILE, HISTC_MISPREDICT, diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index a97bceeac0e7..6b9556d298c9 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -21,6 +21,7 @@ int sort__need_collapse = 0; int sort__has_parent = 0; int sort__has_sym = 0; int sort__has_dso = 0; +int sort__has_socket = 0; enum sort_mode sort__mode = SORT_MODE__NORMAL; @@ -421,6 +422,27 @@ struct sort_entry sort_cpu = { .se_width_idx = HISTC_CPU, }; +/* --sort socket */ + +static int64_t +sort__socket_cmp(struct hist_entry *left, struct hist_entry *right) +{ + return right->socket - left->socket; +} + +static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ + return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); +} + +struct sort_entry sort_socket = { + .se_header = "Socket", + .se_cmp = sort__socket_cmp, + .se_snprintf = hist_entry__socket_snprintf, + .se_width_idx = HISTC_SOCKET, +}; + /* sort keys for branch stacks */ static int64_t @@ -1248,6 +1270,7 @@ static struct sort_dimension common_sort_dimensions[] = { DIM(SORT_SYM, "symbol", sort_sym), DIM(SORT_PARENT, "parent", sort_parent), DIM(SORT_CPU, "cpu", sort_cpu), + DIM(SORT_SOCKET, "socket", sort_socket), DIM(SORT_SRCLINE, "srcline", sort_srcline), DIM(SORT_SRCFILE, "srcfile", sort_srcfile), DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), @@ -1550,6 +1573,8 @@ int sort_dimension__add(const char *tok) } else if (sd->entry == &sort_dso) { sort__has_dso = 1; + } else if (sd->entry == &sort_socket) { + sort__has_socket = 1; } return __sort_dimension__add(sd); diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 7cf1cf7d2406..c06b75746613 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -34,6 +34,7 @@ extern int have_ignore_callees; extern int sort__need_collapse; extern int sort__has_parent; extern int sort__has_sym; +extern int sort__has_socket; extern enum sort_mode sort__mode; extern struct sort_entry sort_comm; extern struct sort_entry sort_dso; @@ -173,6 +174,7 @@ enum sort_type { SORT_SYM, SORT_PARENT, SORT_CPU, + SORT_SOCKET, SORT_SRCLINE, SORT_SRCFILE, SORT_LOCAL_WEIGHT, From 21394d948a0c7c451d4a4d68afed9a06c4969636 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 4 Sep 2015 10:45:44 -0400 Subject: [PATCH 073/260] perf report: Introduce --socket-filter option Introduce --socket-filter option for 'perf report' to only show entries for a processor socket that match this filter. $ perf report --socket-filter 1 --stdio # To display the perf.data header info, please use --header/--header-only options. # # Total Lost Samples: 0 # # Samples: 752 of event 'cycles' # Event count (approx.): 350995599 # Processor Socket: 1 # # Overhead Command Shared Object Symbol # ........ ......... ................ ................................. # 97.02% test test [.] plusB_c 0.97% test test [.] plusA_c 0.23% swapper [kernel.vmlinux] [k] acpi_idle_do_entry 0.09% rcu_sched [kernel.vmlinux] [k] dyntick_save_progress_counter 0.01% swapper [kernel.vmlinux] [k] task_waking_fair 0.00% swapper [kernel.vmlinux] [k] run_timer_softirq Signed-off-by: Kan Liang Cc: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1441377946-44429-3-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 3 +++ tools/perf/builtin-report.c | 11 +++++++++++ tools/perf/ui/browsers/hists.c | 4 ++++ tools/perf/util/hist.c | 16 ++++++++++++++++ tools/perf/util/hist.h | 4 +++- 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 92361a7771f4..b941d5e07e28 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -350,6 +350,9 @@ include::itrace.txt[] This option extends the perf report to show reference callgraphs, which collected by reference event, in no callgraph event. +--socket-filter:: + Only report the samples on the processor socket that match with this filter + include::callchain-overhead-calculation.txt[] SEE ALSO diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 62b285e32aa5..9b5083630a56 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -62,6 +62,7 @@ struct report { float min_percent; u64 nr_entries; u64 queue_size; + int socket_filter; DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); }; @@ -286,6 +287,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report struct perf_evsel *evsel = hists_to_evsel(hists); char buf[512]; size_t size = sizeof(buf); + int socket = hists->socket_filter; if (symbol_conf.filter_relative) { nr_samples = hists->stats.nr_non_filtered_samples; @@ -326,6 +328,10 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ret += fprintf(fp, "\n# Sort order : %s", sort_order ? : default_mem_sort_order); } else ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); + + if (socket > -1) + ret += fprintf(fp, "\n# Processor Socket: %d", socket); + return ret + fprintf(fp, "\n#\n"); } @@ -450,6 +456,8 @@ static void report__collapse_hists(struct report *rep) if (pos->idx == 0) hists->symbol_filter_str = rep->symbol_filter_str; + hists->socket_filter = rep->socket_filter; + hists__collapse_resort(hists, &prog); /* Non-group events are considered as leader */ @@ -635,6 +643,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) }, .max_stack = PERF_MAX_STACK_DEPTH, .pretty_printing_style = "normal", + .socket_filter = -1, }; const struct option options[] = { OPT_STRING('i', "input", &input_name, "file", @@ -747,6 +756,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "Show full source file name path for source lines"), OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph, "Show callgraph from reference event"), + OPT_INTEGER(0, "socket-filter", &report.socket_filter, + "only show processor socket that match with this filter"), OPT_END() }; struct perf_data_file file = { diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 17d6c6dbb27f..792dcf55cbe1 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1261,6 +1261,7 @@ static int hists__browser_title(struct hists *hists, int printed; const struct dso *dso = hists->dso_filter; const struct thread *thread = hists->thread_filter; + int socket = hists->socket_filter; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; struct perf_evsel *evsel = hists_to_evsel(hists); @@ -1314,6 +1315,9 @@ static int hists__browser_title(struct hists *hists, if (dso) printed += scnprintf(bf + printed, size - printed, ", DSO: %s", dso->short_name); + if (socket > -1) + printed += scnprintf(bf + printed, size - printed, + ", Processor Socket: %d", socket); if (!is_report_browser(hbt)) { struct perf_top *top = hbt->arg; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index ba72a297676c..5d78ae879017 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -15,6 +15,8 @@ static bool hists__filter_entry_by_thread(struct hists *hists, struct hist_entry *he); static bool hists__filter_entry_by_symbol(struct hists *hists, struct hist_entry *he); +static bool hists__filter_entry_by_socket(struct hists *hists, + struct hist_entry *he); u16 hists__col_len(struct hists *hists, enum hist_column col) { @@ -1027,6 +1029,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he) hists__filter_entry_by_dso(hists, he); hists__filter_entry_by_thread(hists, he); hists__filter_entry_by_symbol(hists, he); + hists__filter_entry_by_socket(hists, he); } void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) @@ -1295,6 +1298,18 @@ void hists__filter_by_symbol(struct hists *hists) } } +static bool hists__filter_entry_by_socket(struct hists *hists, + struct hist_entry *he) +{ + if ((hists->socket_filter > -1) && + (he->socket != hists->socket_filter)) { + he->filtered |= (1 << HIST_FILTER__SOCKET); + return true; + } + + return false; +} + void events_stats__inc(struct events_stats *stats, u32 type) { ++stats->nr_events[0]; @@ -1520,6 +1535,7 @@ static int hists_evsel__init(struct perf_evsel *evsel) hists->entries_collapsed = RB_ROOT; hists->entries = RB_ROOT; pthread_mutex_init(&hists->lock, NULL); + hists->socket_filter = -1; return 0; } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 5d04d28eedd7..ef682f210923 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -20,6 +20,7 @@ enum hist_filter { HIST_FILTER__SYMBOL, HIST_FILTER__GUEST, HIST_FILTER__HOST, + HIST_FILTER__SOCKET, }; enum hist_column { @@ -71,6 +72,7 @@ struct hists { struct events_stats stats; u64 event_stream; u16 col_len[HISTC_NR_COLS]; + int socket_filter; }; struct hist_entry_iter; @@ -149,7 +151,7 @@ void hists__filter_by_symbol(struct hists *hists); static inline bool hists__has_filter(struct hists *hists) { return hists->thread_filter || hists->dso_filter || - hists->symbol_filter_str; + hists->symbol_filter_str || (hists->socket_filter > -1); } u16 hists__col_len(struct hists *hists, enum hist_column col); From 84734b06b63093cd44533f4caa43d4452fb11ec3 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 4 Sep 2015 10:45:45 -0400 Subject: [PATCH 074/260] perf hists browser: Zoom in/out for processor socket Currently, users can zoom in/out for threads and dso in 'perf top' and 'perf report'. This patch extends it for the processor sockets. 'S' is the short key to zoom into current Processor Socket. Signed-off-by: Kan Liang Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1441377946-44429-4-git-send-email-kan.liang@intel.com [ - Made it elide the Socket column when zooming into it, just like with the other zoom ops; - Make it use browser->pstack, to unzoom level by level; - Rename 'socket' variables to 'socket_id' to make it build on older systems where it shadows a global glibc declaration ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 6 ++-- tools/perf/ui/browsers/hists.c | 61 ++++++++++++++++++++++++++++++---- tools/perf/util/hist.c | 19 +++++++++++ tools/perf/util/hist.h | 1 + 4 files changed, 77 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 9b5083630a56..e4e3f1432622 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -287,7 +287,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report struct perf_evsel *evsel = hists_to_evsel(hists); char buf[512]; size_t size = sizeof(buf); - int socket = hists->socket_filter; + int socked_id = hists->socket_filter; if (symbol_conf.filter_relative) { nr_samples = hists->stats.nr_non_filtered_samples; @@ -329,8 +329,8 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report } else ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); - if (socket > -1) - ret += fprintf(fp, "\n# Processor Socket: %d", socket); + if (socked_id > -1) + ret += fprintf(fp, "\n# Processor Socket: %d", socked_id); return ret + fprintf(fp, "\n#\n"); } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 792dcf55cbe1..380e9080991e 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1261,7 +1261,7 @@ static int hists__browser_title(struct hists *hists, int printed; const struct dso *dso = hists->dso_filter; const struct thread *thread = hists->thread_filter; - int socket = hists->socket_filter; + int socket_id = hists->socket_filter; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; struct perf_evsel *evsel = hists_to_evsel(hists); @@ -1315,9 +1315,9 @@ static int hists__browser_title(struct hists *hists, if (dso) printed += scnprintf(bf + printed, size - printed, ", DSO: %s", dso->short_name); - if (socket > -1) + if (socket_id > -1) printed += scnprintf(bf + printed, size - printed, - ", Processor Socket: %d", socket); + ", Processor Socket: %d", socket_id); if (!is_report_browser(hbt)) { struct perf_top *top = hbt->arg; @@ -1429,6 +1429,7 @@ struct popup_action { struct thread *thread; struct dso *dso; struct map_symbol ms; + int socket; int (*fn)(struct hist_browser *browser, struct popup_action *act); }; @@ -1676,6 +1677,41 @@ add_exit_opt(struct hist_browser *browser __maybe_unused, return 1; } +static int +do_zoom_socket(struct hist_browser *browser, struct popup_action *act) +{ + if (browser->hists->socket_filter > -1) { + pstack__remove(browser->pstack, &browser->hists->socket_filter); + browser->hists->socket_filter = -1; + perf_hpp__set_elide(HISTC_SOCKET, false); + } else { + browser->hists->socket_filter = act->socket; + perf_hpp__set_elide(HISTC_SOCKET, true); + pstack__push(browser->pstack, &browser->hists->socket_filter); + } + + hists__filter_by_socket(browser->hists); + hist_browser__reset(browser); + return 0; +} + +static int +add_socket_opt(struct hist_browser *browser, struct popup_action *act, + char **optstr, int socket_id) +{ + if (socket_id < 0) + return 0; + + if (asprintf(optstr, "Zoom %s Processor Socket %d", + (browser->hists->socket_filter > -1) ? "out of" : "into", + socket_id) < 0) + return 0; + + act->socket = socket_id; + act->fn = do_zoom_socket; + return 1; +} + static void hist_browser__update_nr_entries(struct hist_browser *hb) { u64 nr_entries = 0; @@ -1729,6 +1765,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "E Expand all callchains\n" \ "F Toggle percentage of filtered entries\n" \ "H Display column headers\n" \ + "S Zoom into current Processor Socket\n" \ /* help messages are sorted by lexical order of the hotkey */ const char report_help[] = HIST_BROWSER_HELP_COMMON @@ -1759,7 +1796,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, hist_browser__update_nr_entries(browser); } - browser->pstack = pstack__new(2); + browser->pstack = pstack__new(3); if (browser->pstack == NULL) goto out; @@ -1778,6 +1815,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, struct thread *thread = NULL; struct dso *dso = NULL; int choice = 0; + int socked_id = -1; nr_options = 0; @@ -1786,6 +1824,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (browser->he_selection != NULL) { thread = hist_browser__selected_thread(browser); dso = browser->selection->map ? browser->selection->map->dso : NULL; + socked_id = browser->he_selection->socket; } switch (key) { case K_TAB: @@ -1828,6 +1867,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, actions->thread = thread; do_zoom_thread(browser, actions); continue; + case 'S': + actions->socket = socked_id; + do_zoom_socket(browser, actions); + continue; case '/': if (ui_browser__input_window("Symbol to show", "Please enter the name of symbol you want to see", @@ -1903,9 +1946,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, * Ditto for thread below. */ do_zoom_dso(browser, actions); - } - if (top == &browser->hists->thread_filter) + } else if (top == &browser->hists->thread_filter) { do_zoom_thread(browser, actions); + } else if (top == &browser->hists->socket_filter) { + do_zoom_socket(browser, actions); + } continue; } case 'q': @@ -1973,7 +2018,9 @@ skip_annotation: nr_options += add_map_opt(browser, &actions[nr_options], &options[nr_options], browser->selection->map); - + nr_options += add_socket_opt(browser, &actions[nr_options], + &options[nr_options], + socked_id); /* perf script support */ if (browser->he_selection) { nr_options += add_script_opt(browser, diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 5d78ae879017..b3567a25f0c4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1310,6 +1310,25 @@ static bool hists__filter_entry_by_socket(struct hists *hists, return false; } +void hists__filter_by_socket(struct hists *hists) +{ + struct rb_node *nd; + + hists->stats.nr_non_filtered_samples = 0; + + hists__reset_filter_stats(hists); + hists__reset_col_len(hists); + + for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { + struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); + + if (hists__filter_entry_by_socket(hists, h)) + continue; + + hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET); + } +} + void events_stats__inc(struct events_stats *stats, u32 type) { ++stats->nr_events[0]; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index ef682f210923..4d6aa1dbdaee 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -147,6 +147,7 @@ size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); void hists__filter_by_dso(struct hists *hists); void hists__filter_by_thread(struct hists *hists); void hists__filter_by_symbol(struct hists *hists); +void hists__filter_by_socket(struct hists *hists); static inline bool hists__has_filter(struct hists *hists) { From 92d424ae898e0d04ac34263aa33e40acc1e1f3d1 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 4 Sep 2015 10:45:46 -0400 Subject: [PATCH 075/260] perf test: Add entry for hists socket filter Add test case for hists socket filter. Signed-off-by: Kan Liang Cc: Adrian Hunter Cc: Andi Kleen Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1441377946-44429-5-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/hists_filter.c | 55 +++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index ce48775e6ada..818acf875dd0 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c @@ -16,30 +16,31 @@ struct sample { struct thread *thread; struct map *map; struct symbol *sym; + int socket; }; /* For the numbers, see hists_common.c */ static struct sample fake_samples[] = { /* perf [kernel] schedule() */ - { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, }, + { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, .socket = 0 }, /* perf [perf] main() */ - { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, }, + { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, .socket = 0 }, /* perf [libc] malloc() */ - { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, }, + { .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, .socket = 0 }, /* perf [perf] main() */ - { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, }, /* will be merged */ + { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, .socket = 0 }, /* will be merged */ /* perf [perf] cmd_record() */ - { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, }, + { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, .socket = 1 }, /* perf [kernel] page_fault() */ - { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, }, + { .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 1 }, /* bash [bash] main() */ - { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, }, + { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, .socket = 2 }, /* bash [bash] xmalloc() */ - { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, }, + { .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, .socket = 2 }, /* bash [libc] malloc() */ - { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, }, + { .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, .socket = 3 }, /* bash [kernel] page_fault() */ - { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, }, + { .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 3 }, }; static int add_hist_entries(struct perf_evlist *evlist, @@ -83,6 +84,7 @@ static int add_hist_entries(struct perf_evlist *evlist, &sample) < 0) goto out; + al.socket = fake_samples[i].socket; if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, NULL) < 0) { addr_location__put(&al); @@ -253,6 +255,39 @@ int test__hists_filter(void) TEST_ASSERT_VAL("Unmatched total period for symbol filter", hists->stats.total_non_filtered_period == 300); + /* remove symbol filter first */ + hists->symbol_filter_str = NULL; + hists__filter_by_symbol(hists); + + /* now applying socket filters */ + hists->socket_filter = 2; + hists__filter_by_socket(hists); + + if (verbose > 2) { + pr_info("Histogram for socket filters\n"); + print_hists_out(hists); + } + + /* normal stats should be invariant */ + TEST_ASSERT_VAL("Invalid nr samples", + hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10); + TEST_ASSERT_VAL("Invalid nr hist entries", + hists->nr_entries == 9); + TEST_ASSERT_VAL("Invalid total period", + hists->stats.total_period == 1000); + + /* but filter stats are changed */ + TEST_ASSERT_VAL("Unmatched nr samples for socket filter", + hists->stats.nr_non_filtered_samples == 2); + TEST_ASSERT_VAL("Unmatched nr hist entries for socket filter", + hists->nr_non_filtered_entries == 2); + TEST_ASSERT_VAL("Unmatched total period for socket filter", + hists->stats.total_non_filtered_period == 200); + + /* remove socket filter first */ + hists->socket_filter = -1; + hists__filter_by_socket(hists); + /* now applying all filters at once. */ hists->thread_filter = fake_samples[1].thread; hists->dso_filter = fake_samples[1].map->dso; From a43aac299c3abc09eff856039f5b72166b780d35 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 10 Sep 2015 11:27:04 +0900 Subject: [PATCH 076/260] perf probe: Free perf_probe_event in cleanup_perf_probe_events() The cleanup_perf_probe_events() frees all resources related to a perf probe event. However it only freed resources in trace probe events, not perf probe events. So call clear_perf_probe_event() too. Reported-by: Wang Nan Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441852026-28974-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5964eccbe94d..3d7d60cc6f16 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2792,6 +2792,7 @@ void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs) clear_probe_trace_event(&pevs[i].tevs[j]); zfree(&pevs[i].tevs); pevs[i].ntevs = 0; + clear_perf_probe_event(&pevs[i]); } exit_symbol_maps(); From 9bae1e8c3fe5359ce17309b894f54667fd563e98 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 10 Sep 2015 11:27:05 +0900 Subject: [PATCH 077/260] perf probe: Export init/exit_probe_symbol_maps() The init/exit_symbols_maps() functions are to setup and cleanup necessary info for probe events. But they need to be called from out of the probe code now, so this patch exports them. However the names are too generic, so change them to have 'probe'. :) Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1441852026-28974-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 5 +++++ tools/perf/util/probe-event.c | 31 +++++++++++++++---------------- tools/perf/util/probe-event.h | 2 ++ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 2bec9c1ef2a3..94385ee89dc8 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -317,6 +317,10 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs) int i, k; const char *event = NULL, *group = NULL; + ret = init_probe_symbol_maps(pevs->uprobes); + if (ret < 0) + return ret; + ret = convert_perf_probe_events(pevs, npevs); if (ret < 0) goto out_cleanup; @@ -354,6 +358,7 @@ static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs) out_cleanup: cleanup_perf_probe_events(pevs, npevs); + exit_probe_symbol_maps(); return ret; } diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3d7d60cc6f16..2b78e8f19b45 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -71,7 +71,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp); static struct machine *host_machine; /* Initialize symbol maps and path of vmlinux/modules */ -static int init_symbol_maps(bool user_only) +int init_probe_symbol_maps(bool user_only) { int ret; @@ -101,7 +101,7 @@ out: return ret; } -static void exit_symbol_maps(void) +void exit_probe_symbol_maps(void) { if (host_machine) { machine__delete(host_machine); @@ -859,11 +859,11 @@ int show_line_range(struct line_range *lr, const char *module, bool user) { int ret; - ret = init_symbol_maps(user); + ret = init_probe_symbol_maps(user); if (ret < 0) return ret; ret = __show_line_range(lr, module, user); - exit_symbol_maps(); + exit_probe_symbol_maps(); return ret; } @@ -941,7 +941,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, int i, ret = 0; struct debuginfo *dinfo; - ret = init_symbol_maps(pevs->uprobes); + ret = init_probe_symbol_maps(pevs->uprobes); if (ret < 0) return ret; @@ -958,7 +958,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, debuginfo__delete(dinfo); out: - exit_symbol_maps(); + exit_probe_symbol_maps(); return ret; } @@ -2262,7 +2262,7 @@ int show_perf_probe_events(struct strfilter *filter) setup_pager(); - ret = init_symbol_maps(false); + ret = init_probe_symbol_maps(false); if (ret < 0) return ret; @@ -2278,7 +2278,7 @@ int show_perf_probe_events(struct strfilter *filter) close(kp_fd); if (up_fd > 0) close(up_fd); - exit_symbol_maps(); + exit_probe_symbol_maps(); return ret; } @@ -2746,10 +2746,6 @@ int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int i, ret; - ret = init_symbol_maps(pevs->uprobes); - if (ret < 0) - return ret; - /* Loop 1: convert all events */ for (i = 0; i < npevs; i++) { /* Init kprobe blacklist if needed */ @@ -2794,20 +2790,23 @@ void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs) pevs[i].ntevs = 0; clear_perf_probe_event(&pevs[i]); } - - exit_symbol_maps(); } int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) { int ret; + ret = init_probe_symbol_maps(pevs->uprobes); + if (ret < 0) + return ret; + ret = convert_perf_probe_events(pevs, npevs); if (ret == 0) ret = apply_perf_probe_events(pevs, npevs); cleanup_perf_probe_events(pevs, npevs); + exit_probe_symbol_maps(); return ret; } @@ -2867,7 +2866,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, struct map *map; int ret; - ret = init_symbol_maps(user); + ret = init_probe_symbol_maps(user); if (ret < 0) return ret; @@ -2897,7 +2896,7 @@ end: if (user) { map__put(map); } - exit_symbol_maps(); + exit_probe_symbol_maps(); return ret; } diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 9bcea36359f2..ba926c30f8cd 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -110,6 +110,8 @@ struct variable_list { }; struct map; +int init_probe_symbol_maps(bool user_only); +void exit_probe_symbol_maps(void); /* Command string to events */ extern int parse_perf_probe_command(const char *cmd, From 01ca9fd41d6f2ad796a6b109b5253e06b6ae6dc7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 7 Sep 2015 10:38:03 +0200 Subject: [PATCH 078/260] tools: Add err.h with ERR_PTR PTR_ERR interface Adding part of the kernel's interface: inline void * __must_check ERR_PTR(long error); inline long __must_check PTR_ERR(__force const void *ptr); inline bool __must_check IS_ERR(__force const void *ptr); It will be used to propagate error through pointers in following patches. Signed-off-by: Jiri Olsa Reviewed-by: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441615087-13886-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/err.h | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 tools/include/linux/err.h diff --git a/tools/include/linux/err.h b/tools/include/linux/err.h new file mode 100644 index 000000000000..c9ada48f5156 --- /dev/null +++ b/tools/include/linux/err.h @@ -0,0 +1,49 @@ +#ifndef __TOOLS_LINUX_ERR_H +#define __TOOLS_LINUX_ERR_H + +#include +#include + +#include + +/* + * Original kernel header comment: + * + * Kernel pointers have redundant information, so we can use a + * scheme where we can return either an error code or a normal + * pointer with the same return value. + * + * This should be a per-architecture thing, to allow different + * error and pointer decisions. + * + * Userspace note: + * The same principle works for userspace, because 'error' pointers + * fall down to the unused hole far from user space, as described + * in Documentation/x86/x86_64/mm.txt for x86_64 arch: + * + * 0000000000000000 - 00007fffffffffff (=47 bits) user space, different per mm hole caused by [48:63] sign extension + * ffffffffffe00000 - ffffffffffffffff (=2 MB) unused hole + * + * It should be the same case for other architectures, because + * this code is used in generic kernel code. + */ +#define MAX_ERRNO 4095 + +#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) + +static inline void * __must_check ERR_PTR(long error) +{ + return (void *) error; +} + +static inline long __must_check PTR_ERR(__force const void *ptr) +{ + return (long) ptr; +} + +static inline bool __must_check IS_ERR(__force const void *ptr) +{ + return IS_ERR_VALUE((unsigned long)ptr); +} + +#endif /* _LINUX_ERR_H */ From e2f9f8ea6a54e252e3a94a5c2321f673b5b97360 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 7 Sep 2015 10:38:05 +0200 Subject: [PATCH 079/260] perf tools: Propagate error info for the tracepoint parsing Pass 'struct parse_events_error *error' to the parse-event.c tracepoint adding path. It will be filled with error data in following patches. Signed-off-by: Jiri Olsa Reviewed-by: Raphael Beamonte Reviewed-by: Matt Fleming Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441615087-13886-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 27 ++++++++++++++++----------- tools/perf/util/parse-events.h | 3 ++- tools/perf/util/parse-events.y | 4 ++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 3840176642f8..1b284b8ad243 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -387,7 +387,8 @@ int parse_events_add_cache(struct list_head *list, int *idx, } static int add_tracepoint(struct list_head *list, int *idx, - char *sys_name, char *evt_name) + char *sys_name, char *evt_name, + struct parse_events_error *error __maybe_unused) { struct perf_evsel *evsel; @@ -401,7 +402,8 @@ static int add_tracepoint(struct list_head *list, int *idx, } static int add_tracepoint_multi_event(struct list_head *list, int *idx, - char *sys_name, char *evt_name) + char *sys_name, char *evt_name, + struct parse_events_error *error) { char evt_path[MAXPATHLEN]; struct dirent *evt_ent; @@ -425,7 +427,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, if (!strglobmatch(evt_ent->d_name, evt_name)) continue; - ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name); + ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, error); } closedir(evt_dir); @@ -433,15 +435,17 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, } static int add_tracepoint_event(struct list_head *list, int *idx, - char *sys_name, char *evt_name) + char *sys_name, char *evt_name, + struct parse_events_error *error) { return strpbrk(evt_name, "*?") ? - add_tracepoint_multi_event(list, idx, sys_name, evt_name) : - add_tracepoint(list, idx, sys_name, evt_name); + add_tracepoint_multi_event(list, idx, sys_name, evt_name, error) : + add_tracepoint(list, idx, sys_name, evt_name, error); } static int add_tracepoint_multi_sys(struct list_head *list, int *idx, - char *sys_name, char *evt_name) + char *sys_name, char *evt_name, + struct parse_events_error *error) { struct dirent *events_ent; DIR *events_dir; @@ -465,7 +469,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, continue; ret = add_tracepoint_event(list, idx, events_ent->d_name, - evt_name); + evt_name, error); } closedir(events_dir); @@ -473,12 +477,13 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, } int parse_events_add_tracepoint(struct list_head *list, int *idx, - char *sys, char *event) + char *sys, char *event, + struct parse_events_error *error) { if (strpbrk(sys, "*?")) - return add_tracepoint_multi_sys(list, idx, sys, event); + return add_tracepoint_multi_sys(list, idx, sys, event, error); else - return add_tracepoint_event(list, idx, sys, event); + return add_tracepoint_event(list, idx, sys, event, error); } static int diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index a09b0e210997..ffee7ece75a6 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -118,7 +118,8 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events_name(struct list_head *list, char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, - char *sys, char *event); + char *sys, char *event, + struct parse_events_error *error); int parse_events_add_numeric(struct parse_events_evlist *data, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 9cd70819c795..54a3004a8192 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -376,7 +376,7 @@ PE_NAME '-' PE_NAME ':' PE_NAME snprintf(&sys_name, 128, "%s-%s", $1, $3); ALLOC_LIST(list); - ABORT_ON(parse_events_add_tracepoint(list, &data->idx, &sys_name, $5)); + ABORT_ON(parse_events_add_tracepoint(list, &data->idx, &sys_name, $5, data->error)); $$ = list; } | @@ -386,7 +386,7 @@ PE_NAME ':' PE_NAME struct list_head *list; ALLOC_LIST(list); - if (parse_events_add_tracepoint(list, &data->idx, $1, $3)) { + if (parse_events_add_tracepoint(list, &data->idx, $1, $3, data->error)) { struct parse_events_error *error = data->error; if (error) { From 8dd2a1317eba2c207632dcb19adb7cb746861652 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 7 Sep 2015 10:38:06 +0200 Subject: [PATCH 080/260] perf evsel: Propagate error info from tp_format Propagate error info from tp_format via ERR_PTR to get it all the way down to the parse-event.c tracepoint adding routines. Following functions now return pointer with encoded error: - tp_format - trace_event__tp_format - perf_evsel__newtp_idx - perf_evsel__newtp This affects several other places in perf, that cannot use pointer check anymore, but must utilize the err.h interface, when getting error information from above functions list. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Link: http://lkml.kernel.org/r/1441615087-13886-5-git-send-email-jolsa@kernel.org [ Add two missing ERR_PTR() and one IS_ERR() ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 19 +++++++++++-------- tools/perf/tests/evsel-tp-sched.c | 10 ++++++++-- tools/perf/tests/mmap-basic.c | 3 ++- tools/perf/tests/openat-syscall-all-cpus.c | 3 ++- tools/perf/tests/openat-syscall-tp-fields.c | 3 ++- tools/perf/tests/openat-syscall.c | 3 ++- tools/perf/util/evlist.c | 3 ++- tools/perf/util/evsel.c | 16 +++++++++++++--- tools/perf/util/evsel.h | 3 +++ tools/perf/util/parse-events.c | 6 +++--- tools/perf/util/trace-event.c | 15 ++++++++++++--- 11 files changed, 60 insertions(+), 24 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 215653274102..93b80f12f35e 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -38,6 +38,7 @@ #include #include #include +#include /* For older distros: */ #ifndef MAP_STACK @@ -245,13 +246,14 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */ - if (evsel == NULL) + if (IS_ERR(evsel)) evsel = perf_evsel__newtp("syscalls", direction); - if (evsel) { - if (perf_evsel__init_syscall_tp(evsel, handler)) - goto out_delete; - } + if (IS_ERR(evsel)) + return NULL; + + if (perf_evsel__init_syscall_tp(evsel, handler)) + goto out_delete; return evsel; @@ -1705,12 +1707,12 @@ static int trace__read_syscall_info(struct trace *trace, int id) snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); sc->tp_format = trace_event__tp_format("syscalls", tp_name); - if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { + if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) { snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); sc->tp_format = trace_event__tp_format("syscalls", tp_name); } - if (sc->tp_format == NULL) + if (IS_ERR(sc->tp_format)) return -1; sc->args = sc->tp_format->format.fields; @@ -2390,7 +2392,8 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp); static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist) { struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname"); - if (evsel == NULL) + + if (IS_ERR(evsel)) return false; if (perf_evsel__field(evsel, "pathname") == NULL) { diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c index 52162425c969..790e413d9a1f 100644 --- a/tools/perf/tests/evsel-tp-sched.c +++ b/tools/perf/tests/evsel-tp-sched.c @@ -1,3 +1,4 @@ +#include #include #include "evsel.h" #include "tests.h" @@ -36,8 +37,8 @@ int test__perf_evsel__tp_sched_test(void) struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch"); int ret = 0; - if (evsel == NULL) { - pr_debug("perf_evsel__new\n"); + if (IS_ERR(evsel)) { + pr_debug("perf_evsel__newtp failed with %ld\n", PTR_ERR(evsel)); return -1; } @@ -66,6 +67,11 @@ int test__perf_evsel__tp_sched_test(void) evsel = perf_evsel__newtp("sched", "sched_wakeup"); + if (IS_ERR(evsel)) { + pr_debug("perf_evsel__newtp failed with %ld\n", PTR_ERR(evsel)); + return -1; + } + if (perf_evsel__test_field(evsel, "comm", 16, true)) ret = -1; diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c index 666b67a4df9d..4495493c9431 100644 --- a/tools/perf/tests/mmap-basic.c +++ b/tools/perf/tests/mmap-basic.c @@ -3,6 +3,7 @@ #include "thread_map.h" #include "cpumap.h" #include "tests.h" +#include /* * This test will generate random numbers of calls to some getpid syscalls, @@ -65,7 +66,7 @@ int test__basic_mmap(void) snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); evsels[i] = perf_evsel__newtp("syscalls", name); - if (evsels[i] == NULL) { + if (IS_ERR(evsels[i])) { pr_debug("perf_evsel__new\n"); goto out_delete_evlist; } diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 495d8126b722..9e104a2e973d 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -1,4 +1,5 @@ #include +#include #include "evsel.h" #include "tests.h" #include "thread_map.h" @@ -31,7 +32,7 @@ int test__openat_syscall_event_on_all_cpus(void) CPU_ZERO(&cpu_set); evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); - if (evsel == NULL) { + if (IS_ERR(evsel)) { tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); pr_err("%s\n", errbuf); goto out_thread_map_delete; diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 01a19626c846..473d3869727e 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -1,3 +1,4 @@ +#include #include "perf.h" #include "evlist.h" #include "evsel.h" @@ -30,7 +31,7 @@ int test__syscall_openat_tp_fields(void) } evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); - if (evsel == NULL) { + if (IS_ERR(evsel)) { pr_debug("%s: perf_evsel__newtp\n", __func__); goto out_delete_evlist; } diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 08ac9d94a050..7b1db8306098 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -1,4 +1,5 @@ #include +#include #include "thread_map.h" #include "evsel.h" #include "debug.h" @@ -19,7 +20,7 @@ int test__openat_syscall_event(void) } evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); - if (evsel == NULL) { + if (IS_ERR(evsel)) { tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); pr_err("%s\n", errbuf); goto out_thread_map_delete; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index d51a5200c8af..3cb2bf9bd4bd 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -25,6 +25,7 @@ #include #include #include +#include static void perf_evlist__mmap_put(struct perf_evlist *evlist, int idx); static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx); @@ -265,7 +266,7 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, { struct perf_evsel *evsel = perf_evsel__newtp(sys, name); - if (evsel == NULL) + if (IS_ERR(evsel)) return -1; evsel->handler = handler; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 771ade4d5966..6b5d1b509148 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "asm/bug.h" #include "callchain.h" @@ -225,11 +226,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) return evsel; } +/* + * Returns pointer with encoded error via interface. + */ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) { struct perf_evsel *evsel = zalloc(perf_evsel__object.size); + int err = -ENOMEM; - if (evsel != NULL) { + if (evsel == NULL) { + goto out_err; + } else { struct perf_event_attr attr = { .type = PERF_TYPE_TRACEPOINT, .sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | @@ -240,8 +247,10 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int goto out_free; evsel->tp_format = trace_event__tp_format(sys, name); - if (evsel->tp_format == NULL) + if (IS_ERR(evsel->tp_format)) { + err = PTR_ERR(evsel->tp_format); goto out_free; + } event_attr_init(&attr); attr.config = evsel->tp_format->id; @@ -254,7 +263,8 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int out_free: zfree(&evsel->name); free(evsel); - return NULL; +out_err: + return ERR_PTR(err); } const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = { diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index f164a149da82..62ab307b7306 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -160,6 +160,9 @@ static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx); +/* + * Returns pointer with encoded error via interface. + */ static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name) { return perf_evsel__newtp_idx(sys, name, 0); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1b284b8ad243..c47831c47220 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1,4 +1,5 @@ #include +#include #include "util.h" #include "../perf.h" #include "evlist.h" @@ -393,11 +394,10 @@ static int add_tracepoint(struct list_head *list, int *idx, struct perf_evsel *evsel; evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); - if (!evsel) - return -ENOMEM; + if (IS_ERR(evsel)) + return PTR_ERR(evsel); list_add_tail(&evsel->node, list); - return 0; } diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 2f4996ab313d..802bb868d446 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "trace-event.h" @@ -66,6 +67,9 @@ void trace_event__cleanup(struct trace_event *t) pevent_free(t->pevent); } +/* + * Returns pointer with encoded error via interface. + */ static struct event_format* tp_format(const char *sys, const char *name) { @@ -74,12 +78,14 @@ tp_format(const char *sys, const char *name) char path[PATH_MAX]; size_t size; char *data; + int err; scnprintf(path, PATH_MAX, "%s/%s/%s/format", tracing_events_path, sys, name); - if (filename__read_str(path, &data, &size)) - return NULL; + err = filename__read_str(path, &data, &size); + if (err) + return ERR_PTR(err); pevent_parse_format(pevent, &event, data, size, sys); @@ -87,11 +93,14 @@ tp_format(const char *sys, const char *name) return event; } +/* + * Returns pointer with encoded error via interface. + */ struct event_format* trace_event__tp_format(const char *sys, const char *name) { if (!tevent_initialized && trace_event__init2()) - return NULL; + return ERR_PTR(-ENOMEM); return tp_format(sys, name); } From 196581717d85f59365dc9303685cd5b1cdf106a3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 7 Sep 2015 10:38:07 +0200 Subject: [PATCH 081/260] perf tools: Enhance parsing events tracepoint error output Enhancing parsing events tracepoint error output. Adding more verbose output when the tracepoint is not found or the tracing event path cannot be access. $ sudo perf record -e sched:sched_krava ls event syntax error: 'sched:sched_krava' \___ unknown tracepoint Error: File /sys/kernel/debug/tracing//tracing/events/sched/sched_krava not found. Hint: Perhaps this kernel misses some CONFIG_ setting to enable this feature?. Run 'perf list' for a list of valid events ... $ perf record -e sched:sched_krava ls event syntax error: 'sched:sched_krava' \___ can't access trace events Error: No permissions to read /sys/kernel/debug/tracing//tracing/events/sched/sched_krava Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug' Run 'perf list' for a list of valid events ... Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Raphael Beamonte Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441615087-13886-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 35 +++++++++++++++++++++++++++++++--- tools/perf/util/parse-events.y | 16 +++++++++------- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c47831c47220..d3fb90be6216 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -387,6 +387,33 @@ int parse_events_add_cache(struct list_head *list, int *idx, return add_event(list, idx, &attr, name, NULL); } +static void tracepoint_error(struct parse_events_error *error, int err, + char *sys, char *name) +{ + char help[BUFSIZ]; + + /* + * We get error directly from syscall errno ( > 0), + * or from encoded pointer's error ( < 0). + */ + err = abs(err); + + switch (err) { + case EACCES: + error->str = strdup("can't access trace events"); + break; + case ENOENT: + error->str = strdup("unknown tracepoint"); + break; + default: + error->str = strdup("failed to add tracepoint"); + break; + } + + tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); + error->help = strdup(help); +} + static int add_tracepoint(struct list_head *list, int *idx, char *sys_name, char *evt_name, struct parse_events_error *error __maybe_unused) @@ -394,8 +421,10 @@ static int add_tracepoint(struct list_head *list, int *idx, struct perf_evsel *evsel; evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); - if (IS_ERR(evsel)) + if (IS_ERR(evsel)) { + tracepoint_error(error, PTR_ERR(evsel), sys_name, evt_name); return PTR_ERR(evsel); + } list_add_tail(&evsel->node, list); return 0; @@ -413,7 +442,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); evt_dir = opendir(evt_path); if (!evt_dir) { - perror("Can't open event dir"); + tracepoint_error(error, errno, sys_name, evt_name); return -1; } @@ -453,7 +482,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, events_dir = opendir(tracing_events_path); if (!events_dir) { - perror("Can't open event dir"); + tracepoint_error(error, errno, sys_name, evt_name); return -1; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 54a3004a8192..8bcc45868457 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -371,28 +371,30 @@ event_legacy_tracepoint: PE_NAME '-' PE_NAME ':' PE_NAME { struct parse_events_evlist *data = _data; + struct parse_events_error *error = data->error; struct list_head *list; char sys_name[128]; snprintf(&sys_name, 128, "%s-%s", $1, $3); ALLOC_LIST(list); - ABORT_ON(parse_events_add_tracepoint(list, &data->idx, &sys_name, $5, data->error)); + if (parse_events_add_tracepoint(list, &data->idx, &sys_name, $5, error)) { + if (error) + error->idx = @1.first_column; + return -1; + } $$ = list; } | PE_NAME ':' PE_NAME { struct parse_events_evlist *data = _data; + struct parse_events_error *error = data->error; struct list_head *list; ALLOC_LIST(list); - if (parse_events_add_tracepoint(list, &data->idx, $1, $3, data->error)) { - struct parse_events_error *error = data->error; - - if (error) { + if (parse_events_add_tracepoint(list, &data->idx, $1, $3, error)) { + if (error) error->idx = @1.first_column; - error->str = strdup("unknown tracepoint"); - } return -1; } $$ = list; From 63ab024a5b6f295ca17a293ad81b7c728f49a89a Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Mon, 14 Sep 2015 23:02:49 -0300 Subject: [PATCH 082/260] perf tools: regs_query_register_offset() infrastructure regs_query_register_offset() is a helper function which converts register name like "%rax" to offset of a register in 'struct pt_regs', which is required by BPF prologue generator. PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET indicates an architecture supports converting name of a register to its offset in 'struct pt_regs'. HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET is introduced as the corresponding CFLAGS of PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET. Signed-off-by: Wang Nan Acked-by: Masami Hiramatsu Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: Jiri Olsa Cc: Kaixu Xia Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441523623-152703-19-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang [ Extracted from eBPF patches ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/config/Makefile | 4 ++++ tools/perf/util/include/dwarf-regs.h | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index 827557fc7511..0435ac41cea9 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -109,6 +109,10 @@ endif # include ARCH specific config -include $(src-perf)/arch/$(ARCH)/Makefile +ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET + CFLAGS += -DHAVE_ARCH_REGS_QUERY_REGISTER_OFFSET +endif + include $(src-perf)/config/utilities.mak ifeq ($(call get-executable,$(FLEX)),) diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h index 8f149655f497..07c644ed64c4 100644 --- a/tools/perf/util/include/dwarf-regs.h +++ b/tools/perf/util/include/dwarf-regs.h @@ -5,4 +5,12 @@ const char *get_arch_regstr(unsigned int n); #endif +#ifdef HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET +/* + * Arch should support fetching the offset of a register in pt_regs + * by its name. See kernel's regs_query_register_offset in + * arch/xxx/kernel/ptrace.c. + */ +int regs_query_register_offset(const char *name); +#endif #endif From bbbe6bf6037d77816c4a19aaf35f4cecf662b49a Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Sun, 6 Sep 2015 07:13:35 +0000 Subject: [PATCH 083/260] perf tools: Introduce regs_query_register_offset() for x86 regs_query_register_offset() is a helper function which converts register name like "%rax" to offset of a register in 'struct pt_regs', which is required by BPF prologue generator. Since the function is identical, try to reuse the code in arch/x86/kernel/ptrace.c. Comment inside dwarf-regs.c list the differences between this implementation and kernel code. get_arch_regstr() switches to regoffset_table and the old string table is dropped. Signed-off-by: He Kuang Acked-by: Masami Hiramatsu Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441523623-152703-20-git-send-email-wangnan0@huawei.com Signed-off-by: Wang Nan Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/Makefile | 1 + tools/perf/arch/x86/util/dwarf-regs.c | 122 +++++++++++++++++++------- 2 files changed, 89 insertions(+), 34 deletions(-) diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 21322e0385b8..09ba923debe8 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile @@ -2,3 +2,4 @@ ifndef NO_DWARF PERF_HAVE_DWARF_REGS := 1 endif HAVE_KVM_STAT_SUPPORT := 1 +PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index a08de0a35b83..9223c164e545 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c @@ -21,55 +21,109 @@ */ #include +#include /* for EINVAL */ +#include /* for strcmp */ +#include /* for struct pt_regs */ +#include /* for offsetof */ #include /* - * Generic dwarf analysis helpers + * See arch/x86/kernel/ptrace.c. + * Different from it: + * + * - Since struct pt_regs is defined differently for user and kernel, + * but we want to use 'ax, bx' instead of 'rax, rbx' (which is struct + * field name of user's pt_regs), we make REG_OFFSET_NAME to accept + * both string name and reg field name. + * + * - Since accessing x86_32's pt_regs from x86_64 building is difficult + * and vise versa, we simply fill offset with -1, so + * get_arch_regstr() still works but regs_query_register_offset() + * returns error. + * The only inconvenience caused by it now is that we are not allowed + * to generate BPF prologue for a x86_64 kernel if perf is built for + * x86_32. This is really a rare usecase. + * + * - Order is different from kernel's ptrace.c for get_arch_regstr(). Use + * the order defined by dwarf. */ -#define X86_32_MAX_REGS 8 -const char *x86_32_regs_table[X86_32_MAX_REGS] = { - "%ax", - "%cx", - "%dx", - "%bx", - "$stack", /* Stack address instead of %sp */ - "%bp", - "%si", - "%di", +struct pt_regs_offset { + const char *name; + int offset; }; -#define X86_64_MAX_REGS 16 -const char *x86_64_regs_table[X86_64_MAX_REGS] = { - "%ax", - "%dx", - "%cx", - "%bx", - "%si", - "%di", - "%bp", - "%sp", - "%r8", - "%r9", - "%r10", - "%r11", - "%r12", - "%r13", - "%r14", - "%r15", +#define REG_OFFSET_END {.name = NULL, .offset = 0} + +#ifdef __x86_64__ +# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} +# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = -1} +#else +# define REG_OFFSET_NAME_64(n, r) {.name = n, .offset = -1} +# define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} +#endif + +static const struct pt_regs_offset x86_32_regoffset_table[] = { + REG_OFFSET_NAME_32("%ax", eax), + REG_OFFSET_NAME_32("%cx", ecx), + REG_OFFSET_NAME_32("%dx", edx), + REG_OFFSET_NAME_32("%bx", ebx), + REG_OFFSET_NAME_32("$stack", esp), /* Stack address instead of %sp */ + REG_OFFSET_NAME_32("%bp", ebp), + REG_OFFSET_NAME_32("%si", esi), + REG_OFFSET_NAME_32("%di", edi), + REG_OFFSET_END, +}; + +static const struct pt_regs_offset x86_64_regoffset_table[] = { + REG_OFFSET_NAME_64("%ax", rax), + REG_OFFSET_NAME_64("%dx", rdx), + REG_OFFSET_NAME_64("%cx", rcx), + REG_OFFSET_NAME_64("%bx", rbx), + REG_OFFSET_NAME_64("%si", rsi), + REG_OFFSET_NAME_64("%di", rdi), + REG_OFFSET_NAME_64("%bp", rbp), + REG_OFFSET_NAME_64("%sp", rsp), + REG_OFFSET_NAME_64("%r8", r8), + REG_OFFSET_NAME_64("%r9", r9), + REG_OFFSET_NAME_64("%r10", r10), + REG_OFFSET_NAME_64("%r11", r11), + REG_OFFSET_NAME_64("%r12", r12), + REG_OFFSET_NAME_64("%r13", r13), + REG_OFFSET_NAME_64("%r14", r14), + REG_OFFSET_NAME_64("%r15", r15), + REG_OFFSET_END, }; /* TODO: switching by dwarf address size */ #ifdef __x86_64__ -#define ARCH_MAX_REGS X86_64_MAX_REGS -#define arch_regs_table x86_64_regs_table +#define regoffset_table x86_64_regoffset_table #else -#define ARCH_MAX_REGS X86_32_MAX_REGS -#define arch_regs_table x86_32_regs_table +#define regoffset_table x86_32_regoffset_table #endif +/* Minus 1 for the ending REG_OFFSET_END */ +#define ARCH_MAX_REGS ((sizeof(regoffset_table) / sizeof(regoffset_table[0])) - 1) + /* Return architecture dependent register string (for kprobe-tracer) */ const char *get_arch_regstr(unsigned int n) { - return (n < ARCH_MAX_REGS) ? arch_regs_table[n] : NULL; + return (n < ARCH_MAX_REGS) ? regoffset_table[n].name : NULL; +} + +/* Reuse code from arch/x86/kernel/ptrace.c */ +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; } From 96f3eda67fcf2598e9d2794398e0e7ab35138ea6 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Mon, 14 Sep 2015 10:14:07 -0400 Subject: [PATCH 084/260] perf/x86/intel: Fix static checker warning in lbr enable Commit deb27519bf1f ("perf/x86/intel: Fix LBR callstack issue caused by FREEZE_LBRS_ON_PMI") leads to the following Smatch complaint: warn: variable dereferenced before check 'cpuc->lbr_sel' (see line 154) Fix the warning. Reported-by: Dan Carpenter Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: deb27519bf1f ("perf/x86/intel: Fix LBR callstack issue caused by FREEZE_LBRS_ON_PMI") Link: http://lkml.kernel.org/r/1442240047-48149-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index a1d07c71d3b6..ad0b8b0490a0 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -151,8 +151,9 @@ static void __intel_pmu_lbr_enable(bool pmi) * No need to reprogram LBR_SELECT in a PMI, as it * did not change. */ - lbr_select = cpuc->lbr_sel->config; - if (cpuc->lbr_sel && !pmi) + if (cpuc->lbr_sel) + lbr_select = cpuc->lbr_sel->config; + if (!pmi) wrmsrl(MSR_LBR_SELECT, lbr_select); rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl); From 0fb18553478dee5b3d8dc0af4f99a5288e81142f Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 16 Sep 2015 21:52:42 +0900 Subject: [PATCH 085/260] perf probe: Fix a segfault when removing uprobe events Fix a segfault bug and a small mistake in perf probe -d. Since the "ulist" in perf_del_probe_events is never initialized, strlist__add(ulist, *) always causes a segfault when removing uprobe events by perf probe -d. Also, the "str" local variable is never released if fail to allocate the "klist". This fixes it too. This has been introduced by the commit e607f1426b58 ("perf probe: Print deleted events in cmd_probe()"). Reported-by: Milian Wolff Signed-off-by: Masami Hiramatsu Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20150916125241.4446.44805.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 94385ee89dc8..f7882ae9ebc6 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -380,8 +380,11 @@ static int perf_del_probe_events(struct strfilter *filter) goto out; klist = strlist__new(NULL, NULL); - if (!klist) - return -ENOMEM; + ulist = strlist__new(NULL, NULL); + if (!klist || !ulist) { + ret = -ENOMEM; + goto out; + } ret = probe_file__get_events(kfd, filter, klist); if (ret == 0) { From 854f736364c659046f066a98fed2fdb10a39577a Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Sun, 6 Sep 2015 07:13:17 +0000 Subject: [PATCH 086/260] perf tools: Don't assume that the parser returns non empty evsel list Don't blindly retrieve and use a last element in the lists returned by parse_events__scanner(), as it may have collected no entries, i.e. return an empty list. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441523623-152703-2-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 0fde5293a38e..61c2bc20926d 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -827,6 +827,11 @@ void parse_events__set_leader(char *name, struct list_head *list) { struct perf_evsel *leader; + if (list_empty(list)) { + WARN_ONCE(true, "WARNING: failed to set leader: empty list"); + return; + } + __perf_evlist__set_leader(list); leader = list_entry(list->next, struct perf_evsel, node); leader->group_name = name ? strdup(name) : NULL; @@ -1176,6 +1181,11 @@ int parse_events(struct perf_evlist *evlist, const char *str, if (!ret) { struct perf_evsel *last; + if (list_empty(&data.list)) { + WARN_ONCE(true, "WARNING: event parser found nothing"); + return -1; + } + perf_evlist__splice_list_tail(evlist, &data.list); evlist->nr_groups += data.nr_groups; last = perf_evlist__last(evlist); @@ -1285,6 +1295,12 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist, struct perf_evsel *last = NULL; int err; + /* + * Don't return when list_empty, give func a chance to report + * error when it found last == NULL. + * + * So no need to WARN here, let *func do this. + */ if (evlist->nr_entries > 0) last = perf_evlist__last(evlist); From 6076e2a47cccfb3d48a8d165853c0b799c563df7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Sep 2015 11:49:51 -0300 Subject: [PATCH 087/260] tools build: Fixup feature detection display function name Cut'n'paste mistake, it should eval the name of the function defined right next to it, in the next line, fix it. Before: $ make -C tools/lib/bpf/ make: Entering directory '/home/git/linux/tools/lib/bpf' Auto-detecting system features: ... libelf: [ on ] ... libelf-getphdrnum: [ on ] ... libelf-mmap: [ on ] ... bpf: [ on ] After: $ make -C tools/lib/bpf/ make: Entering directory '/home/git/linux/tools/lib/bpf' Auto-detecting system features: ... libelf: [ on ] ... libelf-getphdrnum: [ OFF ] ... libelf-mmap: [ OFF ] ... bpf: [ on ] Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Cc: pi3orama@163.com Fixes: 58d4f00ff13f ("perf build: Fix feature_check name clash") Link: http://lkml.kernel.org/n/tip-dzu1c4sruukgfq5d5b1c4r30@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index c8fe6d177119..690d5614edd4 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -140,7 +140,7 @@ ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)") feature_display := 1 endif -feature_display_check = $(eval $(feature_check_code)) +feature_display_check = $(eval $(feature_check_display_code)) define feature_display_check_code ifneq ($(feature-$(1)), 1) feature_display := 1 From 20517cd9c5930c9ef580082d23073842e92249ad Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Sep 2015 17:00:27 -0300 Subject: [PATCH 088/260] tools lib bpf: Fix up FEATURE_{TESTS,DISPLAY} usage When libbpf was introduced it wrongly asked for the "libelf" and "bpf" feature tests to be performed (via FEATURE_TESTS), while asking that "libbpf", "libelf-mmap", "libelf-getphdrnum" and "bpf" to have the result of its respective tests to be displayed (via FEATURE_DISPLAY). Due to another recently bug fixed in the tools/build/ infrastructure ("tools build: Fixup feature detection display function name") the results for the entries in the FEATURE_DISPLAY, for this case, were appearing as all succeeding, when two of them (the ones only on the DISPLAY) were not even being performed. Before: $ make -C tools/lib/bpf/ make: Entering directory '/home/git/linux/tools/lib/bpf' Auto-detecting system features: ... libelf: [ on ] ... libelf-getphdrnum: [ OFF ] ... libelf-mmap: [ OFF ] ... bpf: [ on ] After, with FEATURE_TESTS == FEATURE_DISPLAY: Auto-detecting system features: ... libelf: [ on ] ... libelf-getphdrnum: [ on ] ... libelf-mmap: [ on ] ... bpf: [ on ] I just inverted, so that it tests the four features but displays just the libelf and mmap ones, to make it more compact. So it becomes: $ make -C tools/lib/bpf/ make: Entering directory '/home/git/linux/tools/lib/bpf' Auto-detecting system features: ... libelf: [ on ] ... bpf: [ on ] Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Cc: pi3orama@163.com Fixes: 1b76c13e4b36 ("bpf tools: Introduce 'bpf' library and add bpf feature check") Link: http://lkml.kernel.org/n/tip-y4bd59e6j9rzzojiyeqrg2jq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/bpf/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index f68d23a0b487..604c12081b4b 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -64,8 +64,8 @@ srctree := $(patsubst %/,%,$(dir $(srctree))) #$(info Determined 'srctree' to be $(srctree)) endif -FEATURE_DISPLAY = libelf libelf-getphdrnum libelf-mmap bpf -FEATURE_TESTS = libelf bpf +FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf +FEATURE_DISPLAY = libelf bpf INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) From 13e96db61c1c32cd4c8102a95129bb7677cc746d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Sep 2015 12:24:47 -0300 Subject: [PATCH 089/260] tools build: Allow setting the feature detection user We will use the tools/build/ autodetection in the eBPF patchkit and it is currently sharing the output directory with perf, that also uses the feature detection logic. As we keep state in the output directory, so that we can avoid running all the tests again, we need to have different filenames for the files used in this state, allow doing that via the FEATURE_USER variable, to be set alongside the existing FEATURE_{TEST,DISPLAY} variables. v2: Fix comment describing the FEATURE_DUMP filename to make sure where it is created, precisely at $(OUTPUT)FEATURE-DUMP$(FEATURE_USER). Pointed out by Jiri. Acked-by: Jiri Olsa Cc: Alexei Starovoitov Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/n/tip-fdbev0vrn3x6idqc3ajbnvcb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.feature | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 690d5614edd4..72817e4d5e70 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -121,8 +121,9 @@ define feature_print_text_code MSG = $(shell printf '...%30s: %s' $(1) $(2)) endef +FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER) FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat)))) -FEATURE_DUMP_FILE := $(shell touch $(OUTPUT)FEATURE-DUMP; cat $(OUTPUT)FEATURE-DUMP) +FEATURE_DUMP_FILE := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME)) ifeq ($(dwarf-post-unwind),1) FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text)) @@ -131,12 +132,12 @@ endif # The $(feature_display) controls the default detection message # output. It's set if: # - detected features differes from stored features from -# last build (in FEATURE-DUMP file) +# last build (in $(FEATURE_DUMP_FILENAME) file) # - one of the $(FEATURE_DISPLAY) is not detected # - VF is enabled ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)") - $(shell echo "$(FEATURE_DUMP)" > $(OUTPUT)FEATURE-DUMP) + $(shell echo "$(FEATURE_DUMP)" > $(FEATURE_DUMP_FILENAME)) feature_display := 1 endif From 65f041bee7838e2a91dbbc0a917d9291adbb3484 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 21 Sep 2015 17:25:27 -0300 Subject: [PATCH 090/260] tools lib bpf: Use FEATURE_USER to allow building in the same dir as perf When building tools/lib/bpf as part of the tools/perf/ build process, which will happend when we introduce a patch wiring that up, we end up stomping on the feature detection caching mechanism, that uses a file in the output directory (O=) that is shared by libbpf and perf to check if something changed from one build to another that requires redoing the feature detection process. By using the recently introduced FEATURE_USER tools/build/ knob, we can avoid that: Before, every make invokation would run the feature detection: $ make O=/tmp/build/perf -C tools/perf make: Entering directory '/home/git/linux/tools/perf' Auto-detecting system features: ... dwarf: [ on ] ... glibc: [ on ] ... get_cpuid: [ on ] ... bpf: [ on ] GEN perf-archive GEN perf-with-kcore Auto-detecting system features: ... libelf: [ on ] ... bpf: [ on ] After: $ make O=/tmp/build/perf -C tools/perf make: Entering directory '/home/git/linux/tools/perf' BUILD: Doing 'make -j4' parallel build make: Leaving directory '/home/git/linux/tools/perf' $ Because we now have two different feature detection state files: $ ls -la /tmp/build/perf/FEATURE-DUMP* -rw-rw-r--. 1 acme acme 338 Sep 21 17:25 /tmp/build/perf/FEATURE-DUMP -rw-rw-r--. 1 acme acme 33 Sep 21 17:25 /tmp/build/perf/FEATURE-DUMP.libbpf $ Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Cc: pi3orama@163.com Fixes: 1b76c13e4b36 ("bpf tools: Introduce 'bpf' library and add bpf feature check") Link: http://lkml.kernel.org/n/tip-s6ev9wfqy7pvvs58emys2g90@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/bpf/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index 604c12081b4b..e630f9fc4fb6 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -64,6 +64,7 @@ srctree := $(patsubst %/,%,$(dir $(srctree))) #$(info Determined 'srctree' to be $(srctree)) endif +FEATURE_USER = .libbpf FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf FEATURE_DISPLAY = libelf bpf From 96d8bf75da12df17f2c861043158dad2dabfe491 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 21 Sep 2015 16:35:43 +0200 Subject: [PATCH 091/260] perf tools: Add include/err.h into MANIFEST Otherwise the tarpkg is incomplete (tarpkg tests fails). Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Fixes: 01ca9fd41d6f ("tools: Add err.h with ERR_PTR PTR_ERR interface") Link: http://lkml.kernel.org/r/1442846143-8556-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/MANIFEST | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 2a958a80c763..9e6bdf5b2df6 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -50,6 +50,7 @@ tools/include/linux/poison.h tools/include/linux/rbtree.h tools/include/linux/rbtree_augmented.h tools/include/linux/types.h +tools/include/linux/err.h include/asm-generic/bitops/arch_hweight.h include/asm-generic/bitops/const_hweight.h include/asm-generic/bitops/fls64.h From f6489bc2d402c0db84aa64f13b864d17f7eecb07 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 22 Sep 2015 13:13:04 -0300 Subject: [PATCH 092/260] tools vm: Fix build due to removal of tools/lib/api/fs/debugfs.h There were some changes in how this debugfs mounting helper is implemented/exported and we forgot to check if there were other users besides perf, fix it. Need to do a make -C tools/ everytime we do changes to tools/{lib,include} and other places where we're moving things from tools/perf/ to be used by other tools/ living code. Fixed: $ make -C tools/vm make: Entering directory '/home/git/linux/tools/vm' make -C ../lib/api make[1]: Entering directory '/home/git/linux/tools/lib/api' CC fd/array.o LD fd/libapi-in.o CC fs/fs.o CC fs/tracing_path.o LD fs/libapi-in.o CC cpu.o LD libapi-in.o AR libapi.a make[1]: Leaving directory '/home/git/linux/tools/lib/api' gcc -Wall -Wextra -I../lib/ -o page-types page-types.c ../lib/api/libapi.a make: Leaving directory '/home/git/linux/tools/vm' $ Reported-by: Vinson Lee Tested-by: Vinson Lee Cc: Steven Rostedt Cc: Jiri Olsa Cc: Matt Fleming Cc: Raphael Beamonte Cc: H. Peter Anvin Cc: Peter Zijlstra Cc: David Ahern Cc: Thomas Gleixner Cc: Namhyung Kim Fixes: 60a1133a5b39 ("tools lib api fs: Remove debugfs, tracefs and findfs objects") Signed-off-by: Arnaldo Carvalho de Melo --- tools/vm/page-types.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 7f73fa32a590..bcf5ec760eb9 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -42,7 +42,7 @@ #include #include "../../include/uapi/linux/magic.h" #include "../../include/uapi/linux/kernel-page-flags.h" -#include +#include #ifndef MAX_PATH # define MAX_PATH 256 @@ -188,7 +188,7 @@ static int kpageflags_fd; static int opt_hwpoison; static int opt_unpoison; -static char *hwpoison_debug_fs; +static const char *hwpoison_debug_fs; static int hwpoison_inject_fd; static int hwpoison_forget_fd; @@ -487,7 +487,7 @@ static void prepare_hwpoison_fd(void) { char buf[MAX_PATH + 1]; - hwpoison_debug_fs = debugfs_mount(NULL); + hwpoison_debug_fs = debugfs__mount(); if (!hwpoison_debug_fs) { perror("mount debugfs"); exit(EXIT_FAILURE); From e803cf97a4f90d31bcc2c9a1ea20fe9cdc12b2f9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 22 Sep 2015 09:24:55 +0900 Subject: [PATCH 093/260] perf record: Synthesize COMM event for a command line workload When perf creates a new child to profile, the events are enabled on exec(). And in this case, it doesn't synthesize any event for the child since they'll be generated during exec(). But there's an window between the enabling and the event generation. It used to be overcome since samples are only in kernel (so we always have the map) and the comm is overridden by a later COMM event. However it won't work if events are processed and displayed before the COMM event overrides like in 'perf script'. This leads to those early samples (like native_write_msr_safe) not having a comm but pid (like ':15328'). So it needs to synthesize COMM event for the child explicitly before enabling so that it can have a correct comm. But at this time, the comm will be "perf" since it's not exec-ed yet. Committer note: Before this patch: # perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.017 MB perf.data (7 samples) ] # perf script --show-task-events :4429 4429 27909.079372: 1 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. :4429 4429 27909.079375: 1 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. :4429 4429 27909.079376: 10 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. :4429 4429 27909.079377: 223 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. :4429 4429 27909.079378: 6571 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. usleep 4429 27909.079380: PERF_RECORD_COMM exec: usleep:4429/4429 usleep 4429 27909.079381: 185403 cycles: ffffffff810a72d3 flush_signal_handlers (/lib/modules/4. usleep 4429 27909.079444: 2241110 cycles: 7fc575355be3 _dl_start (/usr/lib64/ld-2.20.so) usleep 4429 27909.079875: PERF_RECORD_EXIT(4429:4429):(4429:4429) After: # perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.017 MB perf.data (7 samples) ] # perf script --show-task perf 0 0.000000: PERF_RECORD_COMM: perf:8446/8446 perf 8446 30154.038944: 1 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. perf 8446 30154.038948: 1 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. perf 8446 30154.038949: 9 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. perf 8446 30154.038950: 230 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. perf 8446 30154.038951: 6772 cycles: ffffffff8105f45a native_write_msr_safe (/lib/modules/4. usleep 8446 30154.038952: PERF_RECORD_COMM exec: usleep:8446/8446 usleep 8446 30154.038954: 196923 cycles: ffffffff81766440 _raw_spin_lock (/lib/modules/4.3.0-rc1 usleep 8446 30154.039021: 2292130 cycles: 7f609a173dc4 memcpy (/usr/lib64/ld-2.20.so) usleep 8446 30154.039349: PERF_RECORD_EXIT(8446:8446):(8446:8446) # Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1442881495-2928-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 15 ++++++++++++++- tools/perf/util/event.c | 2 +- tools/perf/util/event.h | 5 +++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 142eeb341b29..a01c8ae1ee07 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -636,8 +636,21 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) /* * Let the child rip */ - if (forks) + if (forks) { + union perf_event event; + /* + * Some H/W events are generated before COMM event + * which is emitted during exec(), so perf script + * cannot see a correct process name for those events. + * Synthesize COMM event to prevent it. + */ + perf_event__synthesize_comm(tool, &event, + rec->evlist->workload.pid, + process_synthesized_event, + machine); + perf_evlist__start_workload(rec->evlist); + } if (opts->initial_delay) { usleep(opts->initial_delay * 1000); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 497157affc9c..6214ad47d554 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -167,7 +167,7 @@ static int perf_event__prepare_comm(union perf_event *event, pid_t pid, return 0; } -static pid_t perf_event__synthesize_comm(struct perf_tool *tool, +pid_t perf_event__synthesize_comm(struct perf_tool *tool, union perf_event *event, pid_t pid, perf_event__handler_t process, struct machine *machine) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index f729df5e25e6..be5cbc7be889 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -478,6 +478,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, const struct perf_sample *sample, bool swapped); +pid_t perf_event__synthesize_comm(struct perf_tool *tool, + union perf_event *event, pid_t pid, + perf_event__handler_t process, + struct machine *machine); + int perf_event__synthesize_mmap_events(struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, From 18ab2cd3ee9d52dc64c5ae984146a261a328c4e8 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Sun, 27 Sep 2015 23:25:50 +0800 Subject: [PATCH 094/260] perf/core, perf/x86: Change needlessly global functions and a variable to static Fixes various sparse warnings. Signed-off-by: Geliang Tang Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/70c14234da1bed6e3e67b9c419e2d5e376ab4f32.1443367286.git.geliangtang@163.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/intel_cacheinfo.c | 8 ++++---- kernel/events/core.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index be4febc58b94..e38d338a6447 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -157,7 +157,7 @@ struct _cpuid4_info_regs { struct amd_northbridge *nb; }; -unsigned short num_cache_leaves; +static unsigned short num_cache_leaves; /* AMD doesn't have CPUID4. Emulate it here to report the same information to the user. This makes some assumptions about the machine: @@ -326,7 +326,7 @@ static void amd_calc_l3_indices(struct amd_northbridge *nb) * * @returns: the disabled index if used or negative value if slot free. */ -int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot) +static int amd_get_l3_disable_slot(struct amd_northbridge *nb, unsigned slot) { unsigned int reg = 0; @@ -403,8 +403,8 @@ static void amd_l3_disable_index(struct amd_northbridge *nb, int cpu, * * @return: 0 on success, error status on failure */ -int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, unsigned slot, - unsigned long index) +static int amd_set_l3_disable_slot(struct amd_northbridge *nb, int cpu, + unsigned slot, unsigned long index) { int ret = 0; diff --git a/kernel/events/core.c b/kernel/events/core.c index f87b434c3c1e..ea02109aee77 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -196,7 +196,7 @@ static int perf_sample_period_ns __read_mostly = DEFAULT_SAMPLE_PERIOD_NS; static int perf_sample_allowed_ns __read_mostly = DEFAULT_SAMPLE_PERIOD_NS * DEFAULT_CPU_TIME_MAX_PERCENT / 100; -void update_perf_cpu_limits(void) +static void update_perf_cpu_limits(void) { u64 tmp = perf_sample_period_ns; @@ -472,7 +472,7 @@ perf_cgroup_set_timestamp(struct task_struct *task, * mode SWOUT : schedule out everything * mode SWIN : schedule in based on cgroup for next */ -void perf_cgroup_switch(struct task_struct *task, int mode) +static void perf_cgroup_switch(struct task_struct *task, int mode) { struct perf_cpu_context *cpuctx; struct pmu *pmu; @@ -7390,7 +7390,7 @@ static int perf_pmu_nop_int(struct pmu *pmu) return 0; } -DEFINE_PER_CPU(unsigned int, nop_txn_flags); +static DEFINE_PER_CPU(unsigned int, nop_txn_flags); static void perf_pmu_start_txn(struct pmu *pmu, unsigned int flags) { @@ -7750,7 +7750,7 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event) return ret; } -struct pmu *perf_init_event(struct perf_event *event) +static struct pmu *perf_init_event(struct perf_event *event) { struct pmu *pmu = NULL; int idx; From cfc5acd4c80b875d2f739d6a93562034aee5563f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 23 Sep 2015 15:15:54 -0300 Subject: [PATCH 095/260] perf top: Filter symbols based on __map__is_kernel(map) Instead of using dso->kernel, this is equivalent at the moment, and helps in reducing the accesses to dso->kernel. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1pc2v63iphtifovw3bv0bo1v@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bdaf44f24d5d..38d4d6cac823 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -655,7 +655,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) { const char *name = sym->name; - if (!map->dso->kernel) + if (!__map__is_kernel(map)) return 0; /* * ppc64 uses function descriptors and appends a '.' to the From 045b80dd03403b8e61a29460987c231317ebfbd4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 23 Sep 2015 15:38:55 -0300 Subject: [PATCH 096/260] perf hists browser: Use the map to determine if a DSO is being used as a kernel The map is what should say if an ELF (or some other format) image is being used for some particular purpose, as a kernel, host or guest. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-zufousvfar0710p4qj71c32d@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e1f28f4cdc8e..a4e9b370c037 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1527,7 +1527,7 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, static int do_zoom_dso(struct hist_browser *browser, struct popup_action *act) { - struct dso *dso = act->dso; + struct map *map = act->ms.map; if (browser->hists->dso_filter) { pstack__remove(browser->pstack, &browser->hists->dso_filter); @@ -1535,11 +1535,11 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) browser->hists->dso_filter = NULL; ui_helpline__pop(); } else { - if (dso == NULL) + if (map == NULL) return 0; ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", - dso->kernel ? "the Kernel" : dso->short_name); - browser->hists->dso_filter = dso; + __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); + browser->hists->dso_filter = map->dso; perf_hpp__set_elide(HISTC_DSO, true); pstack__push(browser->pstack, &browser->hists->dso_filter); } @@ -1551,17 +1551,18 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) static int add_dso_opt(struct hist_browser *browser, struct popup_action *act, - char **optstr, struct dso *dso) + char **optstr, struct map *map) { - if (dso == NULL) + if (map == NULL) return 0; if (asprintf(optstr, "Zoom %s %s DSO", browser->hists->dso_filter ? "out of" : "into", - dso->kernel ? "the Kernel" : dso->short_name) < 0) + __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) return 0; - act->dso = dso; + act->ms.map = map; + act->dso = map->dso; act->fn = do_zoom_dso; return 1; } @@ -1814,6 +1815,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, while (1) { struct thread *thread = NULL; struct dso *dso = NULL; + struct map *map = NULL; int choice = 0; int socked_id = -1; @@ -1823,7 +1825,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, if (browser->he_selection != NULL) { thread = hist_browser__selected_thread(browser); - dso = browser->selection->map ? browser->selection->map->dso : NULL; + map = browser->selection->map; + if (map) + dso = map->dso; socked_id = browser->he_selection->socket; } switch (key) { @@ -2014,7 +2018,7 @@ skip_annotation: nr_options += add_thread_opt(browser, &actions[nr_options], &options[nr_options], thread); nr_options += add_dso_opt(browser, &actions[nr_options], - &options[nr_options], dso); + &options[nr_options], map); nr_options += add_map_opt(browser, &actions[nr_options], &options[nr_options], browser->selection ? From ab9c2bdc8947482057b81258c0128952763661cb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 23 Sep 2015 15:45:20 -0300 Subject: [PATCH 097/260] perf tools: Use __map__is_kernel() when synthesizing kernel module mmap records Equivalent and removes one more case of using dso->kernel. # perf record -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.768 MB perf.data (30 samples) ] Before: [root@zoo ~]# perf script --show-task --show-mmap | head -3 swapper 0 [0] 0.0: PERF_RECORD_MMAP -1/0: [0xffffffff81000000(0x1f000000) @ 0xffffffff81000000]: x [kernel.kallsyms]_text swapper 0 [0] 0.0: PERF_RECORD_MMAP -1/0: [0xffffffffa0000000(0xa000) @ 0]: x /lib/modules/4.3.0-rc1+/kernel/drivers/acpi/video.ko swapper 0 [0] 0.0: PERF_RECORD_MMAP -1/0: [0xffffffffa000a000(0x5000) @ 0]: x /lib/modules/4.3.0-rc1+/kernel/drivers/i2c/algos/i2c-algo-bit.ko # # perf script --show-task --show-mmap | head -3 swapper 0 [0] 0.0: PERF_RECORD_MMAP -1/0: [0xffffffff81000000(0x1f000000) @ 0xffffffff81000000]: x [kernel.kallsyms]_text swapper 0 [0] 0.0: PERF_RECORD_MMAP -1/0: [0xffffffffa0000000(0xa000) @ 0]: x /lib/modules/4.3.0-rc1+/kernel/drivers/acpi/video.ko swapper 0 [0] 0.0: PERF_RECORD_MMAP -1/0: [0xffffffffa000a000(0x5000) @ 0]: x /lib/modules/4.3.0-rc1+/kernel/drivers/i2c/algos/i2c-algo-bit.ko # Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-b65xe578dwq22mzmmj5y94wr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 6214ad47d554..b1bb348ec3b6 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -378,7 +378,7 @@ int perf_event__synthesize_modules(struct perf_tool *tool, for (pos = maps__first(maps); pos; pos = map__next(pos)) { size_t size; - if (pos->dso->kernel) + if (__map__is_kernel(pos)) continue; size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); From dc240c5dc2a02e335c5bcb50ad3a1274818c8609 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sat, 19 Sep 2015 16:47:07 +0200 Subject: [PATCH 098/260] tools lib api fs: Store tracing mountpoint for better error message Storing the actual tracing path mountpoint to display correct error message hint ('Hint:' line). The error hint rediscovers mountpoints, but it could be different from what we actually used in tracing path. Before we'd display debugfs mount even though tracefs was used: $ perf record -e sched:sched_krava ls event syntax error: 'sched:sched_krava' \___ can't access trace events Error: No permissions to read /sys/kernel/debug/tracing/events/sched/sched_krava Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug' ... After this change, correct mountpoint is displayed: $ perf record -e sched:sched_krava ls event syntax error: 'sched:sched_krava' \___ can't access trace events Error: No permissions to read /sys/kernel/debug/tracing/events/sched/sched_krava Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/tracing' ... Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Link: http://lkml.kernel.org/r/1442674027-19427-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/tracing_path.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 38aca2dd1946..0406a7d5c891 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -12,12 +12,14 @@ #include "tracing_path.h" +char tracing_mnt[PATH_MAX + 1] = "/sys/kernel/debug"; char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing"; char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; static void __tracing_path_set(const char *tracing, const char *mountpoint) { + snprintf(tracing_mnt, sizeof(tracing_mnt), "%s", mountpoint); snprintf(tracing_path, sizeof(tracing_path), "%s/%s", mountpoint, tracing); snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s", @@ -109,19 +111,10 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); break; case EACCES: { - const char *mountpoint = debugfs__mountpoint(); - - if (!access(mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { - const char *tracefs_mntpoint = tracefs__mountpoint(); - - if (tracefs_mntpoint) - mountpoint = tracefs__mountpoint(); - } - snprintf(buf, size, "Error:\tNo permissions to read %s/%s\n" "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", - tracing_events_path, filename, mountpoint); + tracing_events_path, filename, tracing_mnt); } break; default: From ab6201d09b1840c7ffcd6606c1d3dae68b8b3048 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:33:56 +0200 Subject: [PATCH 099/260] tools build: Add Makefile.include To ease up build framework code setup for users. More shared code will be added in the following patches. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Documentation/Build.txt | 45 ++++++++++++++++++++--------- tools/build/Makefile.include | 1 + tools/build/tests/ex/Makefile | 3 +- tools/lib/api/Makefile | 2 +- tools/lib/bpf/Makefile | 2 +- tools/lib/lockdep/Makefile | 2 +- tools/perf/Makefile.perf | 2 +- 7 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 tools/build/Makefile.include diff --git a/tools/build/Documentation/Build.txt b/tools/build/Documentation/Build.txt index aa5e092c4352..88824359d595 100644 --- a/tools/build/Documentation/Build.txt +++ b/tools/build/Documentation/Build.txt @@ -11,8 +11,9 @@ Unlike the kernel we don't have a single build object 'obj-y' list that where we setup source objects, but we support more. This allows one 'Build' file to carry a sources list for multiple build objects. -a) Build framework makefiles ----------------------------- + +Build framework makefiles +------------------------- The build framework consists of 2 Makefiles: @@ -23,7 +24,7 @@ While the 'Build.include' file contains just some generic definitions, the 'Makefile.build' file is the makefile used from the outside. It's interface/usage is following: - $ make -f tools/build/Makefile srctree=$(KSRC) dir=$(DIR) obj=$(OBJECT) + $ make -f tools/build/Makefile.build srctree=$(KSRC) dir=$(DIR) obj=$(OBJECT) where: @@ -38,8 +39,9 @@ called $(OBJECT)-in.o: which includes all compiled sources described in 'Build' makefiles. -a) Build makefiles ------------------- + +Build makefiles +--------------- The user supplies 'Build' makefiles that contains a objects list, and connects the build to nested directories. @@ -95,8 +97,24 @@ It's only a matter of 2 single commands to create the final binaries: You can check the 'ex' example in 'tools/build/tests/ex' for more details. -b) Rules --------- + +Makefile.include +---------------- + +The tools/build/Makefile.include makefile could be included +via user makefiles to get usefull definitions. + +It defines following interface: + + - build macro definition: + build := -f $(srctree)/tools/build/Makefile.build dir=. obj + + to make it easier to invoke build like: + make $(build)=ex + + +Rules +----- The build framework provides standard compilation rules to handle .S and .c compilation. @@ -104,8 +122,9 @@ compilation. It's possible to include special rule if needed (like we do for flex or bison code generation). -c) CFLAGS ---------- + +CFLAGS +------ It's possible to alter the standard object C flags in the following way: @@ -115,8 +134,8 @@ It's possible to alter the standard object C flags in the following way: This C flags changes has the scope of the Build makefile they are defined in. -d) Dependencies ---------------- +Dependencies +------------ For each built object file 'a.o' the '.a.cmd' is created and holds: @@ -130,8 +149,8 @@ All existing '.cmd' files are included in the Build process to follow properly the dependencies and trigger a rebuild when necessary. -e) Single rules ---------------- +Single rules +------------ It's possible to build single object file by choice, like: diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include new file mode 100644 index 000000000000..91bc60616de5 --- /dev/null +++ b/tools/build/Makefile.include @@ -0,0 +1 @@ +build := -f $(srctree)/tools/build/Makefile.build dir=. obj diff --git a/tools/build/tests/ex/Makefile b/tools/build/tests/ex/Makefile index 52d2476073a3..a8f596e37fd2 100644 --- a/tools/build/tests/ex/Makefile +++ b/tools/build/tests/ex/Makefile @@ -3,7 +3,8 @@ export CC := gcc export LD := ld export AR := ar -build := -f $(srctree)/tools/build/Makefile.build dir=. obj +include $(srctree)/tools/build/Makefile.include + ex: ex-in.o libex-in.o gcc -o $@ $^ diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index fe1b02c2c95b..8806ea7c2f99 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -21,10 +21,10 @@ CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 RM = rm -f -build := -f $(srctree)/tools/build/Makefile.build dir=. obj API_IN := $(OUTPUT)libapi-in.o export srctree OUTPUT CC LD CFLAGS V +include $(srctree)/tools/build/Makefile.include all: $(LIBFILE) diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index e630f9fc4fb6..c66ade68d4a1 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -124,7 +124,7 @@ endif MAKEOVERRIDES= export srctree OUTPUT CC LD CFLAGS V -build := -f $(srctree)/tools/build/Makefile.build dir=. obj +include $(srctree)/tools/build/Makefile.include BPF_IN := $(OUTPUT)libbpf-in.o LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index 18ffccf00426..d12081da383b 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile @@ -94,7 +94,7 @@ else endif export srctree OUTPUT CC LD CFLAGS V -build := -f $(srctree)/tools/build/Makefile.build dir=. obj +include $(srctree)/tools/build/Makefile.include do_compile_shared_library = \ ($(print_shared_lib_compile) \ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 6c5c699002cb..6dec86665acc 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -297,7 +297,7 @@ strip: $(PROGRAMS) $(OUTPUT)perf PERF_IN := $(OUTPUT)perf-in.o export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK -build := -f $(srctree)/tools/build/Makefile.build dir=. obj +include $(srctree)/tools/build/Makefile.include $(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE $(Q)$(MAKE) $(build)=perf From 0c00c3fb4e4a6ff714b7ad864f58e0fb33b3534c Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:33:57 +0200 Subject: [PATCH 100/260] tools build: Add test for missing include The current build framework fails to cope with header file removal. The reason is that the removed header file stays in the .cmd file target rule and forces the build to fail. This issue is fixed and explained in the following patches. Adding a new build test that simulates header removal. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/tests/ex/Build | 1 + tools/build/tests/ex/Makefile | 2 +- tools/build/tests/ex/ex.c | 2 ++ tools/build/tests/ex/inc.c | 8 ++++++++ tools/build/tests/run.sh | 27 +++++++++++++++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tools/build/tests/ex/inc.c diff --git a/tools/build/tests/ex/Build b/tools/build/tests/ex/Build index 429c7d452101..4d502f9b1a50 100644 --- a/tools/build/tests/ex/Build +++ b/tools/build/tests/ex/Build @@ -4,6 +4,7 @@ ex-y += b.o ex-y += b.o ex-y += empty/ ex-y += empty2/ +ex-y += inc.o libex-y += c.o libex-y += d.o diff --git a/tools/build/tests/ex/Makefile b/tools/build/tests/ex/Makefile index a8f596e37fd2..f279b84cb859 100644 --- a/tools/build/tests/ex/Makefile +++ b/tools/build/tests/ex/Makefile @@ -1,4 +1,4 @@ -export srctree := ../../../.. +export srctree := $(abspath ../../../..) export CC := gcc export LD := ld export AR := ar diff --git a/tools/build/tests/ex/ex.c b/tools/build/tests/ex/ex.c index dc42eb2e1a67..57de6074d252 100644 --- a/tools/build/tests/ex/ex.c +++ b/tools/build/tests/ex/ex.c @@ -5,6 +5,7 @@ int c(void); int d(void); int e(void); int f(void); +int inc(void); int main(void) { @@ -14,6 +15,7 @@ int main(void) d(); e(); f(); + inc(); return 0; } diff --git a/tools/build/tests/ex/inc.c b/tools/build/tests/ex/inc.c new file mode 100644 index 000000000000..c20f1e9033a3 --- /dev/null +++ b/tools/build/tests/ex/inc.c @@ -0,0 +1,8 @@ +#ifdef INCLUDE +#include "krava.h" +#endif + +int inc(void) +{ + return 0; +} diff --git a/tools/build/tests/run.sh b/tools/build/tests/run.sh index 5494f8ea7567..44d2a0fade67 100755 --- a/tools/build/tests/run.sh +++ b/tools/build/tests/run.sh @@ -34,9 +34,36 @@ function test_ex_suffix { make -C ex V=1 clean > /dev/null 2>&1 rm -f ex.out } + +function test_ex_include { + make -C ex V=1 clean > ex.out 2>&1 + + # build with krava.h include + touch ex/krava.h + make -C ex V=1 CFLAGS=-DINCLUDE >> ex.out 2>&1 + + if [ ! -x ./ex/ex ]; then + echo FAILED + exit -1 + fi + + # build without the include + rm -f ex/krava.h ex/ex + make -C ex V=1 >> ex.out 2>&1 + + if [ ! -x ./ex/ex ]; then + echo FAILED + exit -1 + fi + + make -C ex V=1 clean > /dev/null 2>&1 + rm -f ex.out +} + echo -n Testing.. test_ex test_ex_suffix +test_ex_include echo OK From 9f7ef9854e800bc3bab3d9a527e8f8f960eec1a6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:33:58 +0200 Subject: [PATCH 101/260] tools build: Add fixdep dependency helper For dependency tracking we currently use targets that fall out of the gcc -MD command. We store this info in the .cmd file and include as makefile during the build. This format put object as target and all the c and header files as dependencies, like: util/abspath.o: util/abspath.c /usr/include/stdc-predef.h util/cache.h \ /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h \ ... If any of those dependency header files (krava.h below) is removed the build fails on: make[1]: *** No rule to make target 'krava.h', needed by 'inc.o'. Stop. This patch adds fixdep helper, that is used by kbuild to alter the shape of the object dependencies like: source_util/abspath.o := util/abspath.c deps_util/abspath.o := \ /usr/include/stdc-predef.h \ util/cache.h \ ... util/abspath.o: $(deps_util/abspath.o) $(deps_util/abspath.o): With this format the header removal won't make the build fail, because it'll be picked up by the last empty target defined for each header. As previously mentioned the fixdep tool is taken from kbuild. It's not complete backport, only the part that alters the standard dependency info was taken, the part that adds the CONFIG_* dependency logic will be probably taken later on. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Kai Germaschewski Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Build | 1 + tools/build/Makefile | 43 +++++++++++ tools/build/fixdep.c | 168 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 tools/build/Build create mode 100644 tools/build/Makefile create mode 100644 tools/build/fixdep.c diff --git a/tools/build/Build b/tools/build/Build new file mode 100644 index 000000000000..63a6c34c0c88 --- /dev/null +++ b/tools/build/Build @@ -0,0 +1 @@ +fixdep-y := fixdep.o diff --git a/tools/build/Makefile b/tools/build/Makefile new file mode 100644 index 000000000000..a93036272d43 --- /dev/null +++ b/tools/build/Makefile @@ -0,0 +1,43 @@ +ifeq ($(srctree),) +srctree := $(patsubst %/,%,$(dir $(shell pwd))) +srctree := $(patsubst %/,%,$(dir $(srctree))) +endif + +include $(srctree)/tools//scripts/Makefile.include + +define allow-override + $(if $(or $(findstring environment,$(origin $(1))),\ + $(findstring command line,$(origin $(1)))),,\ + $(eval $(1) = $(2))) +endef + +$(call allow-override,CC,$(CROSS_COMPILE)gcc) +$(call allow-override,LD,$(CROSS_COMPILE)ld) + +ifeq ($(V),1) + Q = +else + Q = @ +endif + +export Q srctree CC LD + +MAKEFLAGS := --no-print-directory +build := -f $(srctree)/tools/build/Makefile.build dir=. obj + +all: fixdep + +clean: + $(call QUIET_CLEAN, fixdep) + $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete + $(Q)rm -f fixdep + +$(OUTPUT)fixdep-in.o: FORCE + $(Q)$(MAKE) $(build)=fixdep + +$(OUTPUT)fixdep: $(OUTPUT)fixdep-in.o + $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $< + +FORCE: + +.PHONY: FORCE diff --git a/tools/build/fixdep.c b/tools/build/fixdep.c new file mode 100644 index 000000000000..1521d36cef0d --- /dev/null +++ b/tools/build/fixdep.c @@ -0,0 +1,168 @@ +/* + * "Optimize" a list of dependencies as spit out by gcc -MD + * for the build framework. + * + * Original author: + * Copyright 2002 by Kai Germaschewski + * + * This code has been borrowed from kbuild's fixdep (scripts/basic/fixdep.c), + * Please check it for detailed explanation. This fixdep borow only the + * base transformation of dependecies without the CONFIG mangle. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *target; +char *depfile; +char *cmdline; + +static void usage(void) +{ + fprintf(stderr, "Usage: fixdep \n"); + exit(1); +} + +/* + * Print out the commandline prefixed with cmd_ := + */ +static void print_cmdline(void) +{ + printf("cmd_%s := %s\n\n", target, cmdline); +} + +/* + * Important: The below generated source_foo.o and deps_foo.o variable + * assignments are parsed not only by make, but also by the rather simple + * parser in scripts/mod/sumversion.c. + */ +static void parse_dep_file(void *map, size_t len) +{ + char *m = map; + char *end = m + len; + char *p; + char s[PATH_MAX]; + int is_target; + int saw_any_target = 0; + int is_first_dep = 0; + + while (m < end) { + /* Skip any "white space" */ + while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) + m++; + /* Find next "white space" */ + p = m; + while (p < end && *p != ' ' && *p != '\\' && *p != '\n') + p++; + /* Is the token we found a target name? */ + is_target = (*(p-1) == ':'); + /* Don't write any target names into the dependency file */ + if (is_target) { + /* The /next/ file is the first dependency */ + is_first_dep = 1; + } else { + /* Save this token/filename */ + memcpy(s, m, p-m); + s[p - m] = 0; + + /* + * Do not list the source file as dependency, + * so that kbuild is not confused if a .c file + * is rewritten into .S or vice versa. Storing + * it in source_* is needed for modpost to + * compute srcversions. + */ + if (is_first_dep) { + /* + * If processing the concatenation of + * multiple dependency files, only + * process the first target name, which + * will be the original source name, + * and ignore any other target names, + * which will be intermediate temporary + * files. + */ + if (!saw_any_target) { + saw_any_target = 1; + printf("source_%s := %s\n\n", + target, s); + printf("deps_%s := \\\n", + target); + } + is_first_dep = 0; + } else + printf(" %s \\\n", s); + } + /* + * Start searching for next token immediately after the first + * "whitespace" character that follows this token. + */ + m = p + 1; + } + + if (!saw_any_target) { + fprintf(stderr, "fixdep: parse error; no targets found\n"); + exit(1); + } + + printf("\n%s: $(deps_%s)\n\n", target, target); + printf("$(deps_%s):\n", target); +} + +static void print_deps(void) +{ + struct stat st; + int fd; + void *map; + + fd = open(depfile, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "fixdep: error opening depfile: "); + perror(depfile); + exit(2); + } + if (fstat(fd, &st) < 0) { + fprintf(stderr, "fixdep: error fstat'ing depfile: "); + perror(depfile); + exit(2); + } + if (st.st_size == 0) { + fprintf(stderr, "fixdep: %s is empty\n", depfile); + close(fd); + return; + } + map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if ((long) map == -1) { + perror("fixdep: mmap"); + close(fd); + return; + } + + parse_dep_file(map, st.st_size); + + munmap(map, st.st_size); + + close(fd); +} + +int main(int argc, char **argv) +{ + if (argc != 4) + usage(); + + depfile = argv[1]; + target = argv[2]; + cmdline = argv[3]; + + print_cmdline(); + print_deps(); + + return 0; +} From 275e2d95591e2714d6b541d4e26959381d6b2705 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:33:59 +0200 Subject: [PATCH 102/260] tools build: Move dependency copy into function So it's easier to add more functionality in the following commit. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Build.include | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/build/Build.include b/tools/build/Build.include index 4c8daaccb82a..851c420098e7 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include @@ -54,15 +54,20 @@ make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) # PHONY targets skipped in both cases. any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) +### +# Copy dependency data into .cmd file +# - gcc -M dependency info +# - command line to create object 'cmd_object :=' +dep-cmd = cat $(depfile) > $(dot-target).cmd; \ + printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd + ### # if_changed_dep - execute command if any prerequisite is newer than # target, or command line has changed and update # dependencies in the cmd file if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \ @set -e; \ - $(echo-cmd) $(cmd_$(1)); \ - cat $(depfile) > $(dot-target).cmd; \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd) + $(echo-cmd) $(cmd_$(1)) && $(dep-cmd)) # if_changed - execute command if any prerequisite is newer than # target, or command line has changed From 9fb81323eb3085b6a47fe81d78541958ae7eaea3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:34:00 +0200 Subject: [PATCH 103/260] tools build: Make the fixdep helper part of the build process Making the fixdep helper to be invoked within dep-cmd. Each user of the build framework needs to make sure fixdep exists before executing the build itself. If the build doesn't find fixdep, it falls back to the old style dependency tracking. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Build.include | 10 ++++++++-- tools/build/Makefile.build | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/build/Build.include b/tools/build/Build.include index 851c420098e7..4d000bc959b4 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include @@ -58,8 +58,14 @@ any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) # Copy dependency data into .cmd file # - gcc -M dependency info # - command line to create object 'cmd_object :=' -dep-cmd = cat $(depfile) > $(dot-target).cmd; \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd +dep-cmd = $(if $(wildcard $(fixdep)), \ + $(fixdep) $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp; \ + rm -f $(depfile); \ + mv -f $(dot-target).tmp $(dot-target).cmd, \ + printf '\# cannot find fixdep (%s)\n' $(fixdep) > $(dot-target).cmd; \ + printf '\# using basic dep data\n\n' >> $(dot-target).cmd; \ + cat $(depfile) >> $(dot-target).cmd; \ + printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd) ### # if_changed_dep - execute command if any prerequisite is newer than diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index 0c5f485521d6..4a96473b180f 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build @@ -21,6 +21,13 @@ endif build-dir := $(srctree)/tools/build +# Define $(fixdep) for dep-cmd function +ifeq ($(OUTPUT),) + fixdep := $(build-dir)/fixdep +else + fixdep := $(OUTPUT)/fixdep +endif + # Generic definitions include $(build-dir)/Build.include From 324c824ade1cad094a21e6177b9aa7977146feeb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:34:01 +0200 Subject: [PATCH 104/260] perf tools: Rename the 'single_dep' target to 'prepare' And use the new 'prepare' target for the $(PERF_IN) target. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-7-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 6dec86665acc..25c1753ffbeb 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -299,7 +299,7 @@ PERF_IN := $(OUTPUT)perf-in.o export srctree OUTPUT RM CC LD AR CFLAGS V BISON FLEX AWK include $(srctree)/tools/build/Makefile.include -$(PERF_IN): $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h FORCE +$(PERF_IN): prepare FORCE $(Q)$(MAKE) $(build)=perf $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) @@ -349,27 +349,27 @@ endif __build-dir = $(subst $(OUTPUT),,$(dir $@)) build-dir = $(if $(__build-dir),$(__build-dir),.) -single_dep: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h +prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h -$(OUTPUT)%.o: %.c single_dep FORCE +$(OUTPUT)%.o: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ -$(OUTPUT)%.i: %.c single_dep FORCE +$(OUTPUT)%.i: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ -$(OUTPUT)%.s: %.c single_dep FORCE +$(OUTPUT)%.s: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ -$(OUTPUT)%-bison.o: %.c single_dep FORCE +$(OUTPUT)%-bison.o: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ -$(OUTPUT)%-flex.o: %.c single_dep FORCE +$(OUTPUT)%-flex.o: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ -$(OUTPUT)%.o: %.S single_dep FORCE +$(OUTPUT)%.o: %.S prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ -$(OUTPUT)%.i: %.S single_dep FORCE +$(OUTPUT)%.i: %.S prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ $(OUTPUT)perf-%: %.o $(PERFLIBS) @@ -591,6 +591,6 @@ FORCE: .PHONY: all install clean config-clean strip install-gtk .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell -.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE single_dep +.PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare .PHONY: libtraceevent_plugins From 7c422f5572667fef0db38d2046ecce69dcf0afc8 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 23 Sep 2015 12:34:02 +0200 Subject: [PATCH 105/260] tools build: Build fixdep helper from perf and basic libs Adding the fixdep target into the Makefile.include to ease up building of fixdep helper, that needs to be built before we dive in to the build itself. The user can invoke the fixdep target to build the helper. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443004442-32660-8-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Documentation/Build.txt | 7 +++++++ tools/build/Makefile.include | 5 +++++ tools/build/tests/ex/Makefile | 8 +++++--- tools/lib/api/Makefile | 4 +++- tools/lib/bpf/Makefile | 4 +++- tools/lib/lockdep/Makefile | 4 +++- tools/perf/Makefile.perf | 12 ++++++------ 7 files changed, 32 insertions(+), 12 deletions(-) diff --git a/tools/build/Documentation/Build.txt b/tools/build/Documentation/Build.txt index 88824359d595..a47bffbae159 100644 --- a/tools/build/Documentation/Build.txt +++ b/tools/build/Documentation/Build.txt @@ -113,6 +113,13 @@ It defines following interface: make $(build)=ex +Fixdep +------ +It is necessary to build the fixdep helper before invoking the build. +The Makefile.include file adds the fixdep target, that could be +invoked by the user. + + Rules ----- diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include index 91bc60616de5..6572bb023543 100644 --- a/tools/build/Makefile.include +++ b/tools/build/Makefile.include @@ -1 +1,6 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj + +fixdep: + $(Q)$(MAKE) -C $(srctree)/tools/build fixdep + +.PHONY: fixdep diff --git a/tools/build/tests/ex/Makefile b/tools/build/tests/ex/Makefile index f279b84cb859..c50d5782ad5a 100644 --- a/tools/build/tests/ex/Makefile +++ b/tools/build/tests/ex/Makefile @@ -3,18 +3,20 @@ export CC := gcc export LD := ld export AR := ar +ex: + include $(srctree)/tools/build/Makefile.include ex: ex-in.o libex-in.o gcc -o $@ $^ -ex.%: FORCE +ex.%: fixdep FORCE make -f $(srctree)/tools/build/Makefile.build dir=. $@ -ex-in.o: FORCE +ex-in.o: fixdep FORCE make $(build)=ex -libex-in.o: FORCE +libex-in.o: fixdep FORCE make $(build)=libex clean: diff --git a/tools/lib/api/Makefile b/tools/lib/api/Makefile index 8806ea7c2f99..d85904dc9b38 100644 --- a/tools/lib/api/Makefile +++ b/tools/lib/api/Makefile @@ -23,10 +23,12 @@ RM = rm -f API_IN := $(OUTPUT)libapi-in.o +all: + export srctree OUTPUT CC LD CFLAGS V include $(srctree)/tools/build/Makefile.include -all: $(LIBFILE) +all: fixdep $(LIBFILE) $(API_IN): FORCE @$(MAKE) $(build)=libapi diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile index c66ade68d4a1..fc9af57b666e 100644 --- a/tools/lib/bpf/Makefile +++ b/tools/lib/bpf/Makefile @@ -123,6 +123,8 @@ endif # the same command line setup. MAKEOVERRIDES= +all: + export srctree OUTPUT CC LD CFLAGS V include $(srctree)/tools/build/Makefile.include @@ -133,7 +135,7 @@ CMD_TARGETS = $(LIB_FILE) TARGETS = $(CMD_TARGETS) -all: $(VERSION_FILES) all_cmd +all: fixdep $(VERSION_FILES) all_cmd all_cmd: $(CMD_TARGETS) diff --git a/tools/lib/lockdep/Makefile b/tools/lib/lockdep/Makefile index d12081da383b..7e319afac78a 100644 --- a/tools/lib/lockdep/Makefile +++ b/tools/lib/lockdep/Makefile @@ -93,6 +93,8 @@ else print_install = echo ' INSTALL '$1' to $(DESTDIR_SQ)$2'; endif +all: + export srctree OUTPUT CC LD CFLAGS V include $(srctree)/tools/build/Makefile.include @@ -109,7 +111,7 @@ CMD_TARGETS = $(LIB_FILE) TARGETS = $(CMD_TARGETS) -all: all_cmd +all: fixdep all_cmd all_cmd: $(CMD_TARGETS) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 25c1753ffbeb..56517d304772 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -306,7 +306,7 @@ $(OUTPUT)perf: $(PERFLIBS) $(PERF_IN) $(LIBTRACEEVENT_DYNAMIC_LIST) $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $(LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS) \ $(PERF_IN) $(LIBS) -o $@ -$(GTK_IN): FORCE +$(GTK_IN): fixdep FORCE $(Q)$(MAKE) $(build)=gtk $(OUTPUT)libperf-gtk.so: $(GTK_IN) $(PERFLIBS) @@ -349,7 +349,7 @@ endif __build-dir = $(subst $(OUTPUT),,$(dir $@)) build-dir = $(if $(__build-dir),$(__build-dir),.) -prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h +prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep $(OUTPUT)%.o: %.c prepare FORCE $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ @@ -389,7 +389,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) LIBPERF_IN := $(OUTPUT)libperf-in.o -$(LIBPERF_IN): FORCE +$(LIBPERF_IN): fixdep FORCE $(Q)$(MAKE) $(build)=libperf $(LIB_FILE): $(LIBPERF_IN) @@ -397,10 +397,10 @@ $(LIB_FILE): $(LIBPERF_IN) LIBTRACEEVENT_FLAGS += plugin_dir=$(plugindir_SQ) -$(LIBTRACEEVENT): FORCE +$(LIBTRACEEVENT): fixdep FORCE $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) $(OUTPUT)libtraceevent.a -libtraceevent_plugins: FORCE +libtraceevent_plugins: fixdep FORCE $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) plugins $(LIBTRACEEVENT_DYNAMIC_LIST): libtraceevent_plugins @@ -413,7 +413,7 @@ $(LIBTRACEEVENT)-clean: install-traceevent-plugins: $(LIBTRACEEVENT) $(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins -$(LIBAPI): FORCE +$(LIBAPI): fixdep FORCE $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a $(LIBAPI)-clean: From e1791347b5d57d13326cf0114df1a3f3b1c4ca24 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:32 +0300 Subject: [PATCH 106/260] perf auxtrace: Fix 'instructions' period of zero Instruction tracing options (i.e. --itrace) include an option for sampling instructions at an arbitrary period. e.g. --itrace=i10us means make an 'instructions' sample for every 10us of trace. Currently the logic does not distinguish between a period of zero and no period being specified at all, so it gets treated as the default period which is 100000. That doesn't really make sense. Fix it so that zero period is accepted and treated as meaning "as often as possible". In the case of Intel PT that is the same as a period of 1 and a unit of 'instructions' (i.e. --itrace=i1i). Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-2-git-send-email-adrian.hunter@intel.com [ Add a few lines describing this in the Documentation/intel-pt.txt file ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/intel-pt.txt | 5 +++++ tools/perf/util/auxtrace.c | 4 +++- tools/perf/util/intel-pt.c | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index c94c9de3173e..886612b50961 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt @@ -707,6 +707,11 @@ on the sample is *not* adjusted and reflects the last known value of TSC. For Intel PT, the default period is 100us. +Setting it to a zero period means "as often as possible". + +In the case of Intel PT that is the same as a period of 1 and a unit of +'instructions' (i.e. --itrace=i1i). + Also the call chain size (default 16, max. 1024) for instructions or transactions events can be specified. e.g. diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index a980e7c50ee0..c4993b2e6c50 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -950,6 +950,7 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, const char *p; char *endptr; bool period_type_set = false; + bool period_set = false; synth_opts->set = true; @@ -971,6 +972,7 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, p += 1; if (isdigit(*p)) { synth_opts->period = strtoull(p, &endptr, 10); + period_set = true; p = endptr; while (*p == ' ' || *p == ',') p += 1; @@ -1053,7 +1055,7 @@ out: if (!period_type_set) synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; - if (!synth_opts->period) + if (!period_set) synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; } diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 38942e1eac8f..c8bb5ca6a157 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -720,7 +720,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, if (!params.period) { params.period_type = INTEL_PT_PERIOD_INSTRUCTIONS; - params.period = 1000; + params.period = 1; } } From d062ac16f53d1a24047bcc9eded5514a71c363b8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:33 +0300 Subject: [PATCH 107/260] perf report: Fix sample type validation for synthesized callchains Processing instruction tracing data (e.g. Intel PT) can synthesize callchains e.g. $ perf record -e intel_pt//u uname $ perf report --stdio --itrace=ige However perf report's callgraph option gets extra validation, so: $ perf report --stdio --itrace=ige -gflat Error: Selected -g or --branch-history but no callchain data. Did you call 'perf record' without -g? # To display the perf.data header info, # please use --header/--header-only options. # Fix the validation to know about instruction tracing options so above command works. A side-effect of the change is that the default option to accumulate the callchain of child functions comes into force. To get the previous behaviour the --no-children option can be used e.g. $ perf report --stdio --itrace=ige -gflat --no-children Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index e4e3f1432622..0d53b485a87b 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -214,6 +214,12 @@ static int report__setup_sample_type(struct report *rep) u64 sample_type = perf_evlist__combined_sample_type(session->evlist); bool is_pipe = perf_data_file__is_pipe(session->file); + if (session->itrace_synth_opts->callchain || + (!is_pipe && + perf_header__has_feat(&session->header, HEADER_AUXTRACE) && + !session->itrace_synth_opts->set)) + sample_type |= PERF_SAMPLE_CALLCHAIN; + if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { ui__error("Selected --sort parent, but no " From 9992c2d50a73f442653968a98a9e5f3bf4e769e9 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:34 +0300 Subject: [PATCH 108/260] perf intel-pt: Fix potential loop forever TSC packets contain only 7 bytes of TSC. The 8th byte is assumed to change so infrequently that its value can be inferred. However the logic must cater for a 7 byte wraparound, which it does by adding 1 to the top byte. The existing code was doing that with a while loop even though the addition should only need to be done once. That logic won't work (will loop forever) if TSC wraps around at the 8th byte. Theoretically that would take at least 10 years, unless something else went wrong. And what else could go wrong. Well, if the chunks of trace data are processed out of order, it will make it look like the 7-byte TSC has gone backwards (i.e. wrapped). If that happens 256 times then stuck in the while loop it will be. Fix that by getting rid of the unnecessary while loop. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 22ba50224319..9409d014b46c 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -650,7 +650,7 @@ static int intel_pt_calc_cyc_cb(struct intel_pt_pkt_info *pkt_info) if (data->from_mtc && timestamp < data->timestamp && data->timestamp - timestamp < decoder->tsc_slip) return 1; - while (timestamp < data->timestamp) + if (timestamp < data->timestamp) timestamp += (1ULL << 56); if (pkt_info->last_packet_type != INTEL_PT_CYC) { if (data->from_mtc) @@ -1191,7 +1191,7 @@ static void intel_pt_calc_tsc_timestamp(struct intel_pt_decoder *decoder) timestamp); timestamp = decoder->timestamp; } - while (timestamp < decoder->timestamp) { + if (timestamp < decoder->timestamp) { intel_pt_log_to("Wraparound timestamp", timestamp); timestamp += (1ULL << 56); decoder->tsc_timestamp = timestamp; From 116f349c5bf8c7aec4047dd6e06c310354b46e4f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:35 +0300 Subject: [PATCH 109/260] perf intel-pt: Make logging slightly more efficient Logging is only used for debugging. Use macros to save calling into the functions only to return immediately when logging is not enabled. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/util/intel-pt-decoder/intel-pt-log.c | 21 +++++----- .../perf/util/intel-pt-decoder/intel-pt-log.h | 38 ++++++++++++++++--- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.c b/tools/perf/util/intel-pt-decoder/intel-pt-log.c index d09c7d9f9050..319bef33a64b 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.c @@ -29,18 +29,18 @@ static FILE *f; static char log_name[MAX_LOG_NAME]; -static bool enable_logging; +bool intel_pt_enable_logging; void intel_pt_log_enable(void) { - enable_logging = true; + intel_pt_enable_logging = true; } void intel_pt_log_disable(void) { if (f) fflush(f); - enable_logging = false; + intel_pt_enable_logging = false; } void intel_pt_log_set_name(const char *name) @@ -80,7 +80,7 @@ static void intel_pt_print_no_data(uint64_t pos, int indent) static int intel_pt_log_open(void) { - if (!enable_logging) + if (!intel_pt_enable_logging) return -1; if (f) @@ -91,15 +91,15 @@ static int intel_pt_log_open(void) f = fopen(log_name, "w+"); if (!f) { - enable_logging = false; + intel_pt_enable_logging = false; return -1; } return 0; } -void intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, - uint64_t pos, const unsigned char *buf) +void __intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, + uint64_t pos, const unsigned char *buf) { char desc[INTEL_PT_PKT_DESC_MAX]; @@ -111,7 +111,7 @@ void intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, fprintf(f, "%s\n", desc); } -void intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip) +void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip) { char desc[INTEL_PT_INSN_DESC_MAX]; size_t len = intel_pt_insn->length; @@ -128,7 +128,8 @@ void intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip) fprintf(f, "Bad instruction!\n"); } -void intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, uint64_t ip) +void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, + uint64_t ip) { char desc[INTEL_PT_INSN_DESC_MAX]; @@ -142,7 +143,7 @@ void intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, uint64_t ip) fprintf(f, "Bad instruction!\n"); } -void intel_pt_log(const char *fmt, ...) +void __intel_pt_log(const char *fmt, ...) { va_list args; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-log.h b/tools/perf/util/intel-pt-decoder/intel-pt-log.h index db3942f83677..debe751dc3d6 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-log.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-log.h @@ -25,20 +25,46 @@ void intel_pt_log_enable(void); void intel_pt_log_disable(void); void intel_pt_log_set_name(const char *name); -void intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, - uint64_t pos, const unsigned char *buf); +void __intel_pt_log_packet(const struct intel_pt_pkt *packet, int pkt_len, + uint64_t pos, const unsigned char *buf); struct intel_pt_insn; -void intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); -void intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, - uint64_t ip); +void __intel_pt_log_insn(struct intel_pt_insn *intel_pt_insn, uint64_t ip); +void __intel_pt_log_insn_no_data(struct intel_pt_insn *intel_pt_insn, + uint64_t ip); __attribute__((format(printf, 1, 2))) -void intel_pt_log(const char *fmt, ...); +void __intel_pt_log(const char *fmt, ...); + +#define intel_pt_log(fmt, ...) \ + do { \ + if (intel_pt_enable_logging) \ + __intel_pt_log(fmt, ##__VA_ARGS__); \ + } while (0) + +#define intel_pt_log_packet(arg, ...) \ + do { \ + if (intel_pt_enable_logging) \ + __intel_pt_log_packet(arg, ##__VA_ARGS__); \ + } while (0) + +#define intel_pt_log_insn(arg, ...) \ + do { \ + if (intel_pt_enable_logging) \ + __intel_pt_log_insn(arg, ##__VA_ARGS__); \ + } while (0) + +#define intel_pt_log_insn_no_data(arg, ...) \ + do { \ + if (intel_pt_enable_logging) \ + __intel_pt_log_insn_no_data(arg, ##__VA_ARGS__); \ + } while (0) #define x64_fmt "0x%" PRIx64 +extern bool intel_pt_enable_logging; + static inline void intel_pt_log_at(const char *msg, uint64_t u) { intel_pt_log("%s at " x64_fmt "\n", msg, u); From 83e1986032dfcd3f9e9fc0d06e11d9153edae19b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:36 +0300 Subject: [PATCH 110/260] perf script: Allow time to be displayed in nanoseconds Add option --ns to display time to 9 decimal places. That is useful in some cases, for example when using Intel PT cycle accurate mode. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-6-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 3 +++ tools/perf/builtin-script.c | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index dc3ec783b7bd..b3b42f9285df 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -249,6 +249,9 @@ include::itrace.txt[] --full-source-path:: Show the full path for source files for srcline output. +--ns:: + Use 9 decimal places when displaying time (i.e. show the nanoseconds) + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-script-perl[1], diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 284a76e04628..092843968791 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -29,6 +29,7 @@ static bool no_callchain; static bool latency_format; static bool system_wide; static bool print_flags; +static bool nanosecs; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); @@ -415,7 +416,10 @@ static void print_sample_start(struct perf_sample *sample, secs = nsecs / NSECS_PER_SEC; nsecs -= secs * NSECS_PER_SEC; usecs = nsecs / NSECS_PER_USEC; - printf("%5lu.%06lu: ", secs, usecs); + if (nanosecs) + printf("%5lu.%09llu: ", secs, nsecs); + else + printf("%5lu.%06lu: ", secs, usecs); } } @@ -1695,6 +1699,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN('\0', "show-switch-events", &script.show_switch_events, "Show context switch events (if recorded)"), OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), + OPT_BOOLEAN(0, "ns", &nanosecs, + "Use 9 decimal places when displaying time"), OPT_CALLBACK_OPTARG(0, "itrace", &itrace_synth_opts, NULL, "opts", "Instruction Tracing options", itrace_parse_synth_opts), From a38f48e300f9dac30a9b2d2ce958c8dbd7def351 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:37 +0300 Subject: [PATCH 111/260] perf session: Warn when AUX data has been lost By default 'perf record' will postprocess the perf.data file to determine build-ids. When that happens, the number of lost perf events is displayed. Make that also happen for AUX events. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.h | 1 + tools/perf/util/session.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index be5cbc7be889..a0dbcbd4f6d8 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -257,6 +257,7 @@ struct events_stats { u64 total_non_filtered_period; u64 total_lost; u64 total_lost_samples; + u64 total_aux_lost; u64 total_invalid_chains; u32 nr_events[PERF_RECORD_HEADER_MAX]; u32 nr_non_filtered_samples; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index f5e000030a5e..15c84cad213a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1101,6 +1101,9 @@ static int machines__deliver_event(struct machines *machines, case PERF_RECORD_UNTHROTTLE: return tool->unthrottle(tool, event, sample, machine); case PERF_RECORD_AUX: + if (tool->aux == perf_event__process_aux && + (event->aux.flags & PERF_AUX_FLAG_TRUNCATED)) + evlist->stats.total_aux_lost += 1; return tool->aux(tool, event, sample, machine); case PERF_RECORD_ITRACE_START: return tool->itrace_start(tool, event, sample, machine); @@ -1346,6 +1349,13 @@ static void perf_session__warn_about_errors(const struct perf_session *session) } } + if (session->tool->aux == perf_event__process_aux && + stats->total_aux_lost != 0) { + ui__warning("AUX data lost %" PRIu64 " times out of %u!\n\n", + stats->total_aux_lost, + stats->nr_events[PERF_RECORD_AUX]); + } + if (stats->nr_unknown_events != 0) { ui__warning("Found %u unknown events!\n\n" "Is this an older tool processing a perf.data " From 35ca01c117da9b8e5b60204f730cdde414735596 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:38 +0300 Subject: [PATCH 112/260] perf tools: Add more documentation to export-to-postgresql.py script Add some comments to the script and some 'views' to the created database that better illustrate the database structure and how it can be used. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../scripts/python/export-to-postgresql.py | 221 ++++++++++++++++++ 1 file changed, 221 insertions(+) diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py index 84a32037a80f..1b02cdc0cab6 100644 --- a/tools/perf/scripts/python/export-to-postgresql.py +++ b/tools/perf/scripts/python/export-to-postgresql.py @@ -61,6 +61,142 @@ import datetime # # An example of using the database is provided by the script # call-graph-from-postgresql.py. Refer to that script for details. +# +# Tables: +# +# The tables largely correspond to perf tools' data structures. They are largely self-explanatory. +# +# samples +# +# 'samples' is the main table. It represents what instruction was executing at a point in time +# when something (a selected event) happened. The memory address is the instruction pointer or 'ip'. +# +# calls +# +# 'calls' represents function calls and is related to 'samples' by 'call_id' and 'return_id'. +# 'calls' is only created when the 'calls' option to this script is specified. +# +# call_paths +# +# 'call_paths' represents all the call stacks. Each 'call' has an associated record in 'call_paths'. +# 'calls_paths' is only created when the 'calls' option to this script is specified. +# +# branch_types +# +# 'branch_types' provides descriptions for each type of branch. +# +# comm_threads +# +# 'comm_threads' shows how 'comms' relates to 'threads'. +# +# comms +# +# 'comms' contains a record for each 'comm' - the name given to the executable that is running. +# +# dsos +# +# 'dsos' contains a record for each executable file or library. +# +# machines +# +# 'machines' can be used to distinguish virtual machines if virtualization is supported. +# +# selected_events +# +# 'selected_events' contains a record for each kind of event that has been sampled. +# +# symbols +# +# 'symbols' contains a record for each symbol. Only symbols that have samples are present. +# +# threads +# +# 'threads' contains a record for each thread. +# +# Views: +# +# Most of the tables have views for more friendly display. The views are: +# +# calls_view +# call_paths_view +# comm_threads_view +# dsos_view +# machines_view +# samples_view +# symbols_view +# threads_view +# +# More examples of browsing the database with psql: +# Note that some of the examples are not the most optimal SQL query. +# Note that call information is only available if the script's 'calls' option has been used. +# +# Top 10 function calls (not aggregated by symbol): +# +# SELECT * FROM calls_view ORDER BY elapsed_time DESC LIMIT 10; +# +# Top 10 function calls (aggregated by symbol): +# +# SELECT symbol_id,(SELECT name FROM symbols WHERE id = symbol_id) AS symbol, +# SUM(elapsed_time) AS tot_elapsed_time,SUM(branch_count) AS tot_branch_count +# FROM calls_view GROUP BY symbol_id ORDER BY tot_elapsed_time DESC LIMIT 10; +# +# Note that the branch count gives a rough estimation of cpu usage, so functions +# that took a long time but have a relatively low branch count must have spent time +# waiting. +# +# Find symbols by pattern matching on part of the name (e.g. names containing 'alloc'): +# +# SELECT * FROM symbols_view WHERE name LIKE '%alloc%'; +# +# Top 10 function calls for a specific symbol (e.g. whose symbol_id is 187): +# +# SELECT * FROM calls_view WHERE symbol_id = 187 ORDER BY elapsed_time DESC LIMIT 10; +# +# Show function calls made by function in the same context (i.e. same call path) (e.g. one with call_path_id 254): +# +# SELECT * FROM calls_view WHERE parent_call_path_id = 254; +# +# Show branches made during a function call (e.g. where call_id is 29357 and return_id is 29370 and tid is 29670) +# +# SELECT * FROM samples_view WHERE id >= 29357 AND id <= 29370 AND tid = 29670 AND event LIKE 'branches%'; +# +# Show transactions: +# +# SELECT * FROM samples_view WHERE event = 'transactions'; +# +# Note transaction start has 'in_tx' true whereas, transaction end has 'in_tx' false. +# Transaction aborts have branch_type_name 'transaction abort' +# +# Show transaction aborts: +# +# SELECT * FROM samples_view WHERE event = 'transactions' AND branch_type_name = 'transaction abort'; +# +# To print a call stack requires walking the call_paths table. For example this python script: +# #!/usr/bin/python2 +# +# import sys +# from PySide.QtSql import * +# +# if __name__ == '__main__': +# if (len(sys.argv) < 3): +# print >> sys.stderr, "Usage is: printcallstack.py " +# raise Exception("Too few arguments") +# dbname = sys.argv[1] +# call_path_id = sys.argv[2] +# db = QSqlDatabase.addDatabase('QPSQL') +# db.setDatabaseName(dbname) +# if not db.open(): +# raise Exception("Failed to open database " + dbname + " error: " + db.lastError().text()) +# query = QSqlQuery(db) +# print " id ip symbol_id symbol dso_id dso_short_name" +# while call_path_id != 0 and call_path_id != 1: +# ret = query.exec_('SELECT * FROM call_paths_view WHERE id = ' + str(call_path_id)) +# if not ret: +# raise Exception("Query failed: " + query.lastError().text()) +# if not query.next(): +# raise Exception("Query failed") +# print "{0:>6} {1:>10} {2:>9} {3:<30} {4:>6} {5:<30}".format(query.value(0), query.value(1), query.value(2), query.value(3), query.value(4), query.value(5)) +# call_path_id = query.value(6) from PySide.QtSql import * @@ -244,6 +380,91 @@ if perf_db_export_calls: 'parent_call_path_id bigint,' 'flags integer)') +do_query(query, 'CREATE VIEW machines_view AS ' + 'SELECT ' + 'id,' + 'pid,' + 'root_dir,' + 'CASE WHEN id=0 THEN \'unknown\' WHEN pid=-1 THEN \'host\' ELSE \'guest\' END AS host_or_guest' + ' FROM machines') + +do_query(query, 'CREATE VIEW dsos_view AS ' + 'SELECT ' + 'id,' + 'machine_id,' + '(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,' + 'short_name,' + 'long_name,' + 'build_id' + ' FROM dsos') + +do_query(query, 'CREATE VIEW symbols_view AS ' + 'SELECT ' + 'id,' + 'name,' + '(SELECT short_name FROM dsos WHERE id=dso_id) AS dso,' + 'dso_id,' + 'sym_start,' + 'sym_end,' + 'CASE WHEN binding=0 THEN \'local\' WHEN binding=1 THEN \'global\' ELSE \'weak\' END AS binding' + ' FROM symbols') + +do_query(query, 'CREATE VIEW threads_view AS ' + 'SELECT ' + 'id,' + 'machine_id,' + '(SELECT host_or_guest FROM machines_view WHERE id = machine_id) AS host_or_guest,' + 'process_id,' + 'pid,' + 'tid' + ' FROM threads') + +do_query(query, 'CREATE VIEW comm_threads_view AS ' + 'SELECT ' + 'comm_id,' + '(SELECT comm FROM comms WHERE id = comm_id) AS command,' + 'thread_id,' + '(SELECT pid FROM threads WHERE id = thread_id) AS pid,' + '(SELECT tid FROM threads WHERE id = thread_id) AS tid' + ' FROM comm_threads') + +if perf_db_export_calls: + do_query(query, 'CREATE VIEW call_paths_view AS ' + 'SELECT ' + 'c.id,' + 'to_hex(c.ip) AS ip,' + 'c.symbol_id,' + '(SELECT name FROM symbols WHERE id = c.symbol_id) AS symbol,' + '(SELECT dso_id FROM symbols WHERE id = c.symbol_id) AS dso_id,' + '(SELECT dso FROM symbols_view WHERE id = c.symbol_id) AS dso_short_name,' + 'c.parent_id,' + 'to_hex(p.ip) AS parent_ip,' + 'p.symbol_id AS parent_symbol_id,' + '(SELECT name FROM symbols WHERE id = p.symbol_id) AS parent_symbol,' + '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' + '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' + ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') + do_query(query, 'CREATE VIEW calls_view AS ' + 'SELECT ' + 'calls.id,' + 'thread_id,' + '(SELECT pid FROM threads WHERE id = thread_id) AS pid,' + '(SELECT tid FROM threads WHERE id = thread_id) AS tid,' + '(SELECT comm FROM comms WHERE id = comm_id) AS command,' + 'call_path_id,' + 'to_hex(ip) AS ip,' + 'symbol_id,' + '(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,' + 'call_time,' + 'return_time,' + 'return_time - call_time AS elapsed_time,' + 'branch_count,' + 'call_id,' + 'return_id,' + 'CASE WHEN flags=1 THEN \'no call\' WHEN flags=2 THEN \'no return\' WHEN flags=3 THEN \'no call/return\' ELSE \'\' END AS flags,' + 'parent_call_path_id' + ' FROM calls INNER JOIN call_paths ON call_paths.id = call_path_id') + do_query(query, 'CREATE VIEW samples_view AS ' 'SELECT ' 'id,' From 601897b54c7ed492a89b262dccd7c6f7faf12b30 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:39 +0300 Subject: [PATCH 113/260] perf auxtrace: Add option to synthesize branch stacks on samples Add AUX area tracing option 'l' to synthesize branch stacks on samples just like sample type PERF_SAMPLE_BRANCH_STACK. This is taken into use by Intel PT in a subsequent patch. Based-on-patch-by: Andi Kleen Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-9-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/itrace.txt | 4 ++++ tools/perf/util/auxtrace.c | 20 ++++++++++++++++++++ tools/perf/util/auxtrace.h | 4 ++++ 3 files changed, 28 insertions(+) diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index 2ff946677e3b..65453f4c7006 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt @@ -6,6 +6,7 @@ e synthesize error events d create a debug log g synthesize a call chain (use with i or x) + l synthesize last branch entries (use with i or x) The default is all events i.e. the same as --itrace=ibxe @@ -20,3 +21,6 @@ Also the call chain size (default 16, max. 1024) for instructions or transactions events can be specified. + + Also the number of last branch entries (default 64, max. 1024) for + instructions or transactions events can be specified. diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index c4993b2e6c50..7f10430af39c 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -926,6 +926,8 @@ s64 perf_event__process_auxtrace(struct perf_tool *tool, #define PERF_ITRACE_DEFAULT_PERIOD 100000 #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 #define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 +#define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 +#define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) { @@ -936,6 +938,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; + synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; } /* @@ -1043,6 +1046,23 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, synth_opts->callchain_sz = val; } break; + case 'l': + synth_opts->last_branch = true; + synth_opts->last_branch_sz = + PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; + while (*p == ' ' || *p == ',') + p += 1; + if (isdigit(*p)) { + unsigned int val; + + val = strtoul(p, &endptr, 10); + p = endptr; + if (!val || + val > PERF_ITRACE_MAX_LAST_BRANCH_SZ) + goto out_err; + synth_opts->last_branch_sz = val; + } + break; case ' ': case ',': break; diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index bf72b77a588a..b86f90db1352 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -63,7 +63,9 @@ enum itrace_period_type { * @calls: limit branch samples to calls (can be combined with @returns) * @returns: limit branch samples to returns (can be combined with @calls) * @callchain: add callchain to 'instructions' events + * @last_branch: add branch context to 'instruction' events * @callchain_sz: maximum callchain size + * @last_branch_sz: branch context size * @period: 'instructions' events period * @period_type: 'instructions' events period type */ @@ -79,7 +81,9 @@ struct itrace_synth_opts { bool calls; bool returns; bool callchain; + bool last_branch; unsigned int callchain_sz; + unsigned int last_branch_sz; unsigned long long period; enum itrace_period_type period_type; }; From c7eced63f2f67bd06ceb2269062416db9d81d29d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:40 +0300 Subject: [PATCH 114/260] perf report: Adjust sample type validation for synthesized branch stacks perf report looks at event sample types to determine if branch stacks have been sampled. Adjust the validation to know about instruction tracing options. This change allows the use of the -b option which otherwise would complain with an error like: Error: Selected -b but no branch data. Did you call perf record without -b? # To display the perf.data header info, # please use --header/--header-only options. # Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-10-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 0d53b485a87b..7af35af5a5e5 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -220,6 +220,9 @@ static int report__setup_sample_type(struct report *rep) !session->itrace_synth_opts->set)) sample_type |= PERF_SAMPLE_CALLCHAIN; + if (session->itrace_synth_opts->last_branch) + sample_type |= PERF_SAMPLE_BRANCH_STACK; + if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { ui__error("Selected --sort parent, but no " From fb9fab66e6e3ee737e521c899684c6d684b24a22 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:41 +0300 Subject: [PATCH 115/260] perf report: Also do default setup for synthesized branch stacks The 'perf report' tool will default to displaying branch stacks (-b option) if they are present. Make that also happen for synthesized branch stacks. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-11-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 7af35af5a5e5..92f7c5a75208 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -829,6 +829,9 @@ repeat: has_br_stack = perf_header__has_feat(&session->header, HEADER_BRANCH_STACK); + if (itrace_synth_opts.last_branch) + has_br_stack = true; + /* * Branch mode is a tristate: * -1 means default, so decide based on the file having branch data. From f86225db3aa0e394915af45eea1c3cca6f3e2dba Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:42 +0300 Subject: [PATCH 116/260] perf report: Skip events with null branch stacks A non-synthesized event might not have a branch stack if branch stacks have been synthesized (using itrace options). An example of that is when Intel PT records sched_switch events for decoding purposes. Those sched_switch events do not have branch stacks even though the Intel PT decoder may be synthesizing other events that do due to the itrace options. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-12-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 92f7c5a75208..e94e5c7155af 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -163,14 +163,21 @@ static int process_sample_event(struct perf_tool *tool, if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) goto out_put; - if (sort__mode == SORT_MODE__BRANCH) + if (sort__mode == SORT_MODE__BRANCH) { + /* + * A non-synthesized event might not have a branch stack if + * branch stacks have been synthesized (using itrace options). + */ + if (!sample->branch_stack) + goto out_put; iter.ops = &hist_iter_branch; - else if (rep->mem_mode) + } else if (rep->mem_mode) { iter.ops = &hist_iter_mem; - else if (symbol_conf.cumulate_callchain) + } else if (symbol_conf.cumulate_callchain) { iter.ops = &hist_iter_cumulative; - else + } else { iter.ops = &hist_iter_normal; + } if (al.map != NULL) al.map->dso->hit = 1; From 051a01b9a2c1c1ef3049973a43d9ed4ddcc946f3 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:43 +0300 Subject: [PATCH 117/260] perf inject: Set branch stack feature flag when synthesizing branch stacks The branch stack feature flag is set by 'perf record' when recording data that contains branch stacks. Consequently, when 'perf inject' synthesizes branch stacks, the feature flag should be set also. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-13-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index f62c49b35be0..8638fad8a085 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -537,9 +537,13 @@ static int __cmd_inject(struct perf_inject *inject) * The AUX areas have been removed and replaced with * synthesized hardware events, so clear the feature flag. */ - if (inject->itrace_synth_opts.set) + if (inject->itrace_synth_opts.set) { perf_header__clear_feat(&session->header, HEADER_AUXTRACE); + if (inject->itrace_synth_opts.last_branch) + perf_header__set_feat(&session->header, + HEADER_BRANCH_STACK); + } session->header.data_offset = output_data_offset; session->header.data_size = inject->bytes_written; perf_session__write_header(session, session->evlist, fd, true); From 385e33063fb963f5cccb0a37fe539319b6481fa5 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:44 +0300 Subject: [PATCH 118/260] perf intel-pt: Move branch filter logic intel_pt_synth_branch_sample() skips synthesizing if the branch does not match the branch filter. That logic was sitting in the middle of the function but is more efficiently placed at the start of the function, so move it. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-14-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index c8bb5ca6a157..2c01e723826a 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -891,6 +891,9 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) union perf_event *event = ptq->event_buf; struct perf_sample sample = { .ip = 0, }; + if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) + return 0; + event->sample.header.type = PERF_RECORD_SAMPLE; event->sample.header.misc = PERF_RECORD_MISC_USER; event->sample.header.size = sizeof(struct perf_event_header); @@ -909,9 +912,6 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) sample.flags = ptq->flags; sample.insn_len = ptq->insn_len; - if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) - return 0; - if (pt->synth_opts.inject) { ret = intel_pt_inject_event(event, &sample, pt->branches_sample_type, From f14445ee72c59f32aa5cbf4d0f0330a5f62a752d Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:45 +0300 Subject: [PATCH 119/260] perf intel-pt: Support generating branch stack Add support for generating branch stack context for PT samples. The decoder reports a configurable number of branches as branch context for each sample. Internally it keeps track of them by using a simple sliding window. We also flush the last branch buffer on each sample to avoid overlapping intervals. This is useful for: - Reporting accurate basic block edge frequencies through the perf report branch view - Using with --branch-history to get the wider context of samples - Other users of LBRs Also the Documentation is updated. Examples: Record with Intel PT: perf record -e intel_pt//u ls Branch stacks are used by default if synthesized so: perf report --itrace=ile is the same as: perf report --itrace=ile -b Branch history can be requested also: perf report --itrace=igle --branch-history Based-on-patch-by: Andi Kleen Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-15-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/intel-pt.txt | 10 +++ tools/perf/util/intel-pt.c | 115 ++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index 886612b50961..a0fbb5d71f7d 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt @@ -671,6 +671,7 @@ The letters are: e synthesize tracing error events d create a debug log g synthesize a call chain (use with i or x) + l synthesize last branch entries (use with i or x) "Instructions" events look like they were recorded by "perf record -e instructions". @@ -718,6 +719,15 @@ transactions events can be specified. e.g. --itrace=ig32 --itrace=xg32 +Also the number of last branch entries (default 64, max. 1024) for instructions or +transactions events can be specified. e.g. + + --itrace=il10 + --itrace=xl10 + +Note that last branch entries are cleared for each sample, so there is no overlap +from one sample to the next. + To disable trace decoding entirely, use the option --no-itrace. diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 2c01e723826a..05e8fcc5188b 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -22,6 +22,7 @@ #include "../perf.h" #include "session.h" #include "machine.h" +#include "sort.h" #include "tool.h" #include "event.h" #include "evlist.h" @@ -115,6 +116,9 @@ struct intel_pt_queue { void *decoder; const struct intel_pt_state *state; struct ip_callchain *chain; + struct branch_stack *last_branch; + struct branch_stack *last_branch_rb; + size_t last_branch_pos; union perf_event *event_buf; bool on_heap; bool stop; @@ -675,6 +679,19 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, goto out_free; } + if (pt->synth_opts.last_branch) { + size_t sz = sizeof(struct branch_stack); + + sz += pt->synth_opts.last_branch_sz * + sizeof(struct branch_entry); + ptq->last_branch = zalloc(sz); + if (!ptq->last_branch) + goto out_free; + ptq->last_branch_rb = zalloc(sz); + if (!ptq->last_branch_rb) + goto out_free; + } + ptq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE); if (!ptq->event_buf) goto out_free; @@ -732,6 +749,8 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, out_free: zfree(&ptq->event_buf); + zfree(&ptq->last_branch); + zfree(&ptq->last_branch_rb); zfree(&ptq->chain); free(ptq); return NULL; @@ -746,6 +765,8 @@ static void intel_pt_free_queue(void *priv) thread__zput(ptq->thread); intel_pt_decoder_free(ptq->decoder); zfree(&ptq->event_buf); + zfree(&ptq->last_branch); + zfree(&ptq->last_branch_rb); zfree(&ptq->chain); free(ptq); } @@ -876,6 +897,57 @@ static int intel_pt_setup_queues(struct intel_pt *pt) return 0; } +static inline void intel_pt_copy_last_branch_rb(struct intel_pt_queue *ptq) +{ + struct branch_stack *bs_src = ptq->last_branch_rb; + struct branch_stack *bs_dst = ptq->last_branch; + size_t nr = 0; + + bs_dst->nr = bs_src->nr; + + if (!bs_src->nr) + return; + + nr = ptq->pt->synth_opts.last_branch_sz - ptq->last_branch_pos; + memcpy(&bs_dst->entries[0], + &bs_src->entries[ptq->last_branch_pos], + sizeof(struct branch_entry) * nr); + + if (bs_src->nr >= ptq->pt->synth_opts.last_branch_sz) { + memcpy(&bs_dst->entries[nr], + &bs_src->entries[0], + sizeof(struct branch_entry) * ptq->last_branch_pos); + } +} + +static inline void intel_pt_reset_last_branch_rb(struct intel_pt_queue *ptq) +{ + ptq->last_branch_pos = 0; + ptq->last_branch_rb->nr = 0; +} + +static void intel_pt_update_last_branch_rb(struct intel_pt_queue *ptq) +{ + const struct intel_pt_state *state = ptq->state; + struct branch_stack *bs = ptq->last_branch_rb; + struct branch_entry *be; + + if (!ptq->last_branch_pos) + ptq->last_branch_pos = ptq->pt->synth_opts.last_branch_sz; + + ptq->last_branch_pos -= 1; + + be = &bs->entries[ptq->last_branch_pos]; + be->from = state->from_ip; + be->to = state->to_ip; + be->flags.abort = !!(state->flags & INTEL_PT_ABORT_TX); + be->flags.in_tx = !!(state->flags & INTEL_PT_IN_TX); + /* No support for mispredict */ + + if (bs->nr < ptq->pt->synth_opts.last_branch_sz) + bs->nr += 1; +} + static int intel_pt_inject_event(union perf_event *event, struct perf_sample *sample, u64 type, bool swapped) @@ -890,6 +962,10 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) struct intel_pt *pt = ptq->pt; union perf_event *event = ptq->event_buf; struct perf_sample sample = { .ip = 0, }; + struct dummy_branch_stack { + u64 nr; + struct branch_entry entries; + } dummy_bs; if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) return 0; @@ -912,6 +988,21 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) sample.flags = ptq->flags; sample.insn_len = ptq->insn_len; + /* + * perf report cannot handle events without a branch stack when using + * SORT_MODE__BRANCH so make a dummy one. + */ + if (pt->synth_opts.last_branch && sort__mode == SORT_MODE__BRANCH) { + dummy_bs = (struct dummy_branch_stack){ + .nr = 1, + .entries = { + .from = sample.ip, + .to = sample.addr, + }, + }; + sample.branch_stack = (struct branch_stack *)&dummy_bs; + } + if (pt->synth_opts.inject) { ret = intel_pt_inject_event(event, &sample, pt->branches_sample_type, @@ -961,6 +1052,11 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) sample.callchain = ptq->chain; } + if (pt->synth_opts.last_branch) { + intel_pt_copy_last_branch_rb(ptq); + sample.branch_stack = ptq->last_branch; + } + if (pt->synth_opts.inject) { ret = intel_pt_inject_event(event, &sample, pt->instructions_sample_type, @@ -974,6 +1070,9 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) pr_err("Intel Processor Trace: failed to deliver instruction event, error %d\n", ret); + if (pt->synth_opts.last_branch) + intel_pt_reset_last_branch_rb(ptq); + return ret; } @@ -1008,6 +1107,11 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) sample.callchain = ptq->chain; } + if (pt->synth_opts.last_branch) { + intel_pt_copy_last_branch_rb(ptq); + sample.branch_stack = ptq->last_branch; + } + if (pt->synth_opts.inject) { ret = intel_pt_inject_event(event, &sample, pt->transactions_sample_type, @@ -1021,6 +1125,9 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", ret); + if (pt->synth_opts.callchain) + intel_pt_reset_last_branch_rb(ptq); + return ret; } @@ -1116,6 +1223,9 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) return err; } + if (pt->synth_opts.last_branch) + intel_pt_update_last_branch_rb(ptq); + if (!pt->sync_switch) return 0; @@ -1763,6 +1873,8 @@ static int intel_pt_synth_events(struct intel_pt *pt, pt->instructions_sample_period = attr.sample_period; if (pt->synth_opts.callchain) attr.sample_type |= PERF_SAMPLE_CALLCHAIN; + if (pt->synth_opts.last_branch) + attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; pr_debug("Synthesizing 'instructions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", id, (u64)attr.sample_type); err = intel_pt_synth_event(session, &attr, id); @@ -1782,6 +1894,8 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_period = 1; if (pt->synth_opts.callchain) attr.sample_type |= PERF_SAMPLE_CALLCHAIN; + if (pt->synth_opts.last_branch) + attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; pr_debug("Synthesizing 'transactions' event with id %" PRIu64 " sample type %#" PRIx64 "\n", id, (u64)attr.sample_type); err = intel_pt_synth_event(session, &attr, id); @@ -1808,6 +1922,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_period = 1; attr.sample_type |= PERF_SAMPLE_ADDR; attr.sample_type &= ~(u64)PERF_SAMPLE_CALLCHAIN; + attr.sample_type &= ~(u64)PERF_SAMPLE_BRANCH_STACK; pr_debug("Synthesizing 'branches' event with id %" PRIu64 " sample type %#" PRIx64 "\n", id, (u64)attr.sample_type); err = intel_pt_synth_event(session, &attr, id); From 188bb5e2ce112463428994f91291e5df6fc05521 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:46 +0300 Subject: [PATCH 120/260] perf report: Make max_stack value allow for synthesized callchains perf report has an option (--max-stack) to set the maximum stack depth when processing callchains. The option defaults to the hard-coded maximum definition PERF_MAX_STACK_DEPTH which is 127. The intention of the option is to allow the user to reduce the processing time by reducing the amount of the callchain that is processed. It is also possible, when processing instruction traces, to synthesize callchains. Synthesized callchains do not have the kernel size limitation and are whatever size the user requests, although validation presently prevents the user requested a value greater that 1024. The default value is 16. To allow for synthesized callchains, make the max_stack value at least the same size as the synthesized callchain size. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-16-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index e94e5c7155af..37c9f5125887 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -809,6 +809,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) if (report.inverted_callchain) callchain_param.order = ORDER_CALLER; + if (itrace_synth_opts.callchain && + (int)itrace_synth_opts.callchain_sz > report.max_stack) + report.max_stack = itrace_synth_opts.callchain_sz; + if (!input_name || !strlen(input_name)) { if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) input_name = "-"; From 96b40f3c05f36e061fd4dde920b9e9c795a88b69 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:47 +0300 Subject: [PATCH 121/260] perf hists: Allow for max_stack greater than PERF_MAX_STACK_DEPTH Use the max_stack value instead of PERF_MAX_STACK_DEPTH so that arbitrary-sized callchains can be supported. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-17-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 6 ++++-- tools/perf/util/hist.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index b3567a25f0c4..0cad9e07c5b4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -695,7 +695,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, } static int -iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, +iter_prepare_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { struct hist_entry **he_cache; @@ -707,7 +707,7 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused, * cumulated only one time to prevent entries more than 100% * overhead. */ - he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1)); + he_cache = malloc(sizeof(*he_cache) * (iter->max_stack + 1)); if (he_cache == NULL) return -ENOMEM; @@ -868,6 +868,8 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, if (err) return err; + iter->max_stack = max_stack_depth; + err = iter->ops->prepare_entry(iter, al); if (err) goto out; diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 4d6aa1dbdaee..8c20a8f6b214 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -90,6 +90,7 @@ struct hist_entry_iter { int curr; bool hide_unresolved; + int max_stack; struct perf_evsel *evsel; struct perf_sample *sample; From 03cd1fed2b8730271d3a8dbabd87989abddc33c4 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:49 +0300 Subject: [PATCH 122/260] perf script: Add a setting for maximum stack depth Add a setting for maximum stack depth in preparation for allowing for synthesized callchains. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-19-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 6 ++++-- tools/perf/util/session.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 092843968791..a65b498df097 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -33,6 +33,8 @@ static bool nanosecs; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); +static unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; + enum perf_output_field { PERF_OUTPUT_COMM = 1U << 0, PERF_OUTPUT_TID = 1U << 1, @@ -475,7 +477,7 @@ static void print_sample_bts(union perf_event *event, } } perf_evsel__print_ip(evsel, sample, al, print_opts, - PERF_MAX_STACK_DEPTH); + scripting_max_stack); } /* print branch_to information */ @@ -552,7 +554,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample, perf_evsel__print_ip(evsel, sample, al, output[attr->type].print_ip_opts, - PERF_MAX_STACK_DEPTH); + scripting_max_stack); } if (PRINT_FIELD(IREGS)) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 15c84cad213a..84a02eae4394 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1800,7 +1800,7 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, if (thread__resolve_callchain(al->thread, evsel, sample, NULL, NULL, - PERF_MAX_STACK_DEPTH) != 0) { + stack_depth) != 0) { if (verbose) error("Failed to resolve callchain. Skipping\n"); return; From 44cbe7295c3808977159f500a5bcdebf12a7db5f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:50 +0300 Subject: [PATCH 123/260] perf scripting python: Allow for max_stack greater than PERF_MAX_STACK_DEPTH Use the scripting_max_stack value to allow for values greater than PERF_MAX_STACK_DEPTH. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-20-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 2 +- tools/perf/util/scripting-engines/trace-event-python.c | 2 +- tools/perf/util/trace-event.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a65b498df097..5c3c02d5af53 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -33,7 +33,7 @@ static bool nanosecs; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -static unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; +unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; enum perf_output_field { PERF_OUTPUT_COMM = 1U << 0, diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index aa9e1257c1ee..a8e825fca42a 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -319,7 +319,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample, if (thread__resolve_callchain(al->thread, evsel, sample, NULL, NULL, - PERF_MAX_STACK_DEPTH) != 0) { + scripting_max_stack) != 0) { pr_err("Failed to resolve callchain. Skipping\n"); goto exit; } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index da6cc4cc2a4f..b85ee55cca0c 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -78,6 +78,8 @@ struct scripting_ops { int (*generate_script) (struct pevent *pevent, const char *outfile); }; +extern unsigned int scripting_max_stack; + int script_spec_register(const char *spec, struct scripting_ops *ops); void setup_perl_scripting(void); From 3c5b645faee7afbd417f6127694adbd26778a9eb Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:51 +0300 Subject: [PATCH 124/260] perf script: Make scripting_max_stack value allow for synthesized callchains perf script has a setting to set the maximum stack depth when processing callchains. The setting defaults to the hard-coded maximum definition PERF_MAX_STACK_DEPTH which is 127. It is possible, when processing instruction traces, to synthesize callchains. Synthesized callchains do not have the kernel size limitation and are whatever size the user requests, although validation presently prevents the user requested a value greater that 1024. The default value is 16. To allow for synthesized callchains, make the scripting_max_stack value at least the same size as the synthesized callchain size. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-21-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 5c3c02d5af53..8ce1c6bbfa45 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1748,6 +1748,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) } } + if (itrace_synth_opts.callchain && + itrace_synth_opts.callchain_sz > scripting_max_stack) + scripting_max_stack = itrace_synth_opts.callchain_sz; + /* make sure PERF_EXEC_PATH is set for scripts */ perf_set_argv_exec_path(perf_exec_path()); From dddcf6abbf5946f9ec1183dd2099cede6dbe12fc Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:52 +0300 Subject: [PATCH 125/260] perf evlist: Add perf_evlist__id2evsel_strict() perf_evlist__id2evsel_strict() is the same as perf_evlist__id2evsel() except that it ensures that the id must match. This will be used by perf inject to find a specific evsel that is to be deleted, hence the need to match exactly. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-22-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 15 +++++++++++++++ tools/perf/util/evlist.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a8643735dcea..e6760380d731 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -617,6 +617,21 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) return NULL; } +struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, + u64 id) +{ + struct perf_sample_id *sid; + + if (!id) + return NULL; + + sid = perf_evlist__id2sid(evlist, id); + if (sid) + return sid->evsel; + + return NULL; +} + static int perf_evlist__event2id(struct perf_evlist *evlist, union perf_event *event, u64 *id) { diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 115d8b53c601..0edf0d4f4efa 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -104,6 +104,8 @@ int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mas int perf_evlist__poll(struct perf_evlist *evlist, int timeout); struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); +struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, + u64 id); struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); From 4768230ad57d4e4fc6d36c44e98e0062c89b0dc0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:53 +0300 Subject: [PATCH 126/260] perf evlist: Add perf_evlist__remove() Add a counterpart to perf_evlist__add() that does the opposite and deletes the evsel. This will be used by perf inject to remove unwanted evsels. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-23-git-send-email-adrian.hunter@intel.com [ Renamed it from perf_evlist__del() to perf_evlist__remove() and removed the perf_evsel__delete() call ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 7 +++++++ tools/perf/util/evlist.h | 1 + 2 files changed, 8 insertions(+) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index e6760380d731..89546228b8ed 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -165,6 +165,13 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) __perf_evlist__propagate_maps(evlist, entry); } +void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel) +{ + evsel->evlist = NULL; + list_del_init(&evsel->node); + evlist->nr_entries -= 1; +} + void perf_evlist__splice_list_tail(struct perf_evlist *evlist, struct list_head *list) { diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 0edf0d4f4efa..66bc9d4c0869 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -73,6 +73,7 @@ void perf_evlist__exit(struct perf_evlist *evlist); void perf_evlist__delete(struct perf_evlist *evlist); void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); +void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel); int perf_evlist__add_default(struct perf_evlist *evlist); int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); From 73117308f953afb60a1383725b7d5372feeb2433 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:54 +0300 Subject: [PATCH 127/260] perf inject: Remove more aux-related stuff when processing instruction traces perf inject can process instruction traces (using the --itrace option) which removes aux-related events and replaces them with the requested synthesized events. However there are still some leftovers, namely PERF_RECORD_ITRACE_START events and the original evsel (selected event) e.g. intel_pt// For the sake of completeness, remove them too. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-24-git-send-email-adrian.hunter@intel.com [ Made it use perf_evlist__remove() + perf_evsel__delete() ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 8638fad8a085..9b6119f134b4 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -31,6 +31,7 @@ struct perf_inject { const char *input_name; struct perf_data_file output; u64 bytes_written; + u64 aux_id; struct list_head samples; struct itrace_synth_opts itrace_synth_opts; }; @@ -176,6 +177,19 @@ static int perf_event__repipe(struct perf_tool *tool, return perf_event__repipe_synth(tool, event); } +static int perf_event__drop_aux(struct perf_tool *tool, + union perf_event *event __maybe_unused, + struct perf_sample *sample, + struct machine *machine __maybe_unused) +{ + struct perf_inject *inject = container_of(tool, struct perf_inject, tool); + + if (!inject->aux_id) + inject->aux_id = sample->id; + + return 0; +} + typedef int (*inject_handler)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -512,6 +526,8 @@ static int __cmd_inject(struct perf_inject *inject) inject->tool.id_index = perf_event__repipe_id_index; inject->tool.auxtrace_info = perf_event__process_auxtrace_info; inject->tool.auxtrace = perf_event__process_auxtrace; + inject->tool.aux = perf_event__drop_aux; + inject->tool.itrace_start = perf_event__drop_aux, inject->tool.ordered_events = true; inject->tool.ordering_requires_timestamps = true; /* Allow space in the header for new attributes */ @@ -535,14 +551,25 @@ static int __cmd_inject(struct perf_inject *inject) } /* * The AUX areas have been removed and replaced with - * synthesized hardware events, so clear the feature flag. + * synthesized hardware events, so clear the feature flag and + * remove the evsel. */ if (inject->itrace_synth_opts.set) { + struct perf_evsel *evsel; + perf_header__clear_feat(&session->header, HEADER_AUXTRACE); if (inject->itrace_synth_opts.last_branch) perf_header__set_feat(&session->header, HEADER_BRANCH_STACK); + evsel = perf_evlist__id2evsel_strict(session->evlist, + inject->aux_id); + if (evsel) { + pr_debug("Deleting %s\n", + perf_evsel__name(evsel)); + perf_evlist__remove(session->evlist, evsel); + perf_evsel__delete(evsel); + } } session->header.data_offset = output_data_offset; session->header.data_size = inject->bytes_written; From f56fb9864c501dc85ebe40af5bf925dd07d990c0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:55 +0300 Subject: [PATCH 128/260] perf inject: Add --strip option to strip out non-synthesized events Add a new option --strip which is used with --itrace to strip out non-synthesized events. This results in a perf.data file that is simpler for external tools to parse. In particular, this can be used to prepare a perf.data file for consumption by autofdo. A subsequent patch makes a change to Intel PT also to enable use with autofdo and gives an example of that use. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-25-git-send-email-adrian.hunter@intel.com [ Made it use perf_evlist__remove() + perf_evsel__delete() ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-inject.txt | 3 + tools/perf/builtin-inject.c | 92 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt index 0c721c3e37e1..0b1cedeef895 100644 --- a/tools/perf/Documentation/perf-inject.txt +++ b/tools/perf/Documentation/perf-inject.txt @@ -50,6 +50,9 @@ OPTIONS include::itrace.txt[] +--strip:: + Use with --itrace to strip out non-synthesized events. + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1] diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 9b6119f134b4..0a945d2e8ca5 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -28,6 +28,7 @@ struct perf_inject { bool build_ids; bool sched_stat; bool have_auxtrace; + bool strip; const char *input_name; struct perf_data_file output; u64 bytes_written; @@ -177,6 +178,14 @@ static int perf_event__repipe(struct perf_tool *tool, return perf_event__repipe_synth(tool, event); } +static int perf_event__drop(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_sample *sample __maybe_unused, + struct machine *machine __maybe_unused) +{ + return 0; +} + static int perf_event__drop_aux(struct perf_tool *tool, union perf_event *event __maybe_unused, struct perf_sample *sample, @@ -480,6 +489,78 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel, return 0; } +static int drop_sample(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_sample *sample __maybe_unused, + struct perf_evsel *evsel __maybe_unused, + struct machine *machine __maybe_unused) +{ + return 0; +} + +static void strip_init(struct perf_inject *inject) +{ + struct perf_evlist *evlist = inject->session->evlist; + struct perf_evsel *evsel; + + inject->tool.context_switch = perf_event__drop; + + evlist__for_each(evlist, evsel) + evsel->handler = drop_sample; +} + +static bool has_tracking(struct perf_evsel *evsel) +{ + return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm || + evsel->attr.task; +} + +#define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \ + PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER) + +/* + * In order that the perf.data file is parsable, tracking events like MMAP need + * their selected event to exist, except if there is only 1 selected event left + * and it has a compatible sample type. + */ +static bool ok_to_remove(struct perf_evlist *evlist, + struct perf_evsel *evsel_to_remove) +{ + struct perf_evsel *evsel; + int cnt = 0; + bool ok = false; + + if (!has_tracking(evsel_to_remove)) + return true; + + evlist__for_each(evlist, evsel) { + if (evsel->handler != drop_sample) { + cnt += 1; + if ((evsel->attr.sample_type & COMPAT_MASK) == + (evsel_to_remove->attr.sample_type & COMPAT_MASK)) + ok = true; + } + } + + return ok && cnt == 1; +} + +static void strip_fini(struct perf_inject *inject) +{ + struct perf_evlist *evlist = inject->session->evlist; + struct perf_evsel *evsel, *tmp; + + /* Remove non-synthesized evsels if possible */ + evlist__for_each_safe(evlist, tmp, evsel) { + if (evsel->handler == drop_sample && + ok_to_remove(evlist, evsel)) { + pr_debug("Deleting %s\n", perf_evsel__name(evsel)); + perf_evlist__remove(evlist, evsel); + perf_evsel__delete(evsel); + } + } +} + static int __cmd_inject(struct perf_inject *inject) { int ret = -EINVAL; @@ -532,6 +613,8 @@ static int __cmd_inject(struct perf_inject *inject) inject->tool.ordering_requires_timestamps = true; /* Allow space in the header for new attributes */ output_data_offset = 4096; + if (inject->strip) + strip_init(inject); } if (!inject->itrace_synth_opts.set) @@ -570,6 +653,8 @@ static int __cmd_inject(struct perf_inject *inject) perf_evlist__remove(session->evlist, evsel); perf_evsel__delete(evsel); } + if (inject->strip) + strip_fini(inject); } session->header.data_offset = output_data_offset; session->header.data_size = inject->bytes_written; @@ -635,6 +720,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, NULL, "opts", "Instruction Tracing options", itrace_parse_synth_opts), + OPT_BOOLEAN(0, "strip", &inject.strip, + "strip non-synthesized events (use with --itrace)"), OPT_END() }; const char * const inject_usage[] = { @@ -650,6 +737,11 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) if (argc) usage_with_options(inject_usage, options); + if (inject.strip && !inject.itrace_synth_opts.set) { + pr_err("--strip option requires --itrace option\n"); + return -1; + } + if (perf_data_file__open(&inject.output)) { perror("failed to create output file"); return -1; From ba11ba65e02836c475427ae199adfc2d8cc4a900 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:56 +0300 Subject: [PATCH 129/260] perf intel-pt: Add mispred-all config option to aid use with autofdo autofdo incorrectly expects branch flags to include either mispred or predicted. In fact mispred = predicted = 0 is valid and means the flags are not supported, which they aren't by Intel PT. To make autofdo work, add a config option which will cause Intel PT decoder to set the mispred flag on all branches. Below is an example of using Intel PT with autofdo. The example is also added to the Intel PT documentation. It requires autofdo (https://github.com/google/autofdo) and gcc version 5. The bubble sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial) amended to take the number of elements as a parameter. $ gcc-5 -O3 sort.c -o sort_optimized $ ./sort_optimized 30000 Bubble sorting array of 30000 elements 2254 ms $ cat ~/.perfconfig [intel-pt] mispred-all $ perf record -e intel_pt//u ./sort 3000 Bubble sorting array of 3000 elements 58 ms [ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 3.939 MB perf.data ] $ perf inject -i perf.data -o inj --itrace=i100usle --strip $ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1 $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo $ ./sort_autofdo 30000 Bubble sorting array of 30000 elements 2155 ms Note there is currently no advantage to using Intel PT instead of LBR, but that may change in the future if greater use is made of the data. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-26-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/intel-pt.txt | 29 +++++++++++++++++++++++++++ tools/perf/util/intel-pt.c | 14 +++++++++++++ 2 files changed, 43 insertions(+) diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index a0fbb5d71f7d..be764f9ec769 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt @@ -764,3 +764,32 @@ perf inject also accepts the --itrace option in which case tracing data is removed and replaced with the synthesized events. e.g. perf inject --itrace -i perf.data -o perf.data.new + +Below is an example of using Intel PT with autofdo. It requires autofdo +(https://github.com/google/autofdo) and gcc version 5. The bubble +sort example is from the AutoFDO tutorial (https://gcc.gnu.org/wiki/AutoFDO/Tutorial) +amended to take the number of elements as a parameter. + + $ gcc-5 -O3 sort.c -o sort_optimized + $ ./sort_optimized 30000 + Bubble sorting array of 30000 elements + 2254 ms + + $ cat ~/.perfconfig + [intel-pt] + mispred-all + + $ perf record -e intel_pt//u ./sort 3000 + Bubble sorting array of 3000 elements + 58 ms + [ perf record: Woken up 2 times to write data ] + [ perf record: Captured and wrote 3.939 MB perf.data ] + $ perf inject -i perf.data -o inj --itrace=i100usle --strip + $ ./create_gcov --binary=./sort --profile=inj --gcov=sort.gcov -gcov_version=1 + $ gcc-5 -O3 -fauto-profile=sort.gcov sort.c -o sort_autofdo + $ ./sort_autofdo 30000 + Bubble sorting array of 30000 elements + 2155 ms + +Note there is currently no advantage to using Intel PT instead of LBR, but +that may change in the future if greater use is made of the data. diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 05e8fcc5188b..03ff072b5993 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -64,6 +64,7 @@ struct intel_pt { bool data_queued; bool est_tsc; bool sync_switch; + bool mispred_all; int have_sched_switch; u32 pmu_type; u64 kernel_start; @@ -943,6 +944,7 @@ static void intel_pt_update_last_branch_rb(struct intel_pt_queue *ptq) be->flags.abort = !!(state->flags & INTEL_PT_ABORT_TX); be->flags.in_tx = !!(state->flags & INTEL_PT_IN_TX); /* No support for mispredict */ + be->flags.mispred = ptq->pt->mispred_all; if (bs->nr < ptq->pt->synth_opts.last_branch_sz) bs->nr += 1; @@ -1967,6 +1969,16 @@ static bool intel_pt_find_switch(struct perf_evlist *evlist) return false; } +static int intel_pt_perf_config(const char *var, const char *value, void *data) +{ + struct intel_pt *pt = data; + + if (!strcmp(var, "intel-pt.mispred-all")) + pt->mispred_all = perf_config_bool(var, value); + + return 0; +} + static const char * const intel_pt_info_fmts[] = { [INTEL_PT_PMU_TYPE] = " PMU Type %"PRId64"\n", [INTEL_PT_TIME_SHIFT] = " Time Shift %"PRIu64"\n", @@ -2011,6 +2023,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, if (!pt) return -ENOMEM; + perf_config(intel_pt_perf_config, pt); + err = auxtrace_queues__init(&pt->queues); if (err) goto err_free; From 0b8891a8e62cb537b65ebc55cfbbb4ec22333c44 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Mon, 28 Sep 2015 03:52:13 +0000 Subject: [PATCH 130/260] perf tools: Adds the config_term callback for different type events Currently, function config_term() is used for checking config terms of all types of events, while unknown terms is not reported as an error because pmu events have valid terms in sysfs. But this is wrong when unknown terms are specificed to hw/sw events. This patch Adds the config_term callback so we can use separate check routines for each type of events. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Kan Liang Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1443412336-120050-1-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 38 +++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 61c2bc20926d..9dc3fb6ee81e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -599,9 +599,13 @@ static int check_type_val(struct parse_events_term *term, return -EINVAL; } -static int config_term(struct perf_event_attr *attr, - struct parse_events_term *term, - struct parse_events_error *err) +typedef int config_term_func_t(struct perf_event_attr *attr, + struct parse_events_term *term, + struct parse_events_error *err); + +static int config_term_common(struct perf_event_attr *attr, + struct parse_events_term *term, + struct parse_events_error *err) { #define CHECK_TYPE_VAL(type) \ do { \ @@ -610,12 +614,6 @@ do { \ } while (0) switch (term->type_term) { - case PARSE_EVENTS__TERM_TYPE_USER: - /* - * Always succeed for sysfs terms, as we dont know - * at this point what type they need to have. - */ - return 0; case PARSE_EVENTS__TERM_TYPE_CONFIG: CHECK_TYPE_VAL(NUM); attr->config = term->val.num; @@ -665,9 +663,24 @@ do { \ #undef CHECK_TYPE_VAL } +static int config_term_pmu(struct perf_event_attr *attr, + struct parse_events_term *term, + struct parse_events_error *err) +{ + if (term->type_term == PARSE_EVENTS__TERM_TYPE_USER) + /* + * Always succeed for sysfs terms, as we dont know + * at this point what type they need to have. + */ + return 0; + else + return config_term_common(attr, term, err); +} + static int config_attr(struct perf_event_attr *attr, struct list_head *head, - struct parse_events_error *err) + struct parse_events_error *err, + config_term_func_t config_term) { struct parse_events_term *term; @@ -735,7 +748,8 @@ int parse_events_add_numeric(struct parse_events_evlist *data, attr.config = config; if (head_config) { - if (config_attr(&attr, head_config, data->error)) + if (config_attr(&attr, head_config, data->error, + config_term_common)) return -EINVAL; if (get_config_terms(head_config, &config_terms)) @@ -795,7 +809,7 @@ int parse_events_add_pmu(struct parse_events_evlist *data, * Configure hardcoded terms first, no need to check * return value when called with fail == 0 ;) */ - if (config_attr(&attr, head_config, data->error)) + if (config_attr(&attr, head_config, data->error, config_term_pmu)) return -EINVAL; if (get_config_terms(head_config, &config_terms)) From ffeb883e5662e94b14948078e85812261277ad67 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Mon, 28 Sep 2015 03:52:14 +0000 Subject: [PATCH 131/260] perf tools: Show proper error message for wrong terms of hw/sw events Show proper error message and show valid terms when wrong config terms is specified for hw/sw type perf events. This patch makes the original error format function formats_error_string() more generic, which only outputs the static config terms for hw/sw perf events, and prepends pmu formats for pmu events. Before this patch: $ perf record -e 'cpu-clock/freqx=200/' -a sleep 1 invalid or unsupported event: 'cpu-clock/freqx=200/' Run 'perf list' for a list of valid events usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events After this patch: $ perf record -e 'cpu-clock/freqx=200/' -a sleep 1 event syntax error: 'cpu-clock/freqx=200/' \___ unknown term valid terms: config,config1,config2,name,period,freq,branch_type,time,call-graph,stack-size Run 'perf list' for a list of valid events usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Kan Liang Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1443412336-120050-2-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 29 ++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 1 + tools/perf/util/parse-events.l | 2 +- tools/perf/util/pmu.c | 37 +++++++++++++--------------------- 4 files changed, 45 insertions(+), 24 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 9dc3fb6ee81e..ea64ec0720ca 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -656,6 +656,9 @@ do { \ CHECK_TYPE_VAL(STR); break; default: + err->str = strdup("unknown term"); + err->idx = term->err_term; + err->help = parse_events_formats_error_string(NULL); return -EINVAL; } @@ -1875,3 +1878,29 @@ void parse_events_evlist_error(struct parse_events_evlist *data, err->str = strdup(str); WARN_ONCE(!err->str, "WARNING: failed to allocate error string"); } + +/* + * Return string contains valid config terms of an event. + * @additional_terms: For terms such as PMU sysfs terms. + */ +char *parse_events_formats_error_string(char *additional_terms) +{ + char *str; + static const char *static_terms = "config,config1,config2,name," + "period,freq,branch_type,time," + "call-graph,stack-size\n"; + + /* valid terms */ + if (additional_terms) { + if (!asprintf(&str, "valid terms: %s,%s", + additional_terms, static_terms)) + goto fail; + } else { + if (!asprintf(&str, "valid terms: %s", static_terms)) + goto fail; + } + return str; + +fail: + return NULL; +} diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index ffee7ece75a6..c7b904a49189 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -156,5 +156,6 @@ int print_hwcache_events(const char *event_glob, bool name_only); extern int is_valid_tracepoint(const char *event_string); int valid_event_mount(const char *eventfs); +char *parse_events_formats_error_string(char *additional_terms); #endif /* __PERF_PARSE_EVENTS_H */ diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 936d566f48d8..c29832bce496 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -174,7 +174,7 @@ modifier_bp [rwx]{1,3} { /* - * Please update formats_error_string any time + * Please update parse_events_formats_error_string any time * new static term is added. */ config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 89c91a1a67e7..ac42c97be9e4 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -626,38 +626,26 @@ static int pmu_resolve_param_term(struct parse_events_term *term, return -1; } -static char *formats_error_string(struct list_head *formats) +static char *pmu_formats_string(struct list_head *formats) { struct perf_pmu_format *format; - char *err, *str; - static const char *static_terms = "config,config1,config2,name," - "period,freq,branch_type,time," - "call-graph,stack-size\n"; + char *str; + struct strbuf buf; unsigned i = 0; - if (!asprintf(&str, "valid terms:")) + if (!formats) return NULL; + strbuf_init(&buf, 0); /* sysfs exported terms */ - list_for_each_entry(format, formats, list) { - char c = i++ ? ',' : ' '; + list_for_each_entry(format, formats, list) + strbuf_addf(&buf, i++ ? ",%s" : "%s", + format->name); - err = str; - if (!asprintf(&str, "%s%c%s", err, c, format->name)) - goto fail; - free(err); - } + str = strbuf_detach(&buf, NULL); + strbuf_release(&buf); - /* static terms */ - err = str; - if (!asprintf(&str, "%s,%s", err, static_terms)) - goto fail; - - free(err); return str; -fail: - free(err); - return NULL; } /* @@ -693,9 +681,12 @@ static int pmu_config_term(struct list_head *formats, if (verbose) printf("Invalid event/parameter '%s'\n", term->config); if (err) { + char *pmu_term = pmu_formats_string(formats); + err->idx = term->err_term; err->str = strdup("unknown term"); - err->help = formats_error_string(formats); + err->help = parse_events_formats_error_string(pmu_term); + free(pmu_term); } return -EINVAL; } From 865582c3f48e12b7ab9e260161868313e4a37f44 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Mon, 28 Sep 2015 03:52:15 +0000 Subject: [PATCH 132/260] perf tools: Adds the tracepoint name parsing support Adds rules for parsing tracepoint names. Change rules of tracepoint which derives from PE_NAMEs into tracepoint names directly, so adding more rules based on tracepoint names will be easier. Changes v2-v3: - Change __event_legacy_tracepoint label in bison file to tracepoint_name - Fix formats error. Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Kan Liang Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1443412336-120050-3-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 37 +++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 8bcc45868457..1c598c2f8dfc 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -67,6 +67,7 @@ static inc_group_count(struct list_head *list, %type event_legacy_cache %type event_legacy_mem %type event_legacy_tracepoint +%type tracepoint_name %type event_legacy_numeric %type event_legacy_raw %type event_def @@ -84,6 +85,10 @@ static inc_group_count(struct list_head *list, u64 num; struct list_head *head; struct parse_events_term *term; + struct tracepoint_name { + char *sys; + char *event; + } tracepoint_name; } %% @@ -368,36 +373,40 @@ PE_PREFIX_MEM PE_VALUE sep_dc } event_legacy_tracepoint: -PE_NAME '-' PE_NAME ':' PE_NAME +tracepoint_name { struct parse_events_evlist *data = _data; struct parse_events_error *error = data->error; struct list_head *list; - char sys_name[128]; - snprintf(&sys_name, 128, "%s-%s", $1, $3); ALLOC_LIST(list); - if (parse_events_add_tracepoint(list, &data->idx, &sys_name, $5, error)) { + if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event, + error)) { if (error) error->idx = @1.first_column; return -1; } $$ = list; } + +tracepoint_name: +PE_NAME '-' PE_NAME ':' PE_NAME +{ + char sys_name[128]; + struct tracepoint_name tracepoint; + + snprintf(&sys_name, 128, "%s-%s", $1, $3); + tracepoint.sys = &sys_name; + tracepoint.event = $5; + + $$ = tracepoint; +} | PE_NAME ':' PE_NAME { - struct parse_events_evlist *data = _data; - struct parse_events_error *error = data->error; - struct list_head *list; + struct tracepoint_name tracepoint = {$1, $3}; - ALLOC_LIST(list); - if (parse_events_add_tracepoint(list, &data->idx, $1, $3, error)) { - if (error) - error->idx = @1.first_column; - return -1; - } - $$ = list; + $$ = tracepoint; } event_legacy_numeric: From e637d17757a10732fa5d573c18f20b3cd4d31245 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Mon, 28 Sep 2015 03:52:16 +0000 Subject: [PATCH 133/260] perf tools: Enable event_config terms to tracepoint events This patch enables config terms for tracepoint perf events. Valid terms for tracepoint events are 'call-graph' and 'stack-size', so we can use different callgraph settings for each event and eliminate unnecessary overhead. Here is an example for using different call-graph config for each tracepoint. $ perf record -e syscalls:sys_enter_write/call-graph=fp/ -e syscalls:sys_exit_write/call-graph=no/ dd if=/dev/zero of=test bs=4k count=10 $ perf report --stdio # # Total Lost Samples: 0 # # Samples: 13 of event 'syscalls:sys_enter_write' # Event count (approx.): 13 # # Children Self Command Shared Object Symbol # ........ ........ ....... .................. ...................... # 76.92% 76.92% dd libpthread-2.20.so [.] __write_nocancel | ---__write_nocancel 23.08% 23.08% dd libc-2.20.so [.] write | ---write | |--33.33%-- 0x2031342820736574 | |--33.33%-- 0xa6e69207364726f | --33.33%-- 0x34202c7320393039 ... # Samples: 13 of event 'syscalls:sys_exit_write' # Event count (approx.): 13 # # Children Self Command Shared Object Symbol # ........ ........ ....... .................. ...................... # 76.92% 76.92% dd libpthread-2.20.so [.] __write_nocancel 23.08% 23.08% dd libc-2.20.so [.] write 7.69% 0.00% dd [unknown] [.] 0x0a6e69207364726f 7.69% 0.00% dd [unknown] [.] 0x2031342820736574 7.69% 0.00% dd [unknown] [.] 0x34202c7320393039 Signed-off-by: He Kuang Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Kan Liang Cc: Peter Zijlstra Cc: Wang Nan Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1443412336-120050-4-git-send-email-hekuang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 84 ++++++++++++++++++++++++++-------- tools/perf/util/parse-events.h | 3 +- tools/perf/util/parse-events.y | 26 +++++++++-- 3 files changed, 90 insertions(+), 23 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index ea64ec0720ca..5ffb356cbcc6 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -27,6 +27,8 @@ extern int parse_events_debug; #endif int parse_events_parse(void *data, void *scanner); +static int get_config_terms(struct list_head *head_config, + struct list_head *head_terms __maybe_unused); static struct perf_pmu_event_symbol *perf_pmu_events_list; /* @@ -416,7 +418,8 @@ static void tracepoint_error(struct parse_events_error *error, int err, static int add_tracepoint(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error __maybe_unused) + struct parse_events_error *error __maybe_unused, + struct list_head *head_config) { struct perf_evsel *evsel; @@ -426,13 +429,22 @@ static int add_tracepoint(struct list_head *list, int *idx, return PTR_ERR(evsel); } + if (head_config) { + LIST_HEAD(config_terms); + + if (get_config_terms(head_config, &config_terms)) + return -ENOMEM; + list_splice(&config_terms, &evsel->config_terms); + } + list_add_tail(&evsel->node, list); return 0; } static int add_tracepoint_multi_event(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error) + struct parse_events_error *error, + struct list_head *head_config) { char evt_path[MAXPATHLEN]; struct dirent *evt_ent; @@ -456,7 +468,8 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, if (!strglobmatch(evt_ent->d_name, evt_name)) continue; - ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, error); + ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, + error, head_config); } closedir(evt_dir); @@ -465,16 +478,20 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, static int add_tracepoint_event(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error) + struct parse_events_error *error, + struct list_head *head_config) { return strpbrk(evt_name, "*?") ? - add_tracepoint_multi_event(list, idx, sys_name, evt_name, error) : - add_tracepoint(list, idx, sys_name, evt_name, error); + add_tracepoint_multi_event(list, idx, sys_name, evt_name, + error, head_config) : + add_tracepoint(list, idx, sys_name, evt_name, + error, head_config); } static int add_tracepoint_multi_sys(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error) + struct parse_events_error *error, + struct list_head *head_config) { struct dirent *events_ent; DIR *events_dir; @@ -498,23 +515,13 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, continue; ret = add_tracepoint_event(list, idx, events_ent->d_name, - evt_name, error); + evt_name, error, head_config); } closedir(events_dir); return ret; } -int parse_events_add_tracepoint(struct list_head *list, int *idx, - char *sys, char *event, - struct parse_events_error *error) -{ - if (strpbrk(sys, "*?")) - return add_tracepoint_multi_sys(list, idx, sys, event, error); - else - return add_tracepoint_event(list, idx, sys, event, error); -} - static int parse_breakpoint_type(const char *type, struct perf_event_attr *attr) { @@ -680,6 +687,26 @@ static int config_term_pmu(struct perf_event_attr *attr, return config_term_common(attr, term, err); } +static int config_term_tracepoint(struct perf_event_attr *attr, + struct parse_events_term *term, + struct parse_events_error *err) +{ + switch (term->type_term) { + case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: + case PARSE_EVENTS__TERM_TYPE_STACKSIZE: + return config_term_common(attr, term, err); + default: + if (err) { + err->idx = term->err_term; + err->str = strdup("unknown term"); + err->help = strdup("valid terms: call-graph,stack-size\n"); + } + return -EINVAL; + } + + return 0; +} + static int config_attr(struct perf_event_attr *attr, struct list_head *head, struct parse_events_error *err, @@ -738,6 +765,27 @@ do { \ return 0; } +int parse_events_add_tracepoint(struct list_head *list, int *idx, + char *sys, char *event, + struct parse_events_error *error, + struct list_head *head_config) +{ + if (head_config) { + struct perf_event_attr attr; + + if (config_attr(&attr, head_config, error, + config_term_tracepoint)) + return -EINVAL; + } + + if (strpbrk(sys, "*?")) + return add_tracepoint_multi_sys(list, idx, sys, event, + error, head_config); + else + return add_tracepoint_event(list, idx, sys, event, + error, head_config); +} + int parse_events_add_numeric(struct parse_events_evlist *data, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index c7b904a49189..f13d3ccda444 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -119,7 +119,8 @@ int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events_name(struct list_head *list, char *name); int parse_events_add_tracepoint(struct list_head *list, int *idx, char *sys, char *event, - struct parse_events_error *error); + struct parse_events_error *error, + struct list_head *head_config); int parse_events_add_numeric(struct parse_events_evlist *data, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 1c598c2f8dfc..ae6af269f9c9 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -380,12 +380,30 @@ tracepoint_name struct list_head *list; ALLOC_LIST(list); + if (error) + error->idx = @1.first_column; + if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event, - error)) { - if (error) - error->idx = @1.first_column; + error, NULL)) return -1; - } + + $$ = list; +} +| +tracepoint_name '/' event_config '/' +{ + struct parse_events_evlist *data = _data; + struct parse_events_error *error = data->error; + struct list_head *list; + + ALLOC_LIST(list); + if (error) + error->idx = @1.first_column; + + if (parse_events_add_tracepoint(list, &data->idx, $1.sys, $1.event, + error, $3)) + return -1; + $$ = list; } From 45633a169571e81835ec53fe0c089dd20f3195f1 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 29 Sep 2015 16:53:12 +0200 Subject: [PATCH 134/260] tools: Fix shadowed declaration in err.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error variable breaks build on CentOS 6.7, due to collision with global error symbol: CC util/evlist.o cc1: warnings being treated as errors In file included from util/evlist.c:28: tools/include/linux/err.h: In function ‘ERR_PTR’: tools/include/linux/err.h:34: error: declaration of ‘error’ shadows a global declaration util/util.h:135: error: shadowed declaration is here Using 'error_' name instead to fix it. Signed-off-by: Jiri Olsa Link: http://lkml.kernel.org/n/tip-i9mdgdbrgauy3fe76s9rd125@git.kernel.org Reported-by: Vinson Lee [ Use 'error_' instead of 'err' to, visually, not diverge too much from include/linux/err.h ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/err.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/include/linux/err.h b/tools/include/linux/err.h index c9ada48f5156..bdc3dd8131d4 100644 --- a/tools/include/linux/err.h +++ b/tools/include/linux/err.h @@ -31,9 +31,9 @@ #define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO) -static inline void * __must_check ERR_PTR(long error) +static inline void * __must_check ERR_PTR(long error_) { - return (void *) error; + return (void *) error_; } static inline long __must_check PTR_ERR(__force const void *ptr) From 272ed29a91aea4397c05157dea7210dd7e81557a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 29 Sep 2015 17:05:31 +0200 Subject: [PATCH 135/260] perf tools: Fix shadowed declaration in parse-events.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error variable breaks build on CentOS 6.7, due to a collision with a global error symbol: CC util/parse-events.o cc1: warnings being treated as errors util/parse-events.c:419: error: declaration of ‘error’ shadows a global declaration util/util.h:135: error: shadowed declaration is here util/parse-events.c: In function ‘add_tracepoint_multi_event’: ... Using different argument names instead to fix it. Reported-by: Vinson Lee Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: He Kuang Cc: H. Peter Anvin Cc: Jiri Olsa Cc: linux-tip-commits@vger.kernel.org Cc: Matt Fleming Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Raphael Beamonte Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20150929150531.GI27383@krava.redhat.com [ Fix one more case, at line 770 ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5ffb356cbcc6..c1c64fb647aa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -389,7 +389,7 @@ int parse_events_add_cache(struct list_head *list, int *idx, return add_event(list, idx, &attr, name, NULL); } -static void tracepoint_error(struct parse_events_error *error, int err, +static void tracepoint_error(struct parse_events_error *e, int err, char *sys, char *name) { char help[BUFSIZ]; @@ -402,30 +402,30 @@ static void tracepoint_error(struct parse_events_error *error, int err, switch (err) { case EACCES: - error->str = strdup("can't access trace events"); + e->str = strdup("can't access trace events"); break; case ENOENT: - error->str = strdup("unknown tracepoint"); + e->str = strdup("unknown tracepoint"); break; default: - error->str = strdup("failed to add tracepoint"); + e->str = strdup("failed to add tracepoint"); break; } tracing_path__strerror_open_tp(err, help, sizeof(help), sys, name); - error->help = strdup(help); + e->help = strdup(help); } static int add_tracepoint(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error __maybe_unused, + struct parse_events_error *err, struct list_head *head_config) { struct perf_evsel *evsel; evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); if (IS_ERR(evsel)) { - tracepoint_error(error, PTR_ERR(evsel), sys_name, evt_name); + tracepoint_error(err, PTR_ERR(evsel), sys_name, evt_name); return PTR_ERR(evsel); } @@ -443,7 +443,7 @@ static int add_tracepoint(struct list_head *list, int *idx, static int add_tracepoint_multi_event(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error, + struct parse_events_error *err, struct list_head *head_config) { char evt_path[MAXPATHLEN]; @@ -454,7 +454,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); evt_dir = opendir(evt_path); if (!evt_dir) { - tracepoint_error(error, errno, sys_name, evt_name); + tracepoint_error(err, errno, sys_name, evt_name); return -1; } @@ -469,7 +469,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, continue; ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, - error, head_config); + err, head_config); } closedir(evt_dir); @@ -478,19 +478,19 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, static int add_tracepoint_event(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error, + struct parse_events_error *err, struct list_head *head_config) { return strpbrk(evt_name, "*?") ? add_tracepoint_multi_event(list, idx, sys_name, evt_name, - error, head_config) : + err, head_config) : add_tracepoint(list, idx, sys_name, evt_name, - error, head_config); + err, head_config); } static int add_tracepoint_multi_sys(struct list_head *list, int *idx, char *sys_name, char *evt_name, - struct parse_events_error *error, + struct parse_events_error *err, struct list_head *head_config) { struct dirent *events_ent; @@ -499,7 +499,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, events_dir = opendir(tracing_events_path); if (!events_dir) { - tracepoint_error(error, errno, sys_name, evt_name); + tracepoint_error(err, errno, sys_name, evt_name); return -1; } @@ -515,7 +515,7 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, continue; ret = add_tracepoint_event(list, idx, events_ent->d_name, - evt_name, error, head_config); + evt_name, err, head_config); } closedir(events_dir); @@ -767,23 +767,23 @@ do { \ int parse_events_add_tracepoint(struct list_head *list, int *idx, char *sys, char *event, - struct parse_events_error *error, + struct parse_events_error *err, struct list_head *head_config) { if (head_config) { struct perf_event_attr attr; - if (config_attr(&attr, head_config, error, + if (config_attr(&attr, head_config, err, config_term_tracepoint)) return -EINVAL; } if (strpbrk(sys, "*?")) return add_tracepoint_multi_sys(list, idx, sys, event, - error, head_config); + err, head_config); else return add_tracepoint_event(list, idx, sys, event, - error, head_config); + err, head_config); } int parse_events_add_numeric(struct parse_events_evlist *data, From b7f9ff5654d53fa47e0b5ff20f834f3e7a611846 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 29 Sep 2015 17:34:46 -0300 Subject: [PATCH 136/260] perf maps: Introduce maps__find_symbol_by_name() Out of map_groups__find_symbol_by_name(), so that we can turn this later one first into a call to maps__find_symbol_by_name(MAP__FUNCTION) + MAP__VARIABLE, and then to just one call, we'll merge MAP__FUNCTION with MAP__VARIABLE maps, to simplify the code. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-pvkar0jacqn92g148u9sqttt@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 19 +++++++++++++------ tools/perf/util/map.h | 2 ++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b1c475d9b240..622c2c9a1e65 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -553,13 +553,9 @@ struct symbol *map_groups__find_symbol(struct map_groups *mg, return NULL; } -struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, - enum map_type type, - const char *name, - struct map **mapp, - symbol_filter_t filter) +struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, + struct map **mapp, symbol_filter_t filter) { - struct maps *maps = &mg->maps[type]; struct symbol *sym; struct rb_node *nd; @@ -583,6 +579,17 @@ out: return sym; } +struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, + enum map_type type, + const char *name, + struct map **mapp, + symbol_filter_t filter) +{ + struct symbol *sym = maps__find_symbol_by_name(&mg->maps[type], name, mapp, filter); + + return sym; +} + int map_groups__find_ams(struct addr_map_symbol *ams, symbol_filter_t filter) { if (ams->addr < ams->map->start || ams->addr >= ams->map->end) { diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 57829e89b78b..7309d64ce39e 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -190,6 +190,8 @@ void maps__remove(struct maps *maps, struct map *map); struct map *maps__find(struct maps *maps, u64 addr); struct map *maps__first(struct maps *maps); struct map *map__next(struct map *map); +struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, + struct map **mapp, symbol_filter_t filter); void map_groups__init(struct map_groups *mg, struct machine *machine); void map_groups__exit(struct map_groups *mg); int map_groups__clone(struct map_groups *mg, From 40862a7b793945c7080d1566ca3dc6249f3c6354 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 29 Sep 2015 11:52:37 +0300 Subject: [PATCH 137/260] perf report: Amend documentation about max_stack and synthesized callchains The --max_stack option was added as an optimization to reduce processing time, so people specifying --max-stack might get a increased processing time if combined with synthesized callchains, but otherwise no real harm. A warning about setting both --max_stack and the synthesized callchains max depth seems like overkill. Amend the documentation. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/560A5155.4060105@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index b941d5e07e28..ce499035e6d8 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -205,6 +205,8 @@ OPTIONS beyond the specified depth will be ignored. This is a trade-off between information loss and faster processing especially for workloads that can have a very long callchain stack. + Note that when using the --itrace option the synthesized callchain size + will override this value if the synthesized callchain size is bigger. Default: 127 From eb56db54326f910348defbee2803ec0675a664b2 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Thu, 24 Sep 2015 17:53:49 -0400 Subject: [PATCH 138/260] perf tools: Fix build break on powerpc due to sample_reg_masks The perf_regs.c file does not get built on Powerpc as CONFIG_PERF_REGS is false. So the weak definition for 'sample_regs_masks' doesn't get picked up. Adding perf_regs.o to util/Build unconditionally, exposes a redefinition error for 'perf_reg_value()' function (due to the static inline version in util/perf_regs.h). So use #ifdef HAVE_PERF_REGS_SUPPORT' around that function. Signed-off-by: Sukadev Bhattiprolu Acked-by: Jiri Olsa Cc: Dominik Dingel Cc: Naveen N. Rao Cc: Stephane Eranian Cc: linuxppc-dev@ozlabs.org Link: http://lkml.kernel.org/r/20150930182836.GA27858@us.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 2 +- tools/perf/util/perf_regs.c | 2 ++ tools/perf/util/perf_regs.h | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 4bc7a9ab45b1..9217119c4108 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -18,6 +18,7 @@ libperf-y += levenshtein.o libperf-y += llvm-utils.o libperf-y += parse-options.o libperf-y += parse-events.o +libperf-y += perf_regs.o libperf-y += path.o libperf-y += rbtree.o libperf-y += bitmap.o @@ -104,7 +105,6 @@ libperf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o libperf-y += scripting-engines/ -libperf-$(CONFIG_PERF_REGS) += perf_regs.o libperf-$(CONFIG_ZLIB) += zlib.o libperf-$(CONFIG_LZMA) += lzma.o diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index 885e8ac83997..6b8eb13e14e4 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c @@ -6,6 +6,7 @@ const struct sample_reg __weak sample_reg_masks[] = { SMPL_REG_END }; +#ifdef HAVE_PERF_REGS_SUPPORT int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) { int i, idx = 0; @@ -29,3 +30,4 @@ out: *valp = regs->cache_regs[id]; return 0; } +#endif diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 2984dcc54d67..679d6e493962 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -2,6 +2,7 @@ #define __PERF_REGS_H #include +#include struct regs_dump; From 77e65977495cd6f6fcfacd8c16bdd9c8c18a1d72 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Sep 2015 11:08:58 -0300 Subject: [PATCH 139/260] perf machine: Use machine__kernel_map() thoroughly In places where we were using its open coded equivalent. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-khkdugcdoqy3tkszm3jdxgbe@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/tests/code-reading.c | 2 +- tools/perf/util/event.c | 7 +++---- tools/perf/util/machine.c | 23 ++++++++++++----------- tools/perf/util/map.c | 2 +- tools/perf/util/probe-event.c | 7 ++++--- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 23b1faaaa4cc..b122c4e0818e 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -329,7 +329,7 @@ static int build_alloc_func_list(void) return -EINVAL; } - kernel_map = machine->vmlinux_maps[MAP__FUNCTION]; + kernel_map = machine__kernel_map(machine, MAP__FUNCTION) if (map__load(kernel_map, NULL) < 0) { pr_err("cannot load kernel map\n"); return -ENOENT; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 37c9f5125887..7962605b3576 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -387,7 +387,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, static void report__warn_kptr_restrict(const struct report *rep) { - struct map *kernel_map = rep->session->machines.host.vmlinux_maps[MAP__FUNCTION]; + struct map *kernel_map = machine__kernel_map(&rep->session->machines.host, MAP__FUNCTION); struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL; if (kernel_map == NULL || diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 2d21183bd661..47017a8aa685 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -473,7 +473,7 @@ static int do_test_code_reading(bool try_kcore) symbol_conf.kallsyms_name = "/proc/kallsyms"; /* Load kernel map */ - map = machine->vmlinux_maps[MAP__FUNCTION]; + map = machine__kernel_map(machine, MAP__FUNCTION); ret = map__load(map, NULL); if (ret < 0) { pr_debug("map__load failed\n"); diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index b1bb348ec3b6..281ab7f87446 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -649,12 +649,12 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, size_t size; const char *mmap_name; char name_buff[PATH_MAX]; - struct map *map; + struct map *map = machine__kernel_map(machine, MAP__FUNCTION); struct kmap *kmap; int err; union perf_event *event; - if (machine->vmlinux_maps[0] == NULL) + if (map == NULL) return -1; /* @@ -680,7 +680,6 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; } - map = machine->vmlinux_maps[MAP__FUNCTION]; kmap = map__kmap(map); size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1; @@ -1008,7 +1007,7 @@ int perf_event__preprocess_sample(const union perf_event *event, * it now. */ if (cpumode == PERF_RECORD_MISC_KERNEL && - machine->vmlinux_maps[MAP__FUNCTION] == NULL) + machine__kernel_map(machine, MAP__FUNCTION) == NULL) machine__create_kernel_maps(machine); thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al); diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index fd1efeafb343..d71b7dcf4579 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -625,7 +625,7 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) { int i; size_t printed = 0; - struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; + struct dso *kdso = machine__kernel_map(machine, MAP__FUNCTION)->dso; if (kdso->has_build_id) { char filename[PATH_MAX]; @@ -741,6 +741,7 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; + struct map *map; machine->vmlinux_maps[type] = map__new2(start, kernel, type); if (machine->vmlinux_maps[type] == NULL) @@ -749,13 +750,13 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) machine->vmlinux_maps[type]->map_ip = machine->vmlinux_maps[type]->unmap_ip = identity__map_ip; - kmap = map__kmap(machine->vmlinux_maps[type]); + map = machine__kernel_map(machine, type); + kmap = map__kmap(map); if (!kmap) return -1; kmap->kmaps = &machine->kmaps; - map_groups__insert(&machine->kmaps, - machine->vmlinux_maps[type]); + map_groups__insert(&machine->kmaps, map); } return 0; @@ -767,13 +768,13 @@ void machine__destroy_kernel_maps(struct machine *machine) for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; + struct map *map = machine__kernel_map(machine, type); - if (machine->vmlinux_maps[type] == NULL) + if (map == NULL) continue; - kmap = map__kmap(machine->vmlinux_maps[type]); - map_groups__remove(&machine->kmaps, - machine->vmlinux_maps[type]); + kmap = map__kmap(map); + map_groups__remove(&machine->kmaps, map); if (kmap && kmap->ref_reloc_sym) { /* * ref_reloc_sym is shared among all maps, so free just @@ -867,7 +868,7 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) int machine__load_kallsyms(struct machine *machine, const char *filename, enum map_type type, symbol_filter_t filter) { - struct map *map = machine->vmlinux_maps[type]; + struct map *map = machine__kernel_map(machine, MAP__FUNCTION); int ret = dso__load_kallsyms(map->dso, filename, map, filter); if (ret > 0) { @@ -886,7 +887,7 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, int machine__load_vmlinux_path(struct machine *machine, enum map_type type, symbol_filter_t filter) { - struct map *map = machine->vmlinux_maps[type]; + struct map *map = machine__kernel_map(machine, MAP__FUNCTION); int ret = dso__load_vmlinux_path(map->dso, map, filter); if (ret > 0) @@ -1244,7 +1245,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, /* * preload dso of guest kernel and modules */ - dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION], + dso__load(kernel, machine__kernel_map(machine, MAP__FUNCTION), NULL); } } diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 622c2c9a1e65..2a9d859d30b9 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -235,7 +235,7 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type) */ bool __map__is_kernel(const struct map *map) { - return map->groups->machine->vmlinux_maps[map->type] == map; + return machine__kernel_map(map->groups->machine, map->type) == map; } static void map__exit(struct map *map) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 7fb0533ab18c..a0b3f3c886f0 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -126,11 +126,12 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) { /* kmap->ref_reloc_sym should be set if host_machine is initialized */ struct kmap *kmap; + struct map *map = machine__kernel_map(host_machine, MAP__FUNCTION); - if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0) + if (map__load(map, NULL) < 0) return NULL; - kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); + kmap = map__kmap(map); if (!kmap) return NULL; return kmap->ref_reloc_sym; @@ -281,7 +282,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso) return -ENOENT; } - map = host_machine->vmlinux_maps[MAP__FUNCTION]; + map = machine__kernel_map(host_machine, MAP__FUNCTION); dso = map->dso; vmlinux_name = symbol_conf.vmlinux_name; From a5e813c68649366aaa3f785772b00ea6ccad7b8d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Sep 2015 11:54:04 -0300 Subject: [PATCH 140/260] perf machine: Add method for common kernel_map(FUNCTION) operation And it is also a step in the direction of killing the separation of data and text maps in map_groups. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-rrds86kb3wx5wk8v38v56gw8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kmem.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/tests/code-reading.c | 2 +- tools/perf/tests/vmlinux-kallsyms.c | 4 ++-- tools/perf/util/event.c | 4 ++-- tools/perf/util/intel-pt.c | 2 +- tools/perf/util/machine.c | 15 +++++++-------- tools/perf/util/machine.h | 8 +++++++- tools/perf/util/map.c | 2 +- tools/perf/util/probe-event.c | 4 ++-- 10 files changed, 25 insertions(+), 20 deletions(-) diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index b122c4e0818e..93ce665f976f 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -329,7 +329,7 @@ static int build_alloc_func_list(void) return -EINVAL; } - kernel_map = machine__kernel_map(machine, MAP__FUNCTION) + kernel_map = machine__kernel_map(machine); if (map__load(kernel_map, NULL) < 0) { pr_err("cannot load kernel map\n"); return -ENOENT; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 7962605b3576..b5623639f67d 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -387,7 +387,7 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, static void report__warn_kptr_restrict(const struct report *rep) { - struct map *kernel_map = machine__kernel_map(&rep->session->machines.host, MAP__FUNCTION); + struct map *kernel_map = machine__kernel_map(&rep->session->machines.host); struct kmap *kernel_kmap = kernel_map ? map__kmap(kernel_map) : NULL; if (kernel_map == NULL || diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 47017a8aa685..49b1959dda41 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -473,7 +473,7 @@ static int do_test_code_reading(bool try_kcore) symbol_conf.kallsyms_name = "/proc/kallsyms"; /* Load kernel map */ - map = machine__kernel_map(machine, MAP__FUNCTION); + map = machine__kernel_map(machine); ret = map__load(map, NULL); if (ret < 0) { pr_debug("map__load failed\n"); diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index b34c5fc829ae..d677e018e504 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c @@ -68,7 +68,7 @@ int test__vmlinux_matches_kallsyms(void) * to see if the running kernel was relocated by checking if it has the * same value in the vmlinux file we load. */ - kallsyms_map = machine__kernel_map(&kallsyms, type); + kallsyms_map = machine__kernel_map(&kallsyms); /* * Step 5: @@ -80,7 +80,7 @@ int test__vmlinux_matches_kallsyms(void) goto out; } - vmlinux_map = machine__kernel_map(&vmlinux, type); + vmlinux_map = machine__kernel_map(&vmlinux); /* * Step 6: diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 281ab7f87446..cb98b5af9e17 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -649,7 +649,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, size_t size; const char *mmap_name; char name_buff[PATH_MAX]; - struct map *map = machine__kernel_map(machine, MAP__FUNCTION); + struct map *map = machine__kernel_map(machine); struct kmap *kmap; int err; union perf_event *event; @@ -1007,7 +1007,7 @@ int perf_event__preprocess_sample(const union perf_event *event, * it now. */ if (cpumode == PERF_RECORD_MISC_KERNEL && - machine__kernel_map(machine, MAP__FUNCTION) == NULL) + machine__kernel_map(machine) == NULL) machine__create_kernel_maps(machine); thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al); diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 03ff072b5993..97f963a3dcb9 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1268,7 +1268,7 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) if (ptss_ip) *ptss_ip = 0; - map = machine__kernel_map(machine, MAP__FUNCTION); + map = machine__kernel_map(machine); if (!map) return 0; diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index d71b7dcf4579..76fe167c359e 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -625,7 +625,7 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) { int i; size_t printed = 0; - struct dso *kdso = machine__kernel_map(machine, MAP__FUNCTION)->dso; + struct dso *kdso = machine__kernel_map(machine)->dso; if (kdso->has_build_id) { char filename[PATH_MAX]; @@ -750,7 +750,7 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) machine->vmlinux_maps[type]->map_ip = machine->vmlinux_maps[type]->unmap_ip = identity__map_ip; - map = machine__kernel_map(machine, type); + map = __machine__kernel_map(machine, type); kmap = map__kmap(map); if (!kmap) return -1; @@ -768,7 +768,7 @@ void machine__destroy_kernel_maps(struct machine *machine) for (type = 0; type < MAP__NR_TYPES; ++type) { struct kmap *kmap; - struct map *map = machine__kernel_map(machine, type); + struct map *map = __machine__kernel_map(machine, type); if (map == NULL) continue; @@ -868,7 +868,7 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) int machine__load_kallsyms(struct machine *machine, const char *filename, enum map_type type, symbol_filter_t filter) { - struct map *map = machine__kernel_map(machine, MAP__FUNCTION); + struct map *map = machine__kernel_map(machine); int ret = dso__load_kallsyms(map->dso, filename, map, filter); if (ret > 0) { @@ -887,7 +887,7 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, int machine__load_vmlinux_path(struct machine *machine, enum map_type type, symbol_filter_t filter) { - struct map *map = machine__kernel_map(machine, MAP__FUNCTION); + struct map *map = machine__kernel_map(machine); int ret = dso__load_vmlinux_path(map->dso, map, filter); if (ret > 0) @@ -1245,8 +1245,7 @@ static int machine__process_kernel_mmap_event(struct machine *machine, /* * preload dso of guest kernel and modules */ - dso__load(kernel, machine__kernel_map(machine, MAP__FUNCTION), - NULL); + dso__load(kernel, machine__kernel_map(machine), NULL); } } return 0; @@ -1998,7 +1997,7 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, int machine__get_kernel_start(struct machine *machine) { - struct map *map = machine__kernel_map(machine, MAP__FUNCTION); + struct map *map = machine__kernel_map(machine); int err = 0; /* diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 9dfc4281f940..2c2b443df5ba 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -48,11 +48,17 @@ struct machine { }; static inline -struct map *machine__kernel_map(struct machine *machine, enum map_type type) +struct map *__machine__kernel_map(struct machine *machine, enum map_type type) { return machine->vmlinux_maps[type]; } +static inline +struct map *machine__kernel_map(struct machine *machine) +{ + return __machine__kernel_map(machine, MAP__FUNCTION); +} + int machine__get_kernel_start(struct machine *machine); static inline u64 machine__kernel_start(struct machine *machine) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 2a9d859d30b9..4e38c396a897 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -235,7 +235,7 @@ struct map *map__new2(u64 start, struct dso *dso, enum map_type type) */ bool __map__is_kernel(const struct map *map) { - return machine__kernel_map(map->groups->machine, map->type) == map; + return __machine__kernel_map(map->groups->machine, map->type) == map; } static void map__exit(struct map *map) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a0b3f3c886f0..8b9a6807dab4 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -126,7 +126,7 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) { /* kmap->ref_reloc_sym should be set if host_machine is initialized */ struct kmap *kmap; - struct map *map = machine__kernel_map(host_machine, MAP__FUNCTION); + struct map *map = machine__kernel_map(host_machine); if (map__load(map, NULL) < 0) return NULL; @@ -282,7 +282,7 @@ static int kernel_get_module_dso(const char *module, struct dso **pdso) return -ENOENT; } - map = machine__kernel_map(host_machine, MAP__FUNCTION); + map = machine__kernel_map(host_machine); dso = map->dso; vmlinux_name = symbol_conf.vmlinux_name; From 8e947f1e84fd1588f66e5f2ea69c80647de72cd4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Sep 2015 12:42:07 -0300 Subject: [PATCH 141/260] tools lib symbol: Rename kallsyms2elf_type to kallsyms2elf_binding It is about binding, not type, we have just a letter in kallsyms that should map both for the ELF type (STT_FUNC, etc) and to the ELF symbol binding (STB_WEAK, STB_GLOBAL, etc), so rename it now before introducing kallsyms2_elf_type() Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-uu5vj343ms1q2wm55690on6v@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/symbol/kallsyms.h | 2 +- tools/perf/util/symbol.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h index 6084f5e18b3c..bb86c5b76ee8 100644 --- a/tools/lib/symbol/kallsyms.h +++ b/tools/lib/symbol/kallsyms.h @@ -9,7 +9,7 @@ #define KSYM_NAME_LEN 256 #endif -static inline u8 kallsyms2elf_type(char type) +static inline u8 kallsyms2elf_binding(char type) { if (type == 'W') return STB_WEAK; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 1f97ffb158a6..bcda43bee4d4 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -624,7 +624,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name, * symbols, setting length to 0, and rely on * symbols__fixup_end() to fix it up. */ - sym = symbol__new(start, 0, kallsyms2elf_type(type), name); + sym = symbol__new(start, 0, kallsyms2elf_binding(type), name); if (sym == NULL) return -ENOMEM; /* From f845086a8ed49e657a750f87f85966d75c8a9645 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Sep 2015 13:02:08 -0300 Subject: [PATCH 142/260] tools lib symbol: Introduce kallsyms2elf_type Map 't', 'T' (text, local, global), 'w' and 'W' (weak text, local, global) as STT_FUNC, and the rest as STT_OBJECT Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-sbwcixulpc5v1xuxn3xvm0nn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/symbol/kallsyms.c | 6 ++++++ tools/lib/symbol/kallsyms.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/tools/lib/symbol/kallsyms.c b/tools/lib/symbol/kallsyms.c index 18bc271a4bbc..5e431077fcd6 100644 --- a/tools/lib/symbol/kallsyms.c +++ b/tools/lib/symbol/kallsyms.c @@ -2,6 +2,12 @@ #include #include +u8 kallsyms2elf_type(char type) +{ + type = tolower(type); + return (type == 't' || type == 'w') ? STT_FUNC : STT_OBJECT; +} + int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, char type, u64 start)) diff --git a/tools/lib/symbol/kallsyms.h b/tools/lib/symbol/kallsyms.h index bb86c5b76ee8..4071316a766e 100644 --- a/tools/lib/symbol/kallsyms.h +++ b/tools/lib/symbol/kallsyms.h @@ -17,6 +17,8 @@ static inline u8 kallsyms2elf_binding(char type) return isupper(type) ? STB_GLOBAL : STB_LOCAL; } +u8 kallsyms2elf_type(char type); + int kallsyms__parse(const char *filename, void *arg, int (*process_symbol)(void *arg, const char *name, char type, u64 start)); From 663b1151f2d674e2004c015cbe9995749033c49a Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 1 Oct 2015 01:41:30 +0900 Subject: [PATCH 143/260] perf probe: Fix to remove dot suffix from second or latter events Fix to remove dot suffix (e.g. .const, .isra) from the second or latter events which has suffix numbers. Since the previous commit 35a23ff928b0 ("perf probe: Cut off the gcc optimization postfixes from function name") didn't care about the suffix numbered events, therefore we'll have an error when we add additional events on the same dot suffix functions. e.g. ---- # ./perf probe -f -a get_sigframe.isra.2.constprop.3 \ -a get_sigframe.isra.2.constprop.3 Failed to write event: Invalid argument Error: Failed to add events. ---- This fixes above issue as below: ---- # ./perf probe -f -a get_sigframe.isra.2.constprop.3 \ -a get_sigframe.isra.2.constprop.3 Added new events: probe:get_sigframe (on get_sigframe.isra.2.constprop.3) probe:get_sigframe_1 (on get_sigframe.isra.2.constprop.3) You can now use it in all perf tools, such as: perf record -e probe:get_sigframe_1 -aR sleep 1 ---- Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20150930164130.3733.26573.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8b9a6807dab4..5d68f68797a9 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2289,36 +2289,41 @@ static int get_new_event_name(char *buf, size_t len, const char *base, struct strlist *namelist, bool allow_suffix) { int i, ret; - char *p; + char *p, *nbase; if (*base == '.') base++; + nbase = strdup(base); + if (!nbase) + return -ENOMEM; - /* Try no suffix */ - ret = e_snprintf(buf, len, "%s", base); + /* Cut off the dot suffixes (e.g. .const, .isra)*/ + p = strchr(nbase, '.'); + if (p && p != nbase) + *p = '\0'; + + /* Try no suffix number */ + ret = e_snprintf(buf, len, "%s", nbase); if (ret < 0) { pr_debug("snprintf() failed: %d\n", ret); - return ret; + goto out; } - /* Cut off the postfixes (e.g. .const, .isra)*/ - p = strchr(buf, '.'); - if (p && p != buf) - *p = '\0'; if (!strlist__has_entry(namelist, buf)) - return 0; + goto out; if (!allow_suffix) { pr_warning("Error: event \"%s\" already exists. " - "(Use -f to force duplicates.)\n", base); - return -EEXIST; + "(Use -f to force duplicates.)\n", buf); + ret = -EEXIST; + goto out; } /* Try to add suffix */ for (i = 1; i < MAX_EVENT_INDEX; i++) { - ret = e_snprintf(buf, len, "%s_%d", base, i); + ret = e_snprintf(buf, len, "%s_%d", nbase, i); if (ret < 0) { pr_debug("snprintf() failed: %d\n", ret); - return ret; + goto out; } if (!strlist__has_entry(namelist, buf)) break; @@ -2328,6 +2333,8 @@ static int get_new_event_name(char *buf, size_t len, const char *base, ret = -ERANGE; } +out: + free(nbase); return ret; } From 9135949ddd9d0d8d73a2f441912508d25a4a82a2 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 1 Oct 2015 01:41:28 +0900 Subject: [PATCH 144/260] perf probe: Begin and end libdwfl report session correctly Fix a trival bug about libdwfl usage of the report session, it should explicitly begin and end a report session around dwfl_report_offline(). Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20150930164128.3733.59876.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 29c43c0680a8..35f905f4f34c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -70,6 +70,7 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, if (!dbg->dwfl) goto error; + dwfl_report_begin(dbg->dwfl); dbg->mod = dwfl_report_offline(dbg->dwfl, "", "", fd); if (!dbg->mod) goto error; @@ -78,6 +79,8 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *dbg, if (!dbg->dbg) goto error; + dwfl_report_end(dbg->dwfl, NULL, NULL); + return 0; error: if (dbg->dwfl) From 9b239a12bc872f212cefbaee4d028c838abe6ff3 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 1 Oct 2015 01:41:33 +0900 Subject: [PATCH 145/260] perf probe: Show correct source lines of probes on kmodules Perf probe always failed to find appropriate line numbers because of failing to find .text start address offset from debuginfo. e.g. ---- # ./perf probe -m pcspkr pcspkr_event:5 Added new events: probe:pcspkr_event (on pcspkr_event:5 in pcspkr) probe:pcspkr_event_1 (on pcspkr_event:5 in pcspkr) You can now use it in all perf tools, such as: perf record -e probe:pcspkr_event_1 -aR sleep 1 # ./perf probe -l Failed to find debug information for address ffffffffa031f006 Failed to find debug information for address ffffffffa031f016 probe:pcspkr_event (on pcspkr_event+6 in pcspkr) probe:pcspkr_event_1 (on pcspkr_event+22 in pcspkr) ---- This fixes the above issue as below. 1. Get the relative address of the symbol in .text by using map->start. 2. Adjust the address by adding the offset of .text section in the kernel module binary. With this fix, perf probe -l shows lines correctly. ---- # ./perf probe -l probe:pcspkr_event (on pcspkr_event:5@drivers/input/misc/pcspkr.c in pcspkr) probe:pcspkr_event_1 (on pcspkr_event:5@drivers/input/misc/pcspkr.c in pcspkr) ---- Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20150930164132.3733.24643.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 35 ++++++++++++++++++---------- tools/perf/util/probe-finder.c | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5d68f68797a9..65be284823d5 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -137,7 +137,8 @@ static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) return kmap->ref_reloc_sym; } -static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) +static int kernel_get_symbol_address_by_name(const char *name, u64 *addr, + bool reloc, bool reladdr) { struct ref_reloc_sym *reloc_sym; struct symbol *sym; @@ -146,12 +147,14 @@ static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) /* ref_reloc_sym is just a label. Need a special fix*/ reloc_sym = kernel_get_ref_reloc_sym(); if (reloc_sym && strcmp(name, reloc_sym->name) == 0) - return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; + *addr = (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; else { sym = __find_kernel_function_by_name(name, &map); - if (sym) - return map->unmap_ip(map, sym->start) - - ((reloc) ? 0 : map->reloc); + if (!sym) + return -ENOENT; + *addr = map->unmap_ip(map, sym->start) - + ((reloc) ? 0 : map->reloc) - + ((reladdr) ? map->start : 0); } return 0; } @@ -245,12 +248,14 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) static bool kprobe_blacklist__listed(unsigned long address); static bool kprobe_warn_out_range(const char *symbol, unsigned long address) { - u64 etext_addr; + u64 etext_addr = 0; + int ret; /* Get the address of _etext for checking non-probable text symbol */ - etext_addr = kernel_get_symbol_address_by_name("_etext", false); + ret = kernel_get_symbol_address_by_name("_etext", &etext_addr, + false, false); - if (etext_addr != 0 && etext_addr < address) + if (ret == 0 && etext_addr < address) pr_warning("%s is out of .text, skip it.\n", symbol); else if (kprobe_blacklist__listed(address)) pr_warning("%s is blacklisted function, skip it.\n", symbol); @@ -517,8 +522,10 @@ static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, goto error; addr += stext; } else if (tp->symbol) { - addr = kernel_get_symbol_address_by_name(tp->symbol, false); - if (addr == 0) + /* If the module is given, this returns relative address */ + ret = kernel_get_symbol_address_by_name(tp->symbol, &addr, + false, !!tp->module); + if (ret != 0) goto error; addr += tp->offset; } @@ -1884,8 +1891,12 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp, goto out; sym = map__find_symbol(map, addr, NULL); } else { - if (tp->symbol) - addr = kernel_get_symbol_address_by_name(tp->symbol, true); + if (tp->symbol && !addr) { + ret = kernel_get_symbol_address_by_name(tp->symbol, + &addr, true, false); + if (ret < 0) + goto out; + } if (addr) { addr += tp->offset; sym = __find_kernel_function(addr, &map); diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 35f905f4f34c..f0708ffd5e07 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -1402,6 +1402,41 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, return (ret < 0) ? ret : af.nvls; } +/* For the kernel module, we need a special code to get a DIE */ +static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs) +{ + int n, i; + Elf32_Word shndx; + Elf_Scn *scn; + Elf *elf; + GElf_Shdr mem, *shdr; + const char *p; + + elf = dwfl_module_getelf(dbg->mod, &dbg->bias); + if (!elf) + return -EINVAL; + + /* Get the number of relocations */ + n = dwfl_module_relocations(dbg->mod); + if (n < 0) + return -ENOENT; + /* Search the relocation related .text section */ + for (i = 0; i < n; i++) { + p = dwfl_module_relocation_info(dbg->mod, i, &shndx); + if (strcmp(p, ".text") == 0) { + /* OK, get the section header */ + scn = elf_getscn(elf, shndx); + if (!scn) + return -ENOENT; + shdr = gelf_getshdr(scn, &mem); + if (!shdr) + return -ENOENT; + *offs = shdr->sh_addr; + } + } + return 0; +} + /* Reverse search */ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, struct perf_probe_point *ppt) @@ -1410,9 +1445,16 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, Dwarf_Addr _addr = 0, baseaddr = 0; const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; int baseline = 0, lineno = 0, ret = 0; + bool reloc = false; +retry: /* Find cu die */ if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { + if (!reloc && debuginfo__get_text_offset(dbg, &baseaddr) == 0) { + addr += baseaddr; + reloc = true; + goto retry; + } pr_warning("Failed to find debug information for address %lx\n", addr); ret = -EINVAL; From 20f49859c785183d5296670a10dace454131274b Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 1 Oct 2015 01:41:35 +0900 Subject: [PATCH 146/260] perf probe: Fix a segfault bug in debuginfo_cache perf probe --list will get a segfault if the first kprobe event is on a module and the second or latter one is on the kernel. e.g. ---- # ./perf probe -q -m pcspkr pcspkr_event # ./perf probe -q vfs_read # ./perf probe -l Segmentation fault (core dumped) ---- This is because the debuginfo_cache fails to handle NULL module name, which causes segfault on strcmp. (Note that strcmp("something", NULL) always causes segfault) To fix this debuginfo_cache__open always translates the NULL module name to "kernel" (this is correct, because NULL module name means opening the debuginfo for the kernel) ---- # ./perf probe -l probe:pcspkr_event (on pcspkr_event@drivers/input/misc/pcspkr.c in pcspkr) probe:vfs_read (on vfs_read@ksrc/linux-3/fs/read_write.c) ---- Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20150930164135.3733.23993.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 65be284823d5..3010abc071ff 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -441,19 +441,22 @@ static char *debuginfo_cache_path; static struct debuginfo *debuginfo_cache__open(const char *module, bool silent) { - if ((debuginfo_cache_path && !strcmp(debuginfo_cache_path, module)) || - (!debuginfo_cache_path && !module && debuginfo_cache)) + const char *path = module; + + /* If the module is NULL, it should be the kernel. */ + if (!module) + path = "kernel"; + + if (debuginfo_cache_path && !strcmp(debuginfo_cache_path, path)) goto out; /* Copy module path */ free(debuginfo_cache_path); - if (module) { - debuginfo_cache_path = strdup(module); - if (!debuginfo_cache_path) { - debuginfo__delete(debuginfo_cache); - debuginfo_cache = NULL; - goto out; - } + debuginfo_cache_path = strdup(path); + if (!debuginfo_cache_path) { + debuginfo__delete(debuginfo_cache); + debuginfo_cache = NULL; + goto out; } debuginfo_cache = open_debuginfo(module, silent); From 6cca13bdf5a5d561a855259689874e0c7266eec3 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 1 Oct 2015 01:41:37 +0900 Subject: [PATCH 147/260] perf probe: Improve error message when %return is on inlined function perf probe shows more precisely message when it finds given %return target function is inlined. Without this fix: ---- # ./perf probe -V getname_flags%return Return probe must be on the head of a real function. Debuginfo analysis failed. Error: Failed to show vars. ---- With this fix: ---- # ./perf probe -V getname_flags%return Failed to find "getname_flags%return", because getname_flags is an inlined function and has no return point. Debuginfo analysis failed. Error: Failed to show vars. ---- Suggested-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20150930164137.3733.55055.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-finder.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index f0708ffd5e07..bd8f03de5e40 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -594,6 +594,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) /* Convert subprogram DIE to trace point */ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, Dwarf_Addr paddr, bool retprobe, + const char *function, struct probe_trace_point *tp) { Dwarf_Addr eaddr, highaddr; @@ -637,8 +638,10 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod, /* Return probe must be on the head of a subprogram */ if (retprobe) { if (eaddr != paddr) { - pr_warning("Return probe must be on the head of" - " a real function.\n"); + pr_warning("Failed to find \"%s%%return\",\n" + " because %s is an inlined function and" + " has no return point.\n", function, + function); return -EINVAL; } tp->retprobe = true; @@ -1178,6 +1181,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) { struct trace_event_finder *tf = container_of(pf, struct trace_event_finder, pf); + struct perf_probe_point *pp = &pf->pev->point; struct probe_trace_event *tev; struct perf_probe_arg *args; int ret, i; @@ -1192,7 +1196,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) /* Trace point should be converted from subprogram DIE */ ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr, - pf->pev->point.retprobe, &tev->point); + pp->retprobe, pp->function, &tev->point); if (ret < 0) return ret; @@ -1322,6 +1326,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) { struct available_var_finder *af = container_of(pf, struct available_var_finder, pf); + struct perf_probe_point *pp = &pf->pev->point; struct variable_list *vl; Dwarf_Die die_mem; int ret; @@ -1335,7 +1340,7 @@ static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) /* Trace point should be converted from subprogram DIE */ ret = convert_to_trace_point(&pf->sp_die, af->mod, pf->addr, - pf->pev->point.retprobe, &vl->point); + pp->retprobe, pp->function, &vl->point); if (ret < 0) return ret; From dfc431cbdc3a3c0556f1cd462d724d107cc15a9e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Sep 2015 17:13:26 -0300 Subject: [PATCH 148/260] perf list: Remove blank lines, headers when piping output So that one can, for instance, use it with wc -l: # perf list *:*write* | wc -l 60 Or to look for the "bio" tracepoints, without 'perf list' headers: # perf list *:*bio* | head block:block_bio_backmerge [Tracepoint event] block:block_bio_bounce [Tracepoint event] block:block_bio_complete [Tracepoint event] block:block_bio_frontmerge [Tracepoint event] block:block_bio_queue [Tracepoint event] block:block_bio_remap [Tracepoint event] # Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ts7sc0x8u4io4cifzkup4j44@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-list.c | 2 +- tools/perf/util/parse-events.c | 13 +++++++------ tools/perf/util/pmu.c | 2 +- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index af5bd0514108..602414040344 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -36,7 +36,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) setup_pager(); - if (!raw_dump) + if (!raw_dump && pager_in_use()) printf("\nList of pre-defined events (to be used in -e):\n\n"); if (argc == 0) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c1c64fb647aa..5d0cfce2599b 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1534,7 +1534,7 @@ restart: printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[PERF_TYPE_TRACEPOINT]); } - if (evt_num) + if (evt_num && pager_in_use()) printf("\n"); out_free: @@ -1690,7 +1690,7 @@ restart: printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[PERF_TYPE_HW_CACHE]); } - if (evt_num) + if (evt_num && pager_in_use()) printf("\n"); out_free: @@ -1763,7 +1763,7 @@ restart: } printf(" %-50s [%s]\n", evt_list[evt_i++], event_type_descriptors[type]); } - if (evt_num) + if (evt_num && pager_in_use()) printf("\n"); out_free: @@ -1804,13 +1804,14 @@ void print_events(const char *event_glob, bool name_only) printf(" %-50s [%s]\n", "cpu/t1=v1[,t2=v2,t3 ...]/modifier", event_type_descriptors[PERF_TYPE_RAW]); - printf(" (see 'man perf-list' on how to encode it)\n"); - printf("\n"); + if (pager_in_use()) + printf(" (see 'man perf-list' on how to encode it)\n\n"); printf(" %-50s [%s]\n", "mem:[/len][:access]", event_type_descriptors[PERF_TYPE_BREAKPOINT]); - printf("\n"); + if (pager_in_use()) + printf("\n"); } print_tracepoint_events(NULL, NULL, name_only); diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index ac42c97be9e4..41a356ba3cfe 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1026,7 +1026,7 @@ void print_pmu_events(const char *event_glob, bool name_only) printf(" %-50s [Kernel PMU event]\n", aliases[j]); printed++; } - if (printed) + if (printed && pager_in_use()) printf("\n"); out_free: for (j = 0; j < len; j++) From 7f8d1ade1b19f684ed3a7c4fb1dc5d347127b438 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 30 Sep 2015 17:49:49 -0300 Subject: [PATCH 149/260] perf tools: By default use the most precise "cycles" hw counter available If the user doesn't specify any event, try the most precise "cycles" available, i.e. start by "cycles:ppp" and go on removing "p" till it works. E.g. $ perf record usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.017 MB perf.data (11 samples) ] $ perf evlist cycles:pp $ perf evlist -v cycles:pp: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, precise_ip: 2, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 $ grep 'model name' /proc/cpuinfo | head -1 model name : Intel(R) Core(TM) i7-3667U CPU @ 2.00GHz $ When 'cycles' appears explicitely is specified this will not be tried, i.e. the user has full control of the level of precision to be used: $ perf record -e cycles usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.016 MB perf.data (9 samples) ] $ perf evlist cycles $ perf evlist -v cycles: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 $ Cc: Adrian Hunter Cc: Borislav Petkov Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: https://www.youtube.com/watch?v=nXaxk27zwlk Link: http://lkml.kernel.org/n/tip-b1ywebmt22pi78vjxau01wth@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 89546228b8ed..e7e195d867ea 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -205,6 +205,20 @@ void perf_evlist__set_leader(struct perf_evlist *evlist) } } +static void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr) +{ + attr->precise_ip = 3; + + while (attr->precise_ip != 0) { + int fd = sys_perf_event_open(attr, 0, -1, -1, 0); + if (fd != -1) { + close(fd); + break; + } + --attr->precise_ip; + } +} + int perf_evlist__add_default(struct perf_evlist *evlist) { struct perf_event_attr attr = { @@ -215,13 +229,15 @@ int perf_evlist__add_default(struct perf_evlist *evlist) event_attr_init(&attr); + perf_event_attr__set_max_precise_ip(&attr); + evsel = perf_evsel__new(&attr); if (evsel == NULL) goto error; - /* use strdup() because free(evsel) assumes name is allocated */ - evsel->name = strdup("cycles"); - if (!evsel->name) + /* use asprintf() because free(evsel) assumes name is allocated */ + if (asprintf(&evsel->name, "cycles%.*s", + attr.precise_ip ? attr.precise_ip + 1 : 0, ":ppp") < 0) goto error_free; perf_evlist__add(evlist, evsel); From c2365b9388e8ec19305e3f449c1826e7493d156d Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 1 Oct 2015 14:22:02 +0530 Subject: [PATCH 150/260] perf/x86/intel/uncore: Do not use macro DEFINE_PCI_DEVICE_TABLE() The DEFINE_PCI_DEVICE_TABLE() macro is deprecated. Use 'struct pci_device_id' instead of DEFINE_PCI_DEVICE_TABLE(), with the goal of getting rid of this macro completely. This Coccinelle semantic patch performs this transformation: @@ identifier a; declarer name DEFINE_PCI_DEVICE_TABLE; initializer i; @@ - DEFINE_PCI_DEVICE_TABLE(a) + const struct pci_device_id a[] = i; Signed-off-by: Vaishali Thakkar Cc: Arnaldo Carvalho de Melo Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Link: http://lkml.kernel.org/r/20151001085201.GA16939@localhost Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index 694510a887dc..8cbb3f386b07 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -2444,7 +2444,7 @@ static struct intel_uncore_type *bdx_pci_uncores[] = { NULL, }; -static DEFINE_PCI_DEVICE_TABLE(bdx_uncore_pci_ids) = { +static const struct pci_device_id bdx_uncore_pci_ids[] = { { /* Home Agent 0 */ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f30), .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 0), From e5bed564485b340d87f2d8945643a393e55b8225 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 30 Sep 2015 10:45:24 +0900 Subject: [PATCH 151/260] perf record: Allocate area for sample_id_hdr in a synthesized comm event A previous patch added a synthesized comm event for forked child process but it missed that the event should contain area for sample_id_hdr at the end. It worked by accident since the perf_event union contains bigger event structs like mmap_events. This patch fixes it by dynamically allocating event struct including those area like in perf_event__synthesize_thread_map(). Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443577526-3240-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a01c8ae1ee07..5e01c070dbf2 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -637,17 +637,25 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) * Let the child rip */ if (forks) { - union perf_event event; + union perf_event *event; + + event = malloc(sizeof(event->comm) + machine->id_hdr_size); + if (event == NULL) { + err = -ENOMEM; + goto out_child; + } + /* * Some H/W events are generated before COMM event * which is emitted during exec(), so perf script * cannot see a correct process name for those events. * Synthesize COMM event to prevent it. */ - perf_event__synthesize_comm(tool, &event, + perf_event__synthesize_comm(tool, event, rec->evlist->workload.pid, process_synthesized_event, machine); + free(event); perf_evlist__start_workload(rec->evlist); } From 4b37af595742977f1bdd8c0fd0f3e6e55b36e7b7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 30 Sep 2015 10:45:25 +0900 Subject: [PATCH 152/260] perf top: Fix unresolved comm when -s comm is used The perf top uses 'dso,symbol' sort keys by default so it overlooked a problem in task's comm resolving. When the sort key contains 'comm', some task's comm is not shown properly. This is because the perf_top__mmap_read_idx() checks the cpumode value improperly. The cpumode value of non-sample events are 0 (PERF_RECORD_MISC_CPUMODE_ UNKNOWN) so the events will be ignored by the switch statement. This patch allows it for non-sample events. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443577526-3240-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 38d4d6cac823..ae4c6420300b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -857,9 +857,12 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) * TODO: we don't process guest user from host side * except simple counting. */ - /* Fall thru */ - default: goto next_event; + default: + if (event->header.type == PERF_RECORD_SAMPLE) + goto next_event; + machine = &session->machines.host; + break; } From c53d138d41a7f33cf085762c64b4b61e8d223e1c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 30 Sep 2015 10:45:26 +0900 Subject: [PATCH 153/260] perf top: Register idle thread The perf top didn't add the idle/swapper thread to the machine's thread list and its comm was displayed as ':0'. Fix it. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1443577526-3240-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 3 +++ tools/perf/util/session.c | 2 +- tools/perf/util/session.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ae4c6420300b..6f641fd68296 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -964,6 +964,9 @@ static int __cmd_top(struct perf_top *top) if (ret) goto out_delete; + if (perf_session__register_idle_thread(top->session) == NULL) + goto out_delete; + machine__synthesize_threads(&top->session->machines.host, &opts->target, top->evlist->threads, false, opts->proc_map_timeout); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 84a02eae4394..428149bc64d2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1311,7 +1311,7 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) return machine__findnew_thread(&session->machines.host, -1, pid); } -static struct thread *perf_session__register_idle_thread(struct perf_session *session) +struct thread *perf_session__register_idle_thread(struct perf_session *session) { struct thread *thread; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b44afc75d1cc..3e900c0efc73 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -89,6 +89,8 @@ struct machine *perf_session__findnew_machine(struct perf_session *session, pid_ } struct thread *perf_session__findnew(struct perf_session *session, pid_t pid); +struct thread *perf_session__register_idle_thread(struct perf_session *session); + size_t perf_session__fprintf(struct perf_session *session, FILE *fp); size_t perf_session__fprintf_dsos(struct perf_session *session, FILE *fp); From 208e7607459477432d3df52c32d4b961a96d4a94 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 30 Sep 2015 13:34:00 +0900 Subject: [PATCH 154/260] perf report: Fix a bug on "--call-graph none" option The patch f9db0d0f1b2c ("perf callchain: Allow disabling call graphs per event") added an ability to enable/disable callchain recording per event. But it had a problem when the enablement setting is changed at 'perf report' time using -g/--call-graph option. For example, the following scenario will get a segfault. $ perf record -ag sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.500 MB perf.data (2555 samples) ] $ perf report -g none perf: Segmentation fault -------- backtrace -------- perf[0x53a98a] /usr/lib/libc.so.6(+0x335af)[0x7f4e91df95af] This is because callchain_param.sort() callback was not set but it tried to call the function as it had the PERF_SAMPLE_CALLCHAIN bit. Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Fixes: f9db0d0f1b2c ("perf callchain: Allow disabling call graphs per event") Link: http://lkml.kernel.org/r/1443587640-24242-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 0cad9e07c5b4..c346b331b892 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1151,7 +1151,7 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog) struct perf_evsel *evsel = hists_to_evsel(hists); bool use_callchain; - if (evsel && !symbol_conf.show_ref_callgraph) + if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; else use_callchain = symbol_conf.use_callchain; From 0edd453368c6b9cdb756bde2b6675bb0d5d0eb0a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 25 Sep 2015 16:15:48 +0300 Subject: [PATCH 155/260] perf callchain: Allow for max_stack greater than PERF_MAX_STACK_DEPTH Adjust the validation to allow for max_stack greater than PERF_MAX_STACK_DEPTH. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1443186956-18718-18-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/machine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 76fe167c359e..5ef90be2a249 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -1831,7 +1831,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, } check_calls: - if (chain->nr > PERF_MAX_STACK_DEPTH) { + if (chain->nr > PERF_MAX_STACK_DEPTH && (int)chain->nr > max_stack) { pr_warning("corrupted callchain. skipping...\n"); return 0; } From dbc67409fa912ba063dfa956af0543af1258fc97 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 1 Oct 2015 12:12:22 -0300 Subject: [PATCH 156/260] perf list: Do event name substring search as last resort when no events found Before: # perf list _alloc_ | head -10 # After: # perf list _alloc_ | head -10 ext4:ext4_alloc_da_blocks [Tracepoint event] ext4:ext4_get_implied_cluster_alloc_exit [Tracepoint event] kmem:kmem_cache_alloc_node [Tracepoint event] kmem:mm_page_alloc_extfrag [Tracepoint event] kmem:mm_page_alloc_zone_locked [Tracepoint event] xen:xen_mmu_alloc_ptpage [Tracepoint event] # And it works for all types of events: # perf list br List of pre-defined events (to be used in -e): branch-instructions OR branches [Hardware event] branch-misses [Hardware event] branch-load-misses [Hardware cache event] branch-loads [Hardware cache event] branch-instructions OR cpu/branch-instructions/ [Kernel PMU event] branch-misses OR cpu/branch-misses/ [Kernel PMU event] filelock:break_lease_block [Tracepoint event] filelock:break_lease_noblock [Tracepoint event] filelock:break_lease_unblock [Tracepoint event] syscalls:sys_enter_brk [Tracepoint event] syscalls:sys_exit_brk [Tracepoint event] # Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-qieivl18jdemoaghgndj36e6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 2 ++ tools/perf/builtin-list.c | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index bada8933fdd4..ad60c6ea1997 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -125,6 +125,8 @@ To limit the list use: . If none of the above is matched, it will apply the supplied glob to all events, printing the ones that match. +. As a last resort, it will do a substring search in all event names. + One or more types can be used at the same time, listing the events for the types specified. diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c index 602414040344..bf679e2c978b 100644 --- a/tools/perf/builtin-list.c +++ b/tools/perf/builtin-list.c @@ -45,6 +45,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) } for (i = 0; i < argc; ++i) { + char *sep, *s; + if (strcmp(argv[i], "tracepoint") == 0) print_tracepoint_events(NULL, NULL, raw_dump); else if (strcmp(argv[i], "hw") == 0 || @@ -60,8 +62,7 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) print_hwcache_events(NULL, raw_dump); else if (strcmp(argv[i], "pmu") == 0) print_pmu_events(NULL, raw_dump); - else { - char *sep = strchr(argv[i], ':'), *s; + else if ((sep = strchr(argv[i], ':')) != NULL) { int sep_idx; if (sep == NULL) { @@ -76,6 +77,19 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) s[sep_idx] = '\0'; print_tracepoint_events(s, s + sep_idx + 1, raw_dump); free(s); + } else { + if (asprintf(&s, "*%s*", argv[i]) < 0) { + printf("Critical: Not enough memory! Trying to continue...\n"); + continue; + } + print_symbol_events(s, PERF_TYPE_HARDWARE, + event_symbols_hw, PERF_COUNT_HW_MAX, raw_dump); + print_symbol_events(s, PERF_TYPE_SOFTWARE, + event_symbols_sw, PERF_COUNT_SW_MAX, raw_dump); + print_hwcache_events(s, raw_dump); + print_pmu_events(s, raw_dump); + print_tracepoint_events(NULL, s, raw_dump); + free(s); } } return 0; From fa52ceabc2a3e70431a82bca2bc547a15eaf19df Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 2 Oct 2015 15:28:16 -0300 Subject: [PATCH 157/260] perf list: Honour 'event_glob' whem printing selectable PMUs Some PMUs, like the 'intel_bts' one can be used as an event name, i.e.: $ perf record -e intel_bts:// usleep 1 Is a valid event name. But the code printing such PMUs was not honouring the 'event_glob' parameter, so the following line was always appearing: $ intel_bts// [Kernel PMU event] Fix it: $ [acme@felicio linux]$ perf list data List of pre-defined events (to be used in -e): uncore_imc/data_reads/ [Kernel PMU event] uncore_imc/data_writes/ [Kernel PMU event] $ Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ajb71858n7q7ao77b8pyy74w@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 41a356ba3cfe..e4b173dec4b9 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -1008,7 +1008,8 @@ void print_pmu_events(const char *event_glob, bool name_only) goto out_enomem; j++; } - if (pmu->selectable) { + if (pmu->selectable && + (event_glob == NULL || strglobmatch(pmu->name, event_glob))) { char *s; if (asprintf(&s, "%s//", pmu->name) < 0) goto out_enomem; From 1a8ac29cbffc261f6d7c92e573878110a7dcbd94 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Fri, 2 Oct 2015 21:58:32 +0900 Subject: [PATCH 158/260] perf probe: Allow probing on kmodules without dwarf Allow probing on kernel modules when 'perf' is built without debuginfo support. Currently perf-probe --module requires linking with libdw, but this doesn't make sense. E.g. ---- # make NO_DWARF=1 # ./perf probe -m pcspkr pcspkr_event%return Error: unknown switch `m' ---- With this patch ---- # ./perf probe -m pcspkr pcspkr_event%return Added new event: probe:pcspkr_event (on pcspkr_event%return in pcspkr) You can now use it in all perf tools, such as: perf record -e probe:pcspkr_event -aR sleep 1 ---- Signed-off-by: Masami Hiramatsu Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/r/20151002125832.18617.78721.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 8 +++----- tools/perf/util/probe-event.c | 8 +++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index f7882ae9ebc6..530c3a28a58c 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -182,10 +182,8 @@ static int opt_set_target(const struct option *opt, const char *str, if (str) { if (!strcmp(opt->long_name, "exec")) params.uprobes = true; -#ifdef HAVE_DWARF_SUPPORT else if (!strcmp(opt->long_name, "module")) params.uprobes = false; -#endif else return ret; @@ -490,9 +488,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) "file", "vmlinux pathname"), OPT_STRING('s', "source", &symbol_conf.source_prefix, "directory", "path to kernel source"), - OPT_CALLBACK('m', "module", NULL, "modname|path", - "target module name (for online) or path (for offline)", - opt_set_target), OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines, "Don't search inlined functions"), #endif @@ -509,6 +504,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) opt_set_filter), OPT_CALLBACK('x', "exec", NULL, "executable|path", "target executable name or path", opt_set_target), + OPT_CALLBACK('m', "module", NULL, "modname|path", + "target module name (for online) or path (for offline)", + opt_set_target), OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, "Enable symbol demangling"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3010abc071ff..b51a8bfb40f9 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2543,7 +2543,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, goto out; } - if (!pev->uprobes && !pp->retprobe) { + /* Note that the symbols in the kmodule are not relocated */ + if (!pev->uprobes && !pp->retprobe && !pev->target) { reloc_sym = kernel_get_ref_reloc_sym(); if (!reloc_sym) { pr_warning("Relocated base symbol is not found!\n"); @@ -2580,8 +2581,9 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, } /* Add one probe point */ tp->address = map->unmap_ip(map, sym->start) + pp->offset; - /* If we found a wrong one, mark it by NULL symbol */ - if (!pev->uprobes && + + /* Check the kprobe (not in module) is within .text */ + if (!pev->uprobes && !pev->target && kprobe_warn_out_range(sym->name, tp->address)) { tp->symbol = NULL; /* Skip it */ skipped++; From 9f065194e2a505bb6fd23946b410a0036e9de2ca Mon Sep 17 00:00:00 2001 From: Yang Shi Date: Tue, 29 Sep 2015 14:49:43 -0700 Subject: [PATCH 159/260] perf record: Change 'record.samples' type to unsigned long long When run "perf record -e", the number of samples showed up is wrong on some 32 bit systems, i.e. powerpc and arm. For example, run the below commands on 32 bit powerpc: perf probe -x /lib/libc.so.6 malloc perf record -e probe_libc:malloc -a ls perf.data [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.036 MB perf.data (13829241621624967218 samples) ] Actually, "perf script" just shows 21 samples. The number of samples is also absurd since samples is long type, but it is printed as PRIu64. Build test ran on x86-64, x86, aarch64, arm, mips, ppc and ppc64. Signed-off-by: Yang Shi Cc: linaro-kernel@lists.linaro.org Link: http://lkml.kernel.org/r/1443563383-4064-1-git-send-email-yang.shi@linaro.org [ Bumped the 'hits' var used together with record.samples to 'unsigned long long' too ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 5e01c070dbf2..24ace2f318c1 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -49,7 +49,7 @@ struct record { int realtime_prio; bool no_buildid; bool no_buildid_cache; - long samples; + unsigned long long samples; }; static int record__write(struct record *rec, void *bf, size_t size) @@ -667,7 +667,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) auxtrace_snapshot_enabled = 1; for (;;) { - int hits = rec->samples; + unsigned long long hits = rec->samples; if (record__mmap_read_all(rec) < 0) { auxtrace_snapshot_enabled = 0; From 19afd10410957b1c808c2c49a88e6dd8b23aa894 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 2 Oct 2015 05:04:34 -0400 Subject: [PATCH 160/260] perf stat: Reduce min --interval-print to 10ms The --interval-print parameter was limited to 100ms. However, for example, 10ms is required to do sophisticated bandwidth analysis using uncore events. The test shows that the overhead of the system-wide uncore monitoring with 10ms interval is only ~2%. So this patch reduces the minimal interval-print allowd to 10ms. But 10ms may not work well for all cases. For example, when the cpus/threads number is very large, for system-wide core event monitoring the overhead could be high. To handle this issue, a warning will be displayed when the interval-print is set between 10ms to 100ms. So users can make a decision according to their specific cases. # perf stat -e uncore_imc_1/cas_count_read/ -a --interval-print 10 -- sleep 1 print interval < 100ms. The overhead percentage could be high in some cases. Please proceed with caution. # time counts unit events 0.010200451 0.10 MiB uncore_imc_1/cas_count_read/ 0.020475117 0.02 MiB uncore_imc_1/cas_count_read/ 0.030692800 0.01 MiB uncore_imc_1/cas_count_read/ 0.040948161 0.02 MiB uncore_imc_1/cas_count_read/ 0.051159564 0.00 MiB uncore_imc_1/cas_count_read/ Signed-off-by: Kan Liang Acked-by: Jiri Olsa Cc: Andi Kleen Cc: Namhyung Kim Link: http://lkml.kernel.org/r/1443776674-42511-1-git-send-email-kan.liang@intel.com [ Added warning about overhead when using sub 100ms intervals to the man page ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-stat.txt | 5 +++-- tools/perf/builtin-stat.c | 13 +++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 47469abdcc1c..4e074a660826 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -128,8 +128,9 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m -I msecs:: --interval-print msecs:: - Print count deltas every N milliseconds (minimum: 100ms) - example: perf stat -I 1000 -e cycles -a sleep 5 +Print count deltas every N milliseconds (minimum: 10ms) +The overhead percentage could be high in some cases, for instance with small, sub 100ms intervals. Use with caution. + example: 'perf stat -I 1000 -e cycles -a sleep 5' --per-socket:: Aggregate counts per processor socket for system-wide mode measurements. This diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a96fb5c3bedb..5ef88f760b12 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1179,7 +1179,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) OPT_STRING(0, "post", &post_cmd, "command", "command to run after to the measured command"), OPT_UINTEGER('I', "interval-print", &stat_config.interval, - "print counts at regular interval in ms (>= 100)"), + "print counts at regular interval in ms (>= 10)"), OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, "aggregate counts per processor socket", AGGR_SOCKET), OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode, @@ -1332,9 +1332,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) thread_map__read_comms(evsel_list->threads); if (interval && interval < 100) { - pr_err("print interval must be >= 100ms\n"); - parse_options_usage(stat_usage, options, "I", 1); - goto out; + if (interval < 10) { + pr_err("print interval must be >= 10ms\n"); + parse_options_usage(stat_usage, options, "I", 1); + goto out; + } else + pr_warning("print interval < 100ms. " + "The overhead percentage could be high in some cases. " + "Please proceed with caution.\n"); } if (perf_evlist__alloc_stats(evsel_list, interval)) From ccb5597f9ba11b67b8aa8c6f4682675eceee0e21 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:01 +0200 Subject: [PATCH 161/260] tools lib api fs: No need to use PATH_MAX + 1 Because there's no point, PATH_MAX is big enough. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/api/fs/fs.c | 2 +- tools/lib/api/fs/tracing_path.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 732dbef588b0..459599d1b6c4 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -69,7 +69,7 @@ static const char * const tracefs__known_mountpoints[] = { struct fs { const char *name; const char * const *mounts; - char path[PATH_MAX + 1]; + char path[PATH_MAX]; bool found; long magic; }; diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c index 0406a7d5c891..a26bb5ea8283 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -12,9 +12,9 @@ #include "tracing_path.h" -char tracing_mnt[PATH_MAX + 1] = "/sys/kernel/debug"; -char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing"; -char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; +char tracing_mnt[PATH_MAX] = "/sys/kernel/debug"; +char tracing_path[PATH_MAX] = "/sys/kernel/debug/tracing"; +char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events"; static void __tracing_path_set(const char *tracing, const char *mountpoint) From 84422592e58f6f1ea03688fcf92143bbc095fa88 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:02 +0200 Subject: [PATCH 162/260] perf evlist: Display DATA_SRC sample type bit Adding DATA_SRC bit_name call to display sample_type properly. $ perf evlist -v cpu/mem-loads/pp: ...SNIP... sample_type: IP|TID|TIME|ADDR|CPU|PERIOD|DATA_SRC, ... Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 58890044d835..0b1c289da36d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1178,7 +1178,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value) bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU), bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW), bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER), - bit_name(IDENTIFIER), bit_name(REGS_INTR), + bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC), { .name = NULL, } }; #undef bit_name From 5ec4502d774699194952209ff3ebe65d2472e15a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:03 +0200 Subject: [PATCH 163/260] perf annotate: Fix sizeof_sym_hist overflow issue The annotated_source::sizeof_sym_hist could easily overflow int size, resulting in crash in __symbol__inc_addr_samples. Changing its type int size_t as was probably intended from beginning based on the initialization code in symbol__alloc_hist. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index e9996092a093..cea323d9ee7e 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -122,7 +122,7 @@ struct annotated_source { struct list_head source; struct source_line *lines; int nr_histograms; - int sizeof_sym_hist; + size_t sizeof_sym_hist; struct cyc_hist *cycles_hist; struct sym_hist histograms[0]; }; From 45cf6c33f95448752dd3d5531388429c3a5012d0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:04 +0200 Subject: [PATCH 164/260] perf tools: Export perf_event_attr__set_max_precise_ip() It'll be used in following patch. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-5-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evlist.c | 2 +- tools/perf/util/evlist.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index e7e195d867ea..d1392194a9a9 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -205,7 +205,7 @@ void perf_evlist__set_leader(struct perf_evlist *evlist) } } -static void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr) +void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr) { attr->precise_ip = 3; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 66bc9d4c0869..a459fe71b452 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -290,4 +290,6 @@ void perf_evlist__to_front(struct perf_evlist *evlist, void perf_evlist__set_tracking_event(struct perf_evlist *evlist, struct perf_evsel *tracking_evsel); + +void perf_event_attr__set_max_precise_ip(struct perf_event_attr *attr); #endif /* __PERF_EVLIST_H */ From 7f94af7a489fada17d28cc60e8f4409ce216bd6d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:05 +0200 Subject: [PATCH 165/260] perf tools: Introduce 'P' modifier to request max precision The 'P' will cause the event to get maximum possible detected precise level. Following record: $ perf record -e cycles:P ... will detect maximum precise level for 'cycles' event and use it. Commiter note: Testing it: $ perf record -e cycles:P usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.013 MB perf.data (9 samples) ] $ perf evlist cycles:P $ perf evlist -v cycles:P: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, precise_ip: 2, sample_id_all: 1, mmap2: 1, comm_exec: 1 $ Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-6-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 1 + tools/perf/util/evsel.c | 3 +++ tools/perf/util/evsel.h | 1 + tools/perf/util/parse-events.c | 8 +++++++- tools/perf/util/parse-events.l | 2 +- 5 files changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index ad60c6ea1997..79483f40e991 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -30,6 +30,7 @@ counted. The following modifiers exist: G - guest counting (in KVM guests) H - host counting (not in KVM guests) p - precise level + P - use maximum detected precise level S - read sample value (PERF_SAMPLE_READ) D - pin the event to the PMU diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0b1c289da36d..8be867ccefe9 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -882,6 +882,9 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) attr->clockid = opts->clockid; } + if (evsel->precise_max) + perf_event_attr__set_max_precise_ip(attr); + /* * Apply event specific term settings, * it overloads any global configuration. diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 7906666580da..02a5fed8d924 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -111,6 +111,7 @@ struct perf_evsel { bool system_wide; bool tracking; bool per_pkg; + bool precise_max; /* parse modifier helper */ int exclude_GH; int nr_members; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 5d0cfce2599b..3ed8bf175163 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -923,6 +923,7 @@ struct event_modifier { int eG; int eI; int precise; + int precise_max; int exclude_GH; int sample_read; int pinned; @@ -938,6 +939,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str, int eG = evsel ? evsel->attr.exclude_guest : 0; int eI = evsel ? evsel->attr.exclude_idle : 0; int precise = evsel ? evsel->attr.precise_ip : 0; + int precise_max = 0; int sample_read = 0; int pinned = evsel ? evsel->attr.pinned : 0; @@ -974,6 +976,8 @@ static int get_event_modifier(struct event_modifier *mod, char *str, /* use of precise requires exclude_guest */ if (!exclude_GH) eG = 1; + } else if (*str == 'P') { + precise_max = 1; } else if (*str == 'S') { sample_read = 1; } else if (*str == 'D') { @@ -1004,6 +1008,7 @@ static int get_event_modifier(struct event_modifier *mod, char *str, mod->eG = eG; mod->eI = eI; mod->precise = precise; + mod->precise_max = precise_max; mod->exclude_GH = exclude_GH; mod->sample_read = sample_read; mod->pinned = pinned; @@ -1020,7 +1025,7 @@ static int check_modifier(char *str) char *p = str; /* The sizeof includes 0 byte as well. */ - if (strlen(str) > (sizeof("ukhGHpppSDI") - 1)) + if (strlen(str) > (sizeof("ukhGHpppPSDI") - 1)) return -1; while (*p) { @@ -1059,6 +1064,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) evsel->attr.exclude_idle = mod.eI; evsel->exclude_GH = mod.exclude_GH; evsel->sample_read = mod.sample_read; + evsel->precise_max = mod.precise_max; if (perf_evsel__is_group_leader(evsel)) evsel->attr.pinned = mod.pinned; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index c29832bce496..be244573a02e 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -122,7 +122,7 @@ num_raw_hex [a-fA-F0-9]+ name [a-zA-Z_*?][a-zA-Z0-9_*?.]* name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.]* /* If you add a modifier you need to update check_modifier() */ -modifier_event [ukhpGHSDI]+ +modifier_event [ukhpPGHSDI]+ modifier_bp [rwx]{1,3} %% From ddd83c9717ef8204f17cc63d6dcb5053d472caee Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:06 +0200 Subject: [PATCH 166/260] perf tests: Add parsing test for 'P' modifier We cant test 'P' modifier gets properly parsed, the functionality test itself is beyond this suite. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-7-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 3a2ebe666192..0648b84a9171 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1259,6 +1259,17 @@ test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist) return test__checkevent_breakpoint_rw(evlist); } +static int test__checkevent_precise_max_modifier(struct perf_evlist *evlist) +{ + struct perf_evsel *evsel = perf_evlist__first(evlist); + + TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); + TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type); + TEST_ASSERT_VAL("wrong config", + PERF_COUNT_SW_TASK_CLOCK == evsel->attr.config); + return 0; +} + static int count_tracepoints(void) { struct dirent *events_ent; @@ -1562,6 +1573,11 @@ static struct evlist_test test__events[] = { .check = test__checkevent_exclude_idle_modifier_1, .id = 46, }, + { + .name = "task-clock:P,cycles", + .check = test__checkevent_precise_max_modifier, + .id = 47, + }, }; static struct evlist_test test__events_pmu[] = { From 28e6db205b3ed3f1d86a00c69b3304190377da5f Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Mon, 5 Oct 2015 20:06:07 +0200 Subject: [PATCH 167/260] perf tools: Add support for sorting on the iaddr Sorting on 'symbol' gives to broad a resolution as it can cover a range of IP address. Use the iaddr instead to get proper sorting on IP addresses. Need to use the 'mem_sort' feature of perf record. New sort option is: symbol_iaddr, header label is 'Code Symbol'. $ perf mem report --stdio -F +symbol_iaddr # Overhead Samples Code Symbol Local Weight # ........ ............ ........................ ............ # 54.08% 1 [k] nmi_handle 192 4.51% 1 [k] finish_task_switch 16 3.66% 1 [.] malloc 13 3.10% 1 [.] __strcoll_l 11 Signed-off-by: Don Zickus Cc: David Ahern Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-8-git-send-email-jolsa@kernel.org Signed-off-by: Jiri Olsa Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.h | 1 + tools/perf/util/sort.c | 37 +++++++++++++++++++++++++++++++++++++ tools/perf/util/sort.h | 1 + 3 files changed, 39 insertions(+) diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 8c20a8f6b214..a48a2078d288 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -49,6 +49,7 @@ enum hist_column { HISTC_MEM_LVL, HISTC_MEM_SNOOP, HISTC_MEM_DCACHELINE, + HISTC_MEM_IADDR_SYMBOL, HISTC_TRANSACTION, HISTC_CYCLES, HISTC_NR_COLS, /* Last entry */ diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 6b9556d298c9..ee94b728fca4 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -654,6 +654,35 @@ static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf, width); } +static int64_t +sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right) +{ + uint64_t l = 0, r = 0; + + if (left->mem_info) + l = left->mem_info->iaddr.addr; + if (right->mem_info) + r = right->mem_info->iaddr.addr; + + return (int64_t)(r - l); +} + +static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf, + size_t size, unsigned int width) +{ + uint64_t addr = 0; + struct map *map = NULL; + struct symbol *sym = NULL; + + if (he->mem_info) { + addr = he->mem_info->iaddr.addr; + map = he->mem_info->iaddr.map; + sym = he->mem_info->iaddr.sym; + } + return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size, + width); +} + static int64_t sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) { @@ -1077,6 +1106,13 @@ struct sort_entry sort_mem_daddr_sym = { .se_width_idx = HISTC_MEM_DADDR_SYMBOL, }; +struct sort_entry sort_mem_iaddr_sym = { + .se_header = "Code Symbol", + .se_cmp = sort__iaddr_cmp, + .se_snprintf = hist_entry__iaddr_snprintf, + .se_width_idx = HISTC_MEM_IADDR_SYMBOL, +}; + struct sort_entry sort_mem_daddr_dso = { .se_header = "Data Object", .se_cmp = sort__dso_daddr_cmp, @@ -1299,6 +1335,7 @@ static struct sort_dimension bstack_sort_dimensions[] = { static struct sort_dimension memory_sort_dimensions[] = { DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), + DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym), DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index c06b75746613..33b3d30e18d3 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -201,6 +201,7 @@ enum sort_type { SORT_MEM_LVL, SORT_MEM_SNOOP, SORT_MEM_DCACHELINE, + SORT_MEM_IADDR_SYMBOL, }; /* From b34b3bf0798633cc248b682f5b4f6509739ce234 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:08 +0200 Subject: [PATCH 168/260] perf tools: Setup proper width for symbol_iaddr field We need to properly initialize column width for symbol_iaddr field, so all symbols could fit in the column. Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-9-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index c346b331b892..4fd37d6708cb 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -132,6 +132,18 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); } + + if (h->mem_info->iaddr.sym) { + symlen = (int)h->mem_info->iaddr.sym->namelen + 4 + + unresolved_col_width + 2; + hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, + symlen); + } else { + symlen = unresolved_col_width + 4 + 2; + hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, + symlen); + } + if (h->mem_info->daddr.map) { symlen = dso__name_len(h->mem_info->daddr.map->dso); hists__new_col_len(hists, HISTC_MEM_DADDR_DSO, @@ -143,6 +155,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) } else { symlen = unresolved_col_width + 4 + 2; hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen); + hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, symlen); hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO); } From a1853e2c6f8ed488adcd84fb162c5b3f0b674d9b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 20:06:09 +0200 Subject: [PATCH 169/260] perf tools: Handle -h and -v options Adding handling for '-h' and '-v' options to invoke help and version command respectively. Current behaviour is: $ perf -v Unknown option: -v Usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS] $ perf -h Unknown option: -h Usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS] New behaviour: $ perf -h usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS] The most commonly used perf commands are: annotate Read perf.data (created by perf record) and display annotated code archive Create archive with object files with build-ids found in perf.data file bench General framework for benchmark suites ... $ perf -v perf version 4.3.rc3.gc99e32 Updated man page. Requested-by: Peter Zijlstra Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Don Zickus Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444068369-20978-10-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf.txt | 8 ++++++++ tools/perf/perf.c | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/tools/perf/Documentation/perf.txt b/tools/perf/Documentation/perf.txt index 2b131776363e..864e37597252 100644 --- a/tools/perf/Documentation/perf.txt +++ b/tools/perf/Documentation/perf.txt @@ -27,6 +27,14 @@ OPTIONS Setup buildid cache directory. It has higher priority than buildid.dir config file option. +-v:: +--version:: + Display perf version. + +-h:: +--help:: + Run perf help command. + DESCRIPTION ----------- Performance counters for Linux are a new kernel-based subsystem diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 1fded922bcc8..543713422d14 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -161,6 +161,20 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) if (!strcmp(cmd, "--help") || !strcmp(cmd, "--version")) break; + /* + * Shortcut for '-h' and '-v' options to invoke help + * and version command. + */ + if (!strcmp(cmd, "-h")) { + (*argv)[0] = "--help"; + break; + } + + if (!strcmp(cmd, "-v")) { + (*argv)[0] = "--version"; + break; + } + /* * Check remaining flags. */ From 31b6753f95320260b160935d0e9c0b29f096ab57 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 5 Oct 2015 15:40:19 +0100 Subject: [PATCH 170/260] perf tests: Add arch tests Tests that only make sense for some architectures currently live in the same place as the generic tests. Move out the x86-specific tests into tools/perf/arch/x86/tests and define an 'arch_tests' array, which is the list of tests that only apply to the build architecture. The main idea is to encourage developers to add arch tests to build out perf's test coverage, without dumping everything in tools/perf/tests. Signed-off-by: Matt Fleming Cc: Adrian Hunter Cc: Andi Kleen Cc: Fenghua Yu Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Peter Zijlstra Cc: Vikas Shivappa Cc: Vince Weaver Link: http://lkml.kernel.org/n/tip-p4uc1c15ssbj8xj7ku5slpa6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/Build | 2 +- tools/perf/arch/x86/include/arch-tests.h | 6 +++++ tools/perf/arch/x86/tests/Build | 6 +++-- tools/perf/arch/x86/tests/arch-tests.c | 10 +++++++++ tools/perf/tests/builtin-test.c | 28 +++++++++++++++++------- tools/perf/tests/tests.h | 5 +++++ 6 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 tools/perf/arch/x86/include/arch-tests.h create mode 100644 tools/perf/arch/x86/tests/arch-tests.c diff --git a/tools/perf/arch/x86/Build b/tools/perf/arch/x86/Build index 41bf61da476a..db52fa22d3a1 100644 --- a/tools/perf/arch/x86/Build +++ b/tools/perf/arch/x86/Build @@ -1,2 +1,2 @@ libperf-y += util/ -libperf-$(CONFIG_DWARF_UNWIND) += tests/ +libperf-y += tests/ diff --git a/tools/perf/arch/x86/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h new file mode 100644 index 000000000000..4bd41d8e1ca4 --- /dev/null +++ b/tools/perf/arch/x86/include/arch-tests.h @@ -0,0 +1,6 @@ +#ifndef ARCH_TESTS_H +#define ARCH_TESTS_H + +extern struct test arch_tests[]; + +#endif diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build index b30eff9bcc83..d827ef384b33 100644 --- a/tools/perf/arch/x86/tests/Build +++ b/tools/perf/arch/x86/tests/Build @@ -1,2 +1,4 @@ -libperf-y += regs_load.o -libperf-y += dwarf-unwind.o +libperf-$(CONFIG_DWARF_UNWIND) += regs_load.o +libperf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o + +libperf-y += arch-tests.o diff --git a/tools/perf/arch/x86/tests/arch-tests.c b/tools/perf/arch/x86/tests/arch-tests.c new file mode 100644 index 000000000000..fca9eb9d39a2 --- /dev/null +++ b/tools/perf/arch/x86/tests/arch-tests.c @@ -0,0 +1,10 @@ +#include +#include "tests/tests.h" +#include "arch-tests.h" + +struct test arch_tests[] = { + { + .func = NULL, + }, + +}; diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index d9bf51dc8cf5..2b6c1bf13456 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -14,10 +14,13 @@ #include "parse-options.h" #include "symbol.h" -static struct test { - const char *desc; - int (*func)(void); -} tests[] = { +struct test __weak arch_tests[] = { + { + .func = NULL, + }, +}; + +static struct test generic_tests[] = { { .desc = "vmlinux symtab matches kallsyms", .func = test__vmlinux_matches_kallsyms, @@ -195,6 +198,11 @@ static struct test { }, }; +static struct test *tests[] = { + generic_tests, + arch_tests, +}; + static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[]) { int i; @@ -249,22 +257,25 @@ static int run_test(struct test *test) return err; } -#define for_each_test(t) for (t = &tests[0]; t->func; t++) +#define for_each_test(j, t) \ + for (j = 0; j < ARRAY_SIZE(tests); j++) \ + for (t = &tests[j][0]; t->func; t++) static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) { struct test *t; + unsigned int j; int i = 0; int width = 0; - for_each_test(t) { + for_each_test(j, t) { int len = strlen(t->desc); if (width < len) width = len; } - for_each_test(t) { + for_each_test(j, t) { int curr = i++, err; if (!perf_test__matches(t, curr, argc, argv)) @@ -300,10 +311,11 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) static int perf_test__list(int argc, const char **argv) { + unsigned int j; struct test *t; int i = 0; - for_each_test(t) { + for_each_test(j, t) { if (argc > 1 && !strstr(t->desc, argv[1])) continue; diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 0b3549672c16..b1cb1c081e3c 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -24,6 +24,11 @@ enum { TEST_SKIP = -2, }; +struct test { + const char *desc; + int (*func)(void); +}; + /* Tests */ int test__vmlinux_matches_kallsyms(void); int test__openat_syscall_event(void); From d8b167f9d8af817073ee35cf904e2e527465dbc1 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 5 Oct 2015 15:40:20 +0100 Subject: [PATCH 171/260] perf tests: Move x86 tests into arch directory Move out the x86-specific tests into tools/perf/arch/x86/tests and define an 'arch_tests' array, which is the list of tests that only apply to the build architecture. We can also now begin to get rid of some of the #ifdef code that is present in the generic perf tests. Signed-off-by: Matt Fleming Cc: Adrian Hunter Cc: Andi Kleen Cc: Fenghua Yu Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Peter Zijlstra Cc: Vikas Shivappa Cc: Vince Weaver Link: http://lkml.kernel.org/n/tip-9s68h4ptg06ah0lgnjz55mqn@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/include/arch-tests.h | 12 ++++++++ tools/perf/arch/x86/tests/Build | 3 ++ tools/perf/arch/x86/tests/arch-tests.c | 20 +++++++++++++ tools/perf/arch/x86/tests/dwarf-unwind.c | 1 + .../{ => arch/x86}/tests/gen-insn-x86-dat.awk | 0 .../{ => arch/x86}/tests/gen-insn-x86-dat.sh | 0 .../{ => arch/x86}/tests/insn-x86-dat-32.c | 0 .../{ => arch/x86}/tests/insn-x86-dat-64.c | 0 .../{ => arch/x86}/tests/insn-x86-dat-src.c | 0 tools/perf/{ => arch/x86}/tests/insn-x86.c | 3 +- .../{ => arch/x86}/tests/perf-time-to-tsc.c | 4 ++- tools/perf/{ => arch/x86}/tests/rdpmc.c | 7 ++--- tools/perf/tests/Build | 6 ---- tools/perf/tests/builtin-test.c | 28 ------------------- tools/perf/tests/dwarf-unwind.c | 4 +++ tools/perf/tests/tests.h | 5 +--- 16 files changed, 48 insertions(+), 45 deletions(-) rename tools/perf/{ => arch/x86}/tests/gen-insn-x86-dat.awk (100%) rename tools/perf/{ => arch/x86}/tests/gen-insn-x86-dat.sh (100%) rename tools/perf/{ => arch/x86}/tests/insn-x86-dat-32.c (100%) rename tools/perf/{ => arch/x86}/tests/insn-x86-dat-64.c (100%) rename tools/perf/{ => arch/x86}/tests/insn-x86-dat-src.c (100%) rename tools/perf/{ => arch/x86}/tests/insn-x86.c (98%) rename tools/perf/{ => arch/x86}/tests/perf-time-to-tsc.c (98%) rename tools/perf/{ => arch/x86}/tests/rdpmc.c (97%) diff --git a/tools/perf/arch/x86/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h index 4bd41d8e1ca4..5927cf224325 100644 --- a/tools/perf/arch/x86/include/arch-tests.h +++ b/tools/perf/arch/x86/include/arch-tests.h @@ -1,6 +1,18 @@ #ifndef ARCH_TESTS_H #define ARCH_TESTS_H +/* Tests */ +int test__rdpmc(void); +int test__perf_time_to_tsc(void); +int test__insn_x86(void); + +#ifdef HAVE_DWARF_UNWIND_SUPPORT +struct thread; +struct perf_sample; +int test__arch_unwind_sample(struct perf_sample *sample, + struct thread *thread); +#endif + extern struct test arch_tests[]; #endif diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build index d827ef384b33..8e2c5a38c3b9 100644 --- a/tools/perf/arch/x86/tests/Build +++ b/tools/perf/arch/x86/tests/Build @@ -2,3 +2,6 @@ libperf-$(CONFIG_DWARF_UNWIND) += regs_load.o libperf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o libperf-y += arch-tests.o +libperf-y += rdpmc.o +libperf-y += perf-time-to-tsc.o +libperf-$(CONFIG_AUXTRACE) += insn-x86.o diff --git a/tools/perf/arch/x86/tests/arch-tests.c b/tools/perf/arch/x86/tests/arch-tests.c index fca9eb9d39a2..d116c217af99 100644 --- a/tools/perf/arch/x86/tests/arch-tests.c +++ b/tools/perf/arch/x86/tests/arch-tests.c @@ -3,6 +3,26 @@ #include "arch-tests.h" struct test arch_tests[] = { + { + .desc = "x86 rdpmc test", + .func = test__rdpmc, + }, + { + .desc = "Test converting perf time to TSC", + .func = test__perf_time_to_tsc, + }, +#ifdef HAVE_DWARF_UNWIND_SUPPORT + { + .desc = "Test dwarf unwind", + .func = test__dwarf_unwind, + }, +#endif +#ifdef HAVE_AUXTRACE_SUPPORT + { + .desc = "Test x86 instruction decoder - new instructions", + .func = test__insn_x86, + }, +#endif { .func = NULL, }, diff --git a/tools/perf/arch/x86/tests/dwarf-unwind.c b/tools/perf/arch/x86/tests/dwarf-unwind.c index d8bbf7ad1681..7f209ce827bf 100644 --- a/tools/perf/arch/x86/tests/dwarf-unwind.c +++ b/tools/perf/arch/x86/tests/dwarf-unwind.c @@ -5,6 +5,7 @@ #include "event.h" #include "debug.h" #include "tests/tests.h" +#include "arch-tests.h" #define STACK_SIZE 8192 diff --git a/tools/perf/tests/gen-insn-x86-dat.awk b/tools/perf/arch/x86/tests/gen-insn-x86-dat.awk similarity index 100% rename from tools/perf/tests/gen-insn-x86-dat.awk rename to tools/perf/arch/x86/tests/gen-insn-x86-dat.awk diff --git a/tools/perf/tests/gen-insn-x86-dat.sh b/tools/perf/arch/x86/tests/gen-insn-x86-dat.sh similarity index 100% rename from tools/perf/tests/gen-insn-x86-dat.sh rename to tools/perf/arch/x86/tests/gen-insn-x86-dat.sh diff --git a/tools/perf/tests/insn-x86-dat-32.c b/tools/perf/arch/x86/tests/insn-x86-dat-32.c similarity index 100% rename from tools/perf/tests/insn-x86-dat-32.c rename to tools/perf/arch/x86/tests/insn-x86-dat-32.c diff --git a/tools/perf/tests/insn-x86-dat-64.c b/tools/perf/arch/x86/tests/insn-x86-dat-64.c similarity index 100% rename from tools/perf/tests/insn-x86-dat-64.c rename to tools/perf/arch/x86/tests/insn-x86-dat-64.c diff --git a/tools/perf/tests/insn-x86-dat-src.c b/tools/perf/arch/x86/tests/insn-x86-dat-src.c similarity index 100% rename from tools/perf/tests/insn-x86-dat-src.c rename to tools/perf/arch/x86/tests/insn-x86-dat-src.c diff --git a/tools/perf/tests/insn-x86.c b/tools/perf/arch/x86/tests/insn-x86.c similarity index 98% rename from tools/perf/tests/insn-x86.c rename to tools/perf/arch/x86/tests/insn-x86.c index 5c49eec81349..b6115dfd28f0 100644 --- a/tools/perf/tests/insn-x86.c +++ b/tools/perf/arch/x86/tests/insn-x86.c @@ -1,7 +1,8 @@ #include #include "debug.h" -#include "tests.h" +#include "tests/tests.h" +#include "arch-tests.h" #include "intel-pt-decoder/insn.h" #include "intel-pt-decoder/intel-pt-insn-decoder.h" diff --git a/tools/perf/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c similarity index 98% rename from tools/perf/tests/perf-time-to-tsc.c rename to tools/perf/arch/x86/tests/perf-time-to-tsc.c index 5f49484f1abc..658cd200af74 100644 --- a/tools/perf/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c @@ -9,7 +9,9 @@ #include "thread_map.h" #include "cpumap.h" #include "tsc.h" -#include "tests.h" +#include "tests/tests.h" + +#include "arch-tests.h" #define CHECK__(x) { \ while ((x) < 0) { \ diff --git a/tools/perf/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c similarity index 97% rename from tools/perf/tests/rdpmc.c rename to tools/perf/arch/x86/tests/rdpmc.c index d31f2c4d9f64..e7688214c7cf 100644 --- a/tools/perf/tests/rdpmc.c +++ b/tools/perf/arch/x86/tests/rdpmc.c @@ -5,10 +5,9 @@ #include #include "perf.h" #include "debug.h" -#include "tests.h" +#include "tests/tests.h" #include "cloexec.h" - -#if defined(__x86_64__) || defined(__i386__) +#include "arch-tests.h" static u64 rdpmc(unsigned int counter) { @@ -173,5 +172,3 @@ int test__rdpmc(void) return 0; } - -#endif diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index c6f198ae65fb..50de2253cff6 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -8,7 +8,6 @@ perf-y += openat-syscall-all-cpus.o perf-y += openat-syscall-tp-fields.o perf-y += mmap-basic.o perf-y += perf-record.o -perf-y += rdpmc.o perf-y += evsel-roundtrip-name.o perf-y += evsel-tp-sched.o perf-y += fdarray.o @@ -35,11 +34,6 @@ perf-y += thread-map.o perf-y += llvm.o perf-y += topology.o -perf-$(CONFIG_X86) += perf-time-to-tsc.o -ifdef CONFIG_AUXTRACE -perf-$(CONFIG_X86) += insn-x86.o -endif - ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o endif diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 2b6c1bf13456..66f72d3d6677 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -41,12 +41,6 @@ static struct test generic_tests[] = { .desc = "parse events tests", .func = test__parse_events, }, -#if defined(__x86_64__) || defined(__i386__) - { - .desc = "x86 rdpmc test", - .func = test__rdpmc, - }, -#endif { .desc = "Validate PERF_RECORD_* events & perf_sample fields", .func = test__PERF_RECORD, @@ -107,12 +101,6 @@ static struct test generic_tests[] = { .desc = "Test software clock events have valid period values", .func = test__sw_clock_freq, }, -#if defined(__x86_64__) || defined(__i386__) - { - .desc = "Test converting perf time to TSC", - .func = test__perf_time_to_tsc, - }, -#endif { .desc = "Test object code reading", .func = test__code_reading, @@ -129,14 +117,6 @@ static struct test generic_tests[] = { .desc = "Test parsing with no sample_id_all bit set", .func = test__parse_no_sample_id_all, }, -#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) -#ifdef HAVE_DWARF_UNWIND_SUPPORT - { - .desc = "Test dwarf unwind", - .func = test__dwarf_unwind, - }, -#endif -#endif { .desc = "Test filtering hist entries", .func = test__hists_filter, @@ -181,14 +161,6 @@ static struct test generic_tests[] = { .desc = "Test LLVM searching and compiling", .func = test__llvm, }, -#ifdef HAVE_AUXTRACE_SUPPORT -#if defined(__x86_64__) || defined(__i386__) - { - .desc = "Test x86 instruction decoder - new instructions", - .func = test__insn_x86, - }, -#endif -#endif { .desc = "Test topology in session", .func = test_session_topology, diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c index 40b36c462427..07221793a3ac 100644 --- a/tools/perf/tests/dwarf-unwind.c +++ b/tools/perf/tests/dwarf-unwind.c @@ -11,6 +11,10 @@ #include "thread.h" #include "callchain.h" +#if defined (__x86_64__) || defined (__i386__) +#include "arch-tests.h" +#endif + /* For bsearch. We try to unwind functions in shared object. */ #include diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index b1cb1c081e3c..c80486969f83 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -35,7 +35,6 @@ int test__openat_syscall_event(void); int test__openat_syscall_event_on_all_cpus(void); int test__basic_mmap(void); int test__PERF_RECORD(void); -int test__rdpmc(void); int test__perf_evsel__roundtrip_name_test(void); int test__perf_evsel__tp_sched_test(void); int test__syscall_openat_tp_fields(void); @@ -51,7 +50,6 @@ int test__bp_signal(void); int test__bp_signal_overflow(void); int test__task_exit(void); int test__sw_clock_freq(void); -int test__perf_time_to_tsc(void); int test__code_reading(void); int test__sample_parsing(void); int test__keep_tracking(void); @@ -68,10 +66,9 @@ int test__fdarray__add(void); int test__kmod_path__parse(void); int test__thread_map(void); int test__llvm(void); -int test__insn_x86(void); int test_session_topology(void); -#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) +#if defined(__arm__) || defined(__aarch64__) #ifdef HAVE_DWARF_UNWIND_SUPPORT struct thread; struct perf_sample; From 035827e9f2bd71a280f4eb58c65811d377ab2217 Mon Sep 17 00:00:00 2001 From: Matt Fleming Date: Mon, 5 Oct 2015 15:40:21 +0100 Subject: [PATCH 172/260] perf tests: Add Intel CQM test Peter reports that it's possible to trigger a WARN_ON_ONCE() in the Intel CQM code by combining a hardware event and an Intel CQM (software) event into a group. Unfortunately, the perf tools are not able to create this bundle and we need to manually construct a test case. For posterity, record Peter's proof of concept test case in tools/perf so that it presents a model for how we can perform architecture specific tests, or "arch tests", in perf in the future. The particular issue triggered in the test case is that when the counter for the hardware event overflows and triggers a PMI we'll read both the hardware event and the software event counters. Unfortunately, for CQM that involves performing an IPI to read the CQM event counters on all sockets, which in NMI context triggers the WARN_ON_ONCE(). Reported-by: Peter Zijlstra Signed-off-by: Matt Fleming Cc: Adrian Hunter Cc: Andi Kleen Cc: Fenghua Yu Cc: Jiri Olsa Cc: Kanaka Juvva Cc: Vikas Shivappa Cc: Vince Weaver Link: http://lkml.kernel.org/r/1437490509-15373-1-git-send-email-matt@codeblueprint.co.uk Link: http://lkml.kernel.org/n/tip-3p4ra0u8vzm7m289a1m799kf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/include/arch-tests.h | 1 + tools/perf/arch/x86/tests/Build | 1 + tools/perf/arch/x86/tests/arch-tests.c | 4 + tools/perf/arch/x86/tests/intel-cqm.c | 124 +++++++++++++++++++++++ 4 files changed, 130 insertions(+) create mode 100644 tools/perf/arch/x86/tests/intel-cqm.c diff --git a/tools/perf/arch/x86/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h index 5927cf224325..7ed00f4b0908 100644 --- a/tools/perf/arch/x86/include/arch-tests.h +++ b/tools/perf/arch/x86/include/arch-tests.h @@ -5,6 +5,7 @@ int test__rdpmc(void); int test__perf_time_to_tsc(void); int test__insn_x86(void); +int test__intel_cqm_count_nmi_context(void); #ifdef HAVE_DWARF_UNWIND_SUPPORT struct thread; diff --git a/tools/perf/arch/x86/tests/Build b/tools/perf/arch/x86/tests/Build index 8e2c5a38c3b9..cbb7e978166b 100644 --- a/tools/perf/arch/x86/tests/Build +++ b/tools/perf/arch/x86/tests/Build @@ -5,3 +5,4 @@ libperf-y += arch-tests.o libperf-y += rdpmc.o libperf-y += perf-time-to-tsc.o libperf-$(CONFIG_AUXTRACE) += insn-x86.o +libperf-y += intel-cqm.o diff --git a/tools/perf/arch/x86/tests/arch-tests.c b/tools/perf/arch/x86/tests/arch-tests.c index d116c217af99..2218cb64f840 100644 --- a/tools/perf/arch/x86/tests/arch-tests.c +++ b/tools/perf/arch/x86/tests/arch-tests.c @@ -23,6 +23,10 @@ struct test arch_tests[] = { .func = test__insn_x86, }, #endif + { + .desc = "Test intel cqm nmi context read", + .func = test__intel_cqm_count_nmi_context, + }, { .func = NULL, }, diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c new file mode 100644 index 000000000000..d28c1b6a3b54 --- /dev/null +++ b/tools/perf/arch/x86/tests/intel-cqm.c @@ -0,0 +1,124 @@ +#include "tests/tests.h" +#include "perf.h" +#include "cloexec.h" +#include "debug.h" +#include "evlist.h" +#include "evsel.h" +#include "arch-tests.h" + +#include +#include + +static pid_t spawn(void) +{ + pid_t pid; + + pid = fork(); + if (pid) + return pid; + + while(1); + sleep(5); + return 0; +} + +/* + * Create an event group that contains both a sampled hardware + * (cpu-cycles) and software (intel_cqm/llc_occupancy/) event. We then + * wait for the hardware perf counter to overflow and generate a PMI, + * which triggers an event read for both of the events in the group. + * + * Since reading Intel CQM event counters requires sending SMP IPIs, the + * CQM pmu needs to handle the above situation gracefully, and return + * the last read counter value to avoid triggering a WARN_ON_ONCE() in + * smp_call_function_many() caused by sending IPIs from NMI context. + */ +int test__intel_cqm_count_nmi_context(void) +{ + struct perf_evlist *evlist = NULL; + struct perf_evsel *evsel = NULL; + struct perf_event_attr pe; + int i, fd[2], flag, ret; + size_t mmap_len; + void *event; + pid_t pid; + int err = TEST_FAIL; + + flag = perf_event_open_cloexec_flag(); + + evlist = perf_evlist__new(); + if (!evlist) { + pr_debug("perf_evlist__new failed\n"); + return TEST_FAIL; + } + + ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL); + if (ret) { + pr_debug("parse_events failed\n"); + err = TEST_SKIP; + goto out; + } + + evsel = perf_evlist__first(evlist); + if (!evsel) { + pr_debug("perf_evlist__first failed\n"); + goto out; + } + + memset(&pe, 0, sizeof(pe)); + pe.size = sizeof(pe); + + pe.type = PERF_TYPE_HARDWARE; + pe.config = PERF_COUNT_HW_CPU_CYCLES; + pe.read_format = PERF_FORMAT_GROUP; + + pe.sample_period = 128; + pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ; + + pid = spawn(); + + fd[0] = sys_perf_event_open(&pe, pid, -1, -1, flag); + if (fd[0] < 0) { + pr_debug("failed to open event\n"); + goto out; + } + + memset(&pe, 0, sizeof(pe)); + pe.size = sizeof(pe); + + pe.type = evsel->attr.type; + pe.config = evsel->attr.config; + + fd[1] = sys_perf_event_open(&pe, pid, -1, fd[0], flag); + if (fd[1] < 0) { + pr_debug("failed to open event\n"); + goto out; + } + + /* + * Pick a power-of-two number of pages + 1 for the meta-data + * page (struct perf_event_mmap_page). See tools/perf/design.txt. + */ + mmap_len = page_size * 65; + + event = mmap(NULL, mmap_len, PROT_READ, MAP_SHARED, fd[0], 0); + if (event == (void *)(-1)) { + pr_debug("failed to mmap %d\n", errno); + goto out; + } + + sleep(1); + + err = TEST_OK; + + munmap(event, mmap_len); + + for (i = 0; i < 2; i++) + close(fd[i]); + + kill(pid, SIGKILL); + wait(NULL); +out: + perf_evlist__delete(evlist); + return err; +} From def02db0d662b0edd83f80e3c18f660fc414decb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 5 Oct 2015 17:05:35 -0300 Subject: [PATCH 173/260] perf callchain: Switch default to 'graph,0.5,caller' Which is the most common default found in other similar tools. Requested-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: https://www.youtube.com/watch?v=nXaxk27zwlk Link: http://lkml.kernel.org/n/tip-v8lq36aispvdwgxdmt9p9jd9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 2 +- tools/perf/builtin-report.c | 4 ++-- tools/perf/util/util.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index ce499035e6d8..e4fdeeb51123 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -192,7 +192,7 @@ OPTIONS when available. Usually more convenient to use --branch-history for this. - Default: fractal,0.5,callee,function. + Default: graph,0.5,caller --children:: Accumulate callchain of children to parent entry so that then can diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index b5623639f67d..3b23b25d1589 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -633,7 +633,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) bool has_br_stack = false; int branch_mode = -1; bool branch_call_mode = false; - char callchain_default_opt[] = "fractal,0.5,callee"; + char callchain_default_opt[] = "graph,0.5,caller"; const char * const report_usage[] = { "perf report []", NULL @@ -701,7 +701,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "Only display entries with parent-match"), OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]", "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. " - "Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt), + "Default: graph,0.5,caller", &report_parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, "Accumulate callchains of children and show total overhead as well"), OPT_INTEGER(0, "max-stack", &report.max_stack, diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index ce465b259e52..c1bf9ff210b0 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -17,9 +17,9 @@ #include "callchain.h" struct callchain_param callchain_param = { - .mode = CHAIN_GRAPH_REL, + .mode = CHAIN_GRAPH_ABS, .min_percent = 0.5, - .order = ORDER_CALLEE, + .order = ORDER_CALLER, .key = CCKEY_FUNCTION }; From faae6f690eecb82b6d9d9f2112f5b51ac37d4acb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Aug 2015 17:14:40 -0300 Subject: [PATCH 174/260] perf ui browser: Optional horizontal scrolling key binding If the classes derived from ui_browser want to do some sort of horizontal scrolling, they have just to set ui_browser->columns to the number of columns available. Those columns can be the number of characters on the screen, if what is desired is to scroll character by character, or the number of columns in a spreadsheet like table. This is what the hist_browser will do, skipping ui_browser->horiz_scroll columns when rendering each of its lines. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-q6a22bpmpgcr1awgzrmd4jrs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browser.c | 14 ++++++++++++++ tools/perf/ui/browser.h | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index c6c7e5189214..e9703c0829f1 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c @@ -393,6 +393,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs) if (browser->use_navkeypressed && !browser->navkeypressed) { if (key == K_DOWN || key == K_UP || + (browser->columns && (key == K_LEFT || key == K_RIGHT)) || key == K_PGDN || key == K_PGUP || key == K_HOME || key == K_END || key == ' ') { @@ -421,6 +422,18 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs) browser->seek(browser, -1, SEEK_CUR); } break; + case K_RIGHT: + if (!browser->columns) + goto out; + if (browser->horiz_scroll < browser->columns - 1) + ++browser->horiz_scroll; + break; + case K_LEFT: + if (!browser->columns) + goto out; + if (browser->horiz_scroll != 0) + --browser->horiz_scroll; + break; case K_PGDN: case ' ': if (browser->top_idx + browser->rows > browser->nr_entries - 1) @@ -459,6 +472,7 @@ int ui_browser__run(struct ui_browser *browser, int delay_secs) browser->seek(browser, -offset, SEEK_END); break; default: + out: return key; } } diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h index f3cef564de02..01781de59532 100644 --- a/tools/perf/ui/browser.h +++ b/tools/perf/ui/browser.h @@ -14,7 +14,7 @@ struct ui_browser { u64 index, top_idx; void *top, *entries; - u16 y, x, width, height, rows; + u16 y, x, width, height, rows, columns, horiz_scroll; int current_color; void *priv; const char *title; From c6c3c02dea4034431110923ffd8e296ebfbdbe1b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Aug 2015 17:22:43 -0300 Subject: [PATCH 175/260] perf hists browser: Implement horizontal scrolling Do it using the recently introduced ui_brower scrolling mode, setting ui_browser.columns to the number of sort columns and then, when rendering each line, skipping as many initial columns as the user pressed the right arrow. As the user presses the left arrow, the ui_browser code will remove the scrolling counter and the left scrolling takes place. The right arrow key was an alias for ENTER, so people used to press it may get a bit annoyed at first, sorry! Ditto for ESC and the left key. Callchains can be left as is or we can, when rendering the Symbol column, store the at what position on the screen it is and then using ui_browser__gotorc() to print it from there, i.e. the callchain would move around with the symbol. Leaving it as is, i.e. at a fixed position, close to the left, saves precious screen real state for it, so I'm inclined to leave it as is now. Cc: Adrian Hunter Cc: Borislav Petkov Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ccqq9sabgfge5dwbqjwh71ij@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index a4e9b370c037..9b7346a881cf 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -784,11 +784,12 @@ static int hist_browser__show_entry(struct hist_browser *browser, .size = sizeof(s), .ptr = &arg, }; + int column = 0; hist_browser__gotorc(browser, row, 0); perf_hpp__for_each_format(fmt) { - if (perf_hpp__should_skip(fmt)) + if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) continue; if (current_entry && browser->b.navkeypressed) { @@ -861,14 +862,16 @@ static int advance_hpp_check(struct perf_hpp *hpp, int inc) return hpp->size <= 0; } -static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) +static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, size_t size) { + struct hists *hists = browser->hists; struct perf_hpp dummy_hpp = { .buf = buf, .size = size, }; struct perf_hpp_fmt *fmt; size_t ret = 0; + int column = 0; if (symbol_conf.use_callchain) { ret = scnprintf(buf, size, " "); @@ -877,7 +880,7 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists) } perf_hpp__for_each_format(fmt) { - if (perf_hpp__should_skip(fmt)) + if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll) continue; ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); @@ -896,7 +899,7 @@ static void hist_browser__show_headers(struct hist_browser *browser) { char headers[1024]; - hists__scnprintf_headers(headers, sizeof(headers), browser->hists); + hists_browser__scnprintf_headers(browser, headers, sizeof(headers)); ui_browser__gotorc(&browser->b, 0, 0); ui_browser__set_color(&browser->b, HE_COLORSET_ROOT); ui_browser__write_nstring(&browser->b, headers, browser->b.width + 1); @@ -1806,8 +1809,17 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, memset(options, 0, sizeof(options)); memset(actions, 0, sizeof(actions)); - perf_hpp__for_each_format(fmt) + perf_hpp__for_each_format(fmt) { perf_hpp__reset_width(fmt, hists); + /* + * This is done just once, and activates the horizontal scrolling + * code in the ui_browser code, it would be better to have a the + * counter in the perf_hpp code, but I couldn't find doing it here + * works, FIXME by setting this in hist_browser__new, for now, be + * clever 8-) + */ + ++browser->b.columns; + } if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); From 27bf90bf0690f55c3679bcc4c325823cf1cfd19d Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Oct 2015 21:31:17 +0200 Subject: [PATCH 176/260] perf tools: Fail properly in case pattern matching fails to find tracepoint Currently we dont fail properly when pattern matching fails to find any tracepoint. Current behaviour: $ perf record -e 'sched:krava*' sleep 1 WARNING: event parser found nothinginvalid or unsupported event: 'sched:krava*' Run 'perf list' for a list of valid events usage: perf record [] [] or: perf record [] -- [] This patch change: $ perf record -e 'sched:krava*' sleep 1 event syntax error: 'sched:krava*' \___ unknown tracepoint Error: File /sys/kernel/debug/tracing/events/sched/krava* not found. Hint: Perhaps this kernel misses some CONFIG_ setting to enable this feature?. Run 'perf list' for a list of valid events usage: perf record [] [] or: perf record [] -- [] Reported-by: Daniel Bristot de Oliveira Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444073477-3181-1-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 3ed8bf175163..991bbd469bea 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -449,7 +449,7 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, char evt_path[MAXPATHLEN]; struct dirent *evt_ent; DIR *evt_dir; - int ret = 0; + int ret = 0, found = 0; snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); evt_dir = opendir(evt_path); @@ -468,10 +468,17 @@ static int add_tracepoint_multi_event(struct list_head *list, int *idx, if (!strglobmatch(evt_ent->d_name, evt_name)) continue; + found++; + ret = add_tracepoint(list, idx, sys_name, evt_ent->d_name, err, head_config); } + if (!found) { + tracepoint_error(err, ENOENT, sys_name, evt_name); + ret = -1; + } + closedir(evt_dir); return ret; } From 7ce1346a6842550a3c4c453cdf1c7b81fb60b07e Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Mon, 28 Sep 2015 08:30:04 -0400 Subject: [PATCH 177/260] perf/x86: Add Intel cstate PMUs support This patch adds new PMUs to support cstate related free running (read-only) counters. These counters may be used simultaneously by other tools, such as turbostat. However, it still make sense to implement them in perf. Because we can conveniently collect them together with other events, and allow to use them from tools without special MSR access code. These counters include CORE_C*_RESIDENCY and PKG_C*_RESIDENCY. According to counters' scope and category, two PMUs are registered with the perf_event core subsystem. - 'cstate_core': The counter is available for each physical core. The counters include CORE_C*_RESIDENCY. - 'cstate_pkg': The counter is available for each physical package. The counters include PKG_C*_RESIDENCY. The events are exposed in sysfs for use by perf stat and other tools. The files are: /sys/devices/cstate_core/events/c*-residency /sys/devices/cstate_pkg/events/c*-residency These events only support system-wide mode counting. The /sys/devices/cstate_*/cpumask file can be used by tools to figure out which CPUs to monitor by default. The PMU type (attr->type) is dynamically allocated and is available from /sys/devices/core_misc/type and /sys/device/cstate_*/type. Sampling is not supported. Here is an example. - To caculate the fraction of time when the core is running in C6 state CORE_C6_time% = CORE_C6_RESIDENCY / TSC # perf stat -x, -e"cstate_core/c6-residency/,msr/tsc/" -C0 -- taskset -c 0 sleep 5 11838820015,,cstate_core/c6-residency/,5175919658,100.00 11877130740,,msr/tsc/,5175922010,100.00 For sleep, 99.7% of time we ran in C6 state. # perf stat -x, -e"cstate_core/c6-residency/,msr/tsc/" -C0 -- taskset -c 0 busyloop 1253316,,cstate_core/c6-residency/,4360969154,100.00 10012635248,,msr/tsc/,4360972366,100.00 For busyloop, 0.01% of time we ran in C6 state. Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Cc: Arjan van de Ven Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: acme@kernel.org Cc: eranian@google.com Link: http://lkml.kernel.org/r/1443443404-8581-1-git-send-email-kan.liang@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/Makefile | 1 + arch/x86/kernel/cpu/perf_event_intel_cstate.c | 694 ++++++++++++++++++ 2 files changed, 695 insertions(+) create mode 100644 arch/x86/kernel/cpu/perf_event_intel_cstate.c diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile index 4eb065c6bed2..58031303e304 100644 --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_p6.o perf_event_knc.o perf_event_p4.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_lbr.o perf_event_intel_ds.o perf_event_intel.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_rapl.o perf_event_intel_cqm.o obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_pt.o perf_event_intel_bts.o +obj-$(CONFIG_CPU_SUP_INTEL) += perf_event_intel_cstate.o obj-$(CONFIG_PERF_EVENTS_INTEL_UNCORE) += perf_event_intel_uncore.o \ perf_event_intel_uncore_snb.o \ diff --git a/arch/x86/kernel/cpu/perf_event_intel_cstate.c b/arch/x86/kernel/cpu/perf_event_intel_cstate.c new file mode 100644 index 000000000000..75a38b5a2e26 --- /dev/null +++ b/arch/x86/kernel/cpu/perf_event_intel_cstate.c @@ -0,0 +1,694 @@ +/* + * perf_event_intel_cstate.c: support cstate residency counters + * + * Copyright (C) 2015, Intel Corp. + * Author: Kan Liang (kan.liang@intel.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + */ + +/* + * This file export cstate related free running (read-only) counters + * for perf. These counters may be use simultaneously by other tools, + * such as turbostat. However, it still make sense to implement them + * in perf. Because we can conveniently collect them together with + * other events, and allow to use them from tools without special MSR + * access code. + * + * The events only support system-wide mode counting. There is no + * sampling support because it is not supported by the hardware. + * + * According to counters' scope and category, two PMUs are registered + * with the perf_event core subsystem. + * - 'cstate_core': The counter is available for each physical core. + * The counters include CORE_C*_RESIDENCY. + * - 'cstate_pkg': The counter is available for each physical package. + * The counters include PKG_C*_RESIDENCY. + * + * All of these counters are specified in the Intel® 64 and IA-32 + * Architectures Software Developer.s Manual Vol3b. + * + * Model specific counters: + * MSR_CORE_C1_RES: CORE C1 Residency Counter + * perf code: 0x00 + * Available model: SLM,AMT + * Scope: Core (each processor core has a MSR) + * MSR_CORE_C3_RESIDENCY: CORE C3 Residency Counter + * perf code: 0x01 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Core + * MSR_CORE_C6_RESIDENCY: CORE C6 Residency Counter + * perf code: 0x02 + * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Core + * MSR_CORE_C7_RESIDENCY: CORE C7 Residency Counter + * perf code: 0x03 + * Available model: SNB,IVB,HSW,BDW,SKL + * Scope: Core + * MSR_PKG_C2_RESIDENCY: Package C2 Residency Counter. + * perf code: 0x00 + * Available model: SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C3_RESIDENCY: Package C3 Residency Counter. + * perf code: 0x01 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C6_RESIDENCY: Package C6 Residency Counter. + * perf code: 0x02 + * Available model: SLM,AMT,NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C7_RESIDENCY: Package C7 Residency Counter. + * perf code: 0x03 + * Available model: NHM,WSM,SNB,IVB,HSW,BDW,SKL + * Scope: Package (physical package) + * MSR_PKG_C8_RESIDENCY: Package C8 Residency Counter. + * perf code: 0x04 + * Available model: HSW ULT only + * Scope: Package (physical package) + * MSR_PKG_C9_RESIDENCY: Package C9 Residency Counter. + * perf code: 0x05 + * Available model: HSW ULT only + * Scope: Package (physical package) + * MSR_PKG_C10_RESIDENCY: Package C10 Residency Counter. + * perf code: 0x06 + * Available model: HSW ULT only + * Scope: Package (physical package) + * + */ + +#include +#include +#include +#include +#include "perf_event.h" + +#define DEFINE_CSTATE_FORMAT_ATTR(_var, _name, _format) \ +static ssize_t __cstate_##_var##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, \ + char *page) \ +{ \ + BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ + return sprintf(page, _format "\n"); \ +} \ +static struct kobj_attribute format_attr_##_var = \ + __ATTR(_name, 0444, __cstate_##_var##_show, NULL) + +static ssize_t cstate_get_attr_cpumask(struct device *dev, + struct device_attribute *attr, + char *buf); + +struct perf_cstate_msr { + u64 msr; + struct perf_pmu_events_attr *attr; + bool (*test)(int idx); +}; + + +/* cstate_core PMU */ + +static struct pmu cstate_core_pmu; +static bool has_cstate_core; + +enum perf_cstate_core_id { + /* + * cstate_core events + */ + PERF_CSTATE_CORE_C1_RES = 0, + PERF_CSTATE_CORE_C3_RES, + PERF_CSTATE_CORE_C6_RES, + PERF_CSTATE_CORE_C7_RES, + + PERF_CSTATE_CORE_EVENT_MAX, +}; + +bool test_core(int idx) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || + boot_cpu_data.x86 != 6) + return false; + + switch (boot_cpu_data.x86_model) { + case 30: /* 45nm Nehalem */ + case 26: /* 45nm Nehalem-EP */ + case 46: /* 45nm Nehalem-EX */ + + case 37: /* 32nm Westmere */ + case 44: /* 32nm Westmere-EP */ + case 47: /* 32nm Westmere-EX */ + if (idx == PERF_CSTATE_CORE_C3_RES || + idx == PERF_CSTATE_CORE_C6_RES) + return true; + break; + case 42: /* 32nm SandyBridge */ + case 45: /* 32nm SandyBridge-E/EN/EP */ + + case 58: /* 22nm IvyBridge */ + case 62: /* 22nm IvyBridge-EP/EX */ + + case 60: /* 22nm Haswell Core */ + case 63: /* 22nm Haswell Server */ + case 69: /* 22nm Haswell ULT */ + case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ + + case 61: /* 14nm Broadwell Core-M */ + case 86: /* 14nm Broadwell Xeon D */ + case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ + case 79: /* 14nm Broadwell Server */ + + case 78: /* 14nm Skylake Mobile */ + case 94: /* 14nm Skylake Desktop */ + if (idx == PERF_CSTATE_CORE_C3_RES || + idx == PERF_CSTATE_CORE_C6_RES || + idx == PERF_CSTATE_CORE_C7_RES) + return true; + break; + case 55: /* 22nm Atom "Silvermont" */ + case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ + case 76: /* 14nm Atom "Airmont" */ + if (idx == PERF_CSTATE_CORE_C1_RES || + idx == PERF_CSTATE_CORE_C6_RES) + return true; + break; + } + + return false; +} + +PMU_EVENT_ATTR_STRING(c1-residency, evattr_cstate_core_c1, "event=0x00"); +PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_core_c3, "event=0x01"); +PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_core_c6, "event=0x02"); +PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_core_c7, "event=0x03"); + +static struct perf_cstate_msr core_msr[] = { + [PERF_CSTATE_CORE_C1_RES] = { MSR_CORE_C1_RES, &evattr_cstate_core_c1, test_core, }, + [PERF_CSTATE_CORE_C3_RES] = { MSR_CORE_C3_RESIDENCY, &evattr_cstate_core_c3, test_core, }, + [PERF_CSTATE_CORE_C6_RES] = { MSR_CORE_C6_RESIDENCY, &evattr_cstate_core_c6, test_core, }, + [PERF_CSTATE_CORE_C7_RES] = { MSR_CORE_C7_RESIDENCY, &evattr_cstate_core_c7, test_core, }, +}; + +static struct attribute *core_events_attrs[PERF_CSTATE_CORE_EVENT_MAX + 1] = { + NULL, +}; + +static struct attribute_group core_events_attr_group = { + .name = "events", + .attrs = core_events_attrs, +}; + +DEFINE_CSTATE_FORMAT_ATTR(core_event, event, "config:0-63"); +static struct attribute *core_format_attrs[] = { + &format_attr_core_event.attr, + NULL, +}; + +static struct attribute_group core_format_attr_group = { + .name = "format", + .attrs = core_format_attrs, +}; + +static cpumask_t cstate_core_cpu_mask; +static DEVICE_ATTR(cpumask, S_IRUGO, cstate_get_attr_cpumask, NULL); + +static struct attribute *cstate_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL, +}; + +static struct attribute_group cpumask_attr_group = { + .attrs = cstate_cpumask_attrs, +}; + +static const struct attribute_group *core_attr_groups[] = { + &core_events_attr_group, + &core_format_attr_group, + &cpumask_attr_group, + NULL, +}; + +/* cstate_core PMU end */ + + +/* cstate_pkg PMU */ + +static struct pmu cstate_pkg_pmu; +static bool has_cstate_pkg; + +enum perf_cstate_pkg_id { + /* + * cstate_pkg events + */ + PERF_CSTATE_PKG_C2_RES = 0, + PERF_CSTATE_PKG_C3_RES, + PERF_CSTATE_PKG_C6_RES, + PERF_CSTATE_PKG_C7_RES, + PERF_CSTATE_PKG_C8_RES, + PERF_CSTATE_PKG_C9_RES, + PERF_CSTATE_PKG_C10_RES, + + PERF_CSTATE_PKG_EVENT_MAX, +}; + +bool test_pkg(int idx) +{ + if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL || + boot_cpu_data.x86 != 6) + return false; + + switch (boot_cpu_data.x86_model) { + case 30: /* 45nm Nehalem */ + case 26: /* 45nm Nehalem-EP */ + case 46: /* 45nm Nehalem-EX */ + + case 37: /* 32nm Westmere */ + case 44: /* 32nm Westmere-EP */ + case 47: /* 32nm Westmere-EX */ + if (idx == PERF_CSTATE_CORE_C3_RES || + idx == PERF_CSTATE_CORE_C6_RES || + idx == PERF_CSTATE_CORE_C7_RES) + return true; + break; + case 42: /* 32nm SandyBridge */ + case 45: /* 32nm SandyBridge-E/EN/EP */ + + case 58: /* 22nm IvyBridge */ + case 62: /* 22nm IvyBridge-EP/EX */ + + case 60: /* 22nm Haswell Core */ + case 63: /* 22nm Haswell Server */ + case 70: /* 22nm Haswell + GT3e (Intel Iris Pro graphics) */ + + case 61: /* 14nm Broadwell Core-M */ + case 86: /* 14nm Broadwell Xeon D */ + case 71: /* 14nm Broadwell + GT3e (Intel Iris Pro graphics) */ + case 79: /* 14nm Broadwell Server */ + + case 78: /* 14nm Skylake Mobile */ + case 94: /* 14nm Skylake Desktop */ + if (idx == PERF_CSTATE_PKG_C2_RES || + idx == PERF_CSTATE_PKG_C3_RES || + idx == PERF_CSTATE_PKG_C6_RES || + idx == PERF_CSTATE_PKG_C7_RES) + return true; + break; + case 55: /* 22nm Atom "Silvermont" */ + case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */ + case 76: /* 14nm Atom "Airmont" */ + if (idx == PERF_CSTATE_CORE_C6_RES) + return true; + break; + case 69: /* 22nm Haswell ULT */ + if (idx == PERF_CSTATE_PKG_C2_RES || + idx == PERF_CSTATE_PKG_C3_RES || + idx == PERF_CSTATE_PKG_C6_RES || + idx == PERF_CSTATE_PKG_C7_RES || + idx == PERF_CSTATE_PKG_C8_RES || + idx == PERF_CSTATE_PKG_C9_RES || + idx == PERF_CSTATE_PKG_C10_RES) + return true; + break; + } + + return false; +} + +PMU_EVENT_ATTR_STRING(c2-residency, evattr_cstate_pkg_c2, "event=0x00"); +PMU_EVENT_ATTR_STRING(c3-residency, evattr_cstate_pkg_c3, "event=0x01"); +PMU_EVENT_ATTR_STRING(c6-residency, evattr_cstate_pkg_c6, "event=0x02"); +PMU_EVENT_ATTR_STRING(c7-residency, evattr_cstate_pkg_c7, "event=0x03"); +PMU_EVENT_ATTR_STRING(c8-residency, evattr_cstate_pkg_c8, "event=0x04"); +PMU_EVENT_ATTR_STRING(c9-residency, evattr_cstate_pkg_c9, "event=0x05"); +PMU_EVENT_ATTR_STRING(c10-residency, evattr_cstate_pkg_c10, "event=0x06"); + +static struct perf_cstate_msr pkg_msr[] = { + [PERF_CSTATE_PKG_C2_RES] = { MSR_PKG_C2_RESIDENCY, &evattr_cstate_pkg_c2, test_pkg, }, + [PERF_CSTATE_PKG_C3_RES] = { MSR_PKG_C3_RESIDENCY, &evattr_cstate_pkg_c3, test_pkg, }, + [PERF_CSTATE_PKG_C6_RES] = { MSR_PKG_C6_RESIDENCY, &evattr_cstate_pkg_c6, test_pkg, }, + [PERF_CSTATE_PKG_C7_RES] = { MSR_PKG_C7_RESIDENCY, &evattr_cstate_pkg_c7, test_pkg, }, + [PERF_CSTATE_PKG_C8_RES] = { MSR_PKG_C8_RESIDENCY, &evattr_cstate_pkg_c8, test_pkg, }, + [PERF_CSTATE_PKG_C9_RES] = { MSR_PKG_C9_RESIDENCY, &evattr_cstate_pkg_c9, test_pkg, }, + [PERF_CSTATE_PKG_C10_RES] = { MSR_PKG_C10_RESIDENCY, &evattr_cstate_pkg_c10, test_pkg, }, +}; + +static struct attribute *pkg_events_attrs[PERF_CSTATE_PKG_EVENT_MAX + 1] = { + NULL, +}; + +static struct attribute_group pkg_events_attr_group = { + .name = "events", + .attrs = pkg_events_attrs, +}; + +DEFINE_CSTATE_FORMAT_ATTR(pkg_event, event, "config:0-63"); +static struct attribute *pkg_format_attrs[] = { + &format_attr_pkg_event.attr, + NULL, +}; +static struct attribute_group pkg_format_attr_group = { + .name = "format", + .attrs = pkg_format_attrs, +}; + +static cpumask_t cstate_pkg_cpu_mask; + +static const struct attribute_group *pkg_attr_groups[] = { + &pkg_events_attr_group, + &pkg_format_attr_group, + &cpumask_attr_group, + NULL, +}; + +/* cstate_pkg PMU end*/ + +static ssize_t cstate_get_attr_cpumask(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pmu *pmu = dev_get_drvdata(dev); + + if (pmu == &cstate_core_pmu) + return cpumap_print_to_pagebuf(true, buf, &cstate_core_cpu_mask); + else if (pmu == &cstate_pkg_pmu) + return cpumap_print_to_pagebuf(true, buf, &cstate_pkg_cpu_mask); + else + return 0; +} + +static int cstate_pmu_event_init(struct perf_event *event) +{ + u64 cfg = event->attr.config; + int ret = 0; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + /* unsupported modes and filters */ + if (event->attr.exclude_user || + event->attr.exclude_kernel || + event->attr.exclude_hv || + event->attr.exclude_idle || + event->attr.exclude_host || + event->attr.exclude_guest || + event->attr.sample_period) /* no sampling */ + return -EINVAL; + + if (event->pmu == &cstate_core_pmu) { + if (cfg >= PERF_CSTATE_CORE_EVENT_MAX) + return -EINVAL; + if (!core_msr[cfg].attr) + return -EINVAL; + event->hw.event_base = core_msr[cfg].msr; + } else if (event->pmu == &cstate_pkg_pmu) { + if (cfg >= PERF_CSTATE_PKG_EVENT_MAX) + return -EINVAL; + if (!pkg_msr[cfg].attr) + return -EINVAL; + event->hw.event_base = pkg_msr[cfg].msr; + } else + return -ENOENT; + + /* must be done before validate_group */ + event->hw.config = cfg; + event->hw.idx = -1; + + return ret; +} + +static inline u64 cstate_pmu_read_counter(struct perf_event *event) +{ + u64 val; + + rdmsrl(event->hw.event_base, val); + return val; +} + +static void cstate_pmu_event_update(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + u64 prev_raw_count, new_raw_count; + +again: + prev_raw_count = local64_read(&hwc->prev_count); + new_raw_count = cstate_pmu_read_counter(event); + + if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, + new_raw_count) != prev_raw_count) + goto again; + + local64_add(new_raw_count - prev_raw_count, &event->count); +} + +static void cstate_pmu_event_start(struct perf_event *event, int mode) +{ + local64_set(&event->hw.prev_count, cstate_pmu_read_counter(event)); +} + +static void cstate_pmu_event_stop(struct perf_event *event, int mode) +{ + cstate_pmu_event_update(event); +} + +static void cstate_pmu_event_del(struct perf_event *event, int mode) +{ + cstate_pmu_event_stop(event, PERF_EF_UPDATE); +} + +static int cstate_pmu_event_add(struct perf_event *event, int mode) +{ + if (mode & PERF_EF_START) + cstate_pmu_event_start(event, mode); + + return 0; +} + +static void cstate_cpu_exit(int cpu) +{ + int i, id, target; + + /* cpu exit for cstate core */ + if (has_cstate_core) { + id = topology_core_id(cpu); + target = -1; + + for_each_online_cpu(i) { + if (i == cpu) + continue; + if (id == topology_core_id(i)) { + target = i; + break; + } + } + if (cpumask_test_and_clear_cpu(cpu, &cstate_core_cpu_mask) && target >= 0) + cpumask_set_cpu(target, &cstate_core_cpu_mask); + WARN_ON(cpumask_empty(&cstate_core_cpu_mask)); + if (target >= 0) + perf_pmu_migrate_context(&cstate_core_pmu, cpu, target); + } + + /* cpu exit for cstate pkg */ + if (has_cstate_pkg) { + id = topology_physical_package_id(cpu); + target = -1; + + for_each_online_cpu(i) { + if (i == cpu) + continue; + if (id == topology_physical_package_id(i)) { + target = i; + break; + } + } + if (cpumask_test_and_clear_cpu(cpu, &cstate_pkg_cpu_mask) && target >= 0) + cpumask_set_cpu(target, &cstate_pkg_cpu_mask); + WARN_ON(cpumask_empty(&cstate_pkg_cpu_mask)); + if (target >= 0) + perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target); + } +} + +static void cstate_cpu_init(int cpu) +{ + int i, id; + + /* cpu init for cstate core */ + if (has_cstate_core) { + id = topology_core_id(cpu); + for_each_cpu(i, &cstate_core_cpu_mask) { + if (id == topology_core_id(i)) + break; + } + if (i >= nr_cpu_ids) + cpumask_set_cpu(cpu, &cstate_core_cpu_mask); + } + + /* cpu init for cstate pkg */ + if (has_cstate_pkg) { + id = topology_physical_package_id(cpu); + for_each_cpu(i, &cstate_pkg_cpu_mask) { + if (id == topology_physical_package_id(i)) + break; + } + if (i >= nr_cpu_ids) + cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask); + } +} + +static int cstate_cpu_notifier(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (long)hcpu; + + switch (action & ~CPU_TASKS_FROZEN) { + case CPU_UP_PREPARE: + break; + case CPU_STARTING: + cstate_cpu_init(cpu); + break; + case CPU_UP_CANCELED: + case CPU_DYING: + break; + case CPU_ONLINE: + case CPU_DEAD: + break; + case CPU_DOWN_PREPARE: + cstate_cpu_exit(cpu); + break; + default: + break; + } + + return NOTIFY_OK; +} + +/* + * Probe the cstate events and insert the available one into sysfs attrs + * Return false if there is no available events. + */ +static bool cstate_probe_msr(struct perf_cstate_msr *msr, + struct attribute **events_attrs, + int max_event_nr) +{ + int i, j = 0; + u64 val; + + /* Probe the cstate events. */ + for (i = 0; i < max_event_nr; i++) { + if (!msr[i].test(i) || rdmsrl_safe(msr[i].msr, &val)) + msr[i].attr = NULL; + } + + /* List remaining events in the sysfs attrs. */ + for (i = 0; i < max_event_nr; i++) { + if (msr[i].attr) + events_attrs[j++] = &msr[i].attr->attr.attr; + } + events_attrs[j] = NULL; + + return (j > 0) ? true : false; +} + +static int __init cstate_init(void) +{ + /* SLM has different MSR for PKG C6 */ + switch (boot_cpu_data.x86_model) { + case 55: + case 76: + case 77: + pkg_msr[PERF_CSTATE_PKG_C6_RES].msr = MSR_PKG_C7_RESIDENCY; + } + + if (cstate_probe_msr(core_msr, core_events_attrs, PERF_CSTATE_CORE_EVENT_MAX)) + has_cstate_core = true; + + if (cstate_probe_msr(pkg_msr, pkg_events_attrs, PERF_CSTATE_PKG_EVENT_MAX)) + has_cstate_pkg = true; + + return (has_cstate_core || has_cstate_pkg) ? 0 : -ENODEV; +} + +static void __init cstate_cpumask_init(void) +{ + int cpu; + + cpu_notifier_register_begin(); + + for_each_online_cpu(cpu) + cstate_cpu_init(cpu); + + __perf_cpu_notifier(cstate_cpu_notifier); + + cpu_notifier_register_done(); +} + +static struct pmu cstate_core_pmu = { + .attr_groups = core_attr_groups, + .name = "cstate_core", + .task_ctx_nr = perf_invalid_context, + .event_init = cstate_pmu_event_init, + .add = cstate_pmu_event_add, /* must have */ + .del = cstate_pmu_event_del, /* must have */ + .start = cstate_pmu_event_start, + .stop = cstate_pmu_event_stop, + .read = cstate_pmu_event_update, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT, +}; + +static struct pmu cstate_pkg_pmu = { + .attr_groups = pkg_attr_groups, + .name = "cstate_pkg", + .task_ctx_nr = perf_invalid_context, + .event_init = cstate_pmu_event_init, + .add = cstate_pmu_event_add, /* must have */ + .del = cstate_pmu_event_del, /* must have */ + .start = cstate_pmu_event_start, + .stop = cstate_pmu_event_stop, + .read = cstate_pmu_event_update, + .capabilities = PERF_PMU_CAP_NO_INTERRUPT, +}; + +static void __init cstate_pmus_register(void) +{ + int err; + + if (has_cstate_core) { + err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1); + if (WARN_ON(err)) + pr_info("Failed to register PMU %s error %d\n", + cstate_core_pmu.name, err); + } + + if (has_cstate_pkg) { + err = perf_pmu_register(&cstate_pkg_pmu, cstate_pkg_pmu.name, -1); + if (WARN_ON(err)) + pr_info("Failed to register PMU %s error %d\n", + cstate_pkg_pmu.name, err); + } +} + +static int __init cstate_pmu_init(void) +{ + int err; + + if (cpu_has_hypervisor) + return -ENODEV; + + err = cstate_init(); + if (err) + return err; + + cstate_cpumask_init(); + + cstate_pmus_register(); + + return 0; +} + +device_initcall(cstate_pmu_init); From 712df65ccb63da08a484bf57c40b250dfd4103a7 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Thu, 24 Sep 2015 21:10:21 +0900 Subject: [PATCH 178/260] perf/x86/intel/uncore: Fix multi-segment problem of perf_event_intel_uncore In multi-segment system, uncore devices may belong to buses whose segment number is other than 0: .... 0000:ff:10.5 System peripheral: Intel Corporation Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers (rev 03) ... 0001:7f:10.5 System peripheral: Intel Corporation Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers (rev 03) ... 0001:bf:10.5 System peripheral: Intel Corporation Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers (rev 03) ... 0001:ff:10.5 System peripheral: Intel Corporation Xeon E5 v3/Core i7 Scratchpad & Semaphore Registers (rev 03 ... In that case, relation of bus number and physical id may be broken because "uncore_pcibus_to_physid" doesn't take account of PCI segment. For example, bus 0000:ff and 0001:ff uses the same entry of "uncore_pcibus_to_physid" array. This patch fixes this problem by introducing the segment-aware pci2phy_map instead. Signed-off-by: Taku Izumi Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: acme@kernel.org Cc: hpa@zytor.com Link: http://lkml.kernel.org/r/1443096621-4119-1-git-send-email-izumi.taku@jp.fujitsu.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_uncore.c | 61 ++++++++++++++++++- arch/x86/kernel/cpu/perf_event_intel_uncore.h | 12 +++- .../kernel/cpu/perf_event_intel_uncore_snb.c | 14 ++++- .../cpu/perf_event_intel_uncore_snbep.c | 32 +++++++--- 4 files changed, 105 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 560e5255b15e..61215a69b03d 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -7,7 +7,8 @@ struct intel_uncore_type **uncore_pci_uncores = empty_uncore; static bool pcidrv_registered; struct pci_driver *uncore_pci_driver; /* pci bus to socket mapping */ -int uncore_pcibus_to_physid[256] = { [0 ... 255] = -1, }; +DEFINE_RAW_SPINLOCK(pci2phy_map_lock); +struct list_head pci2phy_map_head = LIST_HEAD_INIT(pci2phy_map_head); struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; static DEFINE_RAW_SPINLOCK(uncore_box_lock); @@ -20,6 +21,59 @@ static struct event_constraint uncore_constraint_fixed = struct event_constraint uncore_constraint_empty = EVENT_CONSTRAINT(0, 0, 0); +int uncore_pcibus_to_physid(struct pci_bus *bus) +{ + struct pci2phy_map *map; + int phys_id = -1; + + raw_spin_lock(&pci2phy_map_lock); + list_for_each_entry(map, &pci2phy_map_head, list) { + if (map->segment == pci_domain_nr(bus)) { + phys_id = map->pbus_to_physid[bus->number]; + break; + } + } + raw_spin_unlock(&pci2phy_map_lock); + + return phys_id; +} + +struct pci2phy_map *__find_pci2phy_map(int segment) +{ + struct pci2phy_map *map, *alloc = NULL; + int i; + + lockdep_assert_held(&pci2phy_map_lock); + +lookup: + list_for_each_entry(map, &pci2phy_map_head, list) { + if (map->segment == segment) + goto end; + } + + if (!alloc) { + raw_spin_unlock(&pci2phy_map_lock); + alloc = kmalloc(sizeof(struct pci2phy_map), GFP_KERNEL); + raw_spin_lock(&pci2phy_map_lock); + + if (!alloc) + return NULL; + + goto lookup; + } + + map = alloc; + alloc = NULL; + map->segment = segment; + for (i = 0; i < 256; i++) + map->pbus_to_physid[i] = -1; + list_add_tail(&map->list, &pci2phy_map_head); + +end: + kfree(alloc); + return map; +} + ssize_t uncore_event_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -809,7 +863,7 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id int phys_id; bool first_box = false; - phys_id = uncore_pcibus_to_physid[pdev->bus->number]; + phys_id = uncore_pcibus_to_physid(pdev->bus); if (phys_id < 0) return -ENODEV; @@ -856,9 +910,10 @@ static void uncore_pci_remove(struct pci_dev *pdev) { struct intel_uncore_box *box = pci_get_drvdata(pdev); struct intel_uncore_pmu *pmu; - int i, cpu, phys_id = uncore_pcibus_to_physid[pdev->bus->number]; + int i, cpu, phys_id; bool last_box = false; + phys_id = uncore_pcibus_to_physid(pdev->bus); box = pci_get_drvdata(pdev); if (!box) { for (i = 0; i < UNCORE_EXTRA_PCI_DEV_MAX; i++) { diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 72c54c2e5b1a..2f0a4a98e16b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h @@ -117,6 +117,15 @@ struct uncore_event_desc { const char *config; }; +struct pci2phy_map { + struct list_head list; + int segment; + int pbus_to_physid[256]; +}; + +int uncore_pcibus_to_physid(struct pci_bus *bus); +struct pci2phy_map *__find_pci2phy_map(int segment); + ssize_t uncore_event_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -317,7 +326,8 @@ u64 uncore_shared_reg_config(struct intel_uncore_box *box, int idx); extern struct intel_uncore_type **uncore_msr_uncores; extern struct intel_uncore_type **uncore_pci_uncores; extern struct pci_driver *uncore_pci_driver; -extern int uncore_pcibus_to_physid[256]; +extern raw_spinlock_t pci2phy_map_lock; +extern struct list_head pci2phy_map_head; extern struct pci_dev *uncore_extra_pci_dev[UNCORE_SOCKET_MAX][UNCORE_EXTRA_PCI_DEV_MAX]; extern struct event_constraint uncore_constraint_empty; diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c index f78574b3cb55..845256158a10 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c @@ -420,15 +420,25 @@ static void snb_uncore_imc_event_del(struct perf_event *event, int flags) static int snb_pci2phy_map_init(int devid) { struct pci_dev *dev = NULL; - int bus; + struct pci2phy_map *map; + int bus, segment; dev = pci_get_device(PCI_VENDOR_ID_INTEL, devid, dev); if (!dev) return -ENOTTY; bus = dev->bus->number; + segment = pci_domain_nr(dev->bus); - uncore_pcibus_to_physid[bus] = 0; + raw_spin_lock(&pci2phy_map_lock); + map = __find_pci2phy_map(segment); + if (!map) { + raw_spin_unlock(&pci2phy_map_lock); + pci_dev_put(dev); + return -ENOMEM; + } + map->pbus_to_physid[bus] = 0; + raw_spin_unlock(&pci2phy_map_lock); pci_dev_put(dev); diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c index 8cbb3f386b07..f0f4fcba252e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c @@ -1087,7 +1087,8 @@ static struct pci_driver snbep_uncore_pci_driver = { static int snbep_pci2phy_map_init(int devid) { struct pci_dev *ubox_dev = NULL; - int i, bus, nodeid; + int i, bus, nodeid, segment; + struct pci2phy_map *map; int err = 0; u32 config = 0; @@ -1106,16 +1107,27 @@ static int snbep_pci2phy_map_init(int devid) err = pci_read_config_dword(ubox_dev, 0x54, &config); if (err) break; + + segment = pci_domain_nr(ubox_dev->bus); + raw_spin_lock(&pci2phy_map_lock); + map = __find_pci2phy_map(segment); + if (!map) { + raw_spin_unlock(&pci2phy_map_lock); + err = -ENOMEM; + break; + } + /* * every three bits in the Node ID mapping register maps * to a particular node. */ for (i = 0; i < 8; i++) { if (nodeid == ((config >> (3 * i)) & 0x7)) { - uncore_pcibus_to_physid[bus] = i; + map->pbus_to_physid[bus] = i; break; } } + raw_spin_unlock(&pci2phy_map_lock); } if (!err) { @@ -1123,13 +1135,17 @@ static int snbep_pci2phy_map_init(int devid) * For PCI bus with no UBOX device, find the next bus * that has UBOX device and use its mapping. */ - i = -1; - for (bus = 255; bus >= 0; bus--) { - if (uncore_pcibus_to_physid[bus] >= 0) - i = uncore_pcibus_to_physid[bus]; - else - uncore_pcibus_to_physid[bus] = i; + raw_spin_lock(&pci2phy_map_lock); + list_for_each_entry(map, &pci2phy_map_head, list) { + i = -1; + for (bus = 255; bus >= 0; bus--) { + if (map->pbus_to_physid[bus] >= 0) + i = map->pbus_to_physid[bus]; + else + map->pbus_to_physid[bus] = i; + } } + raw_spin_unlock(&pci2phy_map_lock); } pci_dev_put(ubox_dev); From 0974d2c9719a4c74fea0f6886b9922b100b903a6 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 6 Oct 2015 14:25:10 +0200 Subject: [PATCH 179/260] perf tools: Get rid of superfluos call to reset_dimensions There's no need to call reset_dimensions within __setup_output_field function. It's already called in its caller setup_sorting right before perf_hpp__init, which will be changed in following patch to respect taken dimension. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: David Ahern Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444134312-29136-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index ee94b728fca4..8521e3c89b8d 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1917,8 +1917,6 @@ static int __setup_output_field(void) if (field_order == NULL) return 0; - reset_dimensions(); - strp = str = strdup(field_order); if (str == NULL) { error("Not enough memory to setup output fields"); From beeaaeb3684d97e89548c1b6b6275329214014df Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 6 Oct 2015 14:25:11 +0200 Subject: [PATCH 180/260] perf tools: Introduce hpp_dimension__add_output function This function will allow to register output column from ui code and respect taken sort/output dimensions. Signed-off-by: Jiri Olsa Acked-by: Namhyung Kim Cc: David Ahern Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444134312-29136-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 6 ++++++ tools/perf/util/sort.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 8521e3c89b8d..2d8ccd4d9e1b 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -1577,6 +1577,12 @@ static int __hpp_dimension__add_output(struct hpp_dimension *hd) return 0; } +int hpp_dimension__add_output(unsigned col) +{ + BUG_ON(col >= PERF_HPP__MAX_INDEX); + return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); +} + int sort_dimension__add(const char *tok) { unsigned int i; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 33b3d30e18d3..31228851e397 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -234,4 +234,6 @@ void perf_hpp__set_elide(int idx, bool elide); int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset); bool is_strict_order(const char *order); + +int hpp_dimension__add_output(unsigned col); #endif /* __PERF_SORT_H */ From 1178bfd41f3ab6914eb6884875b776bc3032c9b5 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 6 Oct 2015 14:25:12 +0200 Subject: [PATCH 181/260] perf tools: Use hpp_dimension__add_output to register hpp columns The perf_hpp__init currently does not respect sorting dimensions and the setup_sorting function could endup queueing same format twice. That screwed up the perf_hpp__list and got stuck in loop within perf_hpp__setup_output_field function. $ perf report -F +overhead 0x00000000004c1355 in perf_hpp__is_sort_entry (format=format@entry=0x880440 ) at util/sort.c:1506 1506 { #0 0x00000000004c1355 in perf_hpp__is_sort_entry (format=format@entry=0x880440 ) at util/sort.c:1506 #1 0x00000000004c139d in perf_hpp__same_sort_entry (a=a@entry=0x880440 , b=b@entry=0x2bb2fe0) at util/sort.c:1380 #2 0x00000000004f8d3c in perf_hpp__setup_output_field () at ui/hist.c:554 #3 0x00000000004c1d1e in setup_sorting () at util/sort.c:1984 #4 0x000000000042efbf in cmd_report (argc=0, argv=0x7ffea5a0e790, prefix=) at builtin-report.c:874 #5 0x0000000000476f13 in run_builtin (p=p@entry=0x875628 , argc=argc@entry=3, argv=argv@entry=0x7ffea5a0e790) at perf.c:385 #6 0x000000000047710b in handle_internal_command (argc=3, argv=0x7ffea5a0e790) at perf.c:445 #7 0x0000000000477176 in run_argv (argcp=argcp@entry=0x7ffea5a0e5fc, argv=argv@entry=0x7ffea5a0e5f0) at perf.c:489 #8 0x00000000004773e7 in main (argc=3, argv=0x7ffea5a0e790) at perf.c:606 Using hpp_dimension__add_output function to register the output column. It will also mark the dimension as taken and omit above stuck. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Acked-by: Namhyung Kim Cc: David Ahern Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444134312-29136-4-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/hist.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 25d608394d74..5029ba2b55af 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -463,27 +463,27 @@ void perf_hpp__init(void) return; if (symbol_conf.cumulate_callchain) { - perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_ACC); perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self"; } - perf_hpp__column_enable(PERF_HPP__OVERHEAD); + hpp_dimension__add_output(PERF_HPP__OVERHEAD); if (symbol_conf.show_cpu_utilization) { - perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); - perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_SYS); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_US); if (perf_guest) { - perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); - perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_SYS); + hpp_dimension__add_output(PERF_HPP__OVERHEAD_GUEST_US); } } if (symbol_conf.show_nr_samples) - perf_hpp__column_enable(PERF_HPP__SAMPLES); + hpp_dimension__add_output(PERF_HPP__SAMPLES); if (symbol_conf.show_total_period) - perf_hpp__column_enable(PERF_HPP__PERIOD); + hpp_dimension__add_output(PERF_HPP__PERIOD); /* prepend overhead field for backward compatiblity. */ list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list; From 38349665388fb079fb2bc8c46db9446dd976802a Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 6 Oct 2015 11:00:17 +0200 Subject: [PATCH 182/260] perf tools: Fix handling read result using a signed variable The function can return negative value, assigning it to unsigned variable can cause memory corruption. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2038576 Signed-off-by: Andrzej Hajda Cc: Bartlomiej Zolnierkiewicz Cc: Marek Szyprowski Cc: Peter Zijlstra Cc: kernel-janitors@vger.kernel.org Link: http://lkml.kernel.org/r/1444122017-16856-1-git-send-email-a.hajda@samsung.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index cb98b5af9e17..8b10621b415c 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -67,7 +67,8 @@ static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, char filename[PATH_MAX]; char bf[4096]; int fd; - size_t size = 0, n; + size_t size = 0; + ssize_t n; char *nl, *name, *tgids, *ppids; *tgid = -1; From ae938802443732e77d01f8d5b52b900b9327ff30 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 6 Oct 2015 17:46:46 -0300 Subject: [PATCH 183/260] perf python: Support the PERF_RECORD_SWITCH event To test it check tools/perf/python/twatch.py, after following the instructions there to enable context_switch, output looks like: [root@zoo linux]# tools/perf/python/twatch.py cpu: 1, pid: 31463, tid: 31463 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31463, switch_out: 0 } cpu: 2, pid: 31463, tid: 31496 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31496, switch_out: 0 } cpu: 2, pid: 31463, tid: 31496 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31496, switch_out: 1 } cpu: 3, pid: 31463, tid: 31527 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31527, switch_out: 0 } cpu: 1, pid: 31463, tid: 31463 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31463, switch_out: 1 } cpu: 3, pid: 31463, tid: 31527 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31527, switch_out: 1 } cpu: 1, pid: 31463, tid: 31463 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31463, switch_out: 0 } ^CTraceback (most recent call last): File "tools/perf/python/twatch.py", line 67, in main(context_switch = 1, thread = 31463) File "tools/perf/python/twatch.py", line 40, in main evlist.poll(timeout = -1) KeyboardInterrupt [root@zoo linux]# Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Guy Streeter Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-1ukistmpamc5z717k80ctcp2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/python/twatch.py | 23 +++++++++++++-- tools/perf/util/python.c | 59 ++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/tools/perf/python/twatch.py b/tools/perf/python/twatch.py index b9d508336ae6..c235c22b107a 100755 --- a/tools/perf/python/twatch.py +++ b/tools/perf/python/twatch.py @@ -15,14 +15,14 @@ import perf -def main(): +def main(context_switch = 0, thread = -1): cpus = perf.cpu_map() - threads = perf.thread_map() + threads = perf.thread_map(thread) evsel = perf.evsel(type = perf.TYPE_SOFTWARE, config = perf.COUNT_SW_DUMMY, task = 1, comm = 1, mmap = 0, freq = 0, wakeup_events = 1, watermark = 1, - sample_id_all = 1, + sample_id_all = 1, context_switch = context_switch, sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU) """What we want are just the PERF_RECORD_ lifetime events for threads, @@ -48,4 +48,21 @@ def main(): print event if __name__ == '__main__': + """ + To test the PERF_RECORD_SWITCH record, pick a pid and replace + in the following line. + + Example output: + +cpu: 3, pid: 31463, tid: 31593 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31593, switch_out: 1 } +cpu: 1, pid: 31463, tid: 31489 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31489, switch_out: 1 } +cpu: 2, pid: 31463, tid: 31496 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31496, switch_out: 1 } +cpu: 3, pid: 31463, tid: 31491 { type: context_switch, next_prev_pid: 31463, next_prev_tid: 31491, switch_out: 0 } + + It is possible as well to use event.misc & perf.PERF_RECORD_MISC_SWITCH_OUT + to figure out if this is a context switch in or out of the monitored threads. + + If bored, please add command line option parsing support for these options :-) + """ + # main(context_switch = 1, thread = 31463) main() diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 6324fe6b161e..98f127abfa42 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -67,6 +67,7 @@ static char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object."); static PyMemberDef pyrf_mmap_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), + member_def(perf_event_header, misc, T_UINT, "event misc"), member_def(mmap_event, pid, T_UINT, "event pid"), member_def(mmap_event, tid, T_UINT, "event tid"), member_def(mmap_event, start, T_ULONGLONG, "start of the map"), @@ -297,6 +298,43 @@ static PyTypeObject pyrf_sample_event__type = { .tp_repr = (reprfunc)pyrf_sample_event__repr, }; +static char pyrf_context_switch_event__doc[] = PyDoc_STR("perf context_switch event object."); + +static PyMemberDef pyrf_context_switch_event__members[] = { + sample_members + member_def(perf_event_header, type, T_UINT, "event type"), + member_def(context_switch_event, next_prev_pid, T_UINT, "next/prev pid"), + member_def(context_switch_event, next_prev_tid, T_UINT, "next/prev tid"), + { .name = NULL, }, +}; + +static PyObject *pyrf_context_switch_event__repr(struct pyrf_event *pevent) +{ + PyObject *ret; + char *s; + + if (asprintf(&s, "{ type: context_switch, next_prev_pid: %u, next_prev_tid: %u, switch_out: %u }", + pevent->event.context_switch.next_prev_pid, + pevent->event.context_switch.next_prev_tid, + !!(pevent->event.header.misc & PERF_RECORD_MISC_SWITCH_OUT)) < 0) { + ret = PyErr_NoMemory(); + } else { + ret = PyString_FromString(s); + free(s); + } + return ret; +} + +static PyTypeObject pyrf_context_switch_event__type = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "perf.context_switch_event", + .tp_basicsize = sizeof(struct pyrf_event), + .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, + .tp_doc = pyrf_context_switch_event__doc, + .tp_members = pyrf_context_switch_event__members, + .tp_repr = (reprfunc)pyrf_context_switch_event__repr, +}; + static int pyrf_event__setup_types(void) { int err; @@ -306,6 +344,7 @@ static int pyrf_event__setup_types(void) pyrf_lost_event__type.tp_new = pyrf_read_event__type.tp_new = pyrf_sample_event__type.tp_new = + pyrf_context_switch_event__type.tp_new = pyrf_throttle_event__type.tp_new = PyType_GenericNew; err = PyType_Ready(&pyrf_mmap_event__type); if (err < 0) @@ -328,6 +367,9 @@ static int pyrf_event__setup_types(void) err = PyType_Ready(&pyrf_sample_event__type); if (err < 0) goto out; + err = PyType_Ready(&pyrf_context_switch_event__type); + if (err < 0) + goto out; out: return err; } @@ -342,6 +384,8 @@ static PyTypeObject *pyrf_event__type[] = { [PERF_RECORD_FORK] = &pyrf_task_event__type, [PERF_RECORD_READ] = &pyrf_read_event__type, [PERF_RECORD_SAMPLE] = &pyrf_sample_event__type, + [PERF_RECORD_SWITCH] = &pyrf_context_switch_event__type, + [PERF_RECORD_SWITCH_CPU_WIDE] = &pyrf_context_switch_event__type, }; static PyObject *pyrf_event__new(union perf_event *event) @@ -349,8 +393,10 @@ static PyObject *pyrf_event__new(union perf_event *event) struct pyrf_event *pevent; PyTypeObject *ptype; - if (event->header.type < PERF_RECORD_MMAP || - event->header.type > PERF_RECORD_SAMPLE) + if ((event->header.type < PERF_RECORD_MMAP || + event->header.type > PERF_RECORD_SAMPLE) && + !(event->header.type == PERF_RECORD_SWITCH || + event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)) return NULL; ptype = pyrf_event__type[event->header.type]; @@ -528,6 +574,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, "exclude_hv", "exclude_idle", "mmap", + "context_switch", "comm", "freq", "inherit_stat", @@ -553,6 +600,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, exclude_hv = 0, exclude_idle = 0, mmap = 0, + context_switch = 0, comm = 0, freq = 1, inherit_stat = 0, @@ -565,13 +613,13 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, int idx = 0; if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|iKiKKiiiiiiiiiiiiiiiiiiiiiKK", kwlist, + "|iKiKKiiiiiiiiiiiiiiiiiiiiiiKK", kwlist, &attr.type, &attr.config, &attr.sample_freq, &sample_period, &attr.sample_type, &attr.read_format, &disabled, &inherit, &pinned, &exclusive, &exclude_user, &exclude_kernel, &exclude_hv, &exclude_idle, - &mmap, &comm, &freq, &inherit_stat, + &mmap, &context_switch, &comm, &freq, &inherit_stat, &enable_on_exec, &task, &watermark, &precise_ip, &mmap_data, &sample_id_all, &attr.wakeup_events, &attr.bp_type, @@ -595,6 +643,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, attr.exclude_hv = exclude_hv; attr.exclude_idle = exclude_idle; attr.mmap = mmap; + attr.context_switch = context_switch; attr.comm = comm; attr.freq = freq; attr.inherit_stat = inherit_stat; @@ -1019,6 +1068,8 @@ static struct { PERF_CONST(RECORD_LOST_SAMPLES), PERF_CONST(RECORD_SWITCH), PERF_CONST(RECORD_SWITCH_CPU_WIDE), + + PERF_CONST(RECORD_MISC_SWITCH_OUT), { .name = NULL, }, }; From dc38218e8b598a0092dae9715e603e9628203bec Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 11 Oct 2015 17:17:24 -0300 Subject: [PATCH 184/260] perf symbols: Try the .debug/ DSO cache as a last resort Not as the first attempt at finding a vmlinux for the running kernel, this way we get a more informative filename to present in tools, it will check that the build-id is the same as the one previously loaded in the DSO in dso->build_id, reading from /sys/kernel/notes, for instance. E.g. in the annotation TUI, going from 'perf top', for the scsi_sg_alloc kernel function, in the first line: Before: scsi_sg_alloc /root/.debug/.build-id/28/2777c262e6b3c0451375163c9a81c893218ab1 After: scsi_sg_alloc /lib/modules/4.3.0-rc1+/build/vmlinux And: # ls -la /root/.debug/.build-id/28/2777c262e6b3c0451375163c9a81c893218ab1 lrwxrwxrwx. 1 root root 81 Sep 22 16:11 /root/.debug/.build-id/28/2777c262e6b3c0451375163c9a81c893218ab1 -> ../../home/git/build/v4.3.0-rc1+/vmlinux/282777c262e6b3c0451375163c9a81c893218ab1 # file ~/.debug/home/git/build/v4.3.0-rc1+/vmlinux/282777c262e6b3c0451375163c9a81c893218ab1 /root/.debug/home/git/build/v4.3.0-rc1+/vmlinux/282777c262e6b3c0451375163c9a81c893218ab1: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=282777c262e6b3c0451375163c9a81c893218ab1, not stripped # The same as: # file /lib/modules/4.3.0-rc1+/build/vmlinux /lib/modules/4.3.0-rc1+/build/vmlinux: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, BuildID[sha1]=282777c262e6b3c0451375163c9a81c893218ab1, not stripped Furthermore: # sha256sum /lib/modules/4.3.0-rc1+/build/vmlinux e7a789bbdc61029ec09140c228e1dd651271f38ef0b8416c0b7d5ff727b98be2 /lib/modules/4.3.0-rc1+/build/vmlinux # sha256sum ~/.debug/home/git/build/v4.3.0-rc1+/vmlinux/282777c262e6b3c0451375163c9a81c893218ab1 e7a789bbdc61029ec09140c228e1dd651271f38ef0b8416c0b7d5ff727b98be2 /root/.debug/home/git/build/v4.3.0-rc1+/vmlinux/282777c262e6b3c0451375163c9a81c893218ab1 [root@zoo new]# Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-9y42ikzq3jisiddoi6f07n8z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index bcda43bee4d4..e7bf0c46918d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1607,6 +1607,15 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, int i, err = 0; char *filename = NULL; + pr_debug("Looking at the vmlinux_path (%d entries long)\n", + vmlinux_path__nr_entries + 1); + + for (i = 0; i < vmlinux_path__nr_entries; ++i) { + err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); + if (err > 0) + goto out; + } + if (!symbol_conf.ignore_vmlinux_buildid) filename = dso__build_id_filename(dso, NULL, 0); if (filename != NULL) { @@ -1615,15 +1624,6 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map, goto out; free(filename); } - - pr_debug("Looking at the vmlinux_path (%d entries long)\n", - vmlinux_path__nr_entries + 1); - - for (i = 0; i < vmlinux_path__nr_entries; ++i) { - err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter); - if (err > 0) - break; - } out: return err; } From 7727a92544b2a507b83fdc7d3e4b6f4545c9f364 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 12 Oct 2015 13:56:50 -0300 Subject: [PATCH 185/260] perf ui browsers: Remove help messages about use of right and arrow keys They were repurposed for horizontal scrolling, so use just ENTER/ESC in the help messages. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Fixes: c6c3c02dea40 ("perf hists browser: Implement horizontal scrolling") Link: http://lkml.kernel.org/n/tip-n5ar4qg8fs12ax4vhr3rxhxj@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 6 +++--- tools/perf/ui/browsers/hists.c | 8 ++++---- tools/perf/ui/browsers/map.c | 2 +- tools/perf/ui/browsers/scripts.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 29739b347599..bec0b62d8e38 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -768,8 +768,8 @@ static int annotate_browser__run(struct annotate_browser *browser, "UP/DOWN/PGUP\n" "PGDN/SPACE Navigate\n" "q/ESC/CTRL+C Exit\n\n" - "-> Go to target\n" - "<- Exit\n" + "ENTER Go to target\n" + "ESC Exit\n" "H Cycle thru hottest instructions\n" "j Toggle showing jump to target arrows\n" "J Toggle showing number of jump sources on targets\n" @@ -1056,7 +1056,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, goto out_free_offsets; } - ui_helpline__push("Press <- or ESC to exit"); + ui_helpline__push("Press ESC to exit"); notes = symbol__annotation(sym); browser.start = map__rip_2objdump(map, sym->start); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 9b7346a881cf..eea16278d038 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1496,7 +1496,7 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act) thread__zput(browser->hists->thread_filter); ui_helpline__pop(); } else { - ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", + ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", thread->comm_set ? thread__comm_str(thread) : "", thread->tid); browser->hists->thread_filter = thread__get(thread); @@ -1540,7 +1540,7 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) } else { if (map == NULL) return 0; - ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", + ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", __map__is_kernel(map) ? "the Kernel" : map->dso->short_name); browser->hists->dso_filter = map->dso; perf_hpp__set_elide(HISTC_DSO, true); @@ -1761,8 +1761,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "For multiple event sessions:\n\n" \ "TAB/UNTAB Switch events\n\n" \ "For symbolic views (--sort has sym):\n\n" \ - "-> Zoom into DSO/Threads & Annotate current symbol\n" \ - "<- Zoom out\n" \ + "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ + "ESC Zoom out\n" \ "a Annotate current symbol\n" \ "C Collapse all callchains\n" \ "d Zoom into current DSO\n" \ diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c index 8c154c7d4669..80912778bb6d 100644 --- a/tools/perf/ui/browsers/map.c +++ b/tools/perf/ui/browsers/map.c @@ -72,7 +72,7 @@ static int map_browser__run(struct map_browser *browser) int key; if (ui_browser__show(&browser->b, browser->map->dso->long_name, - "Press <- or ESC to exit, %s / to search", + "Press ESC to exit, %s / to search", verbose ? "" : "restart with -v to use") < 0) return -1; diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index e13b48d705ef..ad6b6ee3770e 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -89,7 +89,7 @@ static int script_browser__run(struct perf_script_browser *browser) int key; if (ui_browser__show(&browser->b, browser->script_name, - "Press <- or ESC to exit") < 0) + "Press ESC to exit") < 0) return -1; while (1) { From 4aa8e454d347a1c96a2322683a6798de7e17da5f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 12 Oct 2015 14:02:29 -0300 Subject: [PATCH 186/260] perf hists browser: Inform how to reset the symbol filter When in the hists browser, i.e. in 'perf report' or in 'perf top', it is possible to press '/' and specify a substring to filter by symbol name. Clarify how to remove a filter by making the prompt be: Please enter the name of symbol you want to see. To remove the filter later, press / + ENTER Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-vbq2b0kyufwy6p0ctkfswcoe@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index eea16278d038..772834912c7c 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1889,7 +1889,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, continue; case '/': if (ui_browser__input_window("Symbol to show", - "Please enter the name of symbol you want to see", + "Please enter the name of symbol you want to see.\n" + "To remove the filter later, press / + ENTER.", buf, "ENTER: OK, ESC: Cancel", delay_secs * 2) == K_ENTER) { hists->symbol_filter_str = *buf ? buf : NULL; From 8eac1d5e9256260b9cc3bfcdd9b8b995990950f5 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 27 Sep 2015 20:37:57 +0200 Subject: [PATCH 187/260] perf callchain: Use debug_frame if eh_frame is unusable When NO_LIBUNWIND_DEBUG_FRAME=0, use the .debug_frame if the .eh_frame doesn't contain the approprate unwind tables. Signed-off-by: Rabin Vincent Acked-by: Jiri Olsa Cc: Peter Zijlstra Cc: Rabin Vincent Link: http://lkml.kernel.org/r/1443379079-29133-3-git-send-email-rabin.vincent@axis.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/unwind-libunwind.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index 4c00507ee3fd..ea993f6c7e0c 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -330,6 +330,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, struct map *map; unw_dyn_info_t di; u64 table_data, segbase, fde_count; + int ret = -EINVAL; map = find_map(ip, ui); if (!map || !map->dso) @@ -348,13 +349,14 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, di.u.rti.table_data = map->start + table_data; di.u.rti.table_len = fde_count * sizeof(struct table_entry) / sizeof(unw_word_t); - return dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); + ret = dwarf_search_unwind_table(as, ip, &di, pi, + need_unwind_info, arg); } #ifndef NO_LIBUNWIND_DEBUG_FRAME /* Check the .debug_frame section for unwinding info */ - if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { + if (ret < 0 && + !read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) { int fd = dso__data_get_fd(map->dso, ui->machine); int is_exec = elf_is_exec(fd, map->dso->name); unw_word_t base = is_exec ? 0 : map->start; @@ -370,7 +372,7 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, } #endif - return -EINVAL; + return ret; } static int access_fpreg(unw_addr_space_t __maybe_unused as, From 186c6cfb32beae66140bc3c3fe4a519ee0234e33 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sun, 27 Sep 2015 20:37:55 +0200 Subject: [PATCH 188/260] perf callchains: Fix unw_word_t pointer casts unw_word_t is uint64_t even on 32-bit MIPS. Cast it to uintptr_t before the cast to void *p to get rid of the following errors: util/unwind-libunwind.c: In function 'access_mem': util/unwind-libunwind.c:464:4: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] util/unwind-libunwind.c:475:2: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] cc1: all warnings being treated as errors make[3]: *** [util/unwind-libunwind.o] Error 1 Signed-off-by: Rabin Vincent Acked-by: Jiri Olsa Cc: Peter Zijlstra Cc: Rabin Vincent Link: http://lkml.kernel.org/r/1443379079-29133-1-git-send-email-rabin.vincent@axis.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/unwind-libunwind.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index ea993f6c7e0c..f729f9e99f99 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -463,7 +463,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as, if (ret) { pr_debug("unwind: access_mem %p not inside range" " 0x%" PRIx64 "-0x%" PRIx64 "\n", - (void *) addr, start, end); + (void *) (uintptr_t) addr, start, end); *valp = 0; return ret; } @@ -473,7 +473,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as, offset = addr - start; *valp = *(unw_word_t *)&stack->data[offset]; pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", - (void *) addr, (unsigned long)*valp, offset); + (void *) (uintptr_t) addr, (unsigned long)*valp, offset); return 0; } From 31eb4360546b4bd890f349db01295a173c09b0fb Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 13 Oct 2015 09:02:01 +0900 Subject: [PATCH 189/260] perf hists browser: Add 'm' key for context menu display With horizontal scrolling, the left/right arrow keys are used to scroll columns and ENTER/ESC keys are used to enter/exit menu. However if callchain is recorded, the ENTER key is used to toggle callchain expansion so there's no way to display menu. Use 'm' key to display the menu for this case. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444694521-8136-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 772834912c7c..e5afb8936040 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1769,6 +1769,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, "E Expand all callchains\n" \ "F Toggle percentage of filtered entries\n" \ "H Display column headers\n" \ + "m Display context menu\n" \ "S Zoom into current Processor Socket\n" \ /* help messages are sorted by lexical order of the hotkey */ @@ -1935,6 +1936,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, continue; case K_ENTER: case K_RIGHT: + case 'm': /* menu */ break; case K_ESC: From c95f3432118c6b7a3bde63aa6eb95ccd163119eb Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 13 Oct 2015 10:52:14 +0200 Subject: [PATCH 190/260] tools include: Fix strict-aliasing rules breakage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vinson reported build breakage with gcc 4.4 due to strict-aliasing. CC util/annotate.o cc1: warnings being treated as errors util/annotate.c: In function ‘disasm__purge’: linux-next/tools/include/linux/compiler.h:66: error: dereferencing pointer ‘res.41’ does break strict-aliasing rules The reason is READ_ONCE/WRITE_ONCE code we took from kernel sources. They intentionaly break aliasing rules. While this is ok for kernel because it's built with -fno-strict-aliasing, it breaks perf which is build with -Wstrict-aliasing=3. Using extra __may_alias__ type to allow aliasing in this case. Reported-and-tested-by: Vinson Lee Signed-off-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: Martin Liska Cc: Peter Zijlstra Cc: Rabin Vincent Cc: linux-next@vger.kernel.org Link: http://lkml.kernel.org/r/20151013085214.GB2705@krava.brq.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/linux/compiler.h | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index 9098083869c8..fa7208a32d76 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -43,13 +43,29 @@ #include +/* + * Following functions are taken from kernel sources and + * break aliasing rules in their original form. + * + * While kernel is compiled with -fno-strict-aliasing, + * perf uses -Wstrict-aliasing=3 which makes build fail + * under gcc 4.4. + * + * Using extra __may_alias__ type to allow aliasing + * in this case. + */ +typedef __u8 __attribute__((__may_alias__)) __u8_alias_t; +typedef __u16 __attribute__((__may_alias__)) __u16_alias_t; +typedef __u32 __attribute__((__may_alias__)) __u32_alias_t; +typedef __u64 __attribute__((__may_alias__)) __u64_alias_t; + static __always_inline void __read_once_size(const volatile void *p, void *res, int size) { switch (size) { - case 1: *(__u8 *)res = *(volatile __u8 *)p; break; - case 2: *(__u16 *)res = *(volatile __u16 *)p; break; - case 4: *(__u32 *)res = *(volatile __u32 *)p; break; - case 8: *(__u64 *)res = *(volatile __u64 *)p; break; + case 1: *(__u8_alias_t *) res = *(volatile __u8_alias_t *) p; break; + case 2: *(__u16_alias_t *) res = *(volatile __u16_alias_t *) p; break; + case 4: *(__u32_alias_t *) res = *(volatile __u32_alias_t *) p; break; + case 8: *(__u64_alias_t *) res = *(volatile __u64_alias_t *) p; break; default: barrier(); __builtin_memcpy((void *)res, (const void *)p, size); @@ -60,10 +76,10 @@ static __always_inline void __read_once_size(const volatile void *p, void *res, static __always_inline void __write_once_size(volatile void *p, void *res, int size) { switch (size) { - case 1: *(volatile __u8 *)p = *(__u8 *)res; break; - case 2: *(volatile __u16 *)p = *(__u16 *)res; break; - case 4: *(volatile __u32 *)p = *(__u32 *)res; break; - case 8: *(volatile __u64 *)p = *(__u64 *)res; break; + case 1: *(volatile __u8_alias_t *) p = *(__u8_alias_t *) res; break; + case 2: *(volatile __u16_alias_t *) p = *(__u16_alias_t *) res; break; + case 4: *(volatile __u32_alias_t *) p = *(__u32_alias_t *) res; break; + case 8: *(volatile __u64_alias_t *) p = *(__u64_alias_t *) res; break; default: barrier(); __builtin_memcpy((void *)p, (const void *)res, size); From 3a70fcd3a4db56731f67f0189514953c74257944 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 13 Oct 2015 14:43:58 +0200 Subject: [PATCH 191/260] tools build: Fix cross compile build He Kuang the new fixdep tool breaks cross compiling. The reason is it wouldn't get compiled under host arch, but under cross arch and failed to run. We need to add support for host side tools build, meanwhile disabling fixdep usage for cross arch builds. Reported-by: He Kuang Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/20151013124358.GB9467@krava.brq.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.include | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include index 6572bb023543..4e09ad617a60 100644 --- a/tools/build/Makefile.include +++ b/tools/build/Makefile.include @@ -1,6 +1,10 @@ build := -f $(srctree)/tools/build/Makefile.build dir=. obj +ifdef CROSS_COMPILE +fixdep: +else fixdep: $(Q)$(MAKE) -C $(srctree)/tools/build fixdep +endif .PHONY: fixdep From 8719138318316656988dbd422461c1addc9a9159 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 20 Oct 2015 00:23:48 +0900 Subject: [PATCH 192/260] perf test: Silence tracepoint event failures Currently, when 'perf test' is run by a normal user, it'll fail to access tracepoint events. The output becomes somewhat messy because it tries to be nice with long error messages and hints. IMHO this is not needed for 'perf test' by default and AFAIK 'perf test' uses pr_debug() rather than pr_err() for such messages so that one can use -v option to see further details on failed testcases if needed. Before: $ perf test 1: vmlinux symtab matches kallsyms : FAILED! 2: detect openat syscall event :Error: No permissions to read /sys/kernel/debug/tracing/events/syscalls/sys_enter_openat Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/tracing' FAILED! 3: detect openat syscall event on all cpus :Error: No permissions to read /sys/kernel/debug/tracing/events/syscalls/sys_enter_openat Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/tracing' FAILED! ... After: $ perf test 1: vmlinux symtab matches kallsyms : FAILED! 2: detect openat syscall event : FAILED! 3: detect openat syscall event on all cpus : FAILED! ... $ perf test -v 2 2: detect openat syscall event : --- start --- test child forked, pid 30575 Error: No permissions to read /sys/kernel/debug/tracing/events/syscalls/sys_enter_openat Hint: Try 'sudo mount -o remount,mode=755 /sys/kernel/debug/tracing' test child finished with -1 ---- end ---- detect openat syscall event: FAILED! Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Acked-by: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1445268229-1601-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/openat-syscall-all-cpus.c | 2 +- tools/perf/tests/openat-syscall-tp-fields.c | 2 +- tools/perf/tests/openat-syscall.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 9e104a2e973d..2006485a2859 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c @@ -34,7 +34,7 @@ int test__openat_syscall_event_on_all_cpus(void) evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); if (IS_ERR(evsel)) { tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); - pr_err("%s\n", errbuf); + pr_debug("%s\n", errbuf); goto out_thread_map_delete; } diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index 473d3869727e..5e811cd8f1c3 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c @@ -89,7 +89,7 @@ int test__syscall_openat_tp_fields(void) err = perf_evsel__parse_sample(evsel, event, &sample); if (err) { - pr_err("Can't parse sample, err = %d\n", err); + pr_debug("Can't parse sample, err = %d\n", err); goto out_delete_evlist; } diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c index 7b1db8306098..033b54797b8a 100644 --- a/tools/perf/tests/openat-syscall.c +++ b/tools/perf/tests/openat-syscall.c @@ -22,7 +22,7 @@ int test__openat_syscall_event(void) evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); if (IS_ERR(evsel)) { tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat"); - pr_err("%s\n", errbuf); + pr_debug("%s\n", errbuf); goto out_thread_map_delete; } From 2690c730935873065175de33f59cce5bb221b9dc Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 20 Oct 2015 00:23:49 +0900 Subject: [PATCH 193/260] perf test: Suppress libtraceevent warnings Currently libtraceevent emits warning on unsupported event formats. However it'd be better to see them only -v option is given. To do that, it needs to override the warning() function which is used in the libtracevent. Thus add set_warning_routine() same as set_die_routine() and check the verbose flag in our warning routine. Before: # perf test 5 5: parse events tests : Warning: [kvmmmu:kvm_mmu_get_page] bad op token { Warning: [kvmmmu:kvm_mmu_sync_page] bad op token { Warning: [kvmmmu:kvm_mmu_unsync_page] bad op token { Warning: [kvmmmu:kvm_mmu_prepare_zap_page] bad op token { Warning: [kvmmmu:fast_page_fault] function is_writable_pte not defined ... Ok After: # perf test 5 5: parse events tests : Ok Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Acked-by: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1445268229-1601-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 14 ++++++++++++++ tools/perf/util/usage.c | 5 +++++ tools/perf/util/util.h | 1 + 3 files changed, 20 insertions(+) diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 0648b84a9171..636d7b42d844 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -5,6 +5,7 @@ #include #include "tests.h" #include "debug.h" +#include "util.h" #include #include @@ -1753,6 +1754,17 @@ static int test_pmu_events(void) return ret; } +static void debug_warn(const char *warn, va_list params) +{ + char msg[1024]; + + if (!verbose) + return; + + vsnprintf(msg, sizeof(msg), warn, params); + fprintf(stderr, " Warning: %s\n", msg); +} + int test__parse_events(void) { int ret1, ret2 = 0; @@ -1764,6 +1776,8 @@ do { \ ret2 = ret1; \ } while (0) + set_warning_routine(debug_warn); + TEST_EVENTS(test__events); if (test_pmu()) diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index 4007aca8e0ca..6adfa18cdd4e 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -50,6 +50,11 @@ void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN) die_routine = routine; } +void set_warning_routine(void (*routine)(const char *err, va_list params)) +{ + warn_routine = routine; +} + void usage(const char *err) { usage_routine(err); diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 3d5b01e8978f..4cfb913aa9e0 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -145,6 +145,7 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2))) extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN); +extern void set_warning_routine(void (*routine)(const char *err, va_list params)); extern int prefixcmp(const char *str, const char *prefix); extern void set_buildid_dir(const char *dir); From 13839ec495a31844d66d487f740c07771c60a0d0 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:17 +0200 Subject: [PATCH 194/260] perf bench: Improve the 'perf bench mem memcpy' code readability - improve the readability of initializations - fix unnecessary double negations - fix ugly line breaks - fix other small details Signed-off-by: Ingo Molnar Cc: Andrew Morton Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-2-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-memcpy.c | 101 +++++++++++++++------------------- 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index d3dfb7936dcd..27606ff5c4f9 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c @@ -1,7 +1,7 @@ /* * mem-memcpy.c * - * memcpy: Simple memory copy in various ways + * Simple memcpy() and memset() benchmarks * * Written by Hitoshi Mitake */ @@ -61,20 +61,17 @@ struct routine { }; struct routine memcpy_routines[] = { - { .name = "default", - .desc = "Default memcpy() provided by glibc", - .fn.memcpy = memcpy }, + { .name = "default", + .desc = "Default memcpy() provided by glibc", + .fn.memcpy = memcpy }, + #ifdef HAVE_ARCH_X86_64_SUPPORT - -#define MEMCPY_FN(_fn, _name, _desc) {.name = _name, .desc = _desc, .fn.memcpy = _fn}, -#include "mem-memcpy-x86-64-asm-def.h" -#undef MEMCPY_FN - +# define MEMCPY_FN(_fn, _name, _desc) {.name = _name, .desc = _desc, .fn.memcpy = _fn}, +# include "mem-memcpy-x86-64-asm-def.h" +# undef MEMCPY_FN #endif - { NULL, - NULL, - {NULL} } + { NULL, } }; static const char * const bench_mem_memcpy_usage[] = { @@ -89,8 +86,7 @@ static struct perf_event_attr cycle_attr = { static void init_cycle(void) { - cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, - perf_event_open_cloexec_flag()); + cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); if (cycle_fd < 0 && errno == ENOSYS) die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); @@ -111,12 +107,9 @@ static u64 get_cycle(void) static double timeval2double(struct timeval *ts) { - return (double)ts->tv_sec + - (double)ts->tv_usec / (double)1000000; + return (double)ts->tv_sec + (double)ts->tv_usec / (double)1000000; } -#define pf (no_prefault ? 0 : 1) - #define print_bps(x) do { \ if (x < K) \ printf(" %14lf B/Sec", x); \ @@ -140,6 +133,7 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l const struct routine *r = &info->routines[r_idx]; double result_bps[2]; u64 result_cycle[2]; + int prefault = no_prefault ? 0 : 1; result_cycle[0] = result_cycle[1] = 0ULL; result_bps[0] = result_bps[1] = 0.0; @@ -149,8 +143,8 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s Bytes ...\n\n", length_str); - if (!only_prefault && !no_prefault) { - /* show both of results */ + if (!only_prefault && prefault) { + /* Show both results: */ if (use_cycle) { result_cycle[0] = info->do_cycle(r, len, false); result_cycle[1] = info->do_cycle(r, len, true); @@ -160,14 +154,14 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l } } else { if (use_cycle) - result_cycle[pf] = info->do_cycle(r, len, only_prefault); + result_cycle[prefault] = info->do_cycle(r, len, only_prefault); else - result_bps[pf] = info->do_gettimeofday(r, len, only_prefault); + result_bps[prefault] = info->do_gettimeofday(r, len, only_prefault); } switch (bench_format) { case BENCH_FORMAT_DEFAULT: - if (!only_prefault && !no_prefault) { + if (!only_prefault && prefault) { if (use_cycle) { printf(" %14lf Cycle/Byte\n", (double)result_cycle[0] @@ -184,16 +178,16 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l } else { if (use_cycle) { printf(" %14lf Cycle/Byte", - (double)result_cycle[pf] + (double)result_cycle[prefault] / totallen); } else - print_bps(result_bps[pf]); + print_bps(result_bps[prefault]); printf("%s\n", only_prefault ? " (with prefault)" : ""); } break; case BENCH_FORMAT_SIMPLE: - if (!only_prefault && !no_prefault) { + if (!only_prefault && prefault) { if (use_cycle) { printf("%lf %lf\n", (double)result_cycle[0] / totallen, @@ -204,14 +198,14 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l } } else { if (use_cycle) { - printf("%lf\n", (double)result_cycle[pf] + printf("%lf\n", (double)result_cycle[prefault] / totallen); } else - printf("%lf\n", result_bps[pf]); + printf("%lf\n", result_bps[prefault]); } break; default: - /* reaching this means there's some disaster: */ + /* Reaching this means there's some disaster: */ die("unknown format: %d\n", bench_format); break; } @@ -225,8 +219,7 @@ static int bench_mem_common(int argc, const char **argv, size_t len; double totallen; - argc = parse_options(argc, argv, options, - info->usage, 0); + argc = parse_options(argc, argv, options, info->usage, 0); if (no_prefault && only_prefault) { fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n"); @@ -244,7 +237,7 @@ static int bench_mem_common(int argc, const char **argv, return 1; } - /* same to without specifying either of prefault and no-prefault */ + /* Same as without specifying either of prefault and no-prefault: */ if (only_prefault && no_prefault) only_prefault = no_prefault = false; @@ -282,7 +275,8 @@ static void memcpy_alloc_mem(void **dst, void **src, size_t length) *src = zalloc(length); if (!*src) die("memory allocation failed - maybe length is too large?\n"); - /* Make sure to always replace the zero pages even if MMAP_THRESH is crossed */ + + /* Make sure to always prefault zero pages even if MMAP_THRESH is crossed: */ memset(*src, 0, length); } @@ -308,8 +302,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) return cycle_end - cycle_start; } -static double do_memcpy_gettimeofday(const struct routine *r, size_t len, - bool prefault) +static double do_memcpy_gettimeofday(const struct routine *r, size_t len, bool prefault) { struct timeval tv_start, tv_end, tv_diff; memcpy_t fn = r->fn.memcpy; @@ -337,10 +330,10 @@ int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) { struct bench_mem_info info = { - .routines = memcpy_routines, - .do_cycle = do_memcpy_cycle, - .do_gettimeofday = do_memcpy_gettimeofday, - .usage = bench_mem_memcpy_usage, + .routines = memcpy_routines, + .do_cycle = do_memcpy_cycle, + .do_gettimeofday = do_memcpy_gettimeofday, + .usage = bench_mem_memcpy_usage, }; return bench_mem_common(argc, argv, prefix, &info); @@ -404,30 +397,26 @@ static const char * const bench_mem_memset_usage[] = { }; static const struct routine memset_routines[] = { - { .name ="default", - .desc = "Default memset() provided by glibc", - .fn.memset = memset }, + { .name = "default", + .desc = "Default memset() provided by glibc", + .fn.memset = memset }, + #ifdef HAVE_ARCH_X86_64_SUPPORT - -#define MEMSET_FN(_fn, _name, _desc) { .name = _name, .desc = _desc, .fn.memset = _fn }, -#include "mem-memset-x86-64-asm-def.h" -#undef MEMSET_FN - +# define MEMSET_FN(_fn, _name, _desc) { .name = _name, .desc = _desc, .fn.memset = _fn }, +# include "mem-memset-x86-64-asm-def.h" +# undef MEMSET_FN #endif - { .name = NULL, - .desc = NULL, - .fn.memset = NULL } + { NULL, } }; -int bench_mem_memset(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unused) { struct bench_mem_info info = { - .routines = memset_routines, - .do_cycle = do_memset_cycle, - .do_gettimeofday = do_memset_gettimeofday, - .usage = bench_mem_memset_usage, + .routines = memset_routines, + .do_cycle = do_memset_cycle, + .do_gettimeofday = do_memset_gettimeofday, + .usage = bench_mem_memset_usage, }; return bench_mem_common(argc, argv, prefix, &info); From 276197415685e2a91ce367562800cf0f8fbe482c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:18 +0200 Subject: [PATCH 195/260] perf bench: Default to all routines in 'perf bench mem' So few people know that the --routine option to 'perf bench memcpy/memset' exists, and would not know that it's capable of testing the kernel's memcpy/memset implementations. Furthermore, 'perf bench mem all' will not run all routines: vega:~> perf bench mem all # Running mem/memcpy benchmark... Routine default (Default memcpy() provided by glibc) # Copying 1MB Bytes ... 894.454383 MB/Sec 3.844734 GB/Sec (with prefault) # Running mem/memset benchmark... Routine default (Default memset() provided by glibc) # Copying 1MB Bytes ... 1.220703 GB/Sec 9.042245 GB/Sec (with prefault) Because misleadingly the 'all' refers to 'all sub-benchmarks', not 'all sub-benchmarks and routines'. Fix all this by making the memcpy/memset routine to default to 'all', which results in all the benchmarks being run: triton:~> perf bench mem all # Running mem/memcpy benchmark... Routine default (Default memcpy() provided by glibc) # Copying 1MB Bytes ... 1.448906 GB/Sec 4.957170 GB/Sec (with prefault) Routine x86-64-unrolled (unrolled memcpy() in arch/x86/lib/memcpy_64.S) # Copying 1MB Bytes ... 1.614153 GB/Sec 4.379204 GB/Sec (with prefault) Routine x86-64-movsq (movsq-based memcpy() in arch/x86/lib/memcpy_64.S) # Copying 1MB Bytes ... 1.570036 GB/Sec 4.264465 GB/Sec (with prefault) Routine x86-64-movsb (movsb-based memcpy() in arch/x86/lib/memcpy_64.S) # Copying 1MB Bytes ... 1.788576 GB/Sec 6.554111 GB/Sec (with prefault) # Running mem/memset benchmark... Routine default (Default memset() provided by glibc) # Copying 1MB Bytes ... 2.082223 GB/Sec 9.126752 GB/Sec (with prefault) Routine x86-64-unrolled (unrolled memset() in arch/x86/lib/memset_64.S) # Copying 1MB Bytes ... 5.710892 GB/Sec 8.346688 GB/Sec (with prefault) Routine x86-64-stosq (movsq-based memset() in arch/x86/lib/memset_64.S) # Copying 1MB Bytes ... 9.765625 GB/Sec 12.520032 GB/Sec (with prefault) Routine x86-64-stosb (movsb-based memset() in arch/x86/lib/memset_64.S) # Copying 1MB Bytes ... 9.668936 GB/Sec 12.682630 GB/Sec (with prefault) Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-3-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-memcpy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 27606ff5c4f9..263f84171ae5 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c @@ -24,7 +24,7 @@ #define K 1024 static const char *length_str = "1MB"; -static const char *routine = "default"; +static const char *routine = "all"; static int iterations = 1; static bool use_cycle; static int cycle_fd; @@ -35,7 +35,7 @@ static const struct option options[] = { OPT_STRING('l', "length", &length_str, "1MB", "Specify length of memory to copy. " "Available units: B, KB, MB, GB and TB (upper and lower)"), - OPT_STRING('r', "routine", &routine, "default", + OPT_STRING('r', "routine", &routine, "all", "Specify routine to copy, \"all\" runs all available routines"), OPT_INTEGER('i', "iterations", &iterations, "repeat memcpy() invocation this number of times"), From 2946f59ac31d703738c00c684613d289e8d001ea Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:19 +0200 Subject: [PATCH 196/260] perf bench: Eliminate unused argument from bench_mem_common() Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-4-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-memcpy.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-memcpy.c index 263f84171ae5..7acb9b83382c 100644 --- a/tools/perf/bench/mem-memcpy.c +++ b/tools/perf/bench/mem-memcpy.c @@ -211,9 +211,7 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l } } -static int bench_mem_common(int argc, const char **argv, - const char *prefix __maybe_unused, - struct bench_mem_info *info) +static int bench_mem_common(int argc, const char **argv, struct bench_mem_info *info) { int i; size_t len; @@ -326,8 +324,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len, bool p return (double)(((double)len * iterations) / timeval2double(&tv_diff)); } -int bench_mem_memcpy(int argc, const char **argv, - const char *prefix __maybe_unused) +int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) { struct bench_mem_info info = { .routines = memcpy_routines, @@ -336,7 +333,7 @@ int bench_mem_memcpy(int argc, const char **argv, .usage = bench_mem_memcpy_usage, }; - return bench_mem_common(argc, argv, prefix, &info); + return bench_mem_common(argc, argv, &info); } static void memset_alloc_mem(void **dst, size_t length) @@ -419,5 +416,5 @@ int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unu .usage = bench_mem_memset_usage, }; - return bench_mem_common(argc, argv, prefix, &info); + return bench_mem_common(argc, argv, &info); } From 9b2fa7f3e7799a335fd839906ab4d45b7d595dc4 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:20 +0200 Subject: [PATCH 197/260] perf bench: Rename 'mem-memcpy.c' => 'mem-functions.c' So mem-memcpy.c started out as a simple memcpy() benchmark, then it grew memset() functionality and now I plan to add string copy benchmarks as well. This makes the file name a misnomer: rename it to the more generic mem-functions.c name. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-5-git-send-email-mingo@kernel.org [ The "rename" was introducing __unused, wasn't removing the old file, and didn't update tools/perf/bench/Build, fix it ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/Build | 2 +- tools/perf/bench/{mem-memcpy.c => mem-functions.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tools/perf/bench/{mem-memcpy.c => mem-functions.c} (100%) diff --git a/tools/perf/bench/Build b/tools/perf/bench/Build index 573e28896038..60bf11943047 100644 --- a/tools/perf/bench/Build +++ b/tools/perf/bench/Build @@ -1,6 +1,6 @@ perf-y += sched-messaging.o perf-y += sched-pipe.o -perf-y += mem-memcpy.o +perf-y += mem-functions.o perf-y += futex-hash.o perf-y += futex-wake.o perf-y += futex-wake-parallel.o diff --git a/tools/perf/bench/mem-memcpy.c b/tools/perf/bench/mem-functions.c similarity index 100% rename from tools/perf/bench/mem-memcpy.c rename to tools/perf/bench/mem-functions.c From 6db175c7333e22ee818373cbea067e3eaa0236f7 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:21 +0200 Subject: [PATCH 198/260] perf bench: Remove the prefaulting complication from 'perf bench mem mem*' So 'perf bench mem memcpy/memset' has elaborate code to measure memcpy()/memset() performance both with freshly allocated buffers (which includes initial page fault overhead) and with preallocated buffers. But the thing is, the resulting bandwidth results are mostly meaningless, because page faults dominate so much of the cost. It might make sense to measure cache cold vs. cache hot performance, but the code does not do this. So remove this complication, and always prefault the ranges before using them. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-6-git-send-email-mingo@kernel.org [ Remove --no-prefault, --only-prefault from docs, noticed by David Ahern ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 16 --- tools/perf/bench/mem-functions.c | 148 ++++++++---------------- 2 files changed, 51 insertions(+), 113 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index ab632d9fbd7d..9cb60abe03aa 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -157,14 +157,6 @@ Repeat memcpy invocation this number of times. --cycle:: Use perf's cpu-cycles event instead of gettimeofday syscall. --o:: ---only-prefault:: -Show only the result with page faults before memcpy. - --n:: ---no-prefault:: -Show only the result without page faults before memcpy. - *memset*:: Suite for evaluating performance of simple memory set in various ways. @@ -189,14 +181,6 @@ Repeat memset invocation this number of times. --cycle:: Use perf's cpu-cycles event instead of gettimeofday syscall. --o:: ---only-prefault:: -Show only the result with page faults before memset. - --n:: ---no-prefault:: -Show only the result without page faults before memset. - SUITES FOR 'numa' ~~~~~~~~~~~~~~~~~ *mem*:: diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 7acb9b83382c..9c18a4b976b6 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -28,8 +28,6 @@ static const char *routine = "all"; static int iterations = 1; static bool use_cycle; static int cycle_fd; -static bool only_prefault; -static bool no_prefault; static const struct option options[] = { OPT_STRING('l', "length", &length_str, "1MB", @@ -41,10 +39,6 @@ static const struct option options[] = { "repeat memcpy() invocation this number of times"), OPT_BOOLEAN('c', "cycle", &use_cycle, "Use cycles event instead of gettimeofday() for measuring"), - OPT_BOOLEAN('o', "only-prefault", &only_prefault, - "Show only the result with page faults before memcpy()"), - OPT_BOOLEAN('n', "no-prefault", &no_prefault, - "Show only the result without page faults before memcpy()"), OPT_END() }; @@ -110,103 +104,60 @@ static double timeval2double(struct timeval *ts) return (double)ts->tv_sec + (double)ts->tv_usec / (double)1000000; } -#define print_bps(x) do { \ - if (x < K) \ - printf(" %14lf B/Sec", x); \ - else if (x < K * K) \ - printf(" %14lfd KB/Sec", x / K); \ - else if (x < K * K * K) \ - printf(" %14lf MB/Sec", x / K / K); \ - else \ - printf(" %14lf GB/Sec", x / K / K / K); \ +#define print_bps(x) do { \ + if (x < K) \ + printf(" %14lf B/Sec\n", x); \ + else if (x < K * K) \ + printf(" %14lfd KB/Sec\n", x / K); \ + else if (x < K * K * K) \ + printf(" %14lf MB/Sec\n", x / K / K); \ + else \ + printf(" %14lf GB/Sec\n", x / K / K / K); \ } while (0) struct bench_mem_info { const struct routine *routines; - u64 (*do_cycle)(const struct routine *r, size_t len, bool prefault); - double (*do_gettimeofday)(const struct routine *r, size_t len, bool prefault); + u64 (*do_cycle)(const struct routine *r, size_t len); + double (*do_gettimeofday)(const struct routine *r, size_t len); const char *const *usage; }; static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t len, double totallen) { const struct routine *r = &info->routines[r_idx]; - double result_bps[2]; - u64 result_cycle[2]; - int prefault = no_prefault ? 0 : 1; - - result_cycle[0] = result_cycle[1] = 0ULL; - result_bps[0] = result_bps[1] = 0.0; + double result_bps = 0.0; + u64 result_cycle = 0; printf("Routine %s (%s)\n", r->name, r->desc); if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s Bytes ...\n\n", length_str); - if (!only_prefault && prefault) { - /* Show both results: */ - if (use_cycle) { - result_cycle[0] = info->do_cycle(r, len, false); - result_cycle[1] = info->do_cycle(r, len, true); - } else { - result_bps[0] = info->do_gettimeofday(r, len, false); - result_bps[1] = info->do_gettimeofday(r, len, true); - } + if (use_cycle) { + result_cycle = info->do_cycle(r, len); } else { - if (use_cycle) - result_cycle[prefault] = info->do_cycle(r, len, only_prefault); - else - result_bps[prefault] = info->do_gettimeofday(r, len, only_prefault); + result_bps = info->do_gettimeofday(r, len); } switch (bench_format) { case BENCH_FORMAT_DEFAULT: - if (!only_prefault && prefault) { - if (use_cycle) { - printf(" %14lf Cycle/Byte\n", - (double)result_cycle[0] - / totallen); - printf(" %14lf Cycle/Byte (with prefault)\n", - (double)result_cycle[1] - / totallen); - } else { - print_bps(result_bps[0]); - printf("\n"); - print_bps(result_bps[1]); - printf(" (with prefault)\n"); - } + if (use_cycle) { + printf(" %14lf Cycle/Byte\n", (double)result_cycle/totallen); } else { - if (use_cycle) { - printf(" %14lf Cycle/Byte", - (double)result_cycle[prefault] - / totallen); - } else - print_bps(result_bps[prefault]); + print_bps(result_bps); + } + break; - printf("%s\n", only_prefault ? " (with prefault)" : ""); - } - break; case BENCH_FORMAT_SIMPLE: - if (!only_prefault && prefault) { - if (use_cycle) { - printf("%lf %lf\n", - (double)result_cycle[0] / totallen, - (double)result_cycle[1] / totallen); - } else { - printf("%lf %lf\n", - result_bps[0], result_bps[1]); - } + if (use_cycle) { + printf("%lf\n", (double)result_cycle/totallen); } else { - if (use_cycle) { - printf("%lf\n", (double)result_cycle[prefault] - / totallen); - } else - printf("%lf\n", result_bps[prefault]); + printf("%lf\n", result_bps); } break; + default: - /* Reaching this means there's some disaster: */ - die("unknown format: %d\n", bench_format); + BUG_ON(1); break; } } @@ -219,11 +170,6 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * argc = parse_options(argc, argv, options, info->usage, 0); - if (no_prefault && only_prefault) { - fprintf(stderr, "Invalid options: -o and -n are mutually exclusive\n"); - return 1; - } - if (use_cycle) init_cycle(); @@ -235,10 +181,6 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * return 1; } - /* Same as without specifying either of prefault and no-prefault: */ - if (only_prefault && no_prefault) - only_prefault = no_prefault = false; - if (!strncmp(routine, "all", 3)) { for (i = 0; info->routines[i].name; i++) __bench_mem_routine(info, i, len, totallen); @@ -278,7 +220,7 @@ static void memcpy_alloc_mem(void **dst, void **src, size_t length) memset(*src, 0, length); } -static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) +static u64 do_memcpy_cycle(const struct routine *r, size_t len) { u64 cycle_start = 0ULL, cycle_end = 0ULL; void *src = NULL, *dst = NULL; @@ -287,8 +229,11 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) memcpy_alloc_mem(&dst, &src, len); - if (prefault) - fn(dst, src, len); + /* + * We prefault the freshly allocated memory range here, + * to not measure page fault overhead: + */ + fn(dst, src, len); cycle_start = get_cycle(); for (i = 0; i < iterations; ++i) @@ -300,7 +245,7 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len, bool prefault) return cycle_end - cycle_start; } -static double do_memcpy_gettimeofday(const struct routine *r, size_t len, bool prefault) +static double do_memcpy_gettimeofday(const struct routine *r, size_t len) { struct timeval tv_start, tv_end, tv_diff; memcpy_t fn = r->fn.memcpy; @@ -309,8 +254,11 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len, bool p memcpy_alloc_mem(&dst, &src, len); - if (prefault) - fn(dst, src, len); + /* + * We prefault the freshly allocated memory range here, + * to not measure page fault overhead: + */ + fn(dst, src, len); BUG_ON(gettimeofday(&tv_start, NULL)); for (i = 0; i < iterations; ++i) @@ -321,6 +269,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len, bool p free(src); free(dst); + return (double)(((double)len * iterations) / timeval2double(&tv_diff)); } @@ -343,7 +292,7 @@ static void memset_alloc_mem(void **dst, size_t length) die("memory allocation failed - maybe length is too large?\n"); } -static u64 do_memset_cycle(const struct routine *r, size_t len, bool prefault) +static u64 do_memset_cycle(const struct routine *r, size_t len) { u64 cycle_start = 0ULL, cycle_end = 0ULL; memset_t fn = r->fn.memset; @@ -352,8 +301,11 @@ static u64 do_memset_cycle(const struct routine *r, size_t len, bool prefault) memset_alloc_mem(&dst, len); - if (prefault) - fn(dst, -1, len); + /* + * We prefault the freshly allocated memory range here, + * to not measure page fault overhead: + */ + fn(dst, -1, len); cycle_start = get_cycle(); for (i = 0; i < iterations; ++i) @@ -364,8 +316,7 @@ static u64 do_memset_cycle(const struct routine *r, size_t len, bool prefault) return cycle_end - cycle_start; } -static double do_memset_gettimeofday(const struct routine *r, size_t len, - bool prefault) +static double do_memset_gettimeofday(const struct routine *r, size_t len) { struct timeval tv_start, tv_end, tv_diff; memset_t fn = r->fn.memset; @@ -374,8 +325,11 @@ static double do_memset_gettimeofday(const struct routine *r, size_t len, memset_alloc_mem(&dst, len); - if (prefault) - fn(dst, -1, len); + /* + * We prefault the freshly allocated memory range here, + * to not measure page fault overhead: + */ + fn(dst, -1, len); BUG_ON(gettimeofday(&tv_start, NULL)); for (i = 0; i < iterations; ++i) From 7a46a8fd13bd60584687f417cd35935965f29ae2 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:22 +0200 Subject: [PATCH 199/260] perf bench: List output formatting options on 'perf bench -h' So 'perf bench -h' is not very helpful when printing the help line about the output formatting options: -f, --format Specify format style There are two output format styles, 'default' and 'simple', so improve the help text to: -f, --format Specify the output formatting style Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-7-git-send-email-mingo@kernel.org [ Removed leftovers from the mem-functions.c rename ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-bench.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index f67934d46d40..1b585213ba5a 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -110,7 +110,7 @@ int bench_format = BENCH_FORMAT_DEFAULT; unsigned int bench_repeat = 10; /* default number of times to repeat the run */ static const struct option bench_options[] = { - OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"), + OPT_STRING('f', "format", &bench_format_str, "default|simple", "Specify the output formatting style"), OPT_UINTEGER('r', "repeat", &bench_repeat, "Specify amount of times to repeat the run"), OPT_END() }; From b14f2d357675bd7fb4e5a705ac7320a9638ecab5 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:23 +0200 Subject: [PATCH 200/260] perf bench mem: Change 'cycle' to 'cycles' So 'perf bench mem memset/memcpy' has a CPU cycles measurement method, but calls it 'cycle' (singular) throughout the code, which makes it harder to read. Rename all related functions, variables and options to a plural 'cycles' nomenclature. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-8-git-send-email-mingo@kernel.org [ s/--cycle/--cycles/g in perf-bench man page ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 4 +- tools/perf/bench/mem-functions.c | 56 ++++++++++++------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index 9cb60abe03aa..17135ef92d70 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -154,7 +154,7 @@ On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported. Repeat memcpy invocation this number of times. -c:: ---cycle:: +--cycles:: Use perf's cpu-cycles event instead of gettimeofday syscall. *memset*:: @@ -178,7 +178,7 @@ On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported. Repeat memset invocation this number of times. -c:: ---cycle:: +--cycles:: Use perf's cpu-cycles event instead of gettimeofday syscall. SUITES FOR 'numa' diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 9c18a4b976b6..6fe8667fbdf2 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -26,8 +26,8 @@ static const char *length_str = "1MB"; static const char *routine = "all"; static int iterations = 1; -static bool use_cycle; -static int cycle_fd; +static bool use_cycles; +static int cycles_fd; static const struct option options[] = { OPT_STRING('l', "length", &length_str, "1MB", @@ -37,8 +37,8 @@ static const struct option options[] = { "Specify routine to copy, \"all\" runs all available routines"), OPT_INTEGER('i', "iterations", &iterations, "repeat memcpy() invocation this number of times"), - OPT_BOOLEAN('c', "cycle", &use_cycle, - "Use cycles event instead of gettimeofday() for measuring"), + OPT_BOOLEAN('c', "cycles", &use_cycles, + "Use a cycles event instead of gettimeofday() to measure performance"), OPT_END() }; @@ -78,22 +78,22 @@ static struct perf_event_attr cycle_attr = { .config = PERF_COUNT_HW_CPU_CYCLES }; -static void init_cycle(void) +static void init_cycles(void) { - cycle_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); + cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); - if (cycle_fd < 0 && errno == ENOSYS) + if (cycles_fd < 0 && errno == ENOSYS) die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); else - BUG_ON(cycle_fd < 0); + BUG_ON(cycles_fd < 0); } -static u64 get_cycle(void) +static u64 get_cycles(void) { int ret; u64 clk; - ret = read(cycle_fd, &clk, sizeof(u64)); + ret = read(cycles_fd, &clk, sizeof(u64)); BUG_ON(ret != sizeof(u64)); return clk; @@ -117,7 +117,7 @@ static double timeval2double(struct timeval *ts) struct bench_mem_info { const struct routine *routines; - u64 (*do_cycle)(const struct routine *r, size_t len); + u64 (*do_cycles)(const struct routine *r, size_t len); double (*do_gettimeofday)(const struct routine *r, size_t len); const char *const *usage; }; @@ -126,31 +126,31 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l { const struct routine *r = &info->routines[r_idx]; double result_bps = 0.0; - u64 result_cycle = 0; + u64 result_cycles = 0; printf("Routine %s (%s)\n", r->name, r->desc); if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s Bytes ...\n\n", length_str); - if (use_cycle) { - result_cycle = info->do_cycle(r, len); + if (use_cycles) { + result_cycles = info->do_cycles(r, len); } else { result_bps = info->do_gettimeofday(r, len); } switch (bench_format) { case BENCH_FORMAT_DEFAULT: - if (use_cycle) { - printf(" %14lf Cycle/Byte\n", (double)result_cycle/totallen); + if (use_cycles) { + printf(" %14lf cycles/Byte\n", (double)result_cycles/totallen); } else { print_bps(result_bps); } break; case BENCH_FORMAT_SIMPLE: - if (use_cycle) { - printf("%lf\n", (double)result_cycle/totallen); + if (use_cycles) { + printf("%lf\n", (double)result_cycles/totallen); } else { printf("%lf\n", result_bps); } @@ -170,8 +170,8 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * argc = parse_options(argc, argv, options, info->usage, 0); - if (use_cycle) - init_cycle(); + if (use_cycles) + init_cycles(); len = (size_t)perf_atoll((char *)length_str); totallen = (double)len * iterations; @@ -220,7 +220,7 @@ static void memcpy_alloc_mem(void **dst, void **src, size_t length) memset(*src, 0, length); } -static u64 do_memcpy_cycle(const struct routine *r, size_t len) +static u64 do_memcpy_cycles(const struct routine *r, size_t len) { u64 cycle_start = 0ULL, cycle_end = 0ULL; void *src = NULL, *dst = NULL; @@ -235,10 +235,10 @@ static u64 do_memcpy_cycle(const struct routine *r, size_t len) */ fn(dst, src, len); - cycle_start = get_cycle(); + cycle_start = get_cycles(); for (i = 0; i < iterations; ++i) fn(dst, src, len); - cycle_end = get_cycle(); + cycle_end = get_cycles(); free(src); free(dst); @@ -277,7 +277,7 @@ int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unu { struct bench_mem_info info = { .routines = memcpy_routines, - .do_cycle = do_memcpy_cycle, + .do_cycles = do_memcpy_cycles, .do_gettimeofday = do_memcpy_gettimeofday, .usage = bench_mem_memcpy_usage, }; @@ -292,7 +292,7 @@ static void memset_alloc_mem(void **dst, size_t length) die("memory allocation failed - maybe length is too large?\n"); } -static u64 do_memset_cycle(const struct routine *r, size_t len) +static u64 do_memset_cycles(const struct routine *r, size_t len) { u64 cycle_start = 0ULL, cycle_end = 0ULL; memset_t fn = r->fn.memset; @@ -307,10 +307,10 @@ static u64 do_memset_cycle(const struct routine *r, size_t len) */ fn(dst, -1, len); - cycle_start = get_cycle(); + cycle_start = get_cycles(); for (i = 0; i < iterations; ++i) fn(dst, i, len); - cycle_end = get_cycle(); + cycle_end = get_cycles(); free(dst); return cycle_end - cycle_start; @@ -365,7 +365,7 @@ int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unu { struct bench_mem_info info = { .routines = memset_routines, - .do_cycle = do_memset_cycle, + .do_cycles = do_memset_cycles, .do_gettimeofday = do_memset_gettimeofday, .usage = bench_mem_memset_usage, }; From e815e327604af880bdcf38cdd711dfa78627ab2a Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:24 +0200 Subject: [PATCH 201/260] perf bench mem: Rename 'routine' to 'routine_str' So bench/mem-functions.c has a 'routine' name for the routines parameter string, but a 'length_str' name for the length parameter string. We also have another entity named 'routine': 'struct routine'. This is inconsistent and confusing: rename 'routine' to 'routine_str'. Also fix typos in the --routine help text. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-9-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 6fe8667fbdf2..a76e57f3ab66 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -24,7 +24,7 @@ #define K 1024 static const char *length_str = "1MB"; -static const char *routine = "all"; +static const char *routine_str = "all"; static int iterations = 1; static bool use_cycles; static int cycles_fd; @@ -33,8 +33,8 @@ static const struct option options[] = { OPT_STRING('l', "length", &length_str, "1MB", "Specify length of memory to copy. " "Available units: B, KB, MB, GB and TB (upper and lower)"), - OPT_STRING('r', "routine", &routine, "all", - "Specify routine to copy, \"all\" runs all available routines"), + OPT_STRING('r', "routine", &routine_str, "all", + "Specify the routine to run, \"all\" runs all available routines"), OPT_INTEGER('i', "iterations", &iterations, "repeat memcpy() invocation this number of times"), OPT_BOOLEAN('c', "cycles", &use_cycles, @@ -181,18 +181,18 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * return 1; } - if (!strncmp(routine, "all", 3)) { + if (!strncmp(routine_str, "all", 3)) { for (i = 0; info->routines[i].name; i++) __bench_mem_routine(info, i, len, totallen); return 0; } for (i = 0; info->routines[i].name; i++) { - if (!strcmp(info->routines[i].name, routine)) + if (!strcmp(info->routines[i].name, routine_str)) break; } if (!info->routines[i].name) { - printf("Unknown routine:%s\n", routine); + printf("Unknown routine: %s\n", routine_str); printf("Available routines...\n"); for (i = 0; info->routines[i].name; i++) { printf("\t%s ... %s\n", From a69b4f741340a52d0976636a45c9976a883f03a0 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:25 +0200 Subject: [PATCH 202/260] perf bench mem: Fix 'length' vs. 'size' naming confusion So 'perf bench mem memcpy/memset' consistently uses 'len' and 'length' for buffer sizes - while it's really a memory buffer size. (strings have length.) Rename all affected variables. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-10-git-send-email-mingo@kernel.org [ Update perf-bench man page ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 8 +-- tools/perf/bench/mem-functions.c | 92 ++++++++++++------------- 2 files changed, 50 insertions(+), 50 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index 17135ef92d70..bbd27d89b50a 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -139,8 +139,8 @@ Suite for evaluating performance of simple memory copy in various ways. Options of *memcpy* ^^^^^^^^^^^^^^^^^^^ -l:: ---length:: -Specify length of memory to copy (default: 1MB). +--size:: +Specify size of memory to copy (default: 1MB). Available units are B, KB, MB, GB and TB (case insensitive). -r:: @@ -163,8 +163,8 @@ Suite for evaluating performance of simple memory set in various ways. Options of *memset* ^^^^^^^^^^^^^^^^^^^ -l:: ---length:: -Specify length of memory to set (default: 1MB). +--size:: +Specify size of memory to set (default: 1MB). Available units are B, KB, MB, GB and TB (case insensitive). -r:: diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index a76e57f3ab66..1605249d2912 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -23,15 +23,15 @@ #define K 1024 -static const char *length_str = "1MB"; +static const char *size_str = "1MB"; static const char *routine_str = "all"; static int iterations = 1; static bool use_cycles; static int cycles_fd; static const struct option options[] = { - OPT_STRING('l', "length", &length_str, "1MB", - "Specify length of memory to copy. " + OPT_STRING('l', "size", &size_str, "1MB", + "Specify the size of the memory buffers. " "Available units: B, KB, MB, GB and TB (upper and lower)"), OPT_STRING('r', "routine", &routine_str, "all", "Specify the routine to run, \"all\" runs all available routines"), @@ -117,12 +117,12 @@ static double timeval2double(struct timeval *ts) struct bench_mem_info { const struct routine *routines; - u64 (*do_cycles)(const struct routine *r, size_t len); - double (*do_gettimeofday)(const struct routine *r, size_t len); + u64 (*do_cycles)(const struct routine *r, size_t size); + double (*do_gettimeofday)(const struct routine *r, size_t size); const char *const *usage; }; -static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t len, double totallen) +static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t size, double size_total) { const struct routine *r = &info->routines[r_idx]; double result_bps = 0.0; @@ -131,18 +131,18 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l printf("Routine %s (%s)\n", r->name, r->desc); if (bench_format == BENCH_FORMAT_DEFAULT) - printf("# Copying %s Bytes ...\n\n", length_str); + printf("# Copying %s Bytes ...\n\n", size_str); if (use_cycles) { - result_cycles = info->do_cycles(r, len); + result_cycles = info->do_cycles(r, size); } else { - result_bps = info->do_gettimeofday(r, len); + result_bps = info->do_gettimeofday(r, size); } switch (bench_format) { case BENCH_FORMAT_DEFAULT: if (use_cycles) { - printf(" %14lf cycles/Byte\n", (double)result_cycles/totallen); + printf(" %14lf cycles/Byte\n", (double)result_cycles/size_total); } else { print_bps(result_bps); } @@ -150,7 +150,7 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l case BENCH_FORMAT_SIMPLE: if (use_cycles) { - printf("%lf\n", (double)result_cycles/totallen); + printf("%lf\n", (double)result_cycles/size_total); } else { printf("%lf\n", result_bps); } @@ -165,25 +165,25 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t l static int bench_mem_common(int argc, const char **argv, struct bench_mem_info *info) { int i; - size_t len; - double totallen; + size_t size; + double size_total; argc = parse_options(argc, argv, options, info->usage, 0); if (use_cycles) init_cycles(); - len = (size_t)perf_atoll((char *)length_str); - totallen = (double)len * iterations; + size = (size_t)perf_atoll((char *)size_str); + size_total = (double)size * iterations; - if ((s64)len <= 0) { - fprintf(stderr, "Invalid length:%s\n", length_str); + if ((s64)size <= 0) { + fprintf(stderr, "Invalid size:%s\n", size_str); return 1; } if (!strncmp(routine_str, "all", 3)) { for (i = 0; info->routines[i].name; i++) - __bench_mem_routine(info, i, len, totallen); + __bench_mem_routine(info, i, size, size_total); return 0; } @@ -201,43 +201,43 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * return 1; } - __bench_mem_routine(info, i, len, totallen); + __bench_mem_routine(info, i, size, size_total); return 0; } -static void memcpy_alloc_mem(void **dst, void **src, size_t length) +static void memcpy_alloc_mem(void **dst, void **src, size_t size) { - *dst = zalloc(length); + *dst = zalloc(size); if (!*dst) - die("memory allocation failed - maybe length is too large?\n"); + die("memory allocation failed - maybe size is too large?\n"); - *src = zalloc(length); + *src = zalloc(size); if (!*src) - die("memory allocation failed - maybe length is too large?\n"); + die("memory allocation failed - maybe size is too large?\n"); /* Make sure to always prefault zero pages even if MMAP_THRESH is crossed: */ - memset(*src, 0, length); + memset(*src, 0, size); } -static u64 do_memcpy_cycles(const struct routine *r, size_t len) +static u64 do_memcpy_cycles(const struct routine *r, size_t size) { u64 cycle_start = 0ULL, cycle_end = 0ULL; void *src = NULL, *dst = NULL; memcpy_t fn = r->fn.memcpy; int i; - memcpy_alloc_mem(&dst, &src, len); + memcpy_alloc_mem(&dst, &src, size); /* * We prefault the freshly allocated memory range here, * to not measure page fault overhead: */ - fn(dst, src, len); + fn(dst, src, size); cycle_start = get_cycles(); for (i = 0; i < iterations; ++i) - fn(dst, src, len); + fn(dst, src, size); cycle_end = get_cycles(); free(src); @@ -245,24 +245,24 @@ static u64 do_memcpy_cycles(const struct routine *r, size_t len) return cycle_end - cycle_start; } -static double do_memcpy_gettimeofday(const struct routine *r, size_t len) +static double do_memcpy_gettimeofday(const struct routine *r, size_t size) { struct timeval tv_start, tv_end, tv_diff; memcpy_t fn = r->fn.memcpy; void *src = NULL, *dst = NULL; int i; - memcpy_alloc_mem(&dst, &src, len); + memcpy_alloc_mem(&dst, &src, size); /* * We prefault the freshly allocated memory range here, * to not measure page fault overhead: */ - fn(dst, src, len); + fn(dst, src, size); BUG_ON(gettimeofday(&tv_start, NULL)); for (i = 0; i < iterations; ++i) - fn(dst, src, len); + fn(dst, src, size); BUG_ON(gettimeofday(&tv_end, NULL)); timersub(&tv_end, &tv_start, &tv_diff); @@ -270,7 +270,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t len) free(src); free(dst); - return (double)(((double)len * iterations) / timeval2double(&tv_diff)); + return (double)(((double)size * iterations) / timeval2double(&tv_diff)); } int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) @@ -285,61 +285,61 @@ int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unu return bench_mem_common(argc, argv, &info); } -static void memset_alloc_mem(void **dst, size_t length) +static void memset_alloc_mem(void **dst, size_t size) { - *dst = zalloc(length); + *dst = zalloc(size); if (!*dst) - die("memory allocation failed - maybe length is too large?\n"); + die("memory allocation failed - maybe size is too large?\n"); } -static u64 do_memset_cycles(const struct routine *r, size_t len) +static u64 do_memset_cycles(const struct routine *r, size_t size) { u64 cycle_start = 0ULL, cycle_end = 0ULL; memset_t fn = r->fn.memset; void *dst = NULL; int i; - memset_alloc_mem(&dst, len); + memset_alloc_mem(&dst, size); /* * We prefault the freshly allocated memory range here, * to not measure page fault overhead: */ - fn(dst, -1, len); + fn(dst, -1, size); cycle_start = get_cycles(); for (i = 0; i < iterations; ++i) - fn(dst, i, len); + fn(dst, i, size); cycle_end = get_cycles(); free(dst); return cycle_end - cycle_start; } -static double do_memset_gettimeofday(const struct routine *r, size_t len) +static double do_memset_gettimeofday(const struct routine *r, size_t size) { struct timeval tv_start, tv_end, tv_diff; memset_t fn = r->fn.memset; void *dst = NULL; int i; - memset_alloc_mem(&dst, len); + memset_alloc_mem(&dst, size); /* * We prefault the freshly allocated memory range here, * to not measure page fault overhead: */ - fn(dst, -1, len); + fn(dst, -1, size); BUG_ON(gettimeofday(&tv_start, NULL)); for (i = 0; i < iterations; ++i) - fn(dst, i, len); + fn(dst, i, size); BUG_ON(gettimeofday(&tv_end, NULL)); timersub(&tv_end, &tv_start, &tv_diff); free(dst); - return (double)(((double)len * iterations) / timeval2double(&tv_diff)); + return (double)(((double)size * iterations) / timeval2double(&tv_diff)); } static const char * const bench_mem_memset_usage[] = { From 13b1fdce8d46027f346c0533a4323b58e2b5bad8 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:26 +0200 Subject: [PATCH 203/260] perf bench mem: Improve user visible strings - fix various typos in user visible output strings - make the output consistent (wrt. capitalization and spelling) - offer the list of routines to benchmark on '-r help'. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-11-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 29 +++++++++++++++++------------ tools/perf/builtin-bench.c | 6 +++--- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 1605249d2912..318da3421e69 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -32,13 +32,17 @@ static int cycles_fd; static const struct option options[] = { OPT_STRING('l', "size", &size_str, "1MB", "Specify the size of the memory buffers. " - "Available units: B, KB, MB, GB and TB (upper and lower)"), + "Available units: B, KB, MB, GB and TB (case insensitive)"), + OPT_STRING('r', "routine", &routine_str, "all", - "Specify the routine to run, \"all\" runs all available routines"), + "Specify the routine to run, \"all\" runs all available routines, \"help\" lists them"), + OPT_INTEGER('i', "iterations", &iterations, - "repeat memcpy() invocation this number of times"), + "Repeat the function this number of times"), + OPT_BOOLEAN('c', "cycles", &use_cycles, "Use a cycles event instead of gettimeofday() to measure performance"), + OPT_END() }; @@ -106,13 +110,13 @@ static double timeval2double(struct timeval *ts) #define print_bps(x) do { \ if (x < K) \ - printf(" %14lf B/Sec\n", x); \ + printf(" %14lf bytes/sec\n", x); \ else if (x < K * K) \ - printf(" %14lfd KB/Sec\n", x / K); \ + printf(" %14lfd KB/sec\n", x / K); \ else if (x < K * K * K) \ - printf(" %14lf MB/Sec\n", x / K / K); \ + printf(" %14lf MB/sec\n", x / K / K); \ else \ - printf(" %14lf GB/Sec\n", x / K / K / K); \ + printf(" %14lf GB/sec\n", x / K / K / K); \ } while (0) struct bench_mem_info { @@ -128,10 +132,10 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t s double result_bps = 0.0; u64 result_cycles = 0; - printf("Routine %s (%s)\n", r->name, r->desc); + printf("# Routine '%s' (%s)\n", r->name, r->desc); if (bench_format == BENCH_FORMAT_DEFAULT) - printf("# Copying %s Bytes ...\n\n", size_str); + printf("# Copying %s bytes ...\n\n", size_str); if (use_cycles) { result_cycles = info->do_cycles(r, size); @@ -142,7 +146,7 @@ static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t s switch (bench_format) { case BENCH_FORMAT_DEFAULT: if (use_cycles) { - printf(" %14lf cycles/Byte\n", (double)result_cycles/size_total); + printf(" %14lf cycles/byte\n", (double)result_cycles/size_total); } else { print_bps(result_bps); } @@ -192,8 +196,9 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * break; } if (!info->routines[i].name) { - printf("Unknown routine: %s\n", routine_str); - printf("Available routines...\n"); + if (strcmp(routine_str, "help") && strcmp(routine_str, "h")) + printf("Unknown routine: %s\n", routine_str); + printf("Available routines:\n"); for (i = 0; info->routines[i].name; i++) { printf("\t%s ... %s\n", info->routines[i].name, info->routines[i].desc); diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index 1b585213ba5a..a8fc948c8ace 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -49,9 +49,9 @@ static struct bench sched_benchmarks[] = { }; static struct bench mem_benchmarks[] = { - { "memcpy", "Benchmark for memcpy()", bench_mem_memcpy }, - { "memset", "Benchmark for memset() tests", bench_mem_memset }, - { "all", "Test all memory benchmarks", NULL }, + { "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy }, + { "memset", "Benchmark for memset() functions", bench_mem_memset }, + { "all", "Test all memory access benchmarks", NULL }, { NULL, NULL, NULL } }; From 5dd93304a5d386c73c0a59117752acdca67f857d Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:27 +0200 Subject: [PATCH 204/260] perf bench mem: Reorganize the code a bit Reorder functions a bit, so that we synchronize the layout of the memcpy() and memset() portions of the code. This improves the code, especially after we'll add an strlcpy() variant as well. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-12-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 318da3421e69..8d980d4a64e5 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -58,25 +58,6 @@ struct routine { } fn; }; -struct routine memcpy_routines[] = { - { .name = "default", - .desc = "Default memcpy() provided by glibc", - .fn.memcpy = memcpy }, - -#ifdef HAVE_ARCH_X86_64_SUPPORT -# define MEMCPY_FN(_fn, _name, _desc) {.name = _name, .desc = _desc, .fn.memcpy = _fn}, -# include "mem-memcpy-x86-64-asm-def.h" -# undef MEMCPY_FN -#endif - - { NULL, } -}; - -static const char * const bench_mem_memcpy_usage[] = { - "perf bench mem memcpy ", - NULL -}; - static struct perf_event_attr cycle_attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES @@ -278,6 +259,25 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t size) return (double)(((double)size * iterations) / timeval2double(&tv_diff)); } +struct routine memcpy_routines[] = { + { .name = "default", + .desc = "Default memcpy() provided by glibc", + .fn.memcpy = memcpy }, + +#ifdef HAVE_ARCH_X86_64_SUPPORT +# define MEMCPY_FN(_fn, _name, _desc) {.name = _name, .desc = _desc, .fn.memcpy = _fn}, +# include "mem-memcpy-x86-64-asm-def.h" +# undef MEMCPY_FN +#endif + + { NULL, } +}; + +static const char * const bench_mem_memcpy_usage[] = { + "perf bench mem memcpy ", + NULL +}; + int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) { struct bench_mem_info info = { From b0d22e52e3d2c2b151dfaa0f6e01bafa5475344f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:28 +0200 Subject: [PATCH 205/260] perf bench: Harmonize all the -l/--nr_loops options We have three benchmarking subsystems that specify some sort of 'number of loops' parameter - but all of them do it inconsistently: numa: -l/--nr_loops sched messaging: -l/--loops mem memset/memcpy: -i/--iterations Harmonize them to -l/--nr_loops by picking the numa variant - which is also the most likely one to have existing scripting which we don't want to break. Plus improve the parameter help texts to indicate the default value for the nr_loops variable to keep users from guessing ... Also propagate the naming to internal variables. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-13-git-send-email-mingo@kernel.org [ Let the harmonisation reach the perf-bench man page as well ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 10 +++++----- tools/perf/bench/mem-functions.c | 22 +++++++++++----------- tools/perf/bench/numa.c | 4 ++-- tools/perf/bench/sched-messaging.c | 10 +++++----- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index bbd27d89b50a..ddfb3e10e88c 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -82,7 +82,7 @@ Be multi thread instead of multi process Specify number of groups -l:: ---loop=:: +--nr_loops=:: Specify number of loops Example of *messaging* @@ -149,8 +149,8 @@ Specify routine to copy (default: default). Available routines are depend on the architecture. On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported. --i:: ---iterations:: +-l:: +--nr_loops:: Repeat memcpy invocation this number of times. -c:: @@ -173,8 +173,8 @@ Specify routine to set (default: default). Available routines are depend on the architecture. On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported. --i:: ---iterations:: +-l:: +--nr_loops:: Repeat memset invocation this number of times. -c:: diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index 8d980d4a64e5..c5dfabdbd8d0 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -25,20 +25,20 @@ static const char *size_str = "1MB"; static const char *routine_str = "all"; -static int iterations = 1; +static int nr_loops = 1; static bool use_cycles; static int cycles_fd; static const struct option options[] = { - OPT_STRING('l', "size", &size_str, "1MB", + OPT_STRING('s', "size", &size_str, "1MB", "Specify the size of the memory buffers. " "Available units: B, KB, MB, GB and TB (case insensitive)"), OPT_STRING('r', "routine", &routine_str, "all", "Specify the routine to run, \"all\" runs all available routines, \"help\" lists them"), - OPT_INTEGER('i', "iterations", &iterations, - "Repeat the function this number of times"), + OPT_INTEGER('l', "nr_loops", &nr_loops, + "Specify the number of loops to run. (default: 1)"), OPT_BOOLEAN('c', "cycles", &use_cycles, "Use a cycles event instead of gettimeofday() to measure performance"), @@ -159,7 +159,7 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * init_cycles(); size = (size_t)perf_atoll((char *)size_str); - size_total = (double)size * iterations; + size_total = (double)size * nr_loops; if ((s64)size <= 0) { fprintf(stderr, "Invalid size:%s\n", size_str); @@ -222,7 +222,7 @@ static u64 do_memcpy_cycles(const struct routine *r, size_t size) fn(dst, src, size); cycle_start = get_cycles(); - for (i = 0; i < iterations; ++i) + for (i = 0; i < nr_loops; ++i) fn(dst, src, size); cycle_end = get_cycles(); @@ -247,7 +247,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t size) fn(dst, src, size); BUG_ON(gettimeofday(&tv_start, NULL)); - for (i = 0; i < iterations; ++i) + for (i = 0; i < nr_loops; ++i) fn(dst, src, size); BUG_ON(gettimeofday(&tv_end, NULL)); @@ -256,7 +256,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t size) free(src); free(dst); - return (double)(((double)size * iterations) / timeval2double(&tv_diff)); + return (double)(((double)size * nr_loops) / timeval2double(&tv_diff)); } struct routine memcpy_routines[] = { @@ -313,7 +313,7 @@ static u64 do_memset_cycles(const struct routine *r, size_t size) fn(dst, -1, size); cycle_start = get_cycles(); - for (i = 0; i < iterations; ++i) + for (i = 0; i < nr_loops; ++i) fn(dst, i, size); cycle_end = get_cycles(); @@ -337,14 +337,14 @@ static double do_memset_gettimeofday(const struct routine *r, size_t size) fn(dst, -1, size); BUG_ON(gettimeofday(&tv_start, NULL)); - for (i = 0; i < iterations; ++i) + for (i = 0; i < nr_loops; ++i) fn(dst, i, size); BUG_ON(gettimeofday(&tv_end, NULL)); timersub(&tv_end, &tv_start, &tv_diff); free(dst); - return (double)(((double)size * iterations) / timeval2double(&tv_diff)); + return (double)(((double)size * nr_loops) / timeval2double(&tv_diff)); } static const char * const bench_mem_memset_usage[] = { diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 870b7e665a20..492df2752a2d 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -164,8 +164,8 @@ static const struct option options[] = { OPT_STRING('L', "mb_proc_locked", &p0.mb_proc_locked_str,"MB", "process serialized/locked memory access (MBs), <= process_memory"), OPT_STRING('T', "mb_thread" , &p0.mb_thread_str, "MB", "thread memory (MBs)"), - OPT_UINTEGER('l', "nr_loops" , &p0.nr_loops, "max number of loops to run"), - OPT_UINTEGER('s', "nr_secs" , &p0.nr_secs, "max number of seconds to run"), + OPT_UINTEGER('l', "nr_loops" , &p0.nr_loops, "max number of loops to run (default: unlimited)"), + OPT_UINTEGER('s', "nr_secs" , &p0.nr_secs, "max number of seconds to run (default: 5 secs)"), OPT_UINTEGER('u', "usleep" , &p0.sleep_usecs, "usecs to sleep per loop iteration"), OPT_BOOLEAN('R', "data_reads" , &p0.data_reads, "access the data via writes (can be mixed with -W)"), diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c index d7f281c2828d..d4ff1b539cfd 100644 --- a/tools/perf/bench/sched-messaging.c +++ b/tools/perf/bench/sched-messaging.c @@ -33,7 +33,7 @@ #define DATASIZE 100 static bool use_pipes = false; -static unsigned int loops = 100; +static unsigned int nr_loops = 100; static bool thread_mode = false; static unsigned int num_groups = 10; @@ -79,7 +79,7 @@ static void ready(int ready_out, int wakefd) err(EXIT_FAILURE, "poll"); } -/* Sender sprays loops messages down each file descriptor */ +/* Sender sprays nr_loops messages down each file descriptor */ static void *sender(struct sender_context *ctx) { char data[DATASIZE]; @@ -88,7 +88,7 @@ static void *sender(struct sender_context *ctx) ready(ctx->ready_out, ctx->wakefd); /* Now pump to every receiver. */ - for (i = 0; i < loops; i++) { + for (i = 0; i < nr_loops; i++) { for (j = 0; j < ctx->num_fds; j++) { int ret, done = 0; @@ -213,7 +213,7 @@ static unsigned int group(pthread_t *pth, /* Create the pipe between client and server */ fdpair(fds); - ctx->num_packets = num_fds * loops; + ctx->num_packets = num_fds * nr_loops; ctx->in_fds[0] = fds[0]; ctx->in_fds[1] = fds[1]; ctx->ready_out = ready_out; @@ -250,7 +250,7 @@ static const struct option options[] = { OPT_BOOLEAN('t', "thread", &thread_mode, "Be multi thread instead of multi process"), OPT_UINTEGER('g', "group", &num_groups, "Specify number of groups"), - OPT_UINTEGER('l', "loop", &loops, "Specify number of loops"), + OPT_UINTEGER('l', "nr_loops", &nr_loops, "Specify the number of loops to run (default: 100)"), OPT_END() }; From 2f211c84ad40469c15226e899b720624fbd28e20 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:29 +0200 Subject: [PATCH 206/260] perf bench mem: Rename 'routine' to 'function' So right now there's a somewhat inconsistent mess of the benchmarking code and options sometimes calling benchmarked functions 'functions', sometimes calling them 'routines'. Name them 'functions' consistently. Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-14-git-send-email-mingo@kernel.org [ Updated perf-bench man page, pointed out by David Ahern ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-bench.txt | 16 +++---- tools/perf/bench/mem-functions.c | 60 ++++++++++++------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/tools/perf/Documentation/perf-bench.txt b/tools/perf/Documentation/perf-bench.txt index ddfb3e10e88c..34750fc32714 100644 --- a/tools/perf/Documentation/perf-bench.txt +++ b/tools/perf/Documentation/perf-bench.txt @@ -143,10 +143,10 @@ Options of *memcpy* Specify size of memory to copy (default: 1MB). Available units are B, KB, MB, GB and TB (case insensitive). --r:: ---routine:: -Specify routine to copy (default: default). -Available routines are depend on the architecture. +-f:: +--function:: +Specify function to copy (default: default). +Available functions are depend on the architecture. On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported. -l:: @@ -167,10 +167,10 @@ Options of *memset* Specify size of memory to set (default: 1MB). Available units are B, KB, MB, GB and TB (case insensitive). --r:: ---routine:: -Specify routine to set (default: default). -Available routines are depend on the architecture. +-f:: +--function:: +Specify function to set (default: default). +Available functions are depend on the architecture. On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported. -l:: diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index c5dfabdbd8d0..d1de9c4a7ddf 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -24,7 +24,7 @@ #define K 1024 static const char *size_str = "1MB"; -static const char *routine_str = "all"; +static const char *function_str = "all"; static int nr_loops = 1; static bool use_cycles; static int cycles_fd; @@ -34,8 +34,8 @@ static const struct option options[] = { "Specify the size of the memory buffers. " "Available units: B, KB, MB, GB and TB (case insensitive)"), - OPT_STRING('r', "routine", &routine_str, "all", - "Specify the routine to run, \"all\" runs all available routines, \"help\" lists them"), + OPT_STRING('f', "function", &function_str, "all", + "Specify the function to run, \"all\" runs all available functions, \"help\" lists them"), OPT_INTEGER('l', "nr_loops", &nr_loops, "Specify the number of loops to run. (default: 1)"), @@ -49,7 +49,7 @@ static const struct option options[] = { typedef void *(*memcpy_t)(void *, const void *, size_t); typedef void *(*memset_t)(void *, int, size_t); -struct routine { +struct function { const char *name; const char *desc; union { @@ -101,19 +101,19 @@ static double timeval2double(struct timeval *ts) } while (0) struct bench_mem_info { - const struct routine *routines; - u64 (*do_cycles)(const struct routine *r, size_t size); - double (*do_gettimeofday)(const struct routine *r, size_t size); + const struct function *functions; + u64 (*do_cycles)(const struct function *r, size_t size); + double (*do_gettimeofday)(const struct function *r, size_t size); const char *const *usage; }; -static void __bench_mem_routine(struct bench_mem_info *info, int r_idx, size_t size, double size_total) +static void __bench_mem_function(struct bench_mem_info *info, int r_idx, size_t size, double size_total) { - const struct routine *r = &info->routines[r_idx]; + const struct function *r = &info->functions[r_idx]; double result_bps = 0.0; u64 result_cycles = 0; - printf("# Routine '%s' (%s)\n", r->name, r->desc); + printf("# function '%s' (%s)\n", r->name, r->desc); if (bench_format == BENCH_FORMAT_DEFAULT) printf("# Copying %s bytes ...\n\n", size_str); @@ -166,28 +166,28 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * return 1; } - if (!strncmp(routine_str, "all", 3)) { - for (i = 0; info->routines[i].name; i++) - __bench_mem_routine(info, i, size, size_total); + if (!strncmp(function_str, "all", 3)) { + for (i = 0; info->functions[i].name; i++) + __bench_mem_function(info, i, size, size_total); return 0; } - for (i = 0; info->routines[i].name; i++) { - if (!strcmp(info->routines[i].name, routine_str)) + for (i = 0; info->functions[i].name; i++) { + if (!strcmp(info->functions[i].name, function_str)) break; } - if (!info->routines[i].name) { - if (strcmp(routine_str, "help") && strcmp(routine_str, "h")) - printf("Unknown routine: %s\n", routine_str); - printf("Available routines:\n"); - for (i = 0; info->routines[i].name; i++) { + if (!info->functions[i].name) { + if (strcmp(function_str, "help") && strcmp(function_str, "h")) + printf("Unknown function: %s\n", function_str); + printf("Available functions:\n"); + for (i = 0; info->functions[i].name; i++) { printf("\t%s ... %s\n", - info->routines[i].name, info->routines[i].desc); + info->functions[i].name, info->functions[i].desc); } return 1; } - __bench_mem_routine(info, i, size, size_total); + __bench_mem_function(info, i, size, size_total); return 0; } @@ -206,7 +206,7 @@ static void memcpy_alloc_mem(void **dst, void **src, size_t size) memset(*src, 0, size); } -static u64 do_memcpy_cycles(const struct routine *r, size_t size) +static u64 do_memcpy_cycles(const struct function *r, size_t size) { u64 cycle_start = 0ULL, cycle_end = 0ULL; void *src = NULL, *dst = NULL; @@ -231,7 +231,7 @@ static u64 do_memcpy_cycles(const struct routine *r, size_t size) return cycle_end - cycle_start; } -static double do_memcpy_gettimeofday(const struct routine *r, size_t size) +static double do_memcpy_gettimeofday(const struct function *r, size_t size) { struct timeval tv_start, tv_end, tv_diff; memcpy_t fn = r->fn.memcpy; @@ -259,7 +259,7 @@ static double do_memcpy_gettimeofday(const struct routine *r, size_t size) return (double)(((double)size * nr_loops) / timeval2double(&tv_diff)); } -struct routine memcpy_routines[] = { +struct function memcpy_functions[] = { { .name = "default", .desc = "Default memcpy() provided by glibc", .fn.memcpy = memcpy }, @@ -281,7 +281,7 @@ static const char * const bench_mem_memcpy_usage[] = { int bench_mem_memcpy(int argc, const char **argv, const char *prefix __maybe_unused) { struct bench_mem_info info = { - .routines = memcpy_routines, + .functions = memcpy_functions, .do_cycles = do_memcpy_cycles, .do_gettimeofday = do_memcpy_gettimeofday, .usage = bench_mem_memcpy_usage, @@ -297,7 +297,7 @@ static void memset_alloc_mem(void **dst, size_t size) die("memory allocation failed - maybe size is too large?\n"); } -static u64 do_memset_cycles(const struct routine *r, size_t size) +static u64 do_memset_cycles(const struct function *r, size_t size) { u64 cycle_start = 0ULL, cycle_end = 0ULL; memset_t fn = r->fn.memset; @@ -321,7 +321,7 @@ static u64 do_memset_cycles(const struct routine *r, size_t size) return cycle_end - cycle_start; } -static double do_memset_gettimeofday(const struct routine *r, size_t size) +static double do_memset_gettimeofday(const struct function *r, size_t size) { struct timeval tv_start, tv_end, tv_diff; memset_t fn = r->fn.memset; @@ -352,7 +352,7 @@ static const char * const bench_mem_memset_usage[] = { NULL }; -static const struct routine memset_routines[] = { +static const struct function memset_functions[] = { { .name = "default", .desc = "Default memset() provided by glibc", .fn.memset = memset }, @@ -369,7 +369,7 @@ static const struct routine memset_routines[] = { int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unused) { struct bench_mem_info info = { - .routines = memset_routines, + .functions = memset_functions, .do_cycles = do_memset_cycles, .do_gettimeofday = do_memset_gettimeofday, .usage = bench_mem_memset_usage, From aa254af25c40d6d1cdc3f354db29eaf3e85a5ede Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 19 Oct 2015 10:04:30 +0200 Subject: [PATCH 207/260] perf bench: Run benchmarks, don't test them So right now we output this text: memcpy: Benchmark for memcpy() functions memset: Benchmark for memset() functions all: Test all memory access benchmarks But the right verb to use with benchmarks is to 'run' them, not 'test' them. So change this (and all similar texts) to: memcpy: Benchmark for memcpy() functions memset: Benchmark for memset() functions all: Run all memory access benchmarks Signed-off-by: Ingo Molnar Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1445241870-24854-15-git-send-email-mingo@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-bench.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c index a8fc948c8ace..b17aed36ca16 100644 --- a/tools/perf/builtin-bench.c +++ b/tools/perf/builtin-bench.c @@ -36,7 +36,7 @@ struct bench { #ifdef HAVE_LIBNUMA_SUPPORT static struct bench numa_benchmarks[] = { { "mem", "Benchmark for NUMA workloads", bench_numa }, - { "all", "Test all NUMA benchmarks", NULL }, + { "all", "Run all NUMA benchmarks", NULL }, { NULL, NULL, NULL } }; #endif @@ -44,14 +44,14 @@ static struct bench numa_benchmarks[] = { static struct bench sched_benchmarks[] = { { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging }, { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe }, - { "all", "Test all scheduler benchmarks", NULL }, + { "all", "Run all scheduler benchmarks", NULL }, { NULL, NULL, NULL } }; static struct bench mem_benchmarks[] = { { "memcpy", "Benchmark for memcpy() functions", bench_mem_memcpy }, { "memset", "Benchmark for memset() functions", bench_mem_memset }, - { "all", "Test all memory access benchmarks", NULL }, + { "all", "Run all memory access benchmarks", NULL }, { NULL, NULL, NULL } }; @@ -62,7 +62,7 @@ static struct bench futex_benchmarks[] = { { "requeue", "Benchmark for futex requeue calls", bench_futex_requeue }, /* pi-futexes */ { "lock-pi", "Benchmark for futex lock_pi calls", bench_futex_lock_pi }, - { "all", "Test all futex benchmarks", NULL }, + { "all", "Run all futex benchmarks", NULL }, { NULL, NULL, NULL } }; From 3a134ae96ca0af06804d343019b85026486e6fe1 Mon Sep 17 00:00:00 2001 From: Yunlong Song Date: Thu, 15 Oct 2015 15:39:51 +0800 Subject: [PATCH 208/260] perf help: Change 'usage' to 'Usage' for consistency Capitalize 'usage' to make it consistent with all the other 'Usage' in the codes, e.g., usage_builtin. Signed-off-by: Yunlong Song Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Ramkumar Ramachandra Cc: Sriram Raghunathan Cc: Wang Nan Link: http://lkml.kernel.org/r/1444894792-2338-3-git-send-email-yunlong.song@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-help.c | 2 +- tools/perf/util/parse-options.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index 36486eade1ef..a7d588bf3cdd 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c @@ -463,7 +463,7 @@ int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused) builtin_help_subcommands, builtin_help_usage, 0); if (show_all) { - printf("\n usage: %s\n\n", perf_usage_string); + printf("\n Usage: %s\n\n", perf_usage_string); list_commands("perf commands", &main_cmds, &other_cmds); printf(" %s\n\n", perf_more_info_string); return 0; diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 9a38b05f0273..8aa7922397a9 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -648,7 +648,7 @@ int usage_with_options_internal(const char * const *usagestr, if (!usagestr) return PARSE_OPT_HELP; - fprintf(stderr, "\n usage: %s\n", *usagestr++); + fprintf(stderr, "\n Usage: %s\n", *usagestr++); while (*usagestr && **usagestr) fprintf(stderr, " or: %s\n", *usagestr++); while (*usagestr) { @@ -684,7 +684,7 @@ int parse_options_usage(const char * const *usagestr, if (!usagestr) goto opt; - fprintf(stderr, "\n usage: %s\n", *usagestr++); + fprintf(stderr, "\n Usage: %s\n", *usagestr++); while (*usagestr && **usagestr) fprintf(stderr, " or: %s\n", *usagestr++); while (*usagestr) { From 581cc8a2a2a00afc864840720186b0f6a38079d9 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:03 +0200 Subject: [PATCH 209/260] perf stat: Rename perf_stat struct into perf_stat_evsel It's used as the perf_evsel::priv data, so the name suits better. Also we'll need the perf_stat name free for more generic struct. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-29-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 4 ++-- tools/perf/util/stat.c | 10 +++++----- tools/perf/util/stat.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5ef88f760b12..184057295970 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -434,7 +434,7 @@ static void print_noise_pct(double total, double avg) static void print_noise(struct perf_evsel *evsel, double avg) { - struct perf_stat *ps; + struct perf_stat_evsel *ps; if (run_count == 1) return; @@ -671,7 +671,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix) static void print_counter_aggr(struct perf_evsel *counter, char *prefix) { FILE *output = stat_config.output; - struct perf_stat *ps = counter->priv; + struct perf_stat_evsel *ps = counter->priv; double avg = avg_stats(&ps->res_stats[0]); int scaled = counter->counts->scaled; double uval; diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 2d065d065b67..93e6d697e574 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -67,7 +67,7 @@ double rel_stddev_stats(double stddev, double avg) bool __perf_evsel_stat__is(struct perf_evsel *evsel, enum perf_stat_evsel_id id) { - struct perf_stat *ps = evsel->priv; + struct perf_stat_evsel *ps = evsel->priv; return ps->id == id; } @@ -84,7 +84,7 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { void perf_stat_evsel_id_init(struct perf_evsel *evsel) { - struct perf_stat *ps = evsel->priv; + struct perf_stat_evsel *ps = evsel->priv; int i; /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */ @@ -100,7 +100,7 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) { int i; - struct perf_stat *ps = evsel->priv; + struct perf_stat_evsel *ps = evsel->priv; for (i = 0; i < 3; i++) init_stats(&ps->res_stats[i]); @@ -110,7 +110,7 @@ void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) { - evsel->priv = zalloc(sizeof(struct perf_stat)); + evsel->priv = zalloc(sizeof(struct perf_stat_evsel)); if (evsel->priv == NULL) return -ENOMEM; perf_evsel__reset_stat_priv(evsel); @@ -304,7 +304,7 @@ int perf_stat_process_counter(struct perf_stat_config *config, struct perf_evsel *counter) { struct perf_counts_values *aggr = &counter->counts->aggr; - struct perf_stat *ps = counter->priv; + struct perf_stat_evsel *ps = counter->priv; u64 *count = counter->counts->aggr.values; int i, ret; diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 62448c8175d3..f8d9d5ce24a9 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -20,7 +20,7 @@ enum perf_stat_evsel_id { PERF_STAT_EVSEL_ID__MAX, }; -struct perf_stat { +struct perf_stat_evsel { struct stats res_stats[3]; enum perf_stat_evsel_id id; }; From 208df99ed07ca5e86ee41617e0384930fc9ca819 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:04 +0200 Subject: [PATCH 210/260] perf stat: Add AGGR_UNSET mode Adding AGGR_UNSET mode, so we could distinguish unset aggr_mode in following patches. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-30-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 5 +++++ tools/perf/util/stat.c | 1 + tools/perf/util/stat.h | 1 + 3 files changed, 7 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 184057295970..abeb15aebd12 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -479,6 +479,7 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr) csv_sep); break; case AGGR_GLOBAL: + case AGGR_UNSET: default: break; } @@ -799,6 +800,8 @@ static void print_interval(char *prefix, struct timespec *ts) case AGGR_GLOBAL: default: fprintf(output, "# time counts %*s events\n", unit_width, "unit"); + case AGGR_UNSET: + break; } } @@ -880,6 +883,7 @@ static void print_counters(struct timespec *ts, int argc, const char **argv) evlist__for_each(evsel_list, counter) print_counter(counter, prefix); break; + case AGGR_UNSET: default: break; } @@ -960,6 +964,7 @@ static int perf_stat_init_aggr_mode(void) case AGGR_NONE: case AGGR_GLOBAL: case AGGR_THREAD: + case AGGR_UNSET: default: break; } diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 93e6d697e574..837374181ec7 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -272,6 +272,7 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel aggr->ena += count->ena; aggr->run += count->run; } + case AGGR_UNSET: default: break; } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index f8d9d5ce24a9..da1d11c4f8c1 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -31,6 +31,7 @@ enum aggr_mode { AGGR_SOCKET, AGGR_CORE, AGGR_THREAD, + AGGR_UNSET, }; struct perf_stat_config { From f1cbb8f35719e36803f226d1bbf08ac12cedcd76 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:14 +0200 Subject: [PATCH 211/260] perf cpu_map: Make cpu_map__build_map global We'll need to call it from perf stat in the stat_script patchkit Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-40-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 4 ++-- tools/perf/util/cpumap.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index c51c29fd0732..70ec8d031f9d 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -258,8 +258,8 @@ static int cmp_ids(const void *a, const void *b) return *(int *)a - *(int *)b; } -static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu)) +int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, + int (*f)(struct cpu_map *map, int cpu)) { struct cpu_map *c; int nr = cpus->nr; diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 8982d538da83..6e36fc35eca6 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -87,4 +87,6 @@ static inline int cpu__get_node(int cpu) return cpunode_map[cpu]; } +int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, + int (*f)(struct cpu_map *map, int cpu)); #endif /* __PERF_CPUMAP_H */ From 1fe7a30028eeccd92e6fccfbeb8c5c3811b11b64 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:15 +0200 Subject: [PATCH 212/260] perf cpu_map: Add data arg to cpu_map__build_map callback Adding data arg to cpu_map__build_map callback, so we could pass data along to the callback. It'll be needed in following patches to retrieve topology info from perf.data. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-41-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 14 ++++++++++++-- tools/perf/tests/topology.c | 4 ++-- tools/perf/util/cpumap.c | 15 ++++++++------- tools/perf/util/cpumap.h | 7 ++++--- tools/perf/util/stat.c | 2 +- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index abeb15aebd12..91e793a76929 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -944,6 +944,16 @@ static int stat__set_big_num(const struct option *opt __maybe_unused, return 0; } +static int perf_stat__get_socket(struct cpu_map *map, int cpu) +{ + return cpu_map__get_socket(map, cpu, NULL); +} + +static int perf_stat__get_core(struct cpu_map *map, int cpu) +{ + return cpu_map__get_core(map, cpu, NULL); +} + static int perf_stat_init_aggr_mode(void) { switch (stat_config.aggr_mode) { @@ -952,14 +962,14 @@ static int perf_stat_init_aggr_mode(void) perror("cannot build socket map"); return -1; } - aggr_get_id = cpu_map__get_socket; + aggr_get_id = perf_stat__get_socket; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = cpu_map__get_core; + aggr_get_id = perf_stat__get_core; break; case AGGR_NONE: case AGGR_GLOBAL: diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index c3aff53a976a..f5bb096c3bd9 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -73,10 +73,10 @@ static int check_cpu_topology(char *path, struct cpu_map *map) for (i = 0; i < map->nr; i++) { TEST_ASSERT_VAL("Core ID doesn't match", - (session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i) & 0xffff))); + (session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i, NULL) & 0xffff))); TEST_ASSERT_VAL("Socket ID doesn't match", - (session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i))); + (session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i, NULL))); } perf_session__delete(session); diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 70ec8d031f9d..b36845347f01 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -241,7 +241,7 @@ int cpu_map__get_socket_id(int cpu) return ret ?: value; } -int cpu_map__get_socket(struct cpu_map *map, int idx) +int cpu_map__get_socket(struct cpu_map *map, int idx, void *data __maybe_unused) { int cpu; @@ -259,7 +259,8 @@ static int cmp_ids(const void *a, const void *b) } int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu)) + int (*f)(struct cpu_map *map, int cpu, void *data), + void *data) { struct cpu_map *c; int nr = cpus->nr; @@ -271,7 +272,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, return -1; for (cpu = 0; cpu < nr; cpu++) { - s1 = f(cpus, cpu); + s1 = f(cpus, cpu, data); for (s2 = 0; s2 < c->nr; s2++) { if (s1 == c->map[s2]) break; @@ -295,7 +296,7 @@ int cpu_map__get_core_id(int cpu) return ret ?: value; } -int cpu_map__get_core(struct cpu_map *map, int idx) +int cpu_map__get_core(struct cpu_map *map, int idx, void *data) { int cpu, s; @@ -306,7 +307,7 @@ int cpu_map__get_core(struct cpu_map *map, int idx) cpu = cpu_map__get_core_id(cpu); - s = cpu_map__get_socket(map, idx); + s = cpu_map__get_socket(map, idx, data); if (s == -1) return -1; @@ -321,12 +322,12 @@ int cpu_map__get_core(struct cpu_map *map, int idx) int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) { - return cpu_map__build_map(cpus, sockp, cpu_map__get_socket); + return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL); } int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) { - return cpu_map__build_map(cpus, corep, cpu_map__get_core); + return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL); } /* setup simple routines to easily access node numbers given a cpu number */ diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 6e36fc35eca6..f1bcd2cfa164 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -19,9 +19,9 @@ struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu); -int cpu_map__get_socket(struct cpu_map *map, int idx); +int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); int cpu_map__get_core_id(int cpu); -int cpu_map__get_core(struct cpu_map *map, int idx); +int cpu_map__get_core(struct cpu_map *map, int idx, void *data); int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); @@ -88,5 +88,6 @@ static inline int cpu__get_node(int cpu) } int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu)); + int (*f)(struct cpu_map *map, int cpu, void *data), + void *data); #endif /* __PERF_CPUMAP_H */ diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 837374181ec7..2d9d8306dbd3 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -230,7 +230,7 @@ static int check_per_pkg(struct perf_evsel *counter, if (!(vals->run && vals->ena)) return 0; - s = cpu_map__get_socket(cpus, cpu); + s = cpu_map__get_socket(cpus, cpu, NULL); if (s < 0) return -1; From d2b5a315ae84d235f00761468885c466f81d7805 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 16 Oct 2015 12:41:25 +0200 Subject: [PATCH 213/260] perf script: Check output fields only for samples There's no need to check sampling output fields for events without perf_event_attr::sample_type field set. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1444992092-17897-51-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 8ce1c6bbfa45..2653c0273b89 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -686,7 +686,10 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, set_print_ip_opts(&evsel->attr); - return perf_evsel__check_attr(evsel, scr->session); + if (evsel->attr.sample_type) + err = perf_evsel__check_attr(evsel, scr->session); + + return err; } static int process_comm_event(struct perf_tool *tool, From a4c6a3e8bbb675a601f529881c51ff226f83c3f1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 19 Oct 2015 18:17:25 -0300 Subject: [PATCH 214/260] perf bench: Use named initializers in the trailer too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid this splat with gcc 4.4.7: cc1: warnings being treated as errors bench/mem-functions.c:273: error: missing initializer bench/mem-functions.c:273: error: (near initialization for ‘memcpy_functions[4].desc’) bench/mem-functions.c:366: error: missing initializer bench/mem-functions.c:366: error: (near initialization for ‘memset_functions[4].desc’) Cc: David Ahern Cc: Hitoshi Mitake Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/n/tip-0s8o6tgw1pdwvdv02llb9tkd@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/mem-functions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index d1de9c4a7ddf..9419b944220f 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c @@ -270,7 +270,7 @@ struct function memcpy_functions[] = { # undef MEMCPY_FN #endif - { NULL, } + { .name = NULL, } }; static const char * const bench_mem_memcpy_usage[] = { @@ -363,7 +363,7 @@ static const struct function memset_functions[] = { # undef MEMSET_FN #endif - { NULL, } + { .name = NULL, } }; int bench_mem_memset(int argc, const char **argv, const char *prefix __maybe_unused) From b9511cd761faafca7a1acc059e792c1399f9d7c6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Fri, 16 Oct 2015 16:24:05 +0300 Subject: [PATCH 215/260] perf/x86: Fix time_shift in perf_event_mmap_page Commit: b20112edeadf ("perf/x86: Improve accuracy of perf/sched clock") allowed the time_shift value in perf_event_mmap_page to be as much as 32. Unfortunately the documented algorithms for using time_shift have it shifting an integer, whereas to work correctly with the value 32, the type must be u64. In the case of perf tools, Intel PT decodes correctly but the timestamps that are output (for example by perf script) have lost 32-bits of granularity so they look like they are not changing at all. Fix by limiting the shift to 31 and adjusting the multiplier accordingly. Also update the documentation of perf_event_mmap_page so that new code based on it will be more future-proof. Signed-off-by: Adrian Hunter Signed-off-by: Peter Zijlstra (Intel) Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: b20112edeadf ("perf/x86: Improve accuracy of perf/sched clock") Link: http://lkml.kernel.org/r/1445001845-13688-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/tsc.c | 11 +++++++++++ include/uapi/linux/perf_event.h | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 69b84a26ea17..c7c4d9c51e99 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -259,6 +259,17 @@ static void set_cyc2ns_scale(unsigned long cpu_khz, int cpu) clocks_calc_mult_shift(&data->cyc2ns_mul, &data->cyc2ns_shift, cpu_khz, NSEC_PER_MSEC, 0); + /* + * cyc2ns_shift is exported via arch_perf_update_userpage() where it is + * not expected to be greater than 31 due to the original published + * conversion algorithm shifting a 32-bit value (now specifies a 64-bit + * value) - refer perf_event_mmap_page documentation in perf_event.h. + */ + if (data->cyc2ns_shift == 32) { + data->cyc2ns_shift = 31; + data->cyc2ns_mul >>= 1; + } + data->cyc2ns_offset = ns_now - mul_u64_u32_shr(tsc_now, data->cyc2ns_mul, data->cyc2ns_shift); diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 2881145cda86..6c72e72e975c 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -476,7 +476,7 @@ struct perf_event_mmap_page { * u64 delta; * * quot = (cyc >> time_shift); - * rem = cyc & ((1 << time_shift) - 1); + * rem = cyc & (((u64)1 << time_shift) - 1); * delta = time_offset + quot * time_mult + * ((rem * time_mult) >> time_shift); * @@ -507,7 +507,7 @@ struct perf_event_mmap_page { * And vice versa: * * quot = cyc >> time_shift; - * rem = cyc & ((1 << time_shift) - 1); + * rem = cyc & (((u64)1 << time_shift) - 1); * timestamp = time_zero + quot * time_mult + * ((rem * time_mult) >> time_shift); */ From c229bf9dc179d2023e185c0f705bdf68484c1e73 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 13 Oct 2015 09:09:08 +0200 Subject: [PATCH 216/260] perf: Add PERF_SAMPLE_BRANCH_CALL Add a new branch sample type to cover only call branches (function calls). The current ANY_CALL included direct, indirect calls and far jumps. We want to be able to differentiate indirect from direct calls. Therefore we introduce PERF_SAMPLE_BRANCH_CALL. The implementation is up to each architecture. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: khandual@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1444720151-10275-2-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- include/uapi/linux/perf_event.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 6c72e72e975c..651221334f49 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -168,6 +168,7 @@ enum perf_branch_sample_type_shift { PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, /* call/ret stack */ PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, /* indirect jumps */ + PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, /* direct call */ PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ }; @@ -188,6 +189,7 @@ enum perf_branch_sample_type { PERF_SAMPLE_BRANCH_CALL_STACK = 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT, PERF_SAMPLE_BRANCH_IND_JUMP = 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT, + PERF_SAMPLE_BRANCH_CALL = 1U << PERF_SAMPLE_BRANCH_CALL_SHIFT, PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, }; From d892819faa6860d469aae71d70c336b391c25505 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 13 Oct 2015 09:09:09 +0200 Subject: [PATCH 217/260] perf/x86: Add support for PERF_SAMPLE_BRANCH_CALL This patch enables the suport for the PERF_SAMPLE_BRANCH_CALL for Intel x86 processors. When the processor support LBR filtering this the selection is done in hardware. Otherwise, the filter is applied by software. Note that we chose to include zero length calls because they also represent calls. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: khandual@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1444720151-10275-3-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/perf_event_intel_lbr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c index ad0b8b0490a0..bfd0b717e944 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c +++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c @@ -555,6 +555,8 @@ static int intel_pmu_setup_sw_lbr_filter(struct perf_event *event) if (br_type & PERF_SAMPLE_BRANCH_IND_JUMP) mask |= X86_BR_IND_JMP; + if (br_type & PERF_SAMPLE_BRANCH_CALL) + mask |= X86_BR_CALL | X86_BR_ZERO_CALL; /* * stash actual user request into reg, it may * be used by fixup code for some CPU @@ -890,6 +892,7 @@ static const int snb_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_IND_CALL_SHIFT] = LBR_IND_CALL, [PERF_SAMPLE_BRANCH_COND_SHIFT] = LBR_JCC, [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, + [PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_REL_CALL, }; static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { @@ -905,6 +908,7 @@ static const int hsw_lbr_sel_map[PERF_SAMPLE_BRANCH_MAX_SHIFT] = { [PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT] = LBR_REL_CALL | LBR_IND_CALL | LBR_RETURN | LBR_CALL_STACK, [PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT] = LBR_IND_JMP, + [PERF_SAMPLE_BRANCH_CALL_SHIFT] = LBR_REL_CALL, }; /* core */ From 24f1a79a5fc10858e05ee0bf651ec99abfc0319b Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 13 Oct 2015 09:09:10 +0200 Subject: [PATCH 218/260] perf/powerpc: Add support for PERF_SAMPLE_BRANCH_CALL The patch catches PERF_SAMPLE_BRANCH_CALL because it is not clear whether this is actually supported by the hardware. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: khandual@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1444720151-10275-4-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- arch/powerpc/perf/power8-pmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/perf/power8-pmu.c b/arch/powerpc/perf/power8-pmu.c index 396351db601b..7d5e295255b7 100644 --- a/arch/powerpc/perf/power8-pmu.c +++ b/arch/powerpc/perf/power8-pmu.c @@ -676,6 +676,9 @@ static u64 power8_bhrb_filter_map(u64 branch_sample_type) if (branch_sample_type & PERF_SAMPLE_BRANCH_IND_CALL) return -1; + if (branch_sample_type & PERF_SAMPLE_BRANCH_CALL) + return -1; + if (branch_sample_type & PERF_SAMPLE_BRANCH_ANY_CALL) { pmu_bhrb_filter |= POWER8_MMCRA_IFM1; return pmu_bhrb_filter; From 43e41adc9e8c36545888d78fed2ef8d102a938dc Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 13 Oct 2015 09:09:11 +0200 Subject: [PATCH 219/260] perf record: Add ability to sample call branches This patch add a new branch type sampling filter to perf record. It is named 'call' and maps to PERF_SAMPLE_BRANCH_CALL. It samples direct call branches only, unlike 'any_call' which includes indirect calls as well. $ perf record -j call -e cycles ..... The man page is updated accordingly. Signed-off-by: Stephane Eranian Signed-off-by: Peter Zijlstra (Intel) Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Cc: khandual@linux.vnet.ibm.com Link: http://lkml.kernel.org/r/1444720151-10275-5-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- tools/perf/Documentation/perf-record.txt | 1 + tools/perf/util/parse-branch-options.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 2e9ce77b5e14..b027d28658f2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -236,6 +236,7 @@ following filters are defined: - any_call: any function call or system call - any_ret: any function return or system call return - ind_call: any indirect branch + - call: direct calls, including far (to/from kernel) calls - u: only when the branch target is at the user level - k: only when the branch target is in the kernel - hv: only when the target is at the hypervisor level diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c index a3b1e13a05c0..355eecf6bf59 100644 --- a/tools/perf/util/parse-branch-options.c +++ b/tools/perf/util/parse-branch-options.c @@ -27,6 +27,7 @@ static const struct branch_mode branch_modes[] = { BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX), BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND), BRANCH_OPT("ind_jmp", PERF_SAMPLE_BRANCH_IND_JUMP), + BRANCH_OPT("call", PERF_SAMPLE_BRANCH_CALL), BRANCH_END }; From e1d040cfcf76c1c1b5d71fc08ab577a0cf72fefd Mon Sep 17 00:00:00 2001 From: Yunlong Song Date: Thu, 15 Oct 2015 16:51:56 +0800 Subject: [PATCH 220/260] perf build: Add fixdep to .gitignore Commit 7c422f5572667fef0db38d2046ecce69dcf0afc8 ("tools build: Build fixdep helper from perf and basic libs") dynamically creates fixdep during the perf building. Add it to .gitignore. Signed-off-by: Yunlong Song Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: David Ahern Cc: Jiri Olsa Cc: Kan Liang Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Wang Nan Fixes: 7c422f557266 ("tools build: Build fixdep helper from perf and basic libs") Link: http://lkml.kernel.org/r/1444899116-8220-1-git-send-email-yunlong.song@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 tools/build/.gitignore diff --git a/tools/build/.gitignore b/tools/build/.gitignore new file mode 100644 index 000000000000..a776371a3502 --- /dev/null +++ b/tools/build/.gitignore @@ -0,0 +1 @@ +fixdep From 2f465deef7ce8c722121b782dd91c284f5ae80ca Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 1 Oct 2015 12:28:11 +0200 Subject: [PATCH 221/260] tools lib traceevent: update KVM plugin The format of the role word has changed through the years and the plugin was never updated; some VMX exit reasons were missing too. Signed-off-by: Paolo Bonzini Acked-by: Steven Rostedt Cc: David Ahern Cc: Namhyung Kim Cc: kvm@vger.kernel.org Link: http://lkml.kernel.org/r/1443695293-31127-1-git-send-email-pbonzini@redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/plugin_kvm.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/lib/traceevent/plugin_kvm.c b/tools/lib/traceevent/plugin_kvm.c index 88fe83dff7cd..18536f756577 100644 --- a/tools/lib/traceevent/plugin_kvm.c +++ b/tools/lib/traceevent/plugin_kvm.c @@ -124,7 +124,10 @@ static const char *disassemble(unsigned char *insn, int len, uint64_t rip, _ER(WBINVD, 54) \ _ER(XSETBV, 55) \ _ER(APIC_WRITE, 56) \ - _ER(INVPCID, 58) + _ER(INVPCID, 58) \ + _ER(PML_FULL, 62) \ + _ER(XSAVES, 63) \ + _ER(XRSTORS, 64) #define SVM_EXIT_REASONS \ _ER(EXIT_READ_CR0, 0x000) \ @@ -352,15 +355,18 @@ static int kvm_nested_vmexit_handler(struct trace_seq *s, struct pevent_record * union kvm_mmu_page_role { unsigned word; struct { - unsigned glevels:4; unsigned level:4; + unsigned cr4_pae:1; unsigned quadrant:2; - unsigned pad_for_nice_hex_output:6; unsigned direct:1; unsigned access:3; unsigned invalid:1; - unsigned cr4_pge:1; unsigned nxe:1; + unsigned cr0_wp:1; + unsigned smep_and_not_wp:1; + unsigned smap_and_not_wp:1; + unsigned pad_for_nice_hex_output:8; + unsigned smm:8; }; }; @@ -385,15 +391,18 @@ static int kvm_mmu_print_role(struct trace_seq *s, struct pevent_record *record, if (pevent_is_file_bigendian(event->pevent) == pevent_is_host_bigendian(event->pevent)) { - trace_seq_printf(s, "%u/%u q%u%s %s%s %spge %snxe", + trace_seq_printf(s, "%u q%u%s %s%s %spae %snxe %swp%s%s%s", role.level, - role.glevels, role.quadrant, role.direct ? " direct" : "", access_str[role.access], role.invalid ? " invalid" : "", - role.cr4_pge ? "" : "!", - role.nxe ? "" : "!"); + role.cr4_pae ? "" : "!", + role.nxe ? "" : "!", + role.cr0_wp ? "" : "!", + role.smep_and_not_wp ? " smep" : "", + role.smap_and_not_wp ? " smap" : "", + role.smm ? " smm" : ""); } else trace_seq_printf(s, "WORD: %08x", role.word); From bc1d03687b9be3a30aab8e8d78c7884449b6e511 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 9 Oct 2015 06:59:23 -0400 Subject: [PATCH 222/260] perf cpu_map: Fix core dump caused by per-socket/core system-wide stat Perf will core dump if --per-socket/core -a are applied for perf stat. The root cause is that cpu_map__build_map set refcnt of evlist's cpu_map to 1. It should set refcnt for the newly created cpu_map, not evlist's cpu_map. Here is the example: # perf stat -e cycles --per-socket -a sleep 1 Performance counter stats for 'system wide': S0 36 30,196,257 cycles S1 28 15,823,536 cycles 1.001126828 seconds time elapsed *** Error in `./perf': corrupted double-linked list: 0x00000000021f9090 *** ======= Backtrace: ========= /lib64/libc.so.6[0x3002e7bbe7] /lib64/libc.so.6[0x3002e7d2b5] ./perf(perf_evsel__delete+0x28)[0x485bdd] ./perf[0x4800e8] ./perf(perf_evlist__delete+0x5e)[0x482cd5] ./perf(cmd_stat+0xf25)[0x432328] ./perf[0x4768e0] ./perf[0x476ad6] ./perf[0x476b41] ./perf(main+0x1d0)[0x476db2] /lib64/libc.so.6(__libc_start_main+0xf5)[0x3002e21b45] ./perf[0x4202c5] Signed-off-by: Kan Liang Acked-by: Jiri Olsa Cc: Andi Kleen Link: http://lkml.kernel.org/r/1444388363-35936-1-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index b36845347f01..aa6b490aa471 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -285,7 +285,7 @@ int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, /* ensure we process id in increasing order */ qsort(c->map, c->nr, sizeof(int), cmp_ids); - atomic_set(&cpus->refcnt, 1); + atomic_set(&c->refcnt, 1); *res = c; return 0; } From 8b8cde49586566471d65af9a59e25d3edb941387 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 20 Oct 2015 11:46:36 -0700 Subject: [PATCH 223/260] perf evsel: Print branch filter state with -vv Add a missing field to the perf_event_attr debug output. Signed-off-by: Andi Kleen Acked-by: Peter Zijlstra (Intel) Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1445366797-30894-4-git-send-email-andi@firstfloor.org [ Print it between config2 and sample_regs_user (peterz)] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8be867ccefe9..ab05fa52a5cd 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1262,6 +1262,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, PRINT_ATTRf(bp_type, p_unsigned); PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); + PRINT_ATTRf(branch_sample_type, p_unsigned); PRINT_ATTRf(sample_regs_user, p_hex); PRINT_ATTRf(sample_stack_user, p_unsigned); PRINT_ATTRf(clockid, p_signed); From e3d006ce8180a0c025ce66bdc89bbc125f85be57 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 21 Oct 2015 15:45:13 -0300 Subject: [PATCH 224/260] perf annotate: Add debug message for out of bounds sample Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-q0lde9ajs84oi38nlyjcqbwg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d1eece70b84d..0fc8d7a2fea5 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -548,8 +548,11 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (addr < sym->start || addr >= sym->end) + if (addr < sym->start || addr >= sym->end) { + pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n", + __func__, __LINE__, sym->name, sym->start, addr, sym->end); return -ERANGE; + } offset = addr - sym->start; h = annotation__histogram(notes, evidx); From b6bd9c7d543ac160646a667470158c5da319a85c Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Mon, 31 Aug 2015 16:16:37 -0500 Subject: [PATCH 225/260] tools lib traceevent: Support %ps/%pS Commits such as 65dd297ac25565 ("xfs: %pF is only for function pointers") caused a regression because pretty_print() didn't support %ps/%pS. The current %pf/%pF implementation in pretty_print() is what %ps/%pS is supposed to do, so use the same code for %ps/%pS. Addressing the incorrect %pf/%pF implementation is beyond the scope of this patch. Signed-off-by: Scott Wood Acked-by: Steven Rostedt Cc: Dave Chinner Link: http://lkml.kernel.org/r/20150831211637.GA12848@home.buserror.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/traceevent/event-parse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 9aa107a0ce8c..2a912df6771b 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -4905,8 +4905,8 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event else ls = 2; - if (*(ptr+1) == 'F' || - *(ptr+1) == 'f') { + if (*(ptr+1) == 'F' || *(ptr+1) == 'f' || + *(ptr+1) == 'S' || *(ptr+1) == 's') { ptr++; show_func = *ptr; } else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') { From 21cf62847d29392e51c37460856d3c3c57769c5e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 22 Oct 2015 15:28:48 +0900 Subject: [PATCH 226/260] perf tools: Move callchain help messages to callchain.h These messages will be used by 'perf top' in the next patch. Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Borislav Petkov Cc: Brendan Gregg Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/1445495330-25416-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 8 +------- tools/perf/builtin-report.c | 10 +++++++--- tools/perf/util/callchain.h | 12 ++++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 24ace2f318c1..1a117623d396 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1010,13 +1010,7 @@ static struct record record = { }, }; -#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " - -#ifdef HAVE_DWARF_UNWIND_SUPPORT -const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf lbr"; -#else -const char record_callchain_help[] = CALLCHAIN_HELP "fp lbr"; -#endif +const char record_callchain_help[] = CALLCHAIN_RECORD_HELP; /* * XXX Will stay a global variable till we fix builtin-script.c to stop messing diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3b23b25d1589..18a8c52d921e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -625,6 +625,9 @@ parse_percent_limit(const struct option *opt, const char *str, return 0; } +const char report_callchain_help[] = "Display callchains using " CALLCHAIN_REPORT_HELP ". " + "Default: graph,0.5,caller"; + int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) { struct perf_session *session; @@ -699,9 +702,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) "regex filter to identify parent, see: '--sort parent'"), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, "Only display entries with parent-match"), - OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]", - "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. " - "Default: graph,0.5,caller", &report_parse_callchain_opt, callchain_default_opt), + OPT_CALLBACK_DEFAULT('g', "call-graph", &report, + "output_type,min_percent[,print_limit],call_order[,branch]", + report_callchain_help, &report_parse_callchain_opt, + callchain_default_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, "Accumulate callchains of children and show total overhead as well"), OPT_INTEGER(0, "max-stack", &report.max_stack, diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index acee2b3cd801..c9e3a2e85a72 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -7,6 +7,18 @@ #include "event.h" #include "symbol.h" +#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " + +#ifdef HAVE_DWARF_UNWIND_SUPPORT +#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP "fp dwarf lbr" +#else +#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP "fp lbr" +#endif + +#define CALLCHAIN_REPORT_HELP "output_type (graph, flat, fractal, or none), " \ + "min percent threshold, optional print limit, callchain order, " \ + "key (function or address), add branches" + enum perf_call_graph_mode { CALLCHAIN_NONE, CALLCHAIN_FP, From a2c10d39af49b00514f7cc7b750757fcc2174f0c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 22 Oct 2015 15:28:49 +0900 Subject: [PATCH 227/260] perf top: Support call-graph display options also Currently 'perf top --call-graph' option is same as 'perf record'. But 'perf top' also need to receive display options in 'perf report'. To do that, change parse_callchain_report_opt() to allow record options too. Now perf top can receive display options like below: $ perf top --call-graph Error: option `call-graph' requires a value Usage: perf top [] --call-graph setup and enables call-graph (stack chain/backtrace) recording: fp dwarf lbr, output_type (graph, flat, fractal, or none), min percent threshold, optional print limit, callchain order, key (function or address), add branches $ perf top --call-graph callee,graph,fp Signed-off-by: Namhyung Kim Cc: Adrian Hunter Cc: Borislav Petkov Cc: Brendan Gregg Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/1445495330-25416-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-top.txt | 5 ++-- tools/perf/builtin-top.c | 26 +++++++++++++---- tools/perf/util/callchain.c | 40 +++++++++++++++++++++++++-- tools/perf/util/callchain.h | 1 + 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index f6a23eb294e7..556cec09bf50 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -160,9 +160,10 @@ Default is to monitor all CPUS. -g:: Enables call-graph (stack chain/backtrace) recording. ---call-graph:: +--call-graph [mode,type,min[,limit],order[,key][,branch]]:: Setup and enable call-graph (stack chain/backtrace) recording, - implies -g. + implies -g. See `--call-graph` section in perf-record and + perf-report man pages for details. --children:: Accumulate callchain of children to parent entry so that then can diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6f641fd68296..1de381d3f29f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1053,8 +1053,22 @@ callchain_opt(const struct option *opt, const char *arg, int unset) static int parse_callchain_opt(const struct option *opt, const char *arg, int unset) { - symbol_conf.use_callchain = true; - return record_parse_callchain_opt(opt, arg, unset); + struct record_opts *record = (struct record_opts *)opt->value; + + record->callgraph_set = true; + callchain_param.enabled = !unset; + callchain_param.record_mode = CALLCHAIN_FP; + + /* + * --no-call-graph + */ + if (unset) { + symbol_conf.use_callchain = false; + callchain_param.record_mode = CALLCHAIN_NONE; + return 0; + } + + return parse_callchain_top_opt(arg); } static int perf_top_config(const char *var, const char *value, void *cb) @@ -1079,6 +1093,8 @@ parse_percent_limit(const struct option *opt, const char *arg, return 0; } +const char top_callchain_help[] = CALLCHAIN_RECORD_HELP ", " CALLCHAIN_REPORT_HELP; + int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) { char errbuf[BUFSIZ]; @@ -1154,11 +1170,11 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, "Show a column with the number of samples"), OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, - NULL, "enables call-graph recording", + NULL, "enables call-graph recording and display", &callchain_opt), OPT_CALLBACK(0, "call-graph", &top.record_opts, - "mode[,dump_size]", record_callchain_help, - &parse_callchain_opt), + "mode[,dump_size],output_type,min_percent[,print_limit],call_order[,branch]", + top_callchain_help, &parse_callchain_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, "Accumulate callchains of children and show total overhead as well"), OPT_INTEGER(0, "max-stack", &top.max_stack, diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 773fe13ce627..842be32899ee 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -77,12 +77,14 @@ static int parse_callchain_sort_key(const char *value) return -1; } -int -parse_callchain_report_opt(const char *arg) +static int +__parse_callchain_report_opt(const char *arg, bool allow_record_opt) { char *tok; char *endptr; bool minpcnt_set = false; + bool record_opt_set = false; + bool try_stack_size = false; symbol_conf.use_callchain = true; @@ -100,6 +102,28 @@ parse_callchain_report_opt(const char *arg) !parse_callchain_order(tok) || !parse_callchain_sort_key(tok)) { /* parsing ok - move on to the next */ + try_stack_size = false; + goto next; + } else if (allow_record_opt && !record_opt_set) { + if (parse_callchain_record(tok, &callchain_param)) + goto try_numbers; + + /* assume that number followed by 'dwarf' is stack size */ + if (callchain_param.record_mode == CALLCHAIN_DWARF) + try_stack_size = true; + + record_opt_set = true; + goto next; + } + +try_numbers: + if (try_stack_size) { + unsigned long size = 0; + + if (get_stack_size(tok, &size) < 0) + return -1; + callchain_param.dump_size = size; + try_stack_size = false; } else if (!minpcnt_set) { /* try to get the min percent */ callchain_param.min_percent = strtod(tok, &endptr); @@ -112,7 +136,7 @@ parse_callchain_report_opt(const char *arg) if (tok == endptr) return -1; } - +next: arg = NULL; } @@ -123,6 +147,16 @@ parse_callchain_report_opt(const char *arg) return 0; } +int parse_callchain_report_opt(const char *arg) +{ + return __parse_callchain_report_opt(arg, false); +} + +int parse_callchain_top_opt(const char *arg) +{ + return __parse_callchain_report_opt(arg, true); +} + int perf_callchain_config(const char *var, const char *value) { char *endptr; diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index c9e3a2e85a72..836d59a001bc 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -192,6 +192,7 @@ extern const char record_callchain_help[]; extern int parse_callchain_record(const char *arg, struct callchain_param *param); int parse_callchain_record_opt(const char *arg, struct callchain_param *param); int parse_callchain_report_opt(const char *arg); +int parse_callchain_top_opt(const char *arg); int perf_callchain_config(const char *var, const char *value); static inline void callchain_cursor_snapshot(struct callchain_cursor *dest, From 792aeafa8ed08e5e18fb66ab93b470f78e619f75 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 22 Oct 2015 16:45:46 +0900 Subject: [PATCH 228/260] perf tools: Defaults to 'caller' callchain order only if --children is enabled The caller callchain order is useful with --children option since it can show 'overview' style output, but other commands which don't use --children feature like 'perf script' or even 'perf report/top' without --children are better to keep callee order. Signed-off-by: Namhyung Kim Acked-by: Brendan Gregg Acked-by: Frederic Weisbecker Acked-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: Chandler Carruth Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/1445499946-29817-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 2 ++ tools/perf/builtin-top.c | 3 +++ tools/perf/util/callchain.c | 2 ++ tools/perf/util/callchain.h | 1 + tools/perf/util/util.c | 2 +- 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 18a8c52d921e..545c51cef7f7 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -812,6 +812,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) if (report.inverted_callchain) callchain_param.order = ORDER_CALLER; + if (symbol_conf.cumulate_callchain && !callchain_param.order_set) + callchain_param.order = ORDER_CALLER; if (itrace_synth_opts.callchain && (int)itrace_synth_opts.callchain_sz > report.max_stack) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1de381d3f29f..af849b1d7389 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1304,6 +1304,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) perf_hpp__cancel_cumulate(); } + if (symbol_conf.cumulate_callchain && !callchain_param.order_set) + callchain_param.order = ORDER_CALLER; + symbol_conf.priv_size = sizeof(struct annotation); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 842be32899ee..735ad48e1858 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -51,10 +51,12 @@ static int parse_callchain_order(const char *value) { if (!strncmp(value, "caller", strlen(value))) { callchain_param.order = ORDER_CALLER; + callchain_param.order_set = true; return 0; } if (!strncmp(value, "callee", strlen(value))) { callchain_param.order = ORDER_CALLEE; + callchain_param.order_set = true; return 0; } return -1; diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 836d59a001bc..aaf467c9ef2b 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -75,6 +75,7 @@ struct callchain_param { double min_percent; sort_chain_func_t sort; enum chain_order order; + bool order_set; enum chain_key key; bool branch_callstack; }; diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index c1bf9ff210b0..cd12c25e4ea4 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -19,7 +19,7 @@ struct callchain_param callchain_param = { .mode = CHAIN_GRAPH_ABS, .min_percent = 0.5, - .order = ORDER_CALLER, + .order = ORDER_CALLEE, .key = CCKEY_FUNCTION }; From 76a26549eb367f683fbb394b7246bef5dc665f8c Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 22 Oct 2015 23:28:32 +0900 Subject: [PATCH 229/260] perf tools: Improve call graph documents and help messages The --call-graph option is complex so we should provide better guide for users. Also change help message to be consistent with config option names. Now perf top will show help like below: $ perf top --call-graph Error: option `call-graph' requires a value Usage: perf top [] --call-graph setup and enables call-graph (stack chain/backtrace): record_mode: call graph recording mode (fp|dwarf|lbr) record_size: if record_mode is 'dwarf', max size of stack recording () default: 8192 (bytes) print_type: call graph printing style (graph|flat|fractal|none) threshold: minimum call graph inclusion threshold () print_limit: maximum number of call graph entry () order: call graph order (caller|callee) sort_key: call graph sort key (function|address) branch: include last branch info to call graph (branch) Default: fp,graph,0.5,caller,function Requested-by: Ingo Molnar Signed-off-by: Namhyung Kim Acked-by: Frederic Weisbecker Cc: Adrian Hunter Cc: Borislav Petkov Cc: Brendan Gregg Cc: Chandler Carruth Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/1445524112-5201-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 9 ++++-- tools/perf/Documentation/perf-report.txt | 38 +++++++++++++++--------- tools/perf/builtin-record.c | 5 ++-- tools/perf/builtin-report.c | 11 ++++--- tools/perf/builtin-top.c | 5 ++-- tools/perf/util/callchain.h | 24 +++++++++++---- 6 files changed, 62 insertions(+), 30 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index b027d28658f2..7ff6a9d0ea0d 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -144,7 +144,7 @@ OPTIONS --call-graph:: Setup and enable call-graph (stack chain/backtrace) recording, - implies -g. + implies -g. Default is "fp". Allows specifying "fp" (frame pointer) or "dwarf" (DWARF's CFI - Call Frame Information) or "lbr" @@ -154,13 +154,18 @@ OPTIONS In some systems, where binaries are build with gcc --fomit-frame-pointer, using the "fp" method will produce bogus call graphs, using "dwarf", if available (perf tools linked to - the libunwind library) should be used instead. + the libunwind or libdw library) should be used instead. Using the "lbr" method doesn't require any compiler options. It will produce call graphs from the hardware LBR registers. The main limition is that it is only available on new Intel platforms, such as Haswell. It can only get user call chain. It doesn't work with branch stack sampling at the same time. + When "dwarf" recording is used, perf also records (user) stack dump + when sampled. Default size of the stack dump is 8192 (bytes). + User can change the size by passing the size after comma like + "--call-graph dwarf,4096". + -q:: --quiet:: Don't print any message, useful for scripting. diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index e4fdeeb51123..ab1fd64e3627 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -169,30 +169,40 @@ OPTIONS --dump-raw-trace:: Dump raw trace in ASCII. --g [type,min[,limit],order[,key][,branch]]:: ---call-graph:: - Display call chains using type, min percent threshold, optional print - limit and order. - type can be either: +-g:: +--call-graph=:: + Display call chains using type, min percent threshold, print limit, + call order, sort key and branch. Note that ordering of parameters is not + fixed so any parement can be given in an arbitraty order. One exception + is the print_limit which should be preceded by threshold. + + print_type can be either: - flat: single column, linear exposure of call chains. - - graph: use a graph tree, displaying absolute overhead rates. + - graph: use a graph tree, displaying absolute overhead rates. (default) - fractal: like graph, but displays relative rates. Each branch of - the tree is considered as a new profiled object. + + the tree is considered as a new profiled object. + - none: disable call chain display. + + threshold is a percentage value which specifies a minimum percent to be + included in the output call graph. Default is 0.5 (%). + + print_limit is only applied when stdio interface is used. It's to limit + number of call graph entries in a single hist entry. Note that it needs + to be given after threshold (but not necessarily consecutive). + Default is 0 (unlimited). order can be either: - callee: callee based call graph. - caller: inverted caller based call graph. + Default is 'caller' when --children is used, otherwise 'callee'. - key can be: - - function: compare on functions + sort_key can be: + - function: compare on functions (default) - address: compare on individual code addresses branch can be: - - branch: include last branch information in callgraph - when available. Usually more convenient to use --branch-history - for this. - - Default: graph,0.5,caller + - branch: include last branch information in callgraph when available. + Usually more convenient to use --branch-history for this. --children:: Accumulate callchain of children to parent entry so that then can diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1a117623d396..2740d7a82ae8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1010,7 +1010,8 @@ static struct record record = { }, }; -const char record_callchain_help[] = CALLCHAIN_RECORD_HELP; +const char record_callchain_help[] = CALLCHAIN_RECORD_HELP + "\n\t\t\t\tDefault: fp"; /* * XXX Will stay a global variable till we fix builtin-script.c to stop messing @@ -1058,7 +1059,7 @@ struct option __record_options[] = { NULL, "enables call-graph recording" , &record_callchain_opt), OPT_CALLBACK(0, "call-graph", &record.opts, - "mode[,dump_size]", record_callchain_help, + "record_mode[,record_size]", record_callchain_help, &record_parse_callchain_opt), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 545c51cef7f7..50dd4d3d8667 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -625,8 +625,11 @@ parse_percent_limit(const struct option *opt, const char *str, return 0; } -const char report_callchain_help[] = "Display callchains using " CALLCHAIN_REPORT_HELP ". " - "Default: graph,0.5,caller"; +#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function" + +const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" + CALLCHAIN_REPORT_HELP + "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -636,7 +639,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) bool has_br_stack = false; int branch_mode = -1; bool branch_call_mode = false; - char callchain_default_opt[] = "graph,0.5,caller"; + char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; const char * const report_usage[] = { "perf report []", NULL @@ -703,7 +706,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, "Only display entries with parent-match"), OPT_CALLBACK_DEFAULT('g', "call-graph", &report, - "output_type,min_percent[,print_limit],call_order[,branch]", + "print_type,threshold[,print_limit],order,sort_key[,branch]", report_callchain_help, &report_parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index af849b1d7389..7e2e72e6d9d1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1093,7 +1093,8 @@ parse_percent_limit(const struct option *opt, const char *arg, return 0; } -const char top_callchain_help[] = CALLCHAIN_RECORD_HELP ", " CALLCHAIN_REPORT_HELP; +const char top_callchain_help[] = CALLCHAIN_RECORD_HELP CALLCHAIN_REPORT_HELP + "\n\t\t\t\tDefault: fp,graph,0.5,caller,function"; int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) { @@ -1173,7 +1174,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) NULL, "enables call-graph recording and display", &callchain_opt), OPT_CALLBACK(0, "call-graph", &top.record_opts, - "mode[,dump_size],output_type,min_percent[,print_limit],call_order[,branch]", + "record_mode[,record_size],print_type,threshold[,print_limit],order,sort_key[,branch]", top_callchain_help, &parse_callchain_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, "Accumulate callchains of children and show total overhead as well"), diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index aaf467c9ef2b..fce8161e54db 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -7,17 +7,29 @@ #include "event.h" #include "symbol.h" -#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: " +#define HELP_PAD "\t\t\t\t" + +#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace):\n\n" #ifdef HAVE_DWARF_UNWIND_SUPPORT -#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP "fp dwarf lbr" +# define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|dwarf|lbr)\n" #else -#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP "fp lbr" +# define RECORD_MODE_HELP HELP_PAD "record_mode:\tcall graph recording mode (fp|lbr)\n" #endif -#define CALLCHAIN_REPORT_HELP "output_type (graph, flat, fractal, or none), " \ - "min percent threshold, optional print limit, callchain order, " \ - "key (function or address), add branches" +#define RECORD_SIZE_HELP \ + HELP_PAD "record_size:\tif record_mode is 'dwarf', max size of stack recording ()\n" \ + HELP_PAD "\t\tdefault: 8192 (bytes)\n" + +#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP + +#define CALLCHAIN_REPORT_HELP \ + HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \ + HELP_PAD "threshold:\tminimum call graph inclusion threshold ()\n" \ + HELP_PAD "print_limit:\tmaximum number of call graph entry ()\n" \ + HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \ + HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \ + HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" enum perf_call_graph_mode { CALLCHAIN_NONE, From 39ff7cdb5a5e6b75dd049255615828c6531cd109 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 21 Oct 2015 11:57:20 +0900 Subject: [PATCH 230/260] perf annotate: Fix 'annotate.use_offset' config variable usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The annotate__configs should be sorted so that it can use bsearch(3). However commit 0c4a5bcea460 ("perf annotate: Display total number of samples with --show-total-period") added a new config item at the end. This resulted in the 'annotate.use_offset' config variable cannot be found and perf terminated like below: $ perf report bad config file line 6 in ~/.perfconfig Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Jiri Olsa Cc: Martin LiÅ¡ka Cc: Peter Zijlstra Cc: Taeung Song Fixes: 0c4a5bcea460 ("perf annotate: Display total number of samples with --show-total-period") Link: http://lkml.kernel.org/r/1445396240-3428-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index bec0b62d8e38..ba72e018e99a 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1125,8 +1125,8 @@ static struct annotate_config { ANNOTATE_CFG(jump_arrows), ANNOTATE_CFG(show_linenr), ANNOTATE_CFG(show_nr_jumps), - ANNOTATE_CFG(use_offset), ANNOTATE_CFG(show_total_period), + ANNOTATE_CFG(use_offset), }; #undef ANNOTATE_CFG From 464b01a48eb6be48bc58332e029760b5e40ea119 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 22 Oct 2015 16:44:17 -0300 Subject: [PATCH 231/260] perf ui tui: Register the error callbacks before initializing the widgets I.e. we want to tell the user about errors found during, for instance, the ui_browser initialization, so that a call to ui__warning() appears as a window waiting for a key to be pressed. Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ederrwizcl6mfz10vfobl5qq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/tui/setup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/perf/ui/tui/setup.c b/tools/perf/ui/tui/setup.c index 60d1f29b4b50..7dfeba0a91f3 100644 --- a/tools/perf/ui/tui/setup.c +++ b/tools/perf/ui/tui/setup.c @@ -141,10 +141,6 @@ int ui__init(void) SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB); - ui_helpline__init(); - ui_browser__init(); - tui_progress__init(); - signal(SIGSEGV, ui__signal_backtrace); signal(SIGFPE, ui__signal_backtrace); signal(SIGINT, ui__signal); @@ -153,6 +149,10 @@ int ui__init(void) perf_error__register(&perf_tui_eops); + ui_helpline__init(); + ui_browser__init(); + tui_progress__init(); + hist_browser__init_hpp(); out: return err; From f06cff7c59b6b252d667435d7baad48687b41002 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 22 Oct 2015 18:10:52 -0300 Subject: [PATCH 232/260] perf annotate: Don't die() when finding an invalid config option The perf_config() infrastructure we inherited from git calls die() when the provided config callback returns -1, meaning some key in a config section is unexpected, that seems ok for a stdio based tool, but in --tui we end up messing up the output, so just tell the user about the error, wait for a keystroke and return 0, being more resilient and proceeding with what we managed to parse. That die() needs to die, tho :-) Cc: Adrian Hunter Cc: Borislav Petkov Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-pqtsffh2kwr5mwm4qg9kgotu@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index ba72e018e99a..d4d7cc27252f 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -1152,9 +1152,9 @@ static int annotate__config(const char *var, const char *value, sizeof(struct annotate_config), annotate_config__cmp); if (cfg == NULL) - return -1; - - *cfg->value = perf_config_bool(name, value); + ui__warning("%s variable unknown, ignoring...", var); + else + *cfg->value = perf_config_bool(name, value); return 0; } From 869c55b0f473fecfe6c294c6fa965dedfe469e02 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Oct 2015 11:23:28 -0300 Subject: [PATCH 233/260] perf tools: Show tool command line options ordered When asking for a listing of the options, be it using -h or when an unknown option is passed, order it by one-letter options, then the ones having just long names. Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: Brendan Gregg Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-41qh68t35n4ehrpsuazp1dx8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-options.c | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 8aa7922397a9..fb26532d67c3 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -2,6 +2,7 @@ #include "parse-options.h" #include "cache.h" #include "header.h" +#include #define OPT_SHORT 1 #define OPT_UNSET 2 @@ -642,9 +643,50 @@ static void print_option_help(const struct option *opts, int full) fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); } +static int option__cmp(const void *va, const void *vb) +{ + const struct option *a = va, *b = vb; + int sa = tolower(a->short_name), sb = tolower(b->short_name), ret; + + if (sa == 0) + sa = 'z' + 1; + if (sb == 0) + sb = 'z' + 1; + + ret = sa - sb; + + if (ret == 0) { + const char *la = a->long_name ?: "", + *lb = b->long_name ?: ""; + ret = strcmp(la, lb); + } + + return ret; +} + +static struct option *options__order(const struct option *opts) +{ + int nr_opts = 0; + const struct option *o = opts; + struct option *ordered; + + for (o = opts; o->type != OPTION_END; o++) + ++nr_opts; + + ordered = memdup(opts, sizeof(*o) * (nr_opts + 1)); + if (ordered == NULL) + goto out; + + qsort(ordered, nr_opts, sizeof(*o), option__cmp); +out: + return ordered; +} + int usage_with_options_internal(const char * const *usagestr, const struct option *opts, int full) { + struct option *ordered; + if (!usagestr) return PARSE_OPT_HELP; @@ -661,11 +703,17 @@ int usage_with_options_internal(const char * const *usagestr, if (opts->type != OPTION_GROUP) fputc('\n', stderr); + ordered = options__order(opts); + if (ordered) + opts = ordered; + for ( ; opts->type != OPTION_END; opts++) print_option_help(opts, full); fputc('\n', stderr); + free(ordered); + return PARSE_OPT_HELP; } From 161d9041782b86c5493481566539bfc058ceeaff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 23 Oct 2015 13:27:39 -0300 Subject: [PATCH 234/260] perf tools: Provide help for subset of options Some tools have a lot of options, so, providing a way to show help just for some of them may come handy: $ perf report -h --tui Usage: perf report [] --tui Use the TUI interface $ perf report -h --tui --showcpuutilization -b -c Usage: perf report [] -b, --branch-stack use branch records for per branch histogram filling -c, --comms only consider symbols in these comms --showcpuutilization Show sample percentage for different cpu modes --tui Use the TUI interface $ Using it with perf bash completion is also handy, just make sure you source the needed file: $ . ~/git/linux/tools/perf/perf-completion.sh Then press tab/tab after -- to see a list of options, put them after -h and only the options chosen will have its help presented: $ perf report -h -- --asm-raw --demangle-kernel --group --kallsyms --pretty --stdio --branch-history --disassembler-style --gtk --max-stack --showcpuutilization --symbol-filter --branch-stack --dsos --header --mem-mode --show-info --symbols --call-graph --dump-raw-trace --header-only --modules --show-nr-samples --symfs --children --exclude-other --hide-unresolved --objdump --show-ref-call-graph --threads --column-widths --fields --ignore-callees --parent --show-total-period --tid --comms --field-separator --input --percentage --socket-filter --tui --cpu --force --inverted --percent-limit --sort --verbose --demangle --full-source-path --itrace --pid --source --vmlinux $ perf report -h --socket-filter Usage: perf report [] --socket-filter only show processor socket that match with this filter Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: Brendan Gregg Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-83mcdd3wj0379jcgea8w0fxa@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-options.c | 42 ++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index fb26532d67c3..22c2806bda98 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -373,7 +373,8 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, } static int usage_with_options_internal(const char * const *, - const struct option *, int); + const struct option *, int, + struct parse_opt_ctx_t *); int parse_options_step(struct parse_opt_ctx_t *ctx, const struct option *options, @@ -397,8 +398,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, if (arg[1] != '-') { ctx->opt = ++arg; - if (internal_help && *ctx->opt == 'h') - return usage_with_options_internal(usagestr, options, 0); + if (internal_help && *ctx->opt == 'h') { + return usage_with_options_internal(usagestr, options, 0, ctx); + } switch (parse_short_opt(ctx, options)) { case -1: return parse_options_usage(usagestr, options, arg, 1); @@ -413,7 +415,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, check_typos(arg, options); while (ctx->opt) { if (internal_help && *ctx->opt == 'h') - return usage_with_options_internal(usagestr, options, 0); + return usage_with_options_internal(usagestr, options, 0, ctx); arg = ctx->opt; switch (parse_short_opt(ctx, options)) { case -1: @@ -446,9 +448,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, arg += 2; if (internal_help && !strcmp(arg, "help-all")) - return usage_with_options_internal(usagestr, options, 1); + return usage_with_options_internal(usagestr, options, 1, ctx); if (internal_help && !strcmp(arg, "help")) - return usage_with_options_internal(usagestr, options, 0); + return usage_with_options_internal(usagestr, options, 0, ctx); if (!strcmp(arg, "list-opts")) return PARSE_OPT_LIST_OPTS; if (!strcmp(arg, "list-cmds")) @@ -682,8 +684,27 @@ out: return ordered; } +static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx) +{ + int i; + + for (i = 1; i < ctx->argc; ++i) { + const char *arg = ctx->argv[i]; + + if (arg[0] != '-') + continue; + + if (arg[1] == opt->short_name || + (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) + return true; + } + + return false; +} + int usage_with_options_internal(const char * const *usagestr, - const struct option *opts, int full) + const struct option *opts, int full, + struct parse_opt_ctx_t *ctx) { struct option *ordered; @@ -707,8 +728,11 @@ int usage_with_options_internal(const char * const *usagestr, if (ordered) opts = ordered; - for ( ; opts->type != OPTION_END; opts++) + for ( ; opts->type != OPTION_END; opts++) { + if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx)) + continue; print_option_help(opts, full); + } fputc('\n', stderr); @@ -721,7 +745,7 @@ void usage_with_options(const char * const *usagestr, const struct option *opts) { exit_browser(false); - usage_with_options_internal(usagestr, opts, 0); + usage_with_options_internal(usagestr, opts, 0, NULL); exit(129); } From a5f4a6932ec2e1a53642e97a1be64bc7b169942f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 25 Oct 2015 00:49:24 +0900 Subject: [PATCH 235/260] perf tools: Improve ambiguous option help message Currently if an option name is ambiguous it only prints first two matched option names but no help. It'd be better it could show all possible names and help messages too. Before: $ perf report --show Error: Ambiguous option: show (could be --show-total-period or --show-ref-call-graph) Usage: perf report [] After: $ perf report --show Error: Ambiguous option: show (could be --show-total-period or --show-ref-call-graph) Usage: perf report [] -n, --show-nr-samples Show a column with the number of samples --showcpuutilization Show sample percentage for different cpu modes -I, --show-info Display extended information about perf.data file --show-total-period Show a column with the sum of periods --show-ref-call-graph Show callgraph from reference event Signed-off-by: Namhyung Kim Acked-by: Ingo Molnar Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445701767-12731-1-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-options.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 22c2806bda98..b8d98229a8af 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -770,24 +770,23 @@ int parse_options_usage(const char * const *usagestr, opt: for ( ; opts->type != OPTION_END; opts++) { if (short_opt) { - if (opts->short_name == *optstr) + if (opts->short_name == *optstr) { + print_option_help(opts, 0); break; + } continue; } if (opts->long_name == NULL) continue; - if (!prefixcmp(optstr, opts->long_name)) - break; - if (!prefixcmp(optstr, "no-") && - !prefixcmp(optstr + 3, opts->long_name)) - break; + if (!prefixcmp(opts->long_name, optstr)) + print_option_help(opts, 0); + if (!prefixcmp("no-", optstr) && + !prefixcmp(opts->long_name, optstr + 3)) + print_option_help(opts, 0); } - if (opts->type != OPTION_END) - print_option_help(opts, 0); - return PARSE_OPT_HELP; } From b272a59d835cd8ca6b45f41c66c61b473996c759 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 25 Oct 2015 00:49:25 +0900 Subject: [PATCH 236/260] perf report: Rename to --show-cpu-utilization So that it can be more consistent with other --show-* options. The old name (--showcpuutilization) is provided only for compatibility. Signed-off-by: Namhyung Kim Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445701767-12731-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-report.txt | 2 +- tools/perf/builtin-report.c | 4 +++- tools/perf/util/parse-options.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index ab1fd64e3627..5ce8da1e1256 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -29,7 +29,7 @@ OPTIONS --show-nr-samples:: Show the number of samples for each symbol ---showcpuutilization:: +--show-cpu-utilization:: Show sample percentage for different cpu modes. -T:: diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 50dd4d3d8667..2853ad2bd435 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -699,8 +699,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) " Please refer the man page for the complete list."), OPT_STRING('F', "fields", &field_order, "key[,keys...]", "output field(s): overhead, period, sample plus all of sort keys"), - OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, + OPT_BOOLEAN(0, "show-cpu-utilization", &symbol_conf.show_cpu_utilization, "Show sample percentage for different cpu modes"), + OPT_BOOLEAN_FLAG(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, + "Show sample percentage for different cpu modes", PARSE_OPT_HIDDEN), OPT_STRING('p', "parent", &parent_pattern, "regex", "regex filter to identify parent, see: '--sort parent'"), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index 367d8b816cc7..182c86099330 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h @@ -111,6 +111,7 @@ struct option { #define OPT_GROUP(h) { .type = OPTION_GROUP, .help = (h) } #define OPT_BIT(s, l, v, h, b) { .type = OPTION_BIT, .short_name = (s), .long_name = (l), .value = check_vtype(v, int *), .help = (h), .defval = (b) } #define OPT_BOOLEAN(s, l, v, h) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h) } +#define OPT_BOOLEAN_FLAG(s, l, v, h, f) { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), .value = check_vtype(v, bool *), .help = (h), .flags = (f) } #define OPT_BOOLEAN_SET(s, l, v, os, h) \ { .type = OPTION_BOOLEAN, .short_name = (s), .long_name = (l), \ .value = check_vtype(v, bool *), .help = (h), \ From 01b19455c08cc37d1c3ef174524278e84c92fec1 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 25 Oct 2015 00:49:26 +0900 Subject: [PATCH 237/260] perf tools: Setup pager when printing usage and help It's annoying to see error or help message when command has many options like in perf record, report or top. So setup pager when print parser error or help message - it should be OK since no UI is enabled at the parsing time. The usage_with_options() already disables it by calling exit_browser() anyway. Signed-off-by: Namhyung Kim Acked-by: Ingo Molnar Tested-by: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445701767-12731-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-options.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index b8d98229a8af..eeeed98eb26d 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -7,6 +7,8 @@ #define OPT_SHORT 1 #define OPT_UNSET 2 +static struct strbuf error_buf = STRBUF_INIT; + static int opterror(const struct option *opt, const char *reason, int flags) { if (flags & OPT_SHORT) @@ -540,9 +542,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o exit(130); default: /* PARSE_OPT_UNKNOWN */ if (ctx.argv[0][1] == '-') { - error("unknown option `%s'", ctx.argv[0] + 2); + strbuf_addf(&error_buf, "unknown option `%s'", + ctx.argv[0] + 2); } else { - error("unknown switch `%c'", *ctx.opt); + strbuf_addf(&error_buf, "unknown switch `%c'", + *ctx.opt); } usage_with_options(usagestr, options); } @@ -711,6 +715,13 @@ int usage_with_options_internal(const char * const *usagestr, if (!usagestr) return PARSE_OPT_HELP; + setup_pager(); + + if (strbuf_avail(&error_buf)) { + fprintf(stderr, " Error: %s\n", error_buf.buf); + strbuf_release(&error_buf); + } + fprintf(stderr, "\n Usage: %s\n", *usagestr++); while (*usagestr && **usagestr) fprintf(stderr, " or: %s\n", *usagestr++); From c71183697250b356be6c7c1abc2e9a74073e1dca Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 25 Oct 2015 00:49:27 +0900 Subject: [PATCH 238/260] perf tools: Introduce usage_with_options_msg() Now usage_with_options() setup a pager before printing message so normal printf() or pr_err() will not be shown. The usage_with_options_msg() can be used to print some help message before usage strings. Signed-off-by: Namhyung Kim Acked-by: Masami Hiramatsu Cc: David Ahern Cc: Jiri Olsa Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445701767-12731-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-evlist.c | 4 ++-- tools/perf/builtin-probe.c | 20 ++++++++++++-------- tools/perf/builtin-record.c | 11 ++++++----- tools/perf/builtin-sched.c | 4 ++-- tools/perf/builtin-script.c | 8 ++++---- tools/perf/util/parse-options.c | 15 +++++++++++++++ tools/perf/util/parse-options.h | 4 ++++ tools/perf/util/strbuf.c | 22 +++++++++++++++------- tools/perf/util/strbuf.h | 2 ++ 9 files changed, 62 insertions(+), 28 deletions(-) diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c index 695ec5a50cf2..f4d62510acbb 100644 --- a/tools/perf/builtin-evlist.c +++ b/tools/perf/builtin-evlist.c @@ -61,8 +61,8 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(evlist_usage, options); if (details.event_group && (details.verbose || details.freq)) { - pr_err("--group option is not compatible with other options\n"); - usage_with_options(evlist_usage, options); + usage_with_options_msg(evlist_usage, options, + "--group option is not compatible with other options\n"); } return __cmd_evlist(input_name, &details); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index 530c3a28a58c..132afc97676c 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -528,12 +528,12 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) PARSE_OPT_STOP_AT_NON_OPTION); if (argc > 0) { if (strcmp(argv[0], "-") == 0) { - pr_warning(" Error: '-' is not supported.\n"); - usage_with_options(probe_usage, options); + usage_with_options_msg(probe_usage, options, + "'-' is not supported.\n"); } if (params.command && params.command != 'a') { - pr_warning(" Error: another command except --add is set.\n"); - usage_with_options(probe_usage, options); + usage_with_options_msg(probe_usage, options, + "another command except --add is set.\n"); } ret = parse_probe_event_argv(argc, argv); if (ret < 0) { @@ -562,8 +562,10 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) switch (params.command) { case 'l': if (params.uprobes) { - pr_warning(" Error: Don't use --list with --exec.\n"); - usage_with_options(probe_usage, options); + pr_err(" Error: Don't use --list with --exec.\n"); + parse_options_usage(probe_usage, options, "l", true); + parse_options_usage(NULL, options, "x", true); + return -EINVAL; } ret = show_perf_probe_events(params.filter); if (ret < 0) @@ -603,8 +605,10 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused) case 'a': /* Ensure the last given target is used */ if (params.target && !params.target_used) { - pr_warning(" Error: -x/-m must follow the probe definitions.\n"); - usage_with_options(probe_usage, options); + pr_err(" Error: -x/-m must follow the probe definitions.\n"); + parse_options_usage(probe_usage, options, "m", true); + parse_options_usage(NULL, options, "x", true); + return -EINVAL; } ret = perf_add_probe_events(params.events, params.nevents); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 2740d7a82ae8..de02267c73d8 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1135,14 +1135,15 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) usage_with_options(record_usage, record_options); if (nr_cgroups && !rec->opts.target.system_wide) { - ui__error("cgroup monitoring only available in" - " system-wide mode\n"); - usage_with_options(record_usage, record_options); + usage_with_options_msg(record_usage, record_options, + "cgroup monitoring only available in system-wide mode"); + } if (rec->opts.record_switch_events && !perf_can_record_switch_events()) { - ui__error("kernel does not support recording context switch events (--switch-events option)\n"); - usage_with_options(record_usage, record_options); + ui__error("kernel does not support recording context switch events\n"); + parse_options_usage(record_usage, record_options, "switch-events", 0); + return -EINVAL; } if (!rec->itr) { diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 33962612a5e9..0ee6d900e100 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1728,8 +1728,8 @@ static void setup_sorting(struct perf_sched *sched, const struct option *options for (tok = strtok_r(str, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { if (sort_dimension__add(tok, &sched->sort_list) < 0) { - error("Unknown --sort key: `%s'", tok); - usage_with_options(usage_msg, options); + usage_with_options_msg(usage_msg, options, + "Unknown --sort key: `%s'", tok); } } diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 2653c0273b89..278acb22f029 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1767,9 +1767,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) rep_script_path = get_script_path(argv[0], REPORT_SUFFIX); if (!rec_script_path && !rep_script_path) { - fprintf(stderr, " Couldn't find script %s\n\n See perf" + usage_with_options_msg(script_usage, options, + "Couldn't find script `%s'\n\n See perf" " script -l for available scripts.\n", argv[0]); - usage_with_options(script_usage, options); } if (is_top_script(argv[0])) { @@ -1780,10 +1780,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) rep_args = has_required_arg(rep_script_path); rec_args = (argc - 1) - rep_args; if (rec_args < 0) { - fprintf(stderr, " %s script requires options." + usage_with_options_msg(script_usage, options, + "`%s' script requires options." "\n\n See perf script -l for available " "scripts and options.\n", argv[0]); - usage_with_options(script_usage, options); } } diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index eeeed98eb26d..230e771407a3 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -760,6 +760,21 @@ void usage_with_options(const char * const *usagestr, exit(129); } +void usage_with_options_msg(const char * const *usagestr, + const struct option *opts, const char *fmt, ...) +{ + va_list ap; + + exit_browser(false); + + va_start(ap, fmt); + strbuf_addv(&error_buf, fmt, ap); + va_end(ap); + + usage_with_options_internal(usagestr, opts, 0, NULL); + exit(129); +} + int parse_options_usage(const char * const *usagestr, const struct option *opts, const char *optstr, bool short_opt) diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h index 182c86099330..a8e407bc251e 100644 --- a/tools/perf/util/parse-options.h +++ b/tools/perf/util/parse-options.h @@ -161,6 +161,10 @@ extern int parse_options_subcommand(int argc, const char **argv, extern NORETURN void usage_with_options(const char * const *usagestr, const struct option *options); +extern NORETURN __attribute__((format(printf,3,4))) +void usage_with_options_msg(const char * const *usagestr, + const struct option *options, + const char *fmt, ...); /*----- incremantal advanced APIs -----*/ diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 4abe23550c73..25671fa16618 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -82,23 +82,22 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len) strbuf_setlen(sb, sb->len + len); } -void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) { int len; - va_list ap; + va_list ap_saved; if (!strbuf_avail(sb)) strbuf_grow(sb, 64); - va_start(ap, fmt); + + va_copy(ap_saved, ap); len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); if (len < 0) die("your vsnprintf is broken"); if (len > strbuf_avail(sb)) { strbuf_grow(sb, len); - va_start(ap, fmt); - len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); - va_end(ap); + len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); + va_end(ap_saved); if (len > strbuf_avail(sb)) { die("this should not happen, your vsnprintf is broken"); } @@ -106,6 +105,15 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...) strbuf_setlen(sb, sb->len + len); } +void strbuf_addf(struct strbuf *sb, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + strbuf_addv(sb, fmt, ap); + va_end(ap); +} + ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) { size_t oldlen = sb->len; diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index 436ac319f6c7..529f2f035249 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h @@ -39,6 +39,7 @@ */ #include +#include extern char strbuf_slopbuf[]; struct strbuf { @@ -85,6 +86,7 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) { __attribute__((format(printf,2,3))) extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...); +extern void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap); /* XXX: if read fails, any partial read is undone */ extern ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); From af3399817428d8adc2c87c91df23fde77dbcdb35 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 25 Oct 2015 15:51:44 +0100 Subject: [PATCH 239/260] perf evsel: Move id_offset out of struct perf_evsel union member Because the 'perf stat record' patches will use the id_offset member together with the priv pointer. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445784728-21732-29-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 02a5fed8d924..0e22c0b7dab5 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -90,9 +90,9 @@ struct perf_evsel { double scale; const char *unit; struct event_format *tp_format; + off_t id_offset; union { void *priv; - off_t id_offset; u64 db_id; }; struct cgroup_sel *cgrp; From 2322f573f8131da9c6d1fab01fe0a0c2c23aa549 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 25 Oct 2015 15:51:17 +0100 Subject: [PATCH 240/260] perf cpu_map: Add cpu_map__empty_new function Adding cpu_map__empty_new interface to create empty cpumap with given size. The cpumap entries are initialized with -1. It'll be used for caching cpu_map in following patches. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445784728-21732-2-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cpumap.c | 17 +++++++++++++++++ tools/perf/util/cpumap.h | 1 + 2 files changed, 18 insertions(+) diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index aa6b490aa471..10af1e7524fb 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -203,6 +203,23 @@ struct cpu_map *cpu_map__dummy_new(void) return cpus; } +struct cpu_map *cpu_map__empty_new(int nr) +{ + struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); + + if (cpus != NULL) { + int i; + + cpus->nr = nr; + for (i = 0; i < nr; i++) + cpus->map[i] = -1; + + atomic_set(&cpus->refcnt, 1); + } + + return cpus; +} + static void cpu_map__delete(struct cpu_map *map) { if (map) { diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index f1bcd2cfa164..85f7772457fa 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -15,6 +15,7 @@ struct cpu_map { }; struct cpu_map *cpu_map__new(const char *cpu_list); +struct cpu_map *cpu_map__empty_new(int nr); struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__read(FILE *file); size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); From 1e5a29318ba8506f52a8d727b5c6a53143f9882a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 25 Oct 2015 15:51:18 +0100 Subject: [PATCH 241/260] perf stat: Cache aggregated map entries in extra cpumap Currently any time we need to access socket or core id for given cpu, we access the sysfs topology file. Adding a cpus_aggr_map cpu_map to cache those entries. Signed-off-by: Jiri Olsa Tested-by: Kan Liang Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1445784728-21732-3-git-send-email-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 59 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 91e793a76929..2f438f76cceb 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -100,6 +100,8 @@ static struct target target = { .uid = UINT_MAX, }; +typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); + static int run_count = 1; static bool no_inherit = false; static volatile pid_t child_pid = -1; @@ -119,7 +121,7 @@ static unsigned int unit_width = 4; /* strlen("unit") */ static bool forever = false; static struct timespec ref_time; static struct cpu_map *aggr_map; -static int (*aggr_get_id)(struct cpu_map *m, int cpu); +static aggr_get_id_t aggr_get_id; static volatile int done = 0; @@ -954,22 +956,63 @@ static int perf_stat__get_core(struct cpu_map *map, int cpu) return cpu_map__get_core(map, cpu, NULL); } +static int cpu_map__get_max(struct cpu_map *map) +{ + int i, max = -1; + + for (i = 0; i < map->nr; i++) { + if (map->map[i] > max) + max = map->map[i]; + } + + return max; +} + +static struct cpu_map *cpus_aggr_map; + +static int perf_stat__get_aggr(aggr_get_id_t get_id, struct cpu_map *map, int idx) +{ + int cpu; + + if (idx >= map->nr) + return -1; + + cpu = map->map[idx]; + + if (cpus_aggr_map->map[cpu] == -1) + cpus_aggr_map->map[cpu] = get_id(map, idx); + + return cpus_aggr_map->map[cpu]; +} + +static int perf_stat__get_socket_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_socket, map, idx); +} + +static int perf_stat__get_core_cached(struct cpu_map *map, int idx) +{ + return perf_stat__get_aggr(perf_stat__get_core, map, idx); +} + static int perf_stat_init_aggr_mode(void) { + int nr; + switch (stat_config.aggr_mode) { case AGGR_SOCKET: if (cpu_map__build_socket_map(evsel_list->cpus, &aggr_map)) { perror("cannot build socket map"); return -1; } - aggr_get_id = perf_stat__get_socket; + aggr_get_id = perf_stat__get_socket_cached; break; case AGGR_CORE: if (cpu_map__build_core_map(evsel_list->cpus, &aggr_map)) { perror("cannot build core map"); return -1; } - aggr_get_id = perf_stat__get_core; + aggr_get_id = perf_stat__get_core_cached; break; case AGGR_NONE: case AGGR_GLOBAL: @@ -978,7 +1021,15 @@ static int perf_stat_init_aggr_mode(void) default: break; } - return 0; + + /* + * The evsel_list->cpus is the base we operate on, + * taking the highest cpu number to be the size of + * the aggregation translate cpumap. + */ + nr = cpu_map__get_max(evsel_list->cpus); + cpus_aggr_map = cpu_map__empty_new(nr + 1); + return cpus_aggr_map ? 0 : -ENOMEM; } /* From f4efcce33d2e5224a905369f9906f3931f5d907c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Oct 2015 17:35:58 -0300 Subject: [PATCH 242/260] perf tools: Search for more options when passing args to -h Recently 'perf -h' was made aware of arguments and would show just the help for the arguments specified, but that required a strict form, i.e.: $ perf -h --tui worked, but: $ perf -h tui didn't. Make it support both cases and also look at the option help when neither matches, so that he following examples works: $ perf report -h interface Usage: perf report [] --gtk Use the GTK2 interface --stdio Use the stdio interface --tui Use the TUI interface $ perf report -h stack Usage: perf report [] -g, --call-graph Display call graph (stack chain/backtrace): print_type: call graph printing style (graph|flat|fractal|none) threshold: minimum call graph inclusion threshold () print_limit: maximum number of call graph entry () order: call graph order (caller|callee) sort_key: call graph sort key (function|address) branch: include last branch info to call graph (branch) Default: graph,0.5,caller,function --max-stack Set the maximum stack depth when parsing the callchain, anything beyond the specified depth will be ignored. Default: 127 $ Suggested-by: Ingo Molnar Cc: Adrian Hunter Cc: Borislav Petkov Cc: Brendan Gregg Cc: Chandler Carruth Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-xzqvamzqv3cv0p6w3inhols3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-options.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c index 230e771407a3..9fca09296eb3 100644 --- a/tools/perf/util/parse-options.c +++ b/tools/perf/util/parse-options.c @@ -695,8 +695,21 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx for (i = 1; i < ctx->argc; ++i) { const char *arg = ctx->argv[i]; - if (arg[0] != '-') + if (arg[0] != '-') { + if (arg[1] == '\0') { + if (arg[0] == opt->short_name) + return true; + continue; + } + + if (opt->long_name && strcmp(opt->long_name, arg) == 0) + return true; + + if (opt->help && strcasestr(opt->help, arg) != NULL) + return true; + continue; + } if (arg[1] == opt->short_name || (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) From f2f3096888569ff1fc15fa0187a39eef3a24b28e Mon Sep 17 00:00:00 2001 From: Dima Kogan Date: Mon, 7 Sep 2015 17:30:28 -0700 Subject: [PATCH 243/260] perf symbols: Fix type error when reading a build-id This was benign, but wrong. The build-id should live in a char[], not a char*[] Signed-off-by: Dima Kogan Link: http://lkml.kernel.org/r/87si6pfwz4.fsf@secretsauce.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol-minimal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index fd8477cacf88..48906333a858 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -337,7 +337,7 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused, symbol_filter_t filter __maybe_unused, int kmodule __maybe_unused) { - unsigned char *build_id[BUILD_ID_SIZE]; + unsigned char build_id[BUILD_ID_SIZE]; int ret; ret = fd__is_64_bit(ss->fd); From 5baecbcd9c9a2f491afe1369fc22e7363f9c94d5 Mon Sep 17 00:00:00 2001 From: Dima Kogan Date: Mon, 7 Sep 2015 17:34:19 -0700 Subject: [PATCH 244/260] perf symbols: we can now read separate debug-info files based on a build ID Recent GDB (at least on a vanilla Debian box) looks for debug information in /usr/lib/debug/.build-id/nn/nnnnnnn where nn/nnnnnn is the build-id of the stripped ELF binary. This is documented here: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html This was not working in perf because we didn't read the build id until AFTER we searched for the separate debug information file. This patch reads the build ID and THEN does the search. Signed-off-by: Dima Kogan Link: http://lkml.kernel.org/r/87si6pfwz4.fsf@secretsauce.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7bf0c46918d..71bf711a628c 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1406,6 +1406,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) struct symsrc ss_[2]; struct symsrc *syms_ss = NULL, *runtime_ss = NULL; bool kmod; + unsigned char build_id[BUILD_ID_SIZE]; pthread_mutex_lock(&dso->lock); @@ -1461,6 +1462,14 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE || dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP; + + /* + * Read the build id if possible. This is required for + * DSO_BINARY_TYPE__BUILDID_DEBUGINFO to work + */ + if (filename__read_build_id(dso->name, build_id, BUILD_ID_SIZE) > 0) + dso__set_build_id(dso, build_id); + /* * Iterate over candidate debug images. * Keep track of "interesting" ones (those which have a symtab, dynsym, From 374ce938aaeb481114b2a8fdedd261f9b2ff9b2b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 28 Oct 2015 10:55:02 +0000 Subject: [PATCH 245/260] perf tools: Enable pre-event inherit setting by config terms This patch allows perf record setting event's attr.inherit bit by config terms like: # perf record -e cycles/no-inherit/ ... # perf record -e cycles/inherit/ ... So user can control inherit bit for each event separately. In following example, a.out fork()s in main then do some complex CPU intensive computations in both of its children. Basic result with and without inherit: # perf record -e cycles -e instructions ./a.out [ perf record: Woken up 9 times to write data ] [ perf record: Captured and wrote 2.205 MB perf.data (47920 samples) ] # perf report --stdio # ... # Samples: 23K of event 'cycles' # Event count (approx.): 23641752891 ... # Samples: 24K of event 'instructions' # Event count (approx.): 30428312415 # perf record -i -e cycles -e instructions ./a.out [ perf record: Woken up 5 times to write data ] [ perf record: Captured and wrote 1.111 MB perf.data (24019 samples) ] ... # Samples: 12K of event 'cycles' # Event count (approx.): 11699501775 ... # Samples: 12K of event 'instructions' # Event count (approx.): 15058023559 Cancel inherit for one event when globally enable: # perf record -e cycles/no-inherit/ -e instructions ./a.out [ perf record: Woken up 7 times to write data ] [ perf record: Captured and wrote 1.660 MB perf.data (36004 samples) ] ... # Samples: 12K of event 'cycles/no-inherit/' # Event count (approx.): 11895759282 ... # Samples: 24K of event 'instructions' # Event count (approx.): 30668000441 Enable inherit for one event when globally disable: # perf record -i -e cycles/inherit/ -e instructions ./a.out [ perf record: Woken up 7 times to write data ] [ perf record: Captured and wrote 1.654 MB perf.data (35868 samples) ] ... # Samples: 23K of event 'cycles/inherit/' # Event count (approx.): 23285400229 ... # Samples: 11K of event 'instructions' # Event count (approx.): 14969050259 Committer note: One can check if the bit was set, in addition to seeing the result in the perf.data file size as above by doing one of: # perf record -e cycles -e instructions -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.911 MB perf.data (63 samples) ] # perf evlist -v cycles: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 instructions: size: 112, config: 0x1, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, freq: 1, sample_id_all: 1, exclude_guest: 1 # So, the inherit bit was set in both, now, if we disable it globally using --no-inherit: # perf record --no-inherit -e cycles -e instructions -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.910 MB perf.data (56 samples) ] # perf evlist -v cycles: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, mmap: 1, comm: 1, freq: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 instructions: size: 112, config: 0x1, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, freq: 1, sample_id_all: 1, exclude_guest: 1 No inherit bit set, then disabling it and setting just on the cycles event: # perf record --no-inherit -e cycles/inherit/ -e instructions -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.909 MB perf.data (48 samples) ] # perf evlist -v cycles/inherit/: size: 112, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 instructions: size: 112, config: 0x1, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|ID|CPU|PERIOD, read_format: ID, disabled: 1, freq: 1, sample_id_all: 1, exclude_guest: 1 # We can see it as well in by using a more verbose level of debug messages in the tool that sets up the perf_event_attr, 'perf record' in this case: [root@zoo ~]# perf record -vv --no-inherit -e cycles/inherit/ -e instructions -a usleep 1 ------------------------------------------------------------ perf_event_attr: size 112 { sample_period, sample_freq } 4000 sample_type IP|TID|TIME|ID|CPU|PERIOD read_format ID disabled 1 inherit 1 mmap 1 comm 1 freq 1 task 1 sample_id_all 1 exclude_guest 1 mmap2 1 comm_exec 1 ------------------------------------------------------------ sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 sys_perf_event_open: pid -1 cpu 1 group_fd -1 flags 0x8 sys_perf_event_open: pid -1 cpu 2 group_fd -1 flags 0x8 sys_perf_event_open: pid -1 cpu 3 group_fd -1 flags 0x8 ------------------------------------------------------------ perf_event_attr: size 112 config 0x1 { sample_period, sample_freq } 4000 sample_type IP|TID|TIME|ID|CPU|PERIOD read_format ID disabled 1 freq 1 sample_id_all 1 exclude_guest 1 ------------------------------------------------------------ sys_perf_event_open: pid -1 cpu 0 group_fd -1 flags 0x8 Signed-off-by: Wang Nan Acked-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: David S. Miller Cc: Li Zefan Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1446029705-199659-2-git-send-email-wangnan0@huawei.com [ s/u64/bool/ for the perf_evsel_config_term inherit field - jolsa] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 9 +++++++++ tools/perf/util/evsel.h | 2 ++ tools/perf/util/parse-events.c | 14 ++++++++++++++ tools/perf/util/parse-events.h | 2 ++ tools/perf/util/parse-events.l | 2 ++ 5 files changed, 29 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ab05fa52a5cd..3ac4ee9c6a6e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -652,6 +652,15 @@ static void apply_config_terms(struct perf_evsel *evsel, case PERF_EVSEL__CONFIG_TERM_STACK_USER: dump_size = term->val.stack_user; break; + case PERF_EVSEL__CONFIG_TERM_INHERIT: + /* + * attr->inherit should has already been set by + * perf_evsel__config. If user explicitly set + * inherit using config terms, override global + * opt->no_inherit setting. + */ + attr->inherit = term->val.inherit ? 1 : 0; + break; default: break; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 0e22c0b7dab5..1e8ff1906f71 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -43,6 +43,7 @@ enum { PERF_EVSEL__CONFIG_TERM_TIME, PERF_EVSEL__CONFIG_TERM_CALLGRAPH, PERF_EVSEL__CONFIG_TERM_STACK_USER, + PERF_EVSEL__CONFIG_TERM_INHERIT, PERF_EVSEL__CONFIG_TERM_MAX, }; @@ -55,6 +56,7 @@ struct perf_evsel_config_term { bool time; char *callgraph; u64 stack_user; + bool inherit; } val; }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 991bbd469bea..72abcf254ccb 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -666,6 +666,12 @@ do { \ case PARSE_EVENTS__TERM_TYPE_STACKSIZE: CHECK_TYPE_VAL(NUM); break; + case PARSE_EVENTS__TERM_TYPE_INHERIT: + CHECK_TYPE_VAL(NUM); + break; + case PARSE_EVENTS__TERM_TYPE_NOINHERIT: + CHECK_TYPE_VAL(NUM); + break; case PARSE_EVENTS__TERM_TYPE_NAME: CHECK_TYPE_VAL(STR); break; @@ -701,6 +707,8 @@ static int config_term_tracepoint(struct perf_event_attr *attr, switch (term->type_term) { case PARSE_EVENTS__TERM_TYPE_CALLGRAPH: case PARSE_EVENTS__TERM_TYPE_STACKSIZE: + case PARSE_EVENTS__TERM_TYPE_INHERIT: + case PARSE_EVENTS__TERM_TYPE_NOINHERIT: return config_term_common(attr, term, err); default: if (err) { @@ -764,6 +772,12 @@ do { \ case PARSE_EVENTS__TERM_TYPE_STACKSIZE: ADD_CONFIG_TERM(STACK_USER, stack_user, term->val.num); break; + case PARSE_EVENTS__TERM_TYPE_INHERIT: + ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 1 : 0); + break; + case PARSE_EVENTS__TERM_TYPE_NOINHERIT: + ADD_CONFIG_TERM(INHERIT, inherit, term->val.num ? 0 : 1); + break; default: break; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index f13d3ccda444..13c9063513eb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -67,6 +67,8 @@ enum { PARSE_EVENTS__TERM_TYPE_TIME, PARSE_EVENTS__TERM_TYPE_CALLGRAPH, PARSE_EVENTS__TERM_TYPE_STACKSIZE, + PARSE_EVENTS__TERM_TYPE_NOINHERIT, + PARSE_EVENTS__TERM_TYPE_INHERIT }; struct parse_events_term { diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index be244573a02e..8d0de5b2991d 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -187,6 +187,8 @@ branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE time { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_TIME); } call-graph { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CALLGRAPH); } stack-size { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_STACKSIZE); } +inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_INHERIT); } +no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } From 443f8c75e8d58d394b0e65b47e02e5cd8ed32b41 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 26 Oct 2015 14:51:30 +0100 Subject: [PATCH 246/260] perf symbols: Fix endless loop in dso__split_kallsyms_for_kcore Currently we split symbols based on the map comparison, but symbols are stored within dso objects and maps could point into same dso objects (kernel maps). Hence we could end up changing rbtree we are currently iterating and mess it up. It's easily reproduced on s390x by running: $ perf record -a -- sleep 3 $ perf buildid-list -i perf.data --with-hits The fix is to compare dso objects instead. Reported-by: Michael Petlan Signed-off-by: Jiri Olsa Acked-by: Adrian Hunter Cc: Andi Kleen Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20151026135130.GA26003@krava.brq.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 71bf711a628c..b4cc7662677e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -680,7 +680,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map, pos->start -= curr_map->start - curr_map->pgoff; if (pos->end) pos->end -= curr_map->start - curr_map->pgoff; - if (curr_map != map) { + if (curr_map->dso != map->dso) { rb_erase_init(&pos->rb_node, root); symbols__insert( &curr_map->dso->symbols[curr_map->type], From ed63f34c026e9a60d17fa750ecdfe3f600d49393 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:12 +0000 Subject: [PATCH 247/260] perf tools: Make perf depend on libbpf By adding libbpf into perf's Makefile, this patch enables perf to build libbpf if libelf is found and neither NO_LIBELF nor NO_LIBBPF is set. The newly introduced code is similar to how libapi and libtraceevent are wired into Makefile.perf. MANIFEST is also updated for 'make perf-*-src-pkg'. Append make_no_libbpf to tools/perf/tests/make. The 'bpf' feature check is appended into default FEATURE_TESTS and FEATURE_DISPLAY, so perf will check the API version of bpf in /path/to/kernel/include/uapi/linux/bpf.h. Which should not fail except when we are trying to port this code to an old kernel. Error messages are also updated to notify users about the lack of BPF support in 'perf record' if libelf is missing or the BPF API check failed. tools/lib/bpf is added to TAG_FOLDERS to allow us to navigate libbpf files when working on perf using tools/perf/tags. Signed-off-by: Wang Nan Acked-by: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-2-git-send-email-wangnan0@huawei.com [ Document NO_LIBBPF in Makefile.perf, noted by Jiri Olsa ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.feature | 6 ++++-- tools/perf/MANIFEST | 3 +++ tools/perf/Makefile.perf | 21 +++++++++++++++++++-- tools/perf/config/Makefile | 19 ++++++++++++++++++- tools/perf/tests/make | 4 +++- 5 files changed, 47 insertions(+), 6 deletions(-) diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 72817e4d5e70..37ff4c9f92f1 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature @@ -53,7 +53,8 @@ FEATURE_TESTS ?= \ libdw-dwarf-unwind \ zlib \ lzma \ - get_cpuid + get_cpuid \ + bpf FEATURE_DISPLAY ?= \ dwarf \ @@ -71,7 +72,8 @@ FEATURE_DISPLAY ?= \ libdw-dwarf-unwind \ zlib \ lzma \ - get_cpuid + get_cpuid \ + bpf # Set FEATURE_CHECK_(C|LD)FLAGS-all for all FEATURE_TESTS features. # If in the future we need per-feature checks/flags for features not diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 9e6bdf5b2df6..39c38cb45b00 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -17,6 +17,7 @@ tools/build tools/arch/x86/include/asm/atomic.h tools/arch/x86/include/asm/rmwcc.h tools/lib/traceevent +tools/lib/bpf tools/lib/api tools/lib/bpf tools/lib/hweight.c @@ -69,6 +70,8 @@ arch/*/lib/memset*.S include/linux/poison.h include/linux/hw_breakpoint.h include/uapi/linux/perf_event.h +include/uapi/linux/bpf.h +include/uapi/linux/bpf_common.h include/uapi/linux/const.h include/uapi/linux/swab.h include/uapi/linux/hw_breakpoint.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 56517d304772..1e2e2d1d26b7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -75,6 +75,8 @@ include config/utilities.mak # Define NO_LZMA if you do not want to support compressed (xz) kernel modules # # Define NO_AUXTRACE if you do not want AUX area tracing support +# +# Define NO_LIBBPF if you do not want BPF support # As per kernel Makefile, avoid funny character set dependencies unexport LC_ALL @@ -145,6 +147,7 @@ AWK = awk LIB_DIR = $(srctree)/tools/lib/api/ TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ +BPF_DIR = $(srctree)/tools/lib/bpf/ # include config/Makefile by default and rule out # non-config cases @@ -180,6 +183,7 @@ strip-libs = $(filter-out -l%,$(1)) ifneq ($(OUTPUT),) TE_PATH=$(OUTPUT) + BPF_PATH=$(OUTPUT) ifneq ($(subdir),) LIB_PATH=$(OUTPUT)/../lib/api/ else @@ -188,6 +192,7 @@ endif else TE_PATH=$(TRACE_EVENT_DIR) LIB_PATH=$(LIB_DIR) + BPF_PATH=$(BPF_DIR) endif LIBTRACEEVENT = $(TE_PATH)libtraceevent.a @@ -199,6 +204,8 @@ LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYN LIBAPI = $(LIB_PATH)libapi.a export LIBAPI +LIBBPF = $(BPF_PATH)libbpf.a + # python extension build directories PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/ PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/ @@ -251,6 +258,9 @@ export PERL_PATH LIB_FILE=$(OUTPUT)libperf.a PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) +ifndef NO_LIBBPF + PERFLIBS += $(LIBBPF) +endif # We choose to avoid "if .. else if .. else .. endif endif" # because maintaining the nesting to match is a pain. If @@ -420,6 +430,13 @@ $(LIBAPI)-clean: $(call QUIET_CLEAN, libapi) $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null +$(LIBBPF): FORCE + $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a + +$(LIBBPF)-clean: + $(call QUIET_CLEAN, libbpf) + $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null + help: @echo 'Perf make targets:' @echo ' doc - make *all* documentation (see below)' @@ -459,7 +476,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html $(DOC_TARGETS): $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) -TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include +TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf TAG_FILES= ../../include/uapi/linux/perf_event.h TAGS: @@ -567,7 +584,7 @@ config-clean: $(call QUIET_CLEAN, config) $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null -clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean +clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete $(Q)$(RM) $(OUTPUT).config-detected diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index ab09adaabc9c..de89ec574361 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -106,6 +106,7 @@ ifdef LIBBABELTRACE FEATURE_CHECK_LDFLAGS-libbabeltrace := $(LIBBABELTRACE_LDFLAGS) -lbabeltrace-ctf endif +FEATURE_CHECK_CFLAGS-bpf = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi # include ARCH specific config -include $(src-perf)/arch/$(ARCH)/Makefile @@ -237,6 +238,7 @@ ifdef NO_LIBELF NO_DEMANGLE := 1 NO_LIBUNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1 + NO_LIBBPF := 1 else ifeq ($(feature-libelf), 0) ifeq ($(feature-glibc), 1) @@ -246,13 +248,14 @@ else LIBC_SUPPORT := 1 endif ifeq ($(LIBC_SUPPORT),1) - msg := $(warning No libelf found, disables 'probe' tool, please install elfutils-libelf-devel/libelf-dev); + msg := $(warning No libelf found, disables 'probe' tool and BPF support in 'perf record', please install elfutils-libelf-devel/libelf-dev); NO_LIBELF := 1 NO_DWARF := 1 NO_DEMANGLE := 1 NO_LIBUNWIND := 1 NO_LIBDW_DWARF_UNWIND := 1 + NO_LIBBPF := 1 else ifneq ($(filter s% -static%,$(LDFLAGS),),) msg := $(error No static glibc found, please install glibc-static); @@ -309,6 +312,13 @@ ifndef NO_LIBELF $(call detected,CONFIG_DWARF) endif # PERF_HAVE_DWARF_REGS endif # NO_DWARF + + ifndef NO_LIBBPF + ifeq ($(feature-bpf), 1) + CFLAGS += -DHAVE_LIBBPF_SUPPORT + $(call detected,CONFIG_LIBBPF) + endif + endif # NO_LIBBPF endif # NO_LIBELF ifeq ($(ARCH),powerpc) @@ -324,6 +334,13 @@ ifndef NO_LIBUNWIND endif endif +ifndef NO_LIBBPF + ifneq ($(feature-bpf), 1) + msg := $(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.) + NO_LIBBPF := 1 + endif +endif + dwarf-post-unwind := 1 dwarf-post-unwind-text := BUG diff --git a/tools/perf/tests/make b/tools/perf/tests/make index ba31c4bd441d..2cbd0c6901e3 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -44,6 +44,7 @@ make_no_libnuma := NO_LIBNUMA=1 make_no_libaudit := NO_LIBAUDIT=1 make_no_libbionic := NO_LIBBIONIC=1 make_no_auxtrace := NO_AUXTRACE=1 +make_no_libbpf := NO_LIBBPF=1 make_tags := tags make_cscope := cscope make_help := help @@ -66,7 +67,7 @@ make_static := LDFLAGS=-static make_minimal := NO_LIBPERL=1 NO_LIBPYTHON=1 NO_NEWT=1 NO_GTK2=1 make_minimal += NO_DEMANGLE=1 NO_LIBELF=1 NO_LIBUNWIND=1 NO_BACKTRACE=1 make_minimal += NO_LIBNUMA=1 NO_LIBAUDIT=1 NO_LIBBIONIC=1 -make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 +make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 NO_LIBBPF=1 # $(run) contains all available tests run := make_pure @@ -94,6 +95,7 @@ run += make_no_libnuma run += make_no_libaudit run += make_no_libbionic run += make_no_auxtrace +run += make_no_libbpf run += make_help run += make_doc run += make_perf_o From 69d262a93a25cf475012ea2e00aeb29f4932c028 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:13 +0000 Subject: [PATCH 248/260] perf ebpf: Add the libbpf glue The 'bpf-loader.[ch]' files are introduced in this patch. Which will be the interface between perf and libbpf. bpf__prepare_load() resides in bpf-loader.c. Following patches will enrich these two files. Signed-off-by: Wang Nan Acked-by: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-loader.c | 57 ++++++++++++++++++++++++++++++++++++ tools/perf/util/bpf-loader.h | 29 ++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 tools/perf/util/bpf-loader.c create mode 100644 tools/perf/util/bpf-loader.h diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c new file mode 100644 index 000000000000..ab56073c5d6e --- /dev/null +++ b/tools/perf/util/bpf-loader.c @@ -0,0 +1,57 @@ +/* + * bpf-loader.c + * + * Copyright (C) 2015 Wang Nan + * Copyright (C) 2015 Huawei Inc. + */ + +#include +#include +#include "perf.h" +#include "debug.h" +#include "bpf-loader.h" + +#define DEFINE_PRINT_FN(name, level) \ +static int libbpf_##name(const char *fmt, ...) \ +{ \ + va_list args; \ + int ret; \ + \ + va_start(args, fmt); \ + ret = veprintf(level, verbose, pr_fmt(fmt), args);\ + va_end(args); \ + return ret; \ +} + +DEFINE_PRINT_FN(warning, 0) +DEFINE_PRINT_FN(info, 0) +DEFINE_PRINT_FN(debug, 1) + +struct bpf_object *bpf__prepare_load(const char *filename) +{ + struct bpf_object *obj; + static bool libbpf_initialized; + + if (!libbpf_initialized) { + libbpf_set_print(libbpf_warning, + libbpf_info, + libbpf_debug); + libbpf_initialized = true; + } + + obj = bpf_object__open(filename); + if (!obj) { + pr_debug("bpf: failed to load %s\n", filename); + return ERR_PTR(-EINVAL); + } + + return obj; +} + +void bpf__clear(void) +{ + struct bpf_object *obj, *tmp; + + bpf_object__for_each_safe(obj, tmp) + bpf_object__close(obj); +} diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h new file mode 100644 index 000000000000..f402d7c8c288 --- /dev/null +++ b/tools/perf/util/bpf-loader.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2015, Wang Nan + * Copyright (C) 2015, Huawei Inc. + */ +#ifndef __BPF_LOADER_H +#define __BPF_LOADER_H + +#include +#include +#include +#include "debug.h" + +struct bpf_object; + +#ifdef HAVE_LIBBPF_SUPPORT +struct bpf_object *bpf__prepare_load(const char *filename); + +void bpf__clear(void); +#else +static inline struct bpf_object * +bpf__prepare_load(const char *filename __maybe_unused) +{ + pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); + return ERR_PTR(-ENOTSUP); +} + +static inline void bpf__clear(void) { } +#endif +#endif From 84c86ca12b2189df751eed7b2d67cb63bc8feda5 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:14 +0000 Subject: [PATCH 249/260] perf tools: Enable passing bpf object file to --event By introducing new rules in tools/perf/util/parse-events.[ly], this patch enables 'perf record --event bpf_file.o' to select events by an eBPF object file. It calls parse_events_load_bpf() to load that file, which uses bpf__prepare_load() and finally calls bpf_object__open() for the object files. After applying this patch, commands like: # perf record --event foo.o sleep become possible. However, at this point it is unable to link any useful things onto the evsel list because the creating of probe points and BPF program attaching have not been implemented. Before real events are possible to be extracted, to avoid perf report error because of empty evsel list, this patch link a dummy evsel. The dummy event related code will be removed when probing and extracting code is ready. Commiter notes: Using it: $ ls -la foo.o ls: cannot access foo.o: No such file or directory $ perf record --event foo.o sleep libbpf: failed to open foo.o: No such file or directory event syntax error: 'foo.o' \___ BPF object file 'foo.o' is invalid (add -v to see detail) Run 'perf list' for a list of valid events Usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events $ $ file /tmp/build/perf/perf.o /tmp/build/perf/perf.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped $ perf record --event /tmp/build/perf/perf.o sleep libbpf: /tmp/build/perf/perf.o is not an eBPF object file event syntax error: '/tmp/build/perf/perf.o' \___ BPF object file '/tmp/build/perf/perf.o' is invalid (add -v to see detail) Run 'perf list' for a list of valid events Usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events $ $ file /tmp/foo.o /tmp/foo.o: ELF 64-bit LSB relocatable, no machine, version 1 (SYSV), not stripped $ perf record --event /tmp/foo.o sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.013 MB perf.data ] $ perf evlist /tmp/foo.o $ perf evlist -v /tmp/foo.o: type: 1, size: 112, config: 0x9, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 $ So, type 1 is PERF_TYPE_SOFTWARE, config 0x9 is PERF_COUNT_SW_DUMMY, ok. $ perf report --stdio Error: The perf.data file has no samples! # To display the perf.data header info, please use --header/--header-only options. # $ Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-4-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 2 ++ tools/perf/util/Build | 1 + tools/perf/util/parse-events.c | 57 ++++++++++++++++++++++++++++++++++ tools/perf/util/parse-events.h | 8 +++++ tools/perf/util/parse-events.l | 3 ++ tools/perf/util/parse-events.y | 18 ++++++++++- 6 files changed, 88 insertions(+), 1 deletion(-) diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 543713422d14..3d4c7c09adea 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -15,6 +15,7 @@ #include "util/run-command.h" #include "util/parse-events.h" #include "util/parse-options.h" +#include "util/bpf-loader.h" #include "util/debug.h" #include #include @@ -385,6 +386,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) status = p->fn(argc, argv, prefix); exit_browser(status); perf_env__exit(&perf_env); + bpf__clear(); if (status) return status & 0xff; diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 9217119c4108..591b3fe3ed49 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-bts.o libperf-y += parse-branch-options.o libperf-y += parse-regs-options.o +libperf-$(CONFIG_LIBBPF) += bpf-loader.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o libperf-$(CONFIG_LIBELF) += probe-event.o diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 72abcf254ccb..a9e1d79d17d7 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -11,6 +11,7 @@ #include "symbol.h" #include "cache.h" #include "header.h" +#include "bpf-loader.h" #include "debug.h" #include #include "parse-events-bison.h" @@ -529,6 +530,62 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, return ret; } +int parse_events_load_bpf_obj(struct parse_events_evlist *data, + struct list_head *list, + struct bpf_object *obj) +{ + int err; + char errbuf[BUFSIZ]; + + if (IS_ERR(obj) || !obj) { + snprintf(errbuf, sizeof(errbuf), + "Internal error: load bpf obj with NULL"); + err = -EINVAL; + goto errout; + } + + /* + * Temporary add a dummy event here so we can check whether + * basic bpf loader works. Following patches will replace + * dummy event by useful evsels. + */ + return parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE, + PERF_COUNT_SW_DUMMY, NULL); +errout: + data->error->help = strdup("(add -v to see detail)"); + data->error->str = strdup(errbuf); + return err; +} + +int parse_events_load_bpf(struct parse_events_evlist *data, + struct list_head *list, + char *bpf_file_name) +{ + struct bpf_object *obj; + + obj = bpf__prepare_load(bpf_file_name); + if (IS_ERR(obj) || !obj) { + char errbuf[BUFSIZ]; + int err; + + err = obj ? PTR_ERR(obj) : -EINVAL; + + if (err == -ENOTSUP) + snprintf(errbuf, sizeof(errbuf), + "BPF support is not compiled"); + else + snprintf(errbuf, sizeof(errbuf), + "BPF object file '%s' is invalid", + bpf_file_name); + + data->error->help = strdup("(add -v to see detail)"); + data->error->str = strdup(errbuf); + return err; + } + + return parse_events_load_bpf_obj(data, list, obj); +} + static int parse_breakpoint_type(const char *type, struct perf_event_attr *attr) { diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 13c9063513eb..765018a17448 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -123,6 +123,14 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, char *sys, char *event, struct parse_events_error *error, struct list_head *head_config); +int parse_events_load_bpf(struct parse_events_evlist *data, + struct list_head *list, + char *bpf_file_name); +/* Provide this function for perf test */ +struct bpf_object; +int parse_events_load_bpf_obj(struct parse_events_evlist *data, + struct list_head *list, + struct bpf_object *obj); int parse_events_add_numeric(struct parse_events_evlist *data, struct list_head *list, u32 type, u64 config, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 8d0de5b2991d..cf330ebf812c 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -115,6 +115,7 @@ do { \ group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event [^,{}/]+ +bpf_object .*\.(o|bpf) num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ @@ -159,6 +160,7 @@ modifier_bp [rwx]{1,3} } {event_pmu} | +{bpf_object} | {event} { BEGIN(INITIAL); REWIND(1); @@ -266,6 +268,7 @@ r{num_raw_hex} { return raw(yyscanner); } {num_hex} { return value(yyscanner, 16); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } +{bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } {name} { return pmu_str_check(yyscanner); } "/" { BEGIN(config); return '/'; } - { return '-'; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index ae6af269f9c9..497f19b20f0b 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -42,6 +42,7 @@ static inc_group_count(struct list_head *list, %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM %token PE_EVENT_NAME %token PE_NAME +%token PE_BPF_OBJECT %token PE_MODIFIER_EVENT PE_MODIFIER_BP %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP @@ -53,6 +54,7 @@ static inc_group_count(struct list_head *list, %type PE_RAW %type PE_TERM %type PE_NAME +%type PE_BPF_OBJECT %type PE_NAME_CACHE_TYPE %type PE_NAME_CACHE_OP_RESULT %type PE_MODIFIER_EVENT @@ -70,6 +72,7 @@ static inc_group_count(struct list_head *list, %type tracepoint_name %type event_legacy_numeric %type event_legacy_raw +%type event_bpf_file %type event_def %type event_mod %type event_name @@ -203,7 +206,8 @@ event_def: event_pmu | event_legacy_mem | event_legacy_tracepoint sep_dc | event_legacy_numeric sep_dc | - event_legacy_raw sep_dc + event_legacy_raw sep_dc | + event_bpf_file event_pmu: PE_NAME '/' event_config '/' @@ -449,6 +453,18 @@ PE_RAW $$ = list; } +event_bpf_file: +PE_BPF_OBJECT +{ + struct parse_events_evlist *data = _data; + struct parse_events_error *error = data->error; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_load_bpf(data, list, $1)); + $$ = list; +} + start_terms: event_config { struct parse_events_terms *data = _data; From aa3abf30bb28addcf593578d37447d42e3f65fc3 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:15 +0000 Subject: [PATCH 250/260] perf tools: Create probe points for BPF programs This patch introduces bpf__{un,}probe() functions to enable callers to create kprobe points based on section names a BPF program. It parses the section names in the program and creates corresponding 'struct perf_probe_event' structures. The parse_perf_probe_command() function is used to do the main parsing work. The resuling 'struct perf_probe_event' is stored into program private data for further using. By utilizing the new probing API, this patch creates probe points during event parsing. To ensure probe points be removed correctly, register an atexit hook so even perf quit through exit() bpf__clear() is still called, so probing points are cleared. Note that bpf_clear() should be registered before bpf__probe() is called, so failure of bpf__probe() can still trigger bpf__clear() to remove probe points which are already probed. strerror style error reporting scaffold is created by this patch. bpf__strerror_probe() is the first error reporting function in bpf-loader.c. Committer note: Trying it: To build a test eBPF object file: I am testing using a script I built from the 'perf test -v LLVM' output: $ cat ~/bin/hello-ebpf export KERNEL_INC_OPTIONS="-nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.8.3/include -I/home/acme/git/linux/arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -I/home/acme/git/linux/include -Iinclude -I/home/acme/git/linux/arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -Iinclude/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h" export WORKING_DIR=/lib/modules/4.2.0/build export CLANG_SOURCE=- export CLANG_OPTIONS=-xc OBJ=/tmp/foo.o rm -f $OBJ echo '__attribute__((section("fork=do_fork"), used)) int fork(void *ctx) {return 0;} char _license[] __attribute__((section("license"), used)) = "GPL";int _version __attribute__((section("version"), used)) = 0x40100;' | \ clang -D__KERNEL__ $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o /tmp/foo.o && file $OBJ --- First asking to put a probe in a function not present in the kernel (misses the initial _): $ perf record --event /tmp/foo.o sleep 1 Probe point 'do_fork' not found. event syntax error: '/tmp/foo.o' \___ You need to check probing points in BPF file (add -v to see detail) Run 'perf list' for a list of valid events Usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events $ --- Now, with "__attribute__((section("fork=_do_fork"), used)): $ grep _do_fork /proc/kallsyms ffffffff81099ab0 T _do_fork $ perf record --event /tmp/foo.o sleep 1 Failed to open kprobe_events: Permission denied event syntax error: '/tmp/foo.o' \___ Permission denied --- Cool, we need to provide some better hints, "kprobe_events" is too low level, one doesn't strictly need to know the precise details of how these things are put in place, so something that shows the command needed to fix the permissions would be more helpful. Lets try as root instead: # perf record --event /tmp/foo.o sleep 1 Lowering default frequency rate to 1000. Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate. [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.013 MB perf.data ] # perf evlist /tmp/foo.o [root@felicio ~]# perf evlist -v /tmp/foo.o: type: 1, size: 112, config: 0x9, { sample_period, sample_freq }: 1000, sample_type: IP|TID|TIME|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, enable_on_exec: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 --- Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-5-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-loader.c | 222 ++++++++++++++++++++++++++++++++- tools/perf/util/bpf-loader.h | 30 +++++ tools/perf/util/parse-events.c | 17 +++ 3 files changed, 268 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index ab56073c5d6e..56f6fe8cf318 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -10,6 +10,8 @@ #include "perf.h" #include "debug.h" #include "bpf-loader.h" +#include "probe-event.h" +#include "probe-finder.h" // for MAX_PROBES #define DEFINE_PRINT_FN(name, level) \ static int libbpf_##name(const char *fmt, ...) \ @@ -27,6 +29,10 @@ DEFINE_PRINT_FN(warning, 0) DEFINE_PRINT_FN(info, 0) DEFINE_PRINT_FN(debug, 1) +struct bpf_prog_priv { + struct perf_probe_event pev; +}; + struct bpf_object *bpf__prepare_load(const char *filename) { struct bpf_object *obj; @@ -52,6 +58,220 @@ void bpf__clear(void) { struct bpf_object *obj, *tmp; - bpf_object__for_each_safe(obj, tmp) + bpf_object__for_each_safe(obj, tmp) { + bpf__unprobe(obj); bpf_object__close(obj); + } +} + +static void +bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused, + void *_priv) +{ + struct bpf_prog_priv *priv = _priv; + + cleanup_perf_probe_events(&priv->pev, 1); + free(priv); +} + +static int +config_bpf_program(struct bpf_program *prog) +{ + struct perf_probe_event *pev = NULL; + struct bpf_prog_priv *priv = NULL; + const char *config_str; + int err; + + config_str = bpf_program__title(prog, false); + if (!config_str) { + pr_debug("bpf: unable to get title for program\n"); + return -EINVAL; + } + + priv = calloc(sizeof(*priv), 1); + if (!priv) { + pr_debug("bpf: failed to alloc priv\n"); + return -ENOMEM; + } + pev = &priv->pev; + + pr_debug("bpf: config program '%s'\n", config_str); + err = parse_perf_probe_command(config_str, pev); + if (err < 0) { + pr_debug("bpf: '%s' is not a valid config string\n", + config_str); + err = -EINVAL; + goto errout; + } + + if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) { + pr_debug("bpf: '%s': group for event is set and not '%s'.\n", + config_str, PERF_BPF_PROBE_GROUP); + err = -EINVAL; + goto errout; + } else if (!pev->group) + pev->group = strdup(PERF_BPF_PROBE_GROUP); + + if (!pev->group) { + pr_debug("bpf: strdup failed\n"); + err = -ENOMEM; + goto errout; + } + + if (!pev->event) { + pr_debug("bpf: '%s': event name is missing\n", + config_str); + err = -EINVAL; + goto errout; + } + pr_debug("bpf: config '%s' is ok\n", config_str); + + err = bpf_program__set_private(prog, priv, bpf_prog_priv__clear); + if (err) { + pr_debug("Failed to set priv for program '%s'\n", config_str); + goto errout; + } + + return 0; + +errout: + if (pev) + clear_perf_probe_event(pev); + free(priv); + return err; +} + +static int bpf__prepare_probe(void) +{ + static int err = 0; + static bool initialized = false; + + /* + * Make err static, so if init failed the first, bpf__prepare_probe() + * fails each time without calling init_probe_symbol_maps multiple + * times. + */ + if (initialized) + return err; + + initialized = true; + err = init_probe_symbol_maps(false); + if (err < 0) + pr_debug("Failed to init_probe_symbol_maps\n"); + probe_conf.max_probes = MAX_PROBES; + return err; +} + +int bpf__probe(struct bpf_object *obj) +{ + int err = 0; + struct bpf_program *prog; + struct bpf_prog_priv *priv; + struct perf_probe_event *pev; + + err = bpf__prepare_probe(); + if (err) { + pr_debug("bpf__prepare_probe failed\n"); + return err; + } + + bpf_object__for_each_program(prog, obj) { + err = config_bpf_program(prog); + if (err) + goto out; + + err = bpf_program__get_private(prog, (void **)&priv); + if (err || !priv) + goto out; + pev = &priv->pev; + + err = convert_perf_probe_events(pev, 1); + if (err < 0) { + pr_debug("bpf_probe: failed to convert perf probe events"); + goto out; + } + + err = apply_perf_probe_events(pev, 1); + if (err < 0) { + pr_debug("bpf_probe: failed to apply perf probe events"); + goto out; + } + } +out: + return err < 0 ? err : 0; +} + +#define EVENTS_WRITE_BUFSIZE 4096 +int bpf__unprobe(struct bpf_object *obj) +{ + int err, ret = 0; + struct bpf_program *prog; + struct bpf_prog_priv *priv; + + bpf_object__for_each_program(prog, obj) { + int i; + + err = bpf_program__get_private(prog, (void **)&priv); + if (err || !priv) + continue; + + for (i = 0; i < priv->pev.ntevs; i++) { + struct probe_trace_event *tev = &priv->pev.tevs[i]; + char name_buf[EVENTS_WRITE_BUFSIZE]; + struct strfilter *delfilter; + + snprintf(name_buf, EVENTS_WRITE_BUFSIZE, + "%s:%s", tev->group, tev->event); + name_buf[EVENTS_WRITE_BUFSIZE - 1] = '\0'; + + delfilter = strfilter__new(name_buf, NULL); + if (!delfilter) { + pr_debug("Failed to create filter for unprobing\n"); + ret = -ENOMEM; + continue; + } + + err = del_perf_probe_events(delfilter); + strfilter__delete(delfilter); + if (err) { + pr_debug("Failed to delete %s\n", name_buf); + ret = err; + continue; + } + } + } + return ret; +} + +#define bpf__strerror_head(err, buf, size) \ + char sbuf[STRERR_BUFSIZE], *emsg;\ + if (!size)\ + return 0;\ + if (err < 0)\ + err = -err;\ + emsg = strerror_r(err, sbuf, sizeof(sbuf));\ + switch (err) {\ + default:\ + scnprintf(buf, size, "%s", emsg);\ + break; + +#define bpf__strerror_entry(val, fmt...)\ + case val: {\ + scnprintf(buf, size, fmt);\ + break;\ + } + +#define bpf__strerror_end(buf, size)\ + }\ + buf[size - 1] = '\0'; + +int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, + int err, char *buf, size_t size) +{ + bpf__strerror_head(err, buf, size); + bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'"); + bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n"); + bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n"); + bpf__strerror_end(buf, size); + return 0; } diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index f402d7c8c288..b819622dc7ce 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -11,11 +11,18 @@ #include "debug.h" struct bpf_object; +#define PERF_BPF_PROBE_GROUP "perf_bpf_probe" #ifdef HAVE_LIBBPF_SUPPORT struct bpf_object *bpf__prepare_load(const char *filename); void bpf__clear(void); + +int bpf__probe(struct bpf_object *obj); +int bpf__unprobe(struct bpf_object *obj); +int bpf__strerror_probe(struct bpf_object *obj, int err, + char *buf, size_t size); + #else static inline struct bpf_object * bpf__prepare_load(const char *filename __maybe_unused) @@ -25,5 +32,28 @@ bpf__prepare_load(const char *filename __maybe_unused) } static inline void bpf__clear(void) { } + +static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} +static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;} + +static inline int +__bpf_strerror(char *buf, size_t size) +{ + if (!size) + return 0; + strncpy(buf, + "ERROR: eBPF object loading is disabled during compiling.\n", + size); + buf[size - 1] = '\0'; + return 0; +} + +static inline int +bpf__strerror_probe(struct bpf_object *obj __maybe_unused, + int err __maybe_unused, + char *buf, size_t size) +{ + return __bpf_strerror(buf, size); +} #endif #endif diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index a9e1d79d17d7..10a946779f46 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -536,6 +536,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, { int err; char errbuf[BUFSIZ]; + static bool registered_unprobe_atexit = false; if (IS_ERR(obj) || !obj) { snprintf(errbuf, sizeof(errbuf), @@ -544,6 +545,22 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, goto errout; } + /* + * Register atexit handler before calling bpf__probe() so + * bpf__probe() don't need to unprobe probe points its already + * created when failure. + */ + if (!registered_unprobe_atexit) { + atexit(bpf__clear); + registered_unprobe_atexit = true; + } + + err = bpf__probe(obj); + if (err) { + bpf__strerror_probe(obj, err, errbuf, sizeof(errbuf)); + goto errout; + } + /* * Temporary add a dummy event here so we can check whether * basic bpf loader works. Following patches will replace From 1e5e3ee8ff3877db6943032b54a6ac21c095affd Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:16 +0000 Subject: [PATCH 251/260] perf tools: Load eBPF object into kernel This patch utilizes bpf_object__load() provided by libbpf to load all objects into kernel. Committer notes: Testing it: When using an incorrect kernel version number, i.e., having this in your eBPF proggie: int _version __attribute__((section("version"), used)) = 0x40100; For a 4.3.0-rc6+ kernel, say, this happens and needs checking at event parsing time, to provide a better error report to the user: # perf record --event /tmp/foo.o sleep 1 libbpf: load bpf program failed: Invalid argument libbpf: -- BEGIN DUMP LOG --- libbpf: libbpf: -- END LOG -- libbpf: failed to load program 'fork=_do_fork' libbpf: failed to load object '/tmp/foo.o' event syntax error: '/tmp/foo.o' \___ Invalid argument: Are you root and runing a CONFIG_BPF_SYSCALL kernel? (add -v to see detail) Run 'perf list' for a list of valid events Usage: perf record [] [] or: perf record [] -- [] -e, --event event selector. use 'perf list' to list available events If we instead make it match, i.e. use 0x40300 on this v4.3.0-rc6+ kernel, the whole process goes thru: # perf record --event /tmp/foo.o -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.202 MB perf.data ] # perf evlist -v /tmp/foo.o: type: 1, size: 112, config: 0x9, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|CPU|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 # Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-6-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-loader.c | 22 ++++++++++++++++++++++ tools/perf/util/bpf-loader.h | 11 +++++++++++ tools/perf/util/parse-events.c | 6 ++++++ 3 files changed, 39 insertions(+) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 56f6fe8cf318..727955858d00 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -243,6 +243,18 @@ int bpf__unprobe(struct bpf_object *obj) return ret; } +int bpf__load(struct bpf_object *obj) +{ + int err; + + err = bpf_object__load(obj); + if (err) { + pr_debug("bpf: load objects failed\n"); + return err; + } + return 0; +} + #define bpf__strerror_head(err, buf, size) \ char sbuf[STRERR_BUFSIZE], *emsg;\ if (!size)\ @@ -275,3 +287,13 @@ int bpf__strerror_probe(struct bpf_object *obj __maybe_unused, bpf__strerror_end(buf, size); return 0; } + +int bpf__strerror_load(struct bpf_object *obj __maybe_unused, + int err, char *buf, size_t size) +{ + bpf__strerror_head(err, buf, size); + bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?", + emsg) + bpf__strerror_end(buf, size); + return 0; +} diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index b819622dc7ce..b091ceb19c48 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -23,6 +23,9 @@ int bpf__unprobe(struct bpf_object *obj); int bpf__strerror_probe(struct bpf_object *obj, int err, char *buf, size_t size); +int bpf__load(struct bpf_object *obj); +int bpf__strerror_load(struct bpf_object *obj, int err, + char *buf, size_t size); #else static inline struct bpf_object * bpf__prepare_load(const char *filename __maybe_unused) @@ -35,6 +38,7 @@ static inline void bpf__clear(void) { } static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;} +static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } static inline int __bpf_strerror(char *buf, size_t size) @@ -55,5 +59,12 @@ bpf__strerror_probe(struct bpf_object *obj __maybe_unused, { return __bpf_strerror(buf, size); } + +static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused, + int err __maybe_unused, + char *buf, size_t size) +{ + return __bpf_strerror(buf, size); +} #endif #endif diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 10a946779f46..c3aabeb63e88 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -561,6 +561,12 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, goto errout; } + err = bpf__load(obj); + if (err) { + bpf__strerror_load(obj, err, errbuf, sizeof(errbuf)); + goto errout; + } + /* * Temporary add a dummy event here so we can check whether * basic bpf loader works. Following patches will replace From 4edf30e39e6cff32390eaff6a1508969b3cd967b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:17 +0000 Subject: [PATCH 252/260] perf bpf: Collect perf_evsel in BPF object files This patch creates a 'struct perf_evsel' for every probe in a BPF object file(s) and fills 'struct evlist' with them. The previously introduced dummy event is now removed. After this patch, the following command: # perf record --event filter.o ls Can trace on each of the probes defined in filter.o. The core of this patch is bpf__foreach_tev(), which calls a callback function for each 'struct probe_trace_event' event for a bpf program with each associated file descriptors. The add_bpf_event() callback creates evsels by calling parse_events_add_tracepoint(). Since bpf-loader.c will not be built if libbpf is turned off, an empty bpf__foreach_tev() is defined in bpf-loader.h to avoid build errors. Committer notes: Before: # /tmp/oldperf record --event /tmp/foo.o -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.198 MB perf.data ] # perf evlist /tmp/foo.o # perf evlist -v /tmp/foo.o: type: 1, size: 112, config: 0x9, { sample_period, sample_freq }: 4000, sample_type: IP|TID|TIME|CPU|PERIOD, disabled: 1, inherit: 1, mmap: 1, comm: 1, freq: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 I.e. we create just the PERF_TYPE_SOFTWARE (type: 1), PERF_COUNT_SW_DUMMY(config 0x9) event, now, with this patch: # perf record --event /tmp/foo.o -a usleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.210 MB perf.data ] # perf evlist -v perf_bpf_probe:fork: type: 2, size: 112, config: 0x6bd, { sample_period, sample_freq }: 1, sample_type: IP|TID|TIME|CPU|PERIOD|RAW, disabled: 1, inherit: 1, mmap: 1, comm: 1, task: 1, sample_id_all: 1, exclude_guest: 1, mmap2: 1, comm_exec: 1 # We now have a PERF_TYPE_SOFTWARE (type: 1), but the config states 0x6bd, which is how, after setting up the event via the kprobes interface, the 'perf_bpf_probe:fork' event is accessible via the perf_event_open syscall. This is all transient, as soon as the 'perf record' session ends, these probes will go away. To see how it looks like, lets try doing a neverending session, one that expects a control+C to end: # perf record --event /tmp/foo.o -a So, with that in place, we can use 'perf probe' to see what is in place: # perf probe -l perf_bpf_probe:fork (on _do_fork@acme/git/linux/kernel/fork.c) We also can use debugfs: [root@felicio ~]# cat /sys/kernel/debug/tracing/kprobe_events p:perf_bpf_probe/fork _text+638512 Ok, now lets stop and see if we got some forks: [root@felicio linux]# perf record --event /tmp/foo.o -a ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.325 MB perf.data (111 samples) ] [root@felicio linux]# perf script sshd 1271 [003] 81797.507678: perf_bpf_probe:fork: (ffffffff8109be30) sshd 18309 [000] 81797.524917: perf_bpf_probe:fork: (ffffffff8109be30) sshd 18309 [001] 81799.381603: perf_bpf_probe:fork: (ffffffff8109be30) sshd 18309 [001] 81799.408635: perf_bpf_probe:fork: (ffffffff8109be30) Sure enough, we have 111 forks :-) Callchains seems to work as well: # perf report --stdio --no-child # To display the perf.data header info, please use --header/--header-only options. # # Total Lost Samples: 0 # # Samples: 562 of event 'perf_bpf_probe:fork' # Event count (approx.): 562 # # Overhead Command Shared Object Symbol # ........ ........ ................ ............ # 44.66% sh [kernel.vmlinux] [k] _do_fork | ---_do_fork entry_SYSCALL_64_fastpath __libc_fork make_child 26.16% make [kernel.vmlinux] [k] _do_fork # Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-7-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf-loader.c | 40 ++++++++++++++++++++++++++ tools/perf/util/bpf-loader.h | 14 +++++++++ tools/perf/util/parse-events.c | 52 +++++++++++++++++++++++++++++----- 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 727955858d00..aa784a498c48 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -255,6 +255,46 @@ int bpf__load(struct bpf_object *obj) return 0; } +int bpf__foreach_tev(struct bpf_object *obj, + bpf_prog_iter_callback_t func, + void *arg) +{ + struct bpf_program *prog; + int err; + + bpf_object__for_each_program(prog, obj) { + struct probe_trace_event *tev; + struct perf_probe_event *pev; + struct bpf_prog_priv *priv; + int i, fd; + + err = bpf_program__get_private(prog, + (void **)&priv); + if (err || !priv) { + pr_debug("bpf: failed to get private field\n"); + return -EINVAL; + } + + pev = &priv->pev; + for (i = 0; i < pev->ntevs; i++) { + tev = &pev->tevs[i]; + + fd = bpf_program__fd(prog); + if (fd < 0) { + pr_debug("bpf: failed to get file descriptor\n"); + return fd; + } + + err = (*func)(tev, fd, arg); + if (err) { + pr_debug("bpf: call back failed, stop iterate\n"); + return err; + } + } + } + return 0; +} + #define bpf__strerror_head(err, buf, size) \ char sbuf[STRERR_BUFSIZE], *emsg;\ if (!size)\ diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index b091ceb19c48..a8f25ee06fc5 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -8,11 +8,15 @@ #include #include #include +#include "probe-event.h" #include "debug.h" struct bpf_object; #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" +typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, + int fd, void *arg); + #ifdef HAVE_LIBBPF_SUPPORT struct bpf_object *bpf__prepare_load(const char *filename); @@ -26,6 +30,8 @@ int bpf__strerror_probe(struct bpf_object *obj, int err, int bpf__load(struct bpf_object *obj); int bpf__strerror_load(struct bpf_object *obj, int err, char *buf, size_t size); +int bpf__foreach_tev(struct bpf_object *obj, + bpf_prog_iter_callback_t func, void *arg); #else static inline struct bpf_object * bpf__prepare_load(const char *filename __maybe_unused) @@ -40,6 +46,14 @@ static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;} static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0;} static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; } +static inline int +bpf__foreach_tev(struct bpf_object *obj __maybe_unused, + bpf_prog_iter_callback_t func __maybe_unused, + void *arg __maybe_unused) +{ + return 0; +} + static inline int __bpf_strerror(char *buf, size_t size) { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index c3aabeb63e88..d97b03710331 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -530,12 +530,49 @@ static int add_tracepoint_multi_sys(struct list_head *list, int *idx, return ret; } +struct __add_bpf_event_param { + struct parse_events_evlist *data; + struct list_head *list; +}; + +static int add_bpf_event(struct probe_trace_event *tev, int fd, + void *_param) +{ + LIST_HEAD(new_evsels); + struct __add_bpf_event_param *param = _param; + struct parse_events_evlist *evlist = param->data; + struct list_head *list = param->list; + int err; + + pr_debug("add bpf event %s:%s and attach bpf program %d\n", + tev->group, tev->event, fd); + + err = parse_events_add_tracepoint(&new_evsels, &evlist->idx, tev->group, + tev->event, evlist->error, NULL); + if (err) { + struct perf_evsel *evsel, *tmp; + + pr_debug("Failed to add BPF event %s:%s\n", + tev->group, tev->event); + list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { + list_del(&evsel->node); + perf_evsel__delete(evsel); + } + return err; + } + pr_debug("adding %s:%s\n", tev->group, tev->event); + + list_splice(&new_evsels, list); + return 0; +} + int parse_events_load_bpf_obj(struct parse_events_evlist *data, struct list_head *list, struct bpf_object *obj) { int err; char errbuf[BUFSIZ]; + struct __add_bpf_event_param param = {data, list}; static bool registered_unprobe_atexit = false; if (IS_ERR(obj) || !obj) { @@ -567,13 +604,14 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data, goto errout; } - /* - * Temporary add a dummy event here so we can check whether - * basic bpf loader works. Following patches will replace - * dummy event by useful evsels. - */ - return parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE, - PERF_COUNT_SW_DUMMY, NULL); + err = bpf__foreach_tev(obj, add_bpf_event, ¶m); + if (err) { + snprintf(errbuf, sizeof(errbuf), + "Attach events in BPF object failed"); + goto errout; + } + + return 0; errout: data->error->help = strdup("(add -v to see detail)"); data->error->str = strdup(errbuf); From 729a78417a7b5c1f59e15d21a1900758375c4647 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 29 Oct 2015 11:48:18 -0300 Subject: [PATCH 253/260] perf trace: Add cmd string table to decode sys_bpf first arg # perf trace -e bpf perf record -e /tmp/foo.o -a 362.779 (0.130 ms): perf/3451 bpf(cmd: PROG_LOAD, uattr: 0x7ffe9a6825d0, size: 48) = 3 Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-2b0nknu53baz9e0wj4thcdd8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 93b80f12f35e..c783d8fd3a80 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -585,6 +585,12 @@ static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct sysc #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op +static const char *bpf_cmd[] = { + "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", + "MAP_GET_NEXT_KEY", "PROG_LOAD", +}; +static DEFINE_STRARRAY(bpf_cmd); + static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", }; static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1); @@ -1011,6 +1017,7 @@ static struct syscall_fmt { .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ [1] = SCA_ACCMODE, /* mode */ }, }, { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, + { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), }, { .name = "brk", .hexret = true, .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, }, { .name = "chdir", .errmsg = true, From dc323ce8e72d6d1beb9af9bbd29c4d55ce3d7fb0 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 31 Aug 2015 18:41:13 +0200 Subject: [PATCH 254/260] perf script: Enable printing of branch stack This patch improves perf script by enabling printing of the branch stack via the 'brstack' and 'brstacksym' arguments to the field selection option -F. The option is off by default and operates only if the perf.data file has branch stack content. The branches are printed in to/from pairs. The most recent branch is printed first. The number of branch entries vary based on the underlying hardware and filtering used. The brstack prints FROM/TO addresses in raw hexadecimal format. The brstacksym prints FROM/TO addresses in symbolic form wherever possible. $ perf script -F ip,brstack 5d3000 0x401aa0/0x5d2000/M/-/-/-/0 ... $ perf script -F ip,brstacksym 4011e0 noploop+0x0/noploop+0x0/P/-/-/0 The notation F/T/M/X/A/C describes the attributes of the branch. F=from, T=to, M/P=misprediction/prediction, X=TSX, A=TSX abort, C=cycles (SKL) Signed-off-by: Stephane Eranian Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Yuanfang Chen Link: http://lkml.kernel.org/r/1441039273-16260-5-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 14 +++- tools/perf/builtin-script.c | 82 +++++++++++++++++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index b3b42f9285df..382ddfb45d1d 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -112,11 +112,11 @@ OPTIONS --debug-mode:: Do various checks like samples ordering and lost events. --f:: +-F:: --fields:: Comma separated list of fields to print. Options are: comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, - srcline, period, iregs, flags. + srcline, period, iregs, brstack, brstacksym, flags. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace @@ -175,6 +175,16 @@ OPTIONS Finally, a user may not set fields to none for all event types. i.e., -f "" is not allowed. + The brstack output includes branch related information with raw addresses using the + /v/v/v/v/ syntax in the following order: + FROM: branch source instruction + TO : branch target instruction + M/P/-: M=branch target mispredicted or branch direction was mispredicted, P=target predicted or direction predicted, -=not supported + X/- : X=branch inside a transactional region, -=not in transaction region or not supported + A/- : A=TSX abort entry, -=not aborted region or not supported + + The brstacksym is identical to brstack, except that the FROM and TO addresses are printed in a symbolic form if possible. + -k:: --vmlinux=:: vmlinux pathname diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 278acb22f029..72b5deb4bd79 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -51,6 +51,8 @@ enum perf_output_field { PERF_OUTPUT_SRCLINE = 1U << 12, PERF_OUTPUT_PERIOD = 1U << 13, PERF_OUTPUT_IREGS = 1U << 14, + PERF_OUTPUT_BRSTACK = 1U << 15, + PERF_OUTPUT_BRSTACKSYM = 1U << 16, }; struct output_option { @@ -72,6 +74,8 @@ struct output_option { {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, {.str = "period", .field = PERF_OUTPUT_PERIOD}, {.str = "iregs", .field = PERF_OUTPUT_IREGS}, + {.str = "brstack", .field = PERF_OUTPUT_BRSTACK}, + {.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, }; /* default set to maintain compatibility with current format */ @@ -425,6 +429,77 @@ static void print_sample_start(struct perf_sample *sample, } } +static inline char +mispred_str(struct branch_entry *br) +{ + if (!(br->flags.mispred || br->flags.predicted)) + return '-'; + + return br->flags.predicted ? 'P' : 'M'; +} + +static void print_sample_brstack(union perf_event *event __maybe_unused, + struct perf_sample *sample, + struct thread *thread __maybe_unused, + struct perf_event_attr *attr __maybe_unused) +{ + struct branch_stack *br = sample->branch_stack; + u64 i; + + if (!(br && br->nr)) + return; + + for (i = 0; i < br->nr; i++) { + printf(" 0x%"PRIx64"/0x%"PRIx64"/%c/%c/%c/%d ", + br->entries[i].from, + br->entries[i].to, + mispred_str( br->entries + i), + br->entries[i].flags.in_tx? 'X' : '-', + br->entries[i].flags.abort? 'A' : '-', + br->entries[i].flags.cycles); + } +} + +static void print_sample_brstacksym(union perf_event *event __maybe_unused, + struct perf_sample *sample, + struct thread *thread __maybe_unused, + struct perf_event_attr *attr __maybe_unused) +{ + struct branch_stack *br = sample->branch_stack; + struct addr_location alf, alt; + u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + u64 i, from, to; + + if (!(br && br->nr)) + return; + + for (i = 0; i < br->nr; i++) { + + memset(&alf, 0, sizeof(alf)); + memset(&alt, 0, sizeof(alt)); + from = br->entries[i].from; + to = br->entries[i].to; + + thread__find_addr_map(thread, cpumode, MAP__FUNCTION, from, &alf); + if (alf.map) + alf.sym = map__find_symbol(alf.map, alf.addr, NULL); + + thread__find_addr_map(thread, cpumode, MAP__FUNCTION, to, &alt); + if (alt.map) + alt.sym = map__find_symbol(alt.map, alt.addr, NULL); + + symbol__fprintf_symname_offs(alf.sym, &alf, stdout); + putchar('/'); + symbol__fprintf_symname_offs(alt.sym, &alt, stdout); + printf("/%c/%c/%c/%d ", + mispred_str( br->entries + i), + br->entries[i].flags.in_tx? 'X' : '-', + br->entries[i].flags.abort? 'A' : '-', + br->entries[i].flags.cycles); + } +} + + static void print_sample_addr(union perf_event *event, struct perf_sample *sample, struct thread *thread, @@ -560,6 +635,11 @@ static void process_event(union perf_event *event, struct perf_sample *sample, if (PRINT_FIELD(IREGS)) print_sample_iregs(event, sample, thread, attr); + if (PRINT_FIELD(BRSTACK)) + print_sample_brstack(event, sample, thread, attr); + else if (PRINT_FIELD(BRSTACKSYM)) + print_sample_brstacksym(event, sample, thread, attr); + printf("\n"); } @@ -1681,7 +1761,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "comma separated output fields prepend with 'type:'. " "Valid types: hw,sw,trace,raw. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," - "addr,symoff,period,iregs,flags", parse_output_fields), + "addr,symoff,period,iregs,brstack,brstacksym,flags", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", From 50f1e6d0431d3343cb506037c43ce623bd15581f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 28 Oct 2015 21:44:50 +0100 Subject: [PATCH 255/260] perf tools: Make sure fixdep is built before libbpf While doing 'make -C tools/perf build-test': LD fixdep-in.o LINK fixdep /bin/sh: /home/acme/git/linux/tools/build/fixdep: Permission denied make[6]: *** [bpf.o] Error 1 make[5]: *** [libbpf-in.o] Error 2 make[4]: *** [/home/acme/git/linux/tools/lib/bpf/libbpf.a] Error 2 make[4]: *** Waiting for unfinished jobs.... The fixdep tool needs to be built as the first binary. Libraries are built in paralel, so each of them needs to depend on fixdep target. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Jiri Olsa Cc: Wang Nan Link: http://lkml.kernel.org/r/20151028204450.GA25553@krava.redhat.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 1e2e2d1d26b7..0d19d5447d6c 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -430,7 +430,7 @@ $(LIBAPI)-clean: $(call QUIET_CLEAN, libapi) $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null -$(LIBBPF): FORCE +$(LIBBPF): fixdep FORCE $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a $(LIBBPF)-clean: From 1f45b1d49073541947193bd7dac9e904142576aa Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:18 +0000 Subject: [PATCH 256/260] perf bpf: Attach eBPF filter to perf event This is the final patch which makes basic BPF filter work. After applying this patch, users are allowed to use BPF filter like: # perf record --event ./hello_world.o ls A bpf_fd field is appended to 'struct evsel', and setup during the callback function add_bpf_event() for each 'probe_trace_event'. PERF_EVENT_IOC_SET_BPF ioctl is used to attach eBPF program to a newly created perf event. The file descriptor of the eBPF program is passed to perf record using previous patches, and stored into evsel->bpf_fd. It is possible that different perf event are created for one kprobe events for different CPUs. In this case, when trying to call the ioctl, EEXIST will be return. This patch doesn't treat it as an error. Committer note: The bpf proggie used so far: __attribute__((section("fork=_do_fork"), used)) int fork(void *ctx) { return 0; } char _license[] __attribute__((section("license"), used)) = "GPL"; int _version __attribute__((section("version"), used)) = 0x40300; failed to produce any samples, even with forks happening and it being running in system wide mode. That is because now the filter is being associated, and the code above always returns zero, meaning that all forks will be probed but filtered away ;-/ Change it to 'return 1;' instead and after that: # trace --no-syscalls --event /tmp/foo.o 0.000 perf_bpf_probe:fork:(ffffffff8109be30)) 2.333 perf_bpf_probe:fork:(ffffffff8109be30)) 3.725 perf_bpf_probe:fork:(ffffffff8109be30)) 4.550 perf_bpf_probe:fork:(ffffffff8109be30)) ^C# And it works with all tools, including 'perf trace'. Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-8-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 17 +++++++++++++++++ tools/perf/util/evsel.h | 1 + tools/perf/util/parse-events.c | 6 ++++++ 3 files changed, 24 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 3ac4ee9c6a6e..397fb4ed3c97 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -208,6 +208,7 @@ void perf_evsel__init(struct perf_evsel *evsel, evsel->unit = ""; evsel->scale = 1.0; evsel->evlist = NULL; + evsel->bpf_fd = -1; INIT_LIST_HEAD(&evsel->node); INIT_LIST_HEAD(&evsel->config_terms); perf_evsel__object.init(evsel); @@ -1356,6 +1357,22 @@ retry_open: err); goto try_fallback; } + + if (evsel->bpf_fd >= 0) { + int evt_fd = FD(evsel, cpu, thread); + int bpf_fd = evsel->bpf_fd; + + err = ioctl(evt_fd, + PERF_EVENT_IOC_SET_BPF, + bpf_fd); + if (err && errno != EEXIST) { + pr_err("failed to attach bpf fd %d: %s\n", + bpf_fd, strerror(errno)); + err = -EINVAL; + goto out_close; + } + } + set_rlimit = NO_CHANGE; /* diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1e8ff1906f71..0e49bd742c63 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -123,6 +123,7 @@ struct perf_evsel { char *group_name; bool cmdline_group_boundary; struct list_head config_terms; + int bpf_fd; }; union u64_swap { diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d97b03710331..cee8c619ec7e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -542,6 +542,7 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, struct __add_bpf_event_param *param = _param; struct parse_events_evlist *evlist = param->data; struct list_head *list = param->list; + struct perf_evsel *pos; int err; pr_debug("add bpf event %s:%s and attach bpf program %d\n", @@ -562,6 +563,11 @@ static int add_bpf_event(struct probe_trace_event *tev, int fd, } pr_debug("adding %s:%s\n", tev->group, tev->event); + list_for_each_entry(pos, &new_evsels, node) { + pr_debug("adding %s:%s to %p\n", + tev->group, tev->event, pos); + pos->bpf_fd = fd; + } list_splice(&new_evsels, list); return 0; } From 71dc2326252ff1bcdddc05db03c0f831d16c9447 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:19 +0000 Subject: [PATCH 257/260] perf record: Add clang options for compiling BPF scripts Although previous patch allows setting BPF compiler related options in perfconfig, on some ad-hoc situation it still requires passing options through cmdline. This patch introduces 2 options to 'perf record' for this propose: --clang-path and --clang-opt. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-9-git-send-email-wangnan0@huawei.com [ Add the new options to the 'record' man page ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 6 ++++++ tools/perf/builtin-record.c | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 7ff6a9d0ea0d..e630a7d2c348 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -314,6 +314,12 @@ This option sets the time out limit. The default value is 500 ms. Record context switch events i.e. events of type PERF_RECORD_SWITCH or PERF_RECORD_SWITCH_CPU_WIDE. +--clang-path:: +Path to clang binary to use for compiling BPF scriptlets. + +--clang-opt:: +Options passed to clang when compiling BPF scriptlets. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index de02267c73d8..199fc31e3919 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -31,6 +31,7 @@ #include "util/auxtrace.h" #include "util/parse-branch-options.h" #include "util/parse-regs-options.h" +#include "util/llvm-utils.h" #include #include @@ -1112,6 +1113,12 @@ struct option __record_options[] = { "per thread proc mmap processing timeout in ms"), OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, "Record context switch events"), +#ifdef HAVE_LIBBPF_SUPPORT + OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", + "clang binary to use for compiling BPF scriptlets"), + OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", + "options passed to clang when compiling BPF scriptlets"), +#endif OPT_END() }; From d509db0473e40134286271b1d1adadccf42ac467 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 14 Oct 2015 12:41:20 +0000 Subject: [PATCH 258/260] perf tools: Compile scriptlets to BPF objects when passing '.c' to --event This patch provides infrastructure for passing source files to --event directly using: # perf record --event bpf-file.c command This patch does following works: 1) Allow passing '.c' file to '--event'. parse_events_load_bpf() is expanded to allow caller tell it whether the passed file is source file or object. 2) llvm__compile_bpf() is called to compile the '.c' file, the result is saved into memory. Use bpf_object__open_buffer() to load the in-memory object. Introduces a bpf-script-example.c so we can manually test it: # perf record --clang-opt "-DLINUX_VERSION_CODE=0x40200" --event ./bpf-script-example.c sleep 1 Note that '--clang-opt' must put before '--event'. Futher patches will merge it into a testcase so can be tested automatically. Signed-off-by: Wang Nan Acked-by: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1444826502-49291-10-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/bpf-script-example.c | 44 +++++++++++++++++++++++++++ tools/perf/util/bpf-loader.c | 17 +++++++++-- tools/perf/util/bpf-loader.h | 5 +-- tools/perf/util/parse-events.c | 5 +-- tools/perf/util/parse-events.h | 3 +- tools/perf/util/parse-events.l | 3 ++ tools/perf/util/parse-events.y | 15 +++++++-- 7 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 tools/perf/tests/bpf-script-example.c diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c new file mode 100644 index 000000000000..410a70b93b93 --- /dev/null +++ b/tools/perf/tests/bpf-script-example.c @@ -0,0 +1,44 @@ +#ifndef LINUX_VERSION_CODE +# error Need LINUX_VERSION_CODE +# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' +#endif +#define BPF_ANY 0 +#define BPF_MAP_TYPE_ARRAY 2 +#define BPF_FUNC_map_lookup_elem 1 +#define BPF_FUNC_map_update_elem 2 + +static void *(*bpf_map_lookup_elem)(void *map, void *key) = + (void *) BPF_FUNC_map_lookup_elem; +static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = + (void *) BPF_FUNC_map_update_elem; + +struct bpf_map_def { + unsigned int type; + unsigned int key_size; + unsigned int value_size; + unsigned int max_entries; +}; + +#define SEC(NAME) __attribute__((section(NAME), used)) +struct bpf_map_def SEC("maps") flip_table = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1, +}; + +SEC("func=sys_epoll_pwait") +int bpf_func__sys_epoll_pwait(void *ctx) +{ + int ind =0; + int *flag = bpf_map_lookup_elem(&flip_table, &ind); + int new_flag; + if (!flag) + return 0; + /* flip flag and store back */ + new_flag = !*flag; + bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); + return new_flag; +} +char _license[] SEC("license") = "GPL"; +int _version SEC("version") = LINUX_VERSION_CODE; diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index aa784a498c48..ba6f7526b282 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -12,6 +12,7 @@ #include "bpf-loader.h" #include "probe-event.h" #include "probe-finder.h" // for MAX_PROBES +#include "llvm-utils.h" #define DEFINE_PRINT_FN(name, level) \ static int libbpf_##name(const char *fmt, ...) \ @@ -33,7 +34,7 @@ struct bpf_prog_priv { struct perf_probe_event pev; }; -struct bpf_object *bpf__prepare_load(const char *filename) +struct bpf_object *bpf__prepare_load(const char *filename, bool source) { struct bpf_object *obj; static bool libbpf_initialized; @@ -45,7 +46,19 @@ struct bpf_object *bpf__prepare_load(const char *filename) libbpf_initialized = true; } - obj = bpf_object__open(filename); + if (source) { + int err; + void *obj_buf; + size_t obj_buf_sz; + + err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz); + if (err) + return ERR_PTR(err); + obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename); + free(obj_buf); + } else + obj = bpf_object__open(filename); + if (!obj) { pr_debug("bpf: failed to load %s\n", filename); return ERR_PTR(-EINVAL); diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index a8f25ee06fc5..ccd8d7fd79d3 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -18,7 +18,7 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev, int fd, void *arg); #ifdef HAVE_LIBBPF_SUPPORT -struct bpf_object *bpf__prepare_load(const char *filename); +struct bpf_object *bpf__prepare_load(const char *filename, bool source); void bpf__clear(void); @@ -34,7 +34,8 @@ int bpf__foreach_tev(struct bpf_object *obj, bpf_prog_iter_callback_t func, void *arg); #else static inline struct bpf_object * -bpf__prepare_load(const char *filename __maybe_unused) +bpf__prepare_load(const char *filename __maybe_unused, + bool source __maybe_unused) { pr_debug("ERROR: eBPF object loading is disabled during compiling.\n"); return ERR_PTR(-ENOTSUP); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index cee8c619ec7e..bee60583839a 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -626,11 +626,12 @@ errout: int parse_events_load_bpf(struct parse_events_evlist *data, struct list_head *list, - char *bpf_file_name) + char *bpf_file_name, + bool source) { struct bpf_object *obj; - obj = bpf__prepare_load(bpf_file_name); + obj = bpf__prepare_load(bpf_file_name, source); if (IS_ERR(obj) || !obj) { char errbuf[BUFSIZ]; int err; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 765018a17448..f1a6db107241 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -125,7 +125,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx, struct list_head *head_config); int parse_events_load_bpf(struct parse_events_evlist *data, struct list_head *list, - char *bpf_file_name); + char *bpf_file_name, + bool source); /* Provide this function for perf test */ struct bpf_object; int parse_events_load_bpf_obj(struct parse_events_evlist *data, diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index cf330ebf812c..58c5831ffd5c 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -116,6 +116,7 @@ group [^,{}/]*[{][^}]*[}][^,{}/]* event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* event [^,{}/]+ bpf_object .*\.(o|bpf) +bpf_source .*\.c num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ @@ -161,6 +162,7 @@ modifier_bp [rwx]{1,3} {event_pmu} | {bpf_object} | +{bpf_source} | {event} { BEGIN(INITIAL); REWIND(1); @@ -269,6 +271,7 @@ r{num_raw_hex} { return raw(yyscanner); } {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } {bpf_object} { return str(yyscanner, PE_BPF_OBJECT); } +{bpf_source} { return str(yyscanner, PE_BPF_SOURCE); } {name} { return pmu_str_check(yyscanner); } "/" { BEGIN(config); return '/'; } - { return '-'; } diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 497f19b20f0b..ad379968d4c1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -42,7 +42,7 @@ static inc_group_count(struct list_head *list, %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM %token PE_EVENT_NAME %token PE_NAME -%token PE_BPF_OBJECT +%token PE_BPF_OBJECT PE_BPF_SOURCE %token PE_MODIFIER_EVENT PE_MODIFIER_BP %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP @@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list, %type PE_TERM %type PE_NAME %type PE_BPF_OBJECT +%type PE_BPF_SOURCE %type PE_NAME_CACHE_TYPE %type PE_NAME_CACHE_OP_RESULT %type PE_MODIFIER_EVENT @@ -461,7 +462,17 @@ PE_BPF_OBJECT struct list_head *list; ALLOC_LIST(list); - ABORT_ON(parse_events_load_bpf(data, list, $1)); + ABORT_ON(parse_events_load_bpf(data, list, $1, false)); + $$ = list; +} +| +PE_BPF_SOURCE +{ + struct parse_events_evlist *data = _data; + struct list_head *list; + + ALLOC_LIST(list); + ABORT_ON(parse_events_load_bpf(data, list, $1, true)); $$ = list; } From 3af6ed84eb43c587beb5f3252222e39e65d08c61 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 29 Oct 2015 08:49:37 +0100 Subject: [PATCH 259/260] tools build: Fix libiberty feature detection Any CFLAGS or LDFLAGS set by the user need to be passed to the feature build command. This many include for example -I or -L to point to libraries and include files in custom paths. In most of the test-*.bin rules in build/feature/Makefile, we use the BUILD macro which always sends in CFLAGS and LDFLAGS. The libiberty build line however doesn't use the BUILD macro and thus needs to send in CFLAGS and LDFLAGS explicitly. Without this, when using custom CFLAGS/LDFLAGS, libiberty fails to be detected and the perf link fails with something like: LINK perf libbfd.a(bfd.o): In function `bfd_errmsg': bfd.c:(.text+0x168): undefined reference to `xstrerror' bbfd.a(opncls.o): In function `_bfd_new_bfd': opncls.c:(.text+0xe8): undefined reference to `objalloc_create' ... Signed-off-by: Rabin Vincent Acked-by: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Rabin Vincent Link: http://lkml.kernel.org/r/1446104978-26429-2-git-send-email-rabin.vincent@axis.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index e43a2971bf56..cea04ce9f35c 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -132,10 +132,10 @@ test-libbfd.bin: $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl test-liberty.bin: - $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty + $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty test-liberty-z.bin: - $(CC) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty -lz + $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz test-cplus-demangle.bin: $(BUILD) -liberty From 7ed4915ad60788d6b846e2cd034f49ee15698143 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 29 Oct 2015 08:49:36 +0100 Subject: [PATCH 260/260] perf unwind: Pass symbol source to libunwind Even if --symfs is used to point to the debug binaries, we send in the non-debug filenames to libunwind, which leads to libunwind not finding the debug frame. Fix this by preferring the file in --symfs, if it is available. Signed-off-by: Rabin Vincent Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Rabin Vincent Link: http://lkml.kernel.org/r/1446104978-26429-1-git-send-email-rabin.vincent@axis.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/unwind-libunwind.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index f729f9e99f99..c83832b555e5 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -360,12 +360,15 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, int fd = dso__data_get_fd(map->dso, ui->machine); int is_exec = elf_is_exec(fd, map->dso->name); unw_word_t base = is_exec ? 0 : map->start; + const char *symfile; if (fd >= 0) dso__data_put_fd(map->dso); + symfile = map->dso->symsrc_filename ?: map->dso->name; + memset(&di, 0, sizeof(di)); - if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name, + if (dwarf_find_debug_frame(0, &di, ip, base, symfile, map->start, map->end)) return dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg);