smp_002_tc.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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 002 Test
  13. *
  14. * Test Objectives:
  15. * - Validate thread-safety of rt_smp_call_cpu_mask() under concurrent calls from multiple CPUs.
  16. * - Verify system stability with simultaneous blocking SMP calls.
  17. * - Test core APIs: rt_smp_call_cpu_mask().
  18. *
  19. * Test Scenarios:
  20. * - One worker thread pinned to each CPU core.
  21. * - All threads simultaneously call rt_smp_call_cpu_mask() with random targets.
  22. * - Atomic counter tracks callbacks executed per thread.
  23. *
  24. * Verification Metrics:
  25. * - Callback count must match requested target count.
  26. * - Callbacks execute in interrupt-disabled context.
  27. * - All threads successfully created and pinned.
  28. * - Each thread tests all available CPUs.
  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 callback executions.
  39. * - Final output: "[ PASSED ] [ result ] testcase (components.drivers.smp_call.smoke_002)"
  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_ubase_t tested_cpus = 0;
  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. tested_cpus |= cpu_mask;
  87. rt_smp_call_cpu_mask(cpu_mask, _test_smp_cb, oncpu_param, SMP_CALL_WAIT_ALL);
  88. popcount += __builtin_popcount(cpu_mask);
  89. }
  90. LOG_D("popcount %d, _entry_counts[%d] %d", popcount, oncpu, _entry_counts[oncpu]);
  91. /* TARG.001 */
  92. uassert_true(popcount == rt_atomic_load(&_entry_counts[oncpu]));
  93. /* TOP.001, TOP.002 */
  94. uassert_true(tested_cpus == RT_ALL_CPU);
  95. rt_sem_release(&_utestd_exited);
  96. }
  97. static void _blocking_mtsafe_call(void)
  98. {
  99. rt_err_t error;
  100. for (size_t i = 0; i < RT_CPUS_NR; i++)
  101. {
  102. error = rt_thread_startup(_utestd[i]);
  103. /* SYNC.001, SYNC.002, SYNC.003 */
  104. uassert_true(!error);
  105. }
  106. for (size_t i = 0; i < RT_CPUS_NR; i++)
  107. {
  108. rt_sem_take(&_utestd_exited, RT_WAITING_FOREVER);
  109. }
  110. }
  111. static rt_err_t utest_tc_init(void)
  112. {
  113. for (size_t i = 0; i < RT_CPUS_NR; i++)
  114. {
  115. rt_atomic_store(&_entry_counts[i], 0);
  116. _utestd[i] = rt_thread_create("utestd", _utestd_entry, (void *)i,
  117. UTEST_THR_STACK_SIZE, UTEST_THR_PRIORITY,
  118. 20);
  119. rt_thread_control(_utestd[i], RT_THREAD_CTRL_BIND_CPU, (void *)i);
  120. /* SYNC.001, SYNC.002, SYNC.003 */
  121. uassert_true(_utestd[i] != RT_NULL);
  122. }
  123. rt_sem_init(&_utestd_exited, "utestd", 0, RT_IPC_FLAG_PRIO);
  124. srand(rt_tick_get());
  125. return RT_EOK;
  126. }
  127. static rt_err_t utest_tc_cleanup(void)
  128. {
  129. rt_sem_detach(&_utestd_exited);
  130. return RT_EOK;
  131. }
  132. static void _testcase(void)
  133. {
  134. UTEST_UNIT_RUN(_blocking_mtsafe_call);
  135. }
  136. UTEST_TC_EXPORT(_testcase, "components.drivers.smp_call.smoke_002", utest_tc_init, utest_tc_cleanup, 10);