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 <zephyr/sys/mpsc_pbuf.h>
13
14 #include <zephyr/tc_util.h>
15 #include <stdbool.h>
16 #include <zephyr/kernel.h>
17 #include <zephyr/ztest.h>
18 #include <zephyr/random/random.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 uint32_t exp_drop_cnt;
56 static uintptr_t exp_dropped_data[10];
57 static uint32_t exp_dropped_len[10];
58
drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)59 static void drop(const struct mpsc_pbuf_buffer *buffer, const union mpsc_pbuf_generic *item)
60 {
61 struct test_data_var *packet = (struct test_data_var *)item;
62
63 zassert_true(drop_cnt < exp_drop_cnt);
64 zassert_equal(packet->hdr.len, exp_dropped_len[drop_cnt],
65 "(%d) Got:%08x, Expected: %08x",
66 drop_cnt, packet->hdr.len, exp_dropped_len[drop_cnt]);
67 zassert_equal(packet->hdr.data, exp_dropped_data[drop_cnt],
68 "(%d) Got:%08x, Expected: %08x",
69 drop_cnt, packet->hdr.data, (uint32_t)exp_dropped_data[drop_cnt]);
70 for (int i = 0; i < exp_dropped_len[drop_cnt] - 1; i++) {
71 int err = memcmp(packet->data, &exp_dropped_data[drop_cnt],
72 sizeof(uint32_t));
73
74
75 zassert_equal(err, 0);
76 }
77
78 drop_cnt++;
79 }
80
81 static uint32_t buf32[512];
82
83 static struct mpsc_pbuf_buffer_config mpsc_buf_cfg = {
84 .buf = buf32,
85 .size = ARRAY_SIZE(buf32),
86 .notify_drop = drop,
87 .get_wlen = get_wlen
88 };
89
init(struct mpsc_pbuf_buffer * buffer,uint32_t wlen,bool overwrite)90 static void init(struct mpsc_pbuf_buffer *buffer, uint32_t wlen, bool overwrite)
91 {
92 drop_cnt = 0;
93 exp_drop_cnt = 0;
94 mpsc_buf_cfg.flags = overwrite ? MPSC_PBUF_MODE_OVERWRITE : 0;
95 mpsc_buf_cfg.size = wlen;
96 mpsc_pbuf_init(buffer, &mpsc_buf_cfg);
97
98 #if CONFIG_SOC_SERIES_NRF52X
99 DCB->DEMCR |= DCB_DEMCR_TRCENA_Msk;
100 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
101 DWT->CYCCNT = 0;
102 #endif
103 }
104
get_cyc(void)105 static inline uint32_t get_cyc(void)
106 {
107 #if CONFIG_SOC_SERIES_NRF52X
108 return DWT->CYCCNT;
109 #else
110 return k_cycle_get_32();
111 #endif
112 }
113
item_put_no_overwrite(bool pow2)114 void item_put_no_overwrite(bool pow2)
115 {
116 struct mpsc_pbuf_buffer buffer;
117
118 init(&buffer, 4 - !pow2, false);
119
120 int repeat = buffer.size*2;
121 union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
122
123 for (int i = 0; i < repeat; i++) {
124 union test_item *t;
125
126 test_1word.data.data = i;
127 mpsc_pbuf_put_word(&buffer, test_1word.item);
128
129 t = (union test_item *)mpsc_pbuf_claim(&buffer);
130 zassert_true(t);
131 zassert_equal(t->data.data, i);
132 mpsc_pbuf_free(&buffer, &t->item);
133
134 }
135
136 zassert_is_null(mpsc_pbuf_claim(&buffer));
137 }
138
ZTEST(log_buffer,test_item_put_no_overwrite)139 ZTEST(log_buffer, test_item_put_no_overwrite)
140 {
141 item_put_no_overwrite(true);
142 item_put_no_overwrite(false);
143 }
144
item_put_overwrite(bool pow2)145 void item_put_overwrite(bool pow2)
146 {
147 struct mpsc_pbuf_buffer buffer;
148
149 init(&buffer, 4 - !pow2, true);
150
151 union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
152
153 exp_dropped_data[0] = 0;
154 exp_dropped_len[0] = 1;
155 exp_drop_cnt = 1;
156
157 for (int i = 0; i < buffer.size + 1; i++) {
158 test_1word.data.data = i;
159 mpsc_pbuf_put_word(&buffer, test_1word.item);
160 }
161
162 zassert_equal(drop_cnt, exp_drop_cnt,
163 "Unexpected number of dropped messages: %d", drop_cnt);
164 }
165
ZTEST(log_buffer,test_item_put_overwrite)166 ZTEST(log_buffer, test_item_put_overwrite)
167 {
168 item_put_overwrite(true);
169 item_put_overwrite(false);
170 }
171
item_put_saturate(bool pow2)172 void item_put_saturate(bool pow2)
173 {
174 struct mpsc_pbuf_buffer buffer;
175
176 init(&buffer, 4 - !pow2, false);
177
178 int repeat = buffer.size;
179 union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
180 union test_item *t;
181
182 zassert_false(mpsc_pbuf_is_pending(&buffer));
183
184 for (int i = 0; i < repeat / 2; i++) {
185 test_1word.data.data = i;
186 mpsc_pbuf_put_word(&buffer, test_1word.item);
187
188 zassert_true(mpsc_pbuf_is_pending(&buffer));
189
190 t = (union test_item *)mpsc_pbuf_claim(&buffer);
191 zassert_true(t);
192 zassert_equal(t->data.data, i);
193 mpsc_pbuf_free(&buffer, &t->item);
194 }
195
196 for (int i = 0; i < repeat + 1; i++) {
197 test_1word.data.data = i;
198 mpsc_pbuf_put_word(&buffer, test_1word.item);
199 }
200
201 for (int i = 0; i < repeat; i++) {
202 t = (union test_item *)mpsc_pbuf_claim(&buffer);
203 zassert_true(t);
204 zassert_equal(t->data.data, i);
205 mpsc_pbuf_free(&buffer, &t->item);
206 }
207
208 zassert_is_null(mpsc_pbuf_claim(&buffer));
209 }
210
ZTEST(log_buffer,test_item_put_saturate)211 ZTEST(log_buffer, test_item_put_saturate)
212 {
213 item_put_saturate(true);
214 item_put_saturate(false);
215 }
216
benchmark_item_put(bool pow2)217 void benchmark_item_put(bool pow2)
218 {
219 struct mpsc_pbuf_buffer buffer;
220
221 init(&buffer, ARRAY_SIZE(buf32) - !pow2, true);
222
223 int repeat = buffer.size - 1;
224 union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
225 uint32_t t = get_cyc();
226
227 for (int i = 0; i < repeat; i++) {
228 test_1word.data.data = i;
229 mpsc_pbuf_put_word(&buffer, test_1word.item);
230 }
231
232 t = get_cyc() - t;
233 PRINT("%s buffer\n", pow2 ? "pow2" : "non-pow2");
234 PRINT("single word put time: %d cycles\n", t/repeat);
235
236 t = get_cyc();
237 for (int i = 0; i < repeat; i++) {
238 union test_item *ti;
239
240 ti = (union test_item *)mpsc_pbuf_claim(&buffer);
241 zassert_true(ti);
242 zassert_equal(ti->data.data, i);
243 mpsc_pbuf_free(&buffer, &ti->item);
244 }
245
246 t = get_cyc() - t;
247 PRINT("single word item claim,free: %d cycles\n", t/repeat);
248
249 zassert_is_null(mpsc_pbuf_claim(&buffer));
250 }
251
ZTEST(log_buffer,test_benchmark_item_put)252 ZTEST(log_buffer, test_benchmark_item_put)
253 {
254 benchmark_item_put(true);
255 benchmark_item_put(false);
256 }
257
item_put_ext_no_overwrite(bool pow2)258 void item_put_ext_no_overwrite(bool pow2)
259 {
260 struct mpsc_pbuf_buffer buffer;
261
262 init(&buffer, 8 - !pow2, false);
263
264 int repeat = buffer.size * 2;
265 union test_item test_ext_item = {
266 .data = {
267 .valid = 1,
268 .len = PUT_EXT_LEN
269 }
270 };
271 void *data;
272
273 for (uintptr_t i = 0; i < repeat; i++) {
274 union test_item *t;
275
276 data = (void *)i;
277 test_ext_item.data.data = i;
278 mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
279
280 t = (union test_item *)mpsc_pbuf_claim(&buffer);
281 zassert_true(t);
282 zassert_equal(t->data_ext.hdr.data, i);
283 zassert_equal(t->data_ext.data, (void *)i);
284 mpsc_pbuf_free(&buffer, &t->item);
285 }
286
287 zassert_is_null(mpsc_pbuf_claim(&buffer));
288 }
289
ZTEST(log_buffer,test_item_put_ext_no_overwrite)290 ZTEST(log_buffer, test_item_put_ext_no_overwrite)
291 {
292 item_put_ext_no_overwrite(true);
293 item_put_ext_no_overwrite(false);
294 }
295
item_put_word_ext_overwrite(bool pow2)296 void item_put_word_ext_overwrite(bool pow2)
297 {
298 struct mpsc_pbuf_buffer buffer;
299
300 init(&buffer, 8 - !pow2, true);
301
302 size_t w = (sizeof(uint32_t) + sizeof(void *)) / sizeof(uint32_t);
303 int repeat = 1 + buffer.size / w;
304 union test_item test_ext_item = {
305 .data = {
306 .valid = 1,
307 .len = PUT_EXT_LEN
308 }
309 };
310
311 exp_dropped_data[0] = 0;
312 exp_dropped_len[0] = w;
313 exp_drop_cnt = 1;
314
315 for (uintptr_t i = 0; i < repeat; i++) {
316 test_ext_item.data.data = i;
317 mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, (void *)i);
318 }
319
320 zassert_equal(drop_cnt, exp_drop_cnt,
321 "Unexpected number of dropped messages: %d (exp: %d)",
322 drop_cnt, exp_drop_cnt);
323 }
324
ZTEST(log_buffer,test_item_put_word_ext_overwrite)325 ZTEST(log_buffer, test_item_put_word_ext_overwrite)
326 {
327 item_put_word_ext_overwrite(true);
328 item_put_word_ext_overwrite(false);
329 }
330
item_put_ext_saturate(bool pow2)331 void item_put_ext_saturate(bool pow2)
332 {
333 struct mpsc_pbuf_buffer buffer;
334
335 init(&buffer, 8 - !pow2, false);
336
337 int repeat = buffer.size / PUT_EXT_LEN;
338 union test_item test_ext_item = {
339 .data = {
340 .valid = 1,
341 .len = PUT_EXT_LEN
342 }
343 };
344 void *data;
345 union test_item *t;
346
347 for (uintptr_t i = 0; i < repeat/2; i++) {
348 test_ext_item.data.data = i;
349 data = (void *)i;
350 mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
351
352 t = (union test_item *)mpsc_pbuf_claim(&buffer);
353 zassert_true(t);
354 zassert_equal(t->data.data, i);
355 mpsc_pbuf_free(&buffer, &t->item);
356 }
357
358 for (uintptr_t i = 0; i < repeat; i++) {
359 test_ext_item.data.data = i;
360 data = (void *)i;
361 mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
362 }
363
364 for (uintptr_t i = 0; i < repeat; i++) {
365 t = (union test_item *)mpsc_pbuf_claim(&buffer);
366 zassert_true(t);
367 zassert_equal(t->data_ext.data, (void *)i);
368 zassert_equal(t->data_ext.hdr.data, i);
369 mpsc_pbuf_free(&buffer, &t->item);
370 }
371
372 zassert_is_null(mpsc_pbuf_claim(&buffer));
373 }
374
ZTEST(log_buffer,test_item_put_ext_saturate)375 ZTEST(log_buffer, test_item_put_ext_saturate)
376 {
377 item_put_ext_saturate(true);
378 item_put_ext_saturate(false);
379 }
380
benchmark_item_put_ext(bool pow2)381 void benchmark_item_put_ext(bool pow2)
382 {
383 struct mpsc_pbuf_buffer buffer;
384
385 init(&buffer, ARRAY_SIZE(buf32) - !pow2, false);
386
387 int repeat = (buffer.size - 1) / PUT_EXT_LEN;
388 union test_item test_ext_item = {
389 .data = {
390 .valid = 1,
391 .len = PUT_EXT_LEN
392 }
393 };
394 void *data = NULL;
395 uint32_t t = get_cyc();
396
397 for (int i = 0; i < repeat; i++) {
398 test_ext_item.data.data = i;
399 mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, data);
400 }
401
402 t = get_cyc() - t;
403 PRINT("%spow2 buffer\n", pow2 ? "" : "non-");
404 PRINT("put_ext time: %d cycles\n", t/repeat);
405
406 t = get_cyc();
407 for (int i = 0; i < repeat; i++) {
408 union test_item *ti;
409
410 ti = (union test_item *)mpsc_pbuf_claim(&buffer);
411 zassert_true(ti);
412 zassert_equal(ti->data.data, i);
413 mpsc_pbuf_free(&buffer, &ti->item);
414 }
415
416 t = get_cyc() - t;
417 PRINT("ext item claim,free: %d cycles\n", t/repeat);
418
419 zassert_is_null(mpsc_pbuf_claim(&buffer));
420 }
421
ZTEST(log_buffer,test_benchmark_item_put_ext)422 ZTEST(log_buffer, test_benchmark_item_put_ext)
423 {
424 benchmark_item_put_ext(true);
425 benchmark_item_put_ext(false);
426 }
427
benchmark_item_put_data(bool pow2)428 void benchmark_item_put_data(bool pow2)
429 {
430 struct mpsc_pbuf_buffer buffer;
431
432 init(&buffer, ARRAY_SIZE(buf32) - !pow2, false);
433
434 int repeat = (buffer.size - 1) / PUT_EXT_LEN;
435 union test_item test_ext_item = {
436 .data_ext = {
437 .hdr = {
438 .valid = 1,
439 .len = PUT_EXT_LEN
440 },
441 .data = NULL
442 }
443 };
444 uint32_t cyc = get_cyc();
445
446 for (uintptr_t i = 0; i < repeat; i++) {
447 test_ext_item.data_ext.hdr.data = i;
448 test_ext_item.data_ext.data = (void *)i;
449 mpsc_pbuf_put_data(&buffer, (uint32_t *)&test_ext_item,
450 PUT_EXT_LEN);
451 }
452
453 cyc = get_cyc() - cyc;
454 PRINT("%spow2 buffer\n", pow2 ? "" : "non-");
455 PRINT("put_ext time: %d cycles\n", cyc/repeat);
456
457 cyc = get_cyc();
458 for (int i = 0; i < repeat; i++) {
459 union test_item *ti;
460
461 ti = (union test_item *)mpsc_pbuf_claim(&buffer);
462 zassert_true(ti);
463 zassert_equal(ti->data.data, i);
464 mpsc_pbuf_free(&buffer, &ti->item);
465 }
466
467 cyc = get_cyc() - cyc;
468 PRINT("ext item claim,free: %d cycles\n", cyc/repeat);
469
470 zassert_is_null(mpsc_pbuf_claim(&buffer));
471 }
472
ZTEST(log_buffer,test_benchmark_item_put_data)473 ZTEST(log_buffer, test_benchmark_item_put_data)
474 {
475 benchmark_item_put_data(true);
476 benchmark_item_put_data(false);
477 }
478
item_put_data_overwrite(bool pow2)479 void item_put_data_overwrite(bool pow2)
480 {
481 struct mpsc_pbuf_buffer buffer;
482
483 init(&buffer, 8 - !pow2, true);
484
485 size_t w = (sizeof(uint32_t) + sizeof(void *)) / sizeof(uint32_t);
486 int repeat = 1 + buffer.size / w;
487 static const int len = sizeof(struct test_data_ext) / sizeof(uint32_t);
488 struct test_data_ext item = {
489 .hdr = {
490 .valid = 1,
491 .len = len
492 }
493 };
494
495 exp_dropped_data[0] = 0;
496 exp_dropped_len[0] = w;
497 exp_drop_cnt = 1;
498
499 for (uintptr_t i = 0; i < repeat; i++) {
500 void *vitem;
501 item.data = (void *)i;
502 item.hdr.data = i;
503 vitem = (uint32_t *)&item;
504 zassert_true(IS_PTR_ALIGNED(vitem, uint32_t), "unaligned ptr");
505 mpsc_pbuf_put_data(&buffer, (uint32_t *)vitem, len);
506 }
507
508 zassert_equal(drop_cnt, exp_drop_cnt,
509 "Unexpected number of dropped messages: %d", drop_cnt);
510 }
511
ZTEST(log_buffer,test_put_data_overwrite)512 ZTEST(log_buffer, test_put_data_overwrite)
513 {
514 item_put_data_overwrite(true);
515 item_put_data_overwrite(false);
516 }
517
item_alloc_commit(bool pow2)518 void item_alloc_commit(bool pow2)
519 {
520 struct mpsc_pbuf_buffer buffer;
521
522 init(&buffer, 16 - !pow2, false);
523
524 struct test_data_var *packet;
525 uint32_t len = 5;
526 int repeat = 1024;
527
528 for (int i = 0; i < repeat; i++) {
529 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
530 K_NO_WAIT);
531 packet->hdr.len = len;
532 for (int j = 0; j < len - 1; j++) {
533 packet->data[j] = i + j;
534 }
535
536 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
537
538 packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
539 zassert_true(packet);
540 zassert_equal(packet->hdr.len, len);
541
542 for (int j = 0; j < len - 1; j++) {
543 zassert_equal(packet->data[j], i + j);
544 }
545
546 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
547 }
548 }
549
ZTEST(log_buffer,test_item_alloc_commit)550 ZTEST(log_buffer, test_item_alloc_commit)
551 {
552 item_alloc_commit(true);
553 item_alloc_commit(false);
554 }
555
item_max_alloc(bool overwrite)556 void item_max_alloc(bool overwrite)
557 {
558 struct mpsc_pbuf_buffer buffer;
559 struct test_data_var *packet;
560
561 init(&buffer, 8, overwrite);
562
563 /* First try to allocate the biggest possible packet. */
564 for (int i = 0; i < 2; i++) {
565 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
566 buffer.size,
567 K_NO_WAIT);
568 zassert_true(packet != NULL);
569 packet->hdr.len = buffer.size;
570 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
571
572 packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
573 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
574 }
575
576 /* Too big packet cannot be allocated. */
577 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
578 buffer.size + 1,
579 K_NO_WAIT);
580 zassert_true(packet == NULL);
581 }
582
ZTEST(log_buffer,test_item_max_alloc)583 ZTEST(log_buffer, test_item_max_alloc)
584 {
585 item_max_alloc(true);
586 item_max_alloc(false);
587 }
588
saturate_buffer_uneven(struct mpsc_pbuf_buffer * buffer,uint32_t len)589 static uint32_t saturate_buffer_uneven(struct mpsc_pbuf_buffer *buffer,
590 uint32_t len)
591 {
592 struct test_data_var *packet;
593 uint32_t uneven = 3;
594 uint32_t cnt = 0;
595 int repeat =
596 uneven + ((buffer->size - (uneven * len)) / len);
597
598 /* Put some data to include wrapping */
599 for (int i = 0; i < uneven; i++) {
600 packet = (struct test_data_var *)mpsc_pbuf_alloc(buffer, len,
601 K_NO_WAIT);
602 packet->hdr.len = len;
603 mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)packet);
604
605 packet = (struct test_data_var *)mpsc_pbuf_claim(buffer);
606 zassert_true(packet);
607 mpsc_pbuf_free(buffer, (union mpsc_pbuf_generic *)packet);
608 }
609
610 for (int i = 0; i < repeat; i++) {
611 packet = (struct test_data_var *)mpsc_pbuf_alloc(buffer, len,
612 K_NO_WAIT);
613 zassert_true(packet);
614 packet->hdr.len = len;
615 packet->hdr.data = i;
616 for (int j = 0; j < len - 1; j++) {
617 packet->data[j] = i + j;
618 }
619
620 mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)packet);
621 cnt++;
622 }
623
624 return cnt;
625 }
626
item_alloc_commit_saturate(bool pow2)627 void item_alloc_commit_saturate(bool pow2)
628 {
629 struct mpsc_pbuf_buffer buffer;
630
631 init(&buffer, 32 - !pow2, false);
632
633 saturate_buffer_uneven(&buffer, 5);
634
635 struct test_data_var *packet;
636 uint32_t len = 5;
637
638 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
639 K_NO_WAIT);
640 zassert_is_null(packet);
641
642 /* Get one packet from the buffer. */
643 packet = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
644 zassert_true(packet);
645 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)packet);
646
647 /* and try to allocate one more time, this time with success. */
648 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len,
649 K_NO_WAIT);
650 zassert_true(packet);
651 }
652
ZTEST(log_buffer,test_item_alloc_commit_saturate)653 ZTEST(log_buffer, test_item_alloc_commit_saturate)
654 {
655 item_alloc_commit_saturate(true);
656 item_alloc_commit_saturate(false);
657 }
658
item_alloc_preemption(bool pow2)659 void item_alloc_preemption(bool pow2)
660 {
661 struct mpsc_pbuf_buffer buffer;
662
663 init(&buffer, ARRAY_SIZE(buf32) - !pow2, false);
664
665 struct test_data_var *p0;
666 struct test_data_var *p1;
667 struct test_data_var *p;
668
669 p0 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 10, K_NO_WAIT);
670 zassert_true(p0);
671 p0->hdr.len = 10;
672
673 /* Check that no packet is yet available */
674 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
675 zassert_is_null(p);
676
677 p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 20, K_NO_WAIT);
678 zassert_true(p1);
679 p1->hdr.len = 20;
680
681 /* Commit p1, p0 is still not committed, there should be no packets
682 * available for reading.
683 */
684 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
685
686 /* Check that no packet is yet available */
687 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
688 zassert_is_null(p);
689
690 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p0);
691
692 /* Validate that p0 is the first one. */
693 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
694 zassert_true(p);
695 zassert_equal(p->hdr.len, 10);
696 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
697
698 /* Validate that p1 is the next one. */
699 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
700 zassert_true(p);
701 zassert_equal(p->hdr.len, 20);
702 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
703
704 /* No more packets. */
705 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
706 zassert_is_null(p);
707 }
708
ZTEST(log_buffer,test_item_alloc_preemption)709 ZTEST(log_buffer, test_item_alloc_preemption)
710 {
711 item_alloc_preemption(true);
712 item_alloc_preemption(false);
713 }
714
overwrite(bool pow2)715 void overwrite(bool pow2)
716 {
717 struct test_data_var *p;
718 uint32_t fill_len = 5;
719 uint32_t len0, len1;
720 struct mpsc_pbuf_buffer buffer;
721
722 init(&buffer, 32 - !pow2, true);
723 uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
724
725 zassert_equal(drop_cnt, exp_drop_cnt);
726
727 exp_dropped_data[0] = 0;
728 exp_dropped_len[0] = fill_len;
729 exp_drop_cnt++;
730 exp_dropped_data[1] = 1;
731 exp_dropped_len[1] = fill_len;
732 exp_drop_cnt++;
733
734 len0 = 6;
735 p = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len0, K_NO_WAIT);
736
737 p->hdr.len = len0;
738 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p);
739 zassert_equal(drop_cnt, exp_drop_cnt);
740
741 /* Request allocation which will require dropping 2 packets. */
742 len1 = 9;
743 exp_dropped_data[1] = 1;
744 exp_dropped_len[1] = fill_len;
745 exp_dropped_data[2] = 2;
746 exp_dropped_len[2] = fill_len;
747 exp_drop_cnt = 3;
748
749 p = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len1, K_NO_WAIT);
750
751 p->hdr.len = len1;
752 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p);
753 zassert_equal(drop_cnt, exp_drop_cnt);
754
755 for (int i = 0; i < (packet_cnt - drop_cnt); i++) {
756 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
757 zassert_true(p);
758 zassert_equal(p->hdr.len, fill_len);
759 zassert_equal(p->hdr.data, i + drop_cnt);
760 for (int j = 0; j < fill_len - 1; j++) {
761 zassert_equal(p->data[j], p->hdr.data + j);
762 }
763
764 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
765 }
766
767 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
768 zassert_true(p);
769 zassert_equal(p->hdr.len, len0);
770 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
771
772 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
773 zassert_true(p);
774 zassert_equal(p->hdr.len, len1);
775 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p);
776
777 p = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
778 zassert_is_null(p);
779 }
780
ZTEST(log_buffer,test_overwrite)781 ZTEST(log_buffer, test_overwrite)
782 {
783 overwrite(true);
784 overwrite(false);
785 }
786
overwrite_while_claimed(bool pow2)787 void overwrite_while_claimed(bool pow2)
788 {
789 struct test_data_var *p0;
790 struct test_data_var *p1;
791 struct mpsc_pbuf_buffer buffer;
792
793 init(&buffer, 32 - !pow2, true);
794
795 uint32_t fill_len = 5;
796 uint32_t len = 6;
797 uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
798
799 /* Start by claiming a packet. Buffer is now full. Allocation shall
800 * skip claimed packed and drop the next one.
801 */
802 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
803 zassert_true(p0);
804 zassert_equal(p0->hdr.len, fill_len);
805
806 exp_dropped_data[0] = p0->hdr.data + 1; /* next packet is dropped */
807 exp_dropped_len[0] = fill_len;
808 exp_dropped_data[1] = p0->hdr.data + 2; /* next packet is dropped */
809 exp_dropped_len[1] = fill_len;
810 exp_drop_cnt = 2;
811 p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, 6, K_NO_WAIT);
812 zassert_equal(drop_cnt, exp_drop_cnt);
813 p1->hdr.len = len;
814 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
815
816 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
817
818 for (int i = 0; i < packet_cnt - drop_cnt - 1; i++) {
819 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
820 zassert_true(p0);
821 zassert_equal(p0->hdr.len, fill_len);
822 zassert_equal(p0->hdr.data, i + drop_cnt + 1);
823 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
824 }
825
826 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
827 zassert_true(p0);
828 zassert_equal(p0->hdr.len, len);
829
830 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
831 zassert_is_null(p0);
832 }
833
ZTEST(log_buffer,test_overwrite_while_claimed)834 ZTEST(log_buffer, test_overwrite_while_claimed)
835 {
836 overwrite_while_claimed(true);
837 overwrite_while_claimed(false);
838 }
839
overwrite_while_claimed2(bool pow2)840 void overwrite_while_claimed2(bool pow2)
841 {
842 struct test_data_var *p0;
843 struct test_data_var *p1;
844 struct mpsc_pbuf_buffer buffer;
845
846 init(&buffer, 32 - !pow2, true);
847
848 uint32_t fill_len = 1;
849 uint32_t len = 3;
850 uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
851
852 /* Start by claiming a packet. Buffer is now full. Allocation shall
853 * skip claimed packed and drop the next one.
854 */
855 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
856 zassert_true(p0);
857 zassert_equal(p0->hdr.len, fill_len);
858
859 exp_dropped_data[0] = p0->hdr.data + 1; /* next packet is dropped */
860 exp_dropped_len[0] = fill_len;
861 exp_dropped_data[1] = p0->hdr.data + 2; /* next packet is dropped */
862 exp_dropped_len[1] = fill_len;
863 exp_dropped_data[2] = p0->hdr.data + 3; /* next packet is dropped */
864 exp_dropped_len[2] = fill_len;
865 exp_drop_cnt = 3;
866 p1 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
867
868 zassert_equal(drop_cnt, exp_drop_cnt);
869 p1->hdr.len = len;
870 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)p1);
871
872 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
873
874 for (int i = 0; i < packet_cnt - drop_cnt - 1; i++) {
875 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
876 zassert_true(p0);
877 zassert_equal(p0->hdr.len, fill_len);
878 zassert_equal(p0->hdr.data, i + drop_cnt + 1);
879 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)p0);
880 }
881
882 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
883 zassert_true(p0);
884 zassert_equal(p0->hdr.len, len);
885
886 p0 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
887 zassert_is_null(p0);
888 }
889
ZTEST(log_buffer,test_overwrite_while_claimed2)890 ZTEST(log_buffer, test_overwrite_while_claimed2)
891 {
892 overwrite_while_claimed2(true);
893 overwrite_while_claimed2(false);
894 }
895
896 static uintptr_t current_rd_idx;
897
validate_packet(struct test_data_var * packet)898 static void validate_packet(struct test_data_var *packet)
899 {
900 zassert_equal((uintptr_t)packet->hdr.data, current_rd_idx,
901 "Got %x, expected: %x",
902 (uint32_t)packet->hdr.data, (uint32_t)current_rd_idx);
903 current_rd_idx++;
904 }
905
consistent_drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)906 static void consistent_drop(const struct mpsc_pbuf_buffer *buffer,
907 const union mpsc_pbuf_generic *item)
908 {
909 validate_packet((struct test_data_var *)item);
910 }
911
rand_get(uint32_t min,uint32_t max)912 uint32_t rand_get(uint32_t min, uint32_t max)
913 {
914 return min + (sys_rand32_get() % max);
915 }
916
ZTEST(log_buffer,test_overwrite_consistency)917 ZTEST(log_buffer, test_overwrite_consistency)
918 {
919 struct mpsc_pbuf_buffer buffer;
920 static struct mpsc_pbuf_buffer_config cfg = {
921 .buf = buf32,
922 .size = ARRAY_SIZE(buf32),
923 .notify_drop = consistent_drop,
924 .get_wlen = get_wlen,
925 .flags = MPSC_PBUF_MODE_OVERWRITE
926 };
927
928 mpsc_pbuf_init(&buffer, &cfg);
929 int repeat = 50000;
930 int id = 0;
931
932 while (id < repeat) {
933 struct test_data_var *tdv = NULL;
934 bool alloc_during_claim = (rand_get(1, 5) <= 2);
935
936 /* Occasionally claim buffer to simulate that claiming is
937 * interrupted by allocation.
938 */
939 if (alloc_during_claim) {
940 tdv = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
941 if (tdv) {
942 validate_packet(tdv);
943 }
944 }
945
946 uint32_t wr_cnt = rand_get(1, 15);
947
948 for (int i = 0; i < wr_cnt; i++) {
949 uint32_t wlen = rand_get(1, 15);
950 struct test_data_var *tdv2;
951
952 tdv2 = (struct test_data_var *)mpsc_pbuf_alloc(&buffer,
953 wlen,
954 K_NO_WAIT);
955 tdv2->hdr.len = wlen;
956 tdv2->hdr.data = id++;
957 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)tdv2);
958 }
959
960 /* Put back item claimed before committing new items. */
961 if (tdv) {
962 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)tdv);
963 }
964
965 uint32_t rd_cnt = rand_get(1, 30);
966
967 for (int i = 0; i < rd_cnt; i++) {
968 struct test_data_var *tdv2;
969
970 tdv2 = (struct test_data_var *)mpsc_pbuf_claim(&buffer);
971 if (!tdv2) {
972 continue;
973 }
974
975 validate_packet(tdv2);
976 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)tdv2);
977 }
978 }
979 }
980
981 K_THREAD_STACK_DEFINE(t1_stack, 1024);
982 K_THREAD_STACK_DEFINE(t2_stack, 1024);
983
984 static k_thread_stack_t *stacks[2] = {t1_stack, t2_stack};
985 static struct k_thread threads[2];
986 static k_tid_t tids[2];
987
t_entry(void * p0,void * p1,void * p2)988 void t_entry(void *p0, void *p1, void *p2)
989 {
990 struct mpsc_pbuf_buffer *buffer = p0;
991 uintptr_t wait_ms = (uintptr_t)p1;
992 struct test_data_ext *t;
993 void *vt;
994
995 t = (struct test_data_ext *)mpsc_pbuf_alloc(buffer,
996 sizeof(*t) / sizeof(uint32_t),
997 K_MSEC(1));
998 zassert_is_null(t);
999
1000 t = (struct test_data_ext *)mpsc_pbuf_alloc(buffer,
1001 sizeof(*t) / sizeof(uint32_t),
1002 K_MSEC(wait_ms));
1003 t->hdr.len = PUT_EXT_LEN;
1004 t->data = k_current_get();
1005
1006 vt = t;
1007 zassert_true(IS_PTR_ALIGNED(vt, union mpsc_pbuf_generic), "unaligned ptr");
1008 mpsc_pbuf_commit(buffer, (union mpsc_pbuf_generic *)vt);
1009 while (1) {
1010 k_sleep(K_MSEC(10));
1011 }
1012 }
1013
start_threads(struct mpsc_pbuf_buffer * buffer)1014 void start_threads(struct mpsc_pbuf_buffer *buffer)
1015 {
1016 int prio = 2;
1017 uintptr_t wait_ms = 1000;
1018
1019 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
1020 tids[i] = k_thread_create(&threads[i], stacks[i], 1024, t_entry,
1021 buffer, (void *)wait_ms, NULL,
1022 prio--,
1023 0, K_NO_WAIT);
1024 }
1025
1026 k_sleep(K_MSEC(10));
1027
1028 for (int i = 0; i < ARRAY_SIZE(threads); i++) {
1029 k_ticks_t t = k_thread_timeout_remaining_ticks(tids[i]);
1030 k_ticks_t exp_wait = k_ms_to_ticks_ceil32(wait_ms);
1031
1032 /* Threads shall be blocked, waiting for available space. */
1033 zassert_within(t, exp_wait, k_ms_to_ticks_ceil32(20));
1034 }
1035 }
1036
1037 static uint32_t buf32_1[128];
1038 struct test_msg_data {
1039 union mpsc_pbuf_generic hdr;
1040 uint32_t buf_len; /*contain buf_len and buf*/
1041 uint8_t buf[sizeof(buf32_1)];
1042 };
1043 struct test_msg_hnd {
1044 struct mpsc_pbuf_buffer mpsc_buffer;
1045 uint32_t product_max_cnt;
1046 uint32_t product_cnt;
1047 uint32_t consumer_cnt;
1048 };
1049
1050 K_THREAD_STACK_DEFINE(t3_stack, 1024);
1051 static struct k_thread threads_t3;
1052 static k_tid_t tid3;
1053
test_mpsc_get_used_len(const union mpsc_pbuf_generic * packet)1054 static uint32_t test_mpsc_get_used_len(const union mpsc_pbuf_generic *packet)
1055 {
1056 uint32_t size = 0;
1057 struct test_msg_data *msg_data = NULL;
1058
1059 msg_data = CONTAINER_OF(packet, struct test_msg_data, hdr);
1060 size = msg_data->buf_len + sizeof(union mpsc_pbuf_generic);
1061 size = ROUND_UP(size, sizeof(uint32_t)); /*return number of uint32_t */
1062 size = size / sizeof(uint32_t);
1063 return size;
1064 }
1065
t_data_consumer_entry(void * p0,void * p1,void * p2)1066 static void t_data_consumer_entry(void *p0, void *p1, void *p2)
1067 {
1068 uint32_t read_cnt = 0;
1069 bool wait = true;
1070 const union mpsc_pbuf_generic *msg = NULL;
1071 const struct test_msg_data *test_data = NULL;
1072 struct test_msg_hnd *test_hnd = (struct test_msg_hnd *)p0;
1073
1074 while (1) {
1075 if (msg == NULL) {
1076 msg = mpsc_pbuf_claim(&test_hnd->mpsc_buffer);
1077 }
1078 test_data = (const struct test_msg_data *)msg;
1079 if (test_data == NULL) {
1080 continue;
1081 }
1082 if (test_data && test_hnd->mpsc_buffer.wr_idx == 0) {
1083 wait = false;
1084 }
1085 if (wait == true) {
1086 continue;
1087 }
1088 read_cnt++;
1089 mpsc_pbuf_free(&test_hnd->mpsc_buffer, msg);
1090 msg = NULL;
1091 if (read_cnt == test_hnd->product_max_cnt) {
1092 break;
1093 }
1094
1095 }
1096 test_hnd->consumer_cnt = read_cnt;
1097 }
1098
1099 /* test mpsc_pbuf_alloc can get sem_take
1100 * one thread product data, one thread consumer data
1101 * requirement:
1102 * consumer slow process data
1103 * step:
1104 * 1:product data len is 0.75 of cfg.size
1105 * 2:run product times
1106 *
1107 */
ZTEST(log_buffer,test_sema_lock)1108 ZTEST(log_buffer, test_sema_lock)
1109 {
1110 struct test_msg_hnd test_hnd = {};
1111 struct test_msg_data test_data;
1112 struct test_msg_data *item = NULL;
1113 struct mpsc_pbuf_buffer_config cfg;
1114 uint32_t loop = 0;
1115 size_t wlen = 0;
1116 bool fist_wait = true;
1117
1118 if (CONFIG_SYS_CLOCK_TICKS_PER_SEC < 10000) {
1119 ztest_test_skip();
1120 }
1121
1122 cfg.buf = buf32_1;
1123 cfg.size = ARRAY_SIZE(buf32_1);
1124 cfg.get_wlen = test_mpsc_get_used_len;
1125
1126 mpsc_pbuf_init(&test_hnd.mpsc_buffer, &cfg);
1127 test_hnd.product_max_cnt = 2;
1128
1129 tid3 = k_thread_create(&threads_t3, t3_stack, 1024,
1130 t_data_consumer_entry,
1131 &test_hnd, NULL, NULL,
1132 10, 0, K_NO_WAIT);
1133 k_thread_name_set(&threads_t3, "test_mpsc_consumer");
1134 for (loop = 0; loop < test_hnd.product_max_cnt; loop++) {
1135 if (loop == 0) {
1136 test_data.buf_len = sizeof(buf32_1) / 2;
1137 } else {
1138 test_data.buf_len = sizeof(buf32_1) / 2 + sizeof(buf32_1) / 4;
1139 }
1140 test_data.buf_len = ROUND_UP(test_data.buf_len, sizeof(uint32_t));
1141 memset(test_data.buf, loop + 1, test_data.buf_len);
1142
1143 wlen = test_data.buf_len + sizeof(test_data.buf_len) +
1144 sizeof(test_data.hdr);
1145 wlen = ROUND_UP(wlen, sizeof(uint32_t));
1146 wlen = wlen / sizeof(uint32_t);
1147
1148 if (fist_wait &&
1149 test_data.buf_len == sizeof(buf32_1) / 2 + sizeof(buf32_1) / 4) {
1150 PRINT(" mpsc sema wait\n");
1151 }
1152 item = (struct test_msg_data *)mpsc_pbuf_alloc(&test_hnd.mpsc_buffer,
1153 wlen, K_FOREVER);
1154 item->hdr.raw = 0;
1155 memcpy(item->buf, test_data.buf, test_data.buf_len);
1156 item->buf_len = test_data.buf_len + sizeof(test_data.buf_len);
1157 mpsc_pbuf_commit(&test_hnd.mpsc_buffer, &item->hdr);
1158 if (fist_wait &&
1159 test_data.buf_len == sizeof(buf32_1) / 2 + sizeof(buf32_1) / 4) {
1160 PRINT(" mpsc sema wake\n");
1161 fist_wait = false;
1162 }
1163 test_hnd.product_cnt++;
1164 }
1165 k_thread_join(tid3, K_FOREVER);
1166 zassert_equal(test_hnd.product_cnt,
1167 test_hnd.consumer_cnt, "product %d consume %d",
1168 test_hnd.product_cnt, test_hnd.consumer_cnt);
1169
1170 }
1171 /* Test creates two threads which pends on the buffer until there is a space
1172 * available. When enough buffers is released threads are woken up and they
1173 * allocate packets.
1174 */
ZTEST(log_buffer,test_pending_alloc)1175 ZTEST(log_buffer, test_pending_alloc)
1176 {
1177 int prio = k_thread_priority_get(k_current_get());
1178 struct mpsc_pbuf_buffer buffer;
1179 void *vt;
1180
1181 k_thread_priority_set(k_current_get(), 3);
1182
1183 init(&buffer, ARRAY_SIZE(buf32) - 1, true);
1184
1185 uint32_t fill_len = 1;
1186 uint32_t packet_cnt = saturate_buffer_uneven(&buffer, fill_len);
1187
1188 start_threads(&buffer);
1189
1190 k_sleep(K_MSEC(1));
1191
1192 for (int i = 0; i < packet_cnt; i++) {
1193 union test_item *t = (union test_item *)mpsc_pbuf_claim(&buffer);
1194
1195 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)t);
1196 }
1197
1198
1199 for (int i = 0; i < 2; i++) {
1200 struct test_data_ext *t =
1201 (struct test_data_ext *)mpsc_pbuf_claim(&buffer);
1202
1203 zassert_true(t);
1204 zassert_equal(t->data, tids[ARRAY_SIZE(tids) - 1 - i]);
1205 vt = t;
1206 zassert_true(IS_PTR_ALIGNED(vt, union mpsc_pbuf_generic), "unaligned ptr");
1207 mpsc_pbuf_free(&buffer, (union mpsc_pbuf_generic *)vt);
1208 }
1209
1210 zassert_equal(mpsc_pbuf_claim(&buffer), NULL, "No more packets.");
1211 k_thread_priority_set(k_current_get(), prio);
1212 }
1213
check_packet(struct mpsc_pbuf_buffer * buffer,char exp_c)1214 static void check_packet(struct mpsc_pbuf_buffer *buffer, char exp_c)
1215 {
1216 union test_item claimed_item;
1217 const union mpsc_pbuf_generic *claimed;
1218
1219 claimed = mpsc_pbuf_claim(buffer);
1220 zassert_true(claimed);
1221 claimed_item.item = *claimed;
1222 zassert_equal(claimed_item.data.data, exp_c);
1223
1224 mpsc_pbuf_free(buffer, claimed);
1225 }
1226
ZTEST(log_buffer,test_put_while_claim)1227 ZTEST(log_buffer, test_put_while_claim)
1228 {
1229 struct mpsc_pbuf_buffer buffer;
1230 uint32_t buffer_storage[4];
1231 const union mpsc_pbuf_generic *claimed;
1232 struct mpsc_pbuf_buffer_config buffer_config = {
1233 .buf = buffer_storage,
1234 .size = 4,
1235 .notify_drop = drop,
1236 .get_wlen = get_wlen,
1237 .flags = MPSC_PBUF_SIZE_POW2 | MPSC_PBUF_MODE_OVERWRITE
1238 };
1239 union test_item claimed_item;
1240 union test_item item = {
1241 .data = {
1242 .valid = 1,
1243 .busy = 0,
1244 .len = 1,
1245 .data = (uint32_t)'a'
1246 }
1247 };
1248
1249 exp_drop_cnt = 0;
1250 drop_cnt = 0;
1251 mpsc_pbuf_init(&buffer, &buffer_config);
1252 /* Expect buffer = {} */
1253
1254 for (int i = 0; i < buffer.size; ++i) {
1255 mpsc_pbuf_put_word(&buffer, item.item);
1256 item.data.data++;
1257 }
1258
1259 /* Expect buffer = {a, b, c, d}. Adding new word will drop 'a'. */
1260 exp_dropped_data[exp_drop_cnt] = (uint32_t)'a';
1261 exp_dropped_len[exp_drop_cnt] = 1;
1262 exp_drop_cnt++;
1263
1264 item.data.data = 'e';
1265 mpsc_pbuf_put_word(&buffer, item.item);
1266 zassert_equal(drop_cnt, exp_drop_cnt);
1267 /* Expect buffer = {e, b, c, d} */
1268
1269 claimed = mpsc_pbuf_claim(&buffer);
1270 zassert_true(claimed);
1271 claimed_item.item = *claimed;
1272 zassert_equal(claimed_item.data.data, (uint32_t)'b');
1273
1274 /* Expect buffer = {e, B, c, d}. Adding new will drop 'c'. */
1275 exp_dropped_data[exp_drop_cnt] = (int)'c';
1276 exp_dropped_len[exp_drop_cnt] = 1;
1277 exp_drop_cnt++;
1278
1279 item.data.data = 'f';
1280 mpsc_pbuf_put_word(&buffer, item.item);
1281 zassert_equal(drop_cnt, exp_drop_cnt);
1282 /* Expect buffer = {e, B, f, d}, Adding new will drop 'd'. */
1283
1284 exp_dropped_data[exp_drop_cnt] = (int)'d';
1285 exp_dropped_len[exp_drop_cnt] = 1;
1286 exp_drop_cnt++;
1287 item.data.data = 'g';
1288 mpsc_pbuf_put_word(&buffer, item.item);
1289 zassert_equal(drop_cnt, exp_drop_cnt);
1290 /* Expect buffer = {e, B, f, g} */
1291
1292 mpsc_pbuf_free(&buffer, claimed);
1293 /* Expect buffer = {e -, f, g} */
1294
1295 check_packet(&buffer, 'e');
1296 /* Expect buffer = {-, -, f, g} */
1297
1298 check_packet(&buffer, 'f');
1299 /* Expect buffer = {-, -, -, g} */
1300
1301 check_packet(&buffer, 'g');
1302 /* Expect buffer = {-, -, -, -} */
1303
1304 claimed = mpsc_pbuf_claim(&buffer);
1305 zassert_equal(claimed, NULL);
1306 }
1307
check_usage(struct mpsc_pbuf_buffer * buffer,uint32_t now,int exp_err,uint32_t max,uint32_t line)1308 static void check_usage(struct mpsc_pbuf_buffer *buffer,
1309 uint32_t now, int exp_err, uint32_t max, uint32_t line)
1310 {
1311 uint32_t size;
1312 uint32_t usage;
1313 int err;
1314
1315 mpsc_pbuf_get_utilization(buffer, &size, &usage);
1316 zassert_equal(size / sizeof(int), buffer->size - 1, "%d: got:%d, exp:%d",
1317 line, (uint32_t)(size / sizeof(int)), buffer->size - 1);
1318 zassert_equal(usage, now, "%d: got:%d, exp:%d", line, usage, now);
1319
1320 err = mpsc_pbuf_get_max_utilization(buffer, &usage);
1321 zassert_equal(err, exp_err);
1322 if (err == 0) {
1323 zassert_equal(usage, max, "%d: got:%d, exp:%d", line, usage, max);
1324 }
1325 }
1326
1327 #define CHECK_USAGE(buffer, now, max) \
1328 check_usage(buffer, (now) * sizeof(int), 0, (max) * sizeof(int), __LINE__)
1329
ignore_drop(const struct mpsc_pbuf_buffer * buffer,const union mpsc_pbuf_generic * item)1330 static void ignore_drop(const struct mpsc_pbuf_buffer *buffer,
1331 const union mpsc_pbuf_generic *item)
1332 {
1333 ARG_UNUSED(buffer);
1334 ARG_UNUSED(item);
1335 }
1336
ZTEST(log_buffer,test_utilization)1337 ZTEST(log_buffer, test_utilization)
1338 {
1339 struct mpsc_pbuf_buffer buffer;
1340 struct mpsc_pbuf_buffer_config config = {
1341 .buf = buf32,
1342 .size = ARRAY_SIZE(buf32),
1343 .notify_drop = ignore_drop,
1344 .get_wlen = get_wlen,
1345 .flags = 0 /* Utilization not supported. */
1346 };
1347
1348 mpsc_pbuf_init(&buffer, &config);
1349
1350 check_usage(&buffer, 0, -ENOTSUP, 0, __LINE__);
1351
1352 /* Initialize with max utilization support. */
1353 config.flags = MPSC_PBUF_MAX_UTILIZATION;
1354 mpsc_pbuf_init(&buffer, &config);
1355
1356 CHECK_USAGE(&buffer, 0, 0);
1357
1358 union test_item test_1word = {.data = {.valid = 1, .len = 1 }};
1359 union test_item test_ext_item = {
1360 .data = {
1361 .valid = 1,
1362 .len = PUT_EXT_LEN
1363 }
1364 };
1365 union test_item *t;
1366
1367 mpsc_pbuf_put_word(&buffer, test_1word.item);
1368
1369 CHECK_USAGE(&buffer, 1, 1);
1370
1371 mpsc_pbuf_put_word_ext(&buffer, test_ext_item.item, NULL);
1372
1373 CHECK_USAGE(&buffer, 1 + PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1374
1375 t = (union test_item *)mpsc_pbuf_claim(&buffer);
1376
1377 zassert_true(t != NULL);
1378 CHECK_USAGE(&buffer, 1 + PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1379 mpsc_pbuf_free(&buffer, &t->item);
1380
1381 t = (union test_item *)mpsc_pbuf_claim(&buffer);
1382 zassert_true(t != NULL);
1383
1384 CHECK_USAGE(&buffer, PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1385
1386 mpsc_pbuf_free(&buffer, &t->item);
1387
1388 CHECK_USAGE(&buffer, 0, 1 + PUT_EXT_LEN);
1389
1390 union test_item test_ext_item2 = {
1391 .data_ext = {
1392 .hdr = {
1393 .valid = 1,
1394 .len = PUT_EXT_LEN
1395 },
1396 .data = NULL
1397 }
1398 };
1399
1400 mpsc_pbuf_put_data(&buffer, (uint32_t *)&test_ext_item2, PUT_EXT_LEN);
1401
1402 CHECK_USAGE(&buffer, PUT_EXT_LEN, 1 + PUT_EXT_LEN);
1403
1404 t = (union test_item *)mpsc_pbuf_claim(&buffer);
1405 zassert_true(t != NULL);
1406 mpsc_pbuf_free(&buffer, &t->item);
1407
1408 CHECK_USAGE(&buffer, 0, 1 + PUT_EXT_LEN);
1409
1410 memset(&buffer, 0, sizeof(buffer));
1411 /* Initialize to reset indexes. */
1412 mpsc_pbuf_init(&buffer, &config);
1413
1414 struct test_data_var *packet;
1415 uint32_t len = 5;
1416 uint32_t i;
1417
1418 for (i = 0; i < (buffer.size - 1) / len; i++) {
1419 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
1420 packet->hdr.len = len;
1421
1422 mpsc_pbuf_commit(&buffer, (union mpsc_pbuf_generic *)packet);
1423 CHECK_USAGE(&buffer, len * (i + 1), len * (i + 1));
1424 }
1425
1426 packet = (struct test_data_var *)mpsc_pbuf_alloc(&buffer, len, K_NO_WAIT);
1427
1428 zassert_true(packet == NULL);
1429 }
1430
1431 /* Make sure that `mpsc_pbuf_alloc()` works in spinlock-held context when buf is not available */
ZTEST(log_buffer,test_alloc_in_spinlock)1432 ZTEST(log_buffer, test_alloc_in_spinlock)
1433 {
1434 struct mpsc_pbuf_buffer buffer;
1435 struct test_data_var *packet;
1436 struct k_spinlock l = {0};
1437
1438 init(&buffer, 32, false);
1439
1440 /* Allocate all available buffer */
1441 packet = (struct test_data_var *)mpsc_pbuf_alloc(
1442 &buffer, 32, K_MSEC(10));
1443 zassert_not_null(packet);
1444
1445 K_SPINLOCK(&l) {
1446 /* Try to allocate another buf */
1447 packet = (struct test_data_var *)mpsc_pbuf_alloc(
1448 &buffer, 32, K_MSEC(10));
1449 /* No buf is available this time */
1450 zassert_is_null(packet);
1451 }
1452 }
1453
1454 /*test case main entry*/
1455 ZTEST_SUITE(log_buffer, NULL, NULL, NULL, NULL, NULL);
1456