linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] perf llvm: Fix compile bpf failed to cope with latest llvm
@ 2022-04-14 13:41 Yang Jihong
  2022-04-14 15:57 ` Nick Desaulniers
  0 siblings, 1 reply; 3+ messages in thread
From: Yang Jihong @ 2022-04-14 13:41 UTC (permalink / raw)
  To: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa,
	namhyung, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, nathan, ndesaulniers, trix, ak,
	adrian.hunter, james.clark, linux-perf-users, linux-kernel,
	netdev, bpf, llvm
  Cc: yangjihong1

Inline assembly used by asm/sysreg.h is incompatible with latest llvm,
If bpf C program include "linux/ptrace.h" (which is common), compile will fail:

 # perf --debug verbose record -e bpf-output/no-inherit,name=evt/ \
                              -e ./perf_bpf_test.c/map:channel.event=evt/ ls
 [SNIP]
 /lib/modules/5.17/build/./arch/x86/include/asm/arch_hweight.h:20:7: error: invalid output constraint '=a' in asm
                          : "="REG_OUT (res)
                           ^
 /lib/modules/5.17/build/./arch/x86/include/asm/arch_hweight.h:48:7: error: invalid output constraint '=a' in asm
                          : "="REG_OUT (res)
                           ^
 In file included from /root/projects/perf-bpf/perf_bpf_test.c:2:
 In file included from /lib/modules/5.17/build/./include/linux/ptrace.h:6:
 In file included from /lib/modules/5.17/build/./include/linux/sched.h:12:
 In file included from /lib/modules/5.17/build/./arch/x86/include/asm/current.h:6:
 In file included from /lib/modules/5.17/build/./arch/x86/include/asm/percpu.h:27:
 In file included from /lib/modules/5.17/build/./include/linux/kernel.h:25:
 In file included from /lib/modules/5.17/build/./include/linux/math.h:6:
 /lib/modules/5.17.0/build/./arch/x86/include/asm/div64.h:85:28: error: invalid output constraint '=a' in asm
         asm ("mulq %2; divq %3" : "=a" (q)
 [SNIP]
 # cat /root/projects/perf-bpf/perf_bpf_test.c
 /************************ BEGIN **************************/
 #include <uapi/linux/bpf.h>
 #include <linux/ptrace.h>
 #include <linux/types.h>
 #define SEC(NAME) __attribute__((section(NAME), used))

 struct bpf_map_def {
         unsigned int type;
         unsigned int key_size;
         unsigned int value_size;
         unsigned int max_entries;
 };

 static int (*perf_event_output)(void *, struct bpf_map_def *, int, void *,
     unsigned long) = (void *)BPF_FUNC_perf_event_output;

 struct bpf_map_def SEC("maps") channel = {
         .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
         .key_size = sizeof(int),
         .value_size = sizeof(__u32),
         .max_entries = __NR_CPUS__,
 };

 #define MIN_BYTES 1024

 SEC("func=vfs_read")
 int bpf_myprog(struct pt_regs *ctx)
 {
         long bytes = ctx->dx;
         if (bytes >= MIN_BYTES) {
                 perf_event_output(ctx, &channel, BPF_F_CURRENT_CPU,
                                   &bytes, sizeof(bytes));
         }

         return 0;
 }

char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
/************************* END ***************************/

Compilation command is modified to be the same as that in samples/bpf/Makefile,
use clang | opt | llvm-dis | llc chain of commands to solve the problem.
see the comment in samples/bpf/Makefile.

Modifications:
1. Change "clang --target bpf" to chain of commands "clang | opt | llvm-dis | llc"
2. Delete "CLANG_EMIT_LLVM" and "LLVM_OPTIONS_PIPE" macros from the compilation
   command because the two macros are not defined and the content is empty.
3. Add options llvm.llvm-opt-path, llvm.llvm-dis-path, and llvm.llc-path to
   perf config for user-defined settings, which are similar to llvm.clang-path.
4. Add "-Wno-address-of-packed-member" to resolve the compilation warning of
   "/lib/modules/5.17/build/./arch/x86/include/asm/processor.h:552:17: \
    warning: taking address of packed member 'sp0' of class or structure \
    'x86_hw_tss' may result in an unaligned pointer value [-Waddress-of-packed-member]
        this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
                       ^~~~~~~~~~~~~~~~~~~~~~
   /lib/modules/5.17/build/./include/linux/percpu-defs.h:508:68: note: \
   expanded from macro 'this_cpu_write' \
    #define this_cpu_write(pcp, val)        __pcpu_size_call(this_cpu_write_, pcp, val)",
   which is similar to that of sample/bpf/Makefile.

Signed-off-by: Yang Jihong <yangjihong1@huawei.com>
---
 tools/perf/Documentation/perf-config.txt | 16 ++++++++++-
 tools/perf/util/llvm-utils.c             | 35 ++++++++++++++++++------
 tools/perf/util/llvm-utils.h             |  4 +++
 3 files changed, 45 insertions(+), 10 deletions(-)

diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 0420e71698ee..48f12bd6ca9a 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -655,6 +655,15 @@ llvm.*::
 	llvm.clang-path::
 		Path to clang. If omit, search it from $PATH.
 
+	llvm.llvm-opt-path::
+		Path to llvm opt. If omit, search it from $PATH.
+
+	llvm.llvm-dis-path::
+		Path to llvm-dis. If omit, search it from $PATH.
+
+	llvm.llc-path::
+		Path to llc. If omit, search it from $PATH.
+
 	llvm.clang-bpf-cmd-template::
 		Cmdline template. Below lines show its default value. Environment
 		variable is used to pass options.
@@ -662,8 +671,13 @@ llvm.*::
 		"-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE "	\
 		"$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
 		"-Wno-unused-value -Wno-pointer-sign "		\
+		"-Wno-address-of-packed-member "                \
 		"-working-directory $WORKING_DIR "		\
-		"-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
+		"-c \"$CLANG_SOURCE\" "                               \
+		"-O2 -emit-llvm -Xclang -disable-llvm-passes -o - | " \
+		"$LLVM_OPT_EXEC -O2 -mtriple=bpf-pc-linux | "         \
+		"$LLVM_DIS_EXEC | "                                   \
+		"$LLC_EXEC -march=bpf -filetype=obj -o -"
 
 	llvm.clang-opt::
 		Options passed to clang.
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 96c8ef60f4f8..c939681dfafb 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -24,11 +24,18 @@
 		"-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE "	\
 		"$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
 		"-Wno-unused-value -Wno-pointer-sign "		\
+		"-Wno-address-of-packed-member "		\
 		"-working-directory $WORKING_DIR "		\
-		"-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
+		"-c \"$CLANG_SOURCE\" "				      \
+		"-O2 -emit-llvm -Xclang -disable-llvm-passes -o - | " \
+		"$LLVM_OPT_EXEC -O2 -mtriple=bpf-pc-linux | "	      \
+		"$LLVM_DIS_EXEC | "				      \
+		"$LLC_EXEC -march=bpf -filetype=obj -o -"
 
 struct llvm_param llvm_param = {
 	.clang_path = "clang",
+	.llvm_opt_path = "opt",
+	.llvm_dis_path = "llvm-dis",
 	.llc_path = "llc",
 	.clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
 	.clang_opt = NULL,
@@ -48,6 +55,12 @@ int perf_llvm_config(const char *var, const char *value)
 
 	if (!strcmp(var, "clang-path"))
 		llvm_param.clang_path = strdup(value);
+	else if (!strcmp(var, "llvm-opt-path"))
+		llvm_param.llvm_opt_path = strdup(value);
+	else if (!strcmp(var, "llvm-dis-path"))
+		llvm_param.llvm_dis_path = strdup(value);
+	else if (!strcmp(var, "llc-path"))
+		llvm_param.llc_path = strdup(value);
 	else if (!strcmp(var, "clang-bpf-cmd-template"))
 		llvm_param.clang_bpf_cmd_template = strdup(value);
 	else if (!strcmp(var, "clang-opt"))
@@ -456,6 +469,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	char linux_version_code_str[64];
 	const char *clang_opt = llvm_param.clang_opt;
 	char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
+	char llvm_opt_path[PATH_MAX], llvm_dis_path[PATH_MAX];
 	char serr[STRERR_BUFSIZE];
 	char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
 	     *perf_bpf_include_opts = NULL;
@@ -475,9 +489,10 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	if (!template)
 		template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
 
-	err = search_program_and_warn(llvm_param.clang_path,
-			     "clang", clang_path);
-	if (err)
+	if (search_program_and_warn(llvm_param.clang_path, "clang", clang_path) ||
+	    search_program_and_warn(llvm_param.llvm_opt_path, "opt", llvm_opt_path) ||
+	    search_program_and_warn(llvm_param.llvm_dis_path, "llvm-dis", llvm_dis_path) ||
+	    search_program_and_warn(llvm_param.llc_path, "llc", llc_path))
 		return -ENOENT;
 
 	/*
@@ -495,21 +510,23 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 
 	snprintf(linux_version_code_str, sizeof(linux_version_code_str),
 		 "0x%x", kernel_version);
-	if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0)
+	if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0) {
+		err = -ENOMEM;
 		goto errout;
+	}
+
 	force_set_env("NR_CPUS", nr_cpus_avail_str);
 	force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
 	force_set_env("CLANG_EXEC", clang_path);
+	force_set_env("LLVM_OPT_EXEC", llvm_opt_path);
+	force_set_env("LLVM_DIS_EXEC", llvm_dis_path);
+	force_set_env("LLC_EXEC", llc_path);
 	force_set_env("CLANG_OPTIONS", clang_opt);
 	force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
 	force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
 	force_set_env("WORKING_DIR", kbuild_dir ? : ".");
 
 	if (opts) {
-		err = search_program_and_warn(llvm_param.llc_path, "llc", llc_path);
-		if (err)
-			goto errout;
-
 		err = -ENOMEM;
 		if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -",
 			      template, llc_path, opts) < 0) {
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
index 7878a0e3fa98..e276d10f85b4 100644
--- a/tools/perf/util/llvm-utils.h
+++ b/tools/perf/util/llvm-utils.h
@@ -11,6 +11,10 @@
 struct llvm_param {
 	/* Path of clang executable */
 	const char *clang_path;
+	/* Path of llvm opt executable */
+	const char *llvm_opt_path;
+	/* Path of llvm-dis executable */
+	const char *llvm_dis_path;
 	/* Path of llc executable */
 	const char *llc_path;
 	/*
-- 
2.30.GIT


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] perf llvm: Fix compile bpf failed to cope with latest llvm
  2022-04-14 13:41 [PATCH] perf llvm: Fix compile bpf failed to cope with latest llvm Yang Jihong
@ 2022-04-14 15:57 ` Nick Desaulniers
  2022-04-15  3:53   ` Yang Jihong
  0 siblings, 1 reply; 3+ messages in thread
From: Nick Desaulniers @ 2022-04-14 15:57 UTC (permalink / raw)
  To: Yang Jihong
  Cc: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa,
	namhyung, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, nathan, trix, ak, adrian.hunter,
	james.clark, linux-perf-users, linux-kernel, netdev, bpf, llvm

On Thu, Apr 14, 2022 at 6:42 AM Yang Jihong <yangjihong1@huawei.com> wrote:
>
> Inline assembly used by asm/sysreg.h is incompatible with latest llvm,

With "latest" llvm makes it sound like LLVM has regressed. Has it? Or
have the headers changed in a way where now inline asm from a
different target (x86) than what's being targeted (BPF)? Perhaps
fixing that is simpler?

Clang will validate inline asm before LLVM drops unreferenced static
inline functions; this was a headache getting i386 building with
clang, but not insurmountable.

> If bpf C program include "linux/ptrace.h" (which is common), compile will fail:
>
>  # perf --debug verbose record -e bpf-output/no-inherit,name=evt/ \
>                               -e ./perf_bpf_test.c/map:channel.event=evt/ ls
>  [SNIP]
>  /lib/modules/5.17/build/./arch/x86/include/asm/arch_hweight.h:20:7: error: invalid output constraint '=a' in asm
>                           : "="REG_OUT (res)
>                            ^
>  /lib/modules/5.17/build/./arch/x86/include/asm/arch_hweight.h:48:7: error: invalid output constraint '=a' in asm
>                           : "="REG_OUT (res)
>                            ^
>  In file included from /root/projects/perf-bpf/perf_bpf_test.c:2:
>  In file included from /lib/modules/5.17/build/./include/linux/ptrace.h:6:
>  In file included from /lib/modules/5.17/build/./include/linux/sched.h:12:
>  In file included from /lib/modules/5.17/build/./arch/x86/include/asm/current.h:6:
>  In file included from /lib/modules/5.17/build/./arch/x86/include/asm/percpu.h:27:
>  In file included from /lib/modules/5.17/build/./include/linux/kernel.h:25:
>  In file included from /lib/modules/5.17/build/./include/linux/math.h:6:
>  /lib/modules/5.17.0/build/./arch/x86/include/asm/div64.h:85:28: error: invalid output constraint '=a' in asm
>          asm ("mulq %2; divq %3" : "=a" (q)
>  [SNIP]
>  # cat /root/projects/perf-bpf/perf_bpf_test.c
>  /************************ BEGIN **************************/
>  #include <uapi/linux/bpf.h>
>  #include <linux/ptrace.h>
>  #include <linux/types.h>
>  #define SEC(NAME) __attribute__((section(NAME), used))
>
>  struct bpf_map_def {
>          unsigned int type;
>          unsigned int key_size;
>          unsigned int value_size;
>          unsigned int max_entries;
>  };
>
>  static int (*perf_event_output)(void *, struct bpf_map_def *, int, void *,
>      unsigned long) = (void *)BPF_FUNC_perf_event_output;
>
>  struct bpf_map_def SEC("maps") channel = {
>          .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
>          .key_size = sizeof(int),
>          .value_size = sizeof(__u32),
>          .max_entries = __NR_CPUS__,
>  };
>
>  #define MIN_BYTES 1024
>
>  SEC("func=vfs_read")
>  int bpf_myprog(struct pt_regs *ctx)
>  {
>          long bytes = ctx->dx;
>          if (bytes >= MIN_BYTES) {
>                  perf_event_output(ctx, &channel, BPF_F_CURRENT_CPU,
>                                    &bytes, sizeof(bytes));
>          }
>
>          return 0;
>  }
>
> char _license[] SEC("license") = "GPL";
> int _version SEC("version") = LINUX_VERSION_CODE;
> /************************* END ***************************/
>
> Compilation command is modified to be the same as that in samples/bpf/Makefile,
> use clang | opt | llvm-dis | llc chain of commands to solve the problem.
> see the comment in samples/bpf/Makefile.
>
> Modifications:
> 1. Change "clang --target bpf" to chain of commands "clang | opt | llvm-dis | llc"

This will drop the --target flag. That will mess up the default target
triple, and can affect command line option feature detection.

> 2. Delete "CLANG_EMIT_LLVM" and "LLVM_OPTIONS_PIPE" macros from the compilation
>    command because the two macros are not defined and the content is empty.
> 3. Add options llvm.llvm-opt-path, llvm.llvm-dis-path, and llvm.llc-path to
>    perf config for user-defined settings, which are similar to llvm.clang-path.
> 4. Add "-Wno-address-of-packed-member" to resolve the compilation warning of
>    "/lib/modules/5.17/build/./arch/x86/include/asm/processor.h:552:17: \
>     warning: taking address of packed member 'sp0' of class or structure \
>     'x86_hw_tss' may result in an unaligned pointer value [-Waddress-of-packed-member]
>         this_cpu_write(cpu_tss_rw.x86_tss.sp0, sp0);
>                        ^~~~~~~~~~~~~~~~~~~~~~
>    /lib/modules/5.17/build/./include/linux/percpu-defs.h:508:68: note: \
>    expanded from macro 'this_cpu_write' \
>     #define this_cpu_write(pcp, val)        __pcpu_size_call(this_cpu_write_, pcp, val)",
>    which is similar to that of sample/bpf/Makefile.
>
> Signed-off-by: Yang Jihong <yangjihong1@huawei.com>
> ---
>  tools/perf/Documentation/perf-config.txt | 16 ++++++++++-
>  tools/perf/util/llvm-utils.c             | 35 ++++++++++++++++++------
>  tools/perf/util/llvm-utils.h             |  4 +++
>  3 files changed, 45 insertions(+), 10 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
> index 0420e71698ee..48f12bd6ca9a 100644
> --- a/tools/perf/Documentation/perf-config.txt
> +++ b/tools/perf/Documentation/perf-config.txt
> @@ -655,6 +655,15 @@ llvm.*::
>         llvm.clang-path::
>                 Path to clang. If omit, search it from $PATH.
>
> +       llvm.llvm-opt-path::
> +               Path to llvm opt. If omit, search it from $PATH.
> +
> +       llvm.llvm-dis-path::
> +               Path to llvm-dis. If omit, search it from $PATH.
> +
> +       llvm.llc-path::
> +               Path to llc. If omit, search it from $PATH.
> +
>         llvm.clang-bpf-cmd-template::
>                 Cmdline template. Below lines show its default value. Environment
>                 variable is used to pass options.
> @@ -662,8 +671,13 @@ llvm.*::
>                 "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE "     \
>                 "$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
>                 "-Wno-unused-value -Wno-pointer-sign "          \
> +               "-Wno-address-of-packed-member "                \
>                 "-working-directory $WORKING_DIR "              \
> -               "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
> +               "-c \"$CLANG_SOURCE\" "                               \
> +               "-O2 -emit-llvm -Xclang -disable-llvm-passes -o - | " \
> +               "$LLVM_OPT_EXEC -O2 -mtriple=bpf-pc-linux | "         \
> +               "$LLVM_DIS_EXEC | "                                   \
> +               "$LLC_EXEC -march=bpf -filetype=obj -o -"
>
>         llvm.clang-opt::
>                 Options passed to clang.
> diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
> index 96c8ef60f4f8..c939681dfafb 100644
> --- a/tools/perf/util/llvm-utils.c
> +++ b/tools/perf/util/llvm-utils.c
> @@ -24,11 +24,18 @@
>                 "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE "     \
>                 "$CLANG_OPTIONS $PERF_BPF_INC_OPTIONS $KERNEL_INC_OPTIONS " \
>                 "-Wno-unused-value -Wno-pointer-sign "          \
> +               "-Wno-address-of-packed-member "                \
>                 "-working-directory $WORKING_DIR "              \
> -               "-c \"$CLANG_SOURCE\" -target bpf $CLANG_EMIT_LLVM -O2 -o - $LLVM_OPTIONS_PIPE"
> +               "-c \"$CLANG_SOURCE\" "                               \
> +               "-O2 -emit-llvm -Xclang -disable-llvm-passes -o - | " \
> +               "$LLVM_OPT_EXEC -O2 -mtriple=bpf-pc-linux | "         \
> +               "$LLVM_DIS_EXEC | "                                   \
> +               "$LLC_EXEC -march=bpf -filetype=obj -o -"
>
>  struct llvm_param llvm_param = {
>         .clang_path = "clang",
> +       .llvm_opt_path = "opt",
> +       .llvm_dis_path = "llvm-dis",
>         .llc_path = "llc",
>         .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE,
>         .clang_opt = NULL,
> @@ -48,6 +55,12 @@ int perf_llvm_config(const char *var, const char *value)
>
>         if (!strcmp(var, "clang-path"))
>                 llvm_param.clang_path = strdup(value);
> +       else if (!strcmp(var, "llvm-opt-path"))
> +               llvm_param.llvm_opt_path = strdup(value);
> +       else if (!strcmp(var, "llvm-dis-path"))
> +               llvm_param.llvm_dis_path = strdup(value);
> +       else if (!strcmp(var, "llc-path"))
> +               llvm_param.llc_path = strdup(value);
>         else if (!strcmp(var, "clang-bpf-cmd-template"))
>                 llvm_param.clang_bpf_cmd_template = strdup(value);
>         else if (!strcmp(var, "clang-opt"))
> @@ -456,6 +469,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
>         char linux_version_code_str[64];
>         const char *clang_opt = llvm_param.clang_opt;
>         char clang_path[PATH_MAX], llc_path[PATH_MAX], abspath[PATH_MAX], nr_cpus_avail_str[64];
> +       char llvm_opt_path[PATH_MAX], llvm_dis_path[PATH_MAX];
>         char serr[STRERR_BUFSIZE];
>         char *kbuild_dir = NULL, *kbuild_include_opts = NULL,
>              *perf_bpf_include_opts = NULL;
> @@ -475,9 +489,10 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
>         if (!template)
>                 template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
>
> -       err = search_program_and_warn(llvm_param.clang_path,
> -                            "clang", clang_path);
> -       if (err)
> +       if (search_program_and_warn(llvm_param.clang_path, "clang", clang_path) ||
> +           search_program_and_warn(llvm_param.llvm_opt_path, "opt", llvm_opt_path) ||
> +           search_program_and_warn(llvm_param.llvm_dis_path, "llvm-dis", llvm_dis_path) ||
> +           search_program_and_warn(llvm_param.llc_path, "llc", llc_path))
>                 return -ENOENT;
>
>         /*
> @@ -495,21 +510,23 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
>
>         snprintf(linux_version_code_str, sizeof(linux_version_code_str),
>                  "0x%x", kernel_version);
> -       if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0)
> +       if (asprintf(&perf_bpf_include_opts, "-I%s/bpf", perf_include_dir) < 0) {
> +               err = -ENOMEM;
>                 goto errout;
> +       }
> +
>         force_set_env("NR_CPUS", nr_cpus_avail_str);
>         force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
>         force_set_env("CLANG_EXEC", clang_path);
> +       force_set_env("LLVM_OPT_EXEC", llvm_opt_path);
> +       force_set_env("LLVM_DIS_EXEC", llvm_dis_path);
> +       force_set_env("LLC_EXEC", llc_path);
>         force_set_env("CLANG_OPTIONS", clang_opt);
>         force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
>         force_set_env("PERF_BPF_INC_OPTIONS", perf_bpf_include_opts);
>         force_set_env("WORKING_DIR", kbuild_dir ? : ".");
>
>         if (opts) {
> -               err = search_program_and_warn(llvm_param.llc_path, "llc", llc_path);
> -               if (err)
> -                       goto errout;
> -
>                 err = -ENOMEM;
>                 if (asprintf(&pipe_template, "%s -emit-llvm | %s -march=bpf %s -filetype=obj -o -",
>                               template, llc_path, opts) < 0) {
> diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
> index 7878a0e3fa98..e276d10f85b4 100644
> --- a/tools/perf/util/llvm-utils.h
> +++ b/tools/perf/util/llvm-utils.h
> @@ -11,6 +11,10 @@
>  struct llvm_param {
>         /* Path of clang executable */
>         const char *clang_path;
> +       /* Path of llvm opt executable */
> +       const char *llvm_opt_path;
> +       /* Path of llvm-dis executable */
> +       const char *llvm_dis_path;
>         /* Path of llc executable */
>         const char *llc_path;
>         /*
> --
> 2.30.GIT
>


-- 
Thanks,
~Nick Desaulniers

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] perf llvm: Fix compile bpf failed to cope with latest llvm
  2022-04-14 15:57 ` Nick Desaulniers
@ 2022-04-15  3:53   ` Yang Jihong
  0 siblings, 0 replies; 3+ messages in thread
From: Yang Jihong @ 2022-04-15  3:53 UTC (permalink / raw)
  To: Nick Desaulniers
  Cc: peterz, mingo, acme, mark.rutland, alexander.shishkin, jolsa,
	namhyung, ast, daniel, andrii, kafai, songliubraving, yhs,
	john.fastabend, kpsingh, nathan, trix, ak, adrian.hunter,
	james.clark, linux-perf-users, linux-kernel, netdev, bpf, llvm

On 2022/4/14 23:57, Nick Desaulniers wrote:
> On Thu, Apr 14, 2022 at 6:42 AM Yang Jihong <yangjihong1@huawei.com> wrote:
>>
>> Inline assembly used by asm/sysreg.h is incompatible with latest llvm,
> 
> With "latest" llvm makes it sound like LLVM has regressed. Has it? Or
> have the headers changed in a way where now inline asm from a
> different target (x86) than what's being targeted (BPF)? Perhaps
> fixing that is simpler?
> 
> Clang will validate inline asm before LLVM drops unreferenced static
> inline functions; this was a headache getting i386 building with
> clang, but not insurmountable.
> 
According to the notes of samples/bpf/Makefile:
"The reason is due to llvm change https://reviews.llvm.org/D87153
where the CORE relocation global generation is moved from the beginning
of target dependent optimization (llc) to the beginning
of target independent optimization (opt).

Since samples/bpf programs did not use vmlinux.h and its clang compilation
uses native architecture, we need to adjust arch triple at opt level
to do CORE relocation global generation properly. Otherwise, the above
error will appear."
I think opt and llvm-dis are introduced to solve another problem, that 
is, the incompatibility of native architecture.

>> If bpf C program include "linux/ptrace.h" (which is common), compile will fail:
>>
>>   # perf --debug verbose record -e bpf-output/no-inherit,name=evt/ \
>>                                -e ./perf_bpf_test.c/map:channel.event=evt/ ls
>>   [SNIP]
>>   /lib/modules/5.17/build/./arch/x86/include/asm/arch_hweight.h:20:7: error: invalid output constraint '=a' in asm
>>                            : "="REG_OUT (res)
>>                             ^
>>   /lib/modules/5.17/build/./arch/x86/include/asm/arch_hweight.h:48:7: error: invalid output constraint '=a' in asm
>>                            : "="REG_OUT (res)
>>                             ^
>>   In file included from /root/projects/perf-bpf/perf_bpf_test.c:2:
>>   In file included from /lib/modules/5.17/build/./include/linux/ptrace.h:6:
>>   In file included from /lib/modules/5.17/build/./include/linux/sched.h:12:
>>   In file included from /lib/modules/5.17/build/./arch/x86/include/asm/current.h:6:
>>   In file included from /lib/modules/5.17/build/./arch/x86/include/asm/percpu.h:27:
>>   In file included from /lib/modules/5.17/build/./include/linux/kernel.h:25:
>>   In file included from /lib/modules/5.17/build/./include/linux/math.h:6:
>>   /lib/modules/5.17.0/build/./arch/x86/include/asm/div64.h:85:28: error: invalid output constraint '=a' in asm
>>           asm ("mulq %2; divq %3" : "=a" (q)
>>   [SNIP]
>>   # cat /root/projects/perf-bpf/perf_bpf_test.c
>>   /************************ BEGIN **************************/
>>   #include <uapi/linux/bpf.h>
>>   #include <linux/ptrace.h>
>>   #include <linux/types.h>
>>   #define SEC(NAME) __attribute__((section(NAME), used))
>>
>>   struct bpf_map_def {
>>           unsigned int type;
>>           unsigned int key_size;
>>           unsigned int value_size;
>>           unsigned int max_entries;
>>   };
>>
>>   static int (*perf_event_output)(void *, struct bpf_map_def *, int, void *,
>>       unsigned long) = (void *)BPF_FUNC_perf_event_output;
>>
>>   struct bpf_map_def SEC("maps") channel = {
>>           .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
>>           .key_size = sizeof(int),
>>           .value_size = sizeof(__u32),
>>           .max_entries = __NR_CPUS__,
>>   };
>>
>>   #define MIN_BYTES 1024
>>
>>   SEC("func=vfs_read")
>>   int bpf_myprog(struct pt_regs *ctx)
>>   {
>>           long bytes = ctx->dx;
>>           if (bytes >= MIN_BYTES) {
>>                   perf_event_output(ctx, &channel, BPF_F_CURRENT_CPU,
>>                                     &bytes, sizeof(bytes));
>>           }
>>
>>           return 0;
>>   }
>>
>> char _license[] SEC("license") = "GPL";
>> int _version SEC("version") = LINUX_VERSION_CODE;
>> /************************* END ***************************/
>>
>> Compilation command is modified to be the same as that in samples/bpf/Makefile,
>> use clang | opt | llvm-dis | llc chain of commands to solve the problem.
>> see the comment in samples/bpf/Makefile.
>>
>> Modifications:
>> 1. Change "clang --target bpf" to chain of commands "clang | opt | llvm-dis | llc"
> 
> This will drop the --target flag. That will mess up the default target
> triple, and can affect command line option feature detection.
> 
opt add -mtriple=bpf-pc-linux flag,
The complete command is as follows:
clang -O2 -emit-llvm -Xclang -disable-llvm-passes -c $< -o - |
opt -O2 -mtriple=bpf-pc-linux | $(LLVM_DIS) | \
llc -march=bpf $(LLC_FLAGS) -filetype=obj -o $@

This may be a problem. Currently, no simple method is found. Therefore, 
refer to the processing method of samles/bpf/Makefile.

-- 
Thanks,
Jihong


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2022-04-15  3:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-14 13:41 [PATCH] perf llvm: Fix compile bpf failed to cope with latest llvm Yang Jihong
2022-04-14 15:57 ` Nick Desaulniers
2022-04-15  3:53   ` Yang Jihong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).