perf_counter.c 28 KB

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