From patchwork Mon Jun 3 00:33:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kent Overstreet X-Patchwork-Id: 13683159 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 kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1AAC9C27C50 for ; Mon, 3 Jun 2024 00:33:38 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id C64F96B00D5; Sun, 2 Jun 2024 20:33:29 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id B9FC16B00D8; Sun, 2 Jun 2024 20:33:29 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A178B6B00D9; Sun, 2 Jun 2024 20:33:29 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 8197C6B00D5 for ; Sun, 2 Jun 2024 20:33:29 -0400 (EDT) Received: from smtpin06.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id C1CF41205CE for ; Mon, 3 Jun 2024 00:33:28 +0000 (UTC) X-FDA: 82187703696.06.649F495 Received: from out-178.mta0.migadu.com (out-178.mta0.migadu.com [91.218.175.178]) by imf30.hostedemail.com (Postfix) with ESMTP id AC61880011 for ; Mon, 3 Jun 2024 00:33:26 +0000 (UTC) Authentication-Results: imf30.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=vMHc0xIm; spf=pass (imf30.hostedemail.com: domain of kent.overstreet@linux.dev designates 91.218.175.178 as permitted sender) smtp.mailfrom=kent.overstreet@linux.dev; dmarc=pass (policy=none) header.from=linux.dev ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1717374806; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=lid2ntMsw00JkkyCn7zuRGFLtASs70M1/6euqfBnjHA=; b=f3yvNpRnXHMh55Wx+u+HfZRWWM1FU0xc5YRUVQCuuyylzWjz6DVxneCYuP5xOC01EL8RN0 kCqT+dOZ3LnldfKB3JD003FRZKYGv/9TPIB6BB2WrP+XtmZjfH4mNEMmGT/34VD8GVpq6U wTXcB69jaA/tg9J6/nuNK8QVPWNK3AA= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1717374806; a=rsa-sha256; cv=none; b=3wTLAtkSJpSCE6kzS/9/SiiIZaQeLvg7r5a7tSK3qYNnCcfACfI8Xf36Wb4xTuN8OVaXqy lXKXw9UUSgQdXy2tjM/u9aW1hzf68C269FS4shI1bcIRQBRvDAnVzdXR8ZDC6jEKPgHEYy KndpJHBd0hEctpKZw7jNZTzD5SC4BIA= ARC-Authentication-Results: i=1; imf30.hostedemail.com; dkim=pass header.d=linux.dev header.s=key1 header.b=vMHc0xIm; spf=pass (imf30.hostedemail.com: domain of kent.overstreet@linux.dev designates 91.218.175.178 as permitted sender) smtp.mailfrom=kent.overstreet@linux.dev; dmarc=pass (policy=none) header.from=linux.dev X-Envelope-To: linux-fsdevel@vger.kernel.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1717374802; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lid2ntMsw00JkkyCn7zuRGFLtASs70M1/6euqfBnjHA=; b=vMHc0xImlmkfSN8LhsrQzghIWopuZAElfRf+f441af22PU9ZUB9dOBzOPR/W52K54OE5lJ ulGnaHSIEheKlAZ35eLPPSJucr1Gk1tN0GHJw1pOIN7gpiBlfWtWSF1YYoyX4vIn5gBLDX VhFiQT9b5tZ2sh/SwGXNGNM3J6EAkR4= X-Envelope-To: linux-kernel@vger.kernel.org X-Envelope-To: axboe@kernel.dk X-Envelope-To: kent.overstreet@linux.dev X-Envelope-To: brauner@kernel.org X-Envelope-To: viro@zeniv.linux.org.uk X-Envelope-To: bernd.schubert@fastmail.fm X-Envelope-To: linux-mm@kvack.org X-Envelope-To: josef@toxicpanda.com X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Kent Overstreet To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Jens Axboe , Kent Overstreet , brauner@kernel.org, viro@zeniv.linux.org.uk, Bernd Schubert , linux-mm@kvack.org, Josef Bacik Subject: [PATCH 5/5] ringbuffer: Userspace test helper Date: Sun, 2 Jun 2024 20:33:02 -0400 Message-ID: <20240603003306.2030491-6-kent.overstreet@linux.dev> In-Reply-To: <20240603003306.2030491-1-kent.overstreet@linux.dev> References: <20240603003306.2030491-1-kent.overstreet@linux.dev> MIME-Version: 1.0 X-Migadu-Flow: FLOW_OUT X-Rspam-User: X-Stat-Signature: nk4i9rgr1rzh8567qqbu9bfz5da8f8fe X-Rspamd-Server: rspam07 X-Rspamd-Queue-Id: AC61880011 X-HE-Tag: 1717374806-128643 X-HE-Meta: U2FsdGVkX1/7dp3/VHBUb63219QO8KQw+xt2D0i0eaiJpEZdFRfOvhWob/8xCU+Bl2hQLZdVtDht9kIFHzbBeiiNfmdFo7jXthpc36kooHIxKSXlA2O8FdGw5HHPDlMkYi8AwN+z/8fXXCNN1aQdAaGP5P0Di5uHIu+vSQfB35OvK47BbFhrJMOjFaLlycQz1GizrCaXaiFMAF5LpjJDwe++TmBVQq2caE3G9CPL3DlplinK+FukrUnzL/gtcWzehSf17ygCZPfSGSlcmqI5Is34PDx62+vQix6g5n1zrcIFLIUoE2YKif+GLJ9tWv/z950U/S1KueI5j4vYeOzgkeMQM8/ihryJg3FiK7DGBIA/7zHrP2F3ZcyeQRqmkxpKj7ZDiCHdXZ920ncY1ulgKdV6gnlKas5l6PMsqwTLtQ+f0vgPowgmD1JzFFkbm6IcZLqfINUm5JL0GTs5Yngujxw1s3q+jlNiMi9LeK7ArEl9dbebIgrtVkxzwJJuEPBoOZ6ms0lfkh0yTKino5oG3SwJnPGNWOQ/hQGTlY2vMtEuKAmFujxMJMVdPj/55lArL1Ep2T07qbBcssa0comJ6OEPXFFfW1MX03jkpzCgByJho2n6N/LnD9Zn9u1nFTf8KXY7bc2NoobeKfjI57GgnRxHz8Q8D9tSXRJ8azvGNgb7seJxV1aqaBnNHUWYWVR06n00dOrxQn2DdgcM++zdfoaD70SFSyqc4DTiwnnOG3srg9VjNFMxluNTz288vCPm4iDW5olMtQwQNCTBTcqRFp1p8tRvIrlGWS/bLi+kL21SLDSjTlyW3BnKWiNHKanep2skPc3xjG/K6KPbE+dyLjudJVHRx/1iSrdw/H5+HuRPx3JxoqIoI4VnsNK3rYkqRdm9OKEuuSlWTCofPIvnfoEDMh2eUsaxLXOCBaamXWoRwSFOe0gVTIUUOZVU4T+NrfE9ILLKS1Rv212oMJU YZTDX/QC 9QSJu0dZYbpRiVaG7EawJOgWAuCHwmAh57s5yunIpZwi/ctb1s/Fz3qye5fGzcat7J4snB6Jz4dfbGkI= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: This adds a helper for testing the new ringbuffer syscall using /dev/ringbuffer-test; it can do performance testing of both normal reads and writes, and reads and writes via the ringbuffer interface. Signed-off-by: Kent Overstreet --- tools/ringbuffer/Makefile | 3 + tools/ringbuffer/ringbuffer-test.c | 254 +++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+) create mode 100644 tools/ringbuffer/Makefile create mode 100644 tools/ringbuffer/ringbuffer-test.c diff --git a/tools/ringbuffer/Makefile b/tools/ringbuffer/Makefile new file mode 100644 index 000000000000..2fb27a19b43e --- /dev/null +++ b/tools/ringbuffer/Makefile @@ -0,0 +1,3 @@ +CFLAGS=-g -O2 -Wall -Werror -I../../include + +all: ringbuffer-test diff --git a/tools/ringbuffer/ringbuffer-test.c b/tools/ringbuffer/ringbuffer-test.c new file mode 100644 index 000000000000..0fba99e40858 --- /dev/null +++ b/tools/ringbuffer/ringbuffer-test.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define READ 0 +#define WRITE 1 + +#define min(a, b) (a < b ? a : b) + +#define __EXPORTED_HEADERS__ +#include + +#define BUF_NR 4 + +typedef uint32_t u32; +typedef unsigned long ulong; + +static inline struct ringbuffer_ptrs *ringbuffer(int fd, int rw, u32 size) +{ + ulong addr = 0; + int ret = syscall(463, fd, rw, size, &addr); + if (ret < 0) + errno = -ret; + return (void *) addr; +} + +static inline int ringbuffer_wait(int fd, int rw) +{ + return syscall(464, fd, rw); +} + +static inline int ringbuffer_wakeup(int fd, int rw) +{ + return syscall(465, fd, rw); +} + +static ssize_t ringbuffer_read(int fd, struct ringbuffer_ptrs *rb, + void *buf, size_t len) +{ + void *rb_data = (void *) rb + rb->data_offset; + + u32 head, orig_tail = rb->tail, tail = orig_tail; + + while ((head = __atomic_load_n(&rb->head, __ATOMIC_ACQUIRE)) == tail) + ringbuffer_wait(fd, READ); + + while (len && head != tail) { + u32 tail_masked = tail & rb->mask; + unsigned b = min(len, + min(head - tail, + rb->size - tail_masked)); + + memcpy(buf, rb_data + tail_masked, b); + buf += b; + len -= b; + tail += b; + } + + __atomic_store_n(&rb->tail, tail, __ATOMIC_RELEASE); + + __atomic_thread_fence(__ATOMIC_SEQ_CST); + + if (rb->head - orig_tail >= rb->size) + ringbuffer_wakeup(fd, READ); + + return tail - orig_tail; +} + +static ssize_t ringbuffer_write(int fd, struct ringbuffer_ptrs *rb, + void *buf, size_t len) +{ + void *rb_data = (void *) rb + rb->data_offset; + + u32 orig_head = rb->head, head = orig_head, tail; + + while (head - (tail = __atomic_load_n(&rb->tail, __ATOMIC_ACQUIRE)) >= rb->size) + ringbuffer_wait(fd, WRITE); + + while (len && head - tail < rb->size) { + u32 head_masked = head & rb->mask; + unsigned b = min(len, + min(tail - head + rb->size, + rb->size - head_masked)); + + memcpy(rb_data + head_masked, buf, b); + buf += b; + len -= b; + head += b; + } + + __atomic_store_n(&rb->head, head, __ATOMIC_RELEASE); + + __atomic_thread_fence(__ATOMIC_SEQ_CST); + + if ((s32) (rb->tail - orig_head) >= 0) + ringbuffer_wakeup(fd, WRITE); + + return head - orig_head; +} + +static void usage(void) +{ + puts("ringbuffer-test - test ringbuffer syscall\n" + "Usage: ringbuffer-test [OPTION]...\n" + "\n" + "Options:\n" + " --type=(io|ringbuffer)\n" + " --rw=(read|write)\n" + " -h, --help Display this help and exit\n"); +} + +static inline ssize_t rb_test_read(int fd, struct ringbuffer_ptrs *rb, + void *buf, size_t len) +{ + return rb + ? ringbuffer_read(fd, rb, buf, len) + : read(fd, buf, len); +} + +static inline ssize_t rb_test_write(int fd, struct ringbuffer_ptrs *rb, + void *buf, size_t len) +{ + return rb + ? ringbuffer_write(fd, rb, buf, len) + : write(fd, buf, len); +} + +int main(int argc, char *argv[]) +{ + const struct option longopts[] = { + { "type", required_argument, NULL, 't' }, + { "rw", required_argument, NULL, 'r' }, + { "help", no_argument, NULL, 'h' }, + { NULL } + }; + int use_ringbuffer = false, rw = false; + int opt; + + while ((opt = getopt_long(argc, argv, "h", longopts, NULL)) != -1) { + switch (opt) { + case 't': + if (!strcmp(optarg, "io")) + use_ringbuffer = false; + else if (!strcmp(optarg, "ringbuffer") || + !strcmp(optarg, "rb")) + use_ringbuffer = true; + else { + fprintf(stderr, "Invalid type %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case 'r': + if (!strcmp(optarg, "read")) + rw = false; + else if (!strcmp(optarg, "write")) + rw = true; + else { + fprintf(stderr, "Invalid rw %s\n", optarg); + exit(EXIT_FAILURE); + } + break; + case '?': + fprintf(stderr, "Invalid option %c\n", opt); + usage(); + exit(EXIT_FAILURE); + case 'h': + usage(); + exit(EXIT_SUCCESS); + } + } + + int fd = open("/dev/ringbuffer-test", O_RDWR); + if (fd < 0) { + fprintf(stderr, "Error opening /dev/ringbuffer-test: %m\n"); + exit(EXIT_FAILURE); + } + + struct ringbuffer_ptrs *rb = NULL; + if (use_ringbuffer) { + rb = ringbuffer(fd, rw, 4096); + if (!rb) { + fprintf(stderr, "Error from sys_ringbuffer: %m\n"); + exit(EXIT_FAILURE); + } + + fprintf(stderr, "got ringbuffer %p\n", rb); + } + + printf("Starting test with ringbuffer=%u, rw=%u\n", use_ringbuffer, rw); + static const char * const rw_str[] = { "read", "wrote" }; + + struct timeval start; + gettimeofday(&start, NULL); + size_t nr_prints = 1; + + u32 buf[BUF_NR]; + u32 idx = 0; + + while (true) { + struct timeval now; + gettimeofday(&now, NULL); + + struct timeval next_print = start; + next_print.tv_sec += nr_prints; + + if (timercmp(&now, &next_print, >)) { + printf("%s %u u32s, %lu mb/sec\n", rw_str[rw], idx, + (idx * sizeof(u32) / (now.tv_sec - start.tv_sec)) / (1UL << 20)); + nr_prints++; + if (nr_prints > 20) + break; + } + + if (rw == READ) { + int r = rb_test_read(fd, rb, buf, sizeof(buf)); + if (r <= 0) { + fprintf(stderr, "Read returned %i (%m)\n", r); + exit(EXIT_FAILURE); + } + + unsigned nr = r / sizeof(u32); + for (unsigned i = 0; i < nr; i++) { + if (buf[i] != idx + i) { + fprintf(stderr, "Read returned wrong data at idx %u: got %u instead\n", + idx + i, buf[i]); + exit(EXIT_FAILURE); + } + } + + idx += nr; + } else { + for (unsigned i = 0; i < BUF_NR; i++) + buf[i] = idx + i; + + int r = rb_test_write(fd, rb, buf, sizeof(buf)); + if (r <= 0) { + fprintf(stderr, "Write returned %i (%m)\n", r); + exit(EXIT_FAILURE); + } + + unsigned nr = r / sizeof(u32); + idx += nr; + } + } + + exit(EXIT_SUCCESS); +}