summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tools/perf/tests/Build9
-rw-r--r--tools/perf/tests/bpf-script-example.c4
-rw-r--r--tools/perf/tests/llvm.c131
-rw-r--r--tools/perf/tests/llvm.h16
4 files changed, 129 insertions, 31 deletions
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 50de2253cff6..6c095b3d92a9 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,9 +31,16 @@ perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
-perf-y += llvm.o
+perf-y += llvm.o llvm-src-base.o
 perf-y += topology.o
 
+$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c
+	$(call rule_mkdir)
+	$(Q)echo '#include <tests/llvm.h>' > $@
+	$(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
+	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+	$(Q)echo ';' >> $@
+
 ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
 perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
 endif
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c
index 410a70b93b93..0ec9c2c03164 100644
--- a/tools/perf/tests/bpf-script-example.c
+++ b/tools/perf/tests/bpf-script-example.c
@@ -1,3 +1,7 @@
+/*
+ * bpf-script-example.c
+ * Test basic LLVM building
+ */
 #ifndef LINUX_VERSION_CODE
 # error Need LINUX_VERSION_CODE
 # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 8f713f6d32f3..05683c5f183e 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -2,6 +2,7 @@
 #include <bpf/libbpf.h>
 #include <util/llvm-utils.h>
 #include <util/cache.h>
+#include "llvm.h"
 #include "tests.h"
 #include "debug.h"
 
@@ -11,16 +12,6 @@ static int perf_config_cb(const char *var, const char *val,
 	return perf_default_config(var, val, arg);
 }
 
-/*
- * Randomly give it a "version" section since we don't really load it
- * into kernel
- */
-static const char test_bpf_prog[] =
-	"__attribute__((section(\"do_fork\"), used)) "
-	"int fork(void *ctx) {return 0;} "
-	"char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";"
-	"int _version __attribute__((section(\"version\"), used)) = 0x40100;";
-
 #ifdef HAVE_LIBBPF_SUPPORT
 static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
 {
@@ -28,25 +19,47 @@ static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
 
 	obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
 	if (IS_ERR(obj))
-		return -1;
+		return TEST_FAIL;
 	bpf_object__close(obj);
-	return 0;
+	return TEST_OK;
 }
 #else
 static int test__bpf_parsing(void *obj_buf __maybe_unused,
 			     size_t obj_buf_sz __maybe_unused)
 {
 	pr_debug("Skip bpf parsing\n");
-	return 0;
+	return TEST_OK;
 }
 #endif
 
-int test__llvm(void)
+static struct {
+	const char *source;
+	const char *desc;
+} bpf_source_table[__LLVM_TESTCASE_MAX] = {
+	[LLVM_TESTCASE_BASE] = {
+		.source = test_llvm__bpf_base_prog,
+		.desc = "Basic BPF llvm compiling test",
+	},
+};
+
+
+int
+test_llvm__fetch_bpf_obj(void **p_obj_buf,
+			 size_t *p_obj_buf_sz,
+			 enum test_llvm__testcase index,
+			 bool force)
 {
-	char *tmpl_new, *clang_opt_new;
-	void *obj_buf;
-	size_t obj_buf_sz;
-	int err, old_verbose;
+	const char *source;
+	const char *desc;
+	const char *tmpl_old, *clang_opt_old;
+	char *tmpl_new = NULL, *clang_opt_new = NULL;
+	int err, old_verbose, ret = TEST_FAIL;
+
+	if (index >= __LLVM_TESTCASE_MAX)
+		return TEST_FAIL;
+
+	source = bpf_source_table[index].source;
+	desc = bpf_source_table[index].desc;
 
 	perf_config(perf_config_cb, NULL);
 
@@ -54,42 +67,100 @@ int test__llvm(void)
 	 * Skip this test if user's .perfconfig doesn't set [llvm] section
 	 * and clang is not found in $PATH, and this is not perf test -v
 	 */
-	if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) {
+	if (!force && (verbose == 0 &&
+		       !llvm_param.user_set_param &&
+		       llvm__search_clang())) {
 		pr_debug("No clang and no verbosive, skip this test\n");
 		return TEST_SKIP;
 	}
 
-	old_verbose = verbose;
 	/*
 	 * llvm is verbosity when error. Suppress all error output if
 	 * not 'perf test -v'.
 	 */
+	old_verbose = verbose;
 	if (verbose == 0)
 		verbose = -1;
 
+	*p_obj_buf = NULL;
+	*p_obj_buf_sz = 0;
+
 	if (!llvm_param.clang_bpf_cmd_template)
-		return -1;
+		goto out;
 
 	if (!llvm_param.clang_opt)
 		llvm_param.clang_opt = strdup("");
 
-	err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog,
-		       llvm_param.clang_bpf_cmd_template);
+	err = asprintf(&tmpl_new, "echo '%s' | %s%s", source,
+		       llvm_param.clang_bpf_cmd_template,
+		       old_verbose ? "" : " 2>/dev/null");
 	if (err < 0)
-		return -1;
+		goto out;
 	err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
 	if (err < 0)
-		return -1;
+		goto out;
 
+	tmpl_old = llvm_param.clang_bpf_cmd_template;
 	llvm_param.clang_bpf_cmd_template = tmpl_new;
+	clang_opt_old = llvm_param.clang_opt;
 	llvm_param.clang_opt = clang_opt_new;
-	err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz);
+
+	err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz);
+
+	llvm_param.clang_bpf_cmd_template = tmpl_old;
+	llvm_param.clang_opt = clang_opt_old;
 
 	verbose = old_verbose;
 	if (err)
-		return TEST_FAIL;
+		goto out;
+
+	ret = TEST_OK;
+out:
+	free(tmpl_new);
+	free(clang_opt_new);
+	if (ret != TEST_OK)
+		pr_debug("Failed to compile test case: '%s'\n", desc);
+	return ret;
+}
 
-	err = test__bpf_parsing(obj_buf, obj_buf_sz);
-	free(obj_buf);
-	return err;
+int test__llvm(void)
+{
+	enum test_llvm__testcase i;
+
+	for (i = 0; i < __LLVM_TESTCASE_MAX; i++) {
+		int ret;
+		void *obj_buf = NULL;
+		size_t obj_buf_sz = 0;
+
+		ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
+					       i, false);
+
+		if (ret == TEST_OK) {
+			ret = test__bpf_parsing(obj_buf, obj_buf_sz);
+			if (ret != TEST_OK)
+				pr_debug("Failed to parse test case '%s'\n",
+					 bpf_source_table[i].desc);
+		}
+		free(obj_buf);
+
+		switch (ret) {
+		case TEST_SKIP:
+			return TEST_SKIP;
+		case TEST_OK:
+			break;
+		default:
+			/*
+			 * Test 0 is the basic LLVM test. If test 0
+			 * fail, the basic LLVM support not functional
+			 * so the whole test should fail. If other test
+			 * case fail, it can be fixed by adjusting
+			 * config so don't report error.
+			 */
+			if (i == 0)
+				return TEST_FAIL;
+			else
+				return TEST_SKIP;
+		}
+	}
+	return TEST_OK;
 }
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
new file mode 100644
index 000000000000..bd63cee687b5
--- /dev/null
+++ b/tools/perf/tests/llvm.h
@@ -0,0 +1,16 @@
+#ifndef PERF_TEST_LLVM_H
+#define PERF_TEST_LLVM_H
+
+#include <stddef.h> /* for size_t */
+#include <stdbool.h> /* for bool */
+
+extern const char test_llvm__bpf_base_prog[];
+
+enum test_llvm__testcase {
+	LLVM_TESTCASE_BASE,
+	__LLVM_TESTCASE_MAX,
+};
+
+int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
+			     enum test_llvm__testcase index, bool force);
+#endif