From patchwork Fri Jun 3 05:44:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arseniy Krasnov X-Patchwork-Id: 12868606 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 4CA47C433EF for ; Fri, 3 Jun 2022 05:45:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241299AbiFCFp2 (ORCPT ); Fri, 3 Jun 2022 01:45:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49796 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241401AbiFCFp0 (ORCPT ); Fri, 3 Jun 2022 01:45:26 -0400 Received: from mail.sberdevices.ru (mail.sberdevices.ru [45.89.227.171]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B954139150; Thu, 2 Jun 2022 22:45:23 -0700 (PDT) Received: from s-lin-edge02.sberdevices.ru (localhost [127.0.0.1]) by mail.sberdevices.ru (Postfix) with ESMTP id B6E9C5FD02; Fri, 3 Jun 2022 08:45:21 +0300 (MSK) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sberdevices.ru; s=mail; t=1654235121; bh=7Oqay8UTTuLaTdEIv1K63aAZ4Ls+owjpz32w2F6lkAM=; h=From:To:Subject:Date:Message-ID:Content-Type:MIME-Version; b=rrJQxpIfChwugW1877d0kRziFjh3Y0qIul0gJsKSXkDP73QUInVa8tEWlPjMHKyNa v3HsJX1P5uowkQ6KmVW1GA6FTWWOPL+5nzVWk5EHXKzBPFmYB7G+J1om4umN44rgU3 MlWkrE7abcf4vM/DSSonKpwWx9R76rV0Anm1w3JLgktYSShNaT7ovLjL4az5PcptME uvSr63sG571yH0gedi0wOXJCpMDN5rSQltHqwDiZOxShkJz97HNWuhOsTzkyBFXlOV ikvcb1jwO0rOCUddx/lpuwtAmlOFZThrICLfKJd8q+S3Z6qM/tptcLChdDsh6DMeiQ NGdr7TLxPwfhA== Received: from S-MS-EXCH02.sberdevices.ru (S-MS-EXCH02.sberdevices.ru [172.16.1.5]) by mail.sberdevices.ru (Postfix) with ESMTP; Fri, 3 Jun 2022 08:45:07 +0300 (MSK) From: Arseniy Krasnov To: Stefano Garzarella , Stefan Hajnoczi , "Michael S. Tsirkin" , Jason Wang , "David S. Miller" , "Jakub Kicinski" , Paolo Abeni CC: "linux-kernel@vger.kernel.org" , "kvm@vger.kernel.org" , "virtualization@lists.linux-foundation.org" , "netdev@vger.kernel.org" , kernel , Krasnov Arseniy , Arseniy Krasnov Subject: [RFC PATCH v2 8/8] test/vsock: vsock rx zerocopy utility Thread-Topic: [RFC PATCH v2 8/8] test/vsock: vsock rx zerocopy utility Thread-Index: AQHYdw0EK1VmBCr2Q0ezERh6G9jfKw== Date: Fri, 3 Jun 2022 05:44:39 +0000 Message-ID: In-Reply-To: Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [172.16.1.12] Content-ID: MIME-Version: 1.0 X-KSMG-Rule-ID: 4 X-KSMG-Message-Action: clean X-KSMG-AntiSpam-Status: not scanned, disabled by settings X-KSMG-AntiSpam-Interceptor-Info: not scanned X-KSMG-AntiPhishing: not scanned, disabled by settings X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 1.1.2.30, bases: 2022/06/03 01:19:00 #19656765 X-KSMG-AntiVirus-Status: Clean, skipped Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org This adds simple util for zerocopy benchmarking. Signed-off-by: Arseniy Krasnov --- tools/testing/vsock/Makefile | 1 + tools/testing/vsock/rx_zerocopy.c | 356 ++++++++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 tools/testing/vsock/rx_zerocopy.c diff --git a/tools/testing/vsock/Makefile b/tools/testing/vsock/Makefile index f8293c6910c9..2cb5820ca2f3 100644 --- a/tools/testing/vsock/Makefile +++ b/tools/testing/vsock/Makefile @@ -3,6 +3,7 @@ all: test test: vsock_test vsock_diag_test vsock_test: vsock_test.o timeout.o control.o util.o vsock_diag_test: vsock_diag_test.o timeout.o control.o util.o +rx_zerocopy: rx_zerocopy.o timeout.o control.o util.o CFLAGS += -g -O2 -Werror -Wall -I. -I../../include -I../../../usr/include -Wno-pointer-sign -fno-strict-overflow -fno-strict-aliasing -fno-common -MMD -U_FORTIFY_SOURCE -D_GNU_SOURCE .PHONY: all test clean diff --git a/tools/testing/vsock/rx_zerocopy.c b/tools/testing/vsock/rx_zerocopy.c new file mode 100644 index 000000000000..55deaa665752 --- /dev/null +++ b/tools/testing/vsock/rx_zerocopy.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * rx_zerocopy - benchmark utility for zerocopy + * receive. + * + * Copyright (C) 2022 SberDevices. + * + * Author: Arseniy Krasnov + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +#define PAGE_SIZE 4096 + +#define DEFAULT_TX_SIZE 128 +#define DEFAULT_RX_SIZE 128 +#define DEFAULT_PORT 1234 + +static int client_mode = 1; +static int peer_cid = -1; +static int port = DEFAULT_PORT; +static unsigned long tx_buf_size; +static unsigned long rx_buf_size; +static unsigned long mb_to_send = 40; + +static time_t current_nsec(void) +{ + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts)) { + perror("clock_gettime"); + exit(EXIT_FAILURE); + } + + return (ts.tv_sec * 1000000000ULL) + ts.tv_nsec; +} + +/* Server accepts connection and */ +static void run_server(void) +{ + int fd; + char *data; + int client_fd; + union { + struct sockaddr sa; + struct sockaddr_vm svm; + } addr = { + .svm = { + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = VMADDR_CID_ANY, + }, + }; + union { + struct sockaddr sa; + struct sockaddr_vm svm; + } clientaddr; + + socklen_t clientaddr_len = sizeof(clientaddr.svm); + time_t tx_begin_ns; + ssize_t total_send = 0; + + fprintf(stderr, "Running server, listen %i, mb %lu tx buf %lu\n", + port, mb_to_send, tx_buf_size); + + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + + if (fd < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0) { + perror("bind"); + exit(EXIT_FAILURE); + } + + if (listen(fd, 1) < 0) { + perror("listen"); + exit(EXIT_FAILURE); + } + + client_fd = accept(fd, &clientaddr.sa, &clientaddr_len); + + if (client_fd < 0) { + perror("accept"); + exit(EXIT_FAILURE); + } + + data = malloc(tx_buf_size); + + if (data == NULL) { + fprintf(stderr, "malloc failed\n"); + exit(EXIT_FAILURE); + } + + memset(data, 0, tx_buf_size); + tx_begin_ns = current_nsec(); + + while (1) { + ssize_t sent; + + if (total_send > mb_to_send * 1024 * 1024ULL) + break; + + sent = write(client_fd, data, tx_buf_size); + + if (sent <= 0) { + perror("write"); + exit(EXIT_FAILURE); + } + + total_send += sent; + } + + free(data); + + fprintf(stderr, "Total %zi MB, time %f\n", mb_to_send, + (float)(current_nsec() - tx_begin_ns)/1000.0/1000.0/1000.0); + + close(fd); + close(client_fd); +} + +static void run_client(int zerocopy) +{ + int fd; + union { + struct sockaddr sa; + struct sockaddr_vm svm; + } addr = { + .svm = { + .svm_family = AF_VSOCK, + .svm_port = port, + .svm_cid = peer_cid, + }, + }; + unsigned long sum = 0; + void *rx_va = NULL; + unsigned long zc_on = 1; + + printf("Running client, %s mode, peer %i:%i, rx buf %lu\n", + zerocopy ? "zerocopy" : "copy", peer_cid, port, + rx_buf_size); + + fd = socket(AF_VSOCK, SOCK_STREAM, 0); + + if (fd < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + if (connect(fd, &addr.sa, sizeof(addr.svm))) { + perror("connect"); + exit(EXIT_FAILURE); + } + + if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_ZEROCOPY, + (void *)&zc_on, sizeof(zc_on))) { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + + if (zerocopy) { + rx_va = mmap(NULL, rx_buf_size, + PROT_READ, MAP_SHARED, fd, 0); + + if (rx_va == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + } + + while (1) { + struct pollfd fds = { 0 }; + int done = 0; + + fds.fd = fd; + fds.events = POLLIN | POLLERR | POLLHUP | + POLLRDHUP | POLLNVAL; + + if (poll(&fds, 1, -1) < 0) { + perror("poll"); + exit(EXIT_FAILURE); + } + + if (fds.revents & (POLLHUP | POLLRDHUP)) + done = 1; + + if (fds.revents & POLLERR) { + fprintf(stderr, "Done error\n"); + break; + } + + if (fds.revents & POLLIN) { + if (zerocopy) { + struct virtio_vsock_usr_hdr *hdr; + uintptr_t tmp_rx_va = (uintptr_t)rx_va; + socklen_t len = sizeof(tmp_rx_va); + + if (getsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_MAP_RX, + &tmp_rx_va, &len) < 0) { + perror("getsockopt"); + exit(EXIT_FAILURE); + } + + hdr = (struct virtio_vsock_usr_hdr *)tmp_rx_va; + + if (!hdr->len) { + if (done) { + fprintf(stderr, "Done, sum %lu\n", sum); + break; + } + } + + tmp_rx_va += PAGE_SIZE; + + if (madvise((void *)rx_va, rx_buf_size, + MADV_DONTNEED)) { + perror("madvise"); + exit(EXIT_FAILURE); + } + } else { + char data[rx_buf_size - PAGE_SIZE]; + ssize_t bytes_read; + + bytes_read = read(fd, data, sizeof(data)); + + if (bytes_read <= 0) + break; + } + } + } +} + +static const char optstring[] = ""; +static const struct option longopts[] = { + { + .name = "mode", + .has_arg = required_argument, + .val = 'm', + }, + { + .name = "zerocopy", + .has_arg = no_argument, + .val = 'z', + }, + { + .name = "cid", + .has_arg = required_argument, + .val = 'c', + }, + { + .name = "port", + .has_arg = required_argument, + .val = 'p', + }, + { + .name = "mb", + .has_arg = required_argument, + .val = 's', + }, + { + .name = "tx", + .has_arg = required_argument, + .val = 't', + }, + { + .name = "rx", + .has_arg = required_argument, + .val = 'r', + }, + { + .name = "help", + .has_arg = no_argument, + .val = '?', + }, + {}, +}; + +int main(int argc, char **argv) +{ + int zerocopy = 0; + + for (;;) { + int opt = getopt_long(argc, argv, optstring, longopts, NULL); + + if (opt == -1) + break; + + switch (opt) { + case 's': + mb_to_send = atoi(optarg); + break; + case 'c': + peer_cid = atoi(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 'r': + rx_buf_size = atoi(optarg); + break; + case 't': + tx_buf_size = atoi(optarg); + break; + case 'm': + if (strcmp(optarg, "client") == 0) + client_mode = 1; + else if (strcmp(optarg, "server") == 0) + client_mode = 0; + else { + fprintf(stderr, "--mode must be \"client\" or \"server\"\n"); + return EXIT_FAILURE; + } + break; + case 'z': + zerocopy = 1; + break; + default: + break; + } + + } + + if (!tx_buf_size) + tx_buf_size = DEFAULT_TX_SIZE; + + if (!rx_buf_size) + rx_buf_size = DEFAULT_RX_SIZE; + + tx_buf_size *= PAGE_SIZE; + rx_buf_size *= PAGE_SIZE; + + srand(time(NULL)); + + if (client_mode) + run_client(zerocopy); + else + run_server(); + + return 0; +}