Linux Audio

Check our new training course

Embedded Linux Audio

Check our new training course
with Creative Commons CC-BY-SA
lecture materials

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * Copyright (c) 2017 Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <kernel.h>
#include <zephyr.h>
#include <tc_util.h>
#include <ksched.h>
#include "timing_info.h"


extern char sline[];

K_SEM_DEFINE(sem_bench, 0, 1);
K_SEM_DEFINE(sem_bench_1, 0, 1);

/* To time thread creation*/
extern K_THREAD_STACK_DEFINE(my_stack_area, STACK_SIZE);
extern K_THREAD_STACK_DEFINE(my_stack_area_0, STACK_SIZE);
extern struct k_thread my_thread;
extern struct k_thread my_thread_0;

/* u64_t thread_yield_start_time[1000]; */
/* u64_t thread_yield_end_time[1000]; */
extern u64_t thread_start_time;
extern u64_t thread_end_time;
u64_t sem_start_time;
u64_t sem_end_time;
u64_t sem_give_start_time;
u64_t sem_give_end_time;

u32_t swap_called;
u64_t test_time2;
u64_t test_time1;

void thread_sem0_test(void *p1, void *p2, void *p3);
void thread_sem1_test(void *p1, void *p2, void *p3);
void thread_sem0_give_test(void *p1, void *p2, void *p3);
void thread_sem1_give_test(void *p1, void *p2, void *p3);

k_tid_t sem0_tid;
k_tid_t sem1_tid;

extern u64_t arch_timing_value_swap_common;
extern u32_t arch_timing_value_swap_end;

void semaphore_bench(void)
{

	/* Thread yield*/

	sem0_tid = k_thread_create(&my_thread, my_stack_area,
				   STACK_SIZE,
				   thread_sem0_test, NULL, NULL, NULL,
				   2 /*priority*/, 0, K_NO_WAIT);
	sem1_tid = k_thread_create(&my_thread_0, my_stack_area_0,
				   STACK_SIZE, thread_sem1_test,
				   NULL, NULL, NULL,
				   2 /*priority*/, 0, K_NO_WAIT);

	k_sleep(K_MSEC(1000));


	/* u64_t test_time1 = z_tsc_read(); */
	sem_end_time = (arch_timing_value_swap_common);
	u32_t sem_cycles = sem_end_time - sem_start_time;

	sem0_tid = k_thread_create(&my_thread, my_stack_area,
				   STACK_SIZE, thread_sem0_give_test,
				   NULL, NULL, NULL,
				   2 /*priority*/, 0, K_NO_WAIT);
	sem1_tid = k_thread_create(&my_thread_0, my_stack_area_0,
				   STACK_SIZE, thread_sem1_give_test,
				   NULL, NULL, NULL,
				   2 /*priority*/, 0, K_NO_WAIT);

	k_sleep(K_MSEC(1000));
	sem_give_end_time = (arch_timing_value_swap_common);
	u32_t sem_give_cycles = sem_give_end_time - sem_give_start_time;


	/* Semaphore without context switch*/
	TIMING_INFO_PRE_READ();
	u32_t sem_give_wo_cxt_start = TIMING_INFO_OS_GET_TIME();

	k_sem_give(&sem_bench);

	TIMING_INFO_PRE_READ();
	u32_t sem_give_wo_cxt_end = TIMING_INFO_OS_GET_TIME();
	u32_t sem_give_wo_cxt_cycles = sem_give_wo_cxt_end -
					  sem_give_wo_cxt_start;

	TIMING_INFO_PRE_READ();
	u32_t sem_take_wo_cxt_start = TIMING_INFO_OS_GET_TIME();

	k_sem_take(&sem_bench, K_MSEC(10));
	TIMING_INFO_PRE_READ();
	u32_t sem_take_wo_cxt_end = TIMING_INFO_OS_GET_TIME();
	u32_t sem_take_wo_cxt_cycles = sem_take_wo_cxt_end -
					  sem_take_wo_cxt_start;

	/* TC_PRINT("test_time1 , %d cycles\n", (u32_t)test_time1); */
	/* TC_PRINT("test_time2 , %d cycles\n", (u32_t)test_time2); */

	PRINT_STATS("Semaphore Take with context switch",
		sem_cycles, CYCLES_TO_NS(sem_cycles));
	PRINT_STATS("Semaphore Give with context switch",
		sem_give_cycles, CYCLES_TO_NS(sem_give_cycles));

	PRINT_STATS("Semaphore Take without context switch",
		sem_take_wo_cxt_cycles,
		CYCLES_TO_NS(sem_take_wo_cxt_cycles));
	PRINT_STATS("Semaphore Give without context switch",
		sem_give_wo_cxt_cycles,
		CYCLES_TO_NS(sem_give_wo_cxt_cycles));

}
/******************************************************************************/
K_MUTEX_DEFINE(mutex0);
void mutex_bench(void)
{
	u32_t mutex_lock_start_time;
	u32_t mutex_lock_end_time;
	u32_t mutex_lock_diff = 0U;

	u32_t mutex_unlock_start_time;
	u32_t mutex_unlock_end_time;
	u32_t mutex_unlock_diff = 0U;
	u32_t count = 0U;

	for (int i = 0; i < 1000; i++) {
		s64_t before = k_uptime_get();

		TIMING_INFO_PRE_READ();
		mutex_lock_start_time = TIMING_INFO_OS_GET_TIME();

		k_mutex_lock(&mutex0, K_MSEC(100));

		TIMING_INFO_PRE_READ();
		mutex_lock_end_time = TIMING_INFO_OS_GET_TIME();

		TIMING_INFO_PRE_READ();
		mutex_unlock_start_time = TIMING_INFO_OS_GET_TIME();

		k_mutex_unlock(&mutex0);

		TIMING_INFO_PRE_READ();
		mutex_unlock_end_time = TIMING_INFO_OS_GET_TIME();

		/* If timer interrupt occurs we need to omit that sample*/
		s64_t after = k_uptime_get();

		if (after - before) {
			continue;
		}

		count++;

		mutex_lock_diff += (mutex_lock_end_time -
					mutex_lock_start_time);
		mutex_unlock_diff += (mutex_unlock_end_time -
				      mutex_unlock_start_time);
	}

	PRINT_STATS("Mutex lock", mutex_lock_diff / count,
		CYCLES_TO_NS(mutex_lock_diff / count));

	PRINT_STATS("Mutex unlock", mutex_unlock_diff / count,
		CYCLES_TO_NS(mutex_unlock_diff / count));
}

/******************************************************************************/
void thread_sem1_test(void *p1, void *p2, void *p3)
{

	k_sem_give(&sem_bench); /* sync the 2 threads*/

	arch_timing_value_swap_end = 1U;
	TIMING_INFO_PRE_READ();
	sem_start_time =  TIMING_INFO_OS_GET_TIME();
	k_sem_take(&sem_bench, K_MSEC(10));
}

u32_t sem_count;
void thread_sem0_test(void *p1, void *p2, void *p3)
{
	k_sem_take(&sem_bench, K_MSEC(10));/* To sync threads */

	k_sem_give(&sem_bench);
	sem_count++;
	k_thread_abort(sem0_tid);
}
/******************************************************************************/
void thread_sem1_give_test(void *p1, void *p2, void *p3)
{
	k_sem_give(&sem_bench);         /* sync the 2 threads*/

	k_sem_take(&sem_bench_1, K_MSEC(1000)); /* clear the previous sem_give*/
}

void thread_sem0_give_test(void *p1, void *p2, void *p3)
{
	k_sem_take(&sem_bench, K_MSEC(10));/* To sync threads */

	/* To make sure that the sem give will cause a swap to occur */
	k_thread_priority_set(sem1_tid, 1);

	arch_timing_value_swap_end = 1U;
	TIMING_INFO_PRE_READ();
	sem_give_start_time =  TIMING_INFO_OS_GET_TIME();
	k_sem_give(&sem_bench_1);

}