Merge branch 'developing' into CMSIS-Pack

This commit is contained in:
Gabriel Wang 2024-02-28 21:33:58 +00:00
commit d037eac004
33 changed files with 3138 additions and 2160 deletions

View File

@ -6,7 +6,7 @@
<description>A dedicated performance counter for the Cortex-M Systick. It shares the SysTick with users' original SysTick function without interfering with it. This library will bring new functionalities, such as performance counter, APIs for delay, clock() defined in time.h etc.</description>
<url>https://raw.githubusercontent.com/GorgonMeducer/perf_counter/CMSIS-Pack/cmsis-pack/</url>
<supportContact>https://github.com/GorgonMeducer/perf_counter/issues</supportContact>
<license>lib/LICENSE</license>
<license>LICENSE</license>
<!-- optional license file -->
<!--
<license>
@ -174,7 +174,18 @@
<description>Require Perf_Counter Core</description>
<require Cclass="Utilities" Cgroup="perf_counter" Csub="Core"/>
</condition>
<condition id="PMU Devices">
<description>Require Perf_Counter Core</description>
<require condition="perf_counter" />
<accept Dcore="ARMV8MML"/>
<accept Dcore="ARMV81MML"/>
<accept Dcore="Cortex-M33"/>
<accept Dcore="Cortex-M35P"/>
<accept Dcore="Cortex-M55"/>
<accept Dcore="Cortex-M85"/>
</condition>
<condition id="Cortex-M Arm GCC">
<description>Compile Cortex-M Processors with GNU Tools for Arm Embedded Processors.</description>
<require condition="Arm GCC"/>
@ -257,29 +268,12 @@
-->
<components>
<component Cclass="Utilities" Cversion="2.2.5" Cgroup="perf_counter" Csub="Core" Cvariant="Library" condition="CMSIS-CORE">
<description>A dedicated performance counter for Cortex-M systick.</description>
<files>
<file category="header" name="perf_counter.h"/>
<file category="library" name="lib/perf_counter.lib" condition="Cortex-M Arm Compiler"/>
<file category="library" name="lib/libperf_counter_gcc.a" condition="Cortex-M Arm GCC"/>
</files>
<RTE_Components_h>
#define __PERF_COUNTER__ 1
</RTE_Components_h>
<Pre_Include_Global_h>
#define __PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__ 1
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="2.2.5" Cgroup="perf_counter" Csub="Core" Cvariant="Source" isDefaultVariant="true" condition="CMSIS-CORE">
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="Core" Cvariant="Source" isDefaultVariant="true" condition="CMSIS-CORE">
<description>A dedicated performance counter for Cortex-M systick.</description>
<files>
<file category="header" name="perf_counter.h"/>
<file category="sourceC" name="perf_counter.c" />
<file category="sourceC" name="perfc_port_default.c" />
<file category="sourceAsm" name="systick_wrapper_ual.s" condition="Previous Generation Cortex-M Arm Compiler CMSIS-CORE"/>
<file category="sourceAsm" name="systick_wrapper_gcc.S" condition="Cortex-M Arm GCC CMSIS-CORE"/>
<file category="sourceAsm" name="systick_wrapper_gnu.s" condition="Armv8-M Arm Compiler CMSIS-CORE"/>
@ -295,25 +289,66 @@
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="2.2.5" Cgroup="perf_counter" Csub="Core" Cvariant="SourceNoWrapper" isDefaultVariant="false" condition="CMSIS-CORE">
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="Core" Cvariant="SourceNoWrapper" isDefaultVariant="false" condition="CMSIS-CORE">
<description>A dedicated performance counter for Cortex-M systick.</description>
<files>
<file category="header" name="perf_counter.h"/>
<file category="sourceC" name="perf_counter.c" />
<file category="sourceC" name="perfc_port_default.c" />
</files>
<RTE_Components_h>
#define __PERF_COUNTER__ 1
</RTE_Components_h>
</component>
<component Cclass="Utilities" Cversion="1.0.2" Cgroup="perf_counter" Csub="Porting" Cvariant="User Defined" isDefaultVariant="false" condition="perf_counter">
<description>A user define system timer</description>
<files>
<file category="sourceC" name="template/perfc_port_user.c" attr="config" version="1.0.2"/>
<file category="header" name="template/perfc_port_user.h" attr="config" version="1.0.2"/>
</files>
<RTE_Components_h>
#define __RTE_PERFC_PORTING_USER_DEFINED__ 1
</RTE_Components_h>
<Pre_Include_Global_h>
#define __PERFC_USE_USER_CUSTOM_PORTING__ 1
#define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 1
#define __PERFC_CFG_PORTING_INCLUDE__ "perfc_port_user.h"
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="1.1.0" Cgroup="perf_counter" Csub="Porting" Cvariant="PMU" isDefaultVariant="true" condition="PMU Devices">
<description>Using the Performande Monitor Unit</description>
<files>
<file category="sourceC" name="perfc_port_pmu.c"/>
<file category="header" name="perfc_port_pmu.h"/>
</files>
<RTE_Components_h>
#define __RTE_PERFC_PORTING_PMU__ 1
</RTE_Components_h>
<Pre_Include_Global_h>
#define __PERFC_USE_PMU_PORTING__ 1
#define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 1
#define __PERFC_CFG_PORTING_INCLUDE__ "perfc_port_pmu.h"
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cgroup="perf_counter" Csub="Benchmark" Cvariant="Coremark" Cversion="1.1.2" condition="perf_counter">
<component Cclass="Utilities" Cgroup="perf_counter" Csub="Benchmark" Cvariant="Coremark" Cversion="1.1.3" condition="perf_counter">
<description>Coremark</description>
<files>
<file category="sourceC" name="benchmark/coremark_port/core_main.c"/>
<file category="sourceC" name="benchmark/coremark_port/core_portme.c" attr="config" version="1.1.2" />
<file category="header" name="benchmark/coremark_port/core_portme.h" attr="config" version="1.1.2" />
<file category="sourceC" name="benchmark/coremark_port/core_portme.c" attr="config" version="1.1.3" />
<file category="header" name="benchmark/coremark_port/core_portme.h" attr="config" version="1.1.3" />
<file category="include" name="benchmark/coremark/" />
<file category="sourceC" name="benchmark/coremark/core_list_join.c"/>
@ -331,7 +366,7 @@
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="RTX5 Patch" condition="RTX5 Patch">
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="RTX5 Patch" condition="RTX5 Patch">
<description>A Patch for RTX5</description>
<files>
<file category="source" name="os/perf_os_patch_rtx5.c"/>
@ -343,7 +378,7 @@
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="FreeRTOS Patch" condition="perf_counter">
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="FreeRTOS Patch" condition="perf_counter">
<description>A Patch for FreeRTOS</description>
<files>
<file category="sourceC" name="os/perf_os_patch_freertos.c"/>
@ -366,7 +401,7 @@ extern void __freertos_evr_on_task_switched_in(void *ptTCB, unsigned int uxTopPr
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="RT-Thread Patch" condition="perf_counter">
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="RT-Thread Patch" condition="perf_counter">
<description>A Patch for RT-Thread</description>
<files>
<file category="sourceC" name="os/perf_os_patch_rt_thread.c"/>
@ -384,7 +419,7 @@ extern void __rt_thread_scheduler_hook(struct rt_thread *from, struct rt_thread
</Pre_Include_Global_h>
</component>
<component Cclass="Utilities" Cversion="2.2.3" Cgroup="perf_counter" Csub="ThreadX Patch" condition="perf_counter">
<component Cclass="Utilities" Cversion="2.3.0" Cgroup="perf_counter" Csub="ThreadX Patch" condition="perf_counter">
<description>A Patch for ThreadX</description>
<files>
<file category="sourceC" name="os/perf_os_patch_threadx.c"/>

155
README.md
View File

@ -1,4 +1,4 @@
# perf_counter (v2.2.4)
# perf_counter (v2.3.0)
A 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`.
### Features:
@ -10,10 +10,15 @@ A dedicated performance counter for Cortex-M Systick. It shares the SysTick with
- Measures **RAW / True** cycles used for specified code segment inside a thread, **i.e. scheduling cost are removed**.
- Measure **RAW/True** cycles used for a data-process-path across multiple threads.
- **Easy to use**
- Helper macros: `__cycleof__()` , `__super_loop_monitor__()` etc.
- Helper macros: `__cycleof__()` , `__super_loop_monitor__()` , `__cpu_usage__()`, `__cpu_perf__()` etc.
- Helper functions: `start_cycle_counter()`, `stop_cycle_counter()` etc.
- **Support ALL Cortex-M processors**
- Including **Cortex-M85** and Star-MC1
- Enable a broader processor architecture support
- **Support ALL Cortex-M processors**
- SysTick
- **[new]**Performance Monitor Unit (PMU)
- **[new]**Easy to port to a different architecture with a porting template
- **Provide Free Services**
- Do **NOT** interfer with existing SysTick based applications
- **Support ALL arm compilers**
@ -26,13 +31,12 @@ A dedicated performance counter for Cortex-M Systick. It shares the SysTick with
- **CMSIS-Pack is available**
- **RT-Thread package is avaialble**
- **Time based services**
- `delay_us()` and `delay_ms()`
- **[new]**`delay_us()` and `delay_ms()` with **64bit return value**.
- Provides Timestamp services via `get_system_ticks()`, `get_system_us` and `get_system_ms()`.
- **Support both RTOS and bare-metal environments**
- Support SysTick Reconfiguration
- Support changing System Frequency
- **[new]** Support stack-overflow detection in RTOS environment via `perfc_check_task_stack_canary_safe()`
- Support stack-overflow detection in RTOS environment via `perfc_check_task_stack_canary_safe()`
- **Utilities for C language enhancement**
- Macros to detect compilers, e.g. `__IS_COMPILER_ARM_COMPILER_6__`, `__IS_COMPILER_LLVM__` etc.
- Macro to create atomicity for specified code block, i.e. `__IRQ_SAFE{...}`
@ -60,7 +64,7 @@ __cycleof__(<Description String for the target>, [User Code, see ref 1]) {
}
```
Here, [**ref 1**] is a small user code to read the measurement result via a local variable `__cycle_count__` for perl lovers, you can also use "`_`" to read the result. This User Code is optional. If you don't put anything here, the measured result will be shown with a `printf()`.
Here, [**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__`.
#### **Example 1:** Simple measurement with printf
@ -99,9 +103,123 @@ The result is read out from `__cycle_count__`and used in other place:
![image-20220509004714845](./documents/pictures/__cycleof___output_non_printf)
### 1.2 Performance Analysis
#### 1.2.1 CPU Usage
For 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.
**Syntax**
```c
__cycleof__(<Iteration Count before getting an average result>, [User Code, see ref 1]) {
//! target code segment of measurement
...
}
```
Here, [**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__`.
##### **Example 1: the following code will show 30% of CPU Usage:**
```c
void main(void)
{
...
while (1) {
__cpu_usage__(10) {
delay_us(30000);
}
delay_us(70000);
}
...
}
```
##### Example 2: Read measurement result via `__usage__`
```c
void main(void)
{
...
while (1) {
float fUsage = 0.0f;
__cpu_usage__(10, {
fUsage = __usage__; /*< "__usage__" stores the result */
}) {
delay_us(30000);
}
printf("task 1 cpu usage %3.2f %%\r\n", (double)fUsage);
delay_us(70000);
}
...
}
```
NOTE: The `__usage__` stores the percentage information.
### 1.2 Timestamp
#### 1.2.2 Cycle per Instruction and L1 DCache Miss Rate
For **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__()`.
**Syntax**:
```c
__cpu_perf__(<Description String for the target>, [User Code, see ref 1]) {
//! target code segment of measurement
...
}
```
Here, [**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:
```c
struct {
uint64_t dwNoInstr; /* number of instruction executed */
uint64_t dwNoMemAccess; /* number of memory access */
uint64_t dwNoL1DCacheRefill; /* number of L1 DCache Refill */
int64_t lCycles; /* number of CPU cycles */
uint32_t wInstrCalib;
uint32_t wMemAccessCalib;
float fCPI; /* Cycle per Instruction */
float fDCacheMissRate; /* L1 DCache miss rate in percentage */
} __PERF_INFO__;
```
For example, when insert user code, you can read CPI from `__PERF_INFO__.fCPI`.
**Example 1: measure the Coremark**
```c
void main(void)
{
init_cycle_counter(false);
printf("Run coremark\r\n");
#ifdef __PERF_COUNTER_COREMARK__
__cpu_perf__("Coremark") {
coremark_main();
}
#endif
while(1) {
__NOP();
}
}
```
The result might look like the following:
![](./documents/pictures/__cpu_perf__output.png)
### 1.3 Timestamp
You can get the system timestamp (since the initialization of perf_counter service) via function `get_system_ticks()` and `get_system_ms()`.
@ -172,7 +290,7 @@ This example shows how to use the delta value of `get_system_ticks()` to measure
### 1.3 Timer Services
### 1.4 Timer Services
perf_counter provides the basic timer services for delaying a given period of time and polling-for-timeout. For example:
@ -193,7 +311,7 @@ while(1) {
### 1.4 Work with EventRecorder in MDK
### 1.5 Work with EventRecorder in MDK
If 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()`.
@ -213,9 +331,9 @@ Please set the macro `EVENT_TIMESTAMP_SOURCE` to `3` to suppress it.
### 1.5 On System Environment Changing
### 1.6 On System Environment Changing
#### 1.5.1 System Frequency Changing
#### 1.6.1 System Frequency Changing
If you want to change the System Frequency, **after** the change, make sure:
@ -225,7 +343,7 @@ If you want to change the System Frequency, **after** the change, make sure:
#### 1.5.2 Reconfigure the SysTick
#### 1.6.2 Reconfigure the SysTick
Some systems (e.g. FreeRTOS) might reconfigure the systick timer to fulfil the requirement of their feature. To support this:
@ -250,7 +368,10 @@ git clone https://github.com/GorgonMeducer/perf_counter.git
```
2. Add including path for `perf_counter` folder
3. Add `perf_counter.c` to your compilation
3. Add `perf_counter.c` to your compilation.
> **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`.
4. Include `perf_counter.h` in corresponding c source file:
```c
@ -259,13 +380,13 @@ git clone https://github.com/GorgonMeducer/perf_counter.git
5. Make sure your system contains the CMSIS (with a version 5.7.0 or above) as `perf_counter.h` includes `cmsis_compiler.h`.
6. Call the function `user_code_insert_to_systick_handler()` in your `SysTick_Handler()`
6. Call the function `perfc_port_insert_to_system_timer_insert_ovf_handler()` in your `SysTick_Handler()`
```c
void SysTick_Handler(void)
{
...
user_code_insert_to_systick_handler();
perfc_port_insert_to_system_timer_insert_ovf_handler();
...
}
```

View File

@ -22,6 +22,15 @@ Original Author: Shay Gal-on
*/
#include "coremark.h"
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wreserved-identifier"
# pragma clang diagnostic ignored "-Wconditional-uninitialized"
# pragma clang diagnostic ignored "-Wsign-conversion"
# pragma clang diagnostic ignored "-Wimplicit-int-conversion"
#endif
/* Function: iterate
Run the benchmark for a specified number of iterations.
@ -104,6 +113,9 @@ char *mem_name[3] = { "Static", "Heap", "Stack" };
*/
__attribute__((used))
volatile double dfCoremarkScore = 0.0f;
#if MAIN_HAS_NOARGC
MAIN_RETURN_TYPE
coremark_main(void)
@ -409,6 +421,8 @@ for (i = 0; i < MULTITHREAD; i++)
double dfResult = (double)((double)1000000
* (double)default_num_contexts*results[0].iterations
/ (double)total_time);
dfCoremarkScore = dfResult;
ee_printf( "CoreMark 1.0 : %f / %s %s",
dfResult,
COMPILER_VERSION,

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,80 @@
#! armclang -E --target=arm-arm-none-eabi -mcpu=cortex-m0 -xc
; command above MUST be in first line (no comment above!)
/*
;-------- <<< Use Configuration Wizard in Context Menu >>> -------------------
*/
/*--------------------- Flash Configuration ----------------------------------
; <h> Flash Configuration
; <o0> Flash Base Address <0x0-0xFFFFFFFF:8>
; <o1> Flash Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
*----------------------------------------------------------------------------*/
#define __ROM_BASE 0x00000000
#define __ROM_SIZE 0x00080000
/*--------------------- Embedded RAM Configuration ---------------------------
; <h> RAM Configuration
; <o0> RAM Base Address <0x0-0xFFFFFFFF:8>
; <o1> RAM Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
*----------------------------------------------------------------------------*/
#define __RAM_BASE 0x20000000
#define __RAM_SIZE 0x00040000
/*--------------------- Stack / Heap Configuration ---------------------------
; <h> Stack / Heap Configuration
; <o0> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; <o1> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
*----------------------------------------------------------------------------*/
#define __STACK_SIZE 0x00000200
#define __HEAP_SIZE 0x00000C00
/*
;------------- <<< end of configuration section >>> ---------------------------
*/
/*----------------------------------------------------------------------------
User Stack & Heap boundary definition
*----------------------------------------------------------------------------*/
#define __STACK_TOP (__RAM_BASE + __RAM_SIZE) /* starts at end of RAM */
#define __HEAP_BASE (AlignExpr(+0, 8)) /* starts after RW_RAM section, 8 byte aligned */
/*----------------------------------------------------------------------------
Scatter File Definitions definition
*----------------------------------------------------------------------------*/
#define __RO_BASE __ROM_BASE
#define __RO_SIZE __ROM_SIZE
#define __RW_BASE __RAM_BASE
#define __RW_SIZE (__RAM_SIZE - __STACK_SIZE - __HEAP_SIZE)
LR_ROM __RO_BASE __RO_SIZE { ; load region size_region
ER_ROM __RO_BASE __RO_SIZE { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
.ANY (+XO)
}
RW_NOINIT __RW_BASE UNINIT __RW_SIZE {
*(.bss.noinit)
}
RW_RAM AlignExpr(+0, 8) (__RW_SIZE - AlignExpr(ImageLength(RW_NOINIT), 8)) {
*(+RW +ZI)
}
#if __HEAP_SIZE > 0
ARM_LIB_HEAP __HEAP_BASE EMPTY __HEAP_SIZE { ; Reserve empty region for heap
}
#endif
ARM_LIB_STACK __STACK_TOP EMPTY -__STACK_SIZE { ; Reserve empty region for stack
}
}

View File

@ -0,0 +1,146 @@
/******************************************************************************
* @file startup_ARMCM0.c
* @brief CMSIS-Core(M) Device Startup File for a Cortex-M0 Device
* @version V2.0.3
* @date 31. March 2020
******************************************************************************/
/*
* Copyright (c) 2009-2020 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined (ARMCM0)
#include "ARMCM0.h"
#else
#error device not specified!
#endif
/*----------------------------------------------------------------------------
External References
*----------------------------------------------------------------------------*/
extern uint32_t __INITIAL_SP;
extern __NO_RETURN void __PROGRAM_START(void);
/*----------------------------------------------------------------------------
Internal References
*----------------------------------------------------------------------------*/
__NO_RETURN void Reset_Handler (void);
void Default_Handler(void);
/*----------------------------------------------------------------------------
Exception / Interrupt Handler
*----------------------------------------------------------------------------*/
/* Exceptions */
void NMI_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void HardFault_Handler (void) __attribute__ ((weak));
void SVC_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void PendSV_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void SysTick_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt0_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt1_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt2_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt3_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt4_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt5_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt6_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt7_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt8_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
void Interrupt9_Handler (void) __attribute__ ((weak, alias("Default_Handler")));
/*----------------------------------------------------------------------------
Exception / Interrupt Vector table
*----------------------------------------------------------------------------*/
#if defined ( __GNUC__ )
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
extern const VECTOR_TABLE_Type __VECTOR_TABLE[48];
const VECTOR_TABLE_Type __VECTOR_TABLE[48] __VECTOR_TABLE_ATTRIBUTE = {
(VECTOR_TABLE_Type)(&__INITIAL_SP), /* Initial Stack Pointer */
Reset_Handler, /* Reset Handler */
NMI_Handler, /* -14 NMI Handler */
HardFault_Handler, /* -13 Hard Fault Handler */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
SVC_Handler, /* -5 SVCall Handler */
0, /* Reserved */
0, /* Reserved */
PendSV_Handler, /* -2 PendSV Handler */
SysTick_Handler, /* -1 SysTick Handler */
/* Interrupts */
Interrupt0_Handler, /* 0 Interrupt 0 */
Interrupt1_Handler, /* 1 Interrupt 1 */
Interrupt2_Handler, /* 2 Interrupt 2 */
Interrupt3_Handler, /* 3 Interrupt 3 */
Interrupt4_Handler, /* 4 Interrupt 4 */
Interrupt5_Handler, /* 5 Interrupt 5 */
Interrupt6_Handler, /* 6 Interrupt 6 */
Interrupt7_Handler, /* 7 Interrupt 7 */
Interrupt8_Handler, /* 8 Interrupt 8 */
Interrupt9_Handler /* 9 Interrupt 9 */
/* Interrupts 10..31 are left out */
};
#if defined ( __GNUC__ )
#pragma GCC diagnostic pop
#endif
/*----------------------------------------------------------------------------
Reset Handler called on controller reset
*----------------------------------------------------------------------------*/
__NO_RETURN void Reset_Handler(void)
{
SystemInit(); /* CMSIS System Initialization */
__PROGRAM_START(); /* Enter PreMain (C library entry point) */
}
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-noreturn"
#endif
/*----------------------------------------------------------------------------
Hard Fault Handler
*----------------------------------------------------------------------------*/
void HardFault_Handler(void)
{
while(1);
}
/*----------------------------------------------------------------------------
Default Handler for Exceptions / Interrupts
*----------------------------------------------------------------------------*/
void Default_Handler(void)
{
while(1);
}
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang diagnostic pop
#endif

View File

@ -5,7 +5,7 @@
<Header>### uVision Project, (C) Keil Software</Header>
<WorkspaceName>WorkSpace</WorkspaceName>
<WorkspaceName>Y:\Work\git\perf_counter\example\example.uvmpw</WorkspaceName>
<project>
<PathAndName>.\example.uvprojx</PathAndName>
@ -15,7 +15,6 @@
<project>
<PathAndName>.\gcc_example.uvprojx</PathAndName>
<NodeIsExpanded>1</NodeIsExpanded>
</project>
</ProjectWorkspace>

View File

@ -75,7 +75,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>0</IsCurrentTarget>
<IsCurrentTarget>1</IsCurrentTarget>
</OPTFL>
<CpuCode>7</CpuCode>
<DebugOpt>
@ -130,7 +130,7 @@
<SetRegEntry>
<Number>0</Number>
<Key>DbgFM</Key>
<Name>-I -S"System Generator:FVP_MPS2_Cortex_M0_MDK" -L"armcortexm0ct" -O4102 -C0 -MC".\FVP\MPS2_Cortex-M\FVP_MPS2_Cortex-M0_MDK.exe" -MF -PF -MA</Name>
<Name>-I -S"System Generator:cpu_core" -L"armcortexm0ct" -O4102 -C0 -MC".\VHT\VHT_MPS2_Cortex-M0.exe" -MF -PF -MA</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
@ -195,7 +195,7 @@
</MemoryWindow4>
<ScvdPack>
<Filename>C:\Users\gabriel\AppData\Local\Arm\Packs\Keil\ARM_Compiler\1.7.2\EventRecorder.scvd</Filename>
<Type>Keil.ARM_Compiler.1.7.2</Type>
<Type>Keil::ARM_Compiler@1.7.2</Type>
<SubType>1</SubType>
</ScvdPack>
<Tracepoint>
@ -204,7 +204,7 @@
<DebugFlag>
<trace>0</trace>
<periodic>1</periodic>
<aLwin>0</aLwin>
<aLwin>1</aLwin>
<aCover>0</aCover>
<aSer1>0</aSer1>
<aSer2>0</aSer2>
@ -297,7 +297,7 @@
<OPTFL>
<tvExp>1</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<IsCurrentTarget>1</IsCurrentTarget>
<IsCurrentTarget>0</IsCurrentTarget>
</OPTFL>
<CpuCode>7</CpuCode>
<DebugOpt>
@ -768,12 +768,24 @@
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>7</FileNumber>
<FileType>4</FileType>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\lib\perf_counter.lib</PathWithFileName>
<FilenameWithoutPath>perf_counter.lib</FilenameWithoutPath>
<PathWithFileName>..\perfc_port_default.c</PathWithFileName>
<FilenameWithoutPath>perfc_port_default.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>2</GroupNumber>
<FileNumber>8</FileNumber>
<FileType>5</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\perfc_port_default.h</PathWithFileName>
<FilenameWithoutPath>perfc_port_default.h</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>

View File

@ -10,7 +10,7 @@
<TargetName>example_arm_compiler_6</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
<pCCUsed>6210000::V6.21::.\ArmCompilerforEmbedded6.21</pCCUsed>
<pCCUsed>6210000::V6.21::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@ -408,57 +408,6 @@
<FileName>perf_counter.c</FileName>
<FileType>1</FileType>
<FilePath>..\perf_counter.c</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>2</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Cads>
<interw>2</interw>
<Optim>0</Optim>
<oTime>2</oTime>
<SplitLS>2</SplitLS>
<OneElfS>2</OneElfS>
<Strict>2</Strict>
<EnumInt>2</EnumInt>
<PlainCh>2</PlainCh>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<wLevel>0</wLevel>
<uThumb>2</uThumb>
<uSurpInc>2</uSurpInc>
<uC99>2</uC99>
<uGnu>2</uGnu>
<useXO>2</useXO>
<v6Lang>0</v6Lang>
<v6LangP>0</v6LangP>
<vShortEn>2</vShortEn>
<vShortWch>2</vShortWch>
<v6Lto>2</v6Lto>
<v6WtE>2</v6WtE>
<v6Rtti>2</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Cads>
</FileArmAds>
</FileOption>
</File>
<File>
<FileName>perf_counter.h</FileName>
@ -469,49 +418,16 @@
<FileName>systick_wrapper_ual.s</FileName>
<FileType>2</FileType>
<FilePath>..\systick_wrapper_ual.s</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>2</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Aads>
<interw>2</interw>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<thumb>2</thumb>
<SplitLS>2</SplitLS>
<SwStkChk>2</SwStkChk>
<NoWarn>2</NoWarn>
<uSurpInc>2</uSurpInc>
<useXO>2</useXO>
<ClangAsOpt>0</ClangAsOpt>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Aads>
</FileArmAds>
</FileOption>
</File>
<File>
<FileName>perf_counter.lib</FileName>
<FileType>4</FileType>
<FilePath>..\lib\perf_counter.lib</FilePath>
<FileName>perfc_port_default.c</FileName>
<FileType>1</FileType>
<FilePath>..\perfc_port_default.c</FilePath>
</File>
<File>
<FileName>perfc_port_default.h</FileName>
<FileType>5</FileType>
<FilePath>..\perfc_port_default.h</FilePath>
</File>
</Files>
</Group>
@ -533,14 +449,14 @@
<TargetName>library</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
<pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<pCCUsed>6210000::V6.21::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
<Device>ARMCM0</Device>
<Vendor>ARM</Vendor>
<PackID>ARM.CMSIS.5.9.0</PackID>
<PackURL>http://www.keil.com/pack/</PackURL>
<PackID>ARM.Cortex_DFP.1.0.0</PackID>
<PackURL>https://www.keil.com/pack/</PackURL>
<Cpu>IRAM(0x20000000,0x00020000) IROM(0x00000000,0x00040000) CPUTYPE("Cortex-M0") CLOCK(12000000) ESEL ELITTLE</Cpu>
<FlashUtilSpec></FlashUtilSpec>
<StartupFile></StartupFile>
@ -860,7 +776,7 @@
<v6WtE>0</v6WtE>
<v6Rtti>0</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<MiscControls>-Wno-undef</MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
@ -1012,28 +928,14 @@
<FilePath>..\systick_wrapper_ual.s</FilePath>
</File>
<File>
<FileName>perf_counter.lib</FileName>
<FileType>4</FileType>
<FilePath>..\lib\perf_counter.lib</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>0</IncludeInBuild>
<AlwaysBuild>2</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds/>
</FileOption>
<FileName>perfc_port_default.c</FileName>
<FileType>1</FileType>
<FilePath>..\perfc_port_default.c</FilePath>
</File>
<File>
<FileName>perfc_port_default.h</FileName>
<FileType>5</FileType>
<FilePath>..\perfc_port_default.h</FilePath>
</File>
</Files>
</Group>
@ -1692,9 +1594,14 @@
</FileOption>
</File>
<File>
<FileName>perf_counter.lib</FileName>
<FileType>4</FileType>
<FilePath>..\lib\perf_counter.lib</FilePath>
<FileName>perfc_port_default.c</FileName>
<FileType>1</FileType>
<FilePath>..\perfc_port_default.c</FilePath>
</File>
<File>
<FileName>perfc_port_default.h</FileName>
<FileType>5</FileType>
<FilePath>..\perfc_port_default.h</FilePath>
</File>
</Files>
</Group>
@ -1757,17 +1664,27 @@
<component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="5.6.0" condition="ARMv6_7_8-M Device">
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="example_arm_compiler_6"/>
</targetInfos>
</component>
<component Cclass="CMSIS" Cgroup="CORE" Cvendor="ARM" Cversion="6.0.0" condition="ARMv6_7_8-M Device">
<package name="CMSIS" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="6.0.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="library"/>
</targetInfos>
</component>
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS">
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="library"/>
</targetInfos>
</component>
<component Cclass="Device" Cgroup="Startup" Cvendor="ARM" Cversion="1.2.2" condition="ARMCM0 CMSIS">
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="example_arm_compiler_6"/>
<targetInfo name="library"/>
</targetInfos>
</component>
<component Cbundle="ARM Compiler" Cclass="Compiler" Cgroup="Event Recorder" Cvariant="DAP" Cvendor="Keil" Cversion="1.5.1" condition="Cortex-M Device">
@ -1798,20 +1715,36 @@
<targetInfo name="example_arm_compiler_6"/>
</targetInfos>
</file>
<file attr="config" category="linkerScript" condition="ARMCC6" name="Device\ARMCM0\Config\ARMCM0_ac6.sct" version="1.0.0">
<instance index="0">RTE\Device\ARMCM0\ARMCM0_ac6.sct</instance>
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS" isDefaultVariant="1"/>
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="library"/>
</targetInfos>
</file>
<file attr="config" category="sourceC" name="Device\ARMCM0\Source\startup_ARMCM0.c" version="2.0.3">
<instance index="0">RTE\Device\ARMCM0\startup_ARMCM0.c</instance>
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS" isDefaultVariant="1"/>
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="library"/>
</targetInfos>
</file>
<file attr="config" category="sourceAsm" condition="ARMCC" name="Device\ARM\ARMCM0\Source\ARM\startup_ARMCM0.s" version="1.0.1">
<instance index="0">RTE\Device\ARMCM0\startup_ARMCM0.s</instance>
<component Cclass="Device" Cgroup="Startup" Cvendor="ARM" Cversion="1.2.2" condition="ARMCM0 CMSIS"/>
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="example_arm_compiler_6"/>
<targetInfo name="library"/>
</targetInfos>
</file>
<file attr="config" category="sourceC" name="Device\ARM\ARMCM0\Source\system_ARMCM0.c" version="1.0.0">
<file attr="config" category="sourceC" name="Device\ARMCM0\Source\system_ARMCM0.c" version="1.0.0">
<instance index="0">RTE\Device\ARMCM0\system_ARMCM0.c</instance>
<component Cclass="Device" Cgroup="Startup" Cvendor="ARM" Cversion="1.2.2" condition="ARMCM0 CMSIS"/>
<package name="CMSIS" schemaVersion="1.7.7" url="http://www.keil.com/pack/" vendor="ARM" version="5.9.0"/>
<component Cclass="Device" Cgroup="Startup" Cvariant="C Startup" Cvendor="ARM" Cversion="2.2.0" condition="ARMCM0 CMSIS" isDefaultVariant="1"/>
<package name="Cortex_DFP" schemaVersion="1.7.7" url="https://www.keil.com/pack/" vendor="ARM" version="1.0.0"/>
<targetInfos>
<targetInfo name="example_arm compiler_5"/>
<targetInfo name="example_arm_compiler_6"/>

View File

@ -561,6 +561,30 @@
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>10</FileNumber>
<FileType>1</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\perfc_port_default.c</PathWithFileName>
<FilenameWithoutPath>perfc_port_default.c</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
<File>
<GroupNumber>3</GroupNumber>
<FileNumber>11</FileNumber>
<FileType>5</FileType>
<tvExp>0</tvExp>
<tvExpOptDlg>0</tvExpOptDlg>
<bDave2>0</bDave2>
<PathWithFileName>..\perfc_port_default.h</PathWithFileName>
<FilenameWithoutPath>perfc_port_default.h</FilenameWithoutPath>
<RteFlg>0</RteFlg>
<bShared>0</bShared>
</File>
</Group>
<Group>

View File

@ -403,6 +403,16 @@
<FileType>4</FileType>
<FilePath>..\lib\libperf_counter_gcc.a</FilePath>
</File>
<File>
<FileName>perfc_port_default.c</FileName>
<FileType>1</FileType>
<FilePath>..\perfc_port_default.c</FilePath>
</File>
<File>
<FileName>perfc_port_default.h</FileName>
<FileType>5</FileType>
<FilePath>..\perfc_port_default.h</FilePath>
</File>
</Files>
</Group>
<Group>
@ -852,6 +862,16 @@
<FileArm/>
</FileOption>
</File>
<File>
<FileName>perfc_port_default.c</FileName>
<FileType>1</FileType>
<FilePath>..\perfc_port_default.c</FilePath>
</File>
<File>
<FileName>perfc_port_default.h</FileName>
<FileType>5</FileType>
<FilePath>..\perfc_port_default.h</FilePath>
</File>
</Files>
</Group>
<Group>

View File

@ -190,14 +190,25 @@ int main (void)
#endif
while (1) {
if (perfc_is_time_out_ms(1000)) {
printf("\r[%010d]", get_system_ms());
if (perfc_is_time_out_ms(10000)) {
printf("\r[%010lld]", get_system_ms());
}
__cpu_time__(10) {
__cpu_usage__(10) {
delay_us(30000);
}
delay_us(70000);
float fUsage = 0;
__cpu_usage__(10, {
fUsage = __usage__;
printf("task 1 cpu usage %3.2f %%\r\n", (double)fUsage);
}) {
delay_us(50000);
}
delay_us(20000);
}
}

View File

@ -32,7 +32,7 @@ DEFAULT_ARGS=(-c "v")
benchmark
documents
os
lib
template
"
# Specify file names to be added to pack base directory
@ -42,6 +42,10 @@ DEFAULT_ARGS=(-c "v")
LICENSE
perf_counter.c
perf_counter.h
perfc_port_default.c
perfc_port_default.h
perfc_port_pmu.c
perfc_port_pmu.h
README.md
systick_wrapper_gcc.S
systick_wrapper_gnu.s

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

View File

@ -1,947 +0,0 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
#ifndef __PERFORMANCE_COUNTER_H__
#define __PERFORMANCE_COUNTER_H__
/*============================ INCLUDES ======================================*/
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "cmsis_compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
/*============================ MACROS ========================================*/
/*!
* \addtogroup gBasic 1 Basic
* @{
*/
#define __PERF_COUNTER_VER_MAJOR__ 2
#define __PERF_COUNTER_VER_MINOR__ 2
#define __PERF_COUNTER_VER_REVISE__ 4
#define __PERF_COUNTER_VER_STR__ ""
#define __PER_COUNTER_VER__ (__PERF_COUNTER_VER_MAJOR__ * 10000ul \
+__PERF_COUNTER_VER_MINOR__ * 100ul \
+__PERF_COUNTER_VER_REVISE__)
/*! @} */
/*!
* \addtogroup gHelper 4 Helper
* @{
*/
// for IAR
#undef __IS_COMPILER_IAR__
#if defined(__IAR_SYSTEMS_ICC__)
# define __IS_COMPILER_IAR__ 1
#endif
// for arm compiler 5
#undef __IS_COMPILER_ARM_COMPILER_5__
#if ((__ARMCC_VERSION >= 5000000) && (__ARMCC_VERSION < 6000000))
# define __IS_COMPILER_ARM_COMPILER_5__ 1
#endif
//for arm compiler 6
#undef __IS_COMPILER_ARM_COMPILER_6__
#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
# define __IS_COMPILER_ARM_COMPILER_6__ 1
#endif
#undef __IS_COMPILER_ARM_COMPILER__
#if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__ \
|| defined(__IS_COMPILER_ARM_COMPILER_6__) && __IS_COMPILER_ARM_COMPILER_6__
# define __IS_COMPILER_ARM_COMPILER__ 1
#endif
// for clang
#undef __IS_COMPILER_LLVM__
#if defined(__clang__) && !__IS_COMPILER_ARM_COMPILER_6__
# define __IS_COMPILER_LLVM__ 1
#else
// for gcc
# undef __IS_COMPILER_GCC__
# if defined(__GNUC__) && !( defined(__IS_COMPILER_ARM_COMPILER__) \
|| defined(__IS_COMPILER_LLVM__) \
|| defined(__IS_COMPILER_IAR__))
# define __IS_COMPILER_GCC__ 1
# endif
#endif
#ifdef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
# include __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
#endif
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wreserved-identifier"
# pragma clang diagnostic ignored "-Wdeclaration-after-statement"
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
# pragma clang diagnostic ignored "-Wgnu-statement-expression"
# pragma clang diagnostic ignored "-Wunused-but-set-variable"
# pragma clang diagnostic ignored "-Wshadow"
# pragma clang diagnostic ignored "-Wshorten-64-to-32"
# pragma clang diagnostic ignored "-Wcompound-token-split-by-macro"
# pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
# pragma diag_suppress 550
#elif defined(__IS_COMPILER_GCC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpedantic"
# pragma GCC diagnostic ignored "-Wunused-variable"
# pragma GCC diagnostic ignored "-Wunused-but-set-variable"
# pragma GCC diagnostic ignored "-Wformat="
#endif
#ifndef __PLOOC_VA_NUM_ARGS_IMPL
# define __PLOOC_VA_NUM_ARGS_IMPL( _0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11, \
_12,_13,_14,_15,_16,__N,...) __N
#endif
#ifndef __PLOOC_VA_NUM_ARGS
#define __PLOOC_VA_NUM_ARGS(...) \
__PLOOC_VA_NUM_ARGS_IMPL( 0,##__VA_ARGS__,16,15,14,13,12,11,10,9, \
8,7,6,5,4,3,2,1,0)
#endif
#ifndef UNUSED_PARAM
# define UNUSED_PARAM(__VAR) (void)(__VAR)
#endif
#undef __CONNECT2
#undef __CONNECT3
#undef __CONNECT4
#undef __CONNECT5
#undef __CONNECT6
#undef __CONNECT7
#undef __CONNECT8
#undef __CONNECT9
#undef CONNECT2
#undef CONNECT3
#undef CONNECT4
#undef CONNECT5
#undef CONNECT6
#undef CONNECT7
#undef CONNECT8
#undef CONNECT9
#undef CONNECT
#undef __MACRO_EXPANDING
#define __MACRO_EXPANDING(...) __VA_ARGS__
#define __CONNECT2(__A, __B) __A##__B
#define __CONNECT3(__A, __B, __C) __A##__B##__C
#define __CONNECT4(__A, __B, __C, __D) __A##__B##__C##__D
#define __CONNECT5(__A, __B, __C, __D, __E) __A##__B##__C##__D##__E
#define __CONNECT6(__A, __B, __C, __D, __E, __F) __A##__B##__C##__D##__E##__F
#define __CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
__A##__B##__C##__D##__E##__F##__G
#define __CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
__A##__B##__C##__D##__E##__F##__G##__H
#define __CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
__A##__B##__C##__D##__E##__F##__G##__H##__I
#define ALT_CONNECT2(__A, __B) __CONNECT2(__A, __B)
#define CONNECT2(__A, __B) __CONNECT2(__A, __B)
#define CONNECT3(__A, __B, __C) __CONNECT3(__A, __B, __C)
#define CONNECT4(__A, __B, __C, __D) __CONNECT4(__A, __B, __C, __D)
#define CONNECT5(__A, __B, __C, __D, __E) __CONNECT5(__A, __B, __C, __D, __E)
#define CONNECT6(__A, __B, __C, __D, __E, __F) \
__CONNECT6(__A, __B, __C, __D, __E, __F)
#define CONNECT7(__A, __B, __C, __D, __E, __F, __G) \
__CONNECT7(__A, __B, __C, __D, __E, __F, __G)
#define CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H) \
__CONNECT8(__A, __B, __C, __D, __E, __F, __G, __H)
#define CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I) \
__CONNECT9(__A, __B, __C, __D, __E, __F, __G, __H, __I)
#define CONNECT(...) \
ALT_CONNECT2(CONNECT, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#undef __using1
#undef __using2
#undef __using3
#undef __using4
#undef using
#define __using1(__declare) \
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
)
#define __using2(__declare, __on_leave_expr) \
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
CONNECT3(__using_, __LINE__,_ptr)++ == NULL; \
(__on_leave_expr) \
)
#define __using3(__declare, __on_enter_expr, __on_leave_expr) \
for (__declare, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
((__on_enter_expr),1) : 0; \
(__on_leave_expr) \
)
#define __using4(__dcl1, __dcl2, __on_enter_expr, __on_leave_expr) \
for (__dcl1, __dcl2, *CONNECT3(__using_, __LINE__,_ptr) = NULL; \
CONNECT3(__using_, __LINE__,_ptr)++ == NULL ? \
((__on_enter_expr),1) : 0; \
(__on_leave_expr) \
)
#define using(...) \
CONNECT2(__using, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#undef __with2
#undef __with3
#undef with
#define __with2(__type, __addr) \
using(__type *_=(__addr))
#define __with3(__type, __addr, __item) \
using(__type *_=(__addr), *__item = _, _=_,_=_ )
#define with(...) \
CONNECT2(__with, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#undef _
#ifndef dimof
# define dimof(__array) (sizeof(__array)/sizeof(__array[0]))
#endif
#define SAFE_NAME(__NAME) CONNECT3(__,__NAME,__LINE__)
#undef foreach2
#undef foreach3
#undef foreach
#define foreach2(__type, __array) \
using(__type *_ = __array) \
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
SAFE_NAME(count) > 0; \
_++, SAFE_NAME(count)-- \
)
#define foreach3(__type, __array, __item) \
using(__type *_ = __array, *__item = _, _ = _, _ = _ ) \
for ( uint_fast32_t SAFE_NAME(count) = dimof(__array); \
SAFE_NAME(count) > 0; \
_++, __item = _, SAFE_NAME(count)-- \
)
#define foreach(...) \
CONNECT2(foreach, __PLOOC_VA_NUM_ARGS(__VA_ARGS__))(__VA_ARGS__)
#ifndef safe_atom_code
# define safe_atom_code() \
using( uint32_t SAFE_NAME(temp) = \
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
__disable_irq(); \
SAFE_NAME(temp2);}), \
__set_PRIMASK(SAFE_NAME(temp)))
#endif
#ifndef __IRQ_SAFE
# define __IRQ_SAFE \
using( uint32_t SAFE_NAME(temp) = \
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
__disable_irq(); \
SAFE_NAME(temp2);}), \
__set_PRIMASK(SAFE_NAME(temp)))
#endif
#ifndef __perf_counter_printf__
# define __perf_counter_printf__ printf
#endif
#if __PLOOC_VA_NUM_ARGS() != 0
#warning Please enable GNU extensions, it is required by __cycleof__() and \
__super_loop_monitor__()
#endif
#if defined(__PERF_COUNTER_CFG_USE_SYSTICK_WRAPPER__)
# if defined(__IS_COMPILER_ARM_COMPILER_5__) && __IS_COMPILER_ARM_COMPILER_5__
# pragma import(__ensure_systick_wrapper)
# elif (defined(__GNUC__) || defined(__clang__)) \
&& (!defined(__IS_COMPILER_IAR__) || !__IS_COMPILER_IAR__)
__asm(".global __ensure_systick_wrapper\n\t");
# endif
#endif
/*! @} */
/*============================ MACROFIED FUNCTIONS ===========================*/
/*!
* \addtogroup gBasic 1 Basic
* @{
*/
/*!
* \brief measure the cycle count of a given code segment
* \param[in] __STR a description string for the measurement
* \param[in] ... an optional code segement, in which we can read the measured
* result from __cycle_count__.
* \details Here is an example:
E.g.
\code
__cycleof__("printf") {
printf("hello world\r\n");
}
\endcode
*/
#define __cycleof__(__STR, ...) \
using(int64_t _ = get_system_ticks(), __cycle_count__ = _, \
_=_, { \
_ = get_system_ticks() - _ - g_nOffset; \
__cycle_count__ = _; \
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
__perf_counter_printf__("\r\n"); \
__perf_counter_printf__("-[Cycle Report]"); \
__perf_counter_printf__( \
"--------------------------------------------\r\n"); \
__perf_counter_printf__( \
__STR " total cycle count: %ld [%016lx]\r\n", \
(long)_, (long)_); \
} else { \
__VA_ARGS__ \
}; \
})
/*!
* \brief measure the cpu usage for a given code segment and print out the
* result in percentage.
* \param[in] __CNT generate result on every given iterations
* \param[in] ... an optional code segement, in which we can read the measured
* result from __usage__ which is a float value.
* \details Here is an example, 50% cpu time:
E.g.
\code
while (1) {
__cpu_time__(100) {
delay_us(5000);
}
delay_us(5000);
}
\endcode
*/
#define __cpu_time__(__CNT, ...) \
static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
static uint32_t s_wLoopCounter = (__CNT); \
using(float __usage__ = 0, ({ \
if (0 == s_wLoopCounter) { \
__usage__ = (float)((double)SAFE_NAME(s_lTotal) \
/ (double)( get_system_ticks() \
- SAFE_NAME(s_lTimestamp))); \
__usage__ *= 100.0f; \
SAFE_NAME(s_lTimestamp) = 0; \
SAFE_NAME(s_lTotal) = 0; \
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
__perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__); \
} else { \
__VA_ARGS__ \
} \
} \
if (0 == SAFE_NAME(s_lTimestamp)) { \
SAFE_NAME(s_lTimestamp) = get_system_ticks(); \
s_wLoopCounter = (__CNT); \
} \
start_task_cycle_counter();}), \
({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
s_wLoopCounter--;}))
/*!
* \addtogroup gBasicTimerService 1.2 Timer Service
* \ingroup gBasic
* @{
*/
/*!
* \brief should not use
*/
#define perfc_is_time_out_ms0() true
/*!
* \brief set an alarm with given period in ms and check the status
*
* \param[in] __ms a time period in millisecond
* \param[in] __timestamp_ptr an optional timestamp holder
* \param[in] __auto_reload whether starting next period after a timeout event
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_ms3(__ms, __timestamp_ptr, __auto_reload) \
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
__perfc_is_time_out(perfc_convert_ms_to_ticks(__ms), \
(__timestamp_ptr), (__auto_reload));})
/*!
* \brief set an alarm with given period in ms and check the status
*
* \param[in] __ms a time period in millisecond
* \param[in] __timestamp_ptr an optional timestamp holder
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_ms2(__ms, __timestamp_ptr) \
perfc_is_time_out_ms3((__ms), (__timestamp_ptr), true)
/*!
* \brief set an alarm with given period in ms and check the status
*
* \param[in] __ms a time period in millisecond
* \param[in] __timestamp_ptr an optional timestamp holder
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_ms1(__ms) \
perfc_is_time_out_ms3((__ms), &SAFE_NAME(s_lTimestamp), true)
/*!
* \brief set an alarm with given period in ms and check the status
*
* \param[in] __ms a time period in millisecond
* \param[in] ... an optional timestamp holder
* \param[in] ... an optional indicator for whether starting next period after a timeout event
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_ms(...) \
CONNECT2(perfc_is_time_out_ms, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
(__VA_ARGS__)
/*!
* \brief set an alarm with given period in us and check the status
*
* \param[in] __us a time period in microsecond
* \param[in] __timestamp_ptr an optional timestamp holder
* \param[in] __auto_reload whether starting next period after a timeout event
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_us3(__us, __timestamp_ptr, __auto_reload) \
({ static int64_t SAFE_NAME(s_lTimestamp); (void)SAFE_NAME(s_lTimestamp); \
__perfc_is_time_out(perfc_convert_us_to_ticks(__us), \
(__timestamp_ptr), (__auto_reload));})
/*!
* \brief set an alarm with given period in us and check the status
*
* \param[in] __us a time period in microsecond
* \param[in] __timestamp_ptr an optional timestamp holder
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_us2(__us, __timestamp_ptr) \
perfc_is_time_out_us3((__us), (__timestamp_ptr), true)
/*!
* \brief set an alarm with given period in us and check the status
*
* \param[in] __us a time period in microsecond
* \param[in] __timestamp_ptr an optional timestamp holder
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_us1(__us) \
perfc_is_time_out_us3((__us), &SAFE_NAME(s_lTimestamp), true)
/*!
* \brief set an alarm with given period in us and check the status
*
* \param[in] __us a time period in microsecond
* \param[in] ... an optional timestamp holder
* \param[in] ... an optional indicator for whether starting next period after a timeout event
*
* \return bool whether it is timeout
*/
#define perfc_is_time_out_us(...) \
CONNECT2(perfc_is_time_out_us, __PLOOC_VA_NUM_ARGS(__VA_ARGS__)) \
(__VA_ARGS__)
/*! @} */
/*! @} */
/*!
* \addtogroup gRTOS 2 RTOS Support
* @{
*/
#define __super_loop_monitor__(__N, ...) \
using( \
struct { \
int64_t lStart; \
int64_t lTaskUsedCycles; \
int64_t lTimeElapsed; \
} __cpu_usage__ = {.lStart = get_system_ticks()}) \
using(int SAFE_NAME(cnt) = (__N)) \
for(start_task_cycle_counter();; ({ \
if (!(--SAFE_NAME(cnt))) { \
__cpu_usage__.lTimeElapsed \
= get_system_ticks() - __cpu_usage__.lStart - g_nOffset; \
__cpu_usage__.lTaskUsedCycles = stop_task_cycle_counter(); \
\
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
__perf_counter_printf__( \
"%s CPU Usage %2.3f%%\r\n", __func__, \
(float)((double)__cpu_usage__.lTaskUsedCycles * 100.0 / \
(double)__cpu_usage__.lTimeElapsed)); \
} else { \
__VA_ARGS__; \
} \
SAFE_NAME(cnt) = (__N); \
__cpu_usage__.lStart = get_system_ticks(); \
start_task_cycle_counter(); \
}; \
}))
/*============================ TYPES =========================================*/
typedef struct {
int64_t lStart;
int64_t lUsedTotal;
int32_t nUsedRecent;
uint16_t hwActiveCount;
uint16_t : 15;
uint16_t bEnabled : 1;
} task_cycle_info_t;
typedef struct task_cycle_info_agent_t task_cycle_info_agent_t;
struct task_cycle_info_agent_t {
task_cycle_info_t *ptInfo;
task_cycle_info_agent_t *ptNext;
task_cycle_info_agent_t *ptPrev;
};
/*! @} */
/*============================ GLOBAL VARIABLES ==============================*/
extern volatile int64_t g_lLastTimeStamp;
extern volatile int32_t g_nOffset;
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
/*!
* \addtogroup gBasicTicks 1.1 Ticks APIs
* \ingroup gBasic
* @{
*/
/*!
* \brief get the elapsed cycles since perf_counter is initialised
* \return int64_t the elpased cycles
*/
__attribute__((noinline))
extern int64_t get_system_ticks(void);
#ifdef __PERF_CNT_USE_LONG_CLOCK__
/*! \note the prototype of this clock() is different from the one defined in
*! time.h. As clock_t is usually defined as unsigned int, it is
*! not big enough in Cortex-M system to hold a time-stamp. clock()
*! defined here returns the timestamp since the begining of main()
*! and its unit is clock cycle (rather than 1ms). Hence, for a system
*! running under several hundreds MHz or even 1GHz, e.g. RT10xx from
*! NXP, it is very easy to see a counter overflow as clock_t is
*! defined as uint32_t in timer.h.
*! Since we are not allowed to change the defintion of clock_t in
*! official header file, i.e. time.h, I use a compatible prototype
*! after I checked the AAPCS spec. So, the return of the clock() is
*! int64_t, which will use the R0 to store the lower 32bits and R1
*! to store the higher 32bits. When you are using the prototype from
*! timer.h, caller will only take the lower 32bits stored in R0 and
*! the higher 32bits stored in R1 will be ignored.
*!
*! If you want to use the non-overflow version of this clock(), please
*! 1) define the MACRO: __PERF_CNT_USE_LONG_CLOCK__ in your project
*! and 2) do not include system header file <time.h>
*!
*/
#if !defined(__IS_COMPILER_IAR__)
__attribute__((nothrow))
#endif
__attribute__((noinline))
extern int64_t clock(void);
#endif
/*!
* \brief try to set a start pointer for the performance counter
*/
__STATIC_INLINE
void start_cycle_counter(void)
{
g_lLastTimeStamp = get_system_ticks();
}
/*!
* \brief calculate the elapsed cycle count since the last start point
* \note you can have multiple stop_cycle_counter following one start point
* \return int32_t the elapsed cycle count
*/
__STATIC_INLINE
int64_t stop_cycle_counter(void)
{
int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
return lTemp - g_nOffset;
}
/*! @} */
/*!
* \addtogroup gBasicTimerService 1.2 Timer Service
* \ingroup gBasic
* @{
*/
/*!
* \brief get the elapsed milliseconds since perf_counter is initialised
* \return int32_t the elapsed milliseconds
*/
extern int32_t get_system_ms(void);
/*!
* \brief get the elapsed microsecond since perf_counter is initialised
* \return int32_t the elapsed microsecond
*/
extern int32_t get_system_us(void);
/*!
* \brief delay specified time in microsecond
* \param[in] nUs time in microsecond
*/
extern void delay_us(int32_t nUs);
/*!
* \brief delay specified time in millisecond
* \param[in] nMs time in millisecond
*/
extern void delay_ms(int32_t nMs);
/*!
* \brief convert ticks of a reference timer to millisecond
*
* \param[in] lTick the tick count
* \return int64_t the millisecond
*/
extern
int64_t perfc_convert_ticks_to_ms(int64_t lTick);
/*!
* \brief convert millisecond into ticks of the reference timer
*
* \param[in] wMS the target time in millisecond
* \return int64_t the ticks
*/
extern
int64_t perfc_convert_ms_to_ticks(uint32_t wMS);
/*!
* \brief convert ticks of a reference timer to microsecond
*
* \param[in] lTick the tick count
* \return int64_t the microsecond
*/
extern
int64_t perfc_convert_ticks_to_us(int64_t lTick);
/*!
* \brief convert microsecond into ticks of the reference timer
*
* \param[in] wUS the target time in microsecond
* \return int64_t the ticks
*/
extern
int64_t perfc_convert_us_to_ticks(uint32_t wUS);
/*!
* \brief set an alarm with given period and check the status
*
* \param[in] lPeriod a time period in ticks
* \param[in] plTimestamp a pointer points to an int64_t integer, if NULL is
* passed, an static local variable inside the function will be used
* \param[in] bAutoReload whether starting next period after a timeout event.
* \return bool whether it is timeout or not
*/
extern
bool __perfc_is_time_out(int64_t lPeriod, int64_t *plTimestamp, bool bAutoReload);
/*! @} */
/*!
* \addtogroup gRTOS 2 RTOS Support
* @{
*/
#if defined(__PERF_CNT_USE_RTOS__)
/*! \brief initialize the default virtual cycle counter for the current task
*/
extern void init_task_cycle_counter(void);
/*! \brief check whether the task stack canary is safe or not
* \retval false likely to be a stack-overflow
* \retval true task stack is safe
*/
extern
bool perfc_check_task_stack_canary_safe(void);
/*! \brief provide cycle information for target task
* \details Support RTOS List:
* - RTX5
* - RT-Thread
* - ThreadX
* - FreeRTOS
*
* \return task_cycle_info_t* the cycle info object passed to this function
*/
extern task_cycle_info_t * get_rtos_task_cycle_info(void);
/*!
* \brief intialize a given task_cycle_info_t object and enable it before
* registering it.
* \return task_cycle_info_t* the cycle info object passed to this function
*/
extern task_cycle_info_t *init_task_cycle_info(task_cycle_info_t *ptInfo);
/*! \brief enable a given task_cycle_info_t object
*
* \param[in] ptInfo the address of target task_cycle_info_t object
* \return bool previous status
*/
extern bool enable_task_cycle_info(task_cycle_info_t *ptInfo);
/*! \brief disable a given task_cycle_info_t object
*
* \param[in] ptInfo the address of target task_cycle_info_t object
* \return bool previous status
*/
extern bool disable_task_cycle_info(task_cycle_info_t *ptInfo);
/*! \brief resume the enabled status of a given task_cycle_info_t object
*
* \param[in] ptInfo the address of target task_cycle_info_t object
* \param[in] bEnabledStatus the previous status
*/
extern
void resume_task_cycle_info(task_cycle_info_t *ptInfo, bool bEnabledStatus);
/*!
* \brief register a global virtual cycle counter agent to the current task
* \param[in] ptInfo the address of target task_cycle_info_t object
* \param[in] ptAgent an list node for the task_cycle_info_t object
* \note the ptAgent it is better to be allocated as a static variable, global
* variable or comes from heap or pool
*
* \return task_cycle_info_agent_t* the agent passed to this function
*/
extern
task_cycle_info_agent_t *register_task_cycle_agent(
task_cycle_info_t *ptInfo,
task_cycle_info_agent_t *ptAgent);
/*!
* \brief remove a global virtual cycle counter agent from the current task
* \param[in] ptAgent the list node currently in use
* \return task_cycle_info_agent_t* the agent passed to this function
*/
extern
task_cycle_info_agent_t *
unregister_task_cycle_agent(task_cycle_info_agent_t *ptAgent);
/*! \brief reset and start the virtual cycle counter for the current task
*
* \param[in] ptInfo the target task_cycle_info_t object
*/
__attribute__((noinline))
extern void __start_task_cycle_counter(task_cycle_info_t *ptInfo);
/*! \brief calculate the elapsed cycle count for current task since the last
* start point
*
* \note you can call stop_cycle_counter() multiple times following one
* start_task_cycle_counter()
*
* \param[in] ptInfo the target task_cycle_info_t object
*
* \note When ptInfo is NULL, it returns current task cycle info, when ptInfo
* is non-NULL, it returns the total used cycles of the specified
* task_cycle_info_t object.
*
* \return int64_t the elapsed cycle count.
*/
__attribute__((noinline))
extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
#define start_task_cycle_counter(...) \
__start_task_cycle_counter((NULL,##__VA_ARGS__))
#define stop_task_cycle_counter(...) \
__stop_task_cycle_counter((NULL,##__VA_ARGS__))
#elif !defined(__IMPLEMENT_PERF_COUNTER)
# define start_task_cycle_counter(...) start_cycle_counter()
# define stop_task_cycle_counter(...) stop_cycle_counter()
# define init_task_cycle_counter()
# define register_task_cycle_agent(...)
# define unregister_task_cycle_agent(...)
# define init_task_cycle_info(...) (NULL)
# define enable_task_cycle_info(...) (false)
# define disable_task_cycle_info(...) (false)
# define resume_task_cycle_info(...)
# define perfc_check_task_stack_canary_safe() (false)
#endif
/*! @} */
/*!
* \addtogroup gBasic 1 Basic
* @{
*/
/*----------------------------------------------------------------------------*
* Please ignore the following APIs unless you have encountered some known *
* special conditions *
*----------------------------------------------------------------------------*/
/*! \brief initialise cycle counter service
* \note - don't forget to tell the function whether the systick is already
* used by user applications.
* Don't worry, this cycle counter service won't affect your existing
* systick service.
*
* \note - Usually the perf_counter can initialise itself with the help of
* __attribute__((constructor(255))), this works fine in Arm Compiler
* 5 (armcc), Arm Compiler 6 (armclang), arm gcc and llvm. It doesn't
* work for IAR. So, when you are using IAR, please call this function
* manually to initialise the perf_counter service.
*
* \note - Perf_counter library assumes that:
* 1. Your project has already using SysTick
* 2. It assumes that you have already implemented the SysTick_Handler
* 3. It assumes that you have enabled the exception handling for
* SysTick.
* If these are not the case, please:
* 1. Add an empty SysTick_Handler to your project if you don't have
* one
* 2. Make sure you have the SysTick Exception handling enabled
* 3. And call function init_cycle_counter(false) if you doesn't
* use SysTick in your project at all.
*
* \param[in] bIsSysTickOccupied A boolean value which indicates whether SysTick
* is already used by user application.
*/
extern void init_cycle_counter(bool bIsSysTickOccupied);
/*!
* \brief a system timer handler inserted to the SysTick_Handler
*
* \note - if you are using a compiler other than armcc or armclang, e.g. iar,
* arm gcc etc, the systick_wrapper_ual.o doesn't work with the linker
* of your target toolchain as it use the $Super$$ which is only supported
* by armlink. For this condition, you have to manually put this function
* into your existing SysTick_Handler to make the perf_counter library
* work.
*
* \note - if you are using Arm Compiler 5 (armcc) or Arm Compiler 6 (armclang)
* you do NOT have to insert this function into your SysTick_Handler,
* the systick_wrapper_ual.s will do the work for you.
*/
extern void user_code_insert_to_systick_handler(void);
/*!
* \brief update perf_counter as SystemCoreClock has been updated.
*/
extern void update_perf_counter(void);
/*!
* \brief prepare for reconfiguration of SysTick timer.
*
* \note some systems (e.g. FreeRTOS) might reconfigure the systick timer to
* fulfil the requirement of their feature. To support this, just
* before the reconfiguration, please call this function in order
* to make the perf_counter works correctly later.
*
* \note after the reconfiguration, please call update_perf_counter() to apply
* the changes to perf_counter.
*
* \note this function will stop the SysTick, clear the pending bit and set
* the Load register and Current Value register to zero.
*/
extern void before_cycle_counter_reconfiguration(void);
/*! @} */
/*!
* \addtogroup gBenchmark 3 Benchmark
* @{
*/
#ifdef __PERF_COUNTER_COREMARK__
/*!
* \brief entry for coremark
*/
void coremark_main(void);
#endif
/*! @} */
//#if defined(__clang__)
//# pragma clang diagnostic pop
//#elif defined(__IS_COMPILER_GCC__)
//# pragma GCC diagnostic pop
//#endif
#ifdef __cplusplus
}
#endif
#endif

Binary file not shown.

View File

@ -1,240 +0,0 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
all the API functions to use the MPU wrappers. That should only be done when
task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "stack_macros.h"
/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
for the header files above, but not in this file, in order to generate the
correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
#include "perf_counter.h"
#include "cmsis_compiler.h"
/*============================ MACROS ========================================*/
#undef __WRAP_FUNC
#undef WRAP_FUNC
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
# define __ORIG_FUNC(__NAME) __real_##__NAME
#endif
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
struct __task_cycle_info_t {
task_cycle_info_t tInfo;
int64_t lLastTimeStamp;
task_cycle_info_agent_t tList;
uint32_t wMagicWord;
} ;
/*============================ TYPES =========================================*/
/*
* Task control block. A task control block (TCB) is allocated for each task,
* and stores task state information, including a pointer to the task's context
* (the task's run time environment, including register values)
*/
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
#endif
ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
StackType_t *pxStack; /*< Points to the start of the stack. */
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTCBNumber; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
#endif
#if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
UBaseType_t uxMutexesHeld;
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t pxTaskTag;
#endif
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
#endif
#if( configGENERATE_RUN_TIME_STATS == 1 )
uint32_t ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
#endif
#if ( configUSE_NEWLIB_REENTRANT == 1 )
/* Allocate a Newlib reent structure that is specific to this task.
Note Newlib support has been included by popular demand, but is not
used by the FreeRTOS maintainers themselves. FreeRTOS is not
responsible for resulting newlib operation. User must be familiar with
newlib and must provide system-wide implementations of the necessary
stubs. Be warned that (at the time of writing) the current newlib design
implements a system-wide malloc() that must be provided with locks.
See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
for additional information. */
struct _reent xNewLib_reent;
#endif
#if( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue;
volatile uint8_t ucNotifyState;
#endif
/* See the comments in FreeRTOS.h with the definition of
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
#endif
#if( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted;
#endif
#if( configUSE_POSIX_ERRNO == 1 )
int iTaskErrno;
#endif
} tskTCB;
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;
/*lint -save -e956 A manual analysis and inspection has been used to determine
which static variables must be declared volatile. */
PRIVILEGED_DATA
extern TCB_t * volatile pxCurrentTCB;
/*! \note if you aren't using perf_counter inside KEIL with RTE, please create
*! a header file called "Pre_Include_Global.h", copy the following
*! content into the header file and and put following option
*! to your command line (supposing you are using arm compiler 6):
*! -include "Pre_Include_Global.h"
*/
/*
//! \brief Enable RTOS Patch for perf_counter
#define __PERF_CNT_USE_RTOS__
#define traceTASK_SWITCHED_OUT_DISABLE
#define traceTASK_SWITCHED_IN_DISABLE
extern void __freertos_evr_on_task_switched_out (void *ptTCB);
extern void __freertos_evr_on_task_switched_in(void *ptTCB, unsigned int uxTopPriority) ;
# define traceTASK_SWITCHED_OUT() \
__freertos_evr_on_task_switched_out(pxCurrentTCB)
# define traceTASK_SWITCHED_IN() \
__freertos_evr_on_task_switched_in(pxCurrentTCB, uxTopReadyPriority)
*/
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
extern void __on_context_switch_in(uint32_t *pwStack);
extern void __on_context_switch_out(uint32_t *pwStack);
/*============================ IMPLEMENTATION ================================*/
#if defined(RTE_Compiler_EventRecorder)
# include "EventRecorder.h"
#endif
#define EvtFreeRTOSTasksNo (0xF0U)
#define EvtFreeRTOSTasks_TaskSwitchedOut \
EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0BU)
#define EvtFreeRTOSTasks_TaskSwitchedIn \
EventID(EventLevelOp, EvtFreeRTOSTasksNo, 0x0CU)
void __freertos_evr_on_task_switched_out (void *ptTCB) {
#if defined(RTE_Compiler_EventRecorder)
EventRecord2(EvtFreeRTOSTasks_TaskSwitchedOut, (uint32_t)ptTCB, 0U);
#else
(void)pxCurrentTCB;
#endif
__on_context_switch_out(((TCB_t *)ptTCB)->pxStack);
}
void __freertos_evr_on_task_switched_in(void *ptTCB, uint32_t uxTopPriority) {
#if defined(RTE_Compiler_EventRecorder)
EventRecord2(EvtFreeRTOSTasks_TaskSwitchedIn, (uint32_t)ptTCB, uxTopPriority);
#else
(void)pxCurrentTCB;
(void)uxTopPriority;
#endif
__on_context_switch_in(((TCB_t *)ptTCB)->pxStack);
}
task_cycle_info_t * get_rtos_task_cycle_info(void)
{
return &(((struct __task_cycle_info_t *)pxCurrentTCB->pxStack)->tInfo);
}

View File

@ -1,112 +0,0 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#include <rtthread.h>
#include "perf_counter.h"
#include "cmsis_compiler.h"
/*============================ MACROS ========================================*/
#undef __WRAP_FUNC
#undef WRAP_FUNC
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
# define __ORIG_FUNC(__NAME) __real_##__NAME
#endif
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
struct __task_cycle_info_t {
task_cycle_info_t tInfo;
int64_t lLastTimeStamp;
task_cycle_info_agent_t tList;
uint32_t wMagicWord;
} ;
#ifndef RT_USING_HOOK
#error "In order to use perf_counter:RT-Thread-Patch, please define RT_USING_HOOK \
in rtconfig.h. If you don't want to use this patch, please un-select it in RTE."
#endif
/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
extern void __on_context_switch_in(uint32_t *pwStack);
extern void __on_context_switch_out(uint32_t *pwStack);
extern struct rt_thread *rt_current_thread;
/*============================ IMPLEMENTATION ================================*/
void __rt_thread_scheduler_hook(struct rt_thread *from, struct rt_thread *to)
{
if (NULL != from) {
__on_context_switch_out(from->stack_addr);
}
__on_context_switch_in(to->stack_addr);
}
task_cycle_info_t * get_rtos_task_cycle_info(void)
{
return &(((struct __task_cycle_info_t *)rt_current_thread->stack_addr)->tInfo);
}
void __perf_os_patch_init(void)
{
#if defined(RTTHREAD_VERSION) && (RTTHREAD_VERSION >= (4 * 10000))
rt_tick_sethook(user_code_insert_to_systick_handler);
#endif
#if !defined(PKG_USING_PERF_COUNTER) || (defined(PKG_PERF_COUNTER_USING_THREAD_STATISTIC))
rt_scheduler_sethook(__rt_thread_scheduler_hook);
#endif
}
#ifdef PKG_USING_PERF_COUNTER
#if defined(RTTHREAD_VERSION) && (RTTHREAD_VERSION >= (4 * 10000))
void __ensure_systick_wrapper(void)
{
}
#endif
#define DBG_TAG "perf_counter"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
static int _perf_counter_init(void)
{
extern uint32_t SystemCoreClock;
init_cycle_counter(true);
LOG_I("perf_counter init, SystemCoreClock:%d", SystemCoreClock);
return 0;
}
INIT_PREV_EXPORT(_perf_counter_init);
#endif /* PKG_USING_PERF_COUNTER */

View File

@ -1,99 +0,0 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#include "rtx_os.h"
#include "perf_counter.h"
#include "cmsis_compiler.h"
#include "rtx_evr.h" // RTX Event Recorder definitions
/*============================ MACROS ========================================*/
#undef __WRAP_FUNC
#undef WRAP_FUNC
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
# define __ORIG_FUNC(__NAME) __real_##__NAME
#endif
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
struct __task_cycle_info_t {
task_cycle_info_t tInfo;
int64_t lLastTimeStamp;
task_cycle_info_agent_t tList;
uint32_t wMagicWord;
} ;
/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
extern void __on_context_switch_in(uint32_t *pwStack);
extern void __on_context_switch_out(uint32_t *pwStack);
/*============================ IMPLEMENTATION ================================*/
/*! \brief wrapper function for rtos context switching */
void __on_context_switch (osRtxThread_t *thread)
{
if (NULL != osRtxInfo.thread.run.curr) {
__on_context_switch_out(osRtxInfo.thread.run.curr->stack_mem);
}
__on_context_switch_in(thread->stack_mem);
}
__attribute__((used))
void EvrRtxThreadSwitched (osThreadId_t thread_id)
{
__on_context_switch((osRtxThread_t *)thread_id);
#if defined(RTE_Compiler_EventRecorder)
# define EvtRtxThreadSwitched \
EventID(EventLevelOp, EvtRtxThreadNo, 0x19U)
(void)EventRecord2(EvtRtxThreadSwitched, (uint32_t)thread_id, 0U);
#else
(void)thread_id;
#endif
}
task_cycle_info_t * get_rtos_task_cycle_info(void)
{
osRtxThread_t *curr = osRtxInfo.thread.run.curr;
if (NULL == curr) {
return NULL;
}
return &(((struct __task_cycle_info_t *)curr->stack_mem)->tInfo);
}

View File

@ -1,128 +0,0 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#include "tx_api.h"
#include "tx_thread.h"
#include "perf_counter.h"
#include "cmsis_compiler.h"
/*============================ MACROS ========================================*/
#undef __WRAP_FUNC
#undef WRAP_FUNC
#if defined(__IS_COMPILER_ARM_COMPILER__) && __IS_COMPILER_ARM_COMPILER__
# define __WRAP_FUNC(__NAME) $Sub$$##__NAME
# define __ORIG_FUNC(__NAME) $Super$$##__NAME
#elif (defined(__IS_COMPILER_LLVM__) && __IS_COMPILER_LLVM__) \
|| (defined(__IS_COMPILER_GCC__) && __IS_COMPILER_GCC__)
# define __WRAP_FUNC(__NAME) __wrap_##__NAME
# define __ORIG_FUNC(__NAME) __real_##__NAME
#endif
#define WRAP_FUNC(__NAME) __WRAP_FUNC(__NAME)
#define ORIG_FUNC(__NAME) __ORIG_FUNC(__NAME)
#if defined(TX_ENABLE_EXECUTION_CHANGE_NOTIFY) && defined(TX_EXECUTION_PROFILE_ENABLE)
#error In order to use perf_counter:ThreadX-Patch, please define \
TX_ENABLE_EXECUTION_CHANGE_NOTIFY or TX_EXECUTION_PROFILE_ENABLE \
in the project configuration, according to the version of thread.\
If you don't want to use this patch, please un-select it in RTE\
or remove this patch from the compilation.
#endif
/*============================ TYPES =========================================*/
struct __task_cycle_info_t {
task_cycle_info_t tInfo;
int64_t lLastTimeStamp;
task_cycle_info_agent_t tList;
uint32_t wMagicWord;
} ;
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
extern void __on_context_switch_in(uint32_t *pwStack);
extern void __on_context_switch_out(uint32_t *pwStack);
/*============================ IMPLEMENTATION ================================*/
#if defined(TX_EXECUTION_PROFILE_ENABLE)
void WRAP_FUNC(_tx_execution_thread_enter)(void)
#else
void _tx_execution_thread_enter (void)
#endif
{
TX_THREAD * ptThread = NULL;
TX_THREAD_GET_CURRENT(ptThread);
__on_context_switch_in(ptThread->tx_thread_stack_start);
#if defined(TX_EXECUTION_PROFILE_ENABLE)
extern void ORIG_FUNC(_tx_execution_thread_enter)(void);
ORIG_FUNC(_tx_execution_thread_enter)();
#endif
}
#if defined(TX_EXECUTION_PROFILE_ENABLE)
void WRAP_FUNC(_tx_execution_thread_exit)(void)
#else
void _tx_execution_thread_exit(void)
#endif
{
TX_THREAD * ptThread = NULL;
TX_THREAD_GET_CURRENT(ptThread);
if (NULL != ptThread) {
__on_context_switch_out(ptThread->tx_thread_stack_start);
}
#if defined(TX_EXECUTION_PROFILE_ENABLE)
extern void ORIG_FUNC(_tx_execution_thread_exit)(void);
ORIG_FUNC(_tx_execution_thread_exit)();
#endif
}
#if !defined(TX_EXECUTION_PROFILE_ENABLE)
void _tx_execution_isr_exit(void)
{
}
void _tx_execution_isr_enter(void)
{
}
#endif
task_cycle_info_t * get_rtos_task_cycle_info(void)
{
TX_THREAD * ptThread = NULL;
TX_THREAD_GET_CURRENT(ptThread);
return &(((struct __task_cycle_info_t *)ptThread->tx_thread_stack_start)->tInfo);
}

View File

@ -76,7 +76,7 @@ void EvrRtxThreadSwitched (osThreadId_t thread_id)
{
__on_context_switch((osRtxThread_t *)thread_id);
#if defined(RTE_Compiler_EventRecorder)
#if defined(RTE_Compiler_EventRecorder) || defined(RTE_CMSIS_View_EventRecorder)
# define EvtRtxThreadSwitched \
EventID(EventLevelOp, EvtRtxThreadNo, 0x19U)

View File

@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
@ -48,114 +48,12 @@
# define PERF_CNT_DELAY_US_COMPENSATION 90
#endif
/* IO definitions (access restrictions to peripheral registers) */
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
/* Memory mapping of Core Hardware */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
/*@} end of group CMSIS_SysTick */
#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
#define MAGIC_WORD_AGENT_LIST_VALID 0x8492A53C
#define MAGIC_WORD_CANARY 0xDEADBEEF
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
/*!
\brief Structure type to access the System Timer (SysTick).
*/
typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
/*!
\brief Structure type to access the System Control Block (SCB).
*/
typedef struct
{
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
__IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
__IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
__IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
__IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
__IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
__IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
__IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
__IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
__IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
__IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
__IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
__IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
__IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
uint32_t RESERVED0[5U];
__IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
} SCB_Type;
struct __task_cycle_info_t {
task_cycle_info_t tInfo; //!< cycle information
int64_t lLastTimeStamp; //!< previous timestamp
@ -165,66 +63,66 @@ struct __task_cycle_info_t {
/*============================ GLOBAL VARIABLES ==============================*/
extern uint32_t SystemCoreClock;
/*============================ LOCAL VARIABLES ===============================*/
volatile int64_t g_lLastTimeStamp = 0;
volatile static int64_t s_lOldTimestamp;
volatile int32_t g_nOffset = 0;
volatile static int32_t s_nUSUnit = 1;
volatile static int32_t s_nMSUnit = 1;
volatile static int32_t s_nMSResidule = 0;
volatile static int32_t s_nUSResidule = 0;
volatile static int32_t s_nSystemMS = 0;
volatile static int32_t s_nSystemUS = 0;
volatile static uint32_t s_wUSUnit = 1;
volatile static uint32_t s_wMSUnit = 1;
volatile static uint32_t s_wMSResidule = 0;
volatile static uint32_t s_wUSResidule = 0;
volatile static int64_t s_lSystemMS = 0;
volatile static int64_t s_lSystemUS = 0;
volatile static int64_t s_lSystemClockCounts = 0;
/*============================ PROTOTYPES ====================================*/
/* low level interface for porting */
extern
uint32_t perfc_port_get_system_timer_freq(void);
extern
int64_t perfc_port_get_system_timer_top(void);
extern
bool perfc_port_is_system_timer_ovf_pending(void);
extern
bool perfc_port_init_system_timer(bool bTimerOccupied);
extern
int64_t perfc_port_get_system_timer_elapsed(void);
extern
void perfc_port_clear_system_timer_ovf_pending(void);
extern
void perfc_port_stop_system_timer_counting(void);
extern
void perfc_port_clear_system_timer_counter(void);
/*============================ IMPLEMENTATION ================================*/
/*============================ INCLUDES ======================================*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
void perfc_port_insert_to_system_timer_insert_ovf_handler(void)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
//__IRQ_SAFE {
SysTick->CTRL = 0;
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
//NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
//SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
//}
return (0UL); /* Function successful */
}
void user_code_insert_to_systick_handler(void)
{
uint32_t wLoad = SysTick->LOAD + 1;
s_lSystemClockCounts += wLoad;
int64_t lLoad = perfc_port_get_system_timer_top() + 1;
s_lSystemClockCounts += lLoad;
// update system ms counter
do {
s_nMSResidule += wLoad;
int32_t nMS = s_nMSResidule / s_nMSUnit;
s_nMSResidule -= nMS * s_nMSUnit;
s_nSystemMS += nMS;
int64_t lTemp = s_wMSResidule + lLoad;
int64_t lMS = lTemp / s_wMSUnit;
s_lSystemMS += lMS;
s_wMSResidule = (uint32_t)((int64_t)lTemp - (int64_t)lMS * s_wMSUnit);
} while(0);
// update system us counter
do {
s_nUSResidule += wLoad;
int32_t nUS = s_nUSResidule / s_nUSUnit;
s_nUSResidule -= nUS * s_nUSUnit;
s_nSystemUS += nUS;
int64_t lTemp = s_wUSResidule + lLoad;
int64_t lUS = lTemp / s_wUSUnit;
s_lSystemUS += lUS;
s_wUSResidule = (uint32_t)((int64_t)lTemp - (int64_t)lUS * s_wUSUnit);
} while(0);
}
@ -237,8 +135,9 @@ void __perf_os_patch_init(void)
void update_perf_counter(void)
{
s_nUSUnit = SystemCoreClock / 1000000ul;
s_nMSUnit = SystemCoreClock / 1000ul;
uint32_t wSystemFrequency = perfc_port_get_system_timer_freq();
s_wUSUnit = wSystemFrequency / 1000000ul;
s_wMSUnit = wSystemFrequency / 1000ul;
__IRQ_SAFE {
g_lLastTimeStamp = get_system_ticks();
@ -246,31 +145,32 @@ void update_perf_counter(void)
}
}
void init_cycle_counter(bool bIsSysTickOccupied)
bool init_cycle_counter(bool bIsSysTickOccupied)
{
bool bResult = false;
__IRQ_SAFE {
if (!bIsSysTickOccupied) {
SysTick_Config(0x01000000); // use the longest period
}
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
bResult = perfc_port_init_system_timer(bIsSysTickOccupied); // use the longest period
perfc_port_clear_system_timer_ovf_pending();
}
update_perf_counter();
s_lSystemClockCounts = 0; // reset system cycle counter
s_nSystemMS = 0; // reset system millisecond counter
s_nSystemUS = 0; // reset system microsecond counter
s_lSystemMS = 0; // reset system millisecond counter
s_lSystemUS = 0; // reset system microsecond counter
__perf_os_patch_init();
return bResult;
}
/*! \note this function should only be called when irq is disabled
* hence SysTick-LOAD and (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk)
* won't change.
*/
__STATIC_INLINE int32_t check_systick(void)
__STATIC_INLINE int64_t check_systick(void)
{
int32_t nTemp = (int32_t)SysTick->LOAD - (int32_t)SysTick->VAL;
int64_t lLoad = perfc_port_get_system_timer_top() + 1;
int64_t lTemp = perfc_port_get_system_timer_elapsed();
/* Since we cannot stop counting temporarily, there are several
* conditions which we should take into consideration:
@ -292,35 +192,32 @@ __STATIC_INLINE int32_t check_systick(void)
* equals to) PERF_CNT_COMPENSATION_THRESHOLD.
* The following code implements an equivalent logic.
*/
if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk){
if (((int32_t)SysTick->LOAD - nTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
nTemp += SysTick->LOAD + 1;
if (perfc_port_is_system_timer_ovf_pending()){
if ((lLoad - lTemp) >= PERF_CNT_COMPENSATION_THRESHOLD) {
lTemp += lLoad;
}
}
return nTemp;
return lTemp;
}
void before_cycle_counter_reconfiguration(void)
{
__IRQ_SAFE {
SysTick->CTRL = 0; /* disable SysTick first */
perfc_port_stop_system_timer_counting();
if (SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) { /* pending SysTick exception */
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk; /* clear pending bit */
if (perfc_port_is_system_timer_ovf_pending()) {
perfc_port_clear_system_timer_ovf_pending(); /* clear pending bit */
user_code_insert_to_systick_handler(); /* manually handle exception */
}
s_lSystemClockCounts = get_system_ticks(); /* get the final cycle counter value */
SysTick->LOAD = 0UL;
SysTick->VAL = 0UL; /* clear the Current Value Register */
perfc_port_clear_system_timer_counter();
}
}
__attribute__((constructor))
void __perf_counter_init(void)
{
@ -328,9 +225,9 @@ void __perf_counter_init(void)
}
void delay_us(int32_t nUs)
void delay_us(uint32_t wUs)
{
int64_t lUs = (int64_t)nUs * (int64_t)s_nUSUnit;
int64_t lUs = (int64_t)wUs * (int64_t)s_wUSUnit;
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
? g_nOffset
: PERF_CNT_DELAY_US_COMPENSATION;
@ -345,22 +242,21 @@ void delay_us(int32_t nUs)
while(get_system_ticks() < lUs);
}
void delay_ms(int32_t nMs)
void delay_ms(uint32_t wMs)
{
int64_t lUs = (int64_t)nMs * (int64_t)s_nMSUnit;
int64_t lMs = (int64_t)wMs * (int64_t)s_wMSUnit;
int32_t iCompensate = g_nOffset > PERF_CNT_DELAY_US_COMPENSATION
? g_nOffset
: PERF_CNT_DELAY_US_COMPENSATION;
if (lUs <= iCompensate) {
if (lMs <= iCompensate) {
return ;
}
lUs -= iCompensate;
lMs -= iCompensate;
lUs += get_system_ticks();
while(get_system_ticks() < lUs);
lMs += get_system_ticks();
while(get_system_ticks() < lMs);
}
__attribute__((noinline))
@ -420,47 +316,47 @@ int64_t clock(void)
return get_system_ticks();
}
int32_t get_system_ms(void)
int64_t get_system_ms(void)
{
int32_t nTemp = 0;
int64_t lTemp = 0;
__IRQ_SAFE {
nTemp = s_nSystemMS + (check_systick() + s_nMSResidule) / s_nMSUnit;
lTemp = s_lSystemMS + ((check_systick() + (int64_t)s_wMSResidule) / s_wMSUnit);
}
return nTemp;
return lTemp;
}
int32_t get_system_us(void)
int64_t get_system_us(void)
{
int32_t nTemp = 0;
int64_t lTemp = 0;
__IRQ_SAFE {
nTemp = s_nSystemUS + (check_systick() + s_nUSResidule) / s_nUSUnit;
lTemp = s_lSystemUS + ((check_systick() + (int64_t)s_wUSResidule) / s_wUSUnit);
}
return nTemp;
return lTemp;
}
int64_t perfc_convert_ticks_to_ms(int64_t lTick)
{
return lTick / (int64_t)s_nMSUnit;
return lTick / (int64_t)s_wMSUnit;
}
int64_t perfc_convert_ms_to_ticks(uint32_t wMS)
{
int64_t lResult = (int64_t)s_nMSUnit * (int64_t)wMS;
int64_t lResult = (int64_t)s_wMSUnit * (int64_t)wMS;
return lResult ? lResult : 1;
}
int64_t perfc_convert_ticks_to_us(int64_t lTick)
{
return lTick / (int64_t)s_nUSUnit;
return lTick / (int64_t)s_wUSUnit;
}
int64_t perfc_convert_us_to_ticks(uint32_t wMS)
{
int64_t lResult = (int64_t)s_nUSUnit * (int64_t)wMS;
int64_t lResult = (int64_t)s_wUSUnit * (int64_t)wMS;
return lResult ? lResult : 1;
}
@ -504,7 +400,7 @@ uint32_t EventRecorderTimerSetup (void)
/// \return timer frequency in Hz
uint32_t EventRecorderTimerGetFreq (void)
{
return SystemCoreClock;
return perfc_port_get_system_timer_freq();
}
/// Get timer count.

View File

@ -1,5 +1,5 @@
/****************************************************************************
* Copyright 2022 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
@ -22,7 +22,12 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "cmsis_compiler.h"
#ifndef __PERFC_CFG_PORTING_INCLUDE__
# include "perfc_port_default.h"
#else
# include __PERFC_CFG_PORTING_INCLUDE__
#endif
#ifdef __cplusplus
extern "C" {
@ -34,8 +39,8 @@ extern "C" {
* @{
*/
#define __PERF_COUNTER_VER_MAJOR__ 2
#define __PERF_COUNTER_VER_MINOR__ 2
#define __PERF_COUNTER_VER_REVISE__ 4
#define __PERF_COUNTER_VER_MINOR__ 3
#define __PERF_COUNTER_VER_REVISE__ 0
#define __PERF_COUNTER_VER_STR__ ""
@ -134,6 +139,33 @@ extern "C" {
# define UNUSED_PARAM(__VAR) (void)(__VAR)
#endif
#ifndef MIN
# define MIN(__a, __b) ((__a) <= (__b) ? (__a) : (__b))
#endif
#ifndef MAX
# define MAX(__a, __b) ((__a) >= (__b) ? (__a) : (__b))
#endif
/*!
* \brief an attribute for static variables that no initialisation is required
* in the C startup process.
*/
#ifndef PERF_NOINIT
# if defined(__IS_COMPILER_ARM_COMPILER_5__)
# define PERF_NOINIT __attribute__(( section( ".bss.noinit"),zero_init))
# elif defined(__IS_COMPILER_ARM_COMPILER_6__)
# define PERF_NOINIT __attribute__(( section( ".bss.noinit")))
# elif defined(__IS_COMPILER_IAR__)
# define PERF_NOINIT __no_init
# elif (defined(__IS_COMPILER_GCC__) || defined(__IS_COMPILER_LLVM__)) && !defined(__APPLE__)
# define PERF_NOINIT __attribute__(( section( ".bss.noinit")))
# else
# define PERF_NOINIT
# endif
#endif
#undef __CONNECT2
#undef __CONNECT3
#undef __CONNECT4
@ -265,26 +297,26 @@ extern "C" {
#ifndef safe_atom_code
# define safe_atom_code() \
using( uint32_t SAFE_NAME(temp) = \
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
__disable_irq(); \
SAFE_NAME(temp2);}), \
__set_PRIMASK(SAFE_NAME(temp)))
using( perfc_global_interrupt_status_t SAFE_NAME(temp) = \
perfc_port_disable_global_interrupt(), \
perfc_port_resume_global_interrupt(SAFE_NAME(temp)))
#endif
#ifndef __IRQ_SAFE
# define __IRQ_SAFE \
using( uint32_t SAFE_NAME(temp) = \
({ uint32_t SAFE_NAME(temp2)=__get_PRIMASK(); \
__disable_irq(); \
SAFE_NAME(temp2);}), \
__set_PRIMASK(SAFE_NAME(temp)))
using( perfc_global_interrupt_status_t SAFE_NAME(temp) = \
perfc_port_disable_global_interrupt(), \
perfc_port_resume_global_interrupt(SAFE_NAME(temp)))
#endif
#ifndef __perf_counter_printf__
# define __perf_counter_printf__ printf
#endif
/* deprecated macro for backward compatibility */
#define user_code_insert_to_systick_handler \
perfc_port_insert_to_system_timer_insert_ovf_handler
#if __PLOOC_VA_NUM_ARGS() != 0
#warning Please enable GNU extensions, it is required by __cycleof__() and \
__super_loop_monitor__()
@ -331,7 +363,7 @@ __asm(".global __ensure_systick_wrapper\n\t");
__perf_counter_printf__( \
"--------------------------------------------\r\n"); \
__perf_counter_printf__( \
__STR " total cycle count: %ld [%016lx]\r\n", \
__STR " total cycle count: %ld [%08lx]\r\n", \
(long)_, (long)_); \
} else { \
__VA_ARGS__ \
@ -348,18 +380,18 @@ __asm(".global __ensure_systick_wrapper\n\t");
E.g.
\code
while (1) {
__cpu_time__(100) {
__cpu_usage__(100) {
delay_us(5000);
}
delay_us(5000);
}
\endcode
*/
#define __cpu_time__(__CNT, ...) \
#define __cpu_usage__(__CNT, ...) \
static int64_t SAFE_NAME(s_lTimestamp) = 0, SAFE_NAME(s_lTotal) = 0; \
static uint32_t s_wLoopCounter = (__CNT); \
static uint32_t SAFE_NAME(s_wLoopCounter) = (__CNT); \
using(float __usage__ = 0, ({ \
if (0 == s_wLoopCounter) { \
if (0 == SAFE_NAME(s_wLoopCounter)) { \
__usage__ = (float)((double)SAFE_NAME(s_lTotal) \
/ (double)( get_system_ticks() \
- SAFE_NAME(s_lTimestamp))); \
@ -367,18 +399,20 @@ __asm(".global __ensure_systick_wrapper\n\t");
SAFE_NAME(s_lTimestamp) = 0; \
SAFE_NAME(s_lTotal) = 0; \
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
__perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__); \
__perf_counter_printf__("CPU Usage %3.2f%%\r\n", (double)__usage__);\
} else { \
__VA_ARGS__ \
} \
} \
if (0 == SAFE_NAME(s_lTimestamp)) { \
SAFE_NAME(s_lTimestamp) = get_system_ticks(); \
s_wLoopCounter = (__CNT); \
SAFE_NAME(s_wLoopCounter) = (__CNT); \
} \
start_task_cycle_counter();}), \
({SAFE_NAME(s_lTotal) += stop_task_cycle_counter(); \
s_wLoopCounter--;}))
SAFE_NAME(s_wLoopCounter)--;}))
#define __cpu_time__ __cpu_usage__
/*!
* \addtogroup gBasicTimerService 1.2 Timer Service
@ -555,7 +589,6 @@ extern volatile int32_t g_nOffset;
/*============================ PROTOTYPES ====================================*/
/*!
* \addtogroup gBasicTicks 1.1 Ticks APIs
* \ingroup gBasic
@ -601,7 +634,7 @@ extern int64_t clock(void);
/*!
* \brief try to set a start pointer for the performance counter
*/
__STATIC_INLINE
static inline
void start_cycle_counter(void)
{
g_lLastTimeStamp = get_system_ticks();
@ -612,7 +645,7 @@ void start_cycle_counter(void)
* \note you can have multiple stop_cycle_counter following one start point
* \return int32_t the elapsed cycle count
*/
__STATIC_INLINE
static inline
int64_t stop_cycle_counter(void)
{
int64_t lTemp = (get_system_ticks() - g_lLastTimeStamp);
@ -634,29 +667,27 @@ int64_t stop_cycle_counter(void)
/*!
* \brief get the elapsed milliseconds since perf_counter is initialised
* \return int32_t the elapsed milliseconds
* \return int64_t the elapsed milliseconds
*/
extern int32_t get_system_ms(void);
extern int64_t get_system_ms(void);
/*!
* \brief get the elapsed microsecond since perf_counter is initialised
* \return int32_t the elapsed microsecond
* \return int64_t the elapsed microsecond
*/
extern int32_t get_system_us(void);
extern int64_t get_system_us(void);
/*!
* \brief delay specified time in microsecond
* \param[in] nUs time in microsecond
* \param[in] wUs time in microsecond
*/
extern void delay_us(int32_t nUs);
extern void delay_us(uint32_t wUs);
/*!
* \brief delay specified time in millisecond
* \param[in] nMs time in millisecond
* \param[in] wMs time in millisecond
*/
extern void delay_ms(int32_t nMs);
extern void delay_ms(uint32_t nMs);
/*!
* \brief convert ticks of a reference timer to millisecond
@ -875,12 +906,16 @@ extern int64_t __stop_task_cycle_counter(task_cycle_info_t *ptInfo);
*
* \param[in] bIsSysTickOccupied A boolean value which indicates whether SysTick
* is already used by user application.
*
* \return false Failed to initialize the timer counter, as the timer is not
* available or IO error.
* \return true initialization is successful.
*/
extern void init_cycle_counter(bool bIsSysTickOccupied);
extern bool init_cycle_counter(bool bIsSysTickOccupied);
/*!
* \brief a system timer handler inserted to the SysTick_Handler
* \brief a system timer overflow handler
*
* \note - if you are using a compiler other than armcc or armclang, e.g. iar,
* arm gcc etc, the systick_wrapper_ual.o doesn't work with the linker
@ -893,7 +928,7 @@ extern void init_cycle_counter(bool bIsSysTickOccupied);
* you do NOT have to insert this function into your SysTick_Handler,
* the systick_wrapper_ual.s will do the work for you.
*/
extern void user_code_insert_to_systick_handler(void);
extern void perfc_port_insert_to_system_timer_insert_ovf_handler(void);
/*!
* \brief update perf_counter as SystemCoreClock has been updated.
@ -943,5 +978,4 @@ void coremark_main(void);
#ifdef __cplusplus
}
#endif
#endif

230
perfc_port_default.c Normal file
View File

@ -0,0 +1,230 @@
/****************************************************************************
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#undef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "cmsis_compiler.h"
#define __IMPLEMENT_PERF_COUNTER
#include "perf_counter.h"
#if defined(__IS_COMPILER_GCC__)
# pragma GCC diagnostic ignored "-Wattributes"
#endif
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wreserved-identifier"
# pragma clang diagnostic ignored "-Wconditional-uninitialized"
# pragma clang diagnostic ignored "-Wcast-align"
# pragma clang diagnostic ignored "-Wmissing-prototypes"
#endif
/*============================ MACROS ========================================*/
/* IO definitions (access restrictions to peripheral registers) */
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
/* Memory mapping of Core Hardware */
#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */
#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */
#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */
#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */
#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */
/* SysTick Control / Status Register Definitions */
#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */
#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */
#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */
#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */
#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */
/* SysTick Reload Register Definitions */
#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */
#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */
/* SysTick Current Register Definitions */
#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */
#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */
/* SysTick Calibration Register Definitions */
#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */
#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */
#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */
#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */
/*@} end of group CMSIS_SysTick */
#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */
#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */
#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */
#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */
#ifndef __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
# define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 0
#endif
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
/*!
\brief Structure type to access the System Timer (SysTick).
*/
typedef struct
{
__IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
__IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
__IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
__IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
} SysTick_Type;
/*!
\brief Structure type to access the System Control Block (SCB).
*/
typedef struct
{
__IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */
__IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */
__IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */
__IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */
__IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */
__IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */
__IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */
__IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */
__IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */
__IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */
__IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */
__IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */
__IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */
__IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */
__IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */
__IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */
__IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */
__IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */
__IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */
uint32_t RESERVED0[5U];
__IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */
} SCB_Type;
/*============================ GLOBAL VARIABLES ==============================*/
extern uint32_t SystemCoreClock;
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
/*============================ IMPLEMENTATION ================================*/
/*============================ INCLUDES ======================================*/
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
__WEAK
bool perfc_port_init_system_timer(bool bTimerOccupied)
{
do {
if (bTimerOccupied) {
break;
}
__IRQ_SAFE {
SysTick->CTRL = 0;
SysTick->LOAD = SysTick_LOAD_RELOAD_Msk; /* set reload register */
//NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
//SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
}
} while(0);
return true;
}
__WEAK
uint32_t perfc_port_get_system_timer_freq(void)
{
return SystemCoreClock;
}
__WEAK
bool perfc_port_is_system_timer_ovf_pending(void)
{
return SCB->ICSR & SCB_ICSR_PENDSTSET_Msk;
}
__WEAK
int64_t perfc_port_get_system_timer_top(void)
{
return SysTick->LOAD;
}
__WEAK
int64_t perfc_port_get_system_timer_elapsed(void)
{
return (int64_t)SysTick->LOAD - (uint32_t)SysTick->VAL;
}
__WEAK
void perfc_port_clear_system_timer_ovf_pending(void)
{
SCB->ICSR = SCB_ICSR_PENDSTCLR_Msk;
}
__WEAK
void perfc_port_stop_system_timer_counting(void)
{
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
__WEAK
void perfc_port_clear_system_timer_counter(void)
{
SysTick->VAL = 0UL;
}
#endif

53
perfc_port_default.h Normal file
View File

@ -0,0 +1,53 @@
/****************************************************************************
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#ifndef __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
# define __PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__ 0
#endif
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
#include "cmsis_compiler.h"
/*============================ MACROS ========================================*/
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
typedef uint32_t perfc_global_interrupt_status_t;
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
/*============================ IMPLEMENTATION ================================*/
__STATIC_INLINE
perfc_global_interrupt_status_t perfc_port_disable_global_interrupt(void)
{
perfc_global_interrupt_status_t tStatus = __get_PRIMASK();
__disable_irq();
return tStatus;
}
__STATIC_INLINE
void perfc_port_resume_global_interrupt(perfc_global_interrupt_status_t tStatus)
{
__set_PRIMASK(tStatus);
}
#endif

1769
perfc_port_pmu.c Normal file

File diff suppressed because it is too large Load Diff

131
perfc_port_pmu.h Normal file
View File

@ -0,0 +1,131 @@
/****************************************************************************
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#if __PERFC_USE_PMU_PORTING__
#include "cmsis_compiler.h"
/*============================ MACROS ========================================*/
/*============================ MACROFIED FUNCTIONS ===========================*/
#define __cpu_perf__(__str, ...) \
using( \
struct { \
uint64_t dwNoInstr; \
uint64_t dwNoMemAccess; \
uint64_t dwNoL1DCacheRefill; \
int64_t lCycles; \
uint32_t wInstrCalib; \
uint32_t wMemAccessCalib; \
float fCPI; \
float fDCacheMissRate; \
} __PERF_INFO__ = {0}, \
({ \
__PERF_INFO__.dwNoInstr = perfc_pmu_get_instruction_count(); \
__PERF_INFO__.dwNoMemAccess = perfc_pmu_get_memory_access_count(); \
__PERF_INFO__.wInstrCalib = perfc_pmu_get_instruction_count() \
- __PERF_INFO__.dwNoInstr; \
__PERF_INFO__.wMemAccessCalib = perfc_pmu_get_memory_access_count() \
- __PERF_INFO__.dwNoMemAccess; \
__PERF_INFO__.dwNoL1DCacheRefill \
= perfc_pmu_get_L1_dcache_refill_count(); \
__PERF_INFO__.dwNoInstr = perfc_pmu_get_instruction_count(); \
__PERF_INFO__.dwNoMemAccess = perfc_pmu_get_memory_access_count(); \
}), \
({ \
__PERF_INFO__.dwNoInstr = perfc_pmu_get_instruction_count() \
- __PERF_INFO__.dwNoInstr \
- __PERF_INFO__.wInstrCalib; \
__PERF_INFO__.dwNoMemAccess = perfc_pmu_get_memory_access_count() \
- __PERF_INFO__.dwNoMemAccess \
- __PERF_INFO__.wMemAccessCalib; \
__PERF_INFO__.dwNoL1DCacheRefill \
= perfc_pmu_get_L1_dcache_refill_count() \
- __PERF_INFO__.dwNoL1DCacheRefill; \
\
__PERF_INFO__.fDCacheMissRate \
= (float)( (double)__PERF_INFO__.dwNoL1DCacheRefill \
/ (double)__PERF_INFO__.dwNoMemAccess) \
* 100.0f; \
\
__PERF_INFO__.fCPI = (float)( (double)__PERF_INFO__.lCycles \
/ (double)__PERF_INFO__.dwNoInstr); \
if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \
__perf_counter_printf__( "\r\n" \
"[Report for " __str "]\r\n" \
"-----------------------------------------\r\n" \
"Instruction executed: %lld\r\n" \
"Cycle Used: %lld\r\n" \
"Cycles per Instructions: %3.3f \r\n\r\n" \
"Memory Access Count: %lld\r\n" \
"L1 DCache Refill Count: %lld\r\n" \
"L1 DCache Miss Rate: %3.4f %% \r\n" \
, \
__PERF_INFO__.dwNoInstr, \
__PERF_INFO__.lCycles, \
(double)__PERF_INFO__.fCPI, \
__PERF_INFO__.dwNoMemAccess, \
__PERF_INFO__.dwNoL1DCacheRefill, \
(double)__PERF_INFO__.fDCacheMissRate \
); \
} else { \
__VA_ARGS__ \
} \
})) \
__cycleof__("", { __PERF_INFO__.lCycles = __cycle_count__; })
/*============================ TYPES =========================================*/
typedef uint32_t perfc_global_interrupt_status_t;
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
extern
void perfc_port_pmu_insert_to_debug_monitor_handler(void);
extern
uint64_t perfc_pmu_get_instruction_count(void);
extern
uint64_t perfc_pmu_get_memory_access_count(void);
extern
uint64_t perfc_pmu_get_L1_dcache_refill_count(void);
/*============================ IMPLEMENTATION ================================*/
__STATIC_INLINE
perfc_global_interrupt_status_t perfc_port_disable_global_interrupt(void)
{
perfc_global_interrupt_status_t tStatus = __get_PRIMASK();
__disable_irq();
return tStatus;
}
__STATIC_INLINE
void perfc_port_resume_global_interrupt(perfc_global_interrupt_status_t tStatus)
{
__set_PRIMASK(tStatus);
}
#endif

View File

@ -15,6 +15,7 @@
;* *
;****************************************************************************/
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
.syntax unified
.arch armv6-m
@ -28,7 +29,7 @@
__wrap_SysTick_Handler:
push {r4, r5}
push {r4, lr}
ldr R0, =user_code_insert_to_systick_handler
ldr R0, =perfc_port_insert_to_system_timer_insert_ovf_handler
blx R0
pop {r4, r5}
mov lr, r5
@ -42,3 +43,4 @@ __wrap_SysTick_Handler:
__ensure_systick_wrapper:
bx lr
#endif

View File

@ -14,34 +14,40 @@
;* limitations under the License. *
;* *
;****************************************************************************/
#if defined(_RTE_)
# include "RTE_Components.h"
#endif
#if !defined(__RTE_PERFC_PORTING_USER_DEFINED__) && !defined(__PERFC_USE_PMU_PORTING__)
.syntax unified
.arch armv6-m
#if !__PERFC_CFG_DISABLE_DEFAULT_SYSTICK_PORTING__
.syntax unified
.arch armv6-m
.eabi_attribute Tag_ABI_align_preserved, 1
.text
.thumb
.thumb_func
.align 2
.globl $Sub$$SysTick_Handler
.type $Sub$$SysTick_Handler, %function
.align 2
.globl $Sub$$SysTick_Handler
.type $Sub$$SysTick_Handler, %function
$Sub$$SysTick_Handler:
push {r4, r5}
push {r4, lr}
ldr R0, =user_code_insert_to_systick_handler
ldr R0, =perfc_port_insert_to_system_timer_insert_ovf_handler
blx R0
pop {r4, r5}
mov lr, r5
pop {r4, r5}
ldr R0, =$Super$$SysTick_Handler
bx R0
.globl __ensure_systick_wrapper
.type __ensure_systick_wrapper, %function
.globl __ensure_systick_wrapper
.type __ensure_systick_wrapper, %function
__ensure_systick_wrapper:
bx lr
#endif
#endif

View File

@ -22,11 +22,11 @@
|$Sub$$SysTick_Handler| PROC
EXPORT |$Sub$$SysTick_Handler|
IMPORT user_code_insert_to_systick_handler
IMPORT perfc_port_insert_to_system_timer_insert_ovf_handler
IMPORT |$Super$$SysTick_Handler|
push {r4, r5}
push {r4, lr}
LDR R0, =user_code_insert_to_systick_handler
LDR R0, =perfc_port_insert_to_system_timer_insert_ovf_handler
BLX R0
pop {r4, r5}
mov lr, r5

132
template/perfc_port_user.c Normal file
View File

@ -0,0 +1,132 @@
/****************************************************************************
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#undef __PERF_COUNT_PLATFORM_SPECIFIC_HEADER__
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define __IMPLEMENT_PERF_COUNTER
#include "perf_counter.h"
#if defined(__IS_COMPILER_GCC__)
# pragma GCC diagnostic ignored "-Wattributes"
#endif
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wreserved-identifier"
# pragma clang diagnostic ignored "-Wconditional-uninitialized"
# pragma clang diagnostic ignored "-Wcast-align"
# pragma clang diagnostic ignored "-Wmissing-prototypes"
#endif
/*============================ MACROS ========================================*/
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
/* low level interface for porting */
extern
uint32_t perfc_port_get_system_timer_freq(void);
extern
int64_t perfc_port_get_system_timer_top(void);
extern
bool perfc_port_is_system_timer_ovf_pending(void);
extern
bool perfc_port_init_system_timer(bool bTimerOccupied);
extern
int64_t perfc_port_get_system_timer_elapsed(void);
extern
void perfc_port_clear_system_timer_ovf_pending(void);
extern
void perfc_port_stop_system_timer_counting(void);
extern
void perfc_port_clear_system_timer_counter(void);
/*============================ IMPLEMENTATION ================================*/
/*============================ INCLUDES ======================================*/
#if __PERFC_USE_USER_CUSTOM_PORTING__
bool perfc_port_init_system_timer(bool bIsTimeOccupied)
{
bool bResult = true;
do {
if (bIsTimeOccupied) {
break;
}
__IRQ_SAFE {
/* Configure the system timer count with the longest possible period
* clear counter
* Clear overflow pending flag
* Enable interrupt if required
* start counting
*/
}
} while(0);
return true;
}
uint32_t perfc_port_get_system_timer_freq(void)
{
/* return the system timer frequency */
return 0;
}
bool perfc_port_is_system_timer_ovf_pending(void)
{
/* whether the system timer overflow is pending */
return false;
}
int64_t perfc_port_get_system_timer_top(void)
{
/* the top value of the counting */
return 0;
}
int64_t perfc_port_get_system_timer_elapsed(void)
{
/* the elapsed count number since last overflow */
return 0;
}
void perfc_port_clear_system_timer_ovf_pending(void)
{
/* clear the overflow pending flag */
}
void perfc_port_stop_system_timer_counting(void)
{
/* stop the system timer */
}
void perfc_port_clear_system_timer_counter(void)
{
/* clear the system timer counter */
}
#endif

View File

@ -0,0 +1,53 @@
/****************************************************************************
* Copyright 2024 Gorgon Meducer (Email:embedded_zhuoran@hotmail.com) *
* *
* Licensed under the Apache License, Version 2.0 (the "License"); *
* you may not use this file except in compliance with the License. *
* You may obtain a copy of the License at *
* *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an "AS IS" BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
****************************************************************************/
/*============================ INCLUDES ======================================*/
#if __PERFC_USE_USER_CUSTOM_PORTING__
/*============================ MACROS ========================================*/
/*============================ MACROFIED FUNCTIONS ===========================*/
/*============================ TYPES =========================================*/
typedef uint32_t perfc_global_interrupt_status_t;
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
/*============================ IMPLEMENTATION ================================*/
static
inline
perfc_global_interrupt_status_t perfc_port_disable_global_interrupt(void)
{
perfc_global_interrupt_status_t tStatus;
/* get global interrupt status */
/* disable global interrupt */
/* return the status */
return tStatus;
}
static
inline
void perfc_port_resume_global_interrupt(perfc_global_interrupt_status_t tStatus)
{
/* resume the stored global interrupt status */
}
#endif