26
26
#include < stdlib.h>
27
27
#include < stdio.h>
28
28
#include < algorithm>
29
+ #include " mbed_stats.h"
29
30
30
31
#if !NVSTORE_ENABLED
31
32
#error [NOT_SUPPORTED] NVSTORE needs to be enabled for this test
@@ -42,26 +43,24 @@ static const int thr_test_num_secs = 5;
42
43
static const int thr_test_max_data_size = 32 ;
43
44
static const int thr_test_num_threads = 3 ;
44
45
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
+
50
49
51
50
typedef struct {
52
51
uint8_t *buffs[max_test_keys][thr_test_num_buffs];
53
52
uint16_t sizes[max_test_keys][thr_test_num_buffs];
54
- int inds[max_test_keys];
55
53
uint16_t max_keys;
56
- uint16_t last_key;
57
- int last_ind;
54
+ bool stop_threads;
58
55
} thread_test_data_t ;
59
56
60
57
static thread_test_data_t *thr_test_data;
61
58
62
59
static const int race_test_num_threads = 4 ;
63
60
static const int race_test_key = 1 ;
64
61
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 ;
65
64
66
65
static void gen_random (uint8_t *s, int len)
67
66
{
@@ -378,6 +377,41 @@ static void nvstore_basic_functionality_test()
378
377
delete[] nvstore_testing_buf_get;
379
378
}
380
379
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
+ }
381
415
382
416
static void thread_test_check_key (uint16_t key)
383
417
{
@@ -386,7 +420,7 @@ static void thread_test_check_key(uint16_t key)
386
420
uint16_t actual_len_bytes;
387
421
NVStore &nvstore = NVStore::get_instance ();
388
422
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);
390
424
TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
391
425
TEST_ASSERT_NOT_EQUAL (0 , actual_len_bytes);
392
426
@@ -400,13 +434,6 @@ static void thread_test_check_key(uint16_t key)
400
434
}
401
435
}
402
436
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
-
410
437
// Got here - always assert
411
438
TEST_ASSERT (0 );
412
439
@@ -420,17 +447,13 @@ static void thread_test_worker()
420
447
uint16_t key;
421
448
NVStore &nvstore = NVStore::get_instance ();
422
449
423
- for (;; ) {
450
+ while (!thr_test_data-> stop_threads ) {
424
451
key = rand () % thr_test_data->max_keys ;
425
452
is_set = rand () % 10 ;
426
-
427
453
if (is_set) {
428
454
buf_num = rand () % thr_test_num_buffs;
429
- thr_test_data->last_key = key;
430
- thr_test_data->last_ind = buf_num;
431
455
ret = nvstore.set (key, thr_test_data->sizes [key][buf_num], thr_test_data->buffs [key][buf_num]);
432
456
TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
433
- thr_test_data->inds [key] = buf_num;
434
457
} else {
435
458
thread_test_check_key (key);
436
459
}
@@ -445,6 +468,7 @@ static void nvstore_multi_thread_test()
445
468
#ifdef MBED_CONF_RTOS_PRESENT
446
469
int i;
447
470
int num_threads = thr_test_num_threads;
471
+ uint32_t stack_size;
448
472
uint16_t size;
449
473
uint16_t key;
450
474
int ret;
@@ -458,43 +482,51 @@ static void nvstore_multi_thread_test()
458
482
459
483
thr_test_data = new thread_test_data_t ;
460
484
thr_test_data->max_keys = max_test_keys / 2 ;
485
+ thr_test_data->stop_threads = false ;
461
486
for (key = 0 ; key < thr_test_data->max_keys ; key++) {
462
487
for (i = 0 ; i < thr_test_num_buffs; i++) {
463
488
size = 1 + rand () % thr_test_max_data_size;
464
489
thr_test_data->sizes [key][i] = size;
465
490
thr_test_data->buffs [key][i] = new uint8_t [size + 1 ];
466
- thr_test_data->inds [key] = 0 ;
467
491
gen_random (thr_test_data->buffs [key][i], size);
468
492
}
469
493
ret = nvstore.set (key, thr_test_data->sizes [key][0 ], thr_test_data->buffs [key][0 ]);
470
494
TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
471
495
}
472
496
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
+
473
503
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 );
475
505
threads[i]->start (callback (thread_test_worker));
476
506
}
477
507
478
508
wait_ms (thr_test_num_secs * 1000 );
509
+ thr_test_data->stop_threads = true ;
510
+
511
+ wait_ms (1000 );
479
512
480
513
for (i = 0 ; i < num_threads; i++) {
481
- threads[i]->terminate ();
482
514
delete threads[i];
483
515
}
484
516
485
517
delete[] threads;
486
518
487
- wait_ms (1000 );
488
-
489
- nvstore.deinit ();
519
+ ret = nvstore.deinit ();
520
+ TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
490
521
491
- nvstore.init ();
522
+ ret = nvstore.init ();
523
+ TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
492
524
493
525
for (key = 0 ; key < thr_test_data->max_keys ; key++) {
494
526
thread_test_check_key (key);
495
- TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
496
527
}
497
528
529
+ end:
498
530
for (key = 0 ; key < thr_test_data->max_keys ; key++) {
499
531
for (i = 0 ; i < thr_test_num_buffs; i++) {
500
532
delete[] thr_test_data->buffs [key][i];
@@ -503,9 +535,12 @@ static void nvstore_multi_thread_test()
503
535
504
536
delete thr_test_data;
505
537
538
+ nvstore.reset ();
539
+
506
540
#endif
507
541
}
508
542
543
+
509
544
static void race_test_worker (void *buf)
510
545
{
511
546
int ret;
@@ -519,18 +554,20 @@ static void nvstore_race_test()
519
554
{
520
555
#ifdef MBED_CONF_RTOS_PRESENT
521
556
int i;
557
+ uint32_t stack_size;
522
558
uint16_t initial_buf_size;
523
559
int ret;
524
560
rtos::Thread *threads[race_test_num_threads];
525
561
uint8_t *get_buff, *buffs[race_test_num_threads];
562
+ int num_threads = race_test_num_threads;
526
563
uint16_t actual_len_bytes;
527
564
528
565
NVStore &nvstore = NVStore::get_instance ();
529
566
530
567
ret = nvstore.reset ();
531
568
TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
532
569
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 );
534
571
uint8_t *initial_buf = new uint8_t [initial_buf_size];
535
572
int num_sets = (nvstore.size () - race_test_data_size) / initial_buf_size;
536
573
for (i = 0 ; i < num_sets; i++) {
@@ -539,33 +576,42 @@ static void nvstore_race_test()
539
576
}
540
577
delete[] initial_buf;
541
578
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++) {
543
588
buffs[i] = new uint8_t [race_test_data_size];
544
589
gen_random (buffs[i], race_test_data_size);
545
590
}
546
591
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 );
549
594
threads[i]->start (callback (race_test_worker, (void *) buffs[i]));
550
595
threads[i]->join ();
551
596
}
552
597
553
- get_buff = new uint8_t [race_test_data_size];
554
598
ret = nvstore.get (race_test_key, race_test_data_size, get_buff, actual_len_bytes);
555
599
TEST_ASSERT_EQUAL (NVSTORE_SUCCESS, ret);
556
600
TEST_ASSERT_EQUAL (race_test_data_size, actual_len_bytes);
557
601
558
- for (i = 0 ; i < race_test_num_threads ; i++) {
602
+ for (i = 0 ; i < num_threads ; i++) {
559
603
if (!memcmp (buffs[i], get_buff, actual_len_bytes)) {
560
604
break ;
561
605
}
562
606
}
563
- TEST_ASSERT_NOT_EQUAL (race_test_num_threads , i);
607
+ TEST_ASSERT_NOT_EQUAL (num_threads , i);
564
608
565
- for (i = 0 ; i < race_test_num_threads ; i++) {
609
+ for (i = 0 ; i < num_threads ; i++) {
566
610
delete threads[i];
567
611
delete[] buffs[i];
568
612
}
613
+
614
+ end:
569
615
delete[] get_buff;
570
616
#endif
571
617
}
0 commit comments