1 #include "unity.h"
2 #include <stdatomic.h>
3 #include "esp_log.h"
4 #include "esp_attr.h"
5 #include "hal/cpu_hal.h"
6 #include "../cache_utils.h"
7
8 #define RECORD_TIME_PREPARE() uint32_t __t1, __t2
9 #define RECORD_TIME_START() do {__t1 = cpu_hal_get_cycle_count();}while(0)
10 #define RECORD_TIME_END(p_time) do{__t2 = cpu_hal_get_cycle_count(); *p_time = (__t2-__t1);}while(0)
11
12
13 #define TEST_TIMES 11
14
15 //Test twice, and only get the result of second time, to avoid influence of cache miss
16 #define TEST_WRAP_START() \
17 RECORD_TIME_PREPARE(); \
18 spi_flash_disable_interrupts_caches_and_other_cpu(); \
19 for (int i = 0; i < 2; i++) { \
20 RECORD_TIME_START();
21
22 #define TEST_WRAP_END(output) \
23 RECORD_TIME_END(output); \
24 } \
25 spi_flash_enable_interrupts_caches_and_other_cpu();
26
27 typedef void (*test_f)(uint32_t* t_op);
28
29 static const char TAG[] = "test_atomic";
30 static uint32_t s_t_ref;
31
sorted_array_insert(uint32_t * array,int * size,uint32_t item)32 static void sorted_array_insert(uint32_t* array, int* size, uint32_t item)
33 {
34 int pos;
35 for (pos = *size; pos>0; pos--) {
36 if (array[pos-1] < item) break;
37 array[pos] = array[pos-1];
38 }
39 array[pos]=item;
40 (*size)++;
41 }
42
test_flow(const char * name,test_f func)43 static void test_flow(const char* name, test_f func)
44 {
45 int t_flight_num = 0;
46 uint32_t t_flight_sorted[TEST_TIMES];
47
48 for (int i = 0; i < TEST_TIMES; i++) {
49 uint32_t t_op;
50 func(&t_op);
51 sorted_array_insert(t_flight_sorted, &t_flight_num, t_op);
52 }
53 for (int i = 0; i < TEST_TIMES; i++) {
54 ESP_LOGI(TAG, "%s: %d ops", name, t_flight_sorted[i]-s_t_ref);
55 }
56 }
57
test_ref(uint32_t * t_op)58 static IRAM_ATTR void test_ref(uint32_t* t_op)
59 {
60 TEST_WRAP_START()
61 TEST_WRAP_END(t_op)
62 s_t_ref = *t_op;
63 }
64
test_atomic_load(uint32_t * t_op)65 static IRAM_ATTR void test_atomic_load(uint32_t* t_op)
66 {
67 atomic_uint_fast32_t var;
68 uint32_t target = rand();
69 TEST_WRAP_START()
70 target = atomic_load(&var);
71 TEST_WRAP_END(t_op)
72 (void) target;
73 }
74
test_atomic_store(uint32_t * t_op)75 static IRAM_ATTR void test_atomic_store(uint32_t* t_op)
76 {
77 atomic_uint_fast32_t var;
78 uint32_t src = rand();
79 TEST_WRAP_START()
80 atomic_store(&var, src);
81 TEST_WRAP_END(t_op)
82 }
83
test_atomic_store_load(uint32_t * t_op)84 static IRAM_ATTR void test_atomic_store_load(uint32_t* t_op)
85 {
86 atomic_uint_fast32_t var;
87 uint32_t src = rand();
88 TEST_WRAP_START()
89 atomic_store(&var, src);
90 src = atomic_load(&var);
91 TEST_WRAP_END(t_op)
92 }
93
test_atomic_fetch_and(uint32_t * t_op)94 static IRAM_ATTR void test_atomic_fetch_and(uint32_t* t_op)
95 {
96 atomic_uint_fast32_t var;
97 uint32_t src = rand();
98 TEST_WRAP_START()
99 src = atomic_fetch_and(&var, src);
100 TEST_WRAP_END(t_op)
101 }
102
test_atomic_fetch_or(uint32_t * t_op)103 static IRAM_ATTR void test_atomic_fetch_or(uint32_t* t_op)
104 {
105 atomic_uint_fast32_t var;
106 uint32_t src = rand();
107 TEST_WRAP_START()
108 src = atomic_fetch_or(&var, src);
109 TEST_WRAP_END(t_op)
110 }
111
test_atomic_compare_exchange(uint32_t * t_op)112 static IRAM_ATTR void test_atomic_compare_exchange(uint32_t* t_op)
113 {
114 atomic_uint_fast32_t var;
115 uint32_t src = rand();
116 uint32_t cmp = rand();
117 bool res;
118 TEST_WRAP_START()
119 res = atomic_compare_exchange_weak(&var, &src, cmp);
120 TEST_WRAP_END(t_op)
121 (void) res;
122 }
123
124 TEST_CASE("test atomic","[atomic]")
125 {
126 test_flow("ref", test_ref);
127
128 test_flow("atomic_load", test_atomic_load);
129 test_flow("atomic_store", test_atomic_store);
130 test_flow("atomic_compare_exchange", test_atomic_compare_exchange);
131 test_flow("atomic_store + atomic_load", test_atomic_store_load);
132 test_flow("atomic_and", test_atomic_fetch_and);
133 test_flow("atomic_or", test_atomic_fetch_or);
134 }
135