xref: /freebsd/usr.sbin/bhyve/mevent_test.c (revision b3e76948)
1366f6083SPeter Grehan /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4366f6083SPeter Grehan  * Copyright (c) 2011 NetApp, Inc.
5366f6083SPeter Grehan  * All rights reserved.
6366f6083SPeter Grehan  *
7366f6083SPeter Grehan  * Redistribution and use in source and binary forms, with or without
8366f6083SPeter Grehan  * modification, are permitted provided that the following conditions
9366f6083SPeter Grehan  * are met:
10366f6083SPeter Grehan  * 1. Redistributions of source code must retain the above copyright
11366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer.
12366f6083SPeter Grehan  * 2. Redistributions in binary form must reproduce the above copyright
13366f6083SPeter Grehan  *    notice, this list of conditions and the following disclaimer in the
14366f6083SPeter Grehan  *    documentation and/or other materials provided with the distribution.
15366f6083SPeter Grehan  *
16366f6083SPeter Grehan  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
17366f6083SPeter Grehan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18366f6083SPeter Grehan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19366f6083SPeter Grehan  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
20366f6083SPeter Grehan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21366f6083SPeter Grehan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22366f6083SPeter Grehan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23366f6083SPeter Grehan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24366f6083SPeter Grehan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25366f6083SPeter Grehan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26366f6083SPeter Grehan  * SUCH DAMAGE.
27366f6083SPeter Grehan  */
28366f6083SPeter Grehan 
29366f6083SPeter Grehan /*
30366f6083SPeter Grehan  * Test program for the micro event library. Set up a simple TCP echo
31366f6083SPeter Grehan  * service.
32366f6083SPeter Grehan  *
33366f6083SPeter Grehan  *  cc mevent_test.c mevent.c -lpthread
34366f6083SPeter Grehan  */
35366f6083SPeter Grehan 
36366f6083SPeter Grehan #include <sys/types.h>
37151dba4aSPeter Grehan #include <sys/stdint.h>
38151dba4aSPeter Grehan #include <sys/sysctl.h>
39366f6083SPeter Grehan #include <sys/socket.h>
40366f6083SPeter Grehan #include <netinet/in.h>
41151dba4aSPeter Grehan #include <machine/cpufunc.h>
42366f6083SPeter Grehan 
43366f6083SPeter Grehan #include <stdio.h>
44366f6083SPeter Grehan #include <stdlib.h>
45366f6083SPeter Grehan #include <pthread.h>
46151dba4aSPeter Grehan #include <unistd.h>
47366f6083SPeter Grehan 
48366f6083SPeter Grehan #include "mevent.h"
49366f6083SPeter Grehan 
50366f6083SPeter Grehan #define TEST_PORT	4321
51366f6083SPeter Grehan 
52366f6083SPeter Grehan static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER;
53366f6083SPeter Grehan static pthread_cond_t accept_condvar = PTHREAD_COND_INITIALIZER;
54366f6083SPeter Grehan 
55151dba4aSPeter Grehan static struct mevent *tevp;
56151dba4aSPeter Grehan 
57151dba4aSPeter Grehan 
58366f6083SPeter Grehan #define MEVENT_ECHO
59366f6083SPeter Grehan 
60151dba4aSPeter Grehan /* Number of timer events to capture */
61151dba4aSPeter Grehan #define TEVSZ	4096
62151dba4aSPeter Grehan uint64_t tevbuf[TEVSZ];
63151dba4aSPeter Grehan 
64151dba4aSPeter Grehan static void
timer_print(void)65151dba4aSPeter Grehan timer_print(void)
66151dba4aSPeter Grehan {
67151dba4aSPeter Grehan 	uint64_t min, max, diff, sum, tsc_freq;
68151dba4aSPeter Grehan 	size_t len;
69151dba4aSPeter Grehan 	int j;
70151dba4aSPeter Grehan 
71151dba4aSPeter Grehan 	min = UINT64_MAX;
72151dba4aSPeter Grehan 	max = 0;
73151dba4aSPeter Grehan 	sum = 0;
74151dba4aSPeter Grehan 
75151dba4aSPeter Grehan 	len = sizeof(tsc_freq);
76151dba4aSPeter Grehan 	sysctlbyname("machdep.tsc_freq", &tsc_freq, &len, NULL, 0);
77151dba4aSPeter Grehan 
78151dba4aSPeter Grehan 	for (j = 1; j < TEVSZ; j++) {
79151dba4aSPeter Grehan 		/* Convert a tsc diff into microseconds */
80151dba4aSPeter Grehan 		diff = (tevbuf[j] - tevbuf[j-1]) * 1000000 / tsc_freq;
81151dba4aSPeter Grehan 		sum += diff;
82151dba4aSPeter Grehan 		if (min > diff)
83151dba4aSPeter Grehan 			min = diff;
84151dba4aSPeter Grehan 		if (max < diff)
85151dba4aSPeter Grehan 			max = diff;
86151dba4aSPeter Grehan 	}
87151dba4aSPeter Grehan 
88151dba4aSPeter Grehan 	printf("timers done: usecs, min %ld, max %ld, mean %ld\n", min, max,
89151dba4aSPeter Grehan 	    sum/(TEVSZ - 1));
90151dba4aSPeter Grehan }
91151dba4aSPeter Grehan 
92151dba4aSPeter Grehan static void
timer_callback(int fd,enum ev_type type,void * param)93151dba4aSPeter Grehan timer_callback(int fd, enum ev_type type, void *param)
94151dba4aSPeter Grehan {
95151dba4aSPeter Grehan 	static int i;
96151dba4aSPeter Grehan 
97151dba4aSPeter Grehan 	if (i >= TEVSZ)
98151dba4aSPeter Grehan 		abort();
99151dba4aSPeter Grehan 
100151dba4aSPeter Grehan 	tevbuf[i++] = rdtsc();
101151dba4aSPeter Grehan 
102151dba4aSPeter Grehan 	if (i == TEVSZ) {
103151dba4aSPeter Grehan 		mevent_delete(tevp);
104151dba4aSPeter Grehan 		timer_print();
105151dba4aSPeter Grehan 	}
106151dba4aSPeter Grehan }
107151dba4aSPeter Grehan 
108151dba4aSPeter Grehan 
109366f6083SPeter Grehan #ifdef MEVENT_ECHO
110366f6083SPeter Grehan struct esync {
111366f6083SPeter Grehan 	pthread_mutex_t	e_mt;
112366f6083SPeter Grehan 	pthread_cond_t	e_cond;
113366f6083SPeter Grehan };
114366f6083SPeter Grehan 
115366f6083SPeter Grehan static void
echoer_callback(int fd,enum ev_type type,void * param)116366f6083SPeter Grehan echoer_callback(int fd, enum ev_type type, void *param)
117366f6083SPeter Grehan {
118366f6083SPeter Grehan 	struct esync *sync = param;
119366f6083SPeter Grehan 
120366f6083SPeter Grehan 	pthread_mutex_lock(&sync->e_mt);
121366f6083SPeter Grehan 	pthread_cond_signal(&sync->e_cond);
122366f6083SPeter Grehan 	pthread_mutex_unlock(&sync->e_mt);
123366f6083SPeter Grehan }
124366f6083SPeter Grehan 
125366f6083SPeter Grehan static void *
echoer(void * param)126366f6083SPeter Grehan echoer(void *param)
127366f6083SPeter Grehan {
128366f6083SPeter Grehan 	struct esync sync;
129366f6083SPeter Grehan 	struct mevent *mev;
130366f6083SPeter Grehan 	char buf[128];
131366f6083SPeter Grehan 	int fd = (int)(uintptr_t) param;
132366f6083SPeter Grehan 	int len;
133366f6083SPeter Grehan 
134366f6083SPeter Grehan 	pthread_mutex_init(&sync.e_mt, NULL);
135366f6083SPeter Grehan 	pthread_cond_init(&sync.e_cond, NULL);
136366f6083SPeter Grehan 
137366f6083SPeter Grehan 	pthread_mutex_lock(&sync.e_mt);
138366f6083SPeter Grehan 
139366f6083SPeter Grehan 	mev = mevent_add(fd, EVF_READ, echoer_callback, &sync);
140366f6083SPeter Grehan 	if (mev == NULL) {
141366f6083SPeter Grehan 		printf("Could not allocate echoer event\n");
142989e062bSMarcelo Araujo 		exit(4);
143366f6083SPeter Grehan 	}
144366f6083SPeter Grehan 
145366f6083SPeter Grehan 	while (!pthread_cond_wait(&sync.e_cond, &sync.e_mt)) {
146366f6083SPeter Grehan 		len = read(fd, buf, sizeof(buf));
147366f6083SPeter Grehan 		if (len > 0) {
148366f6083SPeter Grehan 			write(fd, buf, len);
149366f6083SPeter Grehan 			write(0, buf, len);
150366f6083SPeter Grehan 		} else {
151366f6083SPeter Grehan 			break;
152366f6083SPeter Grehan 		}
153366f6083SPeter Grehan 	}
154366f6083SPeter Grehan 
155366f6083SPeter Grehan 	mevent_delete_close(mev);
156366f6083SPeter Grehan 
157366f6083SPeter Grehan 	pthread_mutex_unlock(&sync.e_mt);
158366f6083SPeter Grehan 	pthread_mutex_destroy(&sync.e_mt);
159366f6083SPeter Grehan 	pthread_cond_destroy(&sync.e_cond);
160151dba4aSPeter Grehan 
161151dba4aSPeter Grehan 	return (NULL);
162366f6083SPeter Grehan }
163366f6083SPeter Grehan 
164366f6083SPeter Grehan #else
165366f6083SPeter Grehan 
166366f6083SPeter Grehan static void *
echoer(void * param)167366f6083SPeter Grehan echoer(void *param)
168366f6083SPeter Grehan {
169366f6083SPeter Grehan 	char buf[128];
170366f6083SPeter Grehan 	int fd = (int)(uintptr_t) param;
171366f6083SPeter Grehan 	int len;
172366f6083SPeter Grehan 
173366f6083SPeter Grehan 	while ((len = read(fd, buf, sizeof(buf))) > 0) {
174366f6083SPeter Grehan 		write(1, buf, len);
175366f6083SPeter Grehan 	}
176151dba4aSPeter Grehan 
177151dba4aSPeter Grehan 	return (NULL);
178366f6083SPeter Grehan }
179366f6083SPeter Grehan #endif /* MEVENT_ECHO */
180366f6083SPeter Grehan 
181366f6083SPeter Grehan static void
acceptor_callback(int fd,enum ev_type type,void * param)182366f6083SPeter Grehan acceptor_callback(int fd, enum ev_type type, void *param)
183366f6083SPeter Grehan {
184366f6083SPeter Grehan 	pthread_mutex_lock(&accept_mutex);
185366f6083SPeter Grehan 	pthread_cond_signal(&accept_condvar);
186366f6083SPeter Grehan 	pthread_mutex_unlock(&accept_mutex);
187366f6083SPeter Grehan }
188366f6083SPeter Grehan 
189366f6083SPeter Grehan static void *
acceptor(void * param)190366f6083SPeter Grehan acceptor(void *param)
191366f6083SPeter Grehan {
192366f6083SPeter Grehan 	struct sockaddr_in sin;
193366f6083SPeter Grehan 	pthread_t tid;
194366f6083SPeter Grehan 	int news;
195366f6083SPeter Grehan 	int s;
196151dba4aSPeter Grehan 	static int first;
197366f6083SPeter Grehan 
198366f6083SPeter Grehan 	if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
199989e062bSMarcelo Araujo 		perror("cannot create socket");
200989e062bSMarcelo Araujo 		exit(4);
201366f6083SPeter Grehan 	}
202366f6083SPeter Grehan 
203366f6083SPeter Grehan 	sin.sin_len = sizeof(sin);
204366f6083SPeter Grehan 	sin.sin_family = AF_INET;
205366f6083SPeter Grehan 	sin.sin_addr.s_addr = htonl(INADDR_ANY);
206366f6083SPeter Grehan 	sin.sin_port = htons(TEST_PORT);
207366f6083SPeter Grehan 
208366f6083SPeter Grehan 	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
209989e062bSMarcelo Araujo 		perror("cannot bind socket");
210989e062bSMarcelo Araujo 		exit(4);
211366f6083SPeter Grehan 	}
212366f6083SPeter Grehan 
213366f6083SPeter Grehan 	if (listen(s, 1) < 0) {
214989e062bSMarcelo Araujo 		perror("cannot listen socket");
215989e062bSMarcelo Araujo 		exit(4);
216366f6083SPeter Grehan 	}
217366f6083SPeter Grehan 
218366f6083SPeter Grehan 	(void) mevent_add(s, EVF_READ, acceptor_callback, NULL);
219366f6083SPeter Grehan 
220366f6083SPeter Grehan 	pthread_mutex_lock(&accept_mutex);
221366f6083SPeter Grehan 
222366f6083SPeter Grehan 	while (!pthread_cond_wait(&accept_condvar, &accept_mutex)) {
223366f6083SPeter Grehan 		news = accept(s, NULL, NULL);
224366f6083SPeter Grehan 		if (news < 0) {
225366f6083SPeter Grehan 			perror("accept error");
226366f6083SPeter Grehan 		} else {
227151dba4aSPeter Grehan 			static int first = 1;
228151dba4aSPeter Grehan 
229151dba4aSPeter Grehan 			if (first) {
230151dba4aSPeter Grehan 				/*
231151dba4aSPeter Grehan 				 * Start a timer
232151dba4aSPeter Grehan 				 */
233151dba4aSPeter Grehan 				first = 0;
234151dba4aSPeter Grehan 				tevp = mevent_add(1, EVF_TIMER, timer_callback,
235151dba4aSPeter Grehan 						  NULL);
236151dba4aSPeter Grehan 			}
237151dba4aSPeter Grehan 
238366f6083SPeter Grehan 			printf("incoming connection, spawning thread\n");
239366f6083SPeter Grehan 			pthread_create(&tid, NULL, echoer,
240366f6083SPeter Grehan 				       (void *)(uintptr_t)news);
241366f6083SPeter Grehan 		}
242366f6083SPeter Grehan 	}
243151dba4aSPeter Grehan 
244151dba4aSPeter Grehan 	return (NULL);
245366f6083SPeter Grehan }
246366f6083SPeter Grehan 
main()247366f6083SPeter Grehan main()
248366f6083SPeter Grehan {
249366f6083SPeter Grehan 	pthread_t tid;
250366f6083SPeter Grehan 
251366f6083SPeter Grehan 	pthread_create(&tid, NULL, acceptor, NULL);
252366f6083SPeter Grehan 
253366f6083SPeter Grehan 	mevent_dispatch();
254366f6083SPeter Grehan }
255