Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Make options always available, even if required libs not linked

This patch keeps options of perf builtins same in all conditions. If
one option is disabled because of compiling options, users should be
notified.

Masami suggested another implementation in [1] that, by adding a
OPTION_NEXT_DEPENDS option before those options in the 'struct option'
array, options parser knows an option is disabled. However, in some
cases this array is reordered (options__order()). In addition, in
parse-option.c that array is const, so we can't simply merge
information in decorator option into the affacted option.

This patch chooses a simpler implementation that, introducing a
set_option_nobuild() function and two option parsing flags. Builtins
with such options should call set_option_nobuild() before option
parsing. The complexity of this patch is because we want some of options
can be skipped safely. In this case their arguments should also be
consumed.

Options in 'perf record' and 'perf probe' are fixed in this patch.

[1] http://lkml.kernel.org/g/50399556C9727B4D88A595C8584AAB3752627CD4@GSjpTKYDCembx32.service.hitachi.net

Test result:

Normal case:

# ./perf probe --vmlinux /tmp/vmlinux sys_write
Added new event:
probe:sys_write (on sys_write)

You can now use it in all perf tools, such as:

perf record -e probe:sys_write -aR sleep 1

Build with NO_DWARF=1:

# ./perf probe -L sys_write
Error: switch `L' is not available because NO_DWARF=1

Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
or: perf probe [<options>] --del '[GROUP:]EVENT' ...
or: perf probe --list [GROUP:]EVENT ...
or: perf probe [<options>] --funcs

-L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
Show source code lines.
(not built-in because NO_DWARF=1)

# ./perf probe -k /tmp/vmlinux sys_write
Warning: switch `k' is being ignored because NO_DWARF=1
Added new event:
probe:sys_write (on sys_write)

You can now use it in all perf tools, such as:

perf record -e probe:sys_write -aR sleep 1

# ./perf probe --vmlinux /tmp/vmlinux sys_write
Warning: option `vmlinux' is being ignored because NO_DWARF=1
Added new event:
[SNIP]

# ./perf probe -l
Usage: perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]
or: perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]
...
-k, --vmlinux <file> vmlinux pathname
(not built-in because NO_DWARF=1)
-L, --line <FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]>
Show source code lines.
(not built-in because NO_DWARF=1)
...
-V, --vars <FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT>
Show accessible variables on PROBEDEF
(not built-in because NO_DWARF=1)
--externs Show external variables too (with --vars only)
(not built-in because NO_DWARF=1)
--no-inlines Don't search inlined functions
(not built-in because NO_DWARF=1)
--range Show variables location range in scope (with --vars only)
(not built-in because NO_DWARF=1)

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1450089563-122430-14-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Wang Nan and committed by
Arnaldo Carvalho de Melo
48e1cab1 408cf34c

+134 -13
+13 -2
tools/perf/builtin-probe.c
··· 249 249 250 250 return ret; 251 251 } 252 + #else 253 + # define opt_show_lines NULL 254 + # define opt_show_vars NULL 252 255 #endif 253 256 static int opt_add_probe_event(const struct option *opt, 254 257 const char *str, int unset __maybe_unused) ··· 476 473 opt_add_probe_event), 477 474 OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" 478 475 " with existing name"), 479 - #ifdef HAVE_DWARF_SUPPORT 480 476 OPT_CALLBACK('L', "line", NULL, 481 477 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 482 478 "Show source code lines.", opt_show_lines), ··· 492 490 "directory", "path to kernel source"), 493 491 OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines, 494 492 "Don't search inlined functions"), 495 - #endif 496 493 OPT__DRY_RUN(&probe_event_dry_run), 497 494 OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes, 498 495 "Set how many probe points can be found for a probe."), ··· 522 521 #ifdef HAVE_DWARF_SUPPORT 523 522 set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); 524 523 set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE); 524 + #else 525 + # define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c) 526 + set_nobuild('L', "line", false); 527 + set_nobuild('V', "vars", false); 528 + set_nobuild('\0', "externs", false); 529 + set_nobuild('\0', "range", false); 530 + set_nobuild('k', "vmlinux", true); 531 + set_nobuild('s', "source", true); 532 + set_nobuild('\0', "no-inlines", true); 533 + # undef set_nobuild 525 534 #endif 526 535 set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE); 527 536
+7 -2
tools/perf/builtin-record.c
··· 1113 1113 "per thread proc mmap processing timeout in ms"), 1114 1114 OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, 1115 1115 "Record context switch events"), 1116 - #ifdef HAVE_LIBBPF_SUPPORT 1117 1116 OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", 1118 1117 "clang binary to use for compiling BPF scriptlets"), 1119 1118 OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", 1120 1119 "options passed to clang when compiling BPF scriptlets"), 1121 - #endif 1122 1120 OPT_END() 1123 1121 }; 1124 1122 ··· 1127 1129 int err; 1128 1130 struct record *rec = &record; 1129 1131 char errbuf[BUFSIZ]; 1132 + 1133 + #ifndef HAVE_LIBBPF_SUPPORT 1134 + # define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c) 1135 + set_nobuild('\0', "clang-path", true); 1136 + set_nobuild('\0', "clang-opt", true); 1137 + # undef set_nobuild 1138 + #endif 1130 1139 1131 1140 rec->evlist = perf_evlist__new(); 1132 1141 if (rec->evlist == NULL)
+109 -9
tools/perf/util/parse-options.c
··· 18 18 return error("option `%s' %s", opt->long_name, reason); 19 19 } 20 20 21 + static void optwarning(const struct option *opt, const char *reason, int flags) 22 + { 23 + if (flags & OPT_SHORT) 24 + warning("switch `%c' %s", opt->short_name, reason); 25 + else if (flags & OPT_UNSET) 26 + warning("option `no-%s' %s", opt->long_name, reason); 27 + else 28 + warning("option `%s' %s", opt->long_name, reason); 29 + } 30 + 21 31 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, 22 32 int flags, const char **arg) 23 33 { 34 + const char *res; 35 + 24 36 if (p->opt) { 25 - *arg = p->opt; 37 + res = p->opt; 26 38 p->opt = NULL; 27 39 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || 28 40 **(p->argv + 1) == '-')) { 29 - *arg = (const char *)opt->defval; 41 + res = (const char *)opt->defval; 30 42 } else if (p->argc > 1) { 31 43 p->argc--; 32 - *arg = *++p->argv; 44 + res = *++p->argv; 33 45 } else 34 46 return opterror(opt, "requires a value", flags); 47 + if (arg) 48 + *arg = res; 35 49 return 0; 36 50 } 37 51 ··· 103 89 default: 104 90 break; 105 91 } 92 + } 93 + 94 + if (opt->flags & PARSE_OPT_NOBUILD) { 95 + char reason[128]; 96 + bool noarg = false; 97 + 98 + err = snprintf(reason, sizeof(reason), 99 + opt->flags & PARSE_OPT_CANSKIP ? 100 + "is being ignored because %s " : 101 + "is not available because %s", 102 + opt->build_opt); 103 + reason[sizeof(reason) - 1] = '\0'; 104 + 105 + if (err < 0) 106 + strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ? 107 + "is being ignored" : 108 + "is not available", 109 + sizeof(reason)); 110 + 111 + if (!(opt->flags & PARSE_OPT_CANSKIP)) 112 + return opterror(opt, reason, flags); 113 + 114 + err = 0; 115 + if (unset) 116 + noarg = true; 117 + if (opt->flags & PARSE_OPT_NOARG) 118 + noarg = true; 119 + if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 120 + noarg = true; 121 + 122 + switch (opt->type) { 123 + case OPTION_BOOLEAN: 124 + case OPTION_INCR: 125 + case OPTION_BIT: 126 + case OPTION_SET_UINT: 127 + case OPTION_SET_PTR: 128 + case OPTION_END: 129 + case OPTION_ARGUMENT: 130 + case OPTION_GROUP: 131 + noarg = true; 132 + break; 133 + case OPTION_CALLBACK: 134 + case OPTION_STRING: 135 + case OPTION_INTEGER: 136 + case OPTION_UINTEGER: 137 + case OPTION_LONG: 138 + case OPTION_U64: 139 + default: 140 + break; 141 + } 142 + 143 + if (!noarg) 144 + err = get_arg(p, opt, flags, NULL); 145 + if (err) 146 + return err; 147 + 148 + optwarning(opt, reason, flags); 149 + return 0; 106 150 } 107 151 108 152 switch (opt->type) { ··· 717 645 pad = USAGE_OPTS_WIDTH; 718 646 } 719 647 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); 648 + if (opts->flags & PARSE_OPT_NOBUILD) 649 + fprintf(stderr, "%*s(not built-in because %s)\n", 650 + USAGE_OPTS_WIDTH + USAGE_GAP, "", 651 + opts->build_opt); 720 652 } 721 653 722 654 static int option__cmp(const void *va, const void *vb) ··· 924 848 return 0; 925 849 } 926 850 927 - void set_option_flag(struct option *opts, int shortopt, const char *longopt, 928 - int flag) 851 + static struct option * 852 + find_option(struct option *opts, int shortopt, const char *longopt) 929 853 { 930 854 for (; opts->type != OPTION_END; opts++) { 931 855 if ((shortopt && opts->short_name == shortopt) || 932 856 (opts->long_name && longopt && 933 - !strcmp(opts->long_name, longopt))) { 934 - opts->flags |= flag; 935 - break; 936 - } 857 + !strcmp(opts->long_name, longopt))) 858 + return opts; 937 859 } 860 + return NULL; 861 + } 862 + 863 + void set_option_flag(struct option *opts, int shortopt, const char *longopt, 864 + int flag) 865 + { 866 + struct option *opt = find_option(opts, shortopt, longopt); 867 + 868 + if (opt) 869 + opt->flags |= flag; 870 + return; 871 + } 872 + 873 + void set_option_nobuild(struct option *opts, int shortopt, 874 + const char *longopt, 875 + const char *build_opt, 876 + bool can_skip) 877 + { 878 + struct option *opt = find_option(opts, shortopt, longopt); 879 + 880 + if (!opt) 881 + return; 882 + 883 + opt->flags |= PARSE_OPT_NOBUILD; 884 + opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0; 885 + opt->build_opt = build_opt; 938 886 }
+5
tools/perf/util/parse-options.h
··· 41 41 PARSE_OPT_DISABLED = 32, 42 42 PARSE_OPT_EXCLUSIVE = 64, 43 43 PARSE_OPT_NOEMPTY = 128, 44 + PARSE_OPT_NOBUILD = 256, 45 + PARSE_OPT_CANSKIP = 512, 44 46 }; 45 47 46 48 struct option; ··· 98 96 void *value; 99 97 const char *argh; 100 98 const char *help; 99 + const char *build_opt; 101 100 102 101 int flags; 103 102 parse_opt_cb *callback; ··· 220 217 extern const char *parse_options_fix_filename(const char *prefix, const char *file); 221 218 222 219 void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag); 220 + void set_option_nobuild(struct option *opts, int shortopt, const char *longopt, 221 + const char *build_opt, bool can_skip); 223 222 #endif /* __PERF_PARSE_OPTIONS_H */