blob: 83ff500a11436c2517b74dc4ffa95474260cbc2d [file] [log] [blame]
/*
* Copyright (c) 2022 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/kernel.h>
#include <zephyr/arch/arch_interface.h>
#if defined(CONFIG_SMP) && CONFIG_MP_MAX_NUM_CPUS > 1
#define SMP_TEST
#endif
#ifdef SMP_TEST
#define MAX_NUM_THREADS CONFIG_MP_MAX_NUM_CPUS
#define STACK_SIZE 1024
#define PRIORITY 7
static struct k_thread threads[MAX_NUM_THREADS];
static K_THREAD_STACK_ARRAY_DEFINE(tstack, MAX_NUM_THREADS, 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;
unsigned int num_threads = arch_num_cpus();
for (i = 0; i < num_threads; 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 < num_threads; 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);