perf_counter.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  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. /*============================ INCLUDES ======================================*/
  18. #include <stdint.h>
  19. #include <stdbool.h>
  20. #include <string.h>
  21. #include "cmsis_compiler.h"
  22. #define __IMPLEMENT_PERF_COUNTER
  23. #include "perf_counter.h"
  24. #if defined(__IS_COMPILER_GCC__)
  25. # pragma GCC diagnostic ignored "-Wattributes"
  26. #endif
  27. #if defined(__clang__)
  28. # pragma clang diagnostic ignored "-Wunknown-warning-option"
  29. # pragma clang diagnostic ignored "-Wreserved-identifier"
  30. # pragma clang diagnostic ignored "-Wconditional-uninitialized"
  31. # pragma clang diagnostic ignored "-Wcast-align"
  32. # pragma clang diagnostic ignored "-Wmissing-prototypes"
  33. #endif
  34. /*============================ MACROS ========================================*/
  35. #ifndef PERF_CNT_COMPENSATION_THRESHOLD
  36. # define PERF_CNT_COMPENSATION_THRESHOLD 16
  37. #endif
  38. #ifndef PERF_CNT_DELAY_US_COMPENSATION
  39. # define PERF_CNT_DELAY_US_COMPENSATION 90
  40. #endif
  41. /* IO definitions (access restrictions to peripheral registers) */
  42. #ifdef __cplusplus
  43. #define __I volatile /*!< Defines 'read only' permissions */
  44. #else
  45. #define __I volatile const /*!< Defines 'read only' permissions */
  46. #endif
  47. #define __O volatile /*!< Defines 'write only' permissions */
  48. #define __IO volatile /*!< Defines 'read / write' permissions */
  49. /* following defines should be used for structure members */
  50. #define __IM volatile const /*! Defines 'read only' structure member permissions */
  51. #define __OM volatile /*! Defines 'write only' structure member permissions */
  52. #define __IOM volatile /*! Defines 'read / write' structure member permissions */
  53. /* Memory mapping of Core Hardware */
  54. #define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
  55. #define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
  56. #define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
  57. #define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
  58. #define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
  59. /* SysTick Control / Status Register Definitions */
  60. #define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
  61. #define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
  62. #define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
  63. #define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
  64. #define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
  65. #define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
  66. #define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
  67. #define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
  68. /* SysTick Reload Register Definitions */
  69. #define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
  70. #define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
  71. /* SysTick Current Register Definitions */
  72. #define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
  73. #define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
  74. /* SysTick Calibration Register Definitions */
  75. #define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
  76. #define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
  77. #define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
  78. #define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
  79. #define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
  80. #define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
  81. /*@} end of group CMSIS_SysTick */
  82. #define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
  83. #define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
  84. #define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
  85. #define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
  86. #define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
  87. #define MAGIC_WORD_CANARY 0xDEADBEEF
  88. /*============================ MACROFIED FUNCTIONS ===========================*/
  89. /*============================ TYPES =========================================*/
  90. /*!
  91. \brief Structure type to access the System Timer (SysTick).
  92. */
  93. typedef struct
  94. {
  95. __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
  96. __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
  97. __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
  98. __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
  99. } SysTick_Type;
  100. /*!
  101. \brief Structure type to access the System Control Block (SCB).
  102. */
  103. typedef struct
  104. {
  105. __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
  106. __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
  107. __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
  108. __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
  109. __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
  110. __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
  111. __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
  112. __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
  113. __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
  114. __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
  115. __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
  116. __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
  117. __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
  118. __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
  119. __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
  120. __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
  121. __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
  122. __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
  123. __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
  124. uint32_t RESERVED0[5U];
  125. __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
  126. } SCB_Type;
  127. struct __task_cycle_info_t {
  128. task_cycle_info_t tInfo; //!< cycle information
  129. int64_t lLastTimeStamp; //!< previous timestamp
  130. task_cycle_info_agent_t tList; //!< the root of the agent list
  131. uint32_t wMagicWord; //!< an magic word for validation
  132. } ;
  133. /*============================ GLOBAL VARIABLES ==============================*/
  134. extern uint32_t SystemCoreClock;
  135. /*============================ LOCAL VARIABLES ===============================*/
  136. volatile int64_t g_lLastTimeStamp = 0;
  137. volatile static int64_t s_lOldTimestamp;
  138. volatile int32_t g_nOffset = 0;
  139. volatile static int32_t s_nUSUnit = 1;
  140. volatile static int32_t s_nMSUnit = 1;
  141. volatile static int32_t s_nMSResidule = 0;
  142. volatile static int32_t s_nUSResidule = 0;
  143. volatile static int32_t s_nSystemMS = 0;
  144. volatile static int32_t s_nSystemUS = 0;
  145. volatile static int64_t s_lSystemClockCounts = 0;
  146. /*============================ PROTOTYPES ====================================*/
  147. /*============================ IMPLEMENTATION ================================*/
  148. /*============================ INCLUDES ======================================*/
  149. __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
  150. {
  151. if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  152. {
  153. return (1UL); /* Reload value impossible */
  154. }
  155. //__IRQ_SAFE {
  156. SysTick->CTRL = 0;
  157. SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
  158. //NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  159. SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
  160. SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
  161. SysTick_CTRL_TICKINT_Msk |
  162. SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
  163. //SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
  164. //}
  165. return (0UL); /* Function successful */
  166. }
  167. void user_code_insert_to_systick_handler(void)
  168. {
  169. uint32_t wLoad = SysTick->LOAD + 1;
  170. s_lSystemClockCounts += wLoad;
  171. // update system ms counter
  172. do {
  173. s_nMSResidule += wLoad;
  174. int32_t nMS = s_nMSResidule / s_nMSUnit;
  175. s_nMSResidule -= nMS * s_nMSUnit;
  176. s_nSystemMS += nMS;
  177. } while(0);
  178. // update system us counter
  179. do {
  180. s_nUSResidule += wLoad;
  181. int32_t nUS = s_nUSResidule / s_nUSUnit;
  182. s_nUSResidule -= nUS * s_nUSUnit;
  183. s_nSystemUS += nUS;
  184. } while(0);
  185. }
  186. __WEAK
  187. void __perf_os_patch_init(void)
  188. {
  189. }
  190. void update_perf_counter(void)
  191. {
  192. s_nUSUnit = SystemCoreClock / 1000000ul;
  193. s_nMSUnit = SystemCoreClock / 1000ul;
  194. __IRQ_SAFE {
  195. g_lLastTimeStamp = get_system_ticks();
  196. g_nOffset = get_system_ticks() - g_lLastTimeStamp;
  197. }
  198. }
  199. void init_cycle_counter(bool bIsSysTickOccupied)
  200. {
  201. __IRQ_SAFE {
  202. if (!bIsSysTickOccupied) {
  203. SysTick_Config(0x01000000); // use the longest period
  204. }
  205. SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
  206. }
  207. update_perf_counter();
  208. s_lSystemClockCounts = 0; // reset system cycle counter
  209. s_nSystemMS = 0; // reset system millisecond counter
  210. s_nSystemUS = 0; // reset system microsecond counter
  211. __perf_os_patch_init();
  212. }
  213. /*! \note this function should only be called when irq is disabled
  214. * hence SysTick-LOAD and (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)
  215. * won't change.
  216. */
  217. __STATIC_INLINE int32_t check_systick(void)
  218. {
  219. int32_t nTemp = (int32_t)SysTick->LOAD - (int32_t)SysTick->VAL;
  220. /* Since we cannot stop counting temporarily, there are several
  221. * conditions which we should take into consideration:
  222. * - Condition 1: when assigning nTemp with the register value (LOAD-VAL),
  223. * the underflow didn't happen but when we check the PENDSTSET bit,
  224. * the underflow happens, for this condition, we should not
  225. * do any compensation. When this happens, the (LOAD-nTemp) is
  226. * smaller than PERF_CNT_COMPENSATION_THRESHOLD (a small value) as
  227. * long as LOAD is bigger than (or equals to) the
  228. * PERF_CNT_COMPENSATION_THRESHOLD;
  229. * - Condition 2: when assigning nTemp with the register value (LOAD-VAL),
  230. * the VAL is zero and underflow happened and the PENDSTSET bit
  231. * is set, for this condition, we should not do any compensation.
  232. * When this happens, the (LOAD-nTemp) is equals to zero.
  233. * - Condition 3: when assigning nTemp with the register value (LOAD-VAL),
  234. * the underflow has already happened, hence the PENDSTSET
  235. * is set, for this condition, we should compensate the return
  236. * value. When this happens, the (LOAD-nTemp) is bigger than (or
  237. * equals to) PERF_CNT_COMPENSATION_THRESHOLD.
  238. * The following code implements an equivalent logic.
  239. */
  240. if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk){
  241. if (((int32_t)SysTick->LOAD - nTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
  242. nTemp += SysTick->LOAD + 1;
  243. }
  244. }
  245. return nTemp;
  246. }
  247. void before_cycle_counter_reconfiguration(void)
  248. {
  249. __IRQ_SAFE {
  250. SysTick->CTRL = 0; /* disable SysTick first */
  251. if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) { /* pending SysTick exception */
  252. SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk; /* clear pending bit */
  253. user_code_insert_to_systick_handler(); /* manually handle exception */
  254. }
  255. s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
  256. SysTick->LOAD = 0UL;
  257. SysTick->VAL = 0UL; /* clear the Current Value Register */
  258. }
  259. }
  260. __attribute__((constructor))
  261. void __perf_counter_init(void)
  262. {
  263. init_cycle_counter(true);
  264. }
  265. void delay_us(int32_t nUs)
  266. {
  267. int64_t lUs = (int64_t)nUs * (int64_t)s_nUSUnit;
  268. int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
  269. ? g_nOffset
  270. : PERF_CNT_DELAY_US_COMPENSATION;
  271. if (lUs <= iCompensate) {
  272. return ;
  273. }
  274. lUs -= iCompensate;
  275. lUs += get_system_ticks();
  276. while(get_system_ticks() < lUs);
  277. }
  278. void delay_ms(int32_t nMs)
  279. {
  280. int64_t lUs = (int64_t)nMs * (int64_t)s_nMSUnit;
  281. int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
  282. ? g_nOffset
  283. : PERF_CNT_DELAY_US_COMPENSATION;
  284. if (lUs <= iCompensate) {
  285. return ;
  286. }
  287. lUs -= iCompensate;
  288. lUs += get_system_ticks();
  289. while(get_system_ticks() < lUs);
  290. }
  291. __attribute__((noinline))
  292. int64_t get_system_ticks(void)
  293. {
  294. int64_t lTemp = 0;
  295. __IRQ_SAFE {
  296. lTemp = check_systick() + s_lSystemClockCounts;
  297. /* When calling get_system_ticks() in an exception handler that has a
  298. * higher priority than the SysTick_Handler, in some rare cases, the
  299. * lTemp might be temporarily smaller than the previous value (i.e.
  300. * s_lOldTimestamp), to mitigate the adverse effects of this problem,
  301. * we use the following code to avoid time-rolling-back issue.
  302. *
  303. * NOTE: the issue mentioned above doesn't accumulate or have long-lasting
  304. * effects.
  305. */
  306. if (lTemp < s_lOldTimestamp) {
  307. lTemp = s_lOldTimestamp;
  308. } else {
  309. s_lOldTimestamp = lTemp;
  310. }
  311. }
  312. return lTemp;
  313. }
  314. /*! \note the prototype of this clock() is different from the one defined in
  315. *! time.h. As clock_t is usually defined as unsigned int, it is
  316. *! not big enough in Cortex-M system to hold a time-stamp. clock()
  317. *! defined here returns the timestamp since the begining of main()
  318. *! and its unit is clock cycle (rather than 1ms). Hence, for a system
  319. *! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
  320. *! NXP, it is very easy to see a counter overflow as clock_t is
  321. *! defined as uint32_t in timer.h.
  322. *! Since we are not allowed to change the defintion of clock_t in
  323. *! official header file, i.e. time.h, I use a compatible prototype
  324. *! after I checked the AAPCS spec. So, the return of the clock() is
  325. *! int64_t, which will use the R0 to store the lower 32bits and R1
  326. *! to store the higher 32bits. When you are using the prototype from
  327. *! timer.h, caller will only take the lower 32bits stored in R0 and
  328. *! the higher 32bits stored in R1 will be ignored.
  329. *!
  330. *! If you want to use the non-overflow version of this clock(), please
  331. *! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
  332. *! and 2) do not include system header file <time.h>
  333. *!
  334. */
  335. #if !defined(__IS_COMPILER_IAR__)
  336. __attribute__((nothrow))
  337. #endif
  338. __attribute__((noinline))
  339. int64_t clock(void)
  340. {
  341. return get_system_ticks();
  342. }
  343. int32_t get_system_ms(void)
  344. {
  345. int32_t nTemp = 0;
  346. __IRQ_SAFE {
  347. nTemp = s_nSystemMS + (check_systick() + s_nMSResidule) / s_nMSUnit;
  348. }
  349. return nTemp;
  350. }
  351. int32_t get_system_us(void)
  352. {
  353. int32_t nTemp = 0;
  354. __IRQ_SAFE {
  355. nTemp = s_nSystemUS + (check_systick() + s_nUSResidule) / s_nUSUnit;
  356. }
  357. return nTemp;
  358. }
  359. int64_t perfc_convert_ticks_to_ms(int64_t lTick)
  360. {
  361. return lTick / (int64_t)s_nMSUnit;
  362. }
  363. int64_t perfc_convert_ms_to_ticks(uint32_t wMS)
  364. {
  365. int64_t lResult = (int64_t)s_nMSUnit * (int64_t)wMS;
  366. return lResult ? lResult : 1;
  367. }
  368. int64_t perfc_convert_ticks_to_us(int64_t lTick)
  369. {
  370. return lTick / (int64_t)s_nUSUnit;
  371. }
  372. int64_t perfc_convert_us_to_ticks(uint32_t wMS)
  373. {
  374. int64_t lResult = (int64_t)s_nUSUnit * (int64_t)wMS;
  375. return lResult ? lResult : 1;
  376. }
  377. bool __perfc_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload)
  378. {
  379. if (NULL == plTimestamp) {
  380. return false;
  381. }
  382. int64_t lTimestamp = get_system_ticks();
  383. if (0 == *plTimestamp) {
  384. *plTimestamp = lPeriod;
  385. *plTimestamp += lTimestamp;
  386. return false;
  387. }
  388. if (lTimestamp >= *plTimestamp) {
  389. if (bAutoReload) {
  390. *plTimestamp = lPeriod + lTimestamp;
  391. }
  392. return true;
  393. }
  394. return false;
  395. }
  396. /// Setup timer hardware.
  397. /// \return status (1=Success, 0=Failure)
  398. uint32_t EventRecorderTimerSetup (void)
  399. {
  400. /* doing nothing at all */
  401. return 1;
  402. }
  403. /// Get timer frequency.
  404. /// \return timer frequency in Hz
  405. uint32_t EventRecorderTimerGetFreq (void)
  406. {
  407. return SystemCoreClock;
  408. }
  409. /// Get timer count.
  410. /// \return timer count (32-bit)
  411. uint32_t EventRecorderTimerGetCount (void)
  412. {
  413. return get_system_ticks();
  414. }
  415. __WEAK
  416. task_cycle_info_t * get_rtos_task_cycle_info(void)
  417. {
  418. return NULL;
  419. }
  420. void init_task_cycle_counter(void)
  421. {
  422. struct __task_cycle_info_t * ptRootAgent =
  423. (struct __task_cycle_info_t *)get_rtos_task_cycle_info();
  424. if (NULL == ptRootAgent) {
  425. return ;
  426. }
  427. memset(ptRootAgent, 0, sizeof(struct __task_cycle_info_t));
  428. ptRootAgent->tList.ptInfo = &(ptRootAgent->tInfo);
  429. ptRootAgent->tInfo.lStart = get_system_ticks();
  430. ptRootAgent->wMagicWord = MAGIC_WORD_CANARY;
  431. }
  432. bool perfc_check_task_stack_canary_safe(void)
  433. {
  434. struct __task_cycle_info_t * ptRootAgent =
  435. (struct __task_cycle_info_t *)get_rtos_task_cycle_info();
  436. do {
  437. if (NULL == ptRootAgent) {
  438. break;
  439. }
  440. if ( (MAGIC_WORD_CANARY == ptRootAgent->wMagicWord)
  441. || (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord)) {
  442. return true;
  443. }
  444. } while(0);
  445. return false;
  446. }
  447. task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo)
  448. {
  449. do {
  450. if (NULL == ptInfo) {
  451. break;
  452. }
  453. memset(ptInfo, 0, sizeof(task_cycle_info_t));
  454. ptInfo->bEnabled = true;
  455. } while(0);
  456. return ptInfo;
  457. }
  458. bool enable_task_cycle_info(task_cycle_info_t *ptInfo)
  459. {
  460. if (NULL == ptInfo) {
  461. return false;
  462. }
  463. bool bOrig;
  464. __IRQ_SAFE {
  465. bOrig = ptInfo->bEnabled;
  466. ptInfo->bEnabled = true;
  467. }
  468. return bOrig;
  469. }
  470. bool disable_task_cycle_info(task_cycle_info_t *ptInfo)
  471. {
  472. if (NULL == ptInfo) {
  473. return false;
  474. }
  475. bool bOrig;
  476. __IRQ_SAFE {
  477. bOrig = ptInfo->bEnabled;
  478. ptInfo->bEnabled = false;
  479. }
  480. return bOrig;
  481. }
  482. void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus)
  483. {
  484. if (NULL == ptInfo) {
  485. return;
  486. }
  487. ptInfo->bEnabled = bEnabledStatus;
  488. }
  489. task_cycle_info_agent_t *register_task_cycle_agent(task_cycle_info_t *ptInfo,
  490. task_cycle_info_agent_t *ptAgent)
  491. {
  492. __IRQ_SAFE {
  493. do {
  494. if (NULL == ptAgent || NULL == ptInfo) {
  495. break;
  496. }
  497. struct __task_cycle_info_t * ptRootAgent =
  498. (struct __task_cycle_info_t *)get_rtos_task_cycle_info();
  499. if (NULL == ptRootAgent) {
  500. break;
  501. }
  502. ptRootAgent->wMagicWord = MAGIC_WORD_AGENT_LIST_VALID;
  503. ptAgent->ptInfo = ptInfo;
  504. // push to the stack
  505. do {
  506. // set next-list
  507. ptAgent->ptNext = ptRootAgent->tList.ptNext;
  508. ptRootAgent->tList.ptNext = ptAgent;
  509. // set prev-list
  510. ptAgent->ptPrev = &(ptRootAgent->tList);
  511. if (NULL != ptAgent->ptNext) {
  512. ptAgent->ptNext->ptPrev = ptAgent;
  513. }
  514. } while(0);
  515. } while(0);
  516. }
  517. return ptAgent;
  518. }
  519. task_cycle_info_agent_t *
  520. unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent)
  521. {
  522. __IRQ_SAFE {
  523. do {
  524. if (NULL == ptAgent) {
  525. break;
  526. }
  527. task_cycle_info_agent_t *ptPrev = ptAgent->ptPrev;
  528. if (NULL == ptPrev) {
  529. break; /* this should not happen */
  530. }
  531. if (ptPrev->ptNext != ptAgent) {
  532. // already removed
  533. break;
  534. }
  535. //! remove agent from the next-list
  536. ptPrev->ptNext = ptAgent->ptNext;
  537. if (NULL != ptAgent->ptNext) {
  538. // remove agent from the prev-list
  539. ptAgent->ptNext->ptPrev = ptPrev;
  540. }
  541. ptAgent->ptNext = NULL;
  542. ptAgent->ptPrev = NULL;
  543. } while(0);
  544. }
  545. return ptAgent;
  546. }
  547. void __on_context_switch_in(uint32_t *pwStack)
  548. {
  549. struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *)pwStack;
  550. int64_t lTimeStamp = get_system_ticks();
  551. ptRootAgent->lLastTimeStamp = lTimeStamp;
  552. ptRootAgent->tInfo.hwActiveCount++;
  553. if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
  554. // update all agents
  555. task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
  556. while(NULL != ptAgent) {
  557. if (NULL != ptAgent->ptInfo) {
  558. if (ptAgent->ptInfo->bEnabled) {
  559. ptAgent->ptInfo->hwActiveCount++;
  560. }
  561. }
  562. ptAgent = ptAgent->ptNext;
  563. }
  564. }
  565. }
  566. void __on_context_switch_out(uint32_t *pwStack)
  567. {
  568. struct __task_cycle_info_t *ptRootAgent = (struct __task_cycle_info_t *)pwStack;
  569. int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
  570. ptRootAgent->tInfo.nUsedRecent = lCycleUsed;
  571. ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
  572. if (MAGIC_WORD_AGENT_LIST_VALID == ptRootAgent->wMagicWord) {
  573. // update all agents
  574. task_cycle_info_agent_t *ptAgent = ptRootAgent->tList.ptNext;
  575. while(NULL != ptAgent) {
  576. if (NULL != ptAgent->ptInfo) {
  577. if (ptAgent->ptInfo->bEnabled) {
  578. ptAgent->ptInfo->nUsedRecent = lCycleUsed;
  579. ptAgent->ptInfo->lUsedTotal += lCycleUsed;
  580. }
  581. }
  582. ptAgent = ptAgent->ptNext;
  583. }
  584. }
  585. }
  586. __attribute__((noinline))
  587. void __start_task_cycle_counter(task_cycle_info_t *ptInfo)
  588. {
  589. struct __task_cycle_info_t * ptRootAgent =
  590. (struct __task_cycle_info_t *)get_rtos_task_cycle_info();
  591. if (NULL == ptRootAgent) {
  592. return ;
  593. }
  594. __IRQ_SAFE {
  595. ptRootAgent->lLastTimeStamp = get_system_ticks();
  596. ptRootAgent->tInfo.lUsedTotal = 0;
  597. if (NULL != ptInfo) {
  598. ptInfo->lUsedTotal = 0;
  599. ptInfo->bEnabled = true;
  600. }
  601. }
  602. }
  603. __attribute__((noinline))
  604. int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo)
  605. {
  606. struct __task_cycle_info_t * ptRootAgent =
  607. (struct __task_cycle_info_t *)get_rtos_task_cycle_info();
  608. if (NULL == ptRootAgent) {
  609. return 0;
  610. }
  611. int64_t lCycles = 0;
  612. __IRQ_SAFE {
  613. int64_t lCycleUsed = get_system_ticks() - ptRootAgent->lLastTimeStamp - g_nOffset;
  614. ptRootAgent->tInfo.lUsedTotal += lCycleUsed;
  615. if (NULL != ptInfo) {
  616. if (ptInfo->bEnabled) {
  617. ptInfo->nUsedRecent = lCycleUsed;
  618. ptInfo->lUsedTotal += lCycleUsed;
  619. ptInfo->bEnabled = false;
  620. }
  621. lCycles = ptInfo->lUsedTotal;
  622. } else {
  623. lCycles = ptRootAgent->tInfo.lUsedTotal;
  624. }
  625. }
  626. return lCycles;
  627. }