Skip to content

Commit c02f904

Browse files
nordic-krchcfriedt
authored andcommitted
tests: boards: nrf: dmm: Add stress test
Add stress test which validates that allocator is thread safe and has no memory leaks. Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent 3d31042 commit c02f904

File tree

3 files changed

+185
-0
lines changed

3 files changed

+185
-0
lines changed

tests/boards/nrf/dmm/prj.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
CONFIG_ZTEST=y
2+
CONFIG_ZTRESS=y
23
CONFIG_ASSERT=n
34
CONFIG_SPIN_VALIDATE=n
45
CONFIG_TEST_EXTRA_STACK_SIZE=512

tests/boards/nrf/dmm/src/main.c

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <zephyr/kernel.h>
1111
#include <zephyr/ztest.h>
1212
#include <zephyr/drivers/counter.h>
13+
#include <zephyr/ztress.h>
14+
#include <zephyr/random/random.h>
1315

1416
#include <dmm.h>
1517

@@ -383,6 +385,182 @@ ZTEST_USER_F(dmm, test_check_multiple_alloc_and_free)
383385
}
384386
}
385387

388+
struct dmm_stress_data {
389+
void *mem_reg;
390+
void *alloc_ptr[32];
391+
uint8_t alloc_token[32];
392+
size_t alloc_len[32];
393+
atomic_t alloc_mask;
394+
atomic_t busy_mask;
395+
atomic_t fails;
396+
atomic_t cnt;
397+
bool cached;
398+
};
399+
400+
static void stress_free_op(struct dmm_stress_data *data, int prio, int id)
401+
{
402+
/* buffer is allocated. */
403+
uint8_t token = data->alloc_token[id];
404+
size_t len = data->alloc_len[id];
405+
uint8_t *ptr = data->alloc_ptr[id];
406+
int rv;
407+
408+
for (int j = 0; j < len; j++) {
409+
uint8_t exp_val = (uint8_t)(token + j);
410+
411+
if (ptr[j] != exp_val) {
412+
for (int k = 0; k < len; k++) {
413+
printk("%02x ", ptr[k]);
414+
}
415+
}
416+
zassert_equal(ptr[j], exp_val, "At %d got:%d exp:%d, len:%d id:%d, alloc_cnt:%d",
417+
j, ptr[j], exp_val, len, id, (uint32_t)data->cnt);
418+
}
419+
420+
rv = dmm_buffer_in_release(data->mem_reg, ptr, len, ptr);
421+
zassert_ok(rv);
422+
/* Indicate that buffer is released. */
423+
atomic_and(&data->alloc_mask, ~BIT(id));
424+
}
425+
426+
static bool stress_alloc_op(struct dmm_stress_data *data, int prio, int id)
427+
{
428+
uint32_t r32 = sys_rand32_get();
429+
size_t len = r32 % 512;
430+
uint8_t *ptr = data->alloc_ptr[id];
431+
int rv;
432+
433+
/* Rarely allocate bigger buffer. */
434+
if ((r32 & 0x7) == 0) {
435+
len += 512;
436+
}
437+
438+
rv = dmm_buffer_in_prepare(data->mem_reg, &r32/*dummy*/, len, (void **)&ptr);
439+
if (rv < 0) {
440+
atomic_inc(&data->fails);
441+
return true;
442+
}
443+
444+
uint8_t token = r32 >> 24;
445+
446+
data->alloc_ptr[id] = ptr;
447+
data->alloc_len[id] = len;
448+
data->alloc_token[id] = token;
449+
for (int j = 0; j < len; j++) {
450+
ptr[j] = (uint8_t)(j + token);
451+
}
452+
if (data->cached) {
453+
sys_cache_data_flush_range(ptr, len);
454+
}
455+
atomic_inc(&data->cnt);
456+
return false;
457+
}
458+
459+
bool stress_func(void *user_data, uint32_t cnt, bool last, int prio)
460+
{
461+
struct dmm_stress_data *data = user_data;
462+
uint32_t r = sys_rand32_get();
463+
int rpt = r & 0x3;
464+
465+
r >>= 2;
466+
467+
for (int i = 0; i < rpt + 1; i++) {
468+
int id = r % 32;
469+
int key;
470+
bool free_op;
471+
bool clear_bit;
472+
473+
key = irq_lock();
474+
if ((data->busy_mask & BIT(id)) == 0) {
475+
data->busy_mask |= BIT(id);
476+
if (data->alloc_mask & BIT(id)) {
477+
free_op = true;
478+
} else {
479+
data->alloc_mask |= BIT(id);
480+
free_op = false;
481+
}
482+
} else {
483+
irq_unlock(key);
484+
continue;
485+
}
486+
487+
irq_unlock(key);
488+
r >>= 5;
489+
490+
if (free_op) {
491+
stress_free_op(data, prio, id);
492+
clear_bit = true;
493+
} else {
494+
clear_bit = stress_alloc_op(data, prio, id);
495+
}
496+
497+
key = irq_lock();
498+
data->busy_mask &= ~BIT(id);
499+
if (clear_bit) {
500+
data->alloc_mask &= ~BIT(id);
501+
}
502+
irq_unlock(key);
503+
}
504+
505+
return true;
506+
}
507+
508+
static void free_all(struct dmm_stress_data *data)
509+
{
510+
while (data->alloc_mask) {
511+
int id = 31 - __builtin_clz(data->alloc_mask);
512+
513+
stress_free_op(data, 0, id);
514+
data->alloc_mask &= ~BIT(id);
515+
}
516+
}
517+
518+
static void stress_allocator(void *mem_reg, bool cached)
519+
{
520+
uint32_t timeout = 3000;
521+
struct dmm_stress_data ctx;
522+
int rv;
523+
uint32_t curr_use;
524+
525+
memset(&ctx, 0, sizeof(ctx));
526+
ctx.mem_reg = mem_reg;
527+
ctx.cached = cached;
528+
529+
if (IS_ENABLED(CONFIG_DMM_STATS)) {
530+
rv = dmm_stats_get(ctx.mem_reg, NULL, &curr_use, NULL);
531+
zassert_ok(rv);
532+
}
533+
534+
ztress_set_timeout(K_MSEC(timeout));
535+
536+
ZTRESS_EXECUTE(ZTRESS_THREAD(stress_func, &ctx, INT32_MAX, INT32_MAX, Z_TIMEOUT_TICKS(4)),
537+
ZTRESS_THREAD(stress_func, &ctx, INT32_MAX, INT32_MAX, Z_TIMEOUT_TICKS(4)),
538+
ZTRESS_THREAD(stress_func, &ctx, INT32_MAX, INT32_MAX, Z_TIMEOUT_TICKS(4)));
539+
540+
free_all(&ctx);
541+
TC_PRINT("Executed %d allocation operation. Failed to allocate %d times.\n",
542+
(uint32_t)ctx.cnt, (uint32_t)ctx.fails);
543+
544+
if (IS_ENABLED(CONFIG_DMM_STATS)) {
545+
uint32_t curr_use2;
546+
547+
rv = dmm_stats_get(ctx.mem_reg, NULL, &curr_use2, NULL);
548+
zassert_ok(rv);
549+
zassert_equal(curr_use, curr_use2, "Unexpected usage got:%d exp:%d",
550+
curr_use2, curr_use);
551+
}
552+
}
553+
554+
ZTEST_F(dmm, test_stress_allocator_nocache)
555+
{
556+
stress_allocator(fixture->regions[DMM_TEST_REGION_NOCACHE].mem_reg, false);
557+
}
558+
559+
ZTEST_F(dmm, test_stress_allocator_cache)
560+
{
561+
stress_allocator(fixture->regions[DMM_TEST_REGION_CACHE].mem_reg, true);
562+
}
563+
386564
ZTEST_SUITE(dmm, NULL, test_setup, NULL, test_cleanup, NULL);
387565

388566
int dmm_test_prepare(void)

tests/boards/nrf/dmm/testcase.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,9 @@ tests:
2121
- CONFIG_DMM_STATS=y
2222
platform_allow:
2323
- nrf54h20dk/nrf54h20/cpuapp
24+
boards.nrf.dmm.more_chunks:
25+
extra_configs:
26+
- CONFIG_DMM_STATS=y
27+
- CONFIG_DMM_HEAP_CHUNKS=96
28+
platform_allow:
29+
- nrf54h20dk/nrf54h20/cpuapp

0 commit comments

Comments
 (0)