1 /*
2  * Copyright (c) 2012-2015 Wind River Systems, Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * @file macroses for measuring time in benchmarking tests
9  *
10  * This file contains the macroses for taking and converting time for
11  * benchmarking tests.
12  */
13 
14 #ifndef _TIMESTAMP_H_
15 #define _TIMESTAMP_H_
16 #include <zephyr/kernel.h>
17 
18 #include <limits.h>
19 #if defined(__GNUC__)
20 #include <zephyr/test_asm_inline_gcc.h>
21 #else
22 #include <zephyr/test_asm_inline_other.h>
23 #endif
24 
25 
26 #define TICK_SYNCH()  k_sleep(K_TICKS(1))
27 
28 #define OS_GET_TIME() k_cycle_get_32()
29 
30 /* time necessary to read the time */
31 extern uint32_t tm_off;
32 
TIME_STAMP_DELTA_GET(uint32_t ts)33 static inline uint32_t TIME_STAMP_DELTA_GET(uint32_t ts)
34 {
35 	uint32_t t;
36 
37 	/* serialize so OS_GET_TIME() is not reordered */
38 	timestamp_serialize();
39 
40 	t = OS_GET_TIME();
41 	uint32_t res = (t >= ts) ? (t - ts) : (ULONG_MAX - ts + t);
42 
43 	if (ts > 0) {
44 		res -= tm_off;
45 	}
46 	return res;
47 }
48 
49 /*
50  * Routine initializes the benchmark timing measurement
51  * The function sets up the global variable tm_off
52  */
bench_test_init(void)53 static inline void bench_test_init(void)
54 {
55 	uint32_t t = OS_GET_TIME();
56 
57 	tm_off = OS_GET_TIME() - t;
58 }
59 
60 
61 /* timestamp for checks */
62 static int64_t timestamp_check;
63 
64 /*
65  * Routines are invoked before and after the benchmark and check
66  * if benchmarking code took less time than necessary for the
67  * high precision timer register overflow.
68  * Functions modify the timestamp_check global variable.
69  */
bench_test_start(void)70 static inline void bench_test_start(void)
71 {
72 	timestamp_check = 0;
73 	/* before reading time we synchronize to the start of the timer tick */
74 	TICK_SYNCH();
75 	timestamp_check = k_uptime_delta(&timestamp_check);
76 }
77 
78 
79 /* returns 0 if the completed within a second and -1 if not */
bench_test_end(void)80 static inline int bench_test_end(void)
81 {
82 	timestamp_check = k_uptime_delta(&timestamp_check);
83 
84 	/* Flag an error if the test ran for more than a second.
85 	 * (Note: Existing benchmarks have CONFIG_SYS_CLOCK_TICKS_PER_SEC=1 set,
86 	 * in such configs this check can be an indicator of whether
87 	 * timer tick interrupt overheads too are getting accounted towards
88 	 * benchmark time)
89 	 */
90 	if (timestamp_check >= MSEC_PER_SEC) {
91 		return -1;
92 	}
93 	return 0;
94 }
95 
96 /*
97  * Returns -1 if number of ticks cause high precision timer counter
98  * overflow and 0 otherwise
99  * Called after bench_test_end to see if we still can use timing
100  * results or is it completely invalid
101  */
high_timer_overflow(void)102 static inline int high_timer_overflow(void)
103 {
104 	/* Check if the time elapsed in msec is sufficient to trigger an
105 	 *  overflow of the high precision timer
106 	 */
107 	if (timestamp_check >= (k_cyc_to_ns_floor64(UINT_MAX) /
108 				(NSEC_PER_USEC * USEC_PER_MSEC))) {
109 		return -1;
110 	}
111 	return 0;
112 }
113 
114 #endif /* _TIMESTAMP_H_ */
115