Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA143C433EF for ; Thu, 16 Dec 2021 17:35:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240326AbhLPRfb (ORCPT ); Thu, 16 Dec 2021 12:35:31 -0500 Received: from linux.microsoft.com ([13.77.154.182]:54480 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240291AbhLPRfQ (ORCPT ); Thu, 16 Dec 2021 12:35:16 -0500 Received: from localhost.localdomain (c-73-140-2-214.hsd1.wa.comcast.net [73.140.2.214]) by linux.microsoft.com (Postfix) with ESMTPSA id 517C720B718A; Thu, 16 Dec 2021 09:35:16 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 517C720B718A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1639676116; bh=qQeZEyXlr6ZK07nGwq0BUMOhF74ViprZftDqYTszTz4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XDm1K7OOQIioRO29MN2VcAmnu5htrDs+Ed4ZiyPlqfVqKAUP954drt5y2IqaHIMwQ uKMJpu7OPOLYN6LSnElNlbBiT9Nf6f5VgHZCTt5qjoZFrlN+jvGQHyv+meVwl7c9kM tREul1XJbT3KcScW4cK2RmEzgDJDn3lnk/gu/Yrs= From: Beau Belgrave To: rostedt@goodmis.org, mhiramat@kernel.org Cc: linux-trace-devel@vger.kernel.org, linux-kernel@vger.kernel.org, beaub@linux.microsoft.com Subject: [PATCH v8 07/12] user_events: Add self-test for perf_event integration Date: Thu, 16 Dec 2021 09:35:06 -0800 Message-Id: <20211216173511.10390-8-beaub@linux.microsoft.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20211216173511.10390-1-beaub@linux.microsoft.com> References: <20211216173511.10390-1-beaub@linux.microsoft.com> Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Tests perf can be attached to and written out correctly. Ensures attach updates status bits in user programs. Signed-off-by: Beau Belgrave --- tools/testing/selftests/user_events/Makefile | 2 +- .../testing/selftests/user_events/perf_test.c | 168 ++++++++++++++++++ 2 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/user_events/perf_test.c diff --git a/tools/testing/selftests/user_events/Makefile b/tools/testing/selftests/user_events/Makefile index e824b9c2cae7..c765d8635d9a 100644 --- a/tools/testing/selftests/user_events/Makefile +++ b/tools/testing/selftests/user_events/Makefile @@ -2,7 +2,7 @@ CFLAGS += -Wl,-no-as-needed -Wall -I../../../../usr/include LDLIBS += -lrt -lpthread -lm -TEST_GEN_PROGS = ftrace_test dyn_test +TEST_GEN_PROGS = ftrace_test dyn_test perf_test TEST_FILES := settings diff --git a/tools/testing/selftests/user_events/perf_test.c b/tools/testing/selftests/user_events/perf_test.c new file mode 100644 index 000000000000..26851d51d6bb --- /dev/null +++ b/tools/testing/selftests/user_events/perf_test.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * User Events Perf Events Test Program + * + * Copyright (c) 2021 Beau Belgrave + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest_harness.h" + +const char *data_file = "/sys/kernel/debug/tracing/user_events_data"; +const char *status_file = "/sys/kernel/debug/tracing/user_events_status"; +const char *id_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/id"; +const char *fmt_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/format"; + +struct event { + __u32 index; + __u32 field1; + __u32 field2; +}; + +static long perf_event_open(struct perf_event_attr *pe, pid_t pid, + int cpu, int group_fd, unsigned long flags) +{ + return syscall(__NR_perf_event_open, pe, pid, cpu, group_fd, flags); +} + +static int get_id(void) +{ + FILE *fp = fopen(id_file, "r"); + int ret, id = 0; + + if (!fp) + return -1; + + ret = fscanf(fp, "%d", &id); + fclose(fp); + + if (ret != 1) + return -1; + + return id; +} + +static int get_offset(void) +{ + FILE *fp = fopen(fmt_file, "r"); + int ret, c, last = 0, offset = 0; + + if (!fp) + return -1; + + /* Read until empty line */ + while (true) { + c = getc(fp); + + if (c == EOF) + break; + + if (last == '\n' && c == '\n') + break; + + last = c; + } + + ret = fscanf(fp, "\tfield:u32 field1;\toffset:%d;", &offset); + fclose(fp); + + if (ret != 1) + return -1; + + return offset; +} + +FIXTURE(user) { + int status_fd; + int data_fd; +}; + +FIXTURE_SETUP(user) { + self->status_fd = open(status_file, O_RDONLY); + ASSERT_NE(-1, self->status_fd); + + self->data_fd = open(data_file, O_RDWR); + ASSERT_NE(-1, self->data_fd); +} + +FIXTURE_TEARDOWN(user) { + close(self->status_fd); + close(self->data_fd); +} + +TEST_F(user, perf_write) { + struct perf_event_attr pe = {0}; + struct user_reg reg = {0}; + int page_size = sysconf(_SC_PAGESIZE); + char *status_page; + struct event event; + struct perf_event_mmap_page *perf_page; + int id, fd, offset; + __u32 *val; + + reg.size = sizeof(reg); + reg.name_args = (__u64)"__test_event u32 field1; u32 field2"; + + status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED, + self->status_fd, 0); + ASSERT_NE(MAP_FAILED, status_page); + + /* Register should work */ + ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, ®)); + ASSERT_EQ(0, reg.write_index); + ASSERT_NE(0, reg.status_index); + ASSERT_EQ(0, status_page[reg.status_index]); + + /* Id should be there */ + id = get_id(); + ASSERT_NE(-1, id); + offset = get_offset(); + ASSERT_NE(-1, offset); + + pe.type = PERF_TYPE_TRACEPOINT; + pe.size = sizeof(pe); + pe.config = id; + pe.sample_type = PERF_SAMPLE_RAW; + pe.sample_period = 1; + pe.wakeup_events = 1; + + /* Tracepoint attach should work */ + fd = perf_event_open(&pe, 0, -1, -1, 0); + ASSERT_NE(-1, fd); + + perf_page = mmap(NULL, page_size * 2, PROT_READ, MAP_SHARED, fd, 0); + ASSERT_NE(MAP_FAILED, perf_page); + + /* Status should be updated */ + ASSERT_EQ(EVENT_STATUS_PERF, status_page[reg.status_index]); + + event.index = reg.write_index; + event.field1 = 0xc001; + event.field2 = 0xc01a; + + /* Ensure write shows up at correct offset */ + ASSERT_NE(-1, write(self->data_fd, &event, sizeof(event))); + val = (void *)(((char *)perf_page) + perf_page->data_offset); + ASSERT_EQ(PERF_RECORD_SAMPLE, *val); + /* Skip over header and size, move to offset */ + val += 3; + val = (void *)((char *)val) + offset; + /* Ensure correct */ + ASSERT_EQ(event.field1, *val++); + ASSERT_EQ(event.field2, *val++); +} + +int main(int argc, char **argv) +{ + return test_harness_run(argc, argv); +} -- 2.17.1