tests: arch: add a test case for testing arch_nop() interface

Add a test case to test arch interface arch_nop(), the main focus here
is for coverage of the code. arch_nop() is a special implementation
and it will behave differently on different platforms. By the way, this
also measures how many cycles it spends for platforms that support it.

Signed-off-by: Enjia Mai <enjiax.mai@intel.com>
This commit is contained in:
Enjia Mai 2021-03-01 02:20:35 +08:00 committed by Anas Nashif
parent 4d994af032
commit e92ca60b4e
2 changed files with 110 additions and 1 deletions

View file

@ -60,3 +60,110 @@ void test_irq_offload(void)
zassert_equal(sentinel, SENTINEL_VALUE,
"irq_offload() didn't work properly");
}
/**
* @brief Test the arch_nop() by invoking and measure it.
*
* @details This test is mainly for coverage of the code. arch_nop()
* is a special implementation and it will behave differently on
* different platforms. By the way, this also measures how many
* cycles it spends for platforms that support it.
*
* FYI: The potential uses of arch_nop() could be:
* - Code alignment: Although in this case it's much more likely the
* compiler doing so (or you're in an assembly file, in which case
* you're not calling arch_nop() anyway). And this would require
* that arch_nop() be ALWAYS_INLINE.
* - Giving you a guaranteed place to put a breakpoint / trace trigger
* / etc. when debugging. This is on main usage of arch_nop(); it
* inherently is generally debugging code removed before actually
* pushing.
* - Giving you a guaranteed place to put a patchpoint. E.g. ARMv7
* allows nop (and a few other instructions) to be modified
* concurrently with execution, but not most other instructions.
* - Delaying a few instructions, e.g. for tight timing loops on
* M-cores.
*
* Our test here mainly aims at the 4th scenario mentioned above but
* also potentially tests the 1st scenario. So no optimization here to
* prevent arch_nop() has optimized by the compiler is necessary.
*
* @ingroup kernel_common_tests
*
* @see arch_nop()
*/
__no_optimization void test_nop(void)
{
uint32_t t_get_time, t_before, t_after, diff;
t_before = k_cycle_get_32();
t_after = k_cycle_get_32();
/* calculate time spent between two k_cycle_get_32() call */
t_get_time = t_after - t_before;
printk("time k_cycle_get_32() takes %d cycles\n", t_get_time);
/*
* If two k_cycle_get_32() call take zero cycle here, this
* means it cannot comes out a correct result, in these
* case, we skip this test, such as native posix.
*/
if (t_get_time == 0) {
ztest_test_skip();
}
t_before = k_cycle_get_32();
arch_nop();
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
/* do 4 nop instructions to cost cycles */
arch_nop();
arch_nop();
arch_nop();
#elif defined(CONFIG_ARC)
/* do 8 nop instructions to cost cycles */
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
#elif defined(CONFIG_SPARC)
/* do 9 nop instructions to cost cycles */
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
arch_nop();
#elif defined(CONFIG_ARMV8_A)
/* the ARMv8-A ARM states the following:
* No Operation does nothing, other than advance the value of
* the program counter by 4. This instruction can be used for
* instruction alignment purposes.
* Note: The timing effects of including a NOP instruction in
* a program are not guaranteed. It can increase execution time
* ,leave it unchanged, or even reduce it. Therefore, NOP
* instructions are not suitable for timing loops.
*
* So we skip the this test, it will get a negative cycles.
*/
ztest_test_skip();
#endif
t_after = k_cycle_get_32();
/* Calculate delta time of arch_nop(). */
diff = t_after - t_before - t_get_time;
printk("arch_nop() takes %d cycles\n", diff);
/* An arch_nop() call should spend actual cpu cycles */
zassert_true(diff > 0,
"arch_nop() takes %d cpu cycles", diff);
}

View file

@ -48,6 +48,7 @@ extern void test_bitarray_declare(void);
extern void test_bitarray_set_clear(void);
extern void test_bitarray_alloc_free(void);
extern void test_bitarray_region_set_clear(void);
extern void test_nop(void);
/**
* @defgroup kernel_common_tests Common Tests
@ -160,7 +161,8 @@ void test_main(void)
ztest_unit_test(test_thread_context),
ztest_user_unit_test(test_errno),
ztest_unit_test(test_ms_time_duration),
ztest_unit_test(test_bounds_check_mitigation)
ztest_unit_test(test_bounds_check_mitigation),
ztest_unit_test(test_nop)
);
ztest_run_test_suite(common);