{"id":18305959,"url":"https://github.com/gorgonmeducer/perf_counter","last_synced_at":"2025-05-15T17:06:42.638Z","repository":{"id":37861271,"uuid":"328156701","full_name":"GorgonMeducer/perf_counter","owner":"GorgonMeducer","description":"A dedicated performance counter for Cortex-M systick. It shares the SysTick with users' original SysTick function without interfering it. This library will bring new functionalities, such as performance counter, delay_us and clock() service defined in time.h","archived":false,"fork":false,"pushed_at":"2025-05-09T02:27:59.000Z","size":11594,"stargazers_count":486,"open_issues_count":0,"forks_count":90,"subscribers_count":18,"default_branch":"CMSIS-Pack","last_synced_at":"2025-05-09T03:34:17.298Z","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}},"created_at":"2021-01-09T13:03:54.000Z","updated_at":"2025-05-09T02:28:03.000Z","dependencies_parsed_at":"2024-03-14T17:01:40.686Z","dependency_job_id":"b2cfb1bc-056f-4b89-8d42-b47d3687a3a2","html_url":"https://github.com/GorgonMeducer/perf_counter","commit_stats":null,"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"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","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254384988,"owners_count":22062422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2024-11-05T15:36:13.499Z","updated_at":"2025-05-15T17:06:37.630Z","avatar_url":"https://github.com/GorgonMeducer.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# perf_counter (v2.4.0)\nA dedicated performance counter for Cortex-M Systick. It shares the SysTick with users' original SysTick function(s) without interfering with it. This library will bring new functionalities, such as performance counter,` delay_us` and `clock()` service defined in `time.h`.\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\n- **Provide Free Services**\n  - Do **NOT** interfer 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  - `delay_us()` and `delay_ms()` with **64bit return value**.\n  - Provides Timestamp services via `get_system_ticks()`, `get_system_us` and `get_system_ms()`.\n- **Support both RTOS and bare-metal environments**\n  - Support SysTick Reconfiguration\n  - Support changing System Frequency\n  - Support stack-overflow detection in RTOS environment via `perfc_check_task_stack_canary_safe()`\n- **Utilities for C language enhancement**\n  - Macros to detect compilers, e.g. `__IS_COMPILER_ARM_COMPILER_6__`, `__IS_COMPILER_LLVM__` etc.\n  - Macro to create atomicity for specified code block, i.e. `__IRQ_SAFE{...}`\n  - Helper macros for C language extension:\n    - VB like `with()`\n    - `foreach()`, dimof(), `CONNECT()`\n    - C# like `using()`\n    - simple overload feature of OOPC made out of ANSI-C99, `__PLOOC_VA_NUM_ARGS()`\n    - **[new]** add macros for PT\n    - ...\n  - A dedicated macro `__perfc_sync_barrier__()` for code barrier. \n\n\n\n## 1. How To Use\n\n### 1.1 Measure CPU cycles for specified code segment\n\nYou can measure specified code segment with a macro helper `__cycleof__()`, it is 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#### **Example 1:** Simple measurement with printf\n\n```c\n    __cycleof__() {\n        foreach(example_lv0_t, s_tItem, ptItem) {\n            printf(\"Processing item with ID = %d\\r\\n\", _-\u003echID);\n        }\n    }\n```\n\nYou will see the measured result in 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    int32_t iCycleResult = 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            iCycleResult = __cycle_count__;   /*\u003c \"__cycle_count__\" stores the result */\n        }) {\n        delay_us(1000ul);\n    }\n\n    printf(\"\\r\\n delay_us(1000ul) takes %d cycles\\r\\n\", (int)iCycleResult);\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 environment, 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__cycleof__(\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            delay_us(30000);\n        }\n        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            printf(\"task 1 cpu usage %3.2f %%\\r\\n\", (double)fUsage);\n        }) {\n            delay_us(30000);\n        }\n        \n\n        delay_us(70000);\n    }\n    ...\n}\n```\n\nNOTE: 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 insert 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    init_cycle_counter(false);\n\n    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 function `get_system_ticks()` and `get_system_ms()`. \n\n**NOTE**: The `get_system_ms()` is **NOT** a wrapper of the function `get_system_ticks()`. \n\n\n\nThere are various way 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 = 5;\n   \n   /* Intializes 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      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            printf(\"no interrupt \\r\\n\");\n        }\n        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 specified code segment. In fact, the `__cycleof__()` is implemented in the same way:\n\n```c\n#define __cycleof__(__STR, ...)                                                 \\\n            using(int64_t _ = get_system_ticks(), __cycle_count__ = _,          \\\n                _=_, {                                                          \\\n                _ = get_system_ticks() - _;                                     \\\n                __cycle_count__ = _;                                            \\\n                if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) {                    \\\n                    printf(\"\\r\\n\");                                             \\\n                    printf(\"-[Cycle Report]\");                                  \\\n                    printf(\"--------------------------------------------\\r\\n\"); \\\n                    printf(__STR \" total cycle count: %d [%08x]\\r\\n\",           \\\n                            (int)_, (int)_);                                    \\\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 of time and polling-for-timeout. For example:\n\n```c\ndelay_ms(1000);   /* block the program for 1000ms */\ndelay_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        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 deployed the `perf_counter`, it will provide the timer service for EventRecorder by implenting the following functions: `EventRecorderTimerSetup()`, `EventRecorderTimerGetFreq()` and `EventRecorderTimerGetCount()`. \n\nIf you have not modify 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**IMPORTANT**: 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 worring 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 fulfil the requirement 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 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` to your compilation. \n\n\u003e **NOTE**: 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\n4. Include `perf_counter.h` in corresponding c source file:\n\n```c\n#include \"perf_counter.h\"\n```\n\n\n5. Make sure your system contains the CMSIS (with a version 5.7.0 or above) as `perf_counter.h` 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. Make sure the `SystemCoreClock` is updated with the same value as CPU frequency. \n8. **IMPORTANT**: 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. \n9. Initialize the perf_counter with 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    init_cycle_counter(true);\n    \n    ...\n    while(1) {\n        ...\n    }\n}\n```\n\n10. **IMPORTANT**: Please enable 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. Failed 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()` isn't report `0` when passed with no argument. \n\n```c\n#if __PLOOC_VA_NUM_ARGS() != 0\n#warning Please enable GNC extensions, it is required by __cycleof__() and \\\n__super_loop_monitor__()\n#endif\n```\n\n11. It is nice to add macro definition `__PERF_COUNTER__` to your project GLOBALLY. It helps other module 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()`.\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** inside perf_counter as shown below:\n\n![](./documents/pictures\\RTE) \n\n4. Include `perf_counter.h` in corresponding c source file:\n\n```c\n#include \"perf_counter.h\"\n```\n\n\n5. Make sure your system contains the CMSIS (with a version 5.7.0 or above) as `perf_counter.h` 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. Make sure the `SystemCoreClock` is updated with the same value as CPU frequency. \n7. **IMPORTANT**: 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. \n8. Initialize the perf_counter with 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    init_cycle_counter(true);\n    \n    ...\n    while(1) {\n        ...\n    }\n}\n```\n\n9. **IMPORTANT**: Please enable GNU extension in your compiler. \n\n   For Arm Compiler 5, please select both **C99 mode** and GNU extensions in the **Option for target dialog** 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()` isn't report `0` when passed with no argument. \n\n```c\n#if __PLOOC_VA_NUM_ARGS() != 0\n#warning Please enable GNC extensions, it 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 simply 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 pops up 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.  \n\n\n\n## 4.  License\n\n**Performance Counter for Cortex-M**, 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"}