Boot Linux faster!

Check our new training course

Boot Linux faster!

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

Bootlin logo

Elixir Cross Referencer

/* timestamp.h - macroses for measuring time in benchmarking tests */

/*
 * Copyright (c) 2012-2015 Wind River Systems, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * DESCRIPTION
 * This file contains the macroses for taking and converting time for
 * benchmarking tests.
 */

#ifndef _TIMESTAMP_H_
#define _TIMESTAMP_H_
#include <zephyr.h>

#include <limits.h>
#if defined(__GNUC__)
#include <test_asm_inline_gcc.h>
#else
#include <test_asm_inline_other.h>
#endif

#if defined(CONFIG_NANOKERNEL)
/* number of ticks before timer overflows */
#define BENCH_MAX_TICKS (sys_clock_ticks_per_sec - 1)

typedef int64_t TICK_TYPE;

static inline void TICK_SYNCH(void)
{
	TICK_TYPE  reftime;

	(void) sys_tick_delta(&reftime);
	while (sys_tick_delta(&reftime) == 0) {
	}
}

#elif (defined(CONFIG_MICROKERNEL) && defined(KERNEL))
typedef int64_t TICK_TYPE;

#define TICK_SYNCH() task_sleep(1)

#else
#error either  CONFIG_NANOKERNEL or CONFIG_MICROKERNEL must be defined
#endif /*  CONFIG_NANOKERNEL */

#define TICK_GET(x) ((TICK_TYPE) sys_tick_delta(x))
#define OS_GET_TIME() sys_cycle_get_32()

/* time necessary to read the time */
extern uint32_t tm_off;

static inline uint32_t TIME_STAMP_DELTA_GET(uint32_t ts)
{
	uint32_t t;

	/* serialize so OS_GET_TIME() is not reordered */
	timestamp_serialize();

	t = OS_GET_TIME();
	uint32_t res = (t >= ts)? (t - ts): (ULONG_MAX - ts + t);
	if (ts > 0) {
		res -= tm_off;
	}
	return res;
}

/*
 * Routine initializes the benchmark timing measurement
 * The function sets up the global variable tm_off
 */
static inline void bench_test_init(void)
{
	uint32_t t = OS_GET_TIME();

	tm_off = OS_GET_TIME() - t;
}

#if defined(CONFIG_MICROKERNEL) && defined(KERNEL)

/* number of ticks before timer overflows */
#define BENCH_MAX_TICKS (sys_clock_ticks_per_sec - 1)

#endif /* CONFIG_MICROKERNEL */

#if (defined(CONFIG_NANOKERNEL) || defined(CONFIG_MICROKERNEL))  && defined(KERNEL)
/* tickstamp used for timer counter overflow check */
static TICK_TYPE tCheck;

/*
 * Routines are invoked before and after the benchmark and check
 * if penchmarking code took less time than necessary for the
 * high precision timer register overflow.
 * Functions modify the tCheck global variable.
 */
static inline void bench_test_start(void)
{
	tCheck = 0;
	/* before reading time we synchronize to the start of the timer tick */
	TICK_SYNCH();
	tCheck = TICK_GET(&tCheck);
}


/* returns 0 if the number of ticks is valid and -1 if not */
static inline int bench_test_end(void)
{
	tCheck = TICK_GET(&tCheck);
	if (tCheck > BENCH_MAX_TICKS) {
		return -1;
	}
	return 0;
}

/*
 * Returns -1 if number of ticks cause high precision timer counter
 * overflow and 0 otherwise
 * Called after bench_test_end to see if we still can use timing
 * results or is it completely invalid
 */
static inline int high_timer_overflow(void)
{
	if (tCheck >= (UINT_MAX / sys_clock_hw_cycles_per_tick)) {
		return -1;
	}
	return 0;
}
#endif /*  CONFIG_NANOKERNEL || CONFIG_MICROKERNEL */

#endif /* _TIMESTAMP_H_ */