| /* |
| * Copyright (c) 2022 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <zephyr/ztest.h> |
| #include <zephyr/kernel.h> |
| #include <zephyr/sys/arch_interface.h> |
| |
| #if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 1 |
| #define SMP_TEST |
| #endif |
| |
| #ifdef SMP_TEST |
| #define THREADS_NUM CONFIG_MP_NUM_CPUS |
| #define STACK_SIZE 1024 |
| #define PRIORITY 7 |
| |
| static struct k_thread threads[THREADS_NUM]; |
| static K_THREAD_STACK_ARRAY_DEFINE(tstack, THREADS_NUM, STACK_SIZE); |
| #endif |
| |
| #define WAIT_US 1000 |
| #define WAIT_NS (WAIT_US * 1000) |
| #define TOLERANCE 0.1 |
| |
| static void perform_tests(void) |
| { |
| timing_t start, middle, end; |
| uint64_t diff1, diff2, diff_all, freq_hz; |
| uint64_t diff1_ns, diff2_ns, diff_all_ns, diff_avg_ns; |
| uint32_t freq_mhz; |
| |
| arch_timing_start(); |
| |
| start = arch_timing_counter_get(); |
| k_busy_wait(WAIT_US); |
| middle = arch_timing_counter_get(); |
| k_busy_wait(WAIT_US); |
| end = arch_timing_counter_get(); |
| |
| /* Time shouldn't stop or go backwards */ |
| diff1 = arch_timing_cycles_get(&start, &middle); |
| diff2 = arch_timing_cycles_get(&middle, &end); |
| diff_all = arch_timing_cycles_get(&start, &end); |
| zassert_true(diff1 > 0, NULL); |
| zassert_true(diff2 > 0, NULL); |
| zassert_true(diff_all > 0, NULL); |
| |
| /* Differences shouldn't be so different, as both are spaced by |
| * k_busy_wait(WAIT_US). |
| */ |
| zassert_within(diff1, diff2, diff1 * TOLERANCE, NULL); |
| zassert_within(diff_all, diff1 + diff2, (diff1 + diff2) * TOLERANCE, |
| NULL); |
| |
| freq_hz = arch_timing_freq_get(); |
| freq_mhz = arch_timing_freq_get_mhz(); |
| zassert_equal(freq_mhz, (uint32_t)(freq_hz / 1000000ULL), NULL); |
| |
| diff1_ns = arch_timing_cycles_to_ns(diff1); |
| diff2_ns = arch_timing_cycles_to_ns(diff2); |
| diff_all_ns = arch_timing_cycles_to_ns(diff_all); |
| |
| /* Ensure the differences are close to 100us */ |
| zassert_within(diff1_ns, WAIT_NS, WAIT_NS * TOLERANCE, NULL); |
| zassert_within(diff2_ns, WAIT_NS, WAIT_NS * TOLERANCE, NULL); |
| zassert_within(diff_all_ns, 2 * WAIT_NS, 2 * WAIT_NS * TOLERANCE, NULL); |
| |
| diff_avg_ns = arch_timing_cycles_to_ns_avg(diff1 + diff2, 2); |
| zassert_within(diff_avg_ns, WAIT_NS, WAIT_NS * TOLERANCE, NULL); |
| |
| arch_timing_stop(); |
| } |
| |
| void *timing_setup(void) |
| { |
| arch_timing_init(); |
| |
| return NULL; |
| } |
| |
| ZTEST(arch_timing, test_arch_timing) |
| { |
| perform_tests(); |
| /* Run tests again to ensure nothing breaks after arch_timing_stop */ |
| perform_tests(); |
| } |
| |
| #ifdef SMP_TEST |
| static void thread_entry(void *p1, void *p2, void *p3) |
| { |
| ARG_UNUSED(p1); |
| ARG_UNUSED(p2); |
| ARG_UNUSED(p3); |
| |
| perform_tests(); |
| /* Run tests again to ensure nothing breaks after arch_timing_stop */ |
| perform_tests(); |
| } |
| |
| ZTEST(arch_timing, test_arch_timing_smp) |
| { |
| int i; |
| |
| for (i = 0; i < THREADS_NUM; i++) { |
| k_thread_create(&threads[i], tstack[i], STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| PRIORITY, 0, K_FOREVER); |
| k_thread_cpu_mask_enable(&threads[i], i); |
| k_thread_start(&threads[i]); |
| } |
| |
| for (i = 0; i < THREADS_NUM; i++) |
| k_thread_join(&threads[i], K_FOREVER); |
| } |
| #else |
| ZTEST(arch_timing, test_arch_timing_smp) |
| { |
| ztest_test_skip(); |
| } |
| #endif |
| |
| ZTEST_SUITE(arch_timing, NULL, timing_setup, NULL, NULL, NULL); |