1 /*
2  * Copyright (c) 2021 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Test log message
10  */
11 
12 #include <sys/mpsc_pbuf.h>
13 
14 #include <tc_util.h>
15 #include <stdbool.h>
16 #include <zephyr.h>
17 #include <ztest.h>
18 #include <random/rand32.h>
19 
20 #define PUT_EXT_LEN \
21 	((sizeof(union mpsc_pbuf_generic) + sizeof(void *)) / sizeof(uint32_t))
22 
23 #define LEN_BITS 9
24 
25 struct test_data {
26 	MPSC_PBUF_HDR;
27 	uint32_t len : LEN_BITS;
28 	uint32_t data : 32 - MPSC_PBUF_HDR_BITS - LEN_BITS;
29 };
30 
31 struct test_data_ext {
32 	struct test_data hdr;
33 	void *data;
34 } __packed;
35 
36 struct test_data_var {
37 	struct test_data hdr;
38 	uint32_t data[];
39 };
40 
41 union test_item {
42 	struct test_data data;
43 	struct test_data_ext data_ext;
44 	union mpsc_pbuf_generic item;
45 };
46 
get_wlen(const union mpsc_pbuf_generic * item)47 static uint32_t get_wlen(const union mpsc_pbuf_generic *item)
48 {
49 	union test_item *t_item = (union test_item *)item;
50 
51 	return t_item->data.len;
52 }
53 
54 static uint32_t drop_cnt;
55 static uintptr_t exp_dropped_data[10];
56 static uint32_t exp_dropped_len[10];
57 
drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)58 static void drop(const struct mpsc_pbuf_buffer *buffer, const union mpsc_pbuf_generic *item)
59 {
60 	struct test_data_var *packet = (struct test_data_var *)item;
61 
62 	zassert_equal(packet->hdr.data, exp_dropped_data[drop_cnt], NULL);
63 	zassert_equal(packet->hdr.len, exp_dropped_len[drop_cnt], NULL);
64 	for (int i = 0; i < exp_dropped_len[drop_cnt] - 1; i++) {
65 		int err = memcmp(packet->data, &exp_dropped_data[drop_cnt],
66 				 sizeof(uint32_t));
67 
68 		zassert_equal(err, 0, NULL);
69 	}
70 
71 	drop_cnt++;
72 }
73 
74 static uint32_t buf32[512];
75 
76 static struct mpsc_pbuf_buffer_config cfg = {
77 	.buf = buf32,
78 	.size = ARRAY_SIZE(buf32),
79 	.notify_drop = drop,
80 	.get_wlen = get_wlen
81 };
82 
init(struct mpsc_pbuf_buffer * buffer,bool overwrite,bool pow2)83 static void init(struct mpsc_pbuf_buffer *buffer, bool overwrite, bool pow2)
84 {
85 	drop_cnt = 0;
86 	cfg.flags = overwrite ? MPSC_PBUF_MODE_OVERWRITE : 0;
87 	cfg.size = ARRAY_SIZE(buf32) - (pow2 ? 0 : 1);
88 	mpsc_pbuf_init(buffer, &cfg);
89 
90 #if CONFIG_SOC_SERIES_NRF52X
91 	CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
92 	DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
93 	DWT->CYCCNT = 0;
94 #endif
95 }
96 
get_cyc(void)97 static inline uint32_t get_cyc(void)
98 {
99 #if CONFIG_SOC_SERIES_NRF52X
100 	return DWT->CYCCNT;
101 #else
102 	return k_cycle_get_32();
103 #endif
104 }
105 
item_put_no_overwrite(bool pow2)106 void item_put_no_overwrite(bool pow2)
107 {
108 	struct mpsc_pbuf_buffer buffer;
109 
110 	init(&buffer, false, pow2);
111 
112 	int repeat = buffer.size*2;
113 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
114 
115 	for (int i = 0; i < repeat; i++) {
116 		union test_item *t;
117 
118 		test_1word.data.data = i;
119 		mpsc_pbuf_put_word(&buffer, test_1word.item);
120 
121 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
122 		zassert_true(t, NULL);
123 		zassert_equal(t->data.data, i, NULL);
124 		mpsc_pbuf_free(&buffer, &t->item);
125 
126 	}
127 
128 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
129 }
130 
test_item_put_no_overwrite(void)131 void test_item_put_no_overwrite(void)
132 {
133 	item_put_no_overwrite(true);
134 	item_put_no_overwrite(false);
135 }
136 
item_put_overwrite(bool pow2)137 void item_put_overwrite(bool pow2)
138 {
139 	struct mpsc_pbuf_buffer buffer;
140 
141 	init(&buffer, true, pow2);
142 
143 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
144 
145 	exp_dropped_data[0] = 0;
146 	exp_dropped_len[0] = 1;
147 
148 	for (int i = 0; i < buffer.size; i++) {
149 		test_1word.data.data = i;
150 		mpsc_pbuf_put_word(&buffer, test_1word.item);
151 	}
152 
153 	zassert_equal(drop_cnt, 1,
154 			"Unexpected number of dropped messages: %d", drop_cnt);
155 }
156 
test_item_put_overwrite(void)157 void test_item_put_overwrite(void)
158 {
159 	item_put_overwrite(true);
160 	item_put_overwrite(false);
161 }
162 
item_put_saturate(bool pow2)163 void item_put_saturate(bool pow2)
164 {
165 	struct mpsc_pbuf_buffer buffer;
166 
167 	init(&buffer, false, pow2);
168 
169 	int repeat = buffer.size;
170 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
171 	union test_item *t;
172 
173 	zassert_false(mpsc_pbuf_is_pending(&buffer), NULL);
174 
175 	for (int i = 0; i < repeat/2; i++) {
176 		test_1word.data.data = i;
177 		mpsc_pbuf_put_word(&buffer, test_1word.item);
178 
179 		zassert_true(mpsc_pbuf_is_pending(&buffer), NULL);
180 
181 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
182 		zassert_true(t, NULL);
183 		zassert_equal(t->data.data, i, NULL);
184 		mpsc_pbuf_free(&buffer, &t->item);
185 	}
186 
187 	for (int i = 0; i < repeat; i++) {
188 		test_1word.data.data = i;
189 		mpsc_pbuf_put_word(&buffer, test_1word.item);
190 	}
191 
192 	for (int i = 0; i < (repeat-1); i++) {
193 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
194 		zassert_true(t, NULL);
195 		zassert_equal(t->data.data, i, NULL);
196 		mpsc_pbuf_free(&buffer, &t->item);
197 	}
198 
199 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
200 }
201 
test_item_put_saturate(void)202 void test_item_put_saturate(void)
203 {
204 	item_put_saturate(true);
205 	item_put_saturate(false);
206 }
207 
benchmark_item_put(bool pow2)208 void benchmark_item_put(bool pow2)
209 {
210 	struct mpsc_pbuf_buffer buffer;
211 
212 	init(&buffer, true, pow2);
213 
214 	int repeat = buffer.size - 1;
215 	union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
216 	uint32_t t = get_cyc();
217 
218 	for (int i = 0; i < repeat; i++) {
219 		test_1word.data.data = i;
220 		mpsc_pbuf_put_word(&buffer, test_1word.item);
221 	}
222 
223 	t = get_cyc() - t;
224 	PRINT("%s buffer\n", pow2 ? "pow2" : "non-pow2");
225 	PRINT("single word put time: %d cycles\n", t/repeat);
226 
227 	t = get_cyc();
228 	for (int i = 0; i < repeat; i++) {
229 		union test_item *t;
230 
231 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
232 		zassert_true(t, NULL);
233 		zassert_equal(t->data.data, i, NULL);
234 		mpsc_pbuf_free(&buffer, &t->item);
235 	}
236 
237 	t = get_cyc() - t;
238 	PRINT("single word item claim,free: %d cycles\n", t/repeat);
239 
240 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
241 }
242 
test_benchmark_item_put(void)243 void test_benchmark_item_put(void)
244 {
245 	benchmark_item_put(true);
246 	benchmark_item_put(false);
247 }
248 
item_put_ext_no_overwrite(bool pow2)249 void item_put_ext_no_overwrite(bool pow2)
250 {
251 	struct mpsc_pbuf_buffer buffer;
252 
253 	init(&buffer, false, pow2);
254 
255 	int repeat = buffer.size * 2;
256 	union test_item test_ext_item = {
257 		.data = {
258 			.valid = 1,
259 			.len = PUT_EXT_LEN
260 		}
261 	};
262 	void *data;
263 
264 	for (uintptr_t i = 0; i < repeat; i++) {
265 		union test_item *t;
266 
267 		data = (void *)i;
268 		test_ext_item.data.data = i;
269 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
270 
271 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
272 		zassert_true(t, NULL);
273 		zassert_equal(t->data_ext.hdr.data, i, NULL);
274 		zassert_equal(t->data_ext.data, (void *)i, NULL);
275 		mpsc_pbuf_free(&buffer, &t->item);
276 	}
277 
278 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
279 }
280 
test_item_put_ext_no_overwrite(void)281 void test_item_put_ext_no_overwrite(void)
282 {
283 	item_put_ext_no_overwrite(true);
284 	item_put_ext_no_overwrite(false);
285 }
286 
item_put_word_ext_overwrite(bool pow2)287 void item_put_word_ext_overwrite(bool pow2)
288 {
289 	struct mpsc_pbuf_buffer buffer;
290 
291 	init(&buffer, true, pow2);
292 
293 	size_t w = (sizeof(uint32_t) + sizeof(void *)) / sizeof(uint32_t);
294 	int repeat = 1 + (buffer.size - 1) / w;
295 	union test_item test_ext_item = {
296 		.data = {
297 			.valid = 1,
298 			.len = PUT_EXT_LEN
299 		}
300 	};
301 
302 	exp_dropped_data[0] = 0;
303 	exp_dropped_len[0] = w;
304 	exp_dropped_data[1] = 1;
305 	exp_dropped_len[1] = w;
306 
307 	for (uintptr_t i = 0; i < repeat; i++) {
308 		test_ext_item.data.data = i;
309 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, (void *)i);
310 	}
311 
312 	uint32_t exp_drop_cnt = (sizeof(void *) == sizeof(uint32_t)) ?
313 				(pow2 ? 1 : 2) : 2;
314 
315 	zassert_equal(drop_cnt, exp_drop_cnt,
316 			"Unexpected number of dropped messages: %d", drop_cnt);
317 }
318 
test_item_put_word_ext_overwrite(void)319 void test_item_put_word_ext_overwrite(void)
320 {
321 	item_put_word_ext_overwrite(true);
322 	item_put_word_ext_overwrite(false);
323 }
324 
item_put_ext_saturate(bool pow2)325 void item_put_ext_saturate(bool pow2)
326 {
327 	struct mpsc_pbuf_buffer buffer;
328 
329 	init(&buffer, false, pow2);
330 
331 	int repeat = buffer.size / PUT_EXT_LEN;
332 	union test_item test_ext_item = {
333 		.data = {
334 			.valid = 1,
335 			.len = PUT_EXT_LEN
336 		}
337 	};
338 	void *data;
339 	union test_item *t;
340 
341 	for (uintptr_t i = 0; i < repeat/2; i++) {
342 		test_ext_item.data.data = i;
343 		data = (void *)i;
344 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
345 
346 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
347 		zassert_true(t, NULL);
348 		zassert_equal(t->data.data, i, NULL);
349 		mpsc_pbuf_free(&buffer, &t->item);
350 	}
351 
352 	for (uintptr_t i = 0; i < repeat; i++) {
353 		test_ext_item.data.data = i;
354 		data = (void *)i;
355 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
356 	}
357 
358 	for (uintptr_t i = 0; i < (repeat-1); i++) {
359 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
360 		zassert_true(t, NULL);
361 		zassert_equal(t->data_ext.data, (void *)i, NULL);
362 		zassert_equal(t->data_ext.hdr.data, i, NULL);
363 		mpsc_pbuf_free(&buffer, &t->item);
364 	}
365 
366 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
367 }
368 
test_item_put_ext_saturate(void)369 void test_item_put_ext_saturate(void)
370 {
371 	item_put_ext_saturate(true);
372 	item_put_ext_saturate(false);
373 }
374 
benchmark_item_put_ext(bool pow2)375 void benchmark_item_put_ext(bool pow2)
376 {
377 	struct mpsc_pbuf_buffer buffer;
378 
379 	init(&buffer, false, pow2);
380 
381 	int repeat = (buffer.size - 1) / PUT_EXT_LEN;
382 	union test_item test_ext_item = {
383 		.data = {
384 			.valid = 1,
385 			.len = PUT_EXT_LEN
386 		}
387 	};
388 	void *data = NULL;
389 	uint32_t t = get_cyc();
390 
391 	for (int i = 0; i < repeat; i++) {
392 		test_ext_item.data.data = i;
393 		mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
394 	}
395 
396 	t = get_cyc() - t;
397 	PRINT("%spow2 buffer\n", pow2 ? "" : "non-");
398 	PRINT("put_ext time: %d cycles\n", t/repeat);
399 
400 	t = get_cyc();
401 	for (int i = 0; i < repeat; i++) {
402 		union test_item *t;
403 
404 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
405 		zassert_true(t, NULL);
406 		zassert_equal(t->data.data, i, NULL);
407 		mpsc_pbuf_free(&buffer, &t->item);
408 	}
409 
410 	t = get_cyc() - t;
411 	PRINT("ext item claim,free: %d cycles\n", t/repeat);
412 
413 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
414 }
415 
test_benchmark_item_put_ext(void)416 void test_benchmark_item_put_ext(void)
417 {
418 	benchmark_item_put_ext(true);
419 	benchmark_item_put_ext(false);
420 }
421 
benchmark_item_put_data(bool pow2)422 void benchmark_item_put_data(bool pow2)
423 {
424 	struct mpsc_pbuf_buffer buffer;
425 
426 	init(&buffer, false, pow2);
427 
428 	int repeat = (buffer.size - 1) / PUT_EXT_LEN;
429 	union test_item test_ext_item = {
430 		.data_ext = {
431 			.hdr = {
432 				.valid = 1,
433 				.len = PUT_EXT_LEN
434 			},
435 			.data = NULL
436 		}
437 	};
438 	uint32_t t = get_cyc();
439 
440 	for (uintptr_t i = 0; i < repeat; i++) {
441 		test_ext_item.data_ext.hdr.data = i;
442 		test_ext_item.data_ext.data = (void *)i;
443 		mpsc_pbuf_put_data(&buffer, (uint32_t *)&test_ext_item,
444 				    PUT_EXT_LEN);
445 	}
446 
447 	t = get_cyc() - t;
448 	PRINT("%spow2 buffer\n", pow2 ? "" : "non-");
449 	PRINT("put_ext time: %d cycles\n", t/repeat);
450 
451 	t = get_cyc();
452 	for (int i = 0; i < repeat; i++) {
453 		union test_item *t;
454 
455 		t = (union test_item *)mpsc_pbuf_claim(&buffer);
456 		zassert_true(t, NULL);
457 		zassert_equal(t->data.data, i, NULL);
458 		mpsc_pbuf_free(&buffer, &t->item);
459 	}
460 
461 	t = get_cyc() - t;
462 	PRINT("ext item claim,free: %d cycles\n", t/repeat);
463 
464 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, NULL);
465 }
466 
test_benchmark_item_put_data(void)467 void test_benchmark_item_put_data(void)
468 {
469 	benchmark_item_put_data(true);
470 	benchmark_item_put_data(false);
471 }
472 
item_put_data_overwrite(bool pow2)473 void item_put_data_overwrite(bool pow2)
474 {
475 	struct mpsc_pbuf_buffer buffer;
476 
477 	init(&buffer, true, pow2);
478 
479 	size_t w = (sizeof(uint32_t) + sizeof(void *)) / sizeof(uint32_t);
480 	int repeat = 1 + (buffer.size - 1) / w;
481 	static const int len = sizeof(struct test_data_ext) / sizeof(uint32_t);
482 	struct test_data_ext item = {
483 		.hdr = {
484 			.valid = 1,
485 			.len = len
486 		}
487 	};
488 
489 	exp_dropped_data[0] = 0;
490 	exp_dropped_len[0] = w;
491 	exp_dropped_data[1] = 1;
492 	exp_dropped_len[1] = w;
493 
494 	for (uintptr_t i = 0; i < repeat; i++) {
495 		item.data = (void *)i;
496 		item.hdr.data = i;
497 		mpsc_pbuf_put_data(&buffer, (uint32_t *)&item, len);
498 	}
499 
500 	uint32_t exp_drop_cnt = (sizeof(void *) == sizeof(uint32_t)) ?
501 				(pow2 ? 1 : 2) : 2;
502 
503 	zassert_equal(drop_cnt, exp_drop_cnt,
504 			"Unexpected number of dropped messages: %d", drop_cnt);
505 }
506 
test_put_data_overwrite(void)507 void test_put_data_overwrite(void)
508 {
509 	item_put_data_overwrite(true);
510 	item_put_data_overwrite(false);
511 }
512 
item_alloc_commit(bool pow2)513 void item_alloc_commit(bool pow2)
514 {
515 	struct mpsc_pbuf_buffer buffer;
516 
517 	init(&buffer, false, pow2);
518 
519 	struct test_data_var *packet;
520 	uint32_t len = 5;
521 	int repeat = 1024;
522 
523 	for (int i = 0; i < repeat; i++) {
524 		packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
525 								 K_NO_WAIT);
526 		packet->hdr.len = len;
527 		for (int j = 0; j < len - 1; j++) {
528 			packet->data[j] = i + j;
529 		}
530 
531 		mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
532 
533 		packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
534 		zassert_true(packet, NULL);
535 		zassert_equal(packet->hdr.len, len, NULL);
536 
537 		for (int j = 0; j < len - 1; j++) {
538 			zassert_equal(packet->data[j], i + j, NULL);
539 		}
540 
541 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
542 	}
543 }
544 
test_item_alloc_commit(void)545 void test_item_alloc_commit(void)
546 {
547 	item_alloc_commit(true);
548 	item_alloc_commit(false);
549 }
550 
item_max_alloc(bool overwrite)551 void item_max_alloc(bool overwrite)
552 {
553 	struct mpsc_pbuf_buffer buffer;
554 	struct test_data_var *packet;
555 
556 	init(&buffer, overwrite, true);
557 
558 	/* First try to allocate the biggest possible packet. */
559 	for (int i = 0; i < 2; i++) {
560 		packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
561 								 buffer.size - 1,
562 								 K_NO_WAIT);
563 		zassert_true(packet != NULL, NULL);
564 		packet->hdr.len = buffer.size - 1;
565 		mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
566 
567 		packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
568 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
569 	}
570 
571 	/* Too big packet cannot be allocated. */
572 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
573 							 buffer.size,
574 							 K_NO_WAIT);
575 	zassert_true(packet == NULL, NULL);
576 }
577 
test_item_max_alloc(void)578 void test_item_max_alloc(void)
579 {
580 	item_max_alloc(true);
581 	item_max_alloc(false);
582 }
583 
saturate_buffer_uneven(struct mpsc_pbuf_buffer * buffer,uint32_t len)584 static uint32_t saturate_buffer_uneven(struct mpsc_pbuf_buffer *buffer,
585 					uint32_t len)
586 {
587 	struct test_data_var *packet;
588 	uint32_t uneven = 5;
589 	uint32_t cnt = 0;
590 	int repeat =
591 		uneven - 1 + ((buffer->size - (uneven * len)) / len);
592 
593 	/* Put some data to include wrapping */
594 	for (int i = 0; i < uneven; i++) {
595 		packet = (struct test_data_var *)mpsc_pbuf_alloc(buffer, len,
596 								 K_NO_WAIT);
597 		packet->hdr.len = len;
598 		mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)packet);
599 
600 		packet = (struct test_data_var *)mpsc_pbuf_claim(buffer);
601 		zassert_true(packet, NULL);
602 		mpsc_pbuf_free(buffer, (union mpsc_pbuf_generic *)packet);
603 	}
604 
605 	for (int i = 0; i < repeat; i++) {
606 		packet = (struct test_data_var *)mpsc_pbuf_alloc(buffer, len,
607 								 K_NO_WAIT);
608 		zassert_true(packet, NULL);
609 		packet->hdr.len = len;
610 		packet->hdr.data = i;
611 		for (int j = 0; j < len - 1; j++) {
612 			packet->data[j] = i + j;
613 		}
614 
615 		mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)packet);
616 		cnt++;
617 	}
618 
619 	return cnt;
620 }
621 
item_alloc_commit_saturate(bool pow2)622 void item_alloc_commit_saturate(bool pow2)
623 {
624 	struct mpsc_pbuf_buffer buffer;
625 
626 	init(&buffer, false, pow2);
627 
628 	saturate_buffer_uneven(&buffer, 5);
629 
630 	struct test_data_var *packet;
631 	uint32_t len = 5;
632 
633 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
634 							 K_NO_WAIT);
635 	zassert_equal(packet, NULL, NULL);
636 
637 	/* Get one packet from the buffer. */
638 	packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
639 	zassert_true(packet, NULL);
640 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
641 
642 	/* and try to allocate one more time, this time with success. */
643 	packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
644 							 K_NO_WAIT);
645 	zassert_true(packet, NULL);
646 }
647 
test_item_alloc_commit_saturate(void)648 void test_item_alloc_commit_saturate(void)
649 {
650 	item_alloc_commit_saturate(true);
651 	item_alloc_commit_saturate(false);
652 }
653 
item_alloc_preemption(bool pow2)654 void item_alloc_preemption(bool pow2)
655 {
656 	struct mpsc_pbuf_buffer buffer;
657 
658 	init(&buffer, false, pow2);
659 
660 	struct test_data_var *p0;
661 	struct test_data_var *p1;
662 	struct test_data_var *p;
663 
664 	p0 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 10, K_NO_WAIT);
665 	zassert_true(p0, NULL);
666 	p0->hdr.len = 10;
667 
668 	/* Check that no packet is yet available */
669 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
670 	zassert_equal(p, NULL, NULL);
671 
672 	p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 20, K_NO_WAIT);
673 	zassert_true(p1, NULL);
674 	p1->hdr.len = 20;
675 
676 	/* Commit p1, p0 is still not committed, there should be no packets
677 	 * available for reading.
678 	 */
679 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
680 
681 	/* Check that no packet is yet available */
682 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
683 	zassert_equal(p, NULL, NULL);
684 
685 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p0);
686 
687 	/* Validate that p0 is the first one. */
688 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
689 	zassert_true(p, NULL);
690 	zassert_equal(p->hdr.len, 10, NULL);
691 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
692 
693 	/* Validate that p1 is the next one. */
694 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
695 	zassert_true(p, NULL);
696 	zassert_equal(p->hdr.len, 20, NULL);
697 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
698 
699 	/* No more packets. */
700 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
701 	zassert_equal(p, NULL, NULL);
702 }
703 
test_item_alloc_preemption(void)704 void test_item_alloc_preemption(void)
705 {
706 	item_alloc_preemption(true);
707 	item_alloc_preemption(false);
708 }
709 
overwrite(bool pow2)710 void overwrite(bool pow2)
711 {
712 	struct test_data_var *p;
713 	uint32_t fill_len = 5;
714 	uint32_t len0, len1;
715 	struct mpsc_pbuf_buffer buffer;
716 
717 	init(&buffer, true, pow2);
718 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
719 
720 	exp_dropped_data[0] = 0;
721 	exp_dropped_len[0] = fill_len;
722 	len0 = 6;
723 	p = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len0, K_NO_WAIT);
724 
725 	p->hdr.len = len0;
726 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p);
727 	zassert_equal(drop_cnt, 1, NULL);
728 
729 	/* Request allocation which will require dropping 2 packets. */
730 	len1 = 9;
731 	exp_dropped_data[1] = 1;
732 	exp_dropped_len[1] = fill_len;
733 	exp_dropped_data[2] = 2;
734 	exp_dropped_len[2] = fill_len;
735 
736 	p = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len1, K_NO_WAIT);
737 
738 	p->hdr.len = len1;
739 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p);
740 	zassert_equal(drop_cnt, 3, NULL);
741 
742 	for (int i = 0; i < (packet_cnt - drop_cnt); i++) {
743 		p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
744 		zassert_true(p, NULL);
745 		zassert_equal(p->hdr.len, fill_len, NULL);
746 		zassert_equal(p->hdr.data, i + drop_cnt, NULL);
747 		for (int j = 0; j < fill_len - 1; j++) {
748 			zassert_equal(p->data[j], p->hdr.data + j, NULL);
749 		}
750 
751 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
752 	}
753 
754 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
755 	zassert_true(p, NULL);
756 	zassert_equal(p->hdr.len, len0, NULL);
757 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
758 
759 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
760 	zassert_true(p, NULL);
761 	zassert_equal(p->hdr.len, len1, NULL);
762 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
763 
764 	p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
765 	zassert_equal(p, NULL, NULL);
766 }
767 
test_overwrite(void)768 void test_overwrite(void)
769 {
770 	overwrite(true);
771 	overwrite(false);
772 }
773 
overwrite_while_claimed(bool pow2)774 void overwrite_while_claimed(bool pow2)
775 {
776 	struct test_data_var *p0;
777 	struct test_data_var *p1;
778 	struct mpsc_pbuf_buffer buffer;
779 
780 	init(&buffer, true, pow2);
781 
782 	uint32_t fill_len = 5;
783 	uint32_t len = 6;
784 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
785 
786 	/* Start by claiming a packet. Buffer is now full. Allocation shall
787 	 * skip claimed packed and drop the next one.
788 	 */
789 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
790 	zassert_true(p0, NULL);
791 	zassert_equal(p0->hdr.len, fill_len, NULL);
792 
793 	exp_dropped_data[0] = p0->hdr.data + 1; /* next packet is dropped */
794 	exp_dropped_len[0] = fill_len;
795 	exp_dropped_data[1] = p0->hdr.data + 2; /* next packet is dropped */
796 	exp_dropped_len[1] = fill_len;
797 	p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 6, K_NO_WAIT);
798 
799 	zassert_equal(drop_cnt, 2, NULL);
800 	p1->hdr.len = len;
801 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
802 
803 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
804 
805 	for (int i = 0; i < packet_cnt - drop_cnt - 1; i++) {
806 		p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
807 		zassert_true(p0, NULL);
808 		zassert_equal(p0->hdr.len, fill_len, NULL);
809 		zassert_equal(p0->hdr.data, i + drop_cnt + 1, NULL);
810 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
811 	}
812 
813 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
814 	zassert_true(p0, NULL);
815 	zassert_equal(p0->hdr.len, len, NULL);
816 
817 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
818 	zassert_equal(p0, NULL, NULL);
819 }
820 
test_overwrite_while_claimed(void)821 void test_overwrite_while_claimed(void)
822 {
823 	overwrite_while_claimed(true);
824 	overwrite_while_claimed(false);
825 }
826 
overwrite_while_claimed2(bool pow2)827 void overwrite_while_claimed2(bool pow2)
828 {
829 	struct test_data_var *p0;
830 	struct test_data_var *p1;
831 	struct mpsc_pbuf_buffer buffer;
832 
833 	init(&buffer, true, pow2);
834 
835 	uint32_t fill_len = 1;
836 	uint32_t len = 3;
837 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
838 
839 	/* Start by claiming a packet. Buffer is now full. Allocation shall
840 	 * skip claimed packed and drop the next one.
841 	 */
842 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
843 	zassert_true(p0, NULL);
844 	zassert_equal(p0->hdr.len, fill_len, NULL);
845 
846 	exp_dropped_data[0] = p0->hdr.data + 1; /* next packet is dropped */
847 	exp_dropped_len[0] = fill_len;
848 	exp_dropped_data[1] = p0->hdr.data + 2; /* next packet is dropped */
849 	exp_dropped_len[1] = fill_len;
850 	exp_dropped_data[2] = p0->hdr.data + 3; /* next packet is dropped */
851 	exp_dropped_len[2] = fill_len;
852 	exp_dropped_data[3] = p0->hdr.data + 4; /* next packet is dropped */
853 	exp_dropped_len[3] = fill_len;
854 	p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
855 
856 	zassert_equal(drop_cnt, 4, NULL);
857 	p1->hdr.len = len;
858 	mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
859 
860 	mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
861 
862 	for (int i = 0; i < packet_cnt - drop_cnt - 1; i++) {
863 		p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
864 		zassert_true(p0, NULL);
865 		zassert_equal(p0->hdr.len, fill_len, NULL);
866 		zassert_equal(p0->hdr.data, i + drop_cnt + 1, NULL);
867 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
868 	}
869 
870 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
871 	zassert_true(p0, NULL);
872 	zassert_equal(p0->hdr.len, len, NULL);
873 
874 	p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
875 	zassert_equal(p0, NULL, NULL);
876 }
877 
test_overwrite_while_claimed2(void)878 void test_overwrite_while_claimed2(void)
879 {
880 		overwrite_while_claimed2(true);
881 		overwrite_while_claimed2(false);
882 }
883 
884 static uintptr_t current_rd_idx;
885 
validate_packet(struct test_data_var * packet)886 static void validate_packet(struct test_data_var *packet)
887 {
888 	zassert_equal((uintptr_t)packet->hdr.data, current_rd_idx,
889 			"Got %d, expected: %d",
890 			(uintptr_t)packet->hdr.data, current_rd_idx);
891 	current_rd_idx++;
892 }
893 
consistent_drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)894 static void consistent_drop(const struct mpsc_pbuf_buffer *buffer,
895 			    const union mpsc_pbuf_generic *item)
896 {
897 	validate_packet((struct test_data_var *)item);
898 }
899 
rand_get(uint32_t min,uint32_t max)900 uint32_t rand_get(uint32_t min, uint32_t max)
901 {
902 	return min + (sys_rand32_get() % max);
903 }
904 
test_overwrite_consistency(void)905 void test_overwrite_consistency(void)
906 {
907 	struct mpsc_pbuf_buffer buffer;
908 	static struct mpsc_pbuf_buffer_config cfg = {
909 		.buf = buf32,
910 		.size = ARRAY_SIZE(buf32),
911 		.notify_drop = consistent_drop,
912 		.get_wlen = get_wlen,
913 		.flags = MPSC_PBUF_MODE_OVERWRITE
914 	};
915 
916 	mpsc_pbuf_init(&buffer, &cfg);
917 	int repeat = 50000;
918 	int id = 0;
919 
920 	while (id < repeat) {
921 		struct test_data_var *t = NULL;
922 		bool alloc_during_claim = (rand_get(1, 5) <= 2);
923 
924 		/* Occasionally claim buffer to simulate that claiming is
925 		 * interrupted by allocation.
926 		 */
927 		if (alloc_during_claim) {
928 			t = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
929 			if (t) {
930 				validate_packet(t);
931 			}
932 		}
933 
934 		uint32_t wr_cnt = rand_get(1, 200);
935 
936 		for (int i = 0; i < wr_cnt; i++) {
937 			uint32_t wlen = rand_get(1, 15);
938 			struct test_data_var *t;
939 
940 			t = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
941 								    wlen,
942 								    K_NO_WAIT);
943 			t->hdr.len = wlen;
944 			t->hdr.data = id++;
945 			mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)t);
946 		}
947 
948 		/* Put back item claimed before committing new items. */
949 		if (t) {
950 			mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)t);
951 		}
952 
953 		uint32_t rd_cnt = rand_get(1, 30);
954 
955 		for (int i = 0; i < rd_cnt; i++) {
956 			struct test_data_var *t;
957 
958 			t = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
959 			if (!t) {
960 				continue;
961 			}
962 
963 			validate_packet(t);
964 			mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)t);
965 		}
966 	}
967 }
968 
969 K_THREAD_STACK_DEFINE(t1_stack, 1024);
970 K_THREAD_STACK_DEFINE(t2_stack, 1024);
971 
972 static k_thread_stack_t *stacks[2] = {t1_stack, t2_stack};
973 static struct k_thread threads[2];
974 static k_tid_t tids[2];
975 
t_entry(void * p0,void * p1,void * p2)976 void t_entry(void *p0, void *p1, void *p2)
977 {
978 	struct mpsc_pbuf_buffer *buffer = p0;
979 	uintptr_t wait_ms = (uintptr_t)p1;
980 	struct test_data_ext *t;
981 
982 	t = (struct test_data_ext *)mpsc_pbuf_alloc(buffer,
983 						    sizeof(*t) / sizeof(uint32_t),
984 						    K_MSEC(1));
985 	zassert_equal(t, NULL, NULL);
986 
987 	t = (struct test_data_ext *)mpsc_pbuf_alloc(buffer,
988 						    sizeof(*t) / sizeof(uint32_t),
989 						    K_MSEC(wait_ms));
990 	t->hdr.len = PUT_EXT_LEN;
991 	t->data = k_current_get();
992 
993 	mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)t);
994 	while (1) {
995 		k_sleep(K_MSEC(10));
996 	}
997 }
998 
start_threads(struct mpsc_pbuf_buffer * buffer)999 void start_threads(struct mpsc_pbuf_buffer *buffer)
1000 {
1001 	int prio = 2;
1002 	uintptr_t wait_ms = 1000;
1003 
1004 	for (int i = 0; i < ARRAY_SIZE(threads); i++) {
1005 		tids[i] = k_thread_create(&threads[i], stacks[i], 1024, t_entry,
1006 					  buffer, (void *)wait_ms, NULL,
1007 					  prio--,
1008 					  0, K_NO_WAIT);
1009 	}
1010 
1011 	k_sleep(K_MSEC(10));
1012 
1013 	for (int i = 0; i < ARRAY_SIZE(threads); i++) {
1014 		k_ticks_t t = k_thread_timeout_remaining_ticks(tids[i]);
1015 		k_ticks_t exp_wait = k_ms_to_ticks_ceil32(wait_ms);
1016 
1017 		/* Threads shall be blocked, waiting for available space. */
1018 		zassert_within(t, exp_wait, k_ms_to_ticks_ceil32(2), NULL);
1019 	}
1020 }
1021 
1022 /* Test creates two threads which pends on the buffer until there is a space
1023  * available. When engough buffers is released threads are waken up and they
1024  * allocate packets.
1025  */
test_pending_alloc(void)1026 void test_pending_alloc(void)
1027 {
1028 	int prio = k_thread_priority_get(k_current_get());
1029 	struct mpsc_pbuf_buffer buffer;
1030 
1031 	k_thread_priority_set(k_current_get(), 3);
1032 
1033 	init(&buffer, true, false);
1034 
1035 	uint32_t fill_len = 1;
1036 	uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
1037 
1038 	start_threads(&buffer);
1039 
1040 	k_sleep(K_MSEC(1));
1041 
1042 	for (int i = 0; i < packet_cnt; i++) {
1043 		union test_item *t = (union test_item *)mpsc_pbuf_claim(&buffer);
1044 
1045 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)t);
1046 	}
1047 
1048 
1049 	for (int i = 0; i < 2; i++) {
1050 		struct test_data_ext *t =
1051 			(struct test_data_ext *)mpsc_pbuf_claim(&buffer);
1052 
1053 		zassert_true(t, NULL);
1054 		zassert_equal(t->data, tids[ARRAY_SIZE(tids) - 1 - i], NULL);
1055 		mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)t);
1056 	}
1057 
1058 	zassert_equal(mpsc_pbuf_claim(&buffer), NULL, "No more packets.");
1059 	k_thread_priority_set(k_current_get(), prio);
1060 }
1061 
1062 /*test case main entry*/
test_main(void)1063 void test_main(void)
1064 {
1065 	ztest_test_suite(test_log_buffer,
1066 		ztest_unit_test(test_benchmark_item_put),
1067 		ztest_unit_test(test_item_put_saturate),
1068 		ztest_unit_test(test_item_put_no_overwrite),
1069 		ztest_unit_test(test_item_put_overwrite),
1070 		ztest_unit_test(test_item_put_ext_no_overwrite),
1071 		ztest_unit_test(test_item_put_word_ext_overwrite),
1072 		ztest_unit_test(test_item_put_ext_saturate),
1073 		ztest_unit_test(test_put_data_overwrite),
1074 		ztest_unit_test(test_benchmark_item_put_ext),
1075 		ztest_unit_test(test_benchmark_item_put_data),
1076 		ztest_unit_test(test_item_alloc_commit),
1077 		ztest_unit_test(test_item_max_alloc),
1078 		ztest_unit_test(test_item_alloc_commit_saturate),
1079 		ztest_unit_test(test_item_alloc_preemption),
1080 		ztest_unit_test(test_overwrite),
1081 		ztest_unit_test(test_overwrite_while_claimed),
1082 		ztest_unit_test(test_overwrite_while_claimed2),
1083 		ztest_unit_test(test_overwrite_consistency),
1084 		ztest_unit_test(test_pending_alloc)
1085 		);
1086 	ztest_run_test_suite(test_log_buffer);
1087 }
1088