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