xref: /openbmc/linux/tools/testing/vsock/vsock_perf.c (revision 8abbffd2)
1*8abbffd2SArseniy Krasnov // SPDX-License-Identifier: GPL-2.0-only
2*8abbffd2SArseniy Krasnov /*
3*8abbffd2SArseniy Krasnov  * vsock_perf - benchmark utility for vsock.
4*8abbffd2SArseniy Krasnov  *
5*8abbffd2SArseniy Krasnov  * Copyright (C) 2022 SberDevices.
6*8abbffd2SArseniy Krasnov  *
7*8abbffd2SArseniy Krasnov  * Author: Arseniy Krasnov <AVKrasnov@sberdevices.ru>
8*8abbffd2SArseniy Krasnov  */
9*8abbffd2SArseniy Krasnov #include <getopt.h>
10*8abbffd2SArseniy Krasnov #include <stdio.h>
11*8abbffd2SArseniy Krasnov #include <stdlib.h>
12*8abbffd2SArseniy Krasnov #include <stdbool.h>
13*8abbffd2SArseniy Krasnov #include <string.h>
14*8abbffd2SArseniy Krasnov #include <errno.h>
15*8abbffd2SArseniy Krasnov #include <unistd.h>
16*8abbffd2SArseniy Krasnov #include <time.h>
17*8abbffd2SArseniy Krasnov #include <stdint.h>
18*8abbffd2SArseniy Krasnov #include <poll.h>
19*8abbffd2SArseniy Krasnov #include <sys/socket.h>
20*8abbffd2SArseniy Krasnov #include <linux/vm_sockets.h>
21*8abbffd2SArseniy Krasnov 
22*8abbffd2SArseniy Krasnov #define DEFAULT_BUF_SIZE_BYTES	(128 * 1024)
23*8abbffd2SArseniy Krasnov #define DEFAULT_TO_SEND_BYTES	(64 * 1024)
24*8abbffd2SArseniy Krasnov #define DEFAULT_VSOCK_BUF_BYTES (256 * 1024)
25*8abbffd2SArseniy Krasnov #define DEFAULT_RCVLOWAT_BYTES	1
26*8abbffd2SArseniy Krasnov #define DEFAULT_PORT		1234
27*8abbffd2SArseniy Krasnov 
28*8abbffd2SArseniy Krasnov #define BYTES_PER_GB		(1024 * 1024 * 1024ULL)
29*8abbffd2SArseniy Krasnov #define NSEC_PER_SEC		(1000000000ULL)
30*8abbffd2SArseniy Krasnov 
31*8abbffd2SArseniy Krasnov static unsigned int port = DEFAULT_PORT;
32*8abbffd2SArseniy Krasnov static unsigned long buf_size_bytes = DEFAULT_BUF_SIZE_BYTES;
33*8abbffd2SArseniy Krasnov static unsigned long vsock_buf_bytes = DEFAULT_VSOCK_BUF_BYTES;
34*8abbffd2SArseniy Krasnov 
error(const char * s)35*8abbffd2SArseniy Krasnov static void error(const char *s)
36*8abbffd2SArseniy Krasnov {
37*8abbffd2SArseniy Krasnov 	perror(s);
38*8abbffd2SArseniy Krasnov 	exit(EXIT_FAILURE);
39*8abbffd2SArseniy Krasnov }
40*8abbffd2SArseniy Krasnov 
current_nsec(void)41*8abbffd2SArseniy Krasnov static time_t current_nsec(void)
42*8abbffd2SArseniy Krasnov {
43*8abbffd2SArseniy Krasnov 	struct timespec ts;
44*8abbffd2SArseniy Krasnov 
45*8abbffd2SArseniy Krasnov 	if (clock_gettime(CLOCK_REALTIME, &ts))
46*8abbffd2SArseniy Krasnov 		error("clock_gettime");
47*8abbffd2SArseniy Krasnov 
48*8abbffd2SArseniy Krasnov 	return (ts.tv_sec * NSEC_PER_SEC) + ts.tv_nsec;
49*8abbffd2SArseniy Krasnov }
50*8abbffd2SArseniy Krasnov 
51*8abbffd2SArseniy Krasnov /* From lib/cmdline.c. */
memparse(const char * ptr)52*8abbffd2SArseniy Krasnov static unsigned long memparse(const char *ptr)
53*8abbffd2SArseniy Krasnov {
54*8abbffd2SArseniy Krasnov 	char *endptr;
55*8abbffd2SArseniy Krasnov 
56*8abbffd2SArseniy Krasnov 	unsigned long long ret = strtoull(ptr, &endptr, 0);
57*8abbffd2SArseniy Krasnov 
58*8abbffd2SArseniy Krasnov 	switch (*endptr) {
59*8abbffd2SArseniy Krasnov 	case 'E':
60*8abbffd2SArseniy Krasnov 	case 'e':
61*8abbffd2SArseniy Krasnov 		ret <<= 10;
62*8abbffd2SArseniy Krasnov 	case 'P':
63*8abbffd2SArseniy Krasnov 	case 'p':
64*8abbffd2SArseniy Krasnov 		ret <<= 10;
65*8abbffd2SArseniy Krasnov 	case 'T':
66*8abbffd2SArseniy Krasnov 	case 't':
67*8abbffd2SArseniy Krasnov 		ret <<= 10;
68*8abbffd2SArseniy Krasnov 	case 'G':
69*8abbffd2SArseniy Krasnov 	case 'g':
70*8abbffd2SArseniy Krasnov 		ret <<= 10;
71*8abbffd2SArseniy Krasnov 	case 'M':
72*8abbffd2SArseniy Krasnov 	case 'm':
73*8abbffd2SArseniy Krasnov 		ret <<= 10;
74*8abbffd2SArseniy Krasnov 	case 'K':
75*8abbffd2SArseniy Krasnov 	case 'k':
76*8abbffd2SArseniy Krasnov 		ret <<= 10;
77*8abbffd2SArseniy Krasnov 		endptr++;
78*8abbffd2SArseniy Krasnov 	default:
79*8abbffd2SArseniy Krasnov 		break;
80*8abbffd2SArseniy Krasnov 	}
81*8abbffd2SArseniy Krasnov 
82*8abbffd2SArseniy Krasnov 	return ret;
83*8abbffd2SArseniy Krasnov }
84*8abbffd2SArseniy Krasnov 
vsock_increase_buf_size(int fd)85*8abbffd2SArseniy Krasnov static void vsock_increase_buf_size(int fd)
86*8abbffd2SArseniy Krasnov {
87*8abbffd2SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
88*8abbffd2SArseniy Krasnov 		       &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
89*8abbffd2SArseniy Krasnov 		error("setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
90*8abbffd2SArseniy Krasnov 
91*8abbffd2SArseniy Krasnov 	if (setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
92*8abbffd2SArseniy Krasnov 		       &vsock_buf_bytes, sizeof(vsock_buf_bytes)))
93*8abbffd2SArseniy Krasnov 		error("setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
94*8abbffd2SArseniy Krasnov }
95*8abbffd2SArseniy Krasnov 
vsock_connect(unsigned int cid,unsigned int port)96*8abbffd2SArseniy Krasnov static int vsock_connect(unsigned int cid, unsigned int port)
97*8abbffd2SArseniy Krasnov {
98*8abbffd2SArseniy Krasnov 	union {
99*8abbffd2SArseniy Krasnov 		struct sockaddr sa;
100*8abbffd2SArseniy Krasnov 		struct sockaddr_vm svm;
101*8abbffd2SArseniy Krasnov 	} addr = {
102*8abbffd2SArseniy Krasnov 		.svm = {
103*8abbffd2SArseniy Krasnov 			.svm_family = AF_VSOCK,
104*8abbffd2SArseniy Krasnov 			.svm_port = port,
105*8abbffd2SArseniy Krasnov 			.svm_cid = cid,
106*8abbffd2SArseniy Krasnov 		},
107*8abbffd2SArseniy Krasnov 	};
108*8abbffd2SArseniy Krasnov 	int fd;
109*8abbffd2SArseniy Krasnov 
110*8abbffd2SArseniy Krasnov 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
111*8abbffd2SArseniy Krasnov 
112*8abbffd2SArseniy Krasnov 	if (fd < 0) {
113*8abbffd2SArseniy Krasnov 		perror("socket");
114*8abbffd2SArseniy Krasnov 		return -1;
115*8abbffd2SArseniy Krasnov 	}
116*8abbffd2SArseniy Krasnov 
117*8abbffd2SArseniy Krasnov 	if (connect(fd, &addr.sa, sizeof(addr.svm)) < 0) {
118*8abbffd2SArseniy Krasnov 		perror("connect");
119*8abbffd2SArseniy Krasnov 		close(fd);
120*8abbffd2SArseniy Krasnov 		return -1;
121*8abbffd2SArseniy Krasnov 	}
122*8abbffd2SArseniy Krasnov 
123*8abbffd2SArseniy Krasnov 	return fd;
124*8abbffd2SArseniy Krasnov }
125*8abbffd2SArseniy Krasnov 
get_gbps(unsigned long bits,time_t ns_delta)126*8abbffd2SArseniy Krasnov static float get_gbps(unsigned long bits, time_t ns_delta)
127*8abbffd2SArseniy Krasnov {
128*8abbffd2SArseniy Krasnov 	return ((float)bits / 1000000000ULL) /
129*8abbffd2SArseniy Krasnov 	       ((float)ns_delta / NSEC_PER_SEC);
130*8abbffd2SArseniy Krasnov }
131*8abbffd2SArseniy Krasnov 
run_receiver(unsigned long rcvlowat_bytes)132*8abbffd2SArseniy Krasnov static void run_receiver(unsigned long rcvlowat_bytes)
133*8abbffd2SArseniy Krasnov {
134*8abbffd2SArseniy Krasnov 	unsigned int read_cnt;
135*8abbffd2SArseniy Krasnov 	time_t rx_begin_ns;
136*8abbffd2SArseniy Krasnov 	time_t in_read_ns;
137*8abbffd2SArseniy Krasnov 	size_t total_recv;
138*8abbffd2SArseniy Krasnov 	int client_fd;
139*8abbffd2SArseniy Krasnov 	char *data;
140*8abbffd2SArseniy Krasnov 	int fd;
141*8abbffd2SArseniy Krasnov 	union {
142*8abbffd2SArseniy Krasnov 		struct sockaddr sa;
143*8abbffd2SArseniy Krasnov 		struct sockaddr_vm svm;
144*8abbffd2SArseniy Krasnov 	} addr = {
145*8abbffd2SArseniy Krasnov 		.svm = {
146*8abbffd2SArseniy Krasnov 			.svm_family = AF_VSOCK,
147*8abbffd2SArseniy Krasnov 			.svm_port = port,
148*8abbffd2SArseniy Krasnov 			.svm_cid = VMADDR_CID_ANY,
149*8abbffd2SArseniy Krasnov 		},
150*8abbffd2SArseniy Krasnov 	};
151*8abbffd2SArseniy Krasnov 	union {
152*8abbffd2SArseniy Krasnov 		struct sockaddr sa;
153*8abbffd2SArseniy Krasnov 		struct sockaddr_vm svm;
154*8abbffd2SArseniy Krasnov 	} clientaddr;
155*8abbffd2SArseniy Krasnov 
156*8abbffd2SArseniy Krasnov 	socklen_t clientaddr_len = sizeof(clientaddr.svm);
157*8abbffd2SArseniy Krasnov 
158*8abbffd2SArseniy Krasnov 	printf("Run as receiver\n");
159*8abbffd2SArseniy Krasnov 	printf("Listen port %u\n", port);
160*8abbffd2SArseniy Krasnov 	printf("RX buffer %lu bytes\n", buf_size_bytes);
161*8abbffd2SArseniy Krasnov 	printf("vsock buffer %lu bytes\n", vsock_buf_bytes);
162*8abbffd2SArseniy Krasnov 	printf("SO_RCVLOWAT %lu bytes\n", rcvlowat_bytes);
163*8abbffd2SArseniy Krasnov 
164*8abbffd2SArseniy Krasnov 	fd = socket(AF_VSOCK, SOCK_STREAM, 0);
165*8abbffd2SArseniy Krasnov 
166*8abbffd2SArseniy Krasnov 	if (fd < 0)
167*8abbffd2SArseniy Krasnov 		error("socket");
168*8abbffd2SArseniy Krasnov 
169*8abbffd2SArseniy Krasnov 	if (bind(fd, &addr.sa, sizeof(addr.svm)) < 0)
170*8abbffd2SArseniy Krasnov 		error("bind");
171*8abbffd2SArseniy Krasnov 
172*8abbffd2SArseniy Krasnov 	if (listen(fd, 1) < 0)
173*8abbffd2SArseniy Krasnov 		error("listen");
174*8abbffd2SArseniy Krasnov 
175*8abbffd2SArseniy Krasnov 	client_fd = accept(fd, &clientaddr.sa, &clientaddr_len);
176*8abbffd2SArseniy Krasnov 
177*8abbffd2SArseniy Krasnov 	if (client_fd < 0)
178*8abbffd2SArseniy Krasnov 		error("accept");
179*8abbffd2SArseniy Krasnov 
180*8abbffd2SArseniy Krasnov 	vsock_increase_buf_size(client_fd);
181*8abbffd2SArseniy Krasnov 
182*8abbffd2SArseniy Krasnov 	if (setsockopt(client_fd, SOL_SOCKET, SO_RCVLOWAT,
183*8abbffd2SArseniy Krasnov 		       &rcvlowat_bytes,
184*8abbffd2SArseniy Krasnov 		       sizeof(rcvlowat_bytes)))
185*8abbffd2SArseniy Krasnov 		error("setsockopt(SO_RCVLOWAT)");
186*8abbffd2SArseniy Krasnov 
187*8abbffd2SArseniy Krasnov 	data = malloc(buf_size_bytes);
188*8abbffd2SArseniy Krasnov 
189*8abbffd2SArseniy Krasnov 	if (!data) {
190*8abbffd2SArseniy Krasnov 		fprintf(stderr, "'malloc()' failed\n");
191*8abbffd2SArseniy Krasnov 		exit(EXIT_FAILURE);
192*8abbffd2SArseniy Krasnov 	}
193*8abbffd2SArseniy Krasnov 
194*8abbffd2SArseniy Krasnov 	read_cnt = 0;
195*8abbffd2SArseniy Krasnov 	in_read_ns = 0;
196*8abbffd2SArseniy Krasnov 	total_recv = 0;
197*8abbffd2SArseniy Krasnov 	rx_begin_ns = current_nsec();
198*8abbffd2SArseniy Krasnov 
199*8abbffd2SArseniy Krasnov 	while (1) {
200*8abbffd2SArseniy Krasnov 		struct pollfd fds = { 0 };
201*8abbffd2SArseniy Krasnov 
202*8abbffd2SArseniy Krasnov 		fds.fd = client_fd;
203*8abbffd2SArseniy Krasnov 		fds.events = POLLIN | POLLERR |
204*8abbffd2SArseniy Krasnov 			     POLLHUP | POLLRDHUP;
205*8abbffd2SArseniy Krasnov 
206*8abbffd2SArseniy Krasnov 		if (poll(&fds, 1, -1) < 0)
207*8abbffd2SArseniy Krasnov 			error("poll");
208*8abbffd2SArseniy Krasnov 
209*8abbffd2SArseniy Krasnov 		if (fds.revents & POLLERR) {
210*8abbffd2SArseniy Krasnov 			fprintf(stderr, "'poll()' error\n");
211*8abbffd2SArseniy Krasnov 			exit(EXIT_FAILURE);
212*8abbffd2SArseniy Krasnov 		}
213*8abbffd2SArseniy Krasnov 
214*8abbffd2SArseniy Krasnov 		if (fds.revents & POLLIN) {
215*8abbffd2SArseniy Krasnov 			ssize_t bytes_read;
216*8abbffd2SArseniy Krasnov 			time_t t;
217*8abbffd2SArseniy Krasnov 
218*8abbffd2SArseniy Krasnov 			t = current_nsec();
219*8abbffd2SArseniy Krasnov 			bytes_read = read(fds.fd, data, buf_size_bytes);
220*8abbffd2SArseniy Krasnov 			in_read_ns += (current_nsec() - t);
221*8abbffd2SArseniy Krasnov 			read_cnt++;
222*8abbffd2SArseniy Krasnov 
223*8abbffd2SArseniy Krasnov 			if (!bytes_read)
224*8abbffd2SArseniy Krasnov 				break;
225*8abbffd2SArseniy Krasnov 
226*8abbffd2SArseniy Krasnov 			if (bytes_read < 0) {
227*8abbffd2SArseniy Krasnov 				perror("read");
228*8abbffd2SArseniy Krasnov 				exit(EXIT_FAILURE);
229*8abbffd2SArseniy Krasnov 			}
230*8abbffd2SArseniy Krasnov 
231*8abbffd2SArseniy Krasnov 			total_recv += bytes_read;
232*8abbffd2SArseniy Krasnov 		}
233*8abbffd2SArseniy Krasnov 
234*8abbffd2SArseniy Krasnov 		if (fds.revents & (POLLHUP | POLLRDHUP))
235*8abbffd2SArseniy Krasnov 			break;
236*8abbffd2SArseniy Krasnov 	}
237*8abbffd2SArseniy Krasnov 
238*8abbffd2SArseniy Krasnov 	printf("total bytes received: %zu\n", total_recv);
239*8abbffd2SArseniy Krasnov 	printf("rx performance: %f Gbits/s\n",
240*8abbffd2SArseniy Krasnov 	       get_gbps(total_recv * 8, current_nsec() - rx_begin_ns));
241*8abbffd2SArseniy Krasnov 	printf("total time in 'read()': %f sec\n", (float)in_read_ns / NSEC_PER_SEC);
242*8abbffd2SArseniy Krasnov 	printf("average time in 'read()': %f ns\n", (float)in_read_ns / read_cnt);
243*8abbffd2SArseniy Krasnov 	printf("POLLIN wakeups: %i\n", read_cnt);
244*8abbffd2SArseniy Krasnov 
245*8abbffd2SArseniy Krasnov 	free(data);
246*8abbffd2SArseniy Krasnov 	close(client_fd);
247*8abbffd2SArseniy Krasnov 	close(fd);
248*8abbffd2SArseniy Krasnov }
249*8abbffd2SArseniy Krasnov 
run_sender(int peer_cid,unsigned long to_send_bytes)250*8abbffd2SArseniy Krasnov static void run_sender(int peer_cid, unsigned long to_send_bytes)
251*8abbffd2SArseniy Krasnov {
252*8abbffd2SArseniy Krasnov 	time_t tx_begin_ns;
253*8abbffd2SArseniy Krasnov 	time_t tx_total_ns;
254*8abbffd2SArseniy Krasnov 	size_t total_send;
255*8abbffd2SArseniy Krasnov 	void *data;
256*8abbffd2SArseniy Krasnov 	int fd;
257*8abbffd2SArseniy Krasnov 
258*8abbffd2SArseniy Krasnov 	printf("Run as sender\n");
259*8abbffd2SArseniy Krasnov 	printf("Connect to %i:%u\n", peer_cid, port);
260*8abbffd2SArseniy Krasnov 	printf("Send %lu bytes\n", to_send_bytes);
261*8abbffd2SArseniy Krasnov 	printf("TX buffer %lu bytes\n", buf_size_bytes);
262*8abbffd2SArseniy Krasnov 
263*8abbffd2SArseniy Krasnov 	fd = vsock_connect(peer_cid, port);
264*8abbffd2SArseniy Krasnov 
265*8abbffd2SArseniy Krasnov 	if (fd < 0)
266*8abbffd2SArseniy Krasnov 		exit(EXIT_FAILURE);
267*8abbffd2SArseniy Krasnov 
268*8abbffd2SArseniy Krasnov 	data = malloc(buf_size_bytes);
269*8abbffd2SArseniy Krasnov 
270*8abbffd2SArseniy Krasnov 	if (!data) {
271*8abbffd2SArseniy Krasnov 		fprintf(stderr, "'malloc()' failed\n");
272*8abbffd2SArseniy Krasnov 		exit(EXIT_FAILURE);
273*8abbffd2SArseniy Krasnov 	}
274*8abbffd2SArseniy Krasnov 
275*8abbffd2SArseniy Krasnov 	memset(data, 0, buf_size_bytes);
276*8abbffd2SArseniy Krasnov 	total_send = 0;
277*8abbffd2SArseniy Krasnov 	tx_begin_ns = current_nsec();
278*8abbffd2SArseniy Krasnov 
279*8abbffd2SArseniy Krasnov 	while (total_send < to_send_bytes) {
280*8abbffd2SArseniy Krasnov 		ssize_t sent;
281*8abbffd2SArseniy Krasnov 
282*8abbffd2SArseniy Krasnov 		sent = write(fd, data, buf_size_bytes);
283*8abbffd2SArseniy Krasnov 
284*8abbffd2SArseniy Krasnov 		if (sent <= 0)
285*8abbffd2SArseniy Krasnov 			error("write");
286*8abbffd2SArseniy Krasnov 
287*8abbffd2SArseniy Krasnov 		total_send += sent;
288*8abbffd2SArseniy Krasnov 	}
289*8abbffd2SArseniy Krasnov 
290*8abbffd2SArseniy Krasnov 	tx_total_ns = current_nsec() - tx_begin_ns;
291*8abbffd2SArseniy Krasnov 
292*8abbffd2SArseniy Krasnov 	printf("total bytes sent: %zu\n", total_send);
293*8abbffd2SArseniy Krasnov 	printf("tx performance: %f Gbits/s\n",
294*8abbffd2SArseniy Krasnov 	       get_gbps(total_send * 8, tx_total_ns));
295*8abbffd2SArseniy Krasnov 	printf("total time in 'write()': %f sec\n",
296*8abbffd2SArseniy Krasnov 	       (float)tx_total_ns / NSEC_PER_SEC);
297*8abbffd2SArseniy Krasnov 
298*8abbffd2SArseniy Krasnov 	close(fd);
299*8abbffd2SArseniy Krasnov 	free(data);
300*8abbffd2SArseniy Krasnov }
301*8abbffd2SArseniy Krasnov 
302*8abbffd2SArseniy Krasnov static const char optstring[] = "";
303*8abbffd2SArseniy Krasnov static const struct option longopts[] = {
304*8abbffd2SArseniy Krasnov 	{
305*8abbffd2SArseniy Krasnov 		.name = "help",
306*8abbffd2SArseniy Krasnov 		.has_arg = no_argument,
307*8abbffd2SArseniy Krasnov 		.val = 'H',
308*8abbffd2SArseniy Krasnov 	},
309*8abbffd2SArseniy Krasnov 	{
310*8abbffd2SArseniy Krasnov 		.name = "sender",
311*8abbffd2SArseniy Krasnov 		.has_arg = required_argument,
312*8abbffd2SArseniy Krasnov 		.val = 'S',
313*8abbffd2SArseniy Krasnov 	},
314*8abbffd2SArseniy Krasnov 	{
315*8abbffd2SArseniy Krasnov 		.name = "port",
316*8abbffd2SArseniy Krasnov 		.has_arg = required_argument,
317*8abbffd2SArseniy Krasnov 		.val = 'P',
318*8abbffd2SArseniy Krasnov 	},
319*8abbffd2SArseniy Krasnov 	{
320*8abbffd2SArseniy Krasnov 		.name = "bytes",
321*8abbffd2SArseniy Krasnov 		.has_arg = required_argument,
322*8abbffd2SArseniy Krasnov 		.val = 'M',
323*8abbffd2SArseniy Krasnov 	},
324*8abbffd2SArseniy Krasnov 	{
325*8abbffd2SArseniy Krasnov 		.name = "buf-size",
326*8abbffd2SArseniy Krasnov 		.has_arg = required_argument,
327*8abbffd2SArseniy Krasnov 		.val = 'B',
328*8abbffd2SArseniy Krasnov 	},
329*8abbffd2SArseniy Krasnov 	{
330*8abbffd2SArseniy Krasnov 		.name = "vsk-size",
331*8abbffd2SArseniy Krasnov 		.has_arg = required_argument,
332*8abbffd2SArseniy Krasnov 		.val = 'V',
333*8abbffd2SArseniy Krasnov 	},
334*8abbffd2SArseniy Krasnov 	{
335*8abbffd2SArseniy Krasnov 		.name = "rcvlowat",
336*8abbffd2SArseniy Krasnov 		.has_arg = required_argument,
337*8abbffd2SArseniy Krasnov 		.val = 'R',
338*8abbffd2SArseniy Krasnov 	},
339*8abbffd2SArseniy Krasnov 	{},
340*8abbffd2SArseniy Krasnov };
341*8abbffd2SArseniy Krasnov 
usage(void)342*8abbffd2SArseniy Krasnov static void usage(void)
343*8abbffd2SArseniy Krasnov {
344*8abbffd2SArseniy Krasnov 	printf("Usage: ./vsock_perf [--help] [options]\n"
345*8abbffd2SArseniy Krasnov 	       "\n"
346*8abbffd2SArseniy Krasnov 	       "This is benchmarking utility, to test vsock performance.\n"
347*8abbffd2SArseniy Krasnov 	       "It runs in two modes: sender or receiver. In sender mode, it\n"
348*8abbffd2SArseniy Krasnov 	       "connects to the specified CID and starts data transmission.\n"
349*8abbffd2SArseniy Krasnov 	       "\n"
350*8abbffd2SArseniy Krasnov 	       "Options:\n"
351*8abbffd2SArseniy Krasnov 	       "  --help			This message\n"
352*8abbffd2SArseniy Krasnov 	       "  --sender   <cid>		Sender mode (receiver default)\n"
353*8abbffd2SArseniy Krasnov 	       "                                <cid> of the receiver to connect to\n"
354*8abbffd2SArseniy Krasnov 	       "  --port     <port>		Port (default %d)\n"
355*8abbffd2SArseniy Krasnov 	       "  --bytes    <bytes>KMG		Bytes to send (default %d)\n"
356*8abbffd2SArseniy Krasnov 	       "  --buf-size <bytes>KMG		Data buffer size (default %d). In sender mode\n"
357*8abbffd2SArseniy Krasnov 	       "                                it is the buffer size, passed to 'write()'. In\n"
358*8abbffd2SArseniy Krasnov 	       "                                receiver mode it is the buffer size passed to 'read()'.\n"
359*8abbffd2SArseniy Krasnov 	       "  --vsk-size <bytes>KMG		Socket buffer size (default %d)\n"
360*8abbffd2SArseniy Krasnov 	       "  --rcvlowat <bytes>KMG		SO_RCVLOWAT value (default %d)\n"
361*8abbffd2SArseniy Krasnov 	       "\n", DEFAULT_PORT, DEFAULT_TO_SEND_BYTES,
362*8abbffd2SArseniy Krasnov 	       DEFAULT_BUF_SIZE_BYTES, DEFAULT_VSOCK_BUF_BYTES,
363*8abbffd2SArseniy Krasnov 	       DEFAULT_RCVLOWAT_BYTES);
364*8abbffd2SArseniy Krasnov 	exit(EXIT_FAILURE);
365*8abbffd2SArseniy Krasnov }
366*8abbffd2SArseniy Krasnov 
strtolx(const char * arg)367*8abbffd2SArseniy Krasnov static long strtolx(const char *arg)
368*8abbffd2SArseniy Krasnov {
369*8abbffd2SArseniy Krasnov 	long value;
370*8abbffd2SArseniy Krasnov 	char *end;
371*8abbffd2SArseniy Krasnov 
372*8abbffd2SArseniy Krasnov 	value = strtol(arg, &end, 10);
373*8abbffd2SArseniy Krasnov 
374*8abbffd2SArseniy Krasnov 	if (end != arg + strlen(arg))
375*8abbffd2SArseniy Krasnov 		usage();
376*8abbffd2SArseniy Krasnov 
377*8abbffd2SArseniy Krasnov 	return value;
378*8abbffd2SArseniy Krasnov }
379*8abbffd2SArseniy Krasnov 
main(int argc,char ** argv)380*8abbffd2SArseniy Krasnov int main(int argc, char **argv)
381*8abbffd2SArseniy Krasnov {
382*8abbffd2SArseniy Krasnov 	unsigned long to_send_bytes = DEFAULT_TO_SEND_BYTES;
383*8abbffd2SArseniy Krasnov 	unsigned long rcvlowat_bytes = DEFAULT_RCVLOWAT_BYTES;
384*8abbffd2SArseniy Krasnov 	int peer_cid = -1;
385*8abbffd2SArseniy Krasnov 	bool sender = false;
386*8abbffd2SArseniy Krasnov 
387*8abbffd2SArseniy Krasnov 	while (1) {
388*8abbffd2SArseniy Krasnov 		int opt = getopt_long(argc, argv, optstring, longopts, NULL);
389*8abbffd2SArseniy Krasnov 
390*8abbffd2SArseniy Krasnov 		if (opt == -1)
391*8abbffd2SArseniy Krasnov 			break;
392*8abbffd2SArseniy Krasnov 
393*8abbffd2SArseniy Krasnov 		switch (opt) {
394*8abbffd2SArseniy Krasnov 		case 'V': /* Peer buffer size. */
395*8abbffd2SArseniy Krasnov 			vsock_buf_bytes = memparse(optarg);
396*8abbffd2SArseniy Krasnov 			break;
397*8abbffd2SArseniy Krasnov 		case 'R': /* SO_RCVLOWAT value. */
398*8abbffd2SArseniy Krasnov 			rcvlowat_bytes = memparse(optarg);
399*8abbffd2SArseniy Krasnov 			break;
400*8abbffd2SArseniy Krasnov 		case 'P': /* Port to connect to. */
401*8abbffd2SArseniy Krasnov 			port = strtolx(optarg);
402*8abbffd2SArseniy Krasnov 			break;
403*8abbffd2SArseniy Krasnov 		case 'M': /* Bytes to send. */
404*8abbffd2SArseniy Krasnov 			to_send_bytes = memparse(optarg);
405*8abbffd2SArseniy Krasnov 			break;
406*8abbffd2SArseniy Krasnov 		case 'B': /* Size of rx/tx buffer. */
407*8abbffd2SArseniy Krasnov 			buf_size_bytes = memparse(optarg);
408*8abbffd2SArseniy Krasnov 			break;
409*8abbffd2SArseniy Krasnov 		case 'S': /* Sender mode. CID to connect to. */
410*8abbffd2SArseniy Krasnov 			peer_cid = strtolx(optarg);
411*8abbffd2SArseniy Krasnov 			sender = true;
412*8abbffd2SArseniy Krasnov 			break;
413*8abbffd2SArseniy Krasnov 		case 'H': /* Help. */
414*8abbffd2SArseniy Krasnov 			usage();
415*8abbffd2SArseniy Krasnov 			break;
416*8abbffd2SArseniy Krasnov 		default:
417*8abbffd2SArseniy Krasnov 			usage();
418*8abbffd2SArseniy Krasnov 		}
419*8abbffd2SArseniy Krasnov 	}
420*8abbffd2SArseniy Krasnov 
421*8abbffd2SArseniy Krasnov 	if (!sender)
422*8abbffd2SArseniy Krasnov 		run_receiver(rcvlowat_bytes);
423*8abbffd2SArseniy Krasnov 	else
424*8abbffd2SArseniy Krasnov 		run_sender(peer_cid, to_send_bytes);
425*8abbffd2SArseniy Krasnov 
426*8abbffd2SArseniy Krasnov 	return 0;
427*8abbffd2SArseniy Krasnov }
428