18abbffd2SArseniy Krasnov // SPDX-License-Identifier: GPL-2.0-only
28abbffd2SArseniy Krasnov /*
38abbffd2SArseniy Krasnov * vsock_perf - benchmark utility for vsock.
48abbffd2SArseniy Krasnov *
58abbffd2SArseniy Krasnov * Copyright (C) 2022 SberDevices.
68abbffd2SArseniy Krasnov *
78abbffd2SArseniy Krasnov * Author: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
88abbffd2SArseniy Krasnov */
98abbffd2SArseniy Krasnov #include <getopt.h>
108abbffd2SArseniy Krasnov #include <stdio.h>
118abbffd2SArseniy Krasnov #include <stdlib.h>
128abbffd2SArseniy Krasnov #include <stdbool.h>
138abbffd2SArseniy Krasnov #include <string.h>
148abbffd2SArseniy Krasnov #include <errno.h>
158abbffd2SArseniy Krasnov #include <unistd.h>
168abbffd2SArseniy Krasnov #include <time.h>
178abbffd2SArseniy Krasnov #include <stdint.h>
188abbffd2SArseniy Krasnov #include <poll.h>
198abbffd2SArseniy Krasnov #include <sys/socket.h>
208abbffd2SArseniy Krasnov #include <linux/vm_sockets.h>
21*e846d679SArseniy Krasnov #include <sys/mman.h>
22*e846d679SArseniy Krasnov
23*e846d679SArseniy Krasnov #include "msg_zerocopy_common.h"
248abbffd2SArseniy Krasnov
258abbffd2SArseniy Krasnov #define DEFAULT_BUF_SIZE_BYTES (128 * 1024)
268abbffd2SArseniy Krasnov #define DEFAULT_TO_SEND_BYTES (64 * 1024)
278abbffd2SArseniy Krasnov #define DEFAULT_VSOCK_BUF_BYTES (256 * 1024)
288abbffd2SArseniy Krasnov #define DEFAULT_RCVLOWAT_BYTES 1
298abbffd2SArseniy Krasnov #define DEFAULT_PORT 1234
308abbffd2SArseniy Krasnov
318abbffd2SArseniy Krasnov #define BYTES_PER_GB (1024 * 1024 * 1024ULL)
328abbffd2SArseniy Krasnov #define NSEC_PER_SEC (1000000000ULL)
338abbffd2SArseniy Krasnov
348abbffd2SArseniy Krasnov static unsigned int port = DEFAULT_PORT;
358abbffd2SArseniy Krasnov static unsigned long buf_size_bytes = DEFAULT_BUF_SIZE_BYTES;
368abbffd2SArseniy Krasnov static unsigned long vsock_buf_bytes = DEFAULT_VSOCK_BUF_BYTES;
37*e846d679SArseniy Krasnov static bool zerocopy;
388abbffd2SArseniy Krasnov
error(const char * s)398abbffd2SArseniy Krasnov static void error(const char *s)
408abbffd2SArseniy Krasnov {
418abbffd2SArseniy Krasnov perror(s);
428abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
438abbffd2SArseniy Krasnov }
448abbffd2SArseniy Krasnov
current_nsec(void)458abbffd2SArseniy Krasnov static time_t current_nsec(void)
468abbffd2SArseniy Krasnov {
478abbffd2SArseniy Krasnov struct timespec ts;
488abbffd2SArseniy Krasnov
498abbffd2SArseniy Krasnov if (clock_gettime(CLOCK_REALTIME, &ts))
508abbffd2SArseniy Krasnov error("clock_gettime");
518abbffd2SArseniy Krasnov
528abbffd2SArseniy Krasnov return (ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec;
538abbffd2SArseniy Krasnov }
548abbffd2SArseniy Krasnov
558abbffd2SArseniy Krasnov /* From lib/cmdline.c. */
memparse(const char * ptr)568abbffd2SArseniy Krasnov static unsigned long memparse(const char *ptr)
578abbffd2SArseniy Krasnov {
588abbffd2SArseniy Krasnov char *endptr;
598abbffd2SArseniy Krasnov
608abbffd2SArseniy Krasnov unsigned long long ret = strtoull(ptr, &endptr, 0);
618abbffd2SArseniy Krasnov
628abbffd2SArseniy Krasnov switch (*endptr) {
638abbffd2SArseniy Krasnov case 'E':
648abbffd2SArseniy Krasnov case 'e':
658abbffd2SArseniy Krasnov ret <<= 10;
668abbffd2SArseniy Krasnov case 'P':
678abbffd2SArseniy Krasnov case 'p':
688abbffd2SArseniy Krasnov ret <<= 10;
698abbffd2SArseniy Krasnov case 'T':
708abbffd2SArseniy Krasnov case 't':
718abbffd2SArseniy Krasnov ret <<= 10;
728abbffd2SArseniy Krasnov case 'G':
738abbffd2SArseniy Krasnov case 'g':
748abbffd2SArseniy Krasnov ret <<= 10;
758abbffd2SArseniy Krasnov case 'M':
768abbffd2SArseniy Krasnov case 'm':
778abbffd2SArseniy Krasnov ret <<= 10;
788abbffd2SArseniy Krasnov case 'K':
798abbffd2SArseniy Krasnov case 'k':
808abbffd2SArseniy Krasnov ret <<= 10;
818abbffd2SArseniy Krasnov endptr++;
828abbffd2SArseniy Krasnov default:
838abbffd2SArseniy Krasnov break;
848abbffd2SArseniy Krasnov }
858abbffd2SArseniy Krasnov
868abbffd2SArseniy Krasnov return ret;
878abbffd2SArseniy Krasnov }
888abbffd2SArseniy Krasnov
vsock_increase_buf_size(int fd)898abbffd2SArseniy Krasnov static void vsock_increase_buf_size(int fd)
908abbffd2SArseniy Krasnov {
918abbffd2SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
928abbffd2SArseniy Krasnov &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
938abbffd2SArseniy Krasnov error("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
948abbffd2SArseniy Krasnov
958abbffd2SArseniy Krasnov if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
968abbffd2SArseniy Krasnov &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
978abbffd2SArseniy Krasnov error("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
988abbffd2SArseniy Krasnov }
998abbffd2SArseniy Krasnov
vsock_connect(unsigned int cid,unsigned int port)1008abbffd2SArseniy Krasnov static int vsock_connect(unsigned int cid, unsigned int port)
1018abbffd2SArseniy Krasnov {
1028abbffd2SArseniy Krasnov union {
1038abbffd2SArseniy Krasnov struct sockaddr sa;
1048abbffd2SArseniy Krasnov struct sockaddr_vm svm;
1058abbffd2SArseniy Krasnov } addr = {
1068abbffd2SArseniy Krasnov .svm = {
1078abbffd2SArseniy Krasnov .svm_family = AF_VSOCK,
1088abbffd2SArseniy Krasnov .svm_port = port,
1098abbffd2SArseniy Krasnov .svm_cid = cid,
1108abbffd2SArseniy Krasnov },
1118abbffd2SArseniy Krasnov };
1128abbffd2SArseniy Krasnov int fd;
1138abbffd2SArseniy Krasnov
1148abbffd2SArseniy Krasnov fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1158abbffd2SArseniy Krasnov
1168abbffd2SArseniy Krasnov if (fd < 0) {
1178abbffd2SArseniy Krasnov perror("socket");
1188abbffd2SArseniy Krasnov return -1;
1198abbffd2SArseniy Krasnov }
1208abbffd2SArseniy Krasnov
1218abbffd2SArseniy Krasnov if (connect(fd, &addr.sa, sizeof(addr.svm)) < 0) {
1228abbffd2SArseniy Krasnov perror("connect");
1238abbffd2SArseniy Krasnov close(fd);
1248abbffd2SArseniy Krasnov return -1;
1258abbffd2SArseniy Krasnov }
1268abbffd2SArseniy Krasnov
1278abbffd2SArseniy Krasnov return fd;
1288abbffd2SArseniy Krasnov }
1298abbffd2SArseniy Krasnov
get_gbps(unsigned long bits,time_t ns_delta)1308abbffd2SArseniy Krasnov static float get_gbps(unsigned long bits, time_t ns_delta)
1318abbffd2SArseniy Krasnov {
1328abbffd2SArseniy Krasnov return ((float)bits / 1000000000ULL) /
1338abbffd2SArseniy Krasnov ((float)ns_delta / NSEC_PER_SEC);
1348abbffd2SArseniy Krasnov }
1358abbffd2SArseniy Krasnov
run_receiver(unsigned long rcvlowat_bytes)1368abbffd2SArseniy Krasnov static void run_receiver(unsigned long rcvlowat_bytes)
1378abbffd2SArseniy Krasnov {
1388abbffd2SArseniy Krasnov unsigned int read_cnt;
1398abbffd2SArseniy Krasnov time_t rx_begin_ns;
1408abbffd2SArseniy Krasnov time_t in_read_ns;
1418abbffd2SArseniy Krasnov size_t total_recv;
1428abbffd2SArseniy Krasnov int client_fd;
1438abbffd2SArseniy Krasnov char *data;
1448abbffd2SArseniy Krasnov int fd;
1458abbffd2SArseniy Krasnov union {
1468abbffd2SArseniy Krasnov struct sockaddr sa;
1478abbffd2SArseniy Krasnov struct sockaddr_vm svm;
1488abbffd2SArseniy Krasnov } addr = {
1498abbffd2SArseniy Krasnov .svm = {
1508abbffd2SArseniy Krasnov .svm_family = AF_VSOCK,
1518abbffd2SArseniy Krasnov .svm_port = port,
1528abbffd2SArseniy Krasnov .svm_cid = VMADDR_CID_ANY,
1538abbffd2SArseniy Krasnov },
1548abbffd2SArseniy Krasnov };
1558abbffd2SArseniy Krasnov union {
1568abbffd2SArseniy Krasnov struct sockaddr sa;
1578abbffd2SArseniy Krasnov struct sockaddr_vm svm;
1588abbffd2SArseniy Krasnov } clientaddr;
1598abbffd2SArseniy Krasnov
1608abbffd2SArseniy Krasnov socklen_t clientaddr_len = sizeof(clientaddr.svm);
1618abbffd2SArseniy Krasnov
1628abbffd2SArseniy Krasnov printf("Run as receiver\n");
1638abbffd2SArseniy Krasnov printf("Listen port %u\n", port);
1648abbffd2SArseniy Krasnov printf("RX buffer %lu bytes\n", buf_size_bytes);
1658abbffd2SArseniy Krasnov printf("vsock buffer %lu bytes\n", vsock_buf_bytes);
1668abbffd2SArseniy Krasnov printf("SO_RCVLOWAT %lu bytes\n", rcvlowat_bytes);
1678abbffd2SArseniy Krasnov
1688abbffd2SArseniy Krasnov fd = socket(AF_VSOCK, SOCK_STREAM, 0);
1698abbffd2SArseniy Krasnov
1708abbffd2SArseniy Krasnov if (fd < 0)
1718abbffd2SArseniy Krasnov error("socket");
1728abbffd2SArseniy Krasnov
1738abbffd2SArseniy Krasnov if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0)
1748abbffd2SArseniy Krasnov error("bind");
1758abbffd2SArseniy Krasnov
1768abbffd2SArseniy Krasnov if (listen(fd, 1) < 0)
1778abbffd2SArseniy Krasnov error("listen");
1788abbffd2SArseniy Krasnov
1798abbffd2SArseniy Krasnov client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
1808abbffd2SArseniy Krasnov
1818abbffd2SArseniy Krasnov if (client_fd < 0)
1828abbffd2SArseniy Krasnov error("accept");
1838abbffd2SArseniy Krasnov
1848abbffd2SArseniy Krasnov vsock_increase_buf_size(client_fd);
1858abbffd2SArseniy Krasnov
1868abbffd2SArseniy Krasnov if (setsockopt(client_fd, SOL_SOCKET, SO_RCVLOWAT,
1878abbffd2SArseniy Krasnov &rcvlowat_bytes,
1888abbffd2SArseniy Krasnov sizeof(rcvlowat_bytes)))
1898abbffd2SArseniy Krasnov error("setsockopt(SO_RCVLOWAT)");
1908abbffd2SArseniy Krasnov
1918abbffd2SArseniy Krasnov data = malloc(buf_size_bytes);
1928abbffd2SArseniy Krasnov
1938abbffd2SArseniy Krasnov if (!data) {
1948abbffd2SArseniy Krasnov fprintf(stderr, "'malloc()' failed\n");
1958abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
1968abbffd2SArseniy Krasnov }
1978abbffd2SArseniy Krasnov
1988abbffd2SArseniy Krasnov read_cnt = 0;
1998abbffd2SArseniy Krasnov in_read_ns = 0;
2008abbffd2SArseniy Krasnov total_recv = 0;
2018abbffd2SArseniy Krasnov rx_begin_ns = current_nsec();
2028abbffd2SArseniy Krasnov
2038abbffd2SArseniy Krasnov while (1) {
2048abbffd2SArseniy Krasnov struct pollfd fds = { 0 };
2058abbffd2SArseniy Krasnov
2068abbffd2SArseniy Krasnov fds.fd = client_fd;
2078abbffd2SArseniy Krasnov fds.events = POLLIN | POLLERR |
2088abbffd2SArseniy Krasnov POLLHUP | POLLRDHUP;
2098abbffd2SArseniy Krasnov
2108abbffd2SArseniy Krasnov if (poll(&fds, 1, -1) < 0)
2118abbffd2SArseniy Krasnov error("poll");
2128abbffd2SArseniy Krasnov
2138abbffd2SArseniy Krasnov if (fds.revents & POLLERR) {
2148abbffd2SArseniy Krasnov fprintf(stderr, "'poll()' error\n");
2158abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
2168abbffd2SArseniy Krasnov }
2178abbffd2SArseniy Krasnov
2188abbffd2SArseniy Krasnov if (fds.revents & POLLIN) {
2198abbffd2SArseniy Krasnov ssize_t bytes_read;
2208abbffd2SArseniy Krasnov time_t t;
2218abbffd2SArseniy Krasnov
2228abbffd2SArseniy Krasnov t = current_nsec();
2238abbffd2SArseniy Krasnov bytes_read = read(fds.fd, data, buf_size_bytes);
2248abbffd2SArseniy Krasnov in_read_ns += (current_nsec() - t);
2258abbffd2SArseniy Krasnov read_cnt++;
2268abbffd2SArseniy Krasnov
2278abbffd2SArseniy Krasnov if (!bytes_read)
2288abbffd2SArseniy Krasnov break;
2298abbffd2SArseniy Krasnov
2308abbffd2SArseniy Krasnov if (bytes_read < 0) {
2318abbffd2SArseniy Krasnov perror("read");
2328abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
2338abbffd2SArseniy Krasnov }
2348abbffd2SArseniy Krasnov
2358abbffd2SArseniy Krasnov total_recv += bytes_read;
2368abbffd2SArseniy Krasnov }
2378abbffd2SArseniy Krasnov
2388abbffd2SArseniy Krasnov if (fds.revents & (POLLHUP | POLLRDHUP))
2398abbffd2SArseniy Krasnov break;
2408abbffd2SArseniy Krasnov }
2418abbffd2SArseniy Krasnov
2428abbffd2SArseniy Krasnov printf("total bytes received: %zu\n", total_recv);
2438abbffd2SArseniy Krasnov printf("rx performance: %f Gbits/s\n",
2448abbffd2SArseniy Krasnov get_gbps(total_recv * 8, current_nsec() - rx_begin_ns));
2458abbffd2SArseniy Krasnov printf("total time in 'read()': %f sec\n", (float)in_read_ns / NSEC_PER_SEC);
2468abbffd2SArseniy Krasnov printf("average time in 'read()': %f ns\n", (float)in_read_ns / read_cnt);
2478abbffd2SArseniy Krasnov printf("POLLIN wakeups: %i\n", read_cnt);
2488abbffd2SArseniy Krasnov
2498abbffd2SArseniy Krasnov free(data);
2508abbffd2SArseniy Krasnov close(client_fd);
2518abbffd2SArseniy Krasnov close(fd);
2528abbffd2SArseniy Krasnov }
2538abbffd2SArseniy Krasnov
run_sender(int peer_cid,unsigned long to_send_bytes)2548abbffd2SArseniy Krasnov static void run_sender(int peer_cid, unsigned long to_send_bytes)
2558abbffd2SArseniy Krasnov {
2568abbffd2SArseniy Krasnov time_t tx_begin_ns;
2578abbffd2SArseniy Krasnov time_t tx_total_ns;
2588abbffd2SArseniy Krasnov size_t total_send;
259*e846d679SArseniy Krasnov time_t time_in_send;
2608abbffd2SArseniy Krasnov void *data;
2618abbffd2SArseniy Krasnov int fd;
2628abbffd2SArseniy Krasnov
263*e846d679SArseniy Krasnov if (zerocopy)
264*e846d679SArseniy Krasnov printf("Run as sender MSG_ZEROCOPY\n");
265*e846d679SArseniy Krasnov else
2668abbffd2SArseniy Krasnov printf("Run as sender\n");
267*e846d679SArseniy Krasnov
2688abbffd2SArseniy Krasnov printf("Connect to %i:%u\n", peer_cid, port);
2698abbffd2SArseniy Krasnov printf("Send %lu bytes\n", to_send_bytes);
2708abbffd2SArseniy Krasnov printf("TX buffer %lu bytes\n", buf_size_bytes);
2718abbffd2SArseniy Krasnov
2728abbffd2SArseniy Krasnov fd = vsock_connect(peer_cid, port);
2738abbffd2SArseniy Krasnov
2748abbffd2SArseniy Krasnov if (fd < 0)
2758abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
2768abbffd2SArseniy Krasnov
277*e846d679SArseniy Krasnov if (zerocopy) {
278*e846d679SArseniy Krasnov enable_so_zerocopy(fd);
279*e846d679SArseniy Krasnov
280*e846d679SArseniy Krasnov data = mmap(NULL, buf_size_bytes, PROT_READ | PROT_WRITE,
281*e846d679SArseniy Krasnov MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
282*e846d679SArseniy Krasnov if (data == MAP_FAILED) {
283*e846d679SArseniy Krasnov perror("mmap");
284*e846d679SArseniy Krasnov exit(EXIT_FAILURE);
285*e846d679SArseniy Krasnov }
286*e846d679SArseniy Krasnov } else {
2878abbffd2SArseniy Krasnov data = malloc(buf_size_bytes);
2888abbffd2SArseniy Krasnov
2898abbffd2SArseniy Krasnov if (!data) {
2908abbffd2SArseniy Krasnov fprintf(stderr, "'malloc()' failed\n");
2918abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
2928abbffd2SArseniy Krasnov }
293*e846d679SArseniy Krasnov }
2948abbffd2SArseniy Krasnov
2958abbffd2SArseniy Krasnov memset(data, 0, buf_size_bytes);
2968abbffd2SArseniy Krasnov total_send = 0;
297*e846d679SArseniy Krasnov time_in_send = 0;
2988abbffd2SArseniy Krasnov tx_begin_ns = current_nsec();
2998abbffd2SArseniy Krasnov
3008abbffd2SArseniy Krasnov while (total_send < to_send_bytes) {
3018abbffd2SArseniy Krasnov ssize_t sent;
302*e846d679SArseniy Krasnov size_t rest_bytes;
303*e846d679SArseniy Krasnov time_t before;
3048abbffd2SArseniy Krasnov
305*e846d679SArseniy Krasnov rest_bytes = to_send_bytes - total_send;
306*e846d679SArseniy Krasnov
307*e846d679SArseniy Krasnov before = current_nsec();
308*e846d679SArseniy Krasnov sent = send(fd, data, (rest_bytes > buf_size_bytes) ?
309*e846d679SArseniy Krasnov buf_size_bytes : rest_bytes,
310*e846d679SArseniy Krasnov zerocopy ? MSG_ZEROCOPY : 0);
311*e846d679SArseniy Krasnov time_in_send += (current_nsec() - before);
3128abbffd2SArseniy Krasnov
3138abbffd2SArseniy Krasnov if (sent <= 0)
3148abbffd2SArseniy Krasnov error("write");
3158abbffd2SArseniy Krasnov
3168abbffd2SArseniy Krasnov total_send += sent;
317*e846d679SArseniy Krasnov
318*e846d679SArseniy Krasnov if (zerocopy) {
319*e846d679SArseniy Krasnov struct pollfd fds = { 0 };
320*e846d679SArseniy Krasnov
321*e846d679SArseniy Krasnov fds.fd = fd;
322*e846d679SArseniy Krasnov
323*e846d679SArseniy Krasnov if (poll(&fds, 1, -1) < 0) {
324*e846d679SArseniy Krasnov perror("poll");
325*e846d679SArseniy Krasnov exit(EXIT_FAILURE);
326*e846d679SArseniy Krasnov }
327*e846d679SArseniy Krasnov
328*e846d679SArseniy Krasnov if (!(fds.revents & POLLERR)) {
329*e846d679SArseniy Krasnov fprintf(stderr, "POLLERR expected\n");
330*e846d679SArseniy Krasnov exit(EXIT_FAILURE);
331*e846d679SArseniy Krasnov }
332*e846d679SArseniy Krasnov
333*e846d679SArseniy Krasnov vsock_recv_completion(fd, NULL);
334*e846d679SArseniy Krasnov }
3358abbffd2SArseniy Krasnov }
3368abbffd2SArseniy Krasnov
3378abbffd2SArseniy Krasnov tx_total_ns = current_nsec() - tx_begin_ns;
3388abbffd2SArseniy Krasnov
3398abbffd2SArseniy Krasnov printf("total bytes sent: %zu\n", total_send);
3408abbffd2SArseniy Krasnov printf("tx performance: %f Gbits/s\n",
341*e846d679SArseniy Krasnov get_gbps(total_send * 8, time_in_send));
342*e846d679SArseniy Krasnov printf("total time in tx loop: %f sec\n",
3438abbffd2SArseniy Krasnov (float)tx_total_ns / NSEC_PER_SEC);
344*e846d679SArseniy Krasnov printf("time in 'send()': %f sec\n",
345*e846d679SArseniy Krasnov (float)time_in_send / NSEC_PER_SEC);
3468abbffd2SArseniy Krasnov
3478abbffd2SArseniy Krasnov close(fd);
348*e846d679SArseniy Krasnov
349*e846d679SArseniy Krasnov if (zerocopy)
350*e846d679SArseniy Krasnov munmap(data, buf_size_bytes);
351*e846d679SArseniy Krasnov else
3528abbffd2SArseniy Krasnov free(data);
3538abbffd2SArseniy Krasnov }
3548abbffd2SArseniy Krasnov
3558abbffd2SArseniy Krasnov static const char optstring[] = "";
3568abbffd2SArseniy Krasnov static const struct option longopts[] = {
3578abbffd2SArseniy Krasnov {
3588abbffd2SArseniy Krasnov .name = "help",
3598abbffd2SArseniy Krasnov .has_arg = no_argument,
3608abbffd2SArseniy Krasnov .val = 'H',
3618abbffd2SArseniy Krasnov },
3628abbffd2SArseniy Krasnov {
3638abbffd2SArseniy Krasnov .name = "sender",
3648abbffd2SArseniy Krasnov .has_arg = required_argument,
3658abbffd2SArseniy Krasnov .val = 'S',
3668abbffd2SArseniy Krasnov },
3678abbffd2SArseniy Krasnov {
3688abbffd2SArseniy Krasnov .name = "port",
3698abbffd2SArseniy Krasnov .has_arg = required_argument,
3708abbffd2SArseniy Krasnov .val = 'P',
3718abbffd2SArseniy Krasnov },
3728abbffd2SArseniy Krasnov {
3738abbffd2SArseniy Krasnov .name = "bytes",
3748abbffd2SArseniy Krasnov .has_arg = required_argument,
3758abbffd2SArseniy Krasnov .val = 'M',
3768abbffd2SArseniy Krasnov },
3778abbffd2SArseniy Krasnov {
3788abbffd2SArseniy Krasnov .name = "buf-size",
3798abbffd2SArseniy Krasnov .has_arg = required_argument,
3808abbffd2SArseniy Krasnov .val = 'B',
3818abbffd2SArseniy Krasnov },
3828abbffd2SArseniy Krasnov {
3838abbffd2SArseniy Krasnov .name = "vsk-size",
3848abbffd2SArseniy Krasnov .has_arg = required_argument,
3858abbffd2SArseniy Krasnov .val = 'V',
3868abbffd2SArseniy Krasnov },
3878abbffd2SArseniy Krasnov {
3888abbffd2SArseniy Krasnov .name = "rcvlowat",
3898abbffd2SArseniy Krasnov .has_arg = required_argument,
3908abbffd2SArseniy Krasnov .val = 'R',
3918abbffd2SArseniy Krasnov },
392*e846d679SArseniy Krasnov {
393*e846d679SArseniy Krasnov .name = "zerocopy",
394*e846d679SArseniy Krasnov .has_arg = no_argument,
395*e846d679SArseniy Krasnov .val = 'Z',
396*e846d679SArseniy Krasnov },
3978abbffd2SArseniy Krasnov {},
3988abbffd2SArseniy Krasnov };
3998abbffd2SArseniy Krasnov
usage(void)4008abbffd2SArseniy Krasnov static void usage(void)
4018abbffd2SArseniy Krasnov {
4028abbffd2SArseniy Krasnov printf("Usage: ./vsock_perf [--help] [options]\n"
4038abbffd2SArseniy Krasnov "\n"
4048abbffd2SArseniy Krasnov "This is benchmarking utility, to test vsock performance.\n"
4058abbffd2SArseniy Krasnov "It runs in two modes: sender or receiver. In sender mode, it\n"
4068abbffd2SArseniy Krasnov "connects to the specified CID and starts data transmission.\n"
4078abbffd2SArseniy Krasnov "\n"
4088abbffd2SArseniy Krasnov "Options:\n"
4098abbffd2SArseniy Krasnov " --help This message\n"
4108abbffd2SArseniy Krasnov " --sender <cid> Sender mode (receiver default)\n"
4118abbffd2SArseniy Krasnov " <cid> of the receiver to connect to\n"
412*e846d679SArseniy Krasnov " --zerocopy Enable zerocopy (for sender mode only)\n"
4138abbffd2SArseniy Krasnov " --port <port> Port (default %d)\n"
4148abbffd2SArseniy Krasnov " --bytes <bytes>KMG Bytes to send (default %d)\n"
4158abbffd2SArseniy Krasnov " --buf-size <bytes>KMG Data buffer size (default %d). In sender mode\n"
4168abbffd2SArseniy Krasnov " it is the buffer size, passed to 'write()'. In\n"
4178abbffd2SArseniy Krasnov " receiver mode it is the buffer size passed to 'read()'.\n"
4188abbffd2SArseniy Krasnov " --vsk-size <bytes>KMG Socket buffer size (default %d)\n"
4198abbffd2SArseniy Krasnov " --rcvlowat <bytes>KMG SO_RCVLOWAT value (default %d)\n"
4208abbffd2SArseniy Krasnov "\n", DEFAULT_PORT, DEFAULT_TO_SEND_BYTES,
4218abbffd2SArseniy Krasnov DEFAULT_BUF_SIZE_BYTES, DEFAULT_VSOCK_BUF_BYTES,
4228abbffd2SArseniy Krasnov DEFAULT_RCVLOWAT_BYTES);
4238abbffd2SArseniy Krasnov exit(EXIT_FAILURE);
4248abbffd2SArseniy Krasnov }
4258abbffd2SArseniy Krasnov
strtolx(const char * arg)4268abbffd2SArseniy Krasnov static long strtolx(const char *arg)
4278abbffd2SArseniy Krasnov {
4288abbffd2SArseniy Krasnov long value;
4298abbffd2SArseniy Krasnov char *end;
4308abbffd2SArseniy Krasnov
4318abbffd2SArseniy Krasnov value = strtol(arg, &end, 10);
4328abbffd2SArseniy Krasnov
4338abbffd2SArseniy Krasnov if (end != arg + strlen(arg))
4348abbffd2SArseniy Krasnov usage();
4358abbffd2SArseniy Krasnov
4368abbffd2SArseniy Krasnov return value;
4378abbffd2SArseniy Krasnov }
4388abbffd2SArseniy Krasnov
main(int argc,char ** argv)4398abbffd2SArseniy Krasnov int main(int argc, char **argv)
4408abbffd2SArseniy Krasnov {
4418abbffd2SArseniy Krasnov unsigned long to_send_bytes = DEFAULT_TO_SEND_BYTES;
4428abbffd2SArseniy Krasnov unsigned long rcvlowat_bytes = DEFAULT_RCVLOWAT_BYTES;
4438abbffd2SArseniy Krasnov int peer_cid = -1;
4448abbffd2SArseniy Krasnov bool sender = false;
4458abbffd2SArseniy Krasnov
4468abbffd2SArseniy Krasnov while (1) {
4478abbffd2SArseniy Krasnov int opt = getopt_long(argc, argv, optstring, longopts, NULL);
4488abbffd2SArseniy Krasnov
4498abbffd2SArseniy Krasnov if (opt == -1)
4508abbffd2SArseniy Krasnov break;
4518abbffd2SArseniy Krasnov
4528abbffd2SArseniy Krasnov switch (opt) {
4538abbffd2SArseniy Krasnov case 'V': /* Peer buffer size. */
4548abbffd2SArseniy Krasnov vsock_buf_bytes = memparse(optarg);
4558abbffd2SArseniy Krasnov break;
4568abbffd2SArseniy Krasnov case 'R': /* SO_RCVLOWAT value. */
4578abbffd2SArseniy Krasnov rcvlowat_bytes = memparse(optarg);
4588abbffd2SArseniy Krasnov break;
4598abbffd2SArseniy Krasnov case 'P': /* Port to connect to. */
4608abbffd2SArseniy Krasnov port = strtolx(optarg);
4618abbffd2SArseniy Krasnov break;
4628abbffd2SArseniy Krasnov case 'M': /* Bytes to send. */
4638abbffd2SArseniy Krasnov to_send_bytes = memparse(optarg);
4648abbffd2SArseniy Krasnov break;
4658abbffd2SArseniy Krasnov case 'B': /* Size of rx/tx buffer. */
4668abbffd2SArseniy Krasnov buf_size_bytes = memparse(optarg);
4678abbffd2SArseniy Krasnov break;
4688abbffd2SArseniy Krasnov case 'S': /* Sender mode. CID to connect to. */
4698abbffd2SArseniy Krasnov peer_cid = strtolx(optarg);
4708abbffd2SArseniy Krasnov sender = true;
4718abbffd2SArseniy Krasnov break;
4728abbffd2SArseniy Krasnov case 'H': /* Help. */
4738abbffd2SArseniy Krasnov usage();
4748abbffd2SArseniy Krasnov break;
475*e846d679SArseniy Krasnov case 'Z': /* Zerocopy. */
476*e846d679SArseniy Krasnov zerocopy = true;
477*e846d679SArseniy Krasnov break;
4788abbffd2SArseniy Krasnov default:
4798abbffd2SArseniy Krasnov usage();
4808abbffd2SArseniy Krasnov }
4818abbffd2SArseniy Krasnov }
4828abbffd2SArseniy Krasnov
4838abbffd2SArseniy Krasnov if (!sender)
4848abbffd2SArseniy Krasnov run_receiver(rcvlowat_bytes);
4858abbffd2SArseniy Krasnov else
4868abbffd2SArseniy Krasnov run_sender(peer_cid, to_send_bytes);
4878abbffd2SArseniy Krasnov
4888abbffd2SArseniy Krasnov return 0;
4898abbffd2SArseniy Krasnov }
490