perf llvm: Allow passing options to llc in addition to clang
authorArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 15 Aug 2018 20:07:01 +0000 (17:07 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 20 Aug 2018 11:54:58 +0000 (08:54 -0300)
The newly added 'llvm.opts' variable allows passing options directly to
llc, like needed to get sane DWARF in BPF ELF debug sections:

With:

  [root@seventh perf]# cat ~/.perfconfig
  [llvm]
  dump-obj = true
clang-opt = -g
  [root@seventh perf]#

We get:

  [root@seventh perf]# perf trace -e tools/perf/examples/bpf/hello.c cat /etc/passwd > /dev/null
  LLVM: dumping tools/perf/examples/bpf/hello.o
       0.000 __bpf_stdout__:Hello, world
       0.015 __bpf_stdout__:Hello, world
       0.187 __bpf_stdout__:Hello, world
  [root@seventh perf]# pahole tools/perf/examples/bpf/hello.o
  struct clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c) {
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*     0     4 */
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*     4     4 */
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*     8     4 */
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*    12     4 */
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*    16     4 */
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*    20     4 */
  clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566e.org clang version 8.0.0 (http://llvm.org/git/clang.git 8587270a739ee30c926a76d5657e65e85b560f6e) (http://llvm.org/git/llvm.git 0566eefef9c3777bd780ec4cbb9efa764633b76c); /*    24     4 */

  /* size: 28, cachelines: 1, members: 7 */
  /* last cacheline: 28 bytes */
  };
  [root@seventh perf]#

Adding these options to be passed to llvm's llc:

  [root@seventh perf]# cat ~/.perfconfig
  [llvm]
  dump-obj = true
  clang-opt = -g
  opts = -mattr=dwarfris
  [root@seventh perf]#

We get sane output:

  [root@seventh perf]# perf trace -e tools/perf/examples/bpf/hello.c cat /etc/passwd > /dev/null
  LLVM: dumping tools/perf/examples/bpf/hello.o
       0.000 __bpf_stdout__:Hello, world
       0.015 __bpf_stdout__:Hello, world
       0.185 __bpf_stdout__:Hello, world
  [root@seventh perf]# pahole tools/perf/examples/bpf/hello.o
  struct bpf_map {
  unsigned int               type;                 /*     0     4 */
  unsigned int               key_size;             /*     4     4 */
  unsigned int               value_size;           /*     8     4 */
  unsigned int               max_entries;          /*    12     4 */
  unsigned int               map_flags;            /*    16     4 */
  unsigned int               inner_map_idx;        /*    20     4 */
  unsigned int               numa_node;            /*    24     4 */

  /* size: 28, cachelines: 1, members: 7 */
  /* last cacheline: 28 bytes */
  };
  [root@seventh perf]#

Cc: Alexei Starovoitov <ast@fb.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>,
Cc: Yonghong Song <yhs@fb.com>
Link: https://lkml.kernel.org/n/tip-0lrwmrip4dru1651rm8xa7tq@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/llvm-utils.c
tools/perf/util/llvm-utils.h

index 5e94857dfca2c8c47ae289b79dd2a717ae4a82b5..19262f98cd4e1252c09ca77e6319a02d72db50c0 100644 (file)
                "$CLANG_OPTIONS $KERNEL_INC_OPTIONS $PERF_BPF_INC_OPTIONS " \
                "-Wno-unused-value -Wno-pointer-sign "          \
                "-working-directory $WORKING_DIR "              \
-               "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
+               "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
 
 struct llvm_param llvm_param = {
        .clang_path = "clang",
+       .llc_path = "llc",
        .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
        .clang_opt = NULL,
+       .opts = NULL,
        .kbuild_dir = NULL,
        .kbuild_opts = NULL,
        .user_set_param = false,
@@ -51,6 +53,8 @@ int perf_llvm_config(const char *var, const char *value)
                llvm_param.kbuild_opts = strdup(value);
        else if (!strcmp(var, "dump-obj"))
                llvm_param.dump_obj = !!perf_config_bool(var, value);
+       else if (!strcmp(var, "opts"))
+               llvm_param.opts = strdup(value);
        else {
                pr_debug("Invalid LLVM config option: %s\n", value);
                return -1;
@@ -430,11 +434,13 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
        unsigned int kernel_version;
        char linux_version_code_str[64];
        const char *clang_opt = llvm_param.clang_opt;
-       char clang_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
+       char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
        char serr[STRERR_BUFSIZE];
        char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
             *perf_bpf_include_opts = NULL;
        const char *template = llvm_param.clang_bpf_cmd_template;
+       char *pipe_template = NULL;
+       const char *opts = llvm_param.opts;
        char *command_echo = NULL, *command_out;
        char *perf_include_dir = system_path(PERF_INCLUDE_DIR);
 
@@ -484,6 +490,26 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
        force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
        force_set_env("WORKING_DIR", kbuild_dir ? : ".");
 
+       if (opts) {
+               err = search_program(llvm_param.llc_path, "llc", llc_path);
+               if (err) {
+                       pr_err("ERROR:\tunable to find llc.\n"
+                              "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
+                              "     \tand 'llc-path' option in [llvm] section of ~/.perfconfig.\n");
+                       version_notice();
+                       goto errout;
+               }
+
+               if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -",
+                             template, llc_path, opts) < 0) {
+                       pr_err("ERROR:\tnot enough memory to setup command line\n");
+                       goto errout;
+               }
+
+               template = pipe_template;
+
+       }
+
        /*
         * Since we may reset clang's working dir, path of source file
         * should be transferred into absolute path, except we want
@@ -535,6 +561,7 @@ errout:
        free(obj_buf);
        free(perf_bpf_include_opts);
        free(perf_include_dir);
+       free(pipe_template);
        if (p_obj_buf)
                *p_obj_buf = NULL;
        if (p_obj_buf_sz)
index d3ad8deb5db4d359e28d8cec4794fe78ee34bf15..bf3f3f4c4fe20539ca1ae0158da982c5103fc1c4 100644 (file)
@@ -11,6 +11,8 @@
 struct llvm_param {
        /* Path of clang executable */
        const char *clang_path;
+       /* Path of llc executable */
+       const char *llc_path;
        /*
         * Template of clang bpf compiling. 5 env variables
         * can be used:
@@ -23,6 +25,13 @@ struct llvm_param {
        const char *clang_bpf_cmd_template;
        /* Will be filled in $CLANG_OPTIONS */
        const char *clang_opt;
+       /*
+        * If present it'll add -emit-llvm to $CLANG_OPTIONS to pipe
+        * the clang output to llc, useful for new llvm options not
+        * yet selectable via 'clang -mllvm option', such as -mattr=dwarfris
+        * in clang 6.0/llvm 7
+        */
+       const char *opts;
        /* Where to find kbuild system */
        const char *kbuild_dir;
        /*