As an optional function of the kernel, memory corruption check is used to check the integrity of a dynamic memory pool. This mechanism can detect memory corruption errors in the memory pool in a timely manner and provide alerts. It helps reduce problem locating costs and increase troubleshooting efficiency.
## Function Configuration<a name="section4696190123420"></a>
**LOSCFG\_BASE\_MEM\_NODE\_INTEGRITY\_CHECK**: specifies the setting of the memory corruption check. This function is disabled by default. To enable this function, configure it in **Debug-\> Enable integrity check or not**.
## Function Configuration
**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** specifies the setting of the memory corruption check. This function is disabled by default. You can enable it in **Debug -> Enable integrity check or not**.
If this macro is enabled, the memory pool integrity will be checked in real time upon each memory allocation.
If this macro is not enabled, you can call **LOS\_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS\_MemIntegrityCheck** does not affect the system performance. In addition, the check accuracy decreases because the node header does not contain the magic number \(which is available only when **LOSCFG\_BASE\_MEM\_NODE\_INTEGRITY\_CHECK** is enabled\).
If this macro is not enabled, you can call **LOS_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS_MemIntegrityCheck** does not affect the system performance. However, the check accuracy decreases because the node header does not contain the magic number (which is available only when **LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** is enabled).
This check only detects the corrupted memory node and provides information about the previous node (because memory is contiguous, a node is most likely corrupted by the previous node). To further determine the location where the previous node is requested, you need to enable the memory leak check and use LRs to locate the fault.
> **CAUTION**<br/>
> If memory corruption check is enabled, a magic number is added to the node header, which increases the size of the node header. The real-time integrity check has a great impact on the performance. In performance-sensitive scenarios, you are advised to disable this function and use **LOS_MemIntegrityCheck** to check the memory pool integrity.
This check only detects the corrupted memory node and provides information about the previous node \(because memory is contiguous, a node is most likely corrupted by the previous node\). To further determine the location where the previous node is requested, you need to enable the memory leak check and use LRs to locate the fault.
>If memory corruption check is enabled, a magic number is added to the node header, which increases the size of the node header. The real-time integrity check has a great impact on the performance. In performance-sensitive scenarios, you are advised to disable this function and use **LOS\_MemIntegrityCheck** to check the memory pool integrity.
## Development Guidelines<a name="section672362973417"></a>
### How to Develop
### How to Develop<a name="section026014863416"></a>
Use **LOS_MemIntegrityCheck** to check for memory corruption. If no memory corruption occurs, **0** is returned and no log is output. If memory corruption occurs, the related log is output. For details, see the output of the following example.
Check for memory corruption by calling **LOS\_MemIntegrityCheck**. If no memory corruption occurs, **0** is returned and no log is output. If memory corruption occurs, the related log is output. For details, see the output of the following example.
### Development Example<a name="section186311302356"></a>
### Development Example
This example implements the following:
1. Requests two physically adjacent memory blocks.
2. Calls **memset** to construct an out-of-bounds access and overwrites the first four bytes of the next node.
3. Calls **LOS\_MemIntegrityCheck** to check whether memory corruption occurs.
1. Request two physically adjacent memory blocks.
2. Use **memset** to construct an out-of-bounds access and overwrites the first four bytes of the next node.
3. Call **LOS_MemIntegrityCheck** to check for memory corruption.
**Sample Code**
You can add the test function of the sample code to **TestTaskEntry** in **kernel/liteos_a/testsuites/kernel/src/osTest.c** for testing.
The sample code is as follows:
```
```c
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
...
...
@@ -44,10 +54,10 @@ The sample code is as follows:
voidMemIntegrityTest(void)
{
/* Request two physically adjacent memory blocks.*/
/* Request two physically adjacent memory blocks. */
void*ptr1=LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR,8);
void*ptr2=LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR,8);
/* Construct an out-of-bounds access to cause memory corruption. The memory block of the first node is 8 bytes. Clearing 12 bytes overwrites the header of the second memory node. */
/* Construct an out-of-bounds access to cause memory corruption. The memory block of the first node is 8 bytes. Clearing 12 bytes overwrites the header of the second memory node. */
memory used but magic num wrong, magic num = 0x00000000 /* Error information, indicating that the first four bytes, that is, the magic number, of the next node are corrupted.*/
memory used but magic num wrong, magic num = 0x00000000 /* Error information, indicating that the first four bytes, that is, the magic number, of the next node are corrupted.*/
/* Key information about the corrupted node and its previous node, including the address of the previous node, magic number of the node, and sizeAndFlag of the node. In this example, the magic number of the corrupted node is cleared. */
broken node head LR info: /* The node LR information can be output only after the memory leak check is enabled.*/
broken node head LR info: /* The node LR information can be output only after the memory leak check is enabled. */
LR[0]:0x0800414e
LR[1]:0x08000cc2
LR[2]:0x00000000
pre node head LR info: /* Based on the LR information, you can find where the previous node is requested in the assembly file and then perform further analysis.*/
pre node head LR info: /* Based on the LR information, you can find where the previous node is requested in the assembly file and then perform further analysis.*/
LR[0]:0x08004144
LR[1]:0x08000cc2
LR[2]:0x00000000
[ERR]Memory interity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* Addresses of the corrupted node and its previous node*/
[ERR]Memory integrity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* Addresses of the corrupted node and its previous node */
Memory information includes the memory pool size, memory usage, remaining memory size, maximum free memory, memory waterline, number of memory nodes, and fragmentation rate.
- Memory waterline: indicates the maximum memory used in a memory pool. The waterline value is updated upon each memory allocation and release. The memory pool size can be optimized based on this value.
- The memory waterline indicates the maximum memory used in a memory pool. The waterline value is updated each time the memory is allocated or released. The memory pool size can be optimized based on this value.
- The fragmentation rate indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
- Fragmentation rate: indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:
-You can use **LOS_MemInfoGet()** to scan the node information in the memory pool and collect the related statistics.
Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
## Function Configuration
- Other statistics: When **LOS\_MemInfoGet** is called, the node information in the memory pool is scanned and related statistics are collected.
**LOSCFG_MEM_WATERLINE** specifies the setting of the memory information statistics function. This function is disabled by default. If you want to obtain the memory waterline, enable it in **Debug-> Enable MEM Debug-> Enable memory pool waterline or not**.
## Function Configuration<a name="section470611682411"></a>
**LOSCFG\_MEM\_WATERLINE**: specifies the setting of the memory information statistics function. This function is disabled by default. To enable this function, configure it in **Debug-\> Enable memory pool waterline or not in the configuration item**. If you want to obtain the memory waterline, you must enable this macro.
## Development Guidelines
## Development Guidelines<a name="section9368374243"></a>
### How to Develop<a name="section679912407257"></a>
### How to Develop
Key structure:
```
```c
typedefstruct{
UINT32 totalUsedSize; // Memory usage of the memory pool
UINT32 totalFreeSize; // Remaining memory in the memory pool
UINT32 maxFreeNodeSize; // Maximum size of the free memory block in the memory pool
UINT32 usedNodeNum; // Number of non-free memory blocks in the memory pool
UINT32 freeNodeNum; // Number of free memory blocks in the memory pool
#if (LOSCFG_MEM_WATERLINE == 1) // This function is disabled by default and can be enabled using the menuconfig tool.
UINT32 usageWaterLine; // Waterline of the memory pool
UINT32totalUsedSize;// Memory usage of the memory pool.
UINT32totalFreeSize;// Remaining size of the memory pool.
UINT32maxFreeNodeSize;// Maximum size of the free memory block in the memory pool.
UINT32usedNodeNum;// Number of non-free memory blocks in the memory pool.
UINT32freeNodeNum;// Number of free memory blocks in the memory pool.
#if (LOSCFG_MEM_WATERLINE == 1) // This function is disabled by default and can be enabled using the **menuconfig** tool.
UINT32usageWaterLine;// Waterline of the memory pool.
#endif
}LOS_MEM_POOL_STATUS;
```
- To obtain the memory waterline, call **LOS\_MemInfoGet**. The first parameter in the API is the start address of the memory pool, and the second parameter is the handle of the **LOS\_MEM\_POOL\_STATUS** type. The **usageWaterLine** field indicates the waterline.
To obtain the memory waterline, call **LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *poolStatus)**. The first parameter specifies the start address of the memory pool, and the second parameter specifies the handle of the **LOS_MEM_POOL_STATUS** type. The **usageWaterLine** field indicates the waterline.
- To calculate the memory fragmentation rate, call **LOS\_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:
To calculate the memory fragmentation rate, call **LOS_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:
Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
### Development Example<a name="section1025453412611"></a>
### Development Example
This example implements the following:
1. Creates a monitoring task to obtain information about the memory pool.
2. Calls **LOS\_MemInfoGet** to obtain the basic information about the memory pool.
3. Calculates the memory usage and fragmentation rate.
1. Create a monitoring task to obtain information about the memory pool.
2. Call **LOS_MemInfoGet** to obtain the basic information about the memory pool.
3. Calculate the memory usage and fragmentation rate.
**Sample Code**
You can compile and verify the sample code in **kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **MemTest()** function is called in **TestTaskEntry**.
The sample code is as follows:
```
```c
#include <stdio.h>
#include <string.h>
#include "los_task.h"
...
...
@@ -66,15 +72,14 @@ void MemInfoTaskFunc(void)
{
LOS_MEM_POOL_STATUSpoolStatus={0};
/* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example.*/
/* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example.*/
void*pool=OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool,&poolStatus);
/* Calculate the fragmentation rate of the memory pool. */
As an optional function of the kernel, memory leak check is used to locate dynamic memory leak problems. After this function is enabled, the dynamic memory mechanism automatically records the link registers \(LRs\) used when memory is allocated. If a memory leak occurs, the recorded information helps locate the memory allocated for further analysis.
As an optional function of the kernel, memory leak check is used to locate dynamic memory leak problems. After this function is enabled, the dynamic memory mechanism automatically records the link registers (LRs) used when memory is allocated. If a memory leak occurs, the recorded information helps locate the memory allocated for further analysis.
## Function Configuration<a name="section13991354162914"></a>
1.**LOSCFG\_MEM\_LEAKCHECK**: specifies the setting of the memory leak check. This function is disabled by default. To enable this function, configure it in **Debug-\> Enable Function call stack of Mem operation recorded**.
2.**LOS\_RECORD\_LR\_CNT**: number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof\(void \*\)** bytes.
3.**LOS\_OMIT\_LR\_CNT**: number of ignored LRs. The default value is **2**, which indicates that LRs are recorded from the time when **LOS\_MemAlloc** is called. You can change the value based on actual requirements. This macro is configured because:
-**LOS\_MemAlloc** is also called internally.
-**LOS\_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOS\_RECORD\_LR\_CNT** is limited.
## Function Configuration
**LOSCFG_MEM_LEAKCHECK** specifies the setting of the memory leak check. This function is disabled by default. You can enable it in **Debug-> Enable MEM Debug-> Enable Function call stack of Mem operation recorded**.
**LOS_RECORD_LR_CNT** specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void *)** bytes.
**LOS_OMIT_LR_CNT** specifies the number of ignored LRs. The default value is **2**, which indicates that LRs are recorded from the time when **LOS_MemAlloc** is called. You can change the value based on actual requirements. The reasons for this configuration are as follows:
-**LOS_MemAlloc** is also called internally.
-**LOS_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOS_RECORD_LR_CNT** is limited.
Correctly setting this macro can ignore invalid LRs and reduce memory consumption.
## Development Guidelines<a name="section95828159308"></a>
### How to Develop<a name="section369844416304"></a>
## Development Guidelines
Memory leak check provides a method to check for memory leak in key code logic. If this function is enabled, LR information is recorded each time when memory is allocated. When **LOS\_MemUsedNodeShow** is called before and after the code snippet is checked, information about all nodes that have been used in the specified memory pool is printed. You can compare the node information. The newly added node information indicates the node where the memory leak may occur. You can locate the code based on the LR and further check whether a memory leak occurs.
The node information output by calling **LOS\_MemUsedNodeShow** is in the following format:
### How to Develop
- Each line contains information about a node.
- The first column indicates the node address, based on which you can obtain complete node information using a tool such as a GNU Debugger \(GDB\).
- The second column indicates the node size, which is equal to the node header size plus the data field size.
- Columns 3 to 5 list the LR addresses.
Memory leak check provides a method to check for memory leak in key code logic. If this function is enabled, LR information is recorded each time when memory is allocated. When **LOS_MemUsedNodeShow** is called before and after the code snippet is checked, information about all nodes that have been used in the specified memory pool is printed. You can compare the node information. The newly added node information indicates the node where the memory leak may occur. You can locate the code based on the LR and further check whether a memory leak occurs.
The node information output by calling **LOS_MemUsedNodeShow** is in the following format: <br>Each line contains information about a node. The first column indicates the node address, based on which you can obtain complete node information using a tool such as a GNU Debugger (GDB). The second column indicates the node size, which is equal to the node header size plus the data field size. Columns 3 to 5 list the LR addresses. You can determine the specific memory location of the node based on the LR addresses and the assembly file.
You can determine the specific memory location of the node based on the LR addresses and the assembly file.
>Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
> **CAUTION**
> Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
### Development Example<a name="section460801313313"></a>
### Development Example
This example implements the following:
1. Call **OsMemUsedNodeShow** to print information about all nodes.
2. Simulate a memory leak by requesting memory without releasing it.
3. Call **OsMemUsedNodeShow** to print information about all nodes.
4. Compare the logs to obtain information about the node where a memory leak occurred.
5. Locate the code based on the LR address.
1. Call **OsMemUsedNodeShow** to print information about all nodes.
2. Simulate a memory leak by requesting memory without releasing it.
3. Call **OsMemUsedNodeShow** to print information about all nodes.
4. Compare the logs to obtain information about the node where a memory leak occurred.
5. Locate the code based on the LR address.
**Sample Code**
You can compile and verify the sample code in **kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **MemLeakTest()** function is called in **TestTaskEntry**.
In this example, a memory pool is created. To achieve this purpose, you need to define **LOSCFG_MEM_MUL_POOL** in **target_config.h**.
perf is a performance analysis tool. It uses the performance monitoring unit (PMU) to count sampling events and collect context information and provides hot spot distribution and hot paths.
## Working Principles
When a performance event occurs, the corresponding event counter overflows and triggers an interrupt. The interrupt handler records the event information, including the current PC, task ID, and call stack.
perf provides two working modes: counting mode and sampling mode.
In counting mode, perf collects only the number of event occurrences and duration. In sampling mode, perf also collects context data and stores the data in a circular buffer. The IDE then analyzes the data and provides information about hotspot functions and paths.
## Available APIs
The Perf module of the OpenHarmony LiteOS-A kernel provides the following APIs. For details, see the [API reference](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h).
| Configuring perf sampling events| **LOS_PerfConfig**: sets the event type and sampling period. |
| Reading sampling data| **LOS_PerfDataRead**: reads the sampling data. |
| Registering a hook for the sampling data buffer| **LOS_PerfNotifyHookReg**: registers the hook to be called when the buffer waterline is reached.<br>**LOS_PerfFlushHookReg**: registers the hook for flushing the cache in the buffer. |
**PerfConfigAttr** is the structure of the perf sampling event. For details, see [kernel\include\los_perf.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h).
The sampling data buffer is a circular buffer, and only the region that has been read in the buffer can be overwritten.
The buffer has limited space. You can register a hook to provide a buffer overflow notification or perform buffer read operation when the buffer waterline is reached. The default buffer waterline is 1/2 of the buffer size. The code snippet is as follows:
```c
VOIDExample_PerfNotifyHook(VOID)
{
CHARbuf[LOSCFG_PERF_BUFFER_SIZE]={0};
UINT32len;
PRINT_DEBUG("perf buffer reach the waterline!\n");
If the buffer sampled by perf involves caches across CPUs, you can register a hook for flushing the cache to ensure cache consistency. The code snippet is as follows:
```c
VOIDExample_PerfFlushHook(VOID*addr,UINT32size)
{
OsCacheFlush(addr,size);/* platform interface */
}
LOS_PerfNotifyHookReg(Example_PerfFlushHook);
```
The API for flushing the cache is configured based on the platform.
## Development Guidelines
### Kernel-Mode Development Process
The typical process of enabling perf is as follows:
1. Configure the macros related to the perf module.
Configure the perf control macro **LOSCFG_KERNEL_PERF**, which is disabled by default. In the **kernel/liteos_a** directory, run the **make update_config** command, choose **Kernel**, and select **Enable Perf Feature**.
| LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming Calc Methods->By Tick | Whether to use tick as the perf timing unit.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_CYCLE | Time-consuming Calc Methods->By Cpu Cycle | Whether to use cycle as the perf timing unit.| YES/NO |
| LOSCFG_PERF_BUFFER_SIZE | Perf Sampling Buffer Size | Size of the buffer used for perf sampling.| INT |
| LOSCFG_PERF_HW_PMU | Enable Hardware Pmu Events for Sampling | Whether to enable hardware PMU events. The target platform must support the hardware PMU.| YES/NO |
| LOSCFG_PERF_TIMED_PMU | Enable Hrtimer Period Events for Sampling | Whether to enable high-precision periodical events. The target platform must support the high precision event timer (HPET).| YES/NO |
| LOSCFG_PERF_SW_PMU | Enable Software Events for Sampling | Whether to enable software events. **LOSCFG_KERNEL_HOOK** must also be enabled.| YES/NO |
2. Call **LOS_PerfConfig** to configure the events to be sampled.
perf provides two working modes and three types of events.
- Working modes: counting mode (counts only the number of event occurrences) and sampling mode (collects context information such as task IDs, PC, and backtrace)
- Event types: CPU hardware events (such as cycle, branch, icache, and dcache), high-precision periodical events (such as CPU clock), and OS software events (such as task switch, mux pend, and IRQ)
3. Call **LOS_PerfStart(UINT32 sectionId)** at the start of the code to be sampled. The input parameter **sectionId** specifies different sampling session IDs.
4. Call **LOS_PerfStop** at the end of the code to be sampled.
5. Call **LOS_PerfDataRead** to read the sampling data and use IDE to analyze the collected data.
#### Development Example
This example implements the following:
1. Create a perf task.
2. Configure sampling events.
3. Start perf.
4. Execute algorithms for statistics.
5. Stop perf.
6. Export the result.
#### Sample Code
Prerequisites: **Enable Hook Feature** and **Enable Software Events for Sampling** are selected for the perf module in **menuconfig**.
You can compile and verify the sample code in **kernel/liteos_a/testsuites/kernel/src/osTest.c**.
The code is as follows:
```c
#include "los_perf.h"
#define TEST_MALLOC_SIZE 200
#define TEST_TIME 5
/* Add malloc() and free() in the test() function. */
You can export the data using the JTAG interface and then use the IDE offline tool to analyze the data.
You can also call **LOS_PerfDataRead** to read data to a specified address for further analysis. In the example, **OsPrintBuff** is a test API, which prints the sampled data by byte. **num** indicates the sequence number of the byte, and **hex** indicates the value in the byte.
The central processing unit percent \(CPUP\) includes the system CPUP, process CPUP, task CPUP, and interrupt CPUP. With the system CPUP, you can determine whether the current system load exceeds the designed specifications. With the CPUP of each task/process/interrupt, you can determine whether their CPU usage meets expectations of the design.
The central processing unit percent (CPUP) includes the system CPUP, process CPUP, task CPUP, and interrupt CPUP. With the system CPUP, you can determine whether the current system load exceeds the designed specifications. With the CPUP of each task/process/interrupt, you can determine whether their CPU usage meets expectations of the design.
- System CPUP
- System CPUP
System CPUP is the CPU usage of the system within a period of time. It reflects the CPU load and the system running status (idle or busy) in the given period of time. The valid range of the system CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the system runs with full load.
System CPUP is the CPU usage of the system within a period of time. It reflects the CPU load and the system running status \(idle or busy\) in the given period of time. The valid range of the system CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the system runs with full load.
- Process CPUP
Process CPUP refers to the CPU usage of a single process. It reflects the process status, busy or idle, in a period of time. The valid range of the process CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the process is being executed for a period of time.
- Process CPUP
- Task CPUP
Task CPUP refers to the CPU usage of a single task. It reflects the task status, busy or idle, in a period of time. The valid range of task CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the task is being executed for the given period of time.
Process CPUP refers to the CPU usage of a single process. It reflects the process status, busy or idle, in a period of time. The valid range of the process CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the process is being executed for a period of time.
- Interrupt CPUP
Interrupt CPUP refers to the CPU usage of a single interrupt. It reflects the interrupt status, busy or idle, in a period of time. The valid range of the interrupt CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the interrupt is being executed for a period of time.
- Task CPUP
Task CPUP refers to the CPU usage of a single task. It reflects the task status, busy or idle, in a period of time. The valid range of task CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the task is being executed for the given period of time.
## Working Principles
- Interrupt CPUP
The OpenHarmony LiteOS-A kernel CPUP module records the CPU usage by process, task, and interrupt. When a process or task is switched, the start time of the process or task is recorded. When the process or task is switched out or exits, the system accumulates the CPU time of the entire process or task. When an interrupt is executed, the system accumulates and records the execution time of each interrupt.
Interrupt CPUP refers to the CPU usage of a single interrupt. It reflects the interrupt status, busy or idle, in a period of time. The valid range of the interrupt CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the interrupt is being executed for a period of time.
OpenHarmony provides the following types of CPUP information:
- System CPUP
## Working Principles<a name="section593718536227"></a>
- Process CPUP
The OpenHarmony LiteOS-A kernel CPUP module records the CPU usage by process, task, and interrupt. When a process or task is switched, the start time of the process or task is recorded. When the process or task is switched out or exits, the system accumulates the CPU time of the entire process or task. When an interrupt is executed, the system accumulates and records the execution time of each interrupt.
- Task CPUP
OpenHarmony provides the following types of CPUP information:
- System CPUP
- Process CPUP
- Task CPUP
- Interrupt CPUP
- Interrupt CPUP
The CPUP is calculated as follows:
...
...
@@ -43,136 +42,111 @@ Task CPUP = Total running time of the task/Total running time of the system
Interrupt CPUP = Total running time of the interrupt/Total running time of the system
## Development Guidelines<a name="section11284210152311"></a>
### Available APIs<a name="section3745151592312"></a>
<tdclass="cellrowborder"valign="top"width="35.12648735126487%"headers="mcps1.2.4.1.3 "><pid="p14808115353010"><aname="p14808115353010"></a><aname="p14808115353010"></a>Obtains the historical CPUP of the system.</p>
<tdclass="cellrowborder"valign="top"width="35.12648735126487%"headers="mcps1.2.4.1.3 "><pid="p1747959131016"><aname="p1747959131016"></a><aname="p1747959131016"></a>Obtains the historical CPUP of a specified process.</p>
<tdclass="cellrowborder"valign="top"headers="mcps1.2.4.1.2 "><pid="p1575419483116"><aname="p1575419483116"></a><aname="p1575419483116"></a>Obtains the historical CPUP of all processes in the system.</p>
<tdclass="cellrowborder"valign="top"width="35.12648735126487%"headers="mcps1.2.4.1.3 "><pid="p12808653183016"><aname="p12808653183016"></a><aname="p12808653183016"></a>Obtains the historical CPUP of a specified task.</p>
<tdclass="cellrowborder"valign="top"width="35.12648735126487%"headers="mcps1.2.4.1.3 "><pid="p33741531163313"><aname="p33741531163313"></a><aname="p33741531163313"></a>Obtains the historical CPUP of all interrupts in the system.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop<a name="section122901429182316"></a>
The typical CPUP development process is as follows.
1. Call **LOS\_HistorySysCpuUsage** to obtain the historical CPUP of the system.
2. Call **LOS\_HistoryProcessCpuUsage** to obtain the historical CPUP of a specified process.
- If the process has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the process is not created, return an error code.
3. Call **LOS\_GetAllProcessCpuUsage** to obtain the CPUP of all processes.
- If the CPUP has been initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP is not initialized or has invalid input parameters, return an error code.
4. Call **LOS\_HistoryTaskCpuUsage** to obtain the historical CPUP of a specified task.
- If the task has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the task is not created, return an error code.
5. Call **LOS\_GetAllIrqCpuUsage** to obtain the CPUP of all interrupts.
- If the CPUP has been initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP has not been initialized or has invalid input parameters, return an error code.
### Development Example<a name="section1765785212310"></a>
## Development Guidelines
### Available APIs
**Table 1** CPUP module APIs
| Category| API| Description|
| -------- | -------- | -------- |
| System CPUP| LOS_HistorySysCpuUsage | Obtains the historical CPUP of the system.|
| Process CPUP| LOS_HistoryProcessCpuUsage | Obtains the historical CPUP of a specified process.|
| Process CPUP| LOS_GetAllProcessCpuUsage | Obtains the historical CPUP of all processes in the system.|
| Task CPUP| LOS_HistoryTaskCpuUsage | Obtains the historical CPUP of a specified task.|
| Interrupt CPUP| LOS_GetAllIrqCpuUsage | Obtains the historical CPUP of all interrupts in the system.|
| Reset| LOS_CpupReset | Resets CPUP data.|
### How to Develop
The typical CPUP development process is as follows:
1. Call **LOS_HistorySysCpuUsage** to obtain the historical CPUP of the system.
2. Call **LOS_HistoryProcessCpuUsage** to obtain the historical CPUP of a specified process.
- If the process has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the process is not created, return an error code.
3. Call **LOS_GetAllProcessCpuUsage** to obtain the CPUP of all processes.
- If the CPUP is initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP is not initialized or has invalid input parameters, return an error code.
4. Call **LOS_HistoryTaskCpuUsage** to obtain the historical CPUP of a specified task.
- If the task has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the task is not created, return an error code.
5. Call **LOS_GetAllIrqCpuUsage** to obtain the CPUP of all interrupts.
- If the CPUP has been initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP is not initialized or has invalid input parameters, return an error code.
### Development Example
This example implements the following:
1. Create a task for the CPUP test.
2. Obtain the CPUP of the current system.
3. Obtain the historical system CPUP in different modes.
4. Obtain the CPUP of the created test task.
5. Obtain the CPUP of the created test task in different modes.
1. Create a task for the CPUP test.
2. Obtain the CPUP of the current system.
Prerequisites
3. Obtain the historical system CPUP in different modes.
The CPUP control is enabled in the **menuconfig** configuration.
4. Obtain the CPUP of the created test task.
5. Obtain the CPUP of the created test task in different modes.
Prerequisites:
The CPUP control is enabled in the **menuconfig** configuration.
**Sample Code**
You can compile and verify the sample code in **kernel/liteos_a/testsuites /kernel/src /osTest.c**. The **CpupTest** function is called in **TestTaskEntry**.
The musl libc library of the debug version provides mechanisms, such as memory leak check, heap memory statistics, memory corruption check, and backtrace, to improve the efficiency in locating memory problems in user space.
The musl libc library of the debug version provides maintenance and test methods, such as memory leak check, heap memory statistics, memory corruption check, and backtrace, to improve the efficiency of locating memory problems in user space.
Instrumentation is performed on the **malloc** and **free** APIs to log key node information. When memory is requested and released by a program, the memory node integrity is checked. When the program ends, memory statistics are provided for identifying memory leaks.
Instrumentation is performed in the **malloc** and **free** APIs to log key node information. The memory node integrity is checked when memory is requested and released by an application. When the application ends, memory statistics are provided to help identifying memory leaks.
## Working Principles
...
...
@@ -18,15 +17,15 @@ When memory is requested, key information is saved to the memory node control bl
When memory is released, the system matches the memory node control block based on the memory address to be released and deletes the control block.
When memory is allocated, the returned address is saved in a link register (LR). During the process running, the system adds information, such as the LR corresponding to the suspected leak, to the memory node control block. <xrefhref="#fig716011269106"idp:producemode_text="auto"class="- topic/xref "id="xref106398301961"></xref> shows the heap memory node information.
When memory is allocated, the returned address is saved in a link register (LR). During the process running, the system adds information, such as the LR corresponding to the suspected leak, to the memory node control block. The following figure shows the heap memory node information.
**TID** indicates the thread ID; **PID** indicates the process ID; **ptr** indicates the address of the memory requested; **size** indicates the size of the requested memory; **lr[*n*]** indicates the address of the call stack, and *n* is configurable.
...
...
@@ -34,9 +33,9 @@ When memory is released, the input parameter pointer in the **free** API is used
You can export the memory debugging information of each process through the serial port or file, and use the addr2line tool to convert the exported information into the code lines that cause memory leaks. In this way, the memory leakage problem can be solved.
**Figure 3** Process of locating the code line for a memory leak
**Figure 3** Process of locating the code line for a memory leak
@@ -46,25 +45,33 @@ You can collect statistics on the percentage of heap memory requested by each th
### Memory Integrity Check
- If the memory requested by using **malloc** is less than or equal to 0x1c000 bytes, the heap allocation algorithm is used to allocate memory.
- Requested memory less than or equal to 0x1c000 bytes
When the requested memory is less than or equal to 0x1c000 bytes, **malloc** uses the heap allocation algorithm to allocate memory.
When a user program requests heap memory, information such as the check value is added to the heap memory node. If the check value is abnormal, it is probably that the previous heap memory block is overwritten. Currently, the scenario where the check value is damaged by a wild pointer cannot be identified. When memory is allocated or released, the memory node check value is verified. If the memory node is corrupted and the verification fails, the following information is output: TID, PID, and call stack information saved when the previous heap memory block of the corrupted node is allocated. You can use the addr2line tool to obtain the specific code line and rectify the fault.
**Figure 4** Adding a check value to the node header information
When heap memory is released by **free**, the memory block is not released immediately. Instead, the magic number 0xFE is written into the memory block, which is then placed in the free queue to prevent the memory block from being allocated by **malloc** within a certain period of time. When a wild pointer or **use-after-free** operation is performed to read the memory, an exception can be detected. However, this mechanism does not apply to write operations.
When heap memory is released by using **free**, the memory block is not released immediately. Instead, the magic number 0xFE is written into the memory block, which is then placed in the free queue to prevent the memory block from being allocated by **malloc** within a certain period of time. When a wild pointer or **use-after-free** operation is performed to read the memory, an exception can be detected. However, this mechanism does not apply to write operations.
When the requested memory is greater than 0x1c000 bytes, **malloc** uses **mmap** to allocate memory.
- If the memory requested by using **malloc** is greater than 0x1c000 bytes, **mmap** is used to allocate memory.
When **mmap** is used to request a large memory block, one more page is allocated at the start and end of the memory region. The current **PAGE_SIZE** of each page is **0x1000**. The permissions of the two pages are set to **PROT_NONE** (no read or write permission) by using the **mprotect** API to prevent out-of-bounds read and write of memory. If out-of-bounds read and write of memory occurs, the user program becomes abnormal because the user does not have the read or write permission. The code logic can be identified based on the abnormal call stack information.
When **mmap** is used to allocate a large memory block, one more page is allocated at the start and end of the memory region. The current **PAGE_SIZE** of each page is **0x1000**. The permissions of the two pages are set to **PROT_NONE** (no read or write permission) by using the **mprotect** API to prevent out-of-bounds read and write of memory. If out-of-bounds read and write of memory occurs, the user program becomes abnormal because the user does not have the read or write permission. The code logic can be identified based on the abnormal call stack information.
**Figure 6** Layout of the memory allocated by using the **mmap** mechanism of **malloc**
**Figure 6** Layout of the memory allocated by using the **mmap** mechanism of **malloc**
@@ -105,7 +112,7 @@ You can perform heap memory debugging by using either of the following:
- CLI: By using the CLI, you do not need to modify user code. However, you cannot accurately check the heap memory information of a specific logic segment.
> After memory debugging is enabled, a heap memory leak check and a heap memory integrity check will be performed by default when a process exits. If memory debugging is disabled, the heap memory statistics, heap memory leak check, and heap memory integrity check cannot be enabled, and there is no response to the calling of any debug API.
...
...
@@ -119,7 +126,7 @@ You can perform heap memory debugging by using either of the following:
The sample code explicitly calls the related APIs of the memory debugging module to check the memory.
```
```c
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
...
...
@@ -127,7 +134,8 @@ The sample code explicitly calls the related APIs of the memory debugging module
> - In this example, the compiler path is written into an environment variable in the **.bashrc** file.
>
>
> - When compiling user programs and required libraries, add the option **-funwind-tables -rdynamic -g** for stack backtracking.
>
>
> - The **-mfloat-abi=softfp**, **-mcpu=cortex-a7**, and **-mfpu=neon-vfpv4** options specify the floating-point calculation optimization, chip architecture, and FPU, which must be the same as the compilation options used by the libc library. Otherwise, the libc library file cannot be found during the link time.
>
>
> - **-target arm-liteos** specifies the path of the library files related to the compiler.
>
>
> - **--sysroot=/home/<user-name>/harmony/out/hispark_taurus/ipcamera_hispark_taurus/sysroot** specifies the root directory of the compiler library files. In this example, the OpenHarmony project code is stored in **/home/<user-name>/harmony**. The **out/hispark_taurus/ipcamera_hispark_taurus** directory indicates the product specified by the **hb set** command during compilation. In this example, **ipcamera_hispark_taurus** is the product specified.
>
>
> - **$(clang -mfloat-abi=softfp -mcpu=cortex-a7 -mfpu=neon-vfpv4 -target arm-liteos -print-file-name=libunwind.a)** specifies the path of the unwind library.
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
OHOS # kill -36 4 // Check for heap memory leaks.
OHOS #
OHOS #
==PID:4== Detected memory leak(s):
[Check point]:
#00: <check_leak+0x1c4>[0x2da4c] -> /lib/libc.so
...
...
@@ -355,7 +365,7 @@ OHOS #
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
OHOS # kill -37 4 // Check the integrity of the head node of the heap memory.
OHOS #
OHOS #
Check heap integrity ok!
```
...
...
@@ -391,131 +401,132 @@ Now using addr2line ...
##### Running the mrecord Command
1. Run the user program and specify the path of the file that stores the memory debugging information.
```
OHOS # ./mem_check --mrecord /storage/check.txt
```
2. Run the **kill -35 <*pid*>** command to collect statistics on the memory information. The information is exported to a file. Run the **cat** command to view the information.
```
OHOS # kill -35 4
OHOS # Memory statistics information saved in /storage/pid(4)_check.txt
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
```
3. Run the **kill -36 <*pid*>** command to check memory integrity. The information is exported to a file. Run the **cat** command to view the information.
```
OHOS # kill -36 4
OHOS # Leak check information saved in /storage/pid(4)_check.txt
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
```
4. Run the **kill -9 <*pid*>** command to kill the current process. After the process exits, a memory integrity check is performed by default. The check result is output to a file. You can run the **cat** command to view it.
```
OHOS # kill -9 4
OHOS # Leak check information saved in /storage/pid(4)_check.txt
> The preceding information recorded gradually is added to the file specified during initialization. Therefore, running the **cat** command can also display the historical information in the file.
## Common Problems
### Use After Free (UAF)
- Requested memory block less than or equal to 0x1c000 bytes:
After the memory is released:
- Requested memory less than or equal to 0x1c000 bytes:
Read operation: If the magic number (0xFEFEFEFE) is read from the memory block released, UAF occurs.
> After **free** is called, the heap memory will not be released to the heap memory pool immediately. Instead, the heap memory is placed in a queue with a fixed length and filled with the magic number 0xFE. When the queue is full, the memory block first placed in the queue is released to the heap memory pool first.
Write operation: The memory debugging module cannot detect UAF errors from write operations.
- Requested memory block greater than 0x1c000 bytes:
The heap memory greater than 0x1c000 bytes must be requested by calling the **mmap** API via **malloc**. If the heap memory is accessed after being released, the user program will become abnormal (because the memory region has been unmapped).
...
...
@@ -527,16 +538,17 @@ Double free errors occur when **free()** is called more than once with the same
### Heap Memory Node Corrupted
- Requested memory block less than or equal to 0x1c000 bytes:
When a heap memory node is corrupted, the user program exits unexpectedly, and the call stack that requests the heap memory of the node corrupted is output. The memory debugging module, however, cannot debug the memory corrupted by a wild pointer. For example, if the user program mem_check has heap memory overwriting, you can use the command line to obtain the possible location of the memory corruption.
```
OHOS # ./mem_check --mwatch
OHOS #
OHOS # ./mem_check --mwatch
OHOS #
==PID:6== Memory integrity information:
[TID:28 allocated addr: 0x272e1ea0, size: 0x120] The possible attacker was allocated from:
#00: <malloc+0x808>[0x640e8] -> /lib/libc.so
#01: <threadFunc1+0x7c>[0x21d0] -> mem_check
#01: <threadFunc1+0x7c>[0x21d0] -> mem_check
```
You can use the call stack parsing script to parse the call stack information.
@@ -59,23 +59,20 @@ The user mode provides only the LMS check library. It does not provide external
The typical process for enabling LMS is as follows:
1. Configure the macros related to the LMS module.
Configure the LMS macro **LOSCFG_KERNEL_LMS**, which is disabled by default. Run the **make update_config** command in the **kernel/liteos_a** directory, choose **Kernel**, and select **Enable Lite Memory Sanitizer**.
@@ -260,7 +259,7 @@ The key output information is as follows:
### User-Mode Development Process
Add the following to the build script of the app to be checked. For details about the complete code, see **/kernel/liteos_a/apps/lms/BUILD.gn**.
Add the following to the app build script to be checked. For details about the sample code, see [/kernel/liteos_a/apps/lms/BUILD.gn](https://gitee.com/openharmony/kernel_liteos_a/blob/master/apps/lms/BUILD.gn).
```
...
...
@@ -318,7 +317,7 @@ This example implements the following:
The code is as follows:
```
```c
staticvoidBufWriteTest(void*buf,intstart,intend)
{
for(inti=start;i<=end;i++){
...
...
@@ -335,7 +334,7 @@ static void BufReadTest(void *buf, int start, int end)