perf_counter.h 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  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. #ifndef __PERFORMANCE_COUNTER_H__
  18. #define __PERFORMANCE_COUNTER_H__
  19. /*============================ INCLUDES ======================================*/
  20. #include <stdbool.h>
  21. #include <stdint.h>
  22. #include <stddef.h>
  23. #include "cmsis_compiler.h"
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. /*============================ MACROS ========================================*/
  28. /*!
  29. * \addtogroup gBasic 1 Basic
  30. * @{
  31. */
  32. #define __PERF_COUNTER_VER_MAJOR__ 2
  33. #define __PERF_COUNTER_VER_MINOR__ 2
  34. #define __PERF_COUNTER_VER_REVISE__ 4
  35. #define __PERF_COUNTER_VER_STR__ ""
  36. #define __PER_COUNTER_VER__ (__PERF_COUNTER_VER_MAJOR__ * 10000ul \
  37. +__PERF_COUNTER_VER_MINOR__ * 100ul \
  38. +__PERF_COUNTER_VER_REVISE__)
  39. /*! @} */
  40. /*!
  41. * \addtogroup gHelper 4 Helper
  42. * @{
  43. */
  44. // for IAR
  45. #undef __IS_COMPILER_IAR__
  46. #if defined(__IAR_SYSTEMS_ICC__)
  47. # define __IS_COMPILER_IAR__ 1
  48. #endif
  49. // for arm compiler 5
  50. #undef __IS_COMPILER_ARM_COMPILER_5__
  51. #if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
  52. # define __IS_COMPILER_ARM_COMPILER_5__ 1
  53. #endif
  54. //for arm compiler 6
  55. #undef __IS_COMPILER_ARM_COMPILER_6__
  56. #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
  57. # define __IS_COMPILER_ARM_COMPILER_6__ 1
  58. #endif
  59. #undef __IS_COMPILER_ARM_COMPILER__
  60. #if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
  61. || defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
  62. # define __IS_COMPILER_ARM_COMPILER__ 1
  63. #endif
  64. // for clang
  65. #undef __IS_COMPILER_LLVM__
  66. #if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
  67. # define __IS_COMPILER_LLVM__ 1
  68. #else
  69. // for gcc
  70. # undef __IS_COMPILER_GCC__
  71. # if defined(__GNUC__) && !( defined(__IS_COMPILER_ARM_COMPILER__) \
  72. || defined(__IS_COMPILER_LLVM__) \
  73. || defined(__IS_COMPILER_IAR__))
  74. # define __IS_COMPILER_GCC__ 1
  75. # endif
  76. #endif
  77. #ifdef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
  78. # include __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
  79. #endif
  80. #if defined(__clang__)
  81. # pragma clang diagnostic push
  82. # pragma clang diagnostic ignored "-Wunknown-warning-option"
  83. # pragma clang diagnostic ignored "-Wreserved-identifier"
  84. # pragma clang diagnostic ignored "-Wdeclaration-after-statement"
  85. # pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
  86. # pragma clang diagnostic ignored "-Wgnu-statement-expression"
  87. # pragma clang diagnostic ignored "-Wunused-but-set-variable"
  88. # pragma clang diagnostic ignored "-Wshadow"
  89. # pragma clang diagnostic ignored "-Wshorten-64-to-32"
  90. # pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
  91. # pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
  92. #elif defined(__IS_COMPILER_ARM_COMPILER_5__)
  93. # pragma diag_suppress 550
  94. #elif defined(__IS_COMPILER_GCC__)
  95. # pragma GCC diagnostic push
  96. # pragma GCC diagnostic ignored "-Wpedantic"
  97. # pragma GCC diagnostic ignored "-Wunused-variable"
  98. # pragma GCC diagnostic ignored "-Wunused-but-set-variable"
  99. # pragma GCC diagnostic ignored "-Wformat="
  100. #endif
  101. #ifndef __PLOOC_VA_NUM_ARGS_IMPL
  102. # define __PLOOC_VA_NUM_ARGS_IMPL( _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11, \
  103. _12,_13,_14,_15,_16,__N,...) __N
  104. #endif
  105. #ifndef __PLOOC_VA_NUM_ARGS
  106. #define __PLOOC_VA_NUM_ARGS(...) \
  107. __PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
  108. 8,7,6,5,4,3,2,1,0)
  109. #endif
  110. #ifndef UNUSED_PARAM
  111. # define UNUSED_PARAM(__VAR) (void)(__VAR)
  112. #endif
  113. #undef __CONNECT2
  114. #undef __CONNECT3
  115. #undef __CONNECT4
  116. #undef __CONNECT5
  117. #undef __CONNECT6
  118. #undef __CONNECT7
  119. #undef __CONNECT8
  120. #undef __CONNECT9
  121. #undef CONNECT2
  122. #undef CONNECT3
  123. #undef CONNECT4
  124. #undef CONNECT5
  125. #undef CONNECT6
  126. #undef CONNECT7
  127. #undef CONNECT8
  128. #undef CONNECT9
  129. #undef CONNECT
  130. #undef __MACRO_EXPANDING
  131. #define __MACRO_EXPANDING(...) __VA_ARGS__
  132. #define __CONNECT2(__A, __B) __A##__B
  133. #define __CONNECT3(__A, __B, __C) __A##__B##__C
  134. #define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
  135. #define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
  136. #define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
  137. #define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
  138. __A##__B##__C##__D##__E##__F##__G
  139. #define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
  140. __A##__B##__C##__D##__E##__F##__G##__H
  141. #define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
  142. __A##__B##__C##__D##__E##__F##__G##__H##__I
  143. #define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
  144. #define CONNECT2(__A, __B) __CONNECT2(__A, __B)
  145. #define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
  146. #define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
  147. #define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
  148. #define CONNECT6(__A, __B, __C, __D, __E, __F) \
  149. __CONNECT6(__A, __B, __C, __D, __E, __F)
  150. #define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
  151. __CONNECT7(__A, __B, __C, __D, __E, __F, __G)
  152. #define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
  153. __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
  154. #define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
  155. __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
  156. #define CONNECT(...) \
  157. ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
  158. #undef __using1
  159. #undef __using2
  160. #undef __using3
  161. #undef __using4
  162. #undef using
  163. #define __using1(__declare) \
  164. for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
  165. CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
  166. )
  167. #define __using2(__declare, __on_leave_expr) \
  168. for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
  169. CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
  170. (__on_leave_expr) \
  171. )
  172. #define __using3(__declare, __on_enter_expr, __on_leave_expr) \
  173. for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
  174. CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
  175. ((__on_enter_expr),1) : 0; \
  176. (__on_leave_expr) \
  177. )
  178. #define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
  179. for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
  180. CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
  181. ((__on_enter_expr),1) : 0; \
  182. (__on_leave_expr) \
  183. )
  184. #define using(...) \
  185. CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
  186. #undef __with2
  187. #undef __with3
  188. #undef with
  189. #define __with2(__type, __addr) \
  190. using(__type *_=(__addr))
  191. #define __with3(__type, __addr, __item) \
  192. using(__type *_=(__addr), *__item = _, _=_,_=_ )
  193. #define with(...) \
  194. CONNECT2(__with, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
  195. #undef _
  196. #ifndef dimof
  197. # define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
  198. #endif
  199. #define SAFE_NAME(__NAME) CONNECT3(__,__NAME,__LINE__)
  200. #undef foreach2
  201. #undef foreach3
  202. #undef foreach
  203. #define foreach2(__type, __array) \
  204. using(__type *_ = __array) \
  205. for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
  206. SAFE_NAME(count) > 0; \
  207. _++, SAFE_NAME(count)-- \
  208. )
  209. #define foreach3(__type, __array, __item) \
  210. using(__type *_ = __array, *__item = _, _ = _, _ = _ ) \
  211. for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
  212. SAFE_NAME(count) > 0; \
  213. _++, __item = _, SAFE_NAME(count)-- \
  214. )
  215. #define foreach(...) \
  216. CONNECT2(foreach, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
  217. #ifndef safe_atom_code
  218. # define safe_atom_code() \
  219. using( uint32_t SAFE_NAME(temp) = \
  220. ({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
  221. __disable_irq(); \
  222. SAFE_NAME(temp2);}), \
  223. __set_PRIMASK(SAFE_NAME(temp)))
  224. #endif
  225. #ifndef __IRQ_SAFE
  226. # define __IRQ_SAFE \
  227. using( uint32_t SAFE_NAME(temp) = \
  228. ({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
  229. __disable_irq(); \
  230. SAFE_NAME(temp2);}), \
  231. __set_PRIMASK(SAFE_NAME(temp)))
  232. #endif
  233. #ifndef __perf_counter_printf__
  234. # define __perf_counter_printf__ printf
  235. #endif
  236. #if __PLOOC_VA_NUM_ARGS() != 0
  237. #warning Please enable GNU extensions, it is required by __cycleof__() and \
  238. __super_loop_monitor__()
  239. #endif
  240. #if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__)
  241. # if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__
  242. # pragma import(__ensure_systick_wrapper)
  243. # elif (defined(__GNUC__) || defined(__clang__)) \
  244. && (!defined(__IS_COMPILER_IAR__) || !__IS_COMPILER_IAR__)
  245. __asm(".global __ensure_systick_wrapper\n\t");
  246. # endif
  247. #endif
  248. /*! @} */
  249. /*============================ MACROFIED FUNCTIONS ===========================*/
  250. /*!
  251. * \addtogroup gBasic 1 Basic
  252. * @{
  253. */
  254. /*!
  255. * \brief measure the cycle count of a given code segment
  256. * \param[in] __STR a description string for the measurement
  257. * \param[in] ... an optional code segement, in which we can read the measured
  258. * result from __cycle_count__.
  259. * \details Here is an example:
  260. E.g.
  261. \code
  262. __cycleof__("printf") {
  263. printf("hello world\r\n");
  264. }
  265. \endcode
  266. */
  267. #define __cycleof__(__STR, ...) \
  268. using(int64_t _ = get_system_ticks(), __cycle_count__ = _, \
  269. _=_, { \
  270. _ = get_system_ticks() - _ - g_nOffset; \
  271. __cycle_count__ = _; \
  272. if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
  273. __perf_counter_printf__("\r\n"); \
  274. __perf_counter_printf__("-[Cycle Report]"); \
  275. __perf_counter_printf__( \
  276. "--------------------------------------------\r\n"); \
  277. __perf_counter_printf__( \
  278. __STR " total cycle count: %ld [%016lx]\r\n", \
  279. (long)_, (long)_); \
  280. } else { \
  281. __VA_ARGS__ \
  282. }; \
  283. })
  284. /*!
  285. * \brief measure the cpu usage for a given code segment and print out the
  286. * result in percentage.
  287. * \param[in] __CNT generate result on every given iterations
  288. * \param[in] ... an optional code segement, in which we can read the measured
  289. * result from __usage__ which is a float value.
  290. * \details Here is an example, 50% cpu time:
  291. E.g.
  292. \code
  293. while (1) {
  294. __cpu_time__(100) {
  295. delay_us(5000);
  296. }
  297. delay_us(5000);
  298. }
  299. \endcode
  300. */
  301. #define __cpu_time__(__CNT, ...) \
  302. static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
  303. static uint32_t s_wLoopCounter = (__CNT); \
  304. using(float __usage__ = 0, ({ \
  305. if (0 == s_wLoopCounter) { \
  306. __usage__ = (float)((double)SAFE_NAME(s_lTotal) \
  307. / (double)( get_system_ticks() \
  308. - SAFE_NAME(s_lTimestamp))); \
  309. __usage__ *= 100.0f; \
  310. SAFE_NAME(s_lTimestamp) = 0; \
  311. SAFE_NAME(s_lTotal) = 0; \
  312. if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
  313. __perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__); \
  314. } else { \
  315. __VA_ARGS__ \
  316. } \
  317. } \
  318. if (0 == SAFE_NAME(s_lTimestamp)) { \
  319. SAFE_NAME(s_lTimestamp) = get_system_ticks(); \
  320. s_wLoopCounter = (__CNT); \
  321. } \
  322. start_task_cycle_counter();}), \
  323. ({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
  324. s_wLoopCounter--;}))
  325. /*!
  326. * \addtogroup gBasicTimerService 1.2 Timer Service
  327. * \ingroup gBasic
  328. * @{
  329. */
  330. /*!
  331. * \brief should not use
  332. */
  333. #define perfc_is_time_out_ms0() true
  334. /*!
  335. * \brief set an alarm with given period in ms and check the status
  336. *
  337. * \param[in] __ms a time period in millisecond
  338. * \param[in] __timestamp_ptr an optional timestamp holder
  339. * \param[in] __auto_reload whether starting next period after a timeout event
  340. *
  341. * \return bool whether it is timeout
  342. */
  343. #define perfc_is_time_out_ms3(__ms, __timestamp_ptr, __auto_reload) \
  344. ({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
  345. __perfc_is_time_out(perfc_convert_ms_to_ticks(__ms), \
  346. (__timestamp_ptr), (__auto_reload));})
  347. /*!
  348. * \brief set an alarm with given period in ms and check the status
  349. *
  350. * \param[in] __ms a time period in millisecond
  351. * \param[in] __timestamp_ptr an optional timestamp holder
  352. *
  353. * \return bool whether it is timeout
  354. */
  355. #define perfc_is_time_out_ms2(__ms, __timestamp_ptr) \
  356. perfc_is_time_out_ms3((__ms), (__timestamp_ptr), true)
  357. /*!
  358. * \brief set an alarm with given period in ms and check the status
  359. *
  360. * \param[in] __ms a time period in millisecond
  361. * \param[in] __timestamp_ptr an optional timestamp holder
  362. *
  363. * \return bool whether it is timeout
  364. */
  365. #define perfc_is_time_out_ms1(__ms) \
  366. perfc_is_time_out_ms3((__ms), &SAFE_NAME(s_lTimestamp), true)
  367. /*!
  368. * \brief set an alarm with given period in ms and check the status
  369. *
  370. * \param[in] __ms a time period in millisecond
  371. * \param[in] ... an optional timestamp holder
  372. * \param[in] ... an optional indicator for whether starting next period after a timeout event
  373. *
  374. * \return bool whether it is timeout
  375. */
  376. #define perfc_is_time_out_ms(...) \
  377. CONNECT2(perfc_is_time_out_ms, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
  378. (__VA_ARGS__)
  379. /*!
  380. * \brief set an alarm with given period in us and check the status
  381. *
  382. * \param[in] __us a time period in microsecond
  383. * \param[in] __timestamp_ptr an optional timestamp holder
  384. * \param[in] __auto_reload whether starting next period after a timeout event
  385. *
  386. * \return bool whether it is timeout
  387. */
  388. #define perfc_is_time_out_us3(__us, __timestamp_ptr, __auto_reload) \
  389. ({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
  390. __perfc_is_time_out(perfc_convert_us_to_ticks(__us), \
  391. (__timestamp_ptr), (__auto_reload));})
  392. /*!
  393. * \brief set an alarm with given period in us and check the status
  394. *
  395. * \param[in] __us a time period in microsecond
  396. * \param[in] __timestamp_ptr an optional timestamp holder
  397. *
  398. * \return bool whether it is timeout
  399. */
  400. #define perfc_is_time_out_us2(__us, __timestamp_ptr) \
  401. perfc_is_time_out_us3((__us), (__timestamp_ptr), true)
  402. /*!
  403. * \brief set an alarm with given period in us and check the status
  404. *
  405. * \param[in] __us a time period in microsecond
  406. * \param[in] __timestamp_ptr an optional timestamp holder
  407. *
  408. * \return bool whether it is timeout
  409. */
  410. #define perfc_is_time_out_us1(__us) \
  411. perfc_is_time_out_us3((__us), &SAFE_NAME(s_lTimestamp), true)
  412. /*!
  413. * \brief set an alarm with given period in us and check the status
  414. *
  415. * \param[in] __us a time period in microsecond
  416. * \param[in] ... an optional timestamp holder
  417. * \param[in] ... an optional indicator for whether starting next period after a timeout event
  418. *
  419. * \return bool whether it is timeout
  420. */
  421. #define perfc_is_time_out_us(...) \
  422. CONNECT2(perfc_is_time_out_us, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
  423. (__VA_ARGS__)
  424. /*! @} */
  425. /*! @} */
  426. /*!
  427. * \addtogroup gRTOS 2 RTOS Support
  428. * @{
  429. */
  430. #define __super_loop_monitor__(__N, ...) \
  431. using( \
  432. struct { \
  433. int64_t lStart; \
  434. int64_t lTaskUsedCycles; \
  435. int64_t lTimeElapsed; \
  436. } __cpu_usage__ = {.lStart = get_system_ticks()}) \
  437. using(int SAFE_NAME(cnt) = (__N)) \
  438. for(start_task_cycle_counter();; ({ \
  439. if (!(--SAFE_NAME(cnt))) { \
  440. __cpu_usage__.lTimeElapsed \
  441. = get_system_ticks() - __cpu_usage__.lStart - g_nOffset; \
  442. __cpu_usage__.lTaskUsedCycles = stop_task_cycle_counter(); \
  443. \
  444. if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
  445. __perf_counter_printf__( \
  446. "%s CPU Usage %2.3f%%\r\n", __func__, \
  447. (float)((double)__cpu_usage__.lTaskUsedCycles * 100.0 / \
  448. (double)__cpu_usage__.lTimeElapsed)); \
  449. } else { \
  450. __VA_ARGS__; \
  451. } \
  452. SAFE_NAME(cnt) = (__N); \
  453. __cpu_usage__.lStart = get_system_ticks(); \
  454. start_task_cycle_counter(); \
  455. }; \
  456. }))
  457. /*============================ TYPES =========================================*/
  458. typedef struct {
  459. int64_t lStart;
  460. int64_t lUsedTotal;
  461. int32_t nUsedRecent;
  462. uint16_t hwActiveCount;
  463. uint16_t : 15;
  464. uint16_t bEnabled : 1;
  465. } task_cycle_info_t;
  466. typedef struct task_cycle_info_agent_t task_cycle_info_agent_t;
  467. struct task_cycle_info_agent_t {
  468. task_cycle_info_t *ptInfo;
  469. task_cycle_info_agent_t *ptNext;
  470. task_cycle_info_agent_t *ptPrev;
  471. };
  472. /*! @} */
  473. /*============================ GLOBAL VARIABLES ==============================*/
  474. extern volatile int64_t g_lLastTimeStamp;
  475. extern volatile int32_t g_nOffset;
  476. /*============================ LOCAL VARIABLES ===============================*/
  477. /*============================ PROTOTYPES ====================================*/
  478. /*!
  479. * \addtogroup gBasicTicks 1.1 Ticks APIs
  480. * \ingroup gBasic
  481. * @{
  482. */
  483. /*!
  484. * \brief get the elapsed cycles since perf_counter is initialised
  485. * \return int64_t the elpased cycles
  486. */
  487. __attribute__((noinline))
  488. extern int64_t get_system_ticks(void);
  489. #ifdef __PERF_CNT_USE_LONG_CLOCK__
  490. /*! \note the prototype of this clock() is different from the one defined in
  491. *! time.h. As clock_t is usually defined as unsigned int, it is
  492. *! not big enough in Cortex-M system to hold a time-stamp. clock()
  493. *! defined here returns the timestamp since the begining of main()
  494. *! and its unit is clock cycle (rather than 1ms). Hence, for a system
  495. *! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
  496. *! NXP, it is very easy to see a counter overflow as clock_t is
  497. *! defined as uint32_t in timer.h.
  498. *! Since we are not allowed to change the defintion of clock_t in
  499. *! official header file, i.e. time.h, I use a compatible prototype
  500. *! after I checked the AAPCS spec. So, the return of the clock() is
  501. *! int64_t, which will use the R0 to store the lower 32bits and R1
  502. *! to store the higher 32bits. When you are using the prototype from
  503. *! timer.h, caller will only take the lower 32bits stored in R0 and
  504. *! the higher 32bits stored in R1 will be ignored.
  505. *!
  506. *! If you want to use the non-overflow version of this clock(), please
  507. *! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
  508. *! and 2) do not include system header file <time.h>
  509. *!
  510. */
  511. #if !defined(__IS_COMPILER_IAR__)
  512. __attribute__((nothrow))
  513. #endif
  514. __attribute__((noinline))
  515. extern int64_t clock(void);
  516. #endif
  517. /*!
  518. * \brief try to set a start pointer for the performance counter
  519. */
  520. __STATIC_INLINE
  521. void start_cycle_counter(void)
  522. {
  523. g_lLastTimeStamp = get_system_ticks();
  524. }
  525. /*!
  526. * \brief calculate the elapsed cycle count since the last start point
  527. * \note you can have multiple stop_cycle_counter following one start point
  528. * \return int32_t the elapsed cycle count
  529. */
  530. __STATIC_INLINE
  531. int64_t stop_cycle_counter(void)
  532. {
  533. int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
  534. return lTemp - g_nOffset;
  535. }
  536. /*! @} */
  537. /*!
  538. * \addtogroup gBasicTimerService 1.2 Timer Service
  539. * \ingroup gBasic
  540. * @{
  541. */
  542. /*!
  543. * \brief get the elapsed milliseconds since perf_counter is initialised
  544. * \return int32_t the elapsed milliseconds
  545. */
  546. extern int32_t get_system_ms(void);
  547. /*!
  548. * \brief get the elapsed microsecond since perf_counter is initialised
  549. * \return int32_t the elapsed microsecond
  550. */
  551. extern int32_t get_system_us(void);
  552. /*!
  553. * \brief delay specified time in microsecond
  554. * \param[in] nUs time in microsecond
  555. */
  556. extern void delay_us(int32_t nUs);
  557. /*!
  558. * \brief delay specified time in millisecond
  559. * \param[in] nMs time in millisecond
  560. */
  561. extern void delay_ms(int32_t nMs);
  562. /*!
  563. * \brief convert ticks of a reference timer to millisecond
  564. *
  565. * \param[in] lTick the tick count
  566. * \return int64_t the millisecond
  567. */
  568. extern
  569. int64_t perfc_convert_ticks_to_ms(int64_t lTick);
  570. /*!
  571. * \brief convert millisecond into ticks of the reference timer
  572. *
  573. * \param[in] wMS the target time in millisecond
  574. * \return int64_t the ticks
  575. */
  576. extern
  577. int64_t perfc_convert_ms_to_ticks(uint32_t wMS);
  578. /*!
  579. * \brief convert ticks of a reference timer to microsecond
  580. *
  581. * \param[in] lTick the tick count
  582. * \return int64_t the microsecond
  583. */
  584. extern
  585. int64_t perfc_convert_ticks_to_us(int64_t lTick);
  586. /*!
  587. * \brief convert microsecond into ticks of the reference timer
  588. *
  589. * \param[in] wUS the target time in microsecond
  590. * \return int64_t the ticks
  591. */
  592. extern
  593. int64_t perfc_convert_us_to_ticks(uint32_t wUS);
  594. /*!
  595. * \brief set an alarm with given period and check the status
  596. *
  597. * \param[in] lPeriod a time period in ticks
  598. * \param[in] plTimestamp a pointer points to an int64_t integer, if NULL is
  599. * passed, an static local variable inside the function will be used
  600. * \param[in] bAutoReload whether starting next period after a timeout event.
  601. * \return bool whether it is timeout or not
  602. */
  603. extern
  604. bool __perfc_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload);
  605. /*! @} */
  606. /*!
  607. * \addtogroup gRTOS 2 RTOS Support
  608. * @{
  609. */
  610. #if defined(__PERF_CNT_USE_RTOS__)
  611. /*! \brief initialize the default virtual cycle counter for the current task
  612. */
  613. extern void init_task_cycle_counter(void);
  614. /*! \brief check whether the task stack canary is safe or not
  615. * \retval false likely to be a stack-overflow
  616. * \retval true task stack is safe
  617. */
  618. extern
  619. bool perfc_check_task_stack_canary_safe(void);
  620. /*! \brief provide cycle information for target task
  621. * \details Support RTOS List:
  622. * - RTX5
  623. * - RT-Thread
  624. * - ThreadX
  625. * - FreeRTOS
  626. *
  627. * \return task_cycle_info_t* the cycle info object passed to this function
  628. */
  629. extern task_cycle_info_t * get_rtos_task_cycle_info(void);
  630. /*!
  631. * \brief intialize a given task_cycle_info_t object and enable it before
  632. * registering it.
  633. * \return task_cycle_info_t* the cycle info object passed to this function
  634. */
  635. extern task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo);
  636. /*! \brief enable a given task_cycle_info_t object
  637. *
  638. * \param[in] ptInfo the address of target task_cycle_info_t object
  639. * \return bool previous status
  640. */
  641. extern bool enable_task_cycle_info(task_cycle_info_t *ptInfo);
  642. /*! \brief disable a given task_cycle_info_t object
  643. *
  644. * \param[in] ptInfo the address of target task_cycle_info_t object
  645. * \return bool previous status
  646. */
  647. extern bool disable_task_cycle_info(task_cycle_info_t *ptInfo);
  648. /*! \brief resume the enabled status of a given task_cycle_info_t object
  649. *
  650. * \param[in] ptInfo the address of target task_cycle_info_t object
  651. * \param[in] bEnabledStatus the previous status
  652. */
  653. extern
  654. void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus);
  655. /*!
  656. * \brief register a global virtual cycle counter agent to the current task
  657. * \param[in] ptInfo the address of target task_cycle_info_t object
  658. * \param[in] ptAgent an list node for the task_cycle_info_t object
  659. * \note the ptAgent it is better to be allocated as a static variable, global
  660. * variable or comes from heap or pool
  661. *
  662. * \return task_cycle_info_agent_t* the agent passed to this function
  663. */
  664. extern
  665. task_cycle_info_agent_t *register_task_cycle_agent(
  666. task_cycle_info_t *ptInfo,
  667. task_cycle_info_agent_t *ptAgent);
  668. /*!
  669. * \brief remove a global virtual cycle counter agent from the current task
  670. * \param[in] ptAgent the list node currently in use
  671. * \return task_cycle_info_agent_t* the agent passed to this function
  672. */
  673. extern
  674. task_cycle_info_agent_t *
  675. unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent);
  676. /*! \brief reset and start the virtual cycle counter for the current task
  677. *
  678. * \param[in] ptInfo the target task_cycle_info_t object
  679. */
  680. __attribute__((noinline))
  681. extern void __start_task_cycle_counter(task_cycle_info_t *ptInfo);
  682. /*! \brief calculate the elapsed cycle count for current task since the last
  683. * start point
  684. *
  685. * \note you can call stop_cycle_counter() multiple times following one
  686. * start_task_cycle_counter()
  687. *
  688. * \param[in] ptInfo the target task_cycle_info_t object
  689. *
  690. * \note When ptInfo is NULL, it returns current task cycle info, when ptInfo
  691. * is non-NULL, it returns the total used cycles of the specified
  692. * task_cycle_info_t object.
  693. *
  694. * \return int64_t the elapsed cycle count.
  695. */
  696. __attribute__((noinline))
  697. extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
  698. #define start_task_cycle_counter(...) \
  699. __start_task_cycle_counter((NULL,##__VA_ARGS__))
  700. #define stop_task_cycle_counter(...) \
  701. __stop_task_cycle_counter((NULL,##__VA_ARGS__))
  702. #elif !defined(__IMPLEMENT_PERF_COUNTER)
  703. # define start_task_cycle_counter(...) start_cycle_counter()
  704. # define stop_task_cycle_counter(...) stop_cycle_counter()
  705. # define init_task_cycle_counter()
  706. # define register_task_cycle_agent(...)
  707. # define unregister_task_cycle_agent(...)
  708. # define init_task_cycle_info(...) (NULL)
  709. # define enable_task_cycle_info(...) (false)
  710. # define disable_task_cycle_info(...) (false)
  711. # define resume_task_cycle_info(...)
  712. # define perfc_check_task_stack_canary_safe() (false)
  713. #endif
  714. /*! @} */
  715. /*!
  716. * \addtogroup gBasic 1 Basic
  717. * @{
  718. */
  719. /*----------------------------------------------------------------------------*
  720. * Please ignore the following APIs unless you have encountered some known *
  721. * special conditions *
  722. *----------------------------------------------------------------------------*/
  723. /*! \brief initialise cycle counter service
  724. * \note - don't forget to tell the function whether the systick is already
  725. * used by user applications.
  726. * Don't worry, this cycle counter service won't affect your existing
  727. * systick service.
  728. *
  729. * \note - Usually the perf_counter can initialise itself with the help of
  730. * __attribute__((constructor(255))), this works fine in Arm Compiler
  731. * 5 (armcc), Arm Compiler 6 (armclang), arm gcc and llvm. It doesn't
  732. * work for IAR. So, when you are using IAR, please call this function
  733. * manually to initialise the perf_counter service.
  734. *
  735. * \note - Perf_counter library assumes that:
  736. * 1. Your project has already using SysTick
  737. * 2. It assumes that you have already implemented the SysTick_Handler
  738. * 3. It assumes that you have enabled the exception handling for
  739. * SysTick.
  740. * If these are not the case, please:
  741. * 1. Add an empty SysTick_Handler to your project if you don't have
  742. * one
  743. * 2. Make sure you have the SysTick Exception handling enabled
  744. * 3. And call function init_cycle_counter(false) if you doesn't
  745. * use SysTick in your project at all.
  746. *
  747. * \param[in] bIsSysTickOccupied A boolean value which indicates whether SysTick
  748. * is already used by user application.
  749. */
  750. extern void init_cycle_counter(bool bIsSysTickOccupied);
  751. /*!
  752. * \brief a system timer handler inserted to the SysTick_Handler
  753. *
  754. * \note - if you are using a compiler other than armcc or armclang, e.g. iar,
  755. * arm gcc etc, the systick_wrapper_ual.o doesn't work with the linker
  756. * of your target toolchain as it use the $Super$$ which is only supported
  757. * by armlink. For this condition, you have to manually put this function
  758. * into your existing SysTick_Handler to make the perf_counter library
  759. * work.
  760. *
  761. * \note - if you are using Arm Compiler 5 (armcc) or Arm Compiler 6 (armclang)
  762. * you do NOT have to insert this function into your SysTick_Handler,
  763. * the systick_wrapper_ual.s will do the work for you.
  764. */
  765. extern void user_code_insert_to_systick_handler(void);
  766. /*!
  767. * \brief update perf_counter as SystemCoreClock has been updated.
  768. */
  769. extern void update_perf_counter(void);
  770. /*!
  771. * \brief prepare for reconfiguration of SysTick timer.
  772. *
  773. * \note some systems (e.g. FreeRTOS) might reconfigure the systick timer to
  774. * fulfil the requirement of their feature. To support this, just
  775. * before the reconfiguration, please call this function in order
  776. * to make the perf_counter works correctly later.
  777. *
  778. * \note after the reconfiguration, please call update_perf_counter() to apply
  779. * the changes to perf_counter.
  780. *
  781. * \note this function will stop the SysTick, clear the pending bit and set
  782. * the Load register and Current Value register to zero.
  783. */
  784. extern void before_cycle_counter_reconfiguration(void);
  785. /*! @} */
  786. /*!
  787. * \addtogroup gBenchmark 3 Benchmark
  788. * @{
  789. */
  790. #ifdef __PERF_COUNTER_COREMARK__
  791. /*!
  792. * \brief entry for coremark
  793. */
  794. void coremark_main(void);
  795. #endif
  796. /*! @} */
  797. //#if defined(__clang__)
  798. //# pragma clang diagnostic pop
  799. //#elif defined(__IS_COMPILER_GCC__)
  800. //# pragma GCC diagnostic pop
  801. //#endif
  802. #ifdef __cplusplus
  803. }
  804. #endif
  805. #endif