Skip to content

Commit b290ff3

Browse files
author
Cruz Monrreal
authored
Merge pull request #7127 from davidsaada/david_nvstore_fix_test_alloc
NVStore tests: Tune memory consumption; stop threads greafully
2 parents 3becf77 + 1b5b839 commit b290ff3

File tree

1 file changed

+83
-37
lines changed
  • features/nvstore/TESTS/nvstore/functionality

1 file changed

+83
-37
lines changed

features/nvstore/TESTS/nvstore/functionality/main.cpp

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <stdlib.h>
2727
#include <stdio.h>
2828
#include <algorithm>
29+
#include "mbed_stats.h"
2930

3031
#if !NVSTORE_ENABLED
3132
#error [NOT_SUPPORTED] NVSTORE needs to be enabled for this test
@@ -42,26 +43,24 @@ static const int thr_test_num_secs = 5;
4243
static const int thr_test_max_data_size = 32;
4344
static const int thr_test_num_threads = 3;
4445

45-
#ifdef TARGET_NRF52
46-
static const int thr_test_stack_size = 1024;
47-
#else
48-
static const int thr_test_stack_size = 768;
49-
#endif
46+
static const int thr_test_min_stack_size = 768;
47+
static const int thr_test_max_stack_size = 1024;
48+
5049

5150
typedef struct {
5251
uint8_t *buffs[max_test_keys][thr_test_num_buffs];
5352
uint16_t sizes[max_test_keys][thr_test_num_buffs];
54-
int inds[max_test_keys];
5553
uint16_t max_keys;
56-
uint16_t last_key;
57-
int last_ind;
54+
bool stop_threads;
5855
} thread_test_data_t;
5956

6057
static thread_test_data_t *thr_test_data;
6158

6259
static const int race_test_num_threads = 4;
6360
static const int race_test_key = 1;
6461
static const int race_test_data_size = 128;
62+
static const int race_test_min_stack_size = 768;
63+
static const int race_test_max_stack_size = 1024;
6564

6665
static void gen_random(uint8_t *s, int len)
6766
{
@@ -378,6 +377,41 @@ static void nvstore_basic_functionality_test()
378377
delete[] nvstore_testing_buf_get;
379378
}
380379

380+
// This function calculates the stack size that needs to be allocated per thread in
381+
// the multi-thread tests. Given minimal and maximal stack sizes, and based on the heap
382+
// stats (automatically enabled in CI), the function checks whether each thread has at least
383+
// the minimal stack size, otherwise it reduces the number of threads (something that may happen
384+
// on low memory boards).
385+
static void calc_thread_stack_size(int &num_threads, uint32_t min_size, uint32_t max_size,
386+
uint32_t &stack_size)
387+
{
388+
mbed_stats_heap_t heap_stats;
389+
mbed_stats_heap_get(&heap_stats);
390+
391+
// reserved size (along with all other fields in heap stats) will be zero if
392+
// app is compiled without heap stats (typically local builds)
393+
if (!heap_stats.reserved_size) {
394+
stack_size = max_size;
395+
printf("Heap stats disabled in this build, so test may fail due to insufficient heap size\n");
396+
printf("If this happens, please build the test with heap stats enabled (-DMBED_HEAP_STATS_ENABLED=1)\n");
397+
return;
398+
}
399+
400+
NVStore &nvstore = NVStore::get_instance();
401+
int page_size = nvstore.size() / nvstore.get_max_possible_keys();
402+
// Check if we can allocate enough stack size (per thread) for the current number of threads
403+
while (num_threads) {
404+
stack_size = (heap_stats.reserved_size - heap_stats.current_size) / num_threads - sizeof(rtos::Thread) - page_size;
405+
406+
stack_size = std::min(stack_size, max_size);
407+
if (stack_size >= min_size) {
408+
return;
409+
}
410+
411+
// Got here - stack not sufficient per thread. Reduce number of threads
412+
num_threads--;
413+
}
414+
}
381415

382416
static void thread_test_check_key(uint16_t key)
383417
{
@@ -386,7 +420,7 @@ static void thread_test_check_key(uint16_t key)
386420
uint16_t actual_len_bytes;
387421
NVStore &nvstore = NVStore::get_instance();
388422

389-
ret = nvstore.get(key, basic_func_max_data_size, get_buff, actual_len_bytes);
423+
ret = nvstore.get(key, thr_test_max_data_size, get_buff, actual_len_bytes);
390424
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
391425
TEST_ASSERT_NOT_EQUAL(0, actual_len_bytes);
392426

@@ -400,13 +434,6 @@ static void thread_test_check_key(uint16_t key)
400434
}
401435
}
402436

403-
if (key == thr_test_data->last_key) {
404-
if ((thr_test_data->sizes[key][thr_test_data->last_ind] == actual_len_bytes) &&
405-
(!memcmp(thr_test_data->buffs[key][thr_test_data->last_ind], get_buff, actual_len_bytes))) {
406-
return;
407-
}
408-
}
409-
410437
// Got here - always assert
411438
TEST_ASSERT(0);
412439

@@ -420,17 +447,13 @@ static void thread_test_worker()
420447
uint16_t key;
421448
NVStore &nvstore = NVStore::get_instance();
422449

423-
for (;;) {
450+
while (!thr_test_data->stop_threads) {
424451
key = rand() % thr_test_data->max_keys;
425452
is_set = rand() % 10;
426-
427453
if (is_set) {
428454
buf_num = rand() % thr_test_num_buffs;
429-
thr_test_data->last_key = key;
430-
thr_test_data->last_ind = buf_num;
431455
ret = nvstore.set(key, thr_test_data->sizes[key][buf_num], thr_test_data->buffs[key][buf_num]);
432456
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
433-
thr_test_data->inds[key] = buf_num;
434457
} else {
435458
thread_test_check_key(key);
436459
}
@@ -445,6 +468,7 @@ static void nvstore_multi_thread_test()
445468
#ifdef MBED_CONF_RTOS_PRESENT
446469
int i;
447470
int num_threads = thr_test_num_threads;
471+
uint32_t stack_size;
448472
uint16_t size;
449473
uint16_t key;
450474
int ret;
@@ -458,43 +482,51 @@ static void nvstore_multi_thread_test()
458482

459483
thr_test_data = new thread_test_data_t;
460484
thr_test_data->max_keys = max_test_keys / 2;
485+
thr_test_data->stop_threads = false;
461486
for (key = 0; key < thr_test_data->max_keys; key++) {
462487
for (i = 0; i < thr_test_num_buffs; i++) {
463488
size = 1 + rand() % thr_test_max_data_size;
464489
thr_test_data->sizes[key][i] = size;
465490
thr_test_data->buffs[key][i] = new uint8_t[size + 1];
466-
thr_test_data->inds[key] = 0;
467491
gen_random(thr_test_data->buffs[key][i], size);
468492
}
469493
ret = nvstore.set(key, thr_test_data->sizes[key][0], thr_test_data->buffs[key][0]);
470494
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
471495
}
472496

497+
calc_thread_stack_size(num_threads, thr_test_min_stack_size, thr_test_max_stack_size, stack_size);
498+
if (!num_threads) {
499+
printf("Not enough heap space to run test. Test skipped\n");
500+
goto end;
501+
}
502+
473503
for (i = 0; i < num_threads; i++) {
474-
threads[i] = new rtos::Thread((osPriority_t)((int)osPriorityBelowNormal-num_threads+i), thr_test_stack_size);
504+
threads[i] = new rtos::Thread((osPriority_t)((int)osPriorityBelowNormal - num_threads + i), stack_size);
475505
threads[i]->start(callback(thread_test_worker));
476506
}
477507

478508
wait_ms(thr_test_num_secs * 1000);
509+
thr_test_data->stop_threads = true;
510+
511+
wait_ms(1000);
479512

480513
for (i = 0; i < num_threads; i++) {
481-
threads[i]->terminate();
482514
delete threads[i];
483515
}
484516

485517
delete[] threads;
486518

487-
wait_ms(1000);
488-
489-
nvstore.deinit();
519+
ret = nvstore.deinit();
520+
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
490521

491-
nvstore.init();
522+
ret = nvstore.init();
523+
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
492524

493525
for (key = 0; key < thr_test_data->max_keys; key++) {
494526
thread_test_check_key(key);
495-
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
496527
}
497528

529+
end:
498530
for (key = 0; key < thr_test_data->max_keys; key++) {
499531
for (i = 0; i < thr_test_num_buffs; i++) {
500532
delete[] thr_test_data->buffs[key][i];
@@ -503,9 +535,12 @@ static void nvstore_multi_thread_test()
503535

504536
delete thr_test_data;
505537

538+
nvstore.reset();
539+
506540
#endif
507541
}
508542

543+
509544
static void race_test_worker(void *buf)
510545
{
511546
int ret;
@@ -519,18 +554,20 @@ static void nvstore_race_test()
519554
{
520555
#ifdef MBED_CONF_RTOS_PRESENT
521556
int i;
557+
uint32_t stack_size;
522558
uint16_t initial_buf_size;
523559
int ret;
524560
rtos::Thread *threads[race_test_num_threads];
525561
uint8_t *get_buff, *buffs[race_test_num_threads];
562+
int num_threads = race_test_num_threads;
526563
uint16_t actual_len_bytes;
527564

528565
NVStore &nvstore = NVStore::get_instance();
529566

530567
ret = nvstore.reset();
531568
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
532569

533-
initial_buf_size = std::min((nvstore.size() - race_test_data_size) / 2, (size_t) 256);
570+
initial_buf_size = std::min((nvstore.size() - race_test_data_size) / 2, (size_t) race_test_data_size);
534571
uint8_t *initial_buf = new uint8_t[initial_buf_size];
535572
int num_sets = (nvstore.size() - race_test_data_size) / initial_buf_size;
536573
for (i = 0; i < num_sets; i++) {
@@ -539,33 +576,42 @@ static void nvstore_race_test()
539576
}
540577
delete[] initial_buf;
541578

542-
for (i = 0; i < race_test_num_threads; i++) {
579+
get_buff = new uint8_t[race_test_data_size];
580+
581+
calc_thread_stack_size(num_threads, race_test_min_stack_size, race_test_max_stack_size, stack_size);
582+
if (!num_threads) {
583+
printf("Not enough heap space to run test. Test skipped\n");
584+
goto end;
585+
}
586+
587+
for (i = 0; i < num_threads; i++) {
543588
buffs[i] = new uint8_t[race_test_data_size];
544589
gen_random(buffs[i], race_test_data_size);
545590
}
546591

547-
for (i = 0; i < race_test_num_threads; i++) {
548-
threads[i] = new rtos::Thread((osPriority_t)((int)osPriorityBelowNormal - race_test_num_threads + i), thr_test_stack_size);
592+
for (i = 0; i < num_threads; i++) {
593+
threads[i] = new rtos::Thread((osPriority_t)((int)osPriorityBelowNormal - num_threads + i), stack_size);
549594
threads[i]->start(callback(race_test_worker, (void *) buffs[i]));
550595
threads[i]->join();
551596
}
552597

553-
get_buff = new uint8_t[race_test_data_size];
554598
ret = nvstore.get(race_test_key, race_test_data_size, get_buff, actual_len_bytes);
555599
TEST_ASSERT_EQUAL(NVSTORE_SUCCESS, ret);
556600
TEST_ASSERT_EQUAL(race_test_data_size, actual_len_bytes);
557601

558-
for (i = 0; i < race_test_num_threads; i++) {
602+
for (i = 0; i < num_threads; i++) {
559603
if (!memcmp(buffs[i], get_buff, actual_len_bytes)) {
560604
break;
561605
}
562606
}
563-
TEST_ASSERT_NOT_EQUAL(race_test_num_threads, i);
607+
TEST_ASSERT_NOT_EQUAL(num_threads, i);
564608

565-
for (i = 0; i < race_test_num_threads; i++) {
609+
for (i = 0; i < num_threads; i++) {
566610
delete threads[i];
567611
delete[] buffs[i];
568612
}
613+
614+
end:
569615
delete[] get_buff;
570616
#endif
571617
}

0 commit comments

Comments
 (0)