18class TestSpinLock :
public SpinLock {
24auto test_basic_lock() ->
bool {
26 TestSpinLock lock(
"basic");
29 "IsLockedByCurrentCore failed after lock");
32 "IsLockedByCurrentCore failed after unlock");
37auto test_recursive_lock() ->
bool {
39 TestSpinLock lock(
"recursive");
40 EXPECT_TRUE(lock.Lock(),
"Lock failed in recursive test");
43 klog::Err(
"FAIL: Recursive lock should return false");
49 EXPECT_TRUE(lock.UnLock(),
"Unlock failed in recursive test");
52 klog::Err(
"FAIL: Double unlock should return false");
59auto test_lock_guard() ->
bool {
61 TestSpinLock lock(
"guard");
64 EXPECT_TRUE(lock.IsLockedByCurrentCore(),
"LockGuard failed to lock");
66 EXPECT_TRUE(!lock.IsLockedByCurrentCore(),
"LockGuard failed to unlock");
71auto test_interrupt_restore() ->
bool {
72 klog::Info(
"Running test_interrupt_restore...");
73 TestSpinLock lock(
"intr");
78 klog::Err(
"FAIL: Failed to enable interrupts");
84 klog::Err(
"FAIL: Lock didn't disable interrupts");
91 klog::Err(
"FAIL: Unlock didn't restore interrupts (expected enabled)");
99 klog::Err(
"FAIL: Failed to disable interrupts for test");
105 klog::Err(
"FAIL: Lock enabled interrupts unexpectedly");
113 klog::Err(
"FAIL: Unlock enabled interrupts (expected disabled)");
124int shared_counter = 0;
125std::atomic<int> finished_cores = 0;
127auto spinlock_smp_test() ->
bool {
128 for (
int i = 0; i < 10000; ++i) {
129 (void)smp_lock.Lock();
131 (void)smp_lock.UnLock();
134 int finished = finished_cores.fetch_add(1) + 1;
135 int total_cores = BasicInfoSingleton::instance().core_count;
137 if (finished == total_cores) {
138 bool passed = (shared_counter == total_cores * 10000);
140 klog::Info(
" All cores finished. shared_counter = {}. OK.",
143 klog::Err(
" All cores finished. shared_counter = {}. EXPECTED {}. FAIL.",
144 shared_counter, total_cores * 10000);
152constexpr int BUFFER_SIZE = 8192;
153int shared_buffer[BUFFER_SIZE];
156std::atomic<int> buffer_test_finished_cores = 0;
158auto spinlock_smp_buffer_test() ->
bool {
160 int writes_per_core = 500;
162 for (
int i = 0; i < writes_per_core; ++i) {
163 (void)buffer_lock.Lock();
164 if (buffer_index < BUFFER_SIZE) {
168 (void)buffer_lock.UnLock();
171 int finished = buffer_test_finished_cores.fetch_add(1) + 1;
172 int total_cores = BasicInfoSingleton::instance().core_count;
174 if (finished == total_cores) {
176 klog::Info(
"All cores finished buffer writes. Checking buffer...");
179 int expected_writes = writes_per_core * total_cores;
180 if (expected_writes > BUFFER_SIZE) expected_writes = BUFFER_SIZE;
182 if (buffer_index != expected_writes) {
183 klog::Err(
"FAIL: Buffer index {}, expected {}", buffer_index,
188 klog::Info(
"Buffer test passed. Final index: {}", buffer_index);
195constexpr int STR_BUFFER_SIZE = 512 * 1024;
197char shared_str_buffer[STR_BUFFER_SIZE];
198int str_buffer_offset = 0;
201std::atomic<int> str_test_finished_cores = 0;
202std::atomic<int> str_test_start_barrier = 0;
204auto spinlock_smp_string_test() ->
bool {
206 size_t core_count = BasicInfoSingleton::instance().core_count;
208 if (core_count < 2) {
210 klog::Info(
"Skipping SMP string test: need more than 1 core.");
215 int arrived = str_test_start_barrier.fetch_add(1) + 1;
217 constexpr int kBarrierSpinLimit = 100000000;
219 while (str_test_start_barrier.load() < (
int)core_count) {
220 if (++spins > kBarrierSpinLimit) {
223 "SMP string test barrier timeout: {}/{} cores arrived, skipping",
224 str_test_start_barrier.load(), (
int)core_count);
230 int writes_per_core = 500;
233 for (
int i = 0; i < writes_per_core; ++i) {
236 auto*
end = etl::format_to_n(local_buf,
sizeof(local_buf) - 1,
237 "[C:{}-{}|LongStringPaddingForContention]",
240 int len =
static_cast<int>(
end - local_buf);
242 (void)str_lock.Lock();
243 if (str_buffer_offset + len < STR_BUFFER_SIZE - 1) {
244 for (
int k = 0; k < len; ++k) {
245 shared_str_buffer[str_buffer_offset + k] = local_buf[k];
247 str_buffer_offset += len;
248 shared_str_buffer[str_buffer_offset] =
'\0';
250 (void)str_lock.UnLock();
253 int finished = str_test_finished_cores.fetch_add(1) + 1;
254 if (finished == (
int)core_count) {
257 "All cores finished string writes. Verifying string integrity...");
260 int tokens_found = 0;
262 while (current_idx < str_buffer_offset) {
263 if (shared_str_buffer[current_idx] !=
'[') {
265 klog::Err(
"FAIL: Expected '[' at {}, got '{}'", current_idx,
266 shared_str_buffer[current_idx]);
271 int end_idx = current_idx + 1;
273 while (end_idx < str_buffer_offset) {
274 if (shared_str_buffer[end_idx] ==
']') {
278 if (shared_str_buffer[end_idx] ==
'[') {
287 klog::Err(
"FAIL: Broken token starting at {}", current_idx);
292 if (shared_str_buffer[current_idx + 1] !=
'C' ||
293 shared_str_buffer[current_idx + 2] !=
':') {
295 klog::Err(
"FAIL: Invalid content in token at {}", current_idx);
300 const char* padding =
"|LongStringPaddingForContention";
301 int padding_len = 31;
302 int token_content_len = end_idx - current_idx - 1;
303 bool padding_ok =
true;
305 if (token_content_len < padding_len) {
308 int padding_start = end_idx - padding_len;
309 for (
int p = 0; p < padding_len; ++p) {
310 if (shared_str_buffer[padding_start + p] != padding[p]) {
319 klog::Err(
"FAIL: Broken padding in token at {}. Content len: {}",
320 current_idx, token_content_len);
325 current_idx = end_idx + 1;
328 int expected_tokens = writes_per_core * core_count;
331 if (tokens_found != expected_tokens) {
333 klog::Err(
"FAIL: Expected {} tokens, found {}", expected_tokens,
338 klog::Info(
"String test passed. Length: {}, Tokens: {}",
339 str_buffer_offset, tokens_found);
355 ret = ret && test_basic_lock();
356 ret = ret && test_recursive_lock();
357 ret = ret && test_lock_guard();
358 ret = ret && test_interrupt_restore();
363 if (!spinlock_smp_test()) ret =
false;
364 if (!spinlock_smp_buffer_test()) ret =
false;
365 if (!spinlock_smp_string_test()) ret =
false;
__always_inline auto IsLockedByCurrentCore() -> bool
检查当前 core 是否获得此锁
auto GetCurrentCoreId() -> size_t
bool GetInterruptStatus()
auto Err(etl::format_string< Args... > fmt, Args &&... args) -> void
以 ERROR 级别记录日志
auto Info(etl::format_string< Args... > fmt, Args &&... args) -> void
以 INFO 级别记录日志
auto spinlock_test() -> bool
#define EXPECT_TRUE(cond, msg)