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