1 /*
2 * Copyright (c) 2022 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/ztest.h>
7 #include <zephyr/kernel.h>
8 #include <zephyr/arch/arch_interface.h>
9
10 #if defined(CONFIG_SMP) && CONFIG_MP_MAX_NUM_CPUS > 1
11 #define SMP_TEST
12 #endif
13
14 #ifdef SMP_TEST
15 #define MAX_NUM_THREADS CONFIG_MP_MAX_NUM_CPUS
16 #define STACK_SIZE 1024
17 #define PRIORITY 7
18
19 static struct k_thread threads[MAX_NUM_THREADS];
20 static K_THREAD_STACK_ARRAY_DEFINE(tstack, MAX_NUM_THREADS, STACK_SIZE);
21 #endif
22
23 #define WAIT_US 1000
24 #define WAIT_NS (WAIT_US * 1000)
25 #define TOLERANCE 0.1
26
perform_tests(void)27 static void perform_tests(void)
28 {
29 timing_t start, middle, end;
30 uint64_t diff1, diff2, diff_all, freq_hz;
31 uint64_t diff1_ns, diff2_ns, diff_all_ns, diff_avg_ns;
32 uint32_t freq_mhz;
33
34 arch_timing_start();
35
36 start = arch_timing_counter_get();
37 k_busy_wait(WAIT_US);
38 middle = arch_timing_counter_get();
39 k_busy_wait(WAIT_US);
40 end = arch_timing_counter_get();
41
42 /* Time shouldn't stop or go backwards */
43 diff1 = arch_timing_cycles_get(&start, &middle);
44 diff2 = arch_timing_cycles_get(&middle, &end);
45 diff_all = arch_timing_cycles_get(&start, &end);
46 zassert_true(diff1 > 0, NULL);
47 zassert_true(diff2 > 0, NULL);
48 zassert_true(diff_all > 0, NULL);
49
50 /* Differences shouldn't be so different, as both are spaced by
51 * k_busy_wait(WAIT_US).
52 */
53 zassert_within(diff1, diff2, diff1 * TOLERANCE, NULL);
54 zassert_within(diff_all, diff1 + diff2, (diff1 + diff2) * TOLERANCE,
55 NULL);
56
57 freq_hz = arch_timing_freq_get();
58 freq_mhz = arch_timing_freq_get_mhz();
59 zassert_equal(freq_mhz, (uint32_t)(freq_hz / 1000000ULL), NULL);
60
61 diff1_ns = arch_timing_cycles_to_ns(diff1);
62 diff2_ns = arch_timing_cycles_to_ns(diff2);
63 diff_all_ns = arch_timing_cycles_to_ns(diff_all);
64
65 /* Ensure the differences are close to 100us */
66 zassert_within(diff1_ns, WAIT_NS, WAIT_NS * TOLERANCE, NULL);
67 zassert_within(diff2_ns, WAIT_NS, WAIT_NS * TOLERANCE, NULL);
68 zassert_within(diff_all_ns, 2 * WAIT_NS, 2 * WAIT_NS * TOLERANCE, NULL);
69
70 diff_avg_ns = arch_timing_cycles_to_ns_avg(diff1 + diff2, 2);
71 zassert_within(diff_avg_ns, WAIT_NS, WAIT_NS * TOLERANCE, NULL);
72
73 arch_timing_stop();
74 }
75
timing_setup(void)76 void *timing_setup(void)
77 {
78 arch_timing_init();
79
80 return NULL;
81 }
82
ZTEST(arch_timing,test_arch_timing)83 ZTEST(arch_timing, test_arch_timing)
84 {
85 perform_tests();
86 /* Run tests again to ensure nothing breaks after arch_timing_stop */
87 perform_tests();
88 }
89
90 #ifdef SMP_TEST
thread_entry(void * p1,void * p2,void * p3)91 static void thread_entry(void *p1, void *p2, void *p3)
92 {
93 ARG_UNUSED(p1);
94 ARG_UNUSED(p2);
95 ARG_UNUSED(p3);
96
97 perform_tests();
98 /* Run tests again to ensure nothing breaks after arch_timing_stop */
99 perform_tests();
100 }
101
ZTEST(arch_timing,test_arch_timing_smp)102 ZTEST(arch_timing, test_arch_timing_smp)
103 {
104 int i;
105 unsigned int num_threads = arch_num_cpus();
106
107 for (i = 0; i < num_threads; i++) {
108 k_thread_create(&threads[i], tstack[i], STACK_SIZE,
109 thread_entry, NULL, NULL, NULL,
110 PRIORITY, 0, K_FOREVER);
111 k_thread_cpu_mask_enable(&threads[i], i);
112 k_thread_start(&threads[i]);
113 }
114
115 for (i = 0; i < num_threads; i++)
116 k_thread_join(&threads[i], K_FOREVER);
117 }
118 #else
ZTEST(arch_timing,test_arch_timing_smp)119 ZTEST(arch_timing, test_arch_timing_smp)
120 {
121 ztest_test_skip();
122 }
123 #endif
124
125 ZTEST_SUITE(arch_timing, NULL, timing_setup, NULL, NULL, NULL);
126