lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 10 Aug 2015 06:15:57 +0000
From:	Wang Nan <wangnan0@...wei.com>
To:	<acme@...nel.org>, <ast@...mgrid.com>
CC:	<linux-kernel@...r.kernel.org>, <lizefan@...wei.com>,
	<hekuang@...wei.com>, <xiakaixu@...wei.com>, <pi3orama@....com>,
	<brendan.d.gregg@...il.com>, <daniel@...earbox.net>,
	<dsahern@...il.com>, <jolsa@...nel.org>,
	<masami.hiramatsu.pt@...achi.com>, <namhyung@...nel.org>,
	<paulus@...ba.org>, <a.p.zijlstra@...llo.nl>
Subject: [PATCH 15/27] perf test: Add 'perf test BPF'

This patch adds BPF testcase for testing BPF event filtering.

By utilizing the result of 'perf test LLVM', this patch further forks
a 'perf record' to load and use it.

The BPF script in 'perf test LLVM' collect half of execution of
epoll_pwait(), 'perf test TESTTARGET_EPOLL_PWAIT_LOOP' run 111 times
of it, so the resuling 'perf.data' should contain 56 samples. This
patch checks the result using 'perf report -D'.

Signed-off-by: Wang Nan <wangnan0@...wei.com>
Cc: Arnaldo Carvalho de Melo <acme@...hat.com>
Cc: Alexei Starovoitov <ast@...mgrid.com>
Cc: Brendan Gregg <brendan.d.gregg@...il.com>
Cc: Daniel Borkmann <daniel@...earbox.net>
Cc: David Ahern <dsahern@...il.com>
Cc: He Kuang <hekuang@...wei.com>
Cc: Jiri Olsa <jolsa@...nel.org>
Cc: Kaixu Xia <xiakaixu@...wei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@...achi.com>
Cc: Namhyung Kim <namhyung@...nel.org>
Cc: Peter Zijlstra <a.p.zijlstra@...llo.nl>
Cc: Zefan Li <lizefan@...wei.com>
Cc: pi3orama@....com
---
 tools/perf/tests/bpf.c          | 214 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/tests/builtin-test.c |   4 +
 tools/perf/tests/llvm.c         |  19 ++++
 tools/perf/tests/llvm.h         |   1 +
 tools/perf/tests/tests.h        |   1 +
 5 files changed, 239 insertions(+)

diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 1a9eec3..e911ef8 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -1,6 +1,8 @@
 #include <stdio.h>
+#include <stdarg.h>
 #include <sys/epoll.h>
 #include "tests.h"
+#include "llvm.h"
 #include "debug.h"
 #define NR_ITERS	111
 
@@ -13,3 +15,215 @@ int testtarget__epoll_pwait_loop(void)
 		epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
 	return 0;
 }
+
+#ifdef HAVE_LIBBPF_SUPPORT
+
+static int
+vsystem_exec_cmd(int *pres, const char *format, va_list args)
+{
+	char *cmd;
+	int err, res;
+
+	err = vasprintf(&cmd, format, args);
+	if (err < 0) {
+		pr_err("No enough memory for vasprintf\n");
+		return TEST_FAIL;
+	}
+	res = system(cmd);
+	free(cmd);
+	*pres = res;
+	return 0;
+}
+
+#define __printf(a, b)	__attribute__((format(printf, a, b)))
+__printf(2, 3) static int
+system_exec_cmd(int *pres, const char *format, ...)
+{
+	va_list args;
+	int err;
+
+	va_start(args, format);
+	err = vsystem_exec_cmd(pres, format, args);
+	va_end(args);
+	return err;
+}
+
+static const char *get_tmpdir(void)
+{
+	const char *tmp;
+
+	tmp = getenv("TMPDIR");
+	if (tmp)
+		return tmp;
+#ifdef P_tmpdir
+	return P_tmpdir;
+#else
+	return "/tmp";
+#endif
+}
+
+#define TMPDIR_TEMPLATE "perf-bpf-test-XXXXXX"
+static int
+prepare_tmpdir(char **p_tmpdir, char **p_cmd_rmdir)
+{
+	int err;
+
+	err = asprintf(p_tmpdir, "%s/%s", get_tmpdir(), TMPDIR_TEMPLATE);
+	if (err < 0) {
+		pr_err("No enough memory for tmpdir\n");
+		return TEST_FAIL;
+	}
+
+	if (mkdtemp(*p_tmpdir) != *p_tmpdir) {
+		pr_err("mkdtemp() failed\n");
+		free(*p_tmpdir);
+		*p_tmpdir = NULL;
+		return TEST_FAIL;
+	}
+
+	err = asprintf(p_cmd_rmdir, "rm -rf %s", *p_tmpdir);
+	if (err < 0) {
+		pr_err("No enough memory for rm command\n");
+		free(*p_tmpdir);
+		*p_tmpdir = NULL;
+		return TEST_FAIL;
+	}
+
+	return 0;
+}
+
+static int
+dump_obj(void *obj_buf, size_t obj_buf_sz, const char *tmpdir)
+{
+	char *obj_name;
+	FILE *fp;
+	int err;
+
+	err = asprintf(&obj_name, "%s/test.o", tmpdir);
+	if (err < 0) {
+		pr_err("No enough memory for string '%s/test.o'\n", tmpdir);
+		return TEST_FAIL;
+	}
+
+	fp = fopen(obj_name, "wb");
+	if (!fp) {
+		pr_err("Create '%s' failed", obj_name);
+		free(obj_name);
+		return TEST_FAIL;
+	}
+
+	err = fwrite(obj_buf, 1, obj_buf_sz, fp);
+	if (err != (int)obj_buf_sz) {
+		pr_err("Dump to '%s' failed", obj_name);
+		free(obj_name);
+		fclose(fp);
+		return TEST_FAIL;
+	}
+
+	fclose(fp);
+	return 0;
+}
+
+#define exec_cmd(errstr, fmt...)		\
+do {						\
+	err = system_exec_cmd(&res, fmt);	\
+	if (!err && !res)			\
+		break;				\
+	if (verbose == 0)			\
+		fprintf(stderr, errstr);	\
+	return TEST_FAIL;			\
+} while(0)
+
+static int
+do_test(const char *tmpdir)
+{
+	char *arg0, *result_path;
+	FILE *result_file;
+	int err, res;
+
+	err = asprintf(&arg0, "/proc/%d/exe", getpid());
+	if (err < 0) {
+		pr_err("No enough memory for '/proc/%d/exe'\n", getpid());
+		return TEST_FAIL;
+	}
+
+	exec_cmd(" (failed to collect samples)",
+		"%s record -e %s/test.o -o %s/perf.data %s test '%s' %s",
+		 arg0, tmpdir, tmpdir, arg0, TESTTARGET_EPOLL_PWAIT_LOOP,
+		 verbose == 0 ? " > /dev/null 2>&1" : "");
+
+	exec_cmd(" (failed to read perf.data)",
+"%s report -i %s/perf.data -D | grep PERF_RECORD_SAMPLE | wc -l > %s/result",
+		 arg0, tmpdir, tmpdir);
+
+	free(arg0);
+	arg0 = NULL;
+
+	err = asprintf(&result_path, "%s/result", tmpdir);
+	if (err < 0) {
+		pr_err("No enough memory for result file name\n");
+		return TEST_FAIL;
+	}
+	result_file = fopen(result_path, "r");
+	if (!result_file) {
+		pr_err("Failed to open '%s'\n", result_path);
+		free(result_path);
+		return TEST_FAIL;
+	}
+	free(result_path);
+
+	err = fscanf(result_file, "%d", &res);
+	fclose(result_file);
+
+	if (err != 1) {
+		pr_err("Failed to read result file\n");
+		return TEST_FAIL;
+	}
+
+	if (res != (NR_ITERS + 1) / 2)
+		fprintf(stderr, " (filter result incorrect)");
+	return 0;
+}
+
+int test__bpf(void)
+{
+	int err;
+	char *tmpdir, *cmd_rmdir;
+	void *obj_buf;
+	size_t obj_buf_sz;
+
+	test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz);
+	if (!obj_buf || !obj_buf_sz) {
+		if (verbose == 0)
+			fprintf(stderr, " (fix 'perf test LLVM' first)");
+		return TEST_SKIP;
+	}
+
+	err = prepare_tmpdir(&tmpdir, &cmd_rmdir);
+	if (err)
+		return err;
+
+	err = dump_obj(obj_buf, obj_buf_sz, tmpdir);
+	if (err)
+		goto out;
+
+	err = do_test(tmpdir);
+out:
+	if (system(cmd_rmdir)) {
+		pr_err("'%s' failed\n", cmd_rmdir);
+		return TEST_FAIL;
+	}
+	if (err != TEST_OK)
+		fprintf(stderr, " (use 'perf test -v BPF' to see detail)");
+	return err;
+}
+
+#else
+
+int test__bpf(void)
+{
+	fprintf(stderr, " (disabled)");
+	return TEST_SKIP;
+}
+
+#endif
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 0d0c963..6d59e84 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -183,6 +183,10 @@ static struct test {
 		.prepare = test__llvm_prepare,
 		.cleanup = test__llvm_cleanup,
 	},
+	{
+		.desc = "Test BPF filter",
+		.func = test__bpf,
+	},
 	/*
 	 * Put test targets after all test cases so sequence number will be
 	 * less confusing.
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index e48eb64..94ed5f2 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -174,3 +174,22 @@ void test__llvm_cleanup(void)
 			(~((unsigned long)page_size - 1));
 	munmap((void *)boundary, buf_end - boundary);
 }
+
+void
+test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz)
+{
+	*p_obj_buf = NULL;
+	*p_obj_buf_sz = 0;
+
+	if (!p_test_llvm__bpf_result) {
+		test__llvm_prepare();
+		test__llvm();
+		test__llvm_cleanup();
+	}
+
+	if (!p_test_llvm__bpf_result)
+		return;
+
+	*p_obj_buf = p_test_llvm__bpf_result->object;
+	*p_obj_buf_sz = p_test_llvm__bpf_result->size;
+}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 1e89e46..2fd7ed6 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -10,5 +10,6 @@ struct test_llvm__bpf_result {
 
 extern struct test_llvm__bpf_result *p_test_llvm__bpf_result;
 extern const char test_llvm__bpf_prog[];
+void test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz);
 
 #endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 0138a3d..7704bfd 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -65,6 +65,7 @@ int test__thread_map(void);
 int test__llvm(void);
 void test__llvm_prepare(void);
 void test__llvm_cleanup(void);
+int test__bpf(void);
 #define TESTTARGET_EPOLL_PWAIT_LOOP "TESTTARGET: epoll_pwait loop"
 int testtarget__epoll_pwait_loop(void);
 
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ