| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943 |
- /****************************************************************************
- * Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
- * *
- * 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. *
- * *
- ****************************************************************************/
- #ifndef __PERFORMANCE_COUNTER_H__
- #define __PERFORMANCE_COUNTER_H__
- /*============================ INCLUDES ======================================*/
- #include <stdbool.h>
- #include <stdint.h>
- #include <stddef.h>
- #include "cmsis_compiler.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*============================ MACROS ========================================*/
- /*!
- * \addtogroup gBasic 1 Basic
- * @{
- */
- #define __PERF_COUNTER_VER_MAJOR__ 2
- #define __PERF_COUNTER_VER_MINOR__ 2
- #define __PERF_COUNTER_VER_REVISE__ 4
- #define __PERF_COUNTER_VER_STR__ ""
- #define __PER_COUNTER_VER__ (__PERF_COUNTER_VER_MAJOR__ * 10000ul \
- +__PERF_COUNTER_VER_MINOR__ * 100ul \
- +__PERF_COUNTER_VER_REVISE__)
- /*! @} */
- /*!
- * \addtogroup gHelper 4 Helper
- * @{
- */
- // for IAR
- #undef __IS_COMPILER_IAR__
- #if defined(__IAR_SYSTEMS_ICC__)
- # define __IS_COMPILER_IAR__ 1
- #endif
- // for arm compiler 5
- #undef __IS_COMPILER_ARM_COMPILER_5__
- #if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
- # define __IS_COMPILER_ARM_COMPILER_5__ 1
- #endif
- //for arm compiler 6
- #undef __IS_COMPILER_ARM_COMPILER_6__
- #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
- # define __IS_COMPILER_ARM_COMPILER_6__ 1
- #endif
- #undef __IS_COMPILER_ARM_COMPILER__
- #if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
- || defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
- # define __IS_COMPILER_ARM_COMPILER__ 1
- #endif
- // for clang
- #undef __IS_COMPILER_LLVM__
- #if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
- # define __IS_COMPILER_LLVM__ 1
- #else
- // for gcc
- # undef __IS_COMPILER_GCC__
- # if defined(__GNUC__) && !( defined(__IS_COMPILER_ARM_COMPILER__) \
- || defined(__IS_COMPILER_LLVM__) \
- || defined(__IS_COMPILER_IAR__))
- # define __IS_COMPILER_GCC__ 1
- # endif
- #endif
- #if defined(__clang__)
- # pragma clang diagnostic push
- # pragma clang diagnostic ignored "-Wunknown-warning-option"
- # pragma clang diagnostic ignored "-Wreserved-identifier"
- # pragma clang diagnostic ignored "-Wdeclaration-after-statement"
- # pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
- # pragma clang diagnostic ignored "-Wgnu-statement-expression"
- # pragma clang diagnostic ignored "-Wunused-but-set-variable"
- # pragma clang diagnostic ignored "-Wshadow"
- # pragma clang diagnostic ignored "-Wshorten-64-to-32"
- # pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
- # pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
- #elif defined(__IS_COMPILER_ARM_COMPILER_5__)
- # pragma diag_suppress 550
- #elif defined(__IS_COMPILER_GCC__)
- # pragma GCC diagnostic push
- # pragma GCC diagnostic ignored "-Wpedantic"
- # pragma GCC diagnostic ignored "-Wunused-variable"
- # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
- # pragma GCC diagnostic ignored "-Wformat="
- #endif
- #ifndef __PLOOC_VA_NUM_ARGS_IMPL
- # define __PLOOC_VA_NUM_ARGS_IMPL( _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11, \
- _12,_13,_14,_15,_16,__N,...) __N
- #endif
- #ifndef __PLOOC_VA_NUM_ARGS
- #define __PLOOC_VA_NUM_ARGS(...) \
- __PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
- 8,7,6,5,4,3,2,1,0)
- #endif
- #ifndef UNUSED_PARAM
- # define UNUSED_PARAM(__VAR) (void)(__VAR)
- #endif
- #undef __CONNECT2
- #undef __CONNECT3
- #undef __CONNECT4
- #undef __CONNECT5
- #undef __CONNECT6
- #undef __CONNECT7
- #undef __CONNECT8
- #undef __CONNECT9
- #undef CONNECT2
- #undef CONNECT3
- #undef CONNECT4
- #undef CONNECT5
- #undef CONNECT6
- #undef CONNECT7
- #undef CONNECT8
- #undef CONNECT9
- #undef CONNECT
- #undef __MACRO_EXPANDING
- #define __MACRO_EXPANDING(...) __VA_ARGS__
- #define __CONNECT2(__A, __B) __A##__B
- #define __CONNECT3(__A, __B, __C) __A##__B##__C
- #define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
- #define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
- #define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
- #define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
- __A##__B##__C##__D##__E##__F##__G
- #define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
- __A##__B##__C##__D##__E##__F##__G##__H
- #define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
- __A##__B##__C##__D##__E##__F##__G##__H##__I
- #define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
- #define CONNECT2(__A, __B) __CONNECT2(__A, __B)
- #define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
- #define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
- #define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
- #define CONNECT6(__A, __B, __C, __D, __E, __F) \
- __CONNECT6(__A, __B, __C, __D, __E, __F)
- #define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
- __CONNECT7(__A, __B, __C, __D, __E, __F, __G)
- #define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
- __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
- #define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
- __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
- #define CONNECT(...) \
- ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
- #undef __using1
- #undef __using2
- #undef __using3
- #undef __using4
- #undef using
- #define __using1(__declare) \
- for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
- CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
- )
- #define __using2(__declare, __on_leave_expr) \
- for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
- CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
- (__on_leave_expr) \
- )
- #define __using3(__declare, __on_enter_expr, __on_leave_expr) \
- for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
- CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
- ((__on_enter_expr),1) : 0; \
- (__on_leave_expr) \
- )
- #define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
- for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
- CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
- ((__on_enter_expr),1) : 0; \
- (__on_leave_expr) \
- )
- #define using(...) \
- CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
- #undef __with2
- #undef __with3
- #undef with
- #define __with2(__type, __addr) \
- using(__type *_=(__addr))
- #define __with3(__type, __addr, __item) \
- using(__type *_=(__addr), *__item = _, _=_,_=_ )
- #define with(...) \
- CONNECT2(__with, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
- #undef _
- #ifndef dimof
- # define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
- #endif
- #define SAFE_NAME(__NAME) CONNECT3(__,__NAME,__LINE__)
- #undef foreach2
- #undef foreach3
- #undef foreach
- #define foreach2(__type, __array) \
- using(__type *_ = __array) \
- for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
- SAFE_NAME(count) > 0; \
- _++, SAFE_NAME(count)-- \
- )
- #define foreach3(__type, __array, __item) \
- using(__type *_ = __array, *__item = _, _ = _, _ = _ ) \
- for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
- SAFE_NAME(count) > 0; \
- _++, __item = _, SAFE_NAME(count)-- \
- )
- #define foreach(...) \
- CONNECT2(foreach, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
- #ifndef safe_atom_code
- # define safe_atom_code() \
- using( uint32_t SAFE_NAME(temp) = \
- ({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
- __disable_irq(); \
- SAFE_NAME(temp2);}), \
- __set_PRIMASK(SAFE_NAME(temp)))
- #endif
- #ifndef __IRQ_SAFE
- # define __IRQ_SAFE \
- using( uint32_t SAFE_NAME(temp) = \
- ({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
- __disable_irq(); \
- SAFE_NAME(temp2);}), \
- __set_PRIMASK(SAFE_NAME(temp)))
- #endif
- #ifndef __perf_counter_printf__
- # define __perf_counter_printf__ printf
- #endif
- #if __PLOOC_VA_NUM_ARGS() != 0
- #warning Please enable GNU extensions, it is required by __cycleof__() and \
- __super_loop_monitor__()
- #endif
- #if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__)
- # if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__
- # pragma import(__ensure_systick_wrapper)
- # elif (defined(__GNUC__) || defined(__clang__)) \
- && (!defined(__IS_COMPILER_IAR__) || !__IS_COMPILER_IAR__)
- __asm(".global __ensure_systick_wrapper\n\t");
- # endif
- #endif
- /*! @} */
- /*============================ MACROFIED FUNCTIONS ===========================*/
- /*!
- * \addtogroup gBasic 1 Basic
- * @{
- */
- /*!
- * \brief measure the cycle count of a given code segment
- * \param[in] __STR a description string for the measurement
- * \param[in] ... an optional code segement, in which we can read the measured
- * result from __cycle_count__.
- * \details Here is an example:
- E.g.
- \code
- __cycleof__("printf") {
- printf("hello world\r\n");
- }
- \endcode
- */
- #define __cycleof__(__STR, ...) \
- using(int64_t _ = get_system_ticks(), __cycle_count__ = _, \
- _=_, { \
- _ = get_system_ticks() - _ - g_nOffset; \
- __cycle_count__ = _; \
- if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
- __perf_counter_printf__("\r\n"); \
- __perf_counter_printf__("-[Cycle Report]"); \
- __perf_counter_printf__( \
- "--------------------------------------------\r\n"); \
- __perf_counter_printf__( \
- __STR " total cycle count: %ld [%016lx]\r\n", \
- (long)_, (long)_); \
- } else { \
- __VA_ARGS__ \
- }; \
- })
- /*!
- * \brief measure the cpu usage for a given code segment and print out the
- * result in percentage.
- * \param[in] __CNT generate result on every given iterations
- * \param[in] ... an optional code segement, in which we can read the measured
- * result from __usage__ which is a float value.
- * \details Here is an example, 50% cpu time:
- E.g.
- \code
- while (1) {
- __cpu_time__(100) {
- delay_us(5000);
- }
- delay_us(5000);
- }
- \endcode
- */
- #define __cpu_time__(__CNT, ...) \
- static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
- static uint32_t s_wLoopCounter = (__CNT); \
- using(float __usage__ = 0, ({ \
- if (0 == s_wLoopCounter) { \
- __usage__ = (float)((double)SAFE_NAME(s_lTotal) \
- / (double)( get_system_ticks() \
- - SAFE_NAME(s_lTimestamp))); \
- __usage__ *= 100.0f; \
- SAFE_NAME(s_lTimestamp) = 0; \
- SAFE_NAME(s_lTotal) = 0; \
- if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
- __perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__); \
- } else { \
- __VA_ARGS__ \
- } \
- } \
- if (0 == SAFE_NAME(s_lTimestamp)) { \
- SAFE_NAME(s_lTimestamp) = get_system_ticks(); \
- s_wLoopCounter = (__CNT); \
- } \
- start_task_cycle_counter();}), \
- ({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
- s_wLoopCounter--;}))
- /*!
- * \addtogroup gBasicTimerService 1.2 Timer Service
- * \ingroup gBasic
- * @{
- */
- /*!
- * \brief should not use
- */
- #define perfc_is_time_out_ms0() true
- /*!
- * \brief set an alarm with given period in ms and check the status
- *
- * \param[in] __ms a time period in millisecond
- * \param[in] __timestamp_ptr an optional timestamp holder
- * \param[in] __auto_reload whether starting next period after a timeout event
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_ms3(__ms, __timestamp_ptr, __auto_reload) \
- ({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
- __perfc_is_time_out(perfc_convert_ms_to_ticks(__ms), \
- (__timestamp_ptr), (__auto_reload));})
- /*!
- * \brief set an alarm with given period in ms and check the status
- *
- * \param[in] __ms a time period in millisecond
- * \param[in] __timestamp_ptr an optional timestamp holder
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_ms2(__ms, __timestamp_ptr) \
- perfc_is_time_out_ms3((__ms), (__timestamp_ptr), true)
- /*!
- * \brief set an alarm with given period in ms and check the status
- *
- * \param[in] __ms a time period in millisecond
- * \param[in] __timestamp_ptr an optional timestamp holder
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_ms1(__ms) \
- perfc_is_time_out_ms3((__ms), &SAFE_NAME(s_lTimestamp), true)
- /*!
- * \brief set an alarm with given period in ms and check the status
- *
- * \param[in] __ms a time period in millisecond
- * \param[in] ... an optional timestamp holder
- * \param[in] ... an optional indicator for whether starting next period after a timeout event
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_ms(...) \
- CONNECT2(perfc_is_time_out_ms, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
- (__VA_ARGS__)
- /*!
- * \brief set an alarm with given period in us and check the status
- *
- * \param[in] __us a time period in microsecond
- * \param[in] __timestamp_ptr an optional timestamp holder
- * \param[in] __auto_reload whether starting next period after a timeout event
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_us3(__us, __timestamp_ptr, __auto_reload) \
- ({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
- __perfc_is_time_out(perfc_convert_us_to_ticks(__us), \
- (__timestamp_ptr), (__auto_reload));})
- /*!
- * \brief set an alarm with given period in us and check the status
- *
- * \param[in] __us a time period in microsecond
- * \param[in] __timestamp_ptr an optional timestamp holder
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_us2(__us, __timestamp_ptr) \
- perfc_is_time_out_us3((__us), (__timestamp_ptr), true)
- /*!
- * \brief set an alarm with given period in us and check the status
- *
- * \param[in] __us a time period in microsecond
- * \param[in] __timestamp_ptr an optional timestamp holder
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_us1(__us) \
- perfc_is_time_out_us3((__us), &SAFE_NAME(s_lTimestamp), true)
- /*!
- * \brief set an alarm with given period in us and check the status
- *
- * \param[in] __us a time period in microsecond
- * \param[in] ... an optional timestamp holder
- * \param[in] ... an optional indicator for whether starting next period after a timeout event
- *
- * \return bool whether it is timeout
- */
- #define perfc_is_time_out_us(...) \
- CONNECT2(perfc_is_time_out_us, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
- (__VA_ARGS__)
- /*! @} */
- /*! @} */
- /*!
- * \addtogroup gRTOS 2 RTOS Support
- * @{
- */
- #define __super_loop_monitor__(__N, ...) \
- using( \
- struct { \
- int64_t lStart; \
- int64_t lTaskUsedCycles; \
- int64_t lTimeElapsed; \
- } __cpu_usage__ = {.lStart = get_system_ticks()}) \
- using(int SAFE_NAME(cnt) = (__N)) \
- for(start_task_cycle_counter();; ({ \
- if (!(--SAFE_NAME(cnt))) { \
- __cpu_usage__.lTimeElapsed \
- = get_system_ticks() - __cpu_usage__.lStart - g_nOffset; \
- __cpu_usage__.lTaskUsedCycles = stop_task_cycle_counter(); \
- \
- if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
- __perf_counter_printf__( \
- "%s CPU Usage %2.3f%%\r\n", __func__, \
- (float)((double)__cpu_usage__.lTaskUsedCycles * 100.0 / \
- (double)__cpu_usage__.lTimeElapsed)); \
- } else { \
- __VA_ARGS__; \
- } \
- SAFE_NAME(cnt) = (__N); \
- __cpu_usage__.lStart = get_system_ticks(); \
- start_task_cycle_counter(); \
- }; \
- }))
- /*============================ TYPES =========================================*/
- typedef struct {
- int64_t lStart;
- int64_t lUsedTotal;
- int32_t nUsedRecent;
- uint16_t hwActiveCount;
- uint16_t : 15;
- uint16_t bEnabled : 1;
- } task_cycle_info_t;
- typedef struct task_cycle_info_agent_t task_cycle_info_agent_t;
- struct task_cycle_info_agent_t {
- task_cycle_info_t *ptInfo;
- task_cycle_info_agent_t *ptNext;
- task_cycle_info_agent_t *ptPrev;
- };
- /*! @} */
- /*============================ GLOBAL VARIABLES ==============================*/
- extern volatile int64_t g_lLastTimeStamp;
- extern volatile int32_t g_nOffset;
- /*============================ LOCAL VARIABLES ===============================*/
- /*============================ PROTOTYPES ====================================*/
- /*!
- * \addtogroup gBasicTicks 1.1 Ticks APIs
- * \ingroup gBasic
- * @{
- */
- /*!
- * \brief get the elapsed cycles since perf_counter is initialised
- * \return int64_t the elpased cycles
- */
- __attribute__((noinline))
- extern int64_t get_system_ticks(void);
- #ifdef __PERF_CNT_USE_LONG_CLOCK__
- /*! \note the prototype of this clock() is different from the one defined in
- *! time.h. As clock_t is usually defined as unsigned int, it is
- *! not big enough in Cortex-M system to hold a time-stamp. clock()
- *! defined here returns the timestamp since the begining of main()
- *! and its unit is clock cycle (rather than 1ms). Hence, for a system
- *! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
- *! NXP, it is very easy to see a counter overflow as clock_t is
- *! defined as uint32_t in timer.h.
- *! Since we are not allowed to change the defintion of clock_t in
- *! official header file, i.e. time.h, I use a compatible prototype
- *! after I checked the AAPCS spec. So, the return of the clock() is
- *! int64_t, which will use the R0 to store the lower 32bits and R1
- *! to store the higher 32bits. When you are using the prototype from
- *! timer.h, caller will only take the lower 32bits stored in R0 and
- *! the higher 32bits stored in R1 will be ignored.
- *!
- *! If you want to use the non-overflow version of this clock(), please
- *! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
- *! and 2) do not include system header file <time.h>
- *!
- */
- #if !defined(__IS_COMPILER_IAR__)
- __attribute__((nothrow))
- #endif
- __attribute__((noinline))
- extern int64_t clock(void);
- #endif
- /*!
- * \brief try to set a start pointer for the performance counter
- */
- __STATIC_INLINE
- void start_cycle_counter(void)
- {
- g_lLastTimeStamp = get_system_ticks();
- }
- /*!
- * \brief calculate the elapsed cycle count since the last start point
- * \note you can have multiple stop_cycle_counter following one start point
- * \return int32_t the elapsed cycle count
- */
- __STATIC_INLINE
- int64_t stop_cycle_counter(void)
- {
- int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
- return lTemp - g_nOffset;
- }
- /*! @} */
- /*!
- * \addtogroup gBasicTimerService 1.2 Timer Service
- * \ingroup gBasic
- * @{
- */
- /*!
- * \brief get the elapsed milliseconds since perf_counter is initialised
- * \return int32_t the elapsed milliseconds
- */
- extern int32_t get_system_ms(void);
- /*!
- * \brief get the elapsed microsecond since perf_counter is initialised
- * \return int32_t the elapsed microsecond
- */
- extern int32_t get_system_us(void);
- /*!
- * \brief delay specified time in microsecond
- * \param[in] nUs time in microsecond
- */
- extern void delay_us(int32_t nUs);
- /*!
- * \brief delay specified time in millisecond
- * \param[in] nMs time in millisecond
- */
- extern void delay_ms(int32_t nMs);
- /*!
- * \brief convert ticks of a reference timer to millisecond
- *
- * \param[in] lTick the tick count
- * \return int64_t the millisecond
- */
- extern
- int64_t perfc_convert_ticks_to_ms(int64_t lTick);
- /*!
- * \brief convert millisecond into ticks of the reference timer
- *
- * \param[in] wMS the target time in millisecond
- * \return int64_t the ticks
- */
- extern
- int64_t perfc_convert_ms_to_ticks(uint32_t wMS);
- /*!
- * \brief convert ticks of a reference timer to microsecond
- *
- * \param[in] lTick the tick count
- * \return int64_t the microsecond
- */
- extern
- int64_t perfc_convert_ticks_to_us(int64_t lTick);
- /*!
- * \brief convert microsecond into ticks of the reference timer
- *
- * \param[in] wUS the target time in microsecond
- * \return int64_t the ticks
- */
- extern
- int64_t perfc_convert_us_to_ticks(uint32_t wUS);
- /*!
- * \brief set an alarm with given period and check the status
- *
- * \param[in] lPeriod a time period in ticks
- * \param[in] plTimestamp a pointer points to an int64_t integer, if NULL is
- * passed, an static local variable inside the function will be used
- * \param[in] bAutoReload whether starting next period after a timeout event.
- * \return bool whether it is timeout or not
- */
- extern
- bool __perfc_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload);
- /*! @} */
- /*!
- * \addtogroup gRTOS 2 RTOS Support
- * @{
- */
- #if defined(__PERF_CNT_USE_RTOS__)
- /*! \brief initialize the default virtual cycle counter for the current task
- */
- extern void init_task_cycle_counter(void);
- /*! \brief check whether the task stack canary is safe or not
- * \retval false likely to be a stack-overflow
- * \retval true task stack is safe
- */
- extern
- bool perfc_check_task_stack_canary_safe(void);
- /*! \brief provide cycle information for target task
- * \details Support RTOS List:
- * - RTX5
- * - RT-Thread
- * - ThreadX
- * - FreeRTOS
- *
- * \return task_cycle_info_t* the cycle info object passed to this function
- */
- extern task_cycle_info_t * get_rtos_task_cycle_info(void);
- /*!
- * \brief intialize a given task_cycle_info_t object and enable it before
- * registering it.
- * \return task_cycle_info_t* the cycle info object passed to this function
- */
- extern task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo);
- /*! \brief enable a given task_cycle_info_t object
- *
- * \param[in] ptInfo the address of target task_cycle_info_t object
- * \return bool previous status
- */
- extern bool enable_task_cycle_info(task_cycle_info_t *ptInfo);
- /*! \brief disable a given task_cycle_info_t object
- *
- * \param[in] ptInfo the address of target task_cycle_info_t object
- * \return bool previous status
- */
- extern bool disable_task_cycle_info(task_cycle_info_t *ptInfo);
- /*! \brief resume the enabled status of a given task_cycle_info_t object
- *
- * \param[in] ptInfo the address of target task_cycle_info_t object
- * \param[in] bEnabledStatus the previous status
- */
- extern
- void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus);
- /*!
- * \brief register a global virtual cycle counter agent to the current task
- * \param[in] ptInfo the address of target task_cycle_info_t object
- * \param[in] ptAgent an list node for the task_cycle_info_t object
- * \note the ptAgent it is better to be allocated as a static variable, global
- * variable or comes from heap or pool
- *
- * \return task_cycle_info_agent_t* the agent passed to this function
- */
- extern
- task_cycle_info_agent_t *register_task_cycle_agent(
- task_cycle_info_t *ptInfo,
- task_cycle_info_agent_t *ptAgent);
- /*!
- * \brief remove a global virtual cycle counter agent from the current task
- * \param[in] ptAgent the list node currently in use
- * \return task_cycle_info_agent_t* the agent passed to this function
- */
- extern
- task_cycle_info_agent_t *
- unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent);
- /*! \brief reset and start the virtual cycle counter for the current task
- *
- * \param[in] ptInfo the target task_cycle_info_t object
- */
- __attribute__((noinline))
- extern void __start_task_cycle_counter(task_cycle_info_t *ptInfo);
- /*! \brief calculate the elapsed cycle count for current task since the last
- * start point
- *
- * \note you can call stop_cycle_counter() multiple times following one
- * start_task_cycle_counter()
- *
- * \param[in] ptInfo the target task_cycle_info_t object
- *
- * \note When ptInfo is NULL, it returns current task cycle info, when ptInfo
- * is non-NULL, it returns the total used cycles of the specified
- * task_cycle_info_t object.
- *
- * \return int64_t the elapsed cycle count.
- */
- __attribute__((noinline))
- extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
- #define start_task_cycle_counter(...) \
- __start_task_cycle_counter((NULL,##__VA_ARGS__))
- #define stop_task_cycle_counter(...) \
- __stop_task_cycle_counter((NULL,##__VA_ARGS__))
- #elif !defined(__IMPLEMENT_PERF_COUNTER)
- # define start_task_cycle_counter(...) start_cycle_counter()
- # define stop_task_cycle_counter(...) stop_cycle_counter()
- # define init_task_cycle_counter()
- # define register_task_cycle_agent(...)
- # define unregister_task_cycle_agent(...)
- # define init_task_cycle_info(...) (NULL)
- # define enable_task_cycle_info(...) (false)
- # define disable_task_cycle_info(...) (false)
- # define resume_task_cycle_info(...)
- # define perfc_check_task_stack_canary_safe() (false)
- #endif
- /*! @} */
- /*!
- * \addtogroup gBasic 1 Basic
- * @{
- */
- /*----------------------------------------------------------------------------*
- * Please ignore the following APIs unless you have encountered some known *
- * special conditions *
- *----------------------------------------------------------------------------*/
- /*! \brief initialise cycle counter service
- * \note - don't forget to tell the function whether the systick is already
- * used by user applications.
- * Don't worry, this cycle counter service won't affect your existing
- * systick service.
- *
- * \note - Usually the perf_counter can initialise itself with the help of
- * __attribute__((constructor(255))), this works fine in Arm Compiler
- * 5 (armcc), Arm Compiler 6 (armclang), arm gcc and llvm. It doesn't
- * work for IAR. So, when you are using IAR, please call this function
- * manually to initialise the perf_counter service.
- *
- * \note - Perf_counter library assumes that:
- * 1. Your project has already using SysTick
- * 2. It assumes that you have already implemented the SysTick_Handler
- * 3. It assumes that you have enabled the exception handling for
- * SysTick.
- * If these are not the case, please:
- * 1. Add an empty SysTick_Handler to your project if you don't have
- * one
- * 2. Make sure you have the SysTick Exception handling enabled
- * 3. And call function init_cycle_counter(false) if you doesn't
- * use SysTick in your project at all.
- *
- * \param[in] bIsSysTickOccupied A boolean value which indicates whether SysTick
- * is already used by user application.
- */
- extern void init_cycle_counter(bool bIsSysTickOccupied);
- /*!
- * \brief a system timer handler inserted to the SysTick_Handler
- *
- * \note - if you are using a compiler other than armcc or armclang, e.g. iar,
- * arm gcc etc, the systick_wrapper_ual.o doesn't work with the linker
- * of your target toolchain as it use the $Super$$ which is only supported
- * by armlink. For this condition, you have to manually put this function
- * into your existing SysTick_Handler to make the perf_counter library
- * work.
- *
- * \note - if you are using Arm Compiler 5 (armcc) or Arm Compiler 6 (armclang)
- * you do NOT have to insert this function into your SysTick_Handler,
- * the systick_wrapper_ual.s will do the work for you.
- */
- extern void user_code_insert_to_systick_handler(void);
- /*!
- * \brief update perf_counter as SystemCoreClock has been updated.
- */
- extern void update_perf_counter(void);
- /*!
- * \brief prepare for reconfiguration of SysTick timer.
- *
- * \note some systems (e.g. FreeRTOS) might reconfigure the systick timer to
- * fulfil the requirement of their feature. To support this, just
- * before the reconfiguration, please call this function in order
- * to make the perf_counter works correctly later.
- *
- * \note after the reconfiguration, please call update_perf_counter() to apply
- * the changes to perf_counter.
- *
- * \note this function will stop the SysTick, clear the pending bit and set
- * the Load register and Current Value register to zero.
- */
- extern void before_cycle_counter_reconfiguration(void);
- /*! @} */
- /*!
- * \addtogroup gBenchmark 3 Benchmark
- * @{
- */
- #ifdef __PERF_COUNTER_COREMARK__
- /*!
- * \brief entry for coremark
- */
- void coremark_main(void);
- #endif
- /*! @} */
- //#if defined(__clang__)
- //# pragma clang diagnostic pop
- //#elif defined(__IS_COMPILER_GCC__)
- //# pragma GCC diagnostic pop
- //#endif
- #ifdef __cplusplus
- }
- #endif
- #endif
|