smp_003_tc.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. /*
  2. * Copyright (c) 2006-2024 RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024/10/28 Shell Added smp.smoke
  9. * 2025/12/3 ChuanN-sudo add standardized utest documentation block
  10. */
  11. /**
  12. * Test Case Name: SMP Call Smoke 003 Test
  13. *
  14. * Test Objectives:
  15. * - Validate asynchronous rt_smp_call_cpu_mask() reliability under high-contention.
  16. * - Ensure no Inter-Processor Interrupts are lost when fired rapidly without waiting.
  17. * - Test core APIs: rt_smp_call_cpu_mask() (with wait_flag=0), rt_thread_control(RT_THREAD_CTRL_BIND_CPU)
  18. *
  19. * Test Scenarios:
  20. * - One worker thread pinned to each CPU core.
  21. * - Threads repeatedly call non-blocking rt_smp_call_cpu_mask() with random targets.
  22. * - After dispatching Inter-Processor Interrupts, threads migrate across cores to yield processing time.
  23. * - Final verification checks eventual consistency.
  24. *
  25. * Verification Metrics:
  26. * - Callback count must eventually match requested count.
  27. * - Callbacks execute in interrupt-disabled context.
  28. * - All threads successfully created and started.
  29. *
  30. * Dependencies:
  31. * - Hardware requirements: QEMU emulator or any multi-core hardware platform that supports RT-Thread.
  32. * - Software configuration:
  33. * - RT_USING_UTEST must be enabled (select "RT-Thread Utestcases" in menuconfig).
  34. * - RT_UTEST_SMP_CALL_FUNC must be enabled(enable via: RT-Thread Utestcases -> Kernel Components -> Drivers -> SMP-Call Test -> SMP-Call Smoke Test).
  35. * - Environmental Assumptions: System scheduler and SMP services working normally.
  36. *
  37. * Expected Results:
  38. * - Progress logs: A series of '#' characters indicating asynchronous callback executions.
  39. * - Final output: "[ PASSED ] [ result ] testcase (components.drivers.smp_call.smoke_003)"
  40. */
  41. #include <rtdevice.h>
  42. #include <utest.h>
  43. #include <utest_assert.h>
  44. #include <smp_call.h>
  45. #define PERCPU_TEST_COUNT 10000
  46. #define NEWLINE_ON 80
  47. static struct rt_semaphore _utestd_exited;
  48. static rt_thread_t _utestd[RT_CPUS_NR];
  49. static rt_atomic_t _entry_counts[RT_CPUS_NR];
  50. static void _logging_progress(void)
  51. {
  52. static rt_atomic_t counts;
  53. rt_ubase_t old;
  54. rt_kputs("#");
  55. old = rt_atomic_add(&counts, 1);
  56. if (old % NEWLINE_ON == 0)
  57. {
  58. rt_kputs("\n");
  59. }
  60. }
  61. static void _test_smp_cb(void *param)
  62. {
  63. rt_ubase_t req_cpuid = (rt_ubase_t)param;
  64. if (!rt_hw_interrupt_is_disabled())
  65. {
  66. /* SYNC.004 */
  67. uassert_true(0);
  68. }
  69. _logging_progress();
  70. rt_atomic_add(&_entry_counts[req_cpuid], 1);
  71. }
  72. static void _utestd_entry(void *oncpu_param)
  73. {
  74. rt_ubase_t oncpu = (rt_ubase_t)oncpu_param;
  75. volatile int cpu_mask;
  76. volatile int popcount = 0;
  77. rt_thread_t curthr = rt_thread_self();
  78. if (rt_hw_cpu_id() != oncpu)
  79. {
  80. /* SYNC.004 */
  81. uassert_true(0);
  82. }
  83. for (size_t i = 0; i < PERCPU_TEST_COUNT; i++)
  84. {
  85. cpu_mask = rand() % RT_ALL_CPU;
  86. rt_smp_call_cpu_mask(cpu_mask, _test_smp_cb, oncpu_param, 0);
  87. popcount += __builtin_popcount(cpu_mask);
  88. }
  89. for (size_t i = 0; i < RT_CPUS_NR; i++)
  90. {
  91. rt_thread_control(curthr, RT_THREAD_CTRL_BIND_CPU, (void *)i);
  92. }
  93. LOG_D("popcount %d, _entry_counts[%d] %d", popcount, oncpu, _entry_counts[oncpu]);
  94. /* MP.002 */
  95. uassert_true(popcount == rt_atomic_load(&_entry_counts[oncpu]));
  96. rt_sem_release(&_utestd_exited);
  97. }
  98. static void _async_call(void)
  99. {
  100. for (size_t i = 0; i < RT_CPUS_NR; i++)
  101. {
  102. rt_thread_startup(_utestd[i]);
  103. }
  104. for (size_t i = 0; i < RT_CPUS_NR; i++)
  105. {
  106. rt_sem_take(&_utestd_exited, RT_WAITING_FOREVER);
  107. }
  108. }
  109. static rt_err_t utest_tc_init(void)
  110. {
  111. for (size_t i = 0; i < RT_CPUS_NR; i++)
  112. {
  113. rt_atomic_store(&_entry_counts[i], 0);
  114. _utestd[i] = rt_thread_create("utestd", _utestd_entry, (void *)i,
  115. UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY,
  116. 20);
  117. rt_thread_control(_utestd[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
  118. /* SYNC.001, SYNC.002, SYNC.003 */
  119. uassert_true(_utestd[i] != RT_NULL);
  120. }
  121. rt_sem_init(&_utestd_exited, "utestd", 0, RT_IPC_FLAG_PRIO);
  122. srand(rt_tick_get());
  123. return RT_EOK;
  124. }
  125. static rt_err_t utest_tc_cleanup(void)
  126. {
  127. rt_sem_detach(&_utestd_exited);
  128. return RT_EOK;
  129. }
  130. static void _testcase(void)
  131. {
  132. UTEST_UNIT_RUN(_async_call);
  133. }
  134. UTEST_TC_EXPORT(_testcase, "components.drivers.smp_call.smoke_003", utest_tc_init, utest_tc_cleanup, 10);