Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754815AbbHJGTT (ORCPT ); Mon, 10 Aug 2015 02:19:19 -0400 Received: from szxga03-in.huawei.com ([119.145.14.66]:49080 "EHLO szxga03-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752614AbbHJGTP (ORCPT ); Mon, 10 Aug 2015 02:19:15 -0400 From: Wang Nan To: , CC: , , , , , , , , , , , , Subject: [PATCH 15/27] perf test: Add 'perf test BPF' Date: Mon, 10 Aug 2015 06:15:57 +0000 Message-ID: <1439187369-66492-16-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1439187369-66492-1-git-send-email-wangnan0@huawei.com> References: <1439187369-66492-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.193.248] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A010204.55C841CF.0087,ss=1,re=0.000,recu=0.000,reip=0.000,cl=1,cld=1,fgs=0, ip=0.0.0.0, so=2013-05-26 15:14:31, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 0c84ea2620996f67cfa722059c056425 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 8175 Lines: 334 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 Cc: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.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 +#include #include #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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/