1 /*
2  * Copyright (c) 2020 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_TIMING_TIMING_H_
8 #define ZEPHYR_INCLUDE_TIMING_TIMING_H_
9 
10 #include <zephyr/arch/arch_interface.h>
11 #include <zephyr/timing/types.h>
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 /**
18  * @brief Timing Measurement APIs
19  * @defgroup timing_api Timing Measurement APIs
20  * @ingroup os_services
21  *
22  * The timing measurement APIs can be used to obtain execution
23  * time of a section of code to aid in analysis and optimization.
24  *
25  * Please note that the timing functions may use a different timer
26  * than the default kernel timer, where the timer being used is
27  * specified by architecture, SoC or board configuration.
28  */
29 
30 /**
31  * @brief SoC specific Timing Measurement APIs
32  * @defgroup timing_api_soc SoC specific Timing Measurement APIs
33  * @ingroup timing_api
34  *
35  * Implements the necessary bits to support timing measurement
36  * using SoC specific timing measurement mechanism.
37  *
38  * @{
39  */
40 
41 /**
42  * @brief Initialize the timing subsystem on SoC.
43  *
44  * Perform the necessary steps to initialize the timing subsystem.
45  *
46  * @see timing_init()
47  */
48 void soc_timing_init(void);
49 
50 /**
51  * @brief Signal the start of the timing information gathering.
52  *
53  * Signal to the timing subsystem that timing information
54  * will be gathered from this point forward.
55  *
56  * @see timing_start()
57  */
58 void soc_timing_start(void);
59 
60 /**
61  * @brief Signal the end of the timing information gathering.
62  *
63  * Signal to the timing subsystem that timing information
64  * is no longer being gathered from this point forward.
65  *
66  * @see timing_stop()
67  */
68 void soc_timing_stop(void);
69 
70 /**
71  * @brief Return timing counter.
72  *
73  * @note Not all SoCs have timing counters with 64 bit precision.  It
74  * is possible to see this value "go backwards" due to internal
75  * rollover.  Timing code must be prepared to address the rollover
76  * (with SoC dependent code, e.g. by casting to a uint32_t before
77  * subtraction) or by using soc_timing_cycles_get() which is required
78  * to understand the distinction.
79  *
80  * @return Timing counter.
81  *
82  * @see timing_counter_get()
83  */
84 timing_t soc_timing_counter_get(void);
85 
86 /**
87  * @brief Get number of cycles between @p start and @p end.
88  *
89  * @note The raw numbers from counter need to be scaled to
90  * obtain actual number of cycles, or may roll over internally.
91  * This function computes a positive-definite interval between two
92  * returned cycle values.
93  *
94  * @param start Pointer to counter at start of a measured execution.
95  * @param end Pointer to counter at stop of a measured execution.
96  * @return Number of cycles between start and end.
97  *
98  * @see timing_cycles_get()
99  */
100 uint64_t soc_timing_cycles_get(volatile timing_t *const start,
101 			       volatile timing_t *const end);
102 
103 /**
104  * @brief Get frequency of counter used (in Hz).
105  *
106  * @return Frequency of counter used for timing in Hz.
107  *
108  * @see timing_freq_get()
109  */
110 uint64_t soc_timing_freq_get(void);
111 
112 /**
113  * @brief Convert number of @p cycles into nanoseconds.
114  *
115  * @param cycles Number of cycles
116  * @return Converted time value
117  *
118  * @see timing_cycles_to_ns()
119  */
120 uint64_t soc_timing_cycles_to_ns(uint64_t cycles);
121 
122 /**
123  * @brief Convert number of @p cycles into nanoseconds with averaging.
124  *
125  * @param cycles Number of cycles
126  * @param count Times of accumulated cycles to average over
127  * @return Converted time value
128  *
129  * @see timing_cycles_to_ns_avg()
130  */
131 uint64_t soc_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count);
132 
133 /**
134  * @brief Get frequency of counter used (in MHz).
135  *
136  * @return Frequency of counter used for timing in MHz.
137  *
138  * @see timing_freq_get_mhz()
139  */
140 uint32_t soc_timing_freq_get_mhz(void);
141 
142 /**
143  * @}
144  */
145 
146 /**
147  * @brief Board specific Timing Measurement APIs
148  * @defgroup timing_api_board Board specific Timing Measurement APIs
149  * @ingroup timing_api
150  *
151  * Implements the necessary bits to support timing measurement
152  * using board specific timing measurement mechanism.
153  *
154  * @{
155  */
156 
157 /**
158  * @brief Initialize the timing subsystem.
159  *
160  * Perform the necessary steps to initialize the timing subsystem.
161  *
162  * @see timing_init()
163  */
164 void board_timing_init(void);
165 
166 /**
167  * @brief Signal the start of the timing information gathering.
168  *
169  * Signal to the timing subsystem that timing information
170  * will be gathered from this point forward.
171  *
172  * @see timing_start()
173  */
174 void board_timing_start(void);
175 
176 /**
177  * @brief Signal the end of the timing information gathering.
178  *
179  * Signal to the timing subsystem that timing information
180  * is no longer being gathered from this point forward.
181  *
182  * @see timing_stop()
183  */
184 void board_timing_stop(void);
185 
186 /**
187  * @brief Return timing counter.
188  *
189  * @note Not all timing counters have 64 bit precision.  It is
190  * possible to see this value "go backwards" due to internal
191  * rollover.  Timing code must be prepared to address the rollover
192  * (with board dependent code, e.g. by casting to a uint32_t before
193  * subtraction) or by using board_timing_cycles_get() which is required
194  * to understand the distinction.
195  *
196  * @return Timing counter.
197  *
198  * @see timing_counter_get()
199  */
200 timing_t board_timing_counter_get(void);
201 
202 /**
203  * @brief Get number of cycles between @p start and @p end.
204  *
205  * @note The raw numbers from counter need to be scaled to
206  * obtain actual number of cycles, or may roll over internally.
207  * This function computes a positive-definite interval between two
208  * returned cycle values.
209  *
210  * @param start Pointer to counter at start of a measured execution.
211  * @param end Pointer to counter at stop of a measured execution.
212  * @return Number of cycles between start and end.
213  *
214  * @see timing_cycles_get()
215  */
216 uint64_t board_timing_cycles_get(volatile timing_t *const start,
217 				 volatile timing_t *const end);
218 
219 /**
220  * @brief Get frequency of counter used (in Hz).
221  *
222  * @return Frequency of counter used for timing in Hz.
223  *
224  * @see timing_freq_get()
225  */
226 uint64_t board_timing_freq_get(void);
227 
228 /**
229  * @brief Convert number of @p cycles into nanoseconds.
230  *
231  * @param cycles Number of cycles
232  * @return Converted time value
233  *
234  * @see timing_cycles_to_ns()
235  */
236 uint64_t board_timing_cycles_to_ns(uint64_t cycles);
237 
238 /**
239  * @brief Convert number of @p cycles into nanoseconds with averaging.
240  *
241  * @param cycles Number of cycles
242  * @param count Times of accumulated cycles to average over
243  * @return Converted time value
244  *
245  * @see timing_cycles_to_ns_avg()
246  */
247 uint64_t board_timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count);
248 
249 /**
250  * @brief Get frequency of counter used (in MHz).
251  *
252  * @return Frequency of counter used for timing in MHz.
253  *
254  * @see timing_freq_get_mhz()
255  */
256 uint32_t board_timing_freq_get_mhz(void);
257 
258 /**
259  * @}
260  */
261 
262 /**
263  * @addtogroup timing_api
264  * @{
265  */
266 
267 #ifdef CONFIG_TIMING_FUNCTIONS
268 
269 /**
270  * @brief Initialize the timing subsystem.
271  *
272  * Perform the necessary steps to initialize the timing subsystem.
273  */
274 void timing_init(void);
275 
276 /**
277  * @brief Signal the start of the timing information gathering.
278  *
279  * Signal to the timing subsystem that timing information
280  * will be gathered from this point forward.
281  */
282 void timing_start(void);
283 
284 /**
285  * @brief Signal the end of the timing information gathering.
286  *
287  * Signal to the timing subsystem that timing information
288  * is no longer being gathered from this point forward.
289  */
290 void timing_stop(void);
291 
292 /**
293  * @brief Return timing counter.
294  *
295  * @return Timing counter.
296  */
timing_counter_get(void)297 static inline timing_t timing_counter_get(void)
298 {
299 #if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
300 	return board_timing_counter_get();
301 #elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
302 	return soc_timing_counter_get();
303 #else
304 	return arch_timing_counter_get();
305 #endif
306 }
307 
308 /**
309  * @brief Get number of cycles between @p start and @p end.
310  *
311  * For some architectures or SoCs, the raw numbers from counter
312  * need to be scaled to obtain actual number of cycles.
313  *
314  * @param start Pointer to counter at start of a measured execution.
315  * @param end Pointer to counter at stop of a measured execution.
316  * @return Number of cycles between start and end.
317  */
timing_cycles_get(volatile timing_t * const start,volatile timing_t * const end)318 static inline uint64_t timing_cycles_get(volatile timing_t *const start,
319 					 volatile timing_t *const end)
320 {
321 #if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
322 	return board_timing_cycles_get(start, end);
323 #elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
324 	return soc_timing_cycles_get(start, end);
325 #else
326 	return arch_timing_cycles_get(start, end);
327 #endif
328 }
329 
330 /**
331  * @brief Get frequency of counter used (in Hz).
332  *
333  * @return Frequency of counter used for timing in Hz.
334  */
timing_freq_get(void)335 static inline uint64_t timing_freq_get(void)
336 {
337 #if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
338 	return board_timing_freq_get();
339 #elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
340 	return soc_timing_freq_get();
341 #else
342 	return arch_timing_freq_get();
343 #endif
344 }
345 
346 /**
347  * @brief Convert number of @p cycles into nanoseconds.
348  *
349  * @param cycles Number of cycles
350  * @return Converted time value
351  */
timing_cycles_to_ns(uint64_t cycles)352 static inline uint64_t timing_cycles_to_ns(uint64_t cycles)
353 {
354 #if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
355 	return board_timing_cycles_to_ns(cycles);
356 #elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
357 	return soc_timing_cycles_to_ns(cycles);
358 #else
359 	return arch_timing_cycles_to_ns(cycles);
360 #endif
361 }
362 
363 /**
364  * @brief Convert number of @p cycles into nanoseconds with averaging.
365  *
366  * @param cycles Number of cycles
367  * @param count Times of accumulated cycles to average over
368  * @return Converted time value
369  */
timing_cycles_to_ns_avg(uint64_t cycles,uint32_t count)370 static inline uint64_t timing_cycles_to_ns_avg(uint64_t cycles, uint32_t count)
371 {
372 #if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
373 	return board_timing_cycles_to_ns_avg(cycles, count);
374 #elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
375 	return soc_timing_cycles_to_ns_avg(cycles, count);
376 #else
377 	return arch_timing_cycles_to_ns_avg(cycles, count);
378 #endif
379 }
380 
381 /**
382  * @brief Get frequency of counter used (in MHz).
383  *
384  * @return Frequency of counter used for timing in MHz.
385  */
timing_freq_get_mhz(void)386 static inline uint32_t timing_freq_get_mhz(void)
387 {
388 #if defined(CONFIG_BOARD_HAS_TIMING_FUNCTIONS)
389 	return board_timing_freq_get_mhz();
390 #elif defined(CONFIG_SOC_HAS_TIMING_FUNCTIONS)
391 	return soc_timing_freq_get_mhz();
392 #else
393 	return arch_timing_freq_get_mhz();
394 #endif
395 }
396 
397 #endif /* CONFIG_TIMING_FUNCTIONS */
398 
399 /**
400  * @}
401  */
402 
403 #ifdef __cplusplus
404 }
405 #endif
406 
407 #endif /* ZEPHYR_INCLUDE_TIMING_TIMING_H_ */
408