未验证 提交 d4b7def9 编写于 作者: O openharmony_ci 提交者: Gitee

!14179 [翻译完成】#I6864H

Merge pull request !14179 from Annie_wang/PR12944
......@@ -135,7 +135,7 @@
- [Magic Key](kernel-small-debug-shell-magickey.md)
- [User-Space Exception Information](kernel-small-debug-shell-error.md)
- [Trace](kernel-small-debug-trace.md)
- [Perf](kernel-mini-memory-perf.md)
- [Perf](kernel-small-debug-perf.md)
- [LMS](kernel-small-memory-lms.md)
- [Process Debugging](kernel-small-debug-process-cpu.md)
- Kernel-Mode Memory Debugging
......
# Memory Corruption Check
## Basic Concepts<a name="section17368154517335"></a>
## Basic Concepts
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.
## Development Guidelines
>![](../public_sys-resources/icon-caution.gif) **CAUTION:**
>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:
void MemIntegrityTest(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. */
memset(ptr1, 0, 8 + 4);
LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR);
}
......@@ -55,24 +65,26 @@ void MemIntegrityTest(void)
**Verification**
The log is as follows:
```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
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. */
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
/* 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 Statistics
## Basic Concepts<a name="section52691565235"></a>
## Basic Concepts
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-&gt; Enable MEM Debug-&gt; 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
typedef struct {
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
UINT32 totalUsedSize; // Memory usage of the memory pool.
UINT32 totalFreeSize; // Remaining size of 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.
#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_STATUS poolStatus = {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. */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
/* Calculate the memory usage of the memory pool. */
unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool);
printf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize,
poolStatus.totalFreeSize, poolStatus.usageWaterLine);
dprintf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
}
int MemTest(void)
......@@ -88,18 +93,20 @@ int MemTest(void)
taskStatus.usTaskPrio = 10;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
return -1;
dprintf("task create failed\n");
return LOS_NOK;
}
return 0;
return LOS_OK;
}
```
**Verification**
The result is as follows:
The data may vary depending on the running environment.
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
```
# Memory Leak Check
## Basic Concepts<a name="section1026719436293"></a>
## Basic Concepts
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-&gt; Enable MEM Debug-&gt; 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.
```
node size LR[0] LR[1] LR[2]
0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002
0x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0
0x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4
node size LR[0] LR[1] LR[2]
0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002
0x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0
0x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4
0x10017978: 0x24 0x9b008ed0 0x9b068924 0x9b0687c4
0x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
0x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
```
>![](../public_sys-resources/icon-caution.gif) **CAUTION:**
>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**.
The sample code is as follows:
```
```c
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"
#define TEST_NEW_POOL_SIZE 2000
#define TEST_MALLOC_SIZE 8
void MemLeakTest(void)
{
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
VOID *pool = NULL;
/* Create a memory pool. */
pool = LOS_MemAlloc(OS_SYS_MEM_ADDR, TEST_NEW_POOL_SIZE);
(VOID)LOS_MemInit(pool, TEST_NEW_POOL_SIZE);
OsMemUsedNodeShow(pool);
void *ptr1 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
void *ptr2 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
OsMemUsedNodeShow(pool);
/* Release the memory pool. */
(VOID)LOS_MemDeInit(pool);
}
```
**Verification**
The log is as follows:
```
node size LR[0] LR[1] LR[2]
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc
0x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc
0x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
node size LR[0] LR[1] LR[2]
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc
0x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc
0x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
/* Log for the first OsMemUsedNodeShow. Because the memory pool is not allocated, there is no memory node. */
node LR[0] LR[1] LR[2]
/* Log for the second OsMemUsedNodeShow. There are two memory nodes. */
node LR[0] LR[1] LR[2]
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
```
The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak.
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
```
The following is part of the assembly file:
```
MemLeakTest:
0x80041d4: 0xb510 PUSH {R4, LR}
0x80041d6: 0x4ca8 LDR.N R4, [PC, #0x2a0] ; g_memStart
0x80041d8: 0x0020 MOVS R0, R4
0x80041da: 0xf7fd 0xf93e BL LOS_MemUsedNodeShow ; 0x800145a
0x80041de: 0x2108 MOVS R1, #8
0x80041e0: 0x0020 MOVS R0, R4
0x80041e2: 0xf7fd 0xfbd9 BL LOS_MemAlloc ; 0x8001998
0x80041e6: 0x2108 MOVS R1, #8
0x80041e8: 0x0020 MOVS R0, R4
0x80041ea: 0xf7fd 0xfbd5 BL LOS_MemAlloc ; 0x8001998
0x80041ee: 0x0020 MOVS R0, R4
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0
4009f014: 7d 1e a0 e3 mov r1, #2000
4009f018: 00 00 90 e5 ldr r0, [r0]
4009f01c: 67 7a fe eb bl #-398948 <LOS_MemAlloc>
4009f020: 7d 1e a0 e3 mov r1, #2000
4009f024: 00 40 a0 e1 mov r4, r0
4009f028: c7 79 fe eb bl #-399588 <LOS_MemInit>
4009f02c: 04 00 a0 e1 mov r0, r4
4009f030: 43 78 fe eb bl #-401140 <OsMemUsedNodeShow>
4009f034: 04 00 a0 e1 mov r0, r4
4009f038: 08 10 a0 e3 mov r1, #8
4009f03c: 5f 7a fe eb bl #-398980 <LOS_MemAlloc>
4009f040: 04 00 a0 e1 mov r0, r4
4009f044: 08 10 a0 e3 mov r1, #8
4009f048: 5c 7a fe eb bl #-398992 <LOS_MemAlloc>
4009f04c: 04 00 a0 e1 mov r0, r4
4009f050: 3b 78 fe eb bl #-401172 <OsMemUsedNodeShow>
4009f054: 3c 00 9f e5 ldr r0, [pc, #60]
4009f058: 40 b8 fe eb bl #-335616 <dprintf>
4009f05c: 04 00 a0 e1 mov r0, r4
4009f060: 2c 7a fe eb bl #-399184 <LOS_MemDeInit>
```
The memory node addressed by **0x080041ee** is not released after being requested in **MemLeakTest**.
The memory node addressed by **0x4009f040** is not released after being allocated in **MemLeakTest**.
# perf
## Basic Concepts
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).
**Table 1** APIs of the perf module
| Category| Description|
| -------- | -------- |
| Starting or stopping sampling| **LOS_PerfInit**: initializes perf.<br>**LOS_PerfStart**: starts sampling.<br>**LOS_PerfStop**: stops sampling. |
| 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
VOID Example_PerfNotifyHook(VOID)
{
CHAR buf[LOSCFG_PERF_BUFFER_SIZE] = {0};
UINT32 len;
PRINT_DEBUG("perf buffer reach the waterline!\n");
len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
OsPrintBuff(buf, len); /* print data */
}
LOS_PerfNotifyHookReg(Example_PerfNotifyHook);
```
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
VOID Example_PerfFlushHook(VOID *addr, UINT32 size)
{
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**.
| Configuration Item| menuconfig Option| Description| Value|
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_PERF | Enable&nbsp;Perf&nbsp;Feature | Whether to enable perf.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Tick | Whether to use tick as the perf timing unit.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_CYCLE | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Cpu&nbsp;Cycle | Whether to use cycle as the perf timing unit.| YES/NO |
| LOSCFG_PERF_BUFFER_SIZE | Perf&nbsp;Sampling&nbsp;Buffer&nbsp;Size | Size of the buffer used for perf sampling.| INT |
| LOSCFG_PERF_HW_PMU | Enable&nbsp;Hardware&nbsp;Pmu&nbsp;Events&nbsp;for&nbsp;Sampling | Whether to enable hardware PMU events. The target platform must support the hardware PMU.| YES/NO |
| LOSCFG_PERF_TIMED_PMU | Enable&nbsp;Hrtimer&nbsp;Period&nbsp;Events&nbsp;for&nbsp;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&nbsp;Software&nbsp;Events&nbsp;for&nbsp;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. */
VOID test(VOID)
{
VOID *p = NULL;
int i;
for (i = 0; i < TEST_TIME; i++) {
p = LOS_MemAlloc(m_aucSysMem1, TEST_MALLOC_SIZE);
if (p == NULL) {
PRINT_ERR("test alloc failed\n");
return;
}
(VOID)LOS_MemFree(m_aucSysMem1, p);
}
}
STATIC VOID OsPrintBuff(const CHAR *buf, UINT32 num)
{
UINT32 i = 0;
PRINTK("num: ");
for (i = 0; i < num; i++) {
PRINTK(" %02d", i);
}
PRINTK("\n");
PRINTK("hex: ");
for (i = 0; i < num; i++) {
PRINTK(" %02x", buf[i]);
}
PRINTK("\n");
}
STATIC VOID perfTestHwEvent(VOID)
{
UINT32 ret;
CHAR *buf = NULL;
UINT32 len;
//LOS_PerfInit(NULL, 0);
PerfConfigAttr attr = {
.eventsCfg = {
.type = PERF_EVENT_TYPE_SW,
.events = {
[0] = {PERF_COUNT_SW_TASK_SWITCH, 0xff}, /* Collect task scheduling information. */
[1] = {PERF_COUNT_SW_MEM_ALLOC, 0xff}, /* Collect memory allocation information. */
PERF_COUNT_SW_TASK_SWITCH
},
.eventsNr = 2,
.predivided = 1, /* cycle counter increase every 64 cycles */
},
.taskIds = {0},
.taskIdsNr = 0,
.needSample = 0,
.sampleType = PERF_RECORD_IP | PERF_RECORD_CALLCHAIN,
};
ret = LOS_PerfConfig(&attr);
if (ret != LOS_OK) {
PRINT_ERR("perf config error %u\n", ret);
return;
}
PRINTK("------count mode------\n");
LOS_PerfStart(0);
test(); /* this is any test function*/
LOS_PerfStop();
PRINTK("--------sample mode------ \n");
attr.needSample = 1;
LOS_PerfConfig(&attr);
LOS_PerfStart(2); // 2: set the section id to 2.
test(); /* this is any test function*/
LOS_PerfStop();
buf = LOS_MemAlloc(m_aucSysMem1, LOSCFG_PERF_BUFFER_SIZE);
if (buf == NULL) {
PRINT_ERR("buffer alloc failed\n");
return;
}
/* get sample data */
len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
OsPrintBuff(buf, len); /* print data */
(VOID)LOS_MemFree(m_aucSysMem1, buf);
}
UINT32 Example_Perf_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S perfTestTask = {0};
UINT32 taskID;
/* Create a perf task. */
perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
perfTestTask.pcName = "TestPerfTsk"; /* Test task name. */
perfTestTask.uwStackSize = 0x1000; // 0x8000: perf test task stack size
perfTestTask.usTaskPrio = 5; // 5: perf test task priority
ret = LOS_TaskCreate(&taskID, &perfTestTask);
if (ret != LOS_OK) {
PRINT_ERR("PerfTestTask create failed. 0x%x\n", ret);
return LOS_NOK;
}
return LOS_OK;
}
LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
```
#### Verification
The output is as follows:
```
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 0
------count mode------
[task switch] eventType: 0x1 [core 0]: 0
[mem alloc] eventType: 0x3 [core 0]: 5
time used: 0.005000(s)
--------sample mode------
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 1
dump perf data, addr: 0x402c3e6c length: 0x5000
time used: 0.000000(s)
num: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
hex: 00 ffffffef ffffffef ffffffef 02 00 00 00 14 00 00 00 60 00 00 00 02 00 00 00
The print information may vary depending on the running environment.
```
- For the counting mode, the following information is displayed after perf is stopped:
Event name (cycles), event type (0xff), and number of event occurrences (5466989440)
For hardware PMU events, the displayed event type is the hardware event ID, not the abstract type defined in **enum PmuHWId**.
- For the sampling mode, the address and length of the sampled data will be displayed after perf is stopped:
dump section data, addr: (0x8000000) length: (0x5000)
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.
......@@ -3,35 +3,34 @@
## Basic Concepts
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>
**Table 1** CPUP module APIs
<a name="table147491853163018"></a>
<table><thead align="left"><tr id="row10807205323013"><th class="cellrowborder" valign="top" width="28.3971602839716%" id="mcps1.2.4.1.1"><p id="p980714539304"><a name="p980714539304"></a><a name="p980714539304"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="36.47635236476353%" id="mcps1.2.4.1.2"><p id="p1780715533305"><a name="p1780715533305"></a><a name="p1780715533305"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="35.12648735126487%" id="mcps1.2.4.1.3"><p id="p18807185316301"><a name="p18807185316301"></a><a name="p18807185316301"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row3807145310300"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p174011140141013"><a name="p174011140141013"></a><a name="p174011140141013"></a>System CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p158071153133013"><a name="p158071153133013"></a><a name="p158071153133013"></a>LOS_HistorySysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p14808115353010"><a name="p14808115353010"></a><a name="p14808115353010"></a>Obtains the historical CPUP of the system.</p>
</td>
</tr>
<tr id="row147461859201016"><td class="cellrowborder" rowspan="2" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p374720596102"><a name="p374720596102"></a><a name="p374720596102"></a>Process CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p3747859101010"><a name="p3747859101010"></a><a name="p3747859101010"></a>LOS_HistoryProcessCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p1747959131016"><a name="p1747959131016"></a><a name="p1747959131016"></a>Obtains the historical CPUP of a specified process.</p>
</td>
</tr>
<tr id="row2075434812116"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17541648171114"><a name="p17541648171114"></a><a name="p17541648171114"></a>LOS_GetAllProcessCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1575419483116"><a name="p1575419483116"></a><a name="p1575419483116"></a>Obtains the historical CPUP of all processes in the system.</p>
</td>
</tr>
<tr id="row1480855311301"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p1618792981018"><a name="p1618792981018"></a><a name="p1618792981018"></a>Task CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p9808185353016"><a name="p9808185353016"></a><a name="p9808185353016"></a>LOS_HistoryTaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p12808653183016"><a name="p12808653183016"></a><a name="p12808653183016"></a>Obtains the historical CPUP of a specified task.</p>
</td>
</tr>
<tr id="row680812535306"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p13808125314307"><a name="p13808125314307"></a><a name="p13808125314307"></a>Interrupt CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p1480835316303"><a name="p1480835316303"></a><a name="p1480835316303"></a>LOS_GetAllIrqCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p33741531163313"><a name="p33741531163313"></a><a name="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 sample code is as follows:
```
```c
#include "los_task.h"
#include "los_cpup.h"
#include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
printf("entry cpup test example\n");
while(1) {
usleep(100);
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
int i = 0;
dprintf("entry cpup test example\n");
for (i = 0; i < 10; i++) {
usleep(100); // 100: delay for 100ms
}
}
UINT32 ItCpupTest(VOID)
{
UINT32 CpupTest(VOID)
{
UINT32 ret;
UINT32 cpupUse;
TSK_INIT_PARAM_S cpupTestTask = { 0 };
TSK_INIT_PARAM_S cpupTestTask = {0};
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S));
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800;
cpupTestTask.usTaskPrio = 5;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800; // 0x800: cpup test task stack size
cpupTestTask.usTaskPrio = 5; // 5: cpup test task priority
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
if(ret != LOS_OK) {
if (ret != LOS_OK) {
printf("cpupTestTask create failed .\n");
return LOS_NOK;
}
usleep(100);
usleep(100); // 100: delay for 100ms
/* Obtain the historical CPUP of the system. */
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
printf("the history system cpu usage in all time: %u.%u\n",
/* Obtain the historical CPUP of the system. */
cpupUse = LOS_HistorySysCpuUsage(CPUP_LAST_ONE_SECONDS);
dprintf("the history system cpu usage in all time: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* Obtain the CPUP of the specified task (cpupTestTask in this example).*/
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
/* Obtain the CPUP of the specified task (cpupTestTask in this example). */
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPUP_LAST_ONE_SECONDS);
dprintf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
}
```
......@@ -180,9 +154,12 @@ UINT32 ItCpupTest(VOID)
The development is successful if the return result is as follows:
```
entry cpup test example
the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask in all time: TaskID:10 usage: 0.0
The print information may vary depending on the running environment.
```
# User-Mode Memory Debugging
## Basic Concepts
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.
**Figure 1** Heap memory node linked list
**Figure 1** Heap memory node linked list
![](figures/heap-memory-node-linked-list.png "heap-memory-node-linked-list")
![](figures/heap-memory-node-linked-list.png "heap-memory-node-linked-list")
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. <xref href="#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.
**Figure 2** Heap memory node information
**Figure 2** Heap memory node information
![](figures/heap-memory-node-information.png "heap-memory-node-information")
![](figures/heap-memory-node-information.png "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
![](figures/process-of-locating-the-code-lines-for-a-memory-leak.png "process-of-locating-the-code-lines-for-a-memory-leak")
![](figures/process-of-locating-the-code-lines-for-a-memory-leak.png "process-of-locating-the-code-lines-for-a-memory-leak")
### Heap Memory Statistics
......@@ -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
![](figures/adding-a-check-value-to-the-node-header-information.png "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.
**Figure 5** Process of releasing memory
![](figures/process-of-releasing-memory.png "process-of-releasing-memory")
- Requested memory greater than 0x1c000 bytes
**Figure 4** Adding a check value to the node header information
![](figures/adding-a-check-value-to-the-node-header-information.png "adding-a-check-value-to-the-node-header-information")
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.
**Figure 5** Process of releasing memory
![](figures/process-of-releasing-memory.png "process-of-releasing-memory")
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**
![](figures/layout-of-the-memory-allocated-by-using-the-mmap-mechanism-of-malloc.png "layout-of-the-memory-allocated-by-using-the-mmap-mechanism-of-malloc")
![](figures/layout-of-the-memory-allocated-by-using-the-mmap-mechanism-of-malloc.png "layout-of-the-memory-allocated-by-using-the-mmap-mechanism-of-malloc")
### Usage Guide
#### Available APIs
......@@ -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.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**<br>
> 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
#define MALLOC_LEAK_SIZE 0x300
void func(void) {
void func(void)
{
char *ptr = malloc(MALLOC_LEAK_SIZE);
memset(ptr, '3', MALLOC_LEAK_SIZE);
}
......@@ -156,17 +164,18 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**
>
> - 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.
......@@ -175,7 +184,7 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp
```
OHOS # ./mem_check
OHOS #
OHOS #
==PID:4== Heap memory statistics(bytes): // Heap memory statistics
[Check point]: // Call stack of the check point
#00: <main+0x38>[0x86c] -> mem_check
......@@ -293,14 +302,15 @@ kill -37 <pid> # Check whether the head node of the heap memory is complete.
The sample code constructs a memory problem and uses the command line to perform memory debugging.
```
```c
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define MALLOC_LEAK_SIZE 0x300
void func(void) {
void func(void)
{
char *ptr = malloc(MALLOC_LEAK_SIZE);
memset(ptr, '3', MALLOC_LEAK_SIZE);
}
......@@ -317,7 +327,7 @@ int main()
##### Compilation
For details, see [Compilation](kernel-small-debug-user.md#compilation).
For details, see [Compilation](#compilation).
##### Running the mwatch Command
......@@ -325,9 +335,9 @@ For details, see [Compilation](kernel-small-debug-user.md#compilation).
```
OHOS # ./mem_check --mwatch // Run the task command to obtain the mem_check process PID, which is 4.
OHOS #
OHOS #
OHOS # kill -35 4 // Check heap memory statistics.
OHOS #
OHOS #
==PID:4== Heap memory statistics(bytes):
[Check point]:
#00: <arm_signal_process+0x5c>[0x58dfc] -> /lib/libc.so
......@@ -337,7 +347,7 @@ OHOS #
==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
OHOS # cat /storage/pid(4)_check.txt
==PID:4== Heap memory statistics(bytes):
[Check point]:
#00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID: 18, Used: 0x640]
==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
OHOS # cat /storage/pid(4)_check.txt
==PID:4== Heap memory statistics(bytes):
[Check point]:
#00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID: 18, Used: 0x640]
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
==PID:4== Detected memory leak(s):
[Check point]:
#00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
#01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <main+0x14>[0x724] -> mem_check
#01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <func+0x14>[0x6ec] -> mem_check
#01: <main+0x30>[0x740] -> mem_check
#02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
==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
Check heap integrity ok!
OHOS # cat /storage/pid(4)_check.txt
OHOS #
OHOS #
==PID:4== Heap memory statistics(bytes):
[Check point]:
#00: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID: 18, Used: 0x640]
==PID:4== Total heap: 0x640 byte(s), Peak: 0x640 byte(s)
==PID:4== Detected memory leak(s):
[Check point]:
#00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
#01: <arm_signal_process+0x5c>[0x5973c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <main+0x14>[0x724] -> mem_check
#01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <func+0x14>[0x6ec] -> mem_check
#01: <main+0x30>[0x740] -> mem_check
#02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
==PID:4== Detected memory leak(s):
[Check point]:
#00: <check_leak+0x1c4>[0x2e38c] -> /lib/libc.so
#01: <exit+0x28>[0x11b2c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <main+0x14>[0x724] -> mem_check
#01: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
[TID:18 Leak:0x320 byte(s)] Allocated from:
#00: <func+0x14>[0x6ec] -> mem_check
#01: <main+0x30>[0x740] -> mem_check
#02: <(null)+0x1fdd231c>[0x2231c] -> /lib/libc.so
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**<br>
> 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.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**
>
> 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**.
| Macro| menuconfig Option| Description| Value:|
| Macro| menuconfig Option| Description| Value |
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_LMS | Enable Lms Feature | Whether to enable LMS.| YES/NO |
| LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | Maximum number of memory pools that can be checked by LMS.| INT |
| LOSCFG_LMS_LOAD_CHECK | Enable lms read check | Whether to enable LMS read check.| YES/NO |
| LOSCFG_LMS_STORE_CHECK | Enable lms write check | Whether to enable LMS write check.| YES/NO |
| LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | Whether to enable LMS byte-by-byte check.| YES/NO |
2. Modify the build script of the target module.
2. Modify the build script of the target module.
Add **-fsanitize=kernel-address** to insert memory access checks, and add the **-O0** option to disable optimization performed by the compiler.
The modifications vary depending on the compiler (GCC or Clang) used. The following is an example:
The modifications vary depending on the compiler (GCC or Clang) used. The following is an example:
```
if ("$ohos_build_compiler_specified" == "gcc") {
......@@ -113,9 +110,10 @@ This example implements the following:
#### Kernel-Mode Sample Code
The sample code is as follows:
The functions of the sample code can be added to **TestTaskEntry** in **kernel /liteos_a/testsuites /kernel /src /osTest.c** for testing.
The sample code is as follows:
```
```c
#define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20
UINT32 g_lmsTestTaskId;
......@@ -141,31 +139,32 @@ static VOID LmsTestUseAfterFree(VOID)
PRINTK("\n######%s start ######\n", __FUNCTION__);
UINT32 i;
CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX);
LOS_MemFree(g_testLmsPool, str);
(VOID)LOS_MemFree(g_testLmsPool, str);
PRINTK("str[%2d]=0x%2x ", 0, str[0]); /* trigger use after free at str[0] */
PRINTK("\n######%s stop ######\n", __FUNCTION__);
}
VOID LmsTestCaseTask(VOID)
{
{
testPoolInit();
LmsTestOsmallocOverflow();
LmsTestUseAfterFree();
}
UINT32 Example_Lms_test(VOID){
UINT32 ret;
TSK_INIT_PARAM_S lmsTestTask;
/* Create a task for LMS. */
memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
UINT32 Example_Lms_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S lmsTestTask;
/* Create a task for LMS. */
memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask;
lmsTestTask.pcName = "TestLmsTsk"; /* Test task name. */
lmsTestTask.uwStackSize = 0x800;
lmsTestTask.usTaskPrio = 5;
lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
ret = LOS_TaskCreate(&g_lmsTestTaskId, &lmsTestTask);
if(ret != LOS_OK){
PRINT_ERR("LmsTestTask create failed .\n");
return LOS_NOK;
}
lmsTestTask.pcName = "TestLmsTsk"; /* Test task name. */
lmsTestTask.uwStackSize = 0x800; // 0x800: LMS test task stack size
lmsTestTask.usTaskPrio = 5; // 5: LMS test task priority
lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
ret = LOS_TaskCreate(&g_lmsTestTaskId, &lmsTestTask);
if (ret != LOS_OK) {
PRINT_ERR("LmsTestTask create failed .\n");
return LOS_NOK;
}
return LOS_OK;
}
LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
......@@ -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
static void BufWriteTest(void *buf, int start, int end)
{
for (int i = start; i <= end; i++) {
......@@ -335,7 +334,7 @@ static void BufReadTest(void *buf, int start, int end)
static void LmsMallocTest(void)
{
printf("\n-------- LmsMallocTest Start --------\n");
char *buf = (char *)malloc(16);
char *buf = (char *)malloc(16); // 16: buffer size for test
BufReadTest(buf, -1, 16);
free(buf);
printf("\n-------- LmsMallocTest End --------\n");
......@@ -343,7 +342,7 @@ static void LmsMallocTest(void)
static void LmsFreeTest(void)
{
printf("\n-------- LmsFreeTest Start --------\n");
char *buf = (char *)malloc(16);
char *buf = (char *)malloc(16); // 16: buffer size for test
free(buf);
BufReadTest(buf, 1, 1);
free(buf);
......@@ -352,7 +351,7 @@ static void LmsFreeTest(void)
int main(int argc, char * const * argv)
{
printf("\n############### Lms Test start ###############\n");
char *tmp = (char *)malloc(5000);
char *tmp = (char *)malloc(5000); // 5000: temp buffer size
LmsMallocTest();
LmsFreeTest();
printf("\n############### Lms Test End ###############\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册