From 2f84b42b28eed0f980200401077e51571202f868 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 1 Sep 2015 11:47:19 -0700 Subject: 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); -- cgit v1.2.3 From dabf626f7f0e5cbef0d1cfb5143e40213f079bb8 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Sat, 29 Aug 2015 04:21:55 +0000 Subject: 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 -- cgit v1.2.3 From 76055940c1afc8d445992fb0278b80cf205bbf97 Mon Sep 17 00:00:00 2001 From: He Kuang Date: Sat, 29 Aug 2015 04:22:05 +0000 Subject: 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 + .../perf/util/scripting-engines/trace-event-perl.c | 1 + .../util/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... */ -- cgit v1.2.3 From 193b6bd339ccb30c861a307a915d4532f443e0fb Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 1 Sep 2015 09:58:11 -0400 Subject: 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); -- cgit v1.2.3 From 2bb00d2f95193aea5bfa98392907273115c96920 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 1 Sep 2015 09:58:12 -0400 Subject: 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) -- cgit v1.2.3 From 245bad8eb45fca36638da53fb0a361397a707001 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 1 Sep 2015 15:52:46 -0700 Subject: 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); -- cgit v1.2.3 From f6a09af7de3b39b1e4fcff7374871f834498b7f0 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:32 +0200 Subject: 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); -- cgit v1.2.3 From 65d4b265103a3cb2f0993c946815157a38797421 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:33 +0200 Subject: 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); -- cgit v1.2.3 From 592d5a6ba86a31681fa5e20a63a145b0a3b53c8a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:34 +0200 Subject: 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). -- cgit v1.2.3 From 988bdb319246dea977a375beee39a5452e99b3ef Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:35 +0200 Subject: 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: -- cgit v1.2.3 From b86b0d3570273c6ddc16b1972e82bf7778346286 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:37 +0200 Subject: 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 -- cgit v1.2.3 From 41e3a1fece31d0b2383281e4a917ff4b16fa9223 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:38 +0200 Subject: 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); -- cgit v1.2.3 From 8ccfabdb873df2e18b235bfaf2722f7528d220f1 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:39 +0200 Subject: 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); -- cgit v1.2.3 From c495afb4988dcbb8bae11b8f1bbb7e11f172672b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:40 +0200 Subject: 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); -- cgit v1.2.3 From 73ca85ad364769ffa312b1d892816d8fa23a02bf Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 2 Sep 2015 09:56:41 +0200 Subject: 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 f