perf_counter v2.1.0
A dedicated performance counter for Cortex-M Systick. It shares the SysTick with users' original SysTick function(s) without interfering with it.
perf_counter.h
1/****************************************************************************
2* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
3* *
4* Licensed under the Apache License, Version 2.0 (the "License"); *
5* you may not use this file except in compliance with the License. *
6* You may obtain a copy of the License at *
7* *
8* http://www.apache.org/licenses/LICENSE-2.0 *
9* *
10* Unless required by applicable law or agreed to in writing, software *
11* distributed under the License is distributed on an "AS IS" BASIS, *
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
13* See the License for the specific language governing permissions and *
14* limitations under the License. *
15* *
16****************************************************************************/
17
18#ifndef __PERFORMANCE_COUNTER_H__
19#define __PERFORMANCE_COUNTER_H__
20
21/*============================ INCLUDES ======================================*/
22#include <stdbool.h>
23#include <stdint.h>
24#include <stddef.h>
25#include "cmsis_compiler.h"
26
27#ifdef __cplusplus
28extern "C" {
29#endif
30/*============================ MACROS ========================================*/
31
36#define __PERF_COUNTER_VER_MAJOR__ 2
37#define __PERF_COUNTER_VER_MINOR__ 1
38#define __PERF_COUNTER_VER_REVISE__ 0
39
40#define __PERF_COUNTER_VER_STR__ ""
41
42#define __PER_COUNTER_VER__ (__PERF_COUNTER_VER_MAJOR__ * 10000ul \
43 +__PERF_COUNTER_VER_MINOR__ * 100ul \
44 +__PERF_COUNTER_VER_REVISE__)
45
46
54// for IAR
55#undef __IS_COMPILER_IAR__
56#if defined(__IAR_SYSTEMS_ICC__)
57# define __IS_COMPILER_IAR__ 1
58#endif
59
60// for arm compiler 5
61#undef __IS_COMPILER_ARM_COMPILER_5__
62#if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
63# define __IS_COMPILER_ARM_COMPILER_5__ 1
64#endif
65
66
67//for arm compiler 6
68
69#undef __IS_COMPILER_ARM_COMPILER_6__
70#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
71# define __IS_COMPILER_ARM_COMPILER_6__ 1
72#endif
73#undef __IS_COMPILER_ARM_COMPILER__
74#if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
75|| defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
76# define __IS_COMPILER_ARM_COMPILER__ 1
77#endif
78
79// for clang
80#undef __IS_COMPILER_LLVM__
81#if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
82# define __IS_COMPILER_LLVM__ 1
83#else
84
85// for gcc
86# undef __IS_COMPILER_GCC__
87# if defined(__GNUC__) && !( defined(__IS_COMPILER_ARM_COMPILER__) \
88 || defined(__IS_COMPILER_LLVM__) \
89 || defined(__IS_COMPILER_IAR__))
90# define __IS_COMPILER_GCC__ 1
91# endif
92
93#endif
94
95
96#ifdef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
97# include __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
98#endif
99
100#if defined(__clang__)
101# pragma clang diagnostic push
102# pragma clang diagnostic ignored "-Wunknown-warning-option"
103# pragma clang diagnostic ignored "-Wreserved-identifier"
104# pragma clang diagnostic ignored "-Wdeclaration-after-statement"
105# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
106# pragma clang diagnostic ignored "-Wgnu-statement-expression"
107# pragma clang diagnostic ignored "-Wunused-but-set-variable"
108# pragma clang diagnostic ignored "-Wshadow"
109# pragma clang diagnostic ignored "-Wshorten-64-to-32"
110# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
111#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
112# pragma diag_suppress 550
113#elif defined(__IS_COMPILER_GCC__)
114# pragma GCC diagnostic push
115# pragma GCC diagnostic ignored "-Wpedantic"
116# pragma GCC diagnostic ignored "-Wunused-variable"
117# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
118# pragma GCC diagnostic ignored "-Wformat="
119#endif
120
121#ifndef __PLOOC_VA_NUM_ARGS_IMPL
122# define __PLOOC_VA_NUM_ARGS_IMPL( _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11, \
123 _12,_13,_14,_15,_16,__N,...) __N
124#endif
125
126#ifndef __PLOOC_VA_NUM_ARGS
127#define __PLOOC_VA_NUM_ARGS(...) \
128 __PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
129 8,7,6,5,4,3,2,1,0)
130#endif
131
132#ifndef UNUSED_PARAM
133# define UNUSED_PARAM(__VAR) (void)(__VAR)
134#endif
135
136#undef __CONNECT2
137#undef __CONNECT3
138#undef __CONNECT4
139#undef __CONNECT5
140#undef __CONNECT6
141#undef __CONNECT7
142#undef __CONNECT8
143#undef __CONNECT9
144
145#undef CONNECT2
146#undef CONNECT3
147#undef CONNECT4
148#undef CONNECT5
149#undef CONNECT6
150#undef CONNECT7
151#undef CONNECT8
152#undef CONNECT9
153
154#undef CONNECT
155
156#undef __MACRO_EXPANDING
157#define __MACRO_EXPANDING(...) __VA_ARGS__
158
159#define __CONNECT2(__A, __B) __A##__B
160#define __CONNECT3(__A, __B, __C) __A##__B##__C
161#define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
162#define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
163#define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
164#define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
165 __A##__B##__C##__D##__E##__F##__G
166#define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
167 __A##__B##__C##__D##__E##__F##__G##__H
168#define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
169 __A##__B##__C##__D##__E##__F##__G##__H##__I
170
171#define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
172#define CONNECT2(__A, __B) __CONNECT2(__A, __B)
173#define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
174#define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
175#define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
176#define CONNECT6(__A, __B, __C, __D, __E, __F) \
177 __CONNECT6(__A, __B, __C, __D, __E, __F)
178#define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
179 __CONNECT7(__A, __B, __C, __D, __E, __F, __G)
180#define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
181 __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
182#define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
183 __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
184
185#define CONNECT(...) \
186 ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
187
188#undef __using1
189#undef __using2
190#undef __using3
191#undef __using4
192#undef using
193
194#define __using1(__declare) \
195 for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
196 CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
197 )
198
199#define __using2(__declare, __on_leave_expr) \
200 for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
201 CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
202 (__on_leave_expr) \
203 )
204
205#define __using3(__declare, __on_enter_expr, __on_leave_expr) \
206 for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
207 CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
208 ((__on_enter_expr),1) : 0; \
209 (__on_leave_expr) \
210 )
211
212#define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
213 for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
214 CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
215 ((__on_enter_expr),1) : 0; \
216 (__on_leave_expr) \
217 )
218
219#define using(...) \
220 CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
221
222
223#undef __with2
224#undef __with3
225#undef with
226
227#define __with2(__type, __addr) \
228 using(__type *_=(__addr))
229#define __with3(__type, __addr, __item) \
230 using(__type *_=(__addr), *__item = _, _=_,_=_ )
231
232#define with(...) \
233 CONNECT2(__with, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
234
235#undef _
236
237#ifndef dimof
238# define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
239#endif
240
241
242#define SAFE_NAME(__NAME) CONNECT3(__,__NAME,__LINE__)
243
244#undef foreach2
245#undef foreach3
246#undef foreach
247
248#define foreach2(__type, __array) \
249 using(__type *_ = __array) \
250 for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
251 SAFE_NAME(count) > 0; \
252 _++, SAFE_NAME(count)-- \
253 )
254
255#define foreach3(__type, __array, __item) \
256 using(__type *_ = __array, *__item = _, _ = _, _ = _ ) \
257 for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
258 SAFE_NAME(count) > 0; \
259 _++, __item = _, SAFE_NAME(count)-- \
260 )
261
262#define foreach(...) \
263 CONNECT2(foreach, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
264
265#ifndef safe_atom_code
266# define safe_atom_code() \
267 using( uint32_t SAFE_NAME(temp) = \
268 ({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
269 __disable_irq(); \
270 SAFE_NAME(temp2);}), \
271 __set_PRIMASK(SAFE_NAME(temp)))
272#endif
273
274#ifndef __IRQ_SAFE
275# define __IRQ_SAFE \
276 using( uint32_t SAFE_NAME(temp) = \
277 ({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
278 __disable_irq(); \
279 SAFE_NAME(temp2);}), \
280 __set_PRIMASK(SAFE_NAME(temp)))
281#endif
282
283#ifndef __perf_counter_printf__
284# define __perf_counter_printf__ printf
285#endif
286
287#if __PLOOC_VA_NUM_ARGS() != 0
288#warning Please enable GNU extensions, it is required by __cycleof__() and \
289__super_loop_monitor__()
290#endif
291
292#if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__)
293# if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__
294# pragma import(__ensure_systick_wrapper)
295# elif (defined(__GNUC__) || defined(__clang__)) \
296 && (!defined(__IS_COMPILER_IAR__) || !__IS_COMPILER_IAR__)
297__asm(".global __ensure_systick_wrapper\n\t");
298# endif
299#endif
302/*============================ MACROFIED FUNCTIONS ===========================*/
303
309#define __cycleof__(__STR, ...) \
310 using(int64_t _ = get_system_ticks(), __cycle_count__ = _, \
311 _=_, { \
312 _ = get_system_ticks() - _ - g_nOffset; \
313 __cycle_count__ = _; \
314 if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
315 __perf_counter_printf__("\r\n"); \
316 __perf_counter_printf__("-[Cycle Report]"); \
317 __perf_counter_printf__( \
318 "--------------------------------------------\r\n"); \
319 __perf_counter_printf__( \
320 __STR " total cycle count: %ld [%016lx]\r\n", \
321 (long)_, (long)_); \
322 } else { \
323 __VA_ARGS__ \
324 }; \
325 })
326
333#define __super_loop_monitor__(__N, ...) \
334 using( \
335 struct { \
336 int64_t lStart; \
337 int64_t lTaskUsedCycles; \
338 int64_t lTimeElapsed; \
339 } __cpu_usage__ = {.lStart = get_system_ticks()}) \
340 using(int SAFE_NAME(cnt) = (__N)) \
341 for(start_task_cycle_counter();; ({ \
342 if (!(--SAFE_NAME(cnt))) { \
343 __cpu_usage__.lTimeElapsed \
344 = get_system_ticks() - __cpu_usage__.lStart - g_nOffset; \
345 __cpu_usage__.lTaskUsedCycles = stop_task_cycle_counter(); \
346 \
347 if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
348 __perf_counter_printf__( \
349 "%s CPU Usage %2.3f%%\r\n", __func__, \
350 (float)((double)__cpu_usage__.lTaskUsedCycles * 100.0 / \
351 (double)__cpu_usage__.lTimeElapsed)); \
352 } else { \
353 __VA_ARGS__; \
354 } \
355 SAFE_NAME(cnt) = (__N); \
356 __cpu_usage__.lStart = get_system_ticks(); \
357 start_task_cycle_counter(); \
358 }; \
359 }))
360
361/*============================ TYPES =========================================*/
362typedef struct {
363 int64_t lStart;
364 int64_t lUsedTotal;
365 int32_t nUsedRecent;
366 uint16_t hwActiveCount;
367 uint16_t : 15;
368 uint16_t bEnabled : 1;
370
372
374 task_cycle_info_t *ptInfo;
377};
378
381/*============================ GLOBAL VARIABLES ==============================*/
382extern volatile int64_t g_lLastTimeStamp;
383extern volatile int32_t g_nOffset;
384/*============================ LOCAL VARIABLES ===============================*/
385/*============================ PROTOTYPES ====================================*/
386
387
397__attribute__((noinline))
398extern int64_t get_system_ticks(void);
399
404extern int32_t get_system_ms(void);
405
410extern int32_t get_system_us(void);
411
415__STATIC_INLINE
417{
418 g_lLastTimeStamp = get_system_ticks();
419}
420
426__STATIC_INLINE
428{
429 int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
430
431 return lTemp - g_nOffset;
432}
433
438extern void delay_us(int32_t nUs);
439
444extern void delay_ms(int32_t nMs);
445
446#ifdef __PERF_CNT_USE_LONG_CLOCK__
468#if !defined(__IS_COMPILER_IAR__)
469__attribute__((nothrow))
470#endif
471__attribute__((noinline))
472extern int64_t clock(void);
473#endif
474
482#if defined(__PERF_CNT_USE_RTOS__)
483
486extern void init_task_cycle_counter(void);
487
498
499
506
512extern bool enable_task_cycle_info(task_cycle_info_t *ptInfo);
513
519extern bool disable_task_cycle_info(task_cycle_info_t *ptInfo);
520
526extern
527void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus);
528
538extern
540 task_cycle_info_t *ptInfo,
541 task_cycle_info_agent_t *ptAgent);
542
548extern
551
556__attribute__((noinline))
557extern void __start_task_cycle_counter(task_cycle_info_t *ptInfo);
558
573__attribute__((noinline))
574extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
575
576
577#define start_task_cycle_counter(...) \
578 __start_task_cycle_counter((NULL,##__VA_ARGS__))
579
580#define stop_task_cycle_counter(...) \
581 __stop_task_cycle_counter((NULL,##__VA_ARGS__))
582
583#elif !defined(__IMPLEMENT_PERF_COUNTER)
584# define start_task_cycle_counter(...) start_cycle_counter()
585# define stop_task_cycle_counter(...) stop_cycle_counter()
586# define init_task_cycle_counter()
587# define register_task_cycle_agent(...)
588# define unregister_task_cycle_agent(...)
589# define init_task_cycle_info(...) (NULL)
590# define enable_task_cycle_info(...) (false)
591# define disable_task_cycle_info(...) (false)
592# define resume_task_cycle_info(...)
593#endif
594
602/*----------------------------------------------------------------------------*
603 * Please ignore the following APIs unless you have encountered some known *
604 * special conditions *
605 *----------------------------------------------------------------------------*/
606
634extern void init_cycle_counter(bool bIsSysTickOccupied);
635
636
652
656extern void update_perf_counter(void);
657
665#ifdef __PERF_COUNTER_COREMARK__
666
670void coremark_main(void);
671#endif
672
676//#if defined(__clang__)
677//# pragma clang diagnostic pop
678//#elif defined(__IS_COMPILER_GCC__)
679//# pragma GCC diagnostic pop
680//#endif
681
682#ifdef __cplusplus
683}
684#endif
685
686#endif
int32_t get_system_us(void)
get the elapsed microsecond since perf_counter is initialised
Definition: perf_counter.c:398
void user_code_insert_to_systick_handler(void)
a system timer handler inserted to the SysTick_Handler
Definition: perf_counter.c:208
void update_perf_counter(void)
update perf_counter as SystemCoreClock has been updated.
Definition: perf_counter.c:237
void delay_ms(int32_t nMs)
delay specified time in millisecond
Definition: perf_counter.c:328
void start_cycle_counter(void)
try to set a start pointer for the performance counter
Definition: perf_counter.h:416
int64_t get_system_ticks(void)
get the elapsed cycles since perf_counter is initialised
Definition: perf_counter.c:346
void init_cycle_counter(bool bIsSysTickOccupied)
initialise cycle counter service
Definition: perf_counter.c:249
void delay_us(int32_t nUs)
delay specified time in microsecond
Definition: perf_counter.c:310
int32_t get_system_ms(void)
get the elapsed milliseconds since perf_counter is initialised
Definition: perf_counter.c:387
int64_t stop_cycle_counter(void)
calculate the elapsed cycle count since the last start point
Definition: perf_counter.h:427
void coremark_main(void)
entry for coremark
bool disable_task_cycle_info(task_cycle_info_t *ptInfo)
disable a given task_cycle_info_t object
Definition: perf_counter.c:483
task_cycle_info_agent_t * register_task_cycle_agent(task_cycle_info_t *ptInfo, task_cycle_info_agent_t *ptAgent)
register a global virtual cycle counter agent to the current task
Definition: perf_counter.c:506
void init_task_cycle_counter(void)
initialize the default virtual cycle counter for the current task
Definition: perf_counter.c:440
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus)
resume the enabled status of a given task_cycle_info_t object
Definition: perf_counter.c:496
task_cycle_info_t * get_rtos_task_cycle_info(void)
provide cycle information for target task
Definition: perf_counter.c:435
bool enable_task_cycle_info(task_cycle_info_t *ptInfo)
enable a given task_cycle_info_t object
Definition: perf_counter.c:470
task_cycle_info_agent_t * unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent)
remove a global virtual cycle counter agent from the current task
Definition: perf_counter.c:545
task_cycle_info_t * init_task_cycle_info(task_cycle_info_t *ptInfo)
intialize a given task_cycle_info_t object and enable it before registering it.
Definition: perf_counter.c:455