xref: /xnu-11215.41.3/tests/skywalk/skt_nslots.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*
2  * Copyright (c) 2016-2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <assert.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <uuid/uuid.h>
35 #include <sys/select.h>
36 #include <poll.h>
37 #include <sys/event.h>
38 #include <darwintest.h>
39 #include "skywalk_test_driver.h"
40 #include "skywalk_test_common.h"
41 #include "skywalk_test_utils.h"
42 
43 int
skt_nslots_common(int argc,char * argv[],uint32_t nslots,uint32_t interval,int method)44 skt_nslots_common(int argc, char *argv[], uint32_t nslots, uint32_t interval, int method)
45 {
46 	int error;
47 	channel_t channel;
48 	uuid_t channel_uuid;
49 	ring_id_t ringid;
50 	channel_ring_t ring;
51 	channel_slot_t prev, slot;
52 	channel_attr_t attr;
53 	uint32_t avail;
54 	slot_prop_t prop;
55 	int channelfd;
56 	uint32_t sendcount;
57 	uint32_t recvcount;
58 	uint64_t slotsize;
59 	fd_set fdset, efdset;
60 	struct pollfd fds;
61 	int kq;
62 	struct kevent kev;
63 	time_t start = time(NULL);
64 	time_t now, then = start;
65 
66 	sendcount = 0;
67 	recvcount = 0;
68 
69 	error = uuid_parse(argv[3], channel_uuid);
70 	SKTC_ASSERT_ERR(!error);
71 
72 	channel = sktu_channel_create_extended(channel_uuid, 0,
73 	    CHANNEL_DIR_TX_RX, CHANNEL_RING_ID_ANY, NULL,
74 	    -1, -1, -1, -1, -1, -1, -1, 1, -1, -1);
75 	assert(channel);
76 
77 	channelfd = os_channel_get_fd(channel);
78 	assert(channelfd != -1);
79 
80 	switch (method) {
81 	case 0:
82 		FD_ZERO(&fdset);
83 		FD_ZERO(&efdset);
84 		break;
85 	case 1:
86 		fds.fd = channelfd;
87 		break;
88 	case 2:
89 		kq = kqueue();
90 		assert(kq != -1);
91 		break;
92 	default:
93 		abort();
94 	}
95 
96 	attr = os_channel_attr_create();
97 
98 	error = os_channel_read_attr(channel, attr);
99 	SKTC_ASSERT_ERR(!error);
100 
101 	if (nslots == -1) {
102 		uint64_t attrval = -1;
103 		error = os_channel_attr_get(attr, CHANNEL_ATTR_TX_SLOTS, &attrval);
104 		SKTC_ASSERT_ERR(!error);
105 		assert(attrval != -1);
106 		nslots = attrval;
107 	}
108 
109 	slotsize = -1;
110 	error = os_channel_attr_get(attr, CHANNEL_ATTR_SLOT_BUF_SIZE, &slotsize);
111 	SKTC_ASSERT_ERR(!error);
112 	assert(slotsize != -1);
113 	assert(slotsize >= sizeof(sendcount));
114 
115 	os_channel_attr_destroy(attr);
116 
117 	while (recvcount < nslots) {
118 		now = time(NULL);
119 		if (now > then) {
120 			T_LOG("time %ld send %d recv %d of %d (%2.2f%%, est %ld secs left)\n",
121 			    now - start, sendcount, recvcount, nslots,
122 			    (double)recvcount * 100 / nslots,
123 			    (long)((double)(now - start) * nslots / recvcount) - (now - start));
124 			then = now;
125 		}
126 
127 		if (sendcount < nslots) {
128 			ringid = os_channel_ring_id(channel, CHANNEL_FIRST_TX_RING);
129 			ring = os_channel_tx_ring(channel, ringid);
130 			assert(ring);
131 
132 			switch (method) {
133 			case 0:
134 				FD_SET(channelfd, &fdset);
135 				FD_SET(channelfd, &efdset);
136 				error = select(channelfd + 1, NULL, &fdset, &efdset, NULL);
137 				SKTC_ASSERT_ERR(error != -1);
138 				SKTC_ASSERT_ERR(error == 1);
139 				assert(FD_ISSET(channelfd, &fdset));
140 				assert(!FD_ISSET(channelfd, &efdset));
141 				break;
142 			case 1:
143 				fds.events = POLLWRNORM;
144 				error = poll(&fds, 1, -1);
145 				SKTC_ASSERT_ERR(error != -1);
146 				SKTC_ASSERT_ERR(error == 1);
147 				assert(fds.fd == channelfd);
148 				assert(fds.events == POLLWRNORM);
149 				assert(fds.revents == POLLWRNORM);
150 				break;
151 			case 2:
152 				EV_SET(&kev, channelfd, EVFILT_WRITE, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, NULL);
153 				error = kevent(kq, &kev, 1, &kev, 1, NULL);
154 				SKTC_ASSERT_ERR(error != -1);
155 				SKTC_ASSERT_ERR(error == 1);
156 				assert(kev.filter == EVFILT_WRITE);
157 				assert(kev.ident == channelfd);
158 				assert(kev.udata == NULL);
159 				break;
160 			default:
161 				abort();
162 			}
163 
164 			avail = os_channel_available_slot_count(ring);
165 			assert(avail);
166 
167 			prev = NULL;
168 			slot = os_channel_get_next_slot(ring, NULL, &prop);
169 			assert(slot);
170 
171 			for (uint32_t i = 0; i < avail; i++) {
172 				assert(slot);
173 
174 				if (sendcount == nslots || i == interval) {
175 					slot = NULL;
176 					break;
177 				}
178 
179 				assert(prop.sp_len == slotsize);
180 				memcpy((void *)prop.sp_buf_ptr, &sendcount, sizeof(sendcount));
181 				prop.sp_len = sizeof(sendcount);
182 				os_channel_set_slot_properties(ring, slot, &prop);
183 				sendcount++;
184 
185 				prev = slot;
186 				slot = os_channel_get_next_slot(ring, slot, &prop);
187 			}
188 			assert(!slot);
189 			assert(prev);
190 
191 			error = os_channel_advance_slot(ring, prev);
192 			SKTC_ASSERT_ERR(!error);
193 
194 			error = os_channel_sync(channel, CHANNEL_SYNC_TX);
195 			SKTC_ASSERT_ERR(!error);
196 		}
197 
198 		ringid = os_channel_ring_id(channel, CHANNEL_FIRST_RX_RING);
199 		ring = os_channel_rx_ring(channel, ringid);
200 		assert(ring);
201 
202 		switch (method) {
203 		case 0:
204 			FD_SET(channelfd, &fdset);
205 			FD_SET(channelfd, &efdset);
206 			error = select(channelfd + 1, &fdset, NULL, &efdset, NULL);
207 			SKTC_ASSERT_ERR(error != -1);
208 			SKTC_ASSERT_ERR(error == 1);
209 			assert(FD_ISSET(channelfd, &fdset));
210 			assert(!FD_ISSET(channelfd, &efdset));
211 			break;
212 		case 1:
213 			fds.events = POLLRDNORM;
214 			error = poll(&fds, 1, -1);
215 			SKTC_ASSERT_ERR(error != -1);
216 			SKTC_ASSERT_ERR(error == 1);
217 			assert(fds.fd == channelfd);
218 			assert(fds.events == POLLRDNORM);
219 			assert(fds.revents == POLLRDNORM);
220 			break;
221 		case 2:
222 			EV_SET(&kev, channelfd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 0, NULL);
223 			error = kevent(kq, &kev, 1, &kev, 1, NULL);
224 			SKTC_ASSERT_ERR(error != -1);
225 			SKTC_ASSERT_ERR(error == 1);
226 			assert(kev.filter == EVFILT_READ);
227 			assert(kev.ident == channelfd);
228 			assert(kev.udata == NULL);
229 			break;
230 		default:
231 			abort();
232 		}
233 
234 		avail = os_channel_available_slot_count(ring);
235 		assert(avail);
236 
237 		prev = NULL;
238 		slot = os_channel_get_next_slot(ring, NULL, &prop);
239 
240 		for (uint32_t i = 0; i < avail; i++) {
241 			assert(slot);
242 
243 			assert(prop.sp_len == sizeof(recvcount));
244 			uint32_t count;
245 			memcpy(&count, (void *)prop.sp_buf_ptr, sizeof(count));
246 			assert(!memcmp(&recvcount, (void *)prop.sp_buf_ptr, sizeof(recvcount)));
247 			recvcount++;
248 
249 			prev = slot;
250 			slot = os_channel_get_next_slot(ring, slot, &prop);
251 		}
252 		assert(!slot);
253 		assert(prev);
254 
255 		error = os_channel_advance_slot(ring, prev);
256 		SKTC_ASSERT_ERR(!error);
257 
258 		//T_LOG("rx sync %d\n", avail);
259 
260 		// Unnecessary
261 		//error = os_channel_sync(channel, CHANNEL_SYNC_RX);
262 		//SKTC_ASSERT_ERR(!error);
263 	}
264 
265 	now = time(NULL);
266 	T_LOG("total time %ld for %d slots (rate %.2f)\n",
267 	    now - start, nslots, (double)nslots / (now - start));
268 
269 	switch (method) {
270 	case 0:
271 		break;
272 	case 1:
273 		break;
274 	case 2:
275 		error = close(kq);
276 		SKTC_ASSERT_ERR(!error);
277 		break;
278 	default:
279 		abort();
280 	}
281 
282 	os_channel_destroy(channel);
283 
284 	return 0;
285 }
286 
287 int
skt_nslots_select_main(int argc,char * argv[])288 skt_nslots_select_main(int argc, char *argv[])
289 {
290 	return skt_nslots_common(argc, argv, -1, -1, 0);
291 }
292 
293 int
skt_nslots_poll_main(int argc,char * argv[])294 skt_nslots_poll_main(int argc, char *argv[])
295 {
296 	return skt_nslots_common(argc, argv, -1, -1, 1);
297 }
298 
299 int
skt_nslots_kqueue_main(int argc,char * argv[])300 skt_nslots_kqueue_main(int argc, char *argv[])
301 {
302 	return skt_nslots_common(argc, argv, -1, -1, 2);
303 }
304 
305 struct skywalk_test skt_nslotsus = {
306 	"nslotsus", "test sends TX_SLOTS of data on user pipe loopback using select",
307 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
308 	skt_nslots_select_main, SKTC_GENERIC_UPIPE_ARGV,
309 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
310 };
311 
312 struct skywalk_test skt_nslotsks = {
313 	"nslotsks", "test sends TX_SLOTS of data on kpipe loopback using select",
314 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
315 	skt_nslots_select_main, SKTC_GENERIC_KPIPE_ARGV,
316 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
317 };
318 
319 struct skywalk_test skt_nslotsup = {
320 	"nslotsup", "test sends TX_SLOTS of data on user pipe loopback using poll",
321 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
322 	skt_nslots_poll_main, SKTC_GENERIC_UPIPE_ARGV,
323 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
324 };
325 
326 struct skywalk_test skt_nslotskp = {
327 	"nslotskp", "test sends TX_SLOTS of data on kpipe loopback using poll",
328 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
329 	skt_nslots_poll_main, SKTC_GENERIC_KPIPE_ARGV,
330 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
331 };
332 
333 struct skywalk_test skt_nslotsuk = {
334 	"nslotsuk", "test sends TX_SLOTS of data on user pipe loopback using kqueue",
335 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
336 	skt_nslots_kqueue_main, SKTC_GENERIC_UPIPE_ARGV,
337 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
338 };
339 
340 struct skywalk_test skt_nslotskk = {
341 	"nslotskk", "test sends TX_SLOTS of data on kpipe loopback using kqueue",
342 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
343 	skt_nslots_kqueue_main, SKTC_GENERIC_KPIPE_ARGV,
344 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
345 };
346 
347 /****************************************************************/
348 // <rdar://problem/25995625> Need skywalk unit test that streams packets over upipe for a long time
349 
350 #define MSLOTS 1000000
351 int
skt_mslots_select_main(int argc,char * argv[])352 skt_mslots_select_main(int argc, char *argv[])
353 {
354 	return skt_nslots_common(argc, argv, MSLOTS, -1, 0);
355 }
356 
357 int
skt_mslots_poll_main(int argc,char * argv[])358 skt_mslots_poll_main(int argc, char *argv[])
359 {
360 	return skt_nslots_common(argc, argv, MSLOTS, -1, 1);
361 }
362 
363 int
skt_mslots_kqueue_main(int argc,char * argv[])364 skt_mslots_kqueue_main(int argc, char *argv[])
365 {
366 	return skt_nslots_common(argc, argv, MSLOTS, -1, 2);
367 }
368 
369 struct skywalk_test skt_mslotsus = {
370 	"mslotsus", "test sends 1000000 slots of data on user pipe loopback using select",
371 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
372 	skt_mslots_select_main, SKTC_GENERIC_UPIPE_ARGV,
373 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
374 };
375 
376 struct skywalk_test skt_mslotsks = {
377 	"mslotsks", "test sends 1000000 slots of data on kpipe loopback using select",
378 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
379 	skt_mslots_select_main, SKTC_GENERIC_KPIPE_ARGV,
380 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
381 };
382 
383 struct skywalk_test skt_mslotsup = {
384 	"mslotsup", "test sends 1000000 slots of data on user pipe loopback using poll",
385 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
386 	skt_mslots_poll_main, SKTC_GENERIC_UPIPE_ARGV,
387 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
388 };
389 
390 struct skywalk_test skt_mslotskp = {
391 	"mslotskp", "test sends 1000000 slots of data on kpipe loopback using poll",
392 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
393 	skt_mslots_poll_main, SKTC_GENERIC_KPIPE_ARGV,
394 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
395 };
396 
397 struct skywalk_test skt_mslotsuk = {
398 	"mslotsuk", "test sends 1000000 slots of data on user pipe loopback using kqueue",
399 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
400 	skt_mslots_kqueue_main, SKTC_GENERIC_UPIPE_ARGV,
401 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
402 };
403 
404 struct skywalk_test skt_mslotskk = {
405 	"mslotskk", "test sends 1000000 slots of data on kpipe loopback using kqueue",
406 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
407 	skt_mslots_kqueue_main, SKTC_GENERIC_KPIPE_ARGV,
408 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
409 };
410 
411 /****************************************************************/
412 
413 #define MMSLOTS 10000000
414 int
skt_mmslots_select_main(int argc,char * argv[])415 skt_mmslots_select_main(int argc, char *argv[])
416 {
417 	return skt_nslots_common(argc, argv, MMSLOTS, -1, 0);
418 }
419 
420 int
skt_mmslots_poll_main(int argc,char * argv[])421 skt_mmslots_poll_main(int argc, char *argv[])
422 {
423 	return skt_nslots_common(argc, argv, MMSLOTS, -1, 1);
424 }
425 
426 int
skt_mmslots_kqueue_main(int argc,char * argv[])427 skt_mmslots_kqueue_main(int argc, char *argv[])
428 {
429 	return skt_nslots_common(argc, argv, MMSLOTS, -1, 2);
430 }
431 
432 struct skywalk_test skt_mmslotsus = {
433 	"mmslotsus", "test sends 10000000 slots of data on user pipe loopback using select",
434 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
435 	skt_mmslots_select_main, SKTC_GENERIC_UPIPE_ARGV,
436 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
437 };
438 
439 struct skywalk_test skt_mmslotsks = {
440 	"mmslotsks", "test sends 10000000 slots of data on kpipe loopback using select",
441 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
442 	skt_mmslots_select_main, SKTC_GENERIC_KPIPE_ARGV,
443 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
444 };
445 
446 struct skywalk_test skt_mmslotsup = {
447 	"mmslotsup", "test sends 10000000 slots of data on user pipe loopback using poll",
448 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
449 	skt_mmslots_poll_main, SKTC_GENERIC_UPIPE_ARGV,
450 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
451 };
452 
453 struct skywalk_test skt_mmslotskp = {
454 	"mmslotskp", "test sends 10000000 slots of data on kpipe loopback using poll",
455 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
456 	skt_mmslots_poll_main, SKTC_GENERIC_KPIPE_ARGV,
457 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
458 };
459 
460 struct skywalk_test skt_mmslotsuk = {
461 	"mmslotsuk", "test sends 10000000 slots of data on user pipe loopback using kqueue",
462 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_USER_PIPE,
463 	skt_mmslots_kqueue_main, SKTC_GENERIC_UPIPE_ARGV,
464 	sktc_generic_upipe_echo_init, sktc_generic_upipe_fini,
465 };
466 
467 struct skywalk_test skt_mmslotskk = {
468 	"mmslotskk", "test sends 10000000 slots of data on kpipe loopback using kqueue",
469 	SK_FEATURE_SKYWALK | SK_FEATURE_NEXUS_KERNEL_PIPE | SK_FEATURE_NEXUS_KERNEL_PIPE_LOOPBACK,
470 	skt_mmslots_kqueue_main, SKTC_GENERIC_KPIPE_ARGV,
471 	sktc_generic_kpipe_init, sktc_generic_kpipe_fini,
472 };
473 
474 /****************************************************************/
475