| /* |
| * Copyright (c) 2016 Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /** |
| * @file |
| * @brief Measure time |
| * |
| */ |
| #include <kernel.h> |
| #include <zephyr.h> |
| #include <tc_util.h> |
| #include <ksched.h> |
| #include "timing_info.h" |
| #include <app_memory/app_memdomain.h> |
| |
| K_APPMEM_PARTITION_DEFINE(bench_ptn); |
| struct k_mem_domain bench_domain; |
| |
| extern char sline[256]; |
| extern u64_t __end_drop_to_usermode_time; |
| |
| u32_t drop_to_user_mode_end_time, drop_to_user_mode_start_time; |
| u32_t user_thread_creation_end_time, user_thread_creation_start_time; |
| |
| struct k_thread my_thread_user; |
| K_THREAD_STACK_EXTERN(my_stack_area); |
| K_THREAD_STACK_EXTERN(my_stack_area_0); |
| |
| |
| /******************************************************************************/ |
| /* syscall needed to read timer value when in user space */ |
| u32_t z_impl_userspace_read_timer_value(void) |
| { |
| TIMING_INFO_PRE_READ(); |
| return TIMING_INFO_GET_TIMER_VALUE(); |
| } |
| |
| Z_SYSCALL_HANDLER(userspace_read_timer_value) |
| { |
| TIMING_INFO_PRE_READ(); |
| return TIMING_INFO_GET_TIMER_VALUE(); |
| } |
| |
| /******************************************************************************/ |
| |
| void drop_to_user_mode(void); |
| void user_thread_creation(void); |
| void syscall_overhead(void); |
| void validation_overhead(void); |
| |
| void userspace_bench(void) |
| { |
| struct k_mem_partition *parts[] = { |
| &bench_ptn |
| }; |
| |
| k_mem_domain_init(&bench_domain, ARRAY_SIZE(parts), parts); |
| k_mem_domain_add_thread(&bench_domain, k_current_get()); |
| |
| drop_to_user_mode(); |
| |
| user_thread_creation(); |
| |
| syscall_overhead(); |
| |
| validation_overhead(); |
| } |
| /******************************************************************************/ |
| |
| void test_drop_to_user_mode_1(void *p1, void *p2, void *p3) |
| { |
| volatile u32_t dummy = 100U; |
| |
| dummy++; |
| } |
| |
| void drop_to_user_mode_thread(void *p1, void *p2, void *p3) |
| { |
| TIMING_INFO_PRE_READ(); |
| drop_to_user_mode_start_time = TIMING_INFO_GET_TIMER_VALUE(); |
| k_thread_user_mode_enter(test_drop_to_user_mode_1, NULL, NULL, NULL); |
| } |
| |
| |
| void drop_to_user_mode(void) |
| { |
| #ifdef SysTick |
| /* Reset the counter so that a interrupt doesn't happen inbetween |
| * the benchmark test |
| */ |
| SysTick->VAL = 0; |
| #endif |
| |
| /* Test time to drop to usermode from SU */ |
| |
| k_thread_create(&my_thread_user, my_stack_area_0, STACK_SIZE, |
| drop_to_user_mode_thread, |
| NULL, NULL, NULL, |
| -1 /*priority*/, K_INHERIT_PERMS, 0); |
| |
| k_yield(); |
| |
| drop_to_user_mode_end_time = (u32_t) |
| SUBTRACT_CLOCK_CYCLES(__end_drop_to_usermode_time); |
| |
| u32_t tmp_start_time = |
| SUBTRACT_CLOCK_CYCLES(drop_to_user_mode_start_time); |
| |
| u32_t total_drop_to_user_mode_time = |
| CYCLES_TO_NS((u32_t) |
| ((drop_to_user_mode_end_time - tmp_start_time) & |
| 0xFFFFFFFFULL)); |
| |
| PRINT_STATS("Drop to user mode", |
| (u32_t)((drop_to_user_mode_end_time - tmp_start_time) & |
| 0xFFFFFFFFULL), |
| (u32_t) (total_drop_to_user_mode_time & 0xFFFFFFFFULL)); |
| |
| |
| |
| } |
| |
| /******************************************************************************/ |
| void user_thread_creation(void) |
| { |
| u32_t total_user_thread_creation_time; |
| |
| TIMING_INFO_PRE_READ(); |
| user_thread_creation_start_time = TIMING_INFO_GET_TIMER_VALUE(); |
| |
| k_thread_create(&my_thread_user, my_stack_area, STACK_SIZE, |
| test_drop_to_user_mode_1, |
| NULL, NULL, NULL, |
| 0 /*priority*/, K_INHERIT_PERMS | K_USER, 0); |
| |
| TIMING_INFO_PRE_READ(); |
| user_thread_creation_end_time = TIMING_INFO_GET_TIMER_VALUE(); |
| k_thread_abort(&my_thread_user); |
| |
| u32_t total_cycles = (u32_t) |
| ((SUBTRACT_CLOCK_CYCLES(user_thread_creation_end_time) - |
| SUBTRACT_CLOCK_CYCLES(user_thread_creation_start_time)) & |
| 0xFFFFFFFFULL); |
| |
| total_user_thread_creation_time = CYCLES_TO_NS(total_cycles); |
| |
| PRINT_STATS("User thread Creation", |
| total_cycles, |
| (u32_t) (total_user_thread_creation_time & 0xFFFFFFFFULL)); |
| |
| } |
| |
| /******************************************************************************/ |
| /* dummy syscalls creation */ |
| K_APP_BMEM(bench_ptn) u32_t syscall_overhead_start_time, |
| syscall_overhead_end_time; |
| |
| int z_impl_k_dummy_syscall(void) |
| { |
| return 0; |
| } |
| |
| Z_SYSCALL_HANDLER(k_dummy_syscall) |
| { |
| TIMING_INFO_PRE_READ(); |
| syscall_overhead_end_time = TIMING_INFO_GET_TIMER_VALUE(); |
| return 0; |
| } |
| |
| |
| void syscall_overhead_user_thread(void *p1, void *p2, void *p3) |
| { |
| syscall_overhead_start_time = userspace_read_timer_value(); |
| int val = k_dummy_syscall(); |
| |
| val |= 0xFF; |
| } |
| |
| |
| void syscall_overhead(void) |
| { |
| u32_t total_syscall_overhead_time; |
| |
| k_thread_create(&my_thread_user, my_stack_area_0, STACK_SIZE, |
| syscall_overhead_user_thread, |
| NULL, NULL, NULL, |
| -1 /*priority*/, K_INHERIT_PERMS | K_USER, 0); |
| |
| |
| u32_t total_cycles = (u32_t) |
| ((SUBTRACT_CLOCK_CYCLES(syscall_overhead_end_time) - |
| SUBTRACT_CLOCK_CYCLES(syscall_overhead_start_time)) & |
| 0xFFFFFFFFULL); |
| |
| total_syscall_overhead_time = CYCLES_TO_NS(total_cycles); |
| |
| PRINT_STATS("Syscall overhead", |
| total_cycles, |
| (u32_t) (total_syscall_overhead_time & 0xFFFFFFFFULL)); |
| |
| } |
| |
| /******************************************************************************/ |
| K_SEM_DEFINE(test_sema, 1, 10); |
| u32_t validation_overhead_obj_init_start_time; |
| u32_t validation_overhead_obj_init_end_time; |
| u32_t validation_overhead_obj_start_time; |
| u32_t validation_overhead_obj_end_time; |
| |
| int z_impl_validation_overhead_syscall(void) |
| { |
| return 0; |
| } |
| |
| Z_SYSCALL_HANDLER(validation_overhead_syscall) |
| { |
| TIMING_INFO_PRE_READ(); |
| validation_overhead_obj_init_start_time = TIMING_INFO_GET_TIMER_VALUE(); |
| |
| bool status_0 = Z_SYSCALL_OBJ_INIT(&test_sema, K_OBJ_SEM); |
| |
| TIMING_INFO_PRE_READ(); |
| validation_overhead_obj_init_end_time = TIMING_INFO_GET_TIMER_VALUE(); |
| |
| |
| TIMING_INFO_PRE_READ(); |
| validation_overhead_obj_start_time = TIMING_INFO_GET_TIMER_VALUE(); |
| |
| bool status_1 = Z_SYSCALL_OBJ(&test_sema, K_OBJ_SEM); |
| |
| TIMING_INFO_PRE_READ(); |
| validation_overhead_obj_end_time = TIMING_INFO_GET_TIMER_VALUE(); |
| return status_0 || status_1; |
| } |
| |
| |
| void validation_overhead_user_thread(void *p1, void *p2, void *p3) |
| { |
| /* get validation numbers */ |
| validation_overhead_syscall(); |
| } |
| |
| void validation_overhead(void) |
| { |
| k_thread_access_grant(k_current_get(), &test_sema); |
| |
| |
| k_thread_create(&my_thread_user, my_stack_area, STACK_SIZE, |
| validation_overhead_user_thread, |
| NULL, NULL, NULL, |
| -1 /*priority*/, K_INHERIT_PERMS | K_USER, 0); |
| |
| |
| u32_t total_cycles_obj_init = (u32_t) |
| ((SUBTRACT_CLOCK_CYCLES(validation_overhead_obj_init_end_time) - |
| SUBTRACT_CLOCK_CYCLES(validation_overhead_obj_init_start_time) |
| ) & 0xFFFFFFFFULL); |
| |
| u32_t total_cycles_obj = (u32_t) |
| ((SUBTRACT_CLOCK_CYCLES(validation_overhead_obj_end_time) - |
| SUBTRACT_CLOCK_CYCLES(validation_overhead_obj_start_time)) & |
| 0xFFFFFFFFULL); |
| |
| u32_t total_validation_overhead_obj_init_time = |
| CYCLES_TO_NS(total_cycles_obj_init); |
| |
| u32_t total_validation_overhead_obj_time = |
| CYCLES_TO_NS(total_cycles_obj); |
| |
| PRINT_STATS("Validation overhead k object init", |
| total_cycles_obj_init, |
| (u32_t) (total_validation_overhead_obj_init_time & |
| 0xFFFFFFFFULL)); |
| |
| PRINT_STATS("Validation overhead k object permission", |
| total_cycles_obj, |
| (u32_t) (total_validation_overhead_obj_time & |
| 0xFFFFFFFFULL)); |
| |
| |
| } |