{"id":44655644,"url":"https://github.com/GorgonMeducer/perf_counter","last_synced_at":"2026-02-27T09:01:20.703Z","repository":{"id":37861271,"uuid":"328156701","full_name":"GorgonMeducer/perf_counter","owner":"GorgonMeducer","description":"A dedicated performance counter mainly for micro-controllers.   For Cortex-M processors, the Systick will be used by default. The `perf_counter` shares the SysTick with users' original SysTick function(s) without interfering with it. This library will bring new functionalities.","archived":false,"fork":false,"pushed_at":"2026-01-26T16:21:18.000Z","size":13640,"stargazers_count":556,"open_issues_count":0,"forks_count":101,"subscribers_count":16,"default_branch":"CMSIS-Pack","last_synced_at":"2026-01-27T04:45:28.629Z","etag":null,"topics":["cortex-m","delay","microcontroller","performance-analysis","performance-counters","systick"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GorgonMeducer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-09T13:03:54.000Z","updated_at":"2026-01-24T22:15:58.000Z","dependencies_parsed_at":"2024-03-14T17:01:40.686Z","dependency_job_id":"2b06de63-e475-43dc-ac5c-a8f7df3ac3d7","html_url":"https://github.com/GorgonMeducer/perf_counter","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/GorgonMeducer/perf_counter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GorgonMeducer%2Fperf_counter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GorgonMeducer%2Fperf_counter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GorgonMeducer%2Fperf_counter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GorgonMeducer%2Fperf_counter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GorgonMeducer","download_url":"https://codeload.github.com/GorgonMeducer/perf_counter/tar.gz/refs/heads/CMSIS-Pack","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GorgonMeducer%2Fperf_counter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29888777,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-27T08:34:21.514Z","status":"ssl_error","status_checked_at":"2026-02-27T08:32:38.035Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cortex-m","delay","microcontroller","performance-analysis","performance-counters","systick"],"created_at":"2026-02-14T22:00:25.252Z","updated_at":"2026-02-27T09:01:20.697Z","avatar_url":"https://github.com/GorgonMeducer.png","language":"C","funding_links":[],"categories":["component"],"sub_categories":["timer"],"readme":"[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/GorgonMeducer/perf_counter) ![GitHub](https://img.shields.io/github/license/GorgonMeducer/perf_counter) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/GorgonMeducer/perf_counter?include_prereleases)\n\n# perf_counter (v2.5.4)\nA dedicated performance counter mainly for micro-controllers. \n\nFor Cortex-M processors, the Systick will be used by default. The `perf_counter` shares the SysTick with users' original SysTick function(s) without interfering with it. This library will bring new functionalities, such as performance counter,` perfc_delay_us`, `perfc_delay_ms` and `clock()` service defined in `time.h`.\n\nA dedicated template is provided to port the perf_counter to different architectures or using a different Timer instead of SysTick in Cortex-M processors.\n\n### Features:\n\n- **Measure CPU cycles for specified code segment**\n- **Add Coremark 1.0**\n- **Provide Timer Service for EventRecorder automatically.**\n- **Enhanced measurement services for RTOS**\n  - Measures **RAW / True** cycles used for specified code segment inside a thread, **i.e. scheduling cost are removed**. \n  - Measure **RAW/True** cycles used for a data-process-path across multiple threads.\n- **Easy to use**\n  - Helper macros: `__cycleof__()` , `__super_loop_monitor__()` , `__cpu_usage__()`, `__cpu_perf__() `etc.\n  - Helper functions: `start_cycle_counter()`, `stop_cycle_counter()` etc.\n- Enable a broader processor architecture support\n  - **Support ALL Cortex-M processors**\n    - SysTick\n    - Performance Monitor Unit (PMU)\n\n  - Easy to port to a different architecture with a porting template\n- **Provide Free Services**\n  - Would **NOT** interfere with existing SysTick-based applications\n- **Support most of the arm compilers**\n  - Arm Compiler 5 (armcc), Arm Compiler 6 (armclang)\n  - arm gcc\n  - LLVM\n  - IAR\n- **Simplified Deployment**\n  - **Drag-and-Drop deployment for Arm Compiler 5 and Arm Compiler 6.**\n  - **CMSIS-Pack is available**\n  - **RT-Thread package is avaialble**\n- **Time-based services**\n  - `perfc_delay_us()` and `perfc_delay_ms()` with **64bit return value**.\n    - Adds weak entries `perfc_delay_us_user_code_in_loop()` and `perfc_delay_ms_user_code_in_loop()` for users to override, e.g. feeding the watchdog. \n  - Provides Timestamp services via `get_system_ticks()`, `get_system_us` and `get_system_ms()`.\n  - When passing `false` to `perfc_init()`, it is possible to use perf_counter in ISRs or global interrupt handling is disabled.\n  - Users can call micro-seconds related APIs even when the system timer clock is less than 1MHz. \n- **Support both RTOS and bare-metal environments**\n  - Supports SysTick Reconfiguration\n  - Supports changing System Frequency\n  - Supports stack-overflow detection in RTOS environment via `perfc_check_task_stack_canary_safe()`\n  - Adds macro `__PERFC_SAFE ` to avoid blocking high priority ISRs and tasks. Users should define the system timer priority level with macro `__PERFC_SYSTIMER_PRIORITY__ `. In Cortex-M, `0` means the highest configurable exception level.\n- **Utilities for C language enhancement**\n  - Macros to detect compilers, e.g. `__IS_COMPILER_ARM_COMPILER_6__`, `__IS_COMPILER_LLVM__` etc.\n  - Macros to detect compiler features: \n    - `__COMPILER_HAS_GNU_EXTENSIONS__`\n    - `__IS_COMPILER_SUPPORT_C99__`\n    - `__IS_COMPILER_SUPPORT_C11__`\n  - Macro to create atomicity for a specified code block, i.e. `__IRQ_SAFE{...}`.\n  - Helper macros for C language extension:\n    - VB like `with()`\n    - `foreach()`, `dimof()`  and `CONNECT()`\n    - C# like `using()`\n    - simple overload feature of OOPC made out of ANSI-C99, `__PLOOC_VA_NUM_ARGS()`.\n    - ...\n  - A dedicated macro `__perfc_sync_barrier__()` for code barrier. \n  - Macros to measure stack usage\n    - Adds a macro `__stack_usage__()` and `__stack_usage_max__()` to measure the stack usage for a given code segment.\n    - Adds a macro `ISR()` to measure the stack usage of a given Cortex-M Exception handling. \n      - You can define macro `__PERFC_STACK_CHECK_IN_ISR__` in project configuration to enable this feature.\n    - You can define macro `__PERFC_STACK_WATERMARK_U32__`  in your project configuration to override the default watermark, i.e. `0xDEADBEEF`.\n    - Supports for architectures that use growing-upward stacks. You can define macro `__PERFC_STACK_GROWS_UPWARD__` to switch.\n- Adds C Language Extensions\n  - Adds Coroutine support\n    - Adds watermark to stack and users can call `perfc_coroutine_stack_remain()` to get the stack usage info.\n    - Defining macro `__PERFC_COROUTINE_NO_STACK_CHECK__` in **compilation command line** disables the stack-checking feature. \n  - Adds protoThread support with/without the coroutine.\n    -  Adds timeout feature in **wait_xxxx**\n\n\n### Important Updates\n\n- Following functions/macros are **deprecated**, please use the version with `perfc_` as prefix:\n  - `init_cycle_counter()` -\u003e `perfc_init()`\n  - `delay_us()` -\u003e `perfc_delay_us()`\n  - `delay_ms()` -\u003e `perfc_delay_ms()`\n  - `CONNECT()` -\u003e `PERFC_CONNECT()`\n  - `using()` -\u003e `perfc_using()`\n  - `with()` -\u003e `perfc_with()`\n  - `foreach()` -\u003e `perfc_foreach()`\n\n- You can define the macro `__PERFC_NO_DEPRECATED__` to disable the alias of the deprecated APIs.\n\n  \n\n\n\n## 1. How To Use\n\n### 1.1 Measure CPU cycles for a specified code segment\n\nYou can measure a specified code segment with a macro helper `__cycleof__()`, a wrapper of `get_system_ticks()`.\n\n**Syntax:**\n\n```c\n__cycleof__(\u003cDescription String for the target\u003e, [User Code, see ref 1]) {\n    //! target code segment of measurement\n    ...\n}\n```\n\nHere, [**ref 1**] is a small user code to read the measurement result via a local variable `__cycle_count__`. This User Code is optional. If you don't put anything here, the measured result will be shown with a `__perf_counter_printf__`. \n\n\u003e [!NOTE]\n\u003e\n\u003e The first parameter cannot be ignored. If you don't want to give a description string, please pass an empty string i.e. \"\". \n\n#### **Example 1:** Simple measurement with `printf()`\n\n```c\n    __cycleof__(\"\") {\n        foreach(example_lv0_t, s_tItem, ptItem) {\n            __perf_counter_printf__(\"Processing item with ID = %d\\r\\n\", _-\u003echID);\n        }\n    }\n```\n\nYou will see the measured result in the console:\n\n![image-20220509004258020](./documents/pictures/__cycleof___output_simple) \n\n\n\n#### **Example 2:** Read measured result via `__cycle_counter__`\n\n```c\n    int64_t lCycleResult = 0;\n\n    /* measure cycles and store it in a dedicated variable without printf */\n    __cycleof__(\"delay_us(1000ul)\", \n        /* insert code to __cycleof__ body, \"{}\" can be omitted  */\n        {\n            lCycleResult = __cycle_count__;   /*\u003c \"__cycle_count__\" stores the result */\n        }) {\n        perfc_delay_us(1000ul);\n    }\n\n    __perf_counter_printf__(\"\\r\\n delay_us(1000ul) takes %lld cycles\\r\\n\", lCycleResult);\n```\n\nThe result is read out from `__cycle_count__`and used in other place:\n\n![image-20220509004714845](./documents/pictures/__cycleof___output_non_printf) \n\n### 1.2 Performance Analysis\n\n#### 1.2.1 CPU Usage\n\nFor both bare-metal and OS environments, you can measure the CPU Usage with macro `__cpu_usage__()` for a given code segment as long as it is executed repeatedly. \n\n**Syntax**\n\n```c\n__cpu_usage__(\u003cIteration Count before getting an average result\u003e, [User Code, see ref 1]) {\n    //! target code segment of measurement\n    ...\n}\n```\n\nHere, [**ref 1**] is a small user code to read the measurement result via a local variable `__usage__`. This User Code is optional. If you don't put anything here, the measured result will be shown with a `__perf_counter_printf__`. \n\n##### **Example 1: the following code will show 30% of CPU Usage:**\n\n```c\nvoid main(void)\n{\n    ...\n    while (1) {\n        __cpu_usage__(10) {\n            perfc_delay_us(30000);\n        }\n        perfc_delay_us(70000);\n    }\n    ...\n}\n```\n\n##### Example 2: Read measurement result via `__usage__`\n\n```c\nvoid main(void)\n{\n    ...\n    while (1) {\n        \n        __cpu_usage__(10, {\n            float fUsage = __usage__; /*\u003c \"__usage__\" stores the result */\n            __perf_counter_printf__(\"task 1 cpu usage %3.2f %%\\r\\n\", (double)fUsage);\n        }) {\n            perfc_delay_us(30000);\n        }\n        \n\n        perfc_delay_us(70000);\n    }\n    ...\n}\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e The `__usage__` stores the percentage information.\n\n\n\n#### 1.2.2 Cycle per Instruction and L1 DCache Miss Rate\n\nFor **Armv8.1-m** processors that implement the **PMU**, it is easy to measure the **CPI** (Cycle per Instruction) and **L1 DCache miss rate** with the macro `__cpu_perf__()`.\n\n**Syntax**:\n\n```c\n__cpu_perf__(\u003cDescription String for the target\u003e, [User Code, see ref 1]) {\n    //! target code segment of measurement\n    ...\n}\n```\n\nHere, [**ref 1**] is a small user code to read the measurement result via a local **struct** variable `__PERF_INFO__`. This User Code is optional. If you don't put anything here, the measured result will be shown with a `__perf_counter_printf__`. The prototype of the `__PERF_INFO__` is shown below:\n\n```c\nstruct {                                                                \n    uint64_t dwNoInstr;                 /* number of instruction executed */        \n    uint64_t dwNoMemAccess;             /* number of memory access */\n    uint64_t dwNoL1DCacheRefill;        /* number of L1 DCache Refill */\n    int64_t lCycles;                    /* number of CPU cycles */\n    uint32_t wInstrCalib;                                               \n    uint32_t wMemAccessCalib;                                           \n    float fCPI;                         /* Cycle per Instruction */\n    float fDCacheMissRate;              /* L1 DCache miss rate in percentage */\n} __PERF_INFO__;\n```\n\nFor example, when inserting user code, you can read CPI from `__PERF_INFO__.fCPI`.\n\n**Example 1: measure the Coremark**\n\n```c\nvoid main(void)\n{\n    perfc_init(false);\n\n    __perf_counter_printf__(\"Run coremark\\r\\n\");\n\n#ifdef __PERF_COUNTER_COREMARK__\n    __cpu_perf__(\"Coremark\") {\n        coremark_main();\n    }\n#endif\n\n    while(1) {\n        __NOP();\n    }\n}\n```\n\nThe result might look like the following:\n\n![](./documents/pictures/__cpu_perf__output.png) \n\n\n\n### 1.3 Timestamp\n\nYou can get the system timestamp (since the initialization of perf_counter service) via the functions `get_system_ticks()` and `get_system_ms()`. \n\n\u003e [!NOTE]\n\u003e\n\u003e  The `get_system_ms()` is **NOT** a wrapper of the function `get_system_ticks()`. \n\n\n\nThere are various ways to take advantage of those functions. \n\n#### Example 3: Use `get_system_ms()` as random seed\n\n```c\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \"perf_counter.h\"\n\nint main (void) \n{\n   int i, n;\n   \n   ...\n       \n   n = 5;\n   \n   /* Initialize random number generator */\n   srand((unsigned) get_system_ticks());\n\n   /* Print 5 random numbers from 0 to 1024 */\n   for( i = 0 ; i \u003c n ; i++ ) {\n      __perf_counter_printf__(\"%d\\n\", rand() \u0026 0x3FF);\n   }\n   \n   return(0);\n}\n```\n\n\n\n#### Example 4: Measure CPU cycles\n\n```c\n    do {\n        int64_t tStart = get_system_ticks();\n        __IRQ_SAFE {\n            __perf_counter_printf__(\"no interrupt \\r\\n\");\n        }\n        __perf_counter_printf__(\"used clock cycle: %d\", (int32_t)(get_system_ticks() - tStart));\n    } while(0);\n```\n\nThis example shows how to use the delta value of `get_system_ticks()` to measure the CPU cycles used by a specified code segment. In fact, the `__cycleof__()` is implemented in the same way:\n\n```c\n#define __cycleof__(__STR, ...)                                                 \\\n            perfc_using(int64_t _ = get_system_ticks(), __cycle_count__ = _,    \\\n                {__perfc_sync_barrier__();},                                    \\\n                {                                                               \\\n                __perfc_sync_barrier__();                                       \\\n                _ = get_system_ticks() - _ - g_nOffset;                         \\\n                __cycle_count__ = _;                                            \\\n                if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) {                    \\\n                    __perf_counter_printf__(\"\\r\\n\");                            \\\n                    __perf_counter_printf__(\"-[Cycle Report]\");                 \\\n                    __perf_counter_printf__(                                    \\\n                        \"------------------------------------\\r\\n\");            \\\n                    __perf_counter_printf__(                                    \\\n                        __STR \" total cycle count: %ld [%08lx]\\r\\n\",            \\\n                            (long)_, (long)_);                                  \\\n                } else {                                                        \\\n                    __VA_ARGS__                                                 \\\n                };                                                              \\\n            })\n```\n\n\n\n### 1.4 Timer Services\n\nperf_counter provides the basic timer services for delaying a given period and polling-for-timeout. For example:\n\n```c\nperfc_delay_ms(1000);   /* block the program for 1000ms */\nperfc_delay_us(50);\t  /* block the program for 50us */\n\nwhile(1) {\n    /* return true every 1000 ms */\n    if (perfc_is_time_out_ms(1000)) {\n        /* print hello world every 1000 ms */\n        __perf_counter_printf__(\"\\r\\nHello world\\r\\n\");\n    }\n}\n```\n\n\n\n\n\n### 1.5 Work with EventRecorder in MDK\n\nIf you are using EventRecorder in MDK, once you deploy the `perf_counter`, it will provide the timer service for EventRecorder by implementing the following functions: `EventRecorderTimerSetup()`, `EventRecorderTimerGetFreq()` and `EventRecorderTimerGetCount()`. \n\nIf you have not modified anything in `EventRecorderConf.h`, **you don't have to**, and please keep the default configuration.  If you see warnings like this:\n\n```\nInvalid Time Stamp Source selected in EventRecorderConf.h!\n```\n\nPlease set the macro `EVENT_TIMESTAMP_SOURCE` to `3` to suppress it.\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e Please always make sure the macro `EVENT_TIMESTAMP_FREQ` is `0`\n\n\n\n**By using perf_counter as the reference clock, EventRecorder can have the highest clock resolution on the target system without worrying about the presence of DWT or any conflicting usage of SysTick.** \n\n\n\n### 1.6 On System Environment Changing\n\n#### 1.6.1 System Frequency Changing\n\nIf you want to change the System Frequency, **after** the change, make sure:\n\n1. The `SystemCoreClock` has been updated with the new system frequency. Usually, the HAL will update the `SystemCoreClock` automatically, but in some rare cases where `SystemCoreClock` is updated accordingly, you should do it yourself.\n\n2. please call `update_perf_counter()` to notify perf_counter.\n\n\n\n#### 1.6.2 Reconfigure the SysTick\n\nSome systems (e.g., FreeRTOS) might reconfigure the systick timer to fulfill the requirements of their feature. To support this:\n\n1. **Before the reconfiguration**, please call function `before_cycle_counter_reconfiguration()`.  \n\n   **NOTE**: This function will stop the SysTick, clear the pending bit, and set the Load register and the Current Value registers to zero.\n\n2. After the reconfiguration, please call `update_perf_counter()` to notify perf_counter the new changes. \n\n\n\n## 2. How To Deploy\n\n### 2.1 Generic(Default) method for all compilers\n\n#### 2.1.1 For Bare-metal:\n\n1. Clone the code to your local with the following command lines:\n\n```shell\ngit clone https://github.com/GorgonMeducer/perf_counter.git\n```\n\n2. Add including path for `perf_counter` folder\n3. Add `perf_counter.c` and `perfc_port_default.c` to your project for compilation. \n\n\u003e [!IMPORTANT]\n\u003e\n\u003e Please do **NOT** add any assembly source files of this `perf_counter` library to your compilation, i.e. `systick_wrapper_gcc.S`, `systick_wrapper_gnu.s` or `systick_wrapper_ual.s`.\n\n\n\n4. Include `perf_counter.h` in the corresponding c source file:\n\n```c\n#include \"perf_counter.h\"\n```\n\n\n5. Make sure your system contains the CMSIS (with version 5.7.0 or above) as `perf_counter.h` and includes `cmsis_compiler.h`. \n6. Call the function `perfc_port_insert_to_system_timer_insert_ovf_handler()` in your `SysTick_Handler()`\n\n```c\nvoid SysTick_Handler(void)\n{\n    ...\n    perfc_port_insert_to_system_timer_insert_ovf_handler();\n    ...\n}\n```\n\n\n7. Ensure the `SystemCoreClock` is updated with the same value as CPU frequency. \n\n\u003e [!IMPORTANT]\n\u003e\n\u003e Make sure the `SysTick_CTRL_CLKSOURCE_Msk` bit ( bit 2) of `SysTick-\u003eCTRL` register is `1` that means SysTick runs with the same clock source as the target Cortex-M processor. \n\n\n\n\n8. Initialize the perf_counter with a boolean value that indicates whether the user applications and/or RTOS have already occupied the SysTick.\n\n```c\nvoid main(void)\n{\n    //! setup system clock \n    \n    /*! \\brief Update SystemCoreClock with the latest CPU frequency\n     *!        If the function doesn't exist or doesn't work correctly,\n     *!        Please update SystemCoreClock directly with the correct\n     *!        system frequency in Hz.\n     *!       \n     *!        extern volatile uint32_t SystemCoreClock;\n     */\n    SystemCoreClockUpdate();\n    \n    /*! \\brief initialize perf_counter() and pass true if SysTick is \n     *!        occupied by user applications or RTOS; otherwise, pass\n     *!        false. \n     */\n    perfc_init(true);\n    \n    ...\n    while(1) {\n        ...\n    }\n}\n```\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e Please enable the GNU extension in your compiler. For **GCC** and **CLANG**, it is `--std=gnu99` or `--std=gnu11`, and for other compilers, please check the user manual first. Fail to do so, you will not only trigger the warning in `perf_counter.h`, but also lose the function correctness of `__cycleof__()` and `__super_loop_monitor__()`, because `__PLOOC_VA_NUM_ARGS()` doesn't report `0` when passed with no argument. \n\n```c\n#if !__COMPILER_HAS_GNU_EXTENSIONS__\n#warning Please enable GNC extensions that is required by __cycleof__() and \\\n__super_loop_monitor__()\n#endif\n```\n\n9. It is nice to add macro definition `__PERF_COUNTER__` to your project GLOBALLY. It helps other modules to detect the existence of perf_counter. For Example, LVGL [`lv_conf_cmsis.h`](https://github.com/lvgl/lvgl/blob/d367bb7cf17dc34863f4439bba9b66a820088951/env_support/cmsis-pack/lv_conf_cmsis.h#L81-L99) use this macro to detect perf_counter and uses `get_system_ms()` to implement `lv_tick_get()`.\n10. It is nice to add `-include \"perfc_common.h\"` (or using equivalent option of your compiler) to the command line **GLOBALLY**.\n\n\n\n**Enjoy !**\n\n\n\n### 2.2 Use cmsis-pack in MDK\n\n1. Download the cmsis-pack from the`cmsis-pack` folder. It is a file with name `GorgonMeducer.perf_counter.\u003cversion\u003e.pack`, for example `GorgonMeducer.perf_counter.2.2.0.pack`\n\n2. Double-click it to install this cmsis-pack. Once finished, you can find it in your Pack-Installer:\n\n   ![](./documents/pictures/pack_installer)\n   In the future, you can pull the latest version of perf_counter from the menu `Packs-\u003eCheck For Updates` as shown below:\n\n   ![image-20220509011327392](./documents/pictures/check_for_updates) \n\n   \n\n3. Open the RTE management window, find the **Utilities** and select the **Core**::**Source** inside perf_counter as shown below:\n\n![](./documents/pictures/RTE.png) \n\n4. Include `perf_counter.h` in the corresponding c source file:\n\n```c\n#include \"perf_counter.h\"\n```\n\n\n5. Make sure your system contains the CMSIS (version 5.7.0 or above) as `perf_counter.h` and includes `cmsis_compiler.h`.  Usually, you should do this with RTE, as shown below:\n\n![image-20220509012432408](./documents/pictures/RTE_cmsis_core) \n\n6. Ensure the `SystemCoreClock` is updated with the same value as CPU frequency. \n\n\u003e [!IMPORTANT]\n\u003e\n\u003e Make sure the `SysTick_CTRL_CLKSOURCE_Msk` bit ( bit 2) of `SysTick-\u003eCTRL` register is `1` that means SysTick runs with the same clock source as the target Cortex-M processor. \n\n\n\n7. Initialize the perf_counter with a boolean value that indicates whether the user applications and/or RTOS have already occupied the SysTick.\n\n```c\nvoid main(void)\n{\n    //! Setup system clock \n    \n    /*! \\brief Update SystemCoreClock with the latest CPU frequency\n     *!        If the function doesn't exist or doesn't work correctly,\n     *!        Please update SystemCoreClock directly with the correct\n     *!        system frequency in Hz.\n     *!       \n     *!        extern volatile uint32_t SystemCoreClock;\n     */\n    SystemCoreClockUpdate();\n    \n    /*! \\brief initialize perf_counter() and pass true if SysTick is \n     *!        occupied by user applications or RTOS; otherwise, pass\n     *!        false. \n     */\n    perfc_init(true);\n    \n    ...\n    while(1) {\n        ...\n    }\n}\n```\n\n8. Please enable the **GNU extension** in your compiler. \n\n   For Arm Compiler 5, please select both **C99 mode** and GNU extensions in the **Option for target dialogue** as shown below:\n\n![image-20220509012752097](./documents/pictures/GNU_in_AC5) \n\nFor Arm Compiler 6, please select **gnu99** or **gnu11** in Language C drop-list as shown below:\n\n![image-20220509012944724](./documents/pictures/gnu_in_ac6) \n\nFailed to do so, you will not only trigger the warning in `perf_counter.h`, but also lose the function correctness of `__cycleof__()` and `__super_loop_monitor__()`, because `__PLOOC_VA_NUM_ARGS()` doesn't report `0` when passed with no argument. \n\n```c\n#if !__COMPILER_HAS_GNU_EXTENSIONS__\n#warning Please enable GNC extensions, that is required by __cycleof__() and \\\n__super_loop_monitor__()\n#endif\n```\n\n### 2.3 Use perf_counter in RT-Thread RTOS\n\nperf_counter has registered as one of the [RT-Thread software packages](https://packages.rt-thread.org/en/detail.html?package=perf_counter), which locats in `system` category. In [ENV](https://www.rt-thread.io/download.html?download=Env) or [RT-Thread Studio](https://www.rt-thread.io/download.html?download=Studio), you just need to enable `cputime` framework. RT-Thread will automatically enable perf_counter if you are using Cortex-M architecture.\n\n![rt-thread-settings](./documents/pictures/rt-thread-settings.png) \n\n**Enjoy !**\n\n\n\n## 3. FAQ\n\n### 3.1 Why I see `Undefined symbol $Super$$SysTick_Handler` \n\nThis error usually appears in **Arm Compiler 5** and **Arm Compiler 6**. It is because you haven't implemented any non-weak `SysTick_Handler()`.  Please provide an EMPTY one in any c source file to solve this problem:\n\n```c\nvoid SysTick_Handler(void)\n{\n}\n```\n\n**NOTE**: If you deploy perf_counter using cmsis-pack and encounter this issue, please **DO NOT** call function `user_code_insert_to_systick_handler()` in this **should-be-empty** `SysTick_Handler()`. \n\n### 3.2 Why do I see perf_counter in red in the MDK project manager?\n\nSince version v2.1.0, I removed the unnecessary bundle feature from the cmsis-pack. If you have used the older version, you will encounter this issue. To solve this problem: \n\n1. please unselect ALL the performance components in RTE, press OK and close the uVision. \n2. reopen the mdk project and select the perf_counter components in RTE\n\n\n\nSorry about this inconvenience. \n\n### 3.3 How to feed the watchdog in `perfc_delay_ms()`?\n\nSince version v2.5.0, it is possible to feed the watchdog while waiting for `perfc_delay_ms()` to return. You can implement a function called `perfc_delay_ms_user_code_in_loop()` in ANY of your C source file and use it to feed the watchdog:\n\n```c\nbool perfc_delay_ms_user_code_in_loop(int64_t lRemainInMs)\n{\n    UNUSED_PARAM(lRemainInMs); /* the lRemainInMs tells you about the remaining time in ms */\n  \n    extern void feed_watchdog(void);\n  \n    feed_watchdog();\n  \n\t  /* return false to exit the perfc_delay_ms() earlier */\n    /* usually, we just return true to wait until the end of the target period */\n    return true;\n}\n```\n\n### 3.4 Can I use perf_counter APIs in ISRs and/or when the global interrupt is disabled?\n\nYES. For such scenario, please initialize the **perf_counter** with:\n\n```c\nperfc_init(false);\n```\n\nand make sure the system timer (e.g. **SysTick**) is only used by **perf_counter.** If the SysTick is used by an RTOS or other applications, you can port perf_counter to a different timer using the `perfc_port_user.h` and `perfc_port_user.c` stored in the `template` folder. \n\n\n\n## 4.  License\n\nThe **Performance Counter** for Microcontrollers, a.k.a. ***perf_counter*** is under Apache 2.0 license. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGorgonMeducer%2Fperf_counter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGorgonMeducer%2Fperf_counter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGorgonMeducer%2Fperf_counter/lists"}