diff --git a/zh-cn/device-dev/kernel/Readme-CN.md b/zh-cn/device-dev/kernel/Readme-CN.md
index b63423d773efc9efdb195e0bd5a5bf548736e90f..3197acaa99c845171e4ebb7670c71e58458a3130 100755
--- a/zh-cn/device-dev/kernel/Readme-CN.md
+++ b/zh-cn/device-dev/kernel/Readme-CN.md
@@ -51,6 +51,7 @@
- [踩内存检测](kernel-mini-memory-debug-cet.md)
- [异常调测](kernel-mini-memory-exception.md)
- [Trace调测](kernel-mini-memory-trace.md)
+ - [LMS调测](kernel-mini-debug-lms.md)
- [附录](kernel-mini-app.md)
- [内核编码规范](kernel-mini-appx-code.md)
- [基本数据结构](kernel-mini-appx-data.md)
@@ -165,6 +166,8 @@
- [魔法键使用方法](kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel-small-debug-shell-error.md)
- [Trace调测](kernel-small-debug-trace.md)
+ - [Perf调测](kernel-small-debug-perf.md)
+ - [LMS调测](kernel-small-debug-lms.md)
- [进程调测](kernel-small-debug-process.md)
- [CPU占用率](kernel-small-debug-process-cpu.md)
- [内存调测](kernel-small-debug-memory.md)
diff --git a/zh-cn/device-dev/kernel/kernel-mini-debug-lms.md b/zh-cn/device-dev/kernel/kernel-mini-debug-lms.md
new file mode 100644
index 0000000000000000000000000000000000000000..faf8e495fd9f0de91b148f8da073bce7ded81c44
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-mini-debug-lms.md
@@ -0,0 +1,293 @@
+# LMS调测
+
+- [基本概念](#section1)
+
+- [运行机制](#section2)
+
+- [接口说明](#section3)
+
+- [开发指导](#section4)
+
+ - [开发流程](#section4.1.1)
+
+ - [编程实例](#section4.1.2)
+
+ - [实例代码](#section4.1.3)
+
+ - [结果验证](#section4.1.4)
+
+
+## 基本概念
+LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double Free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
+
+## 运行机制
+LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。
+
+- 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头结点区的影子内存设置为“不可读写”状态。
+
+- 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。
+
+- 编译代码时,会在代码中的读写指令前插入检测函数,对地址的合法性进行检验。主要是检测访问内存的影子内存的状态值,若检测到影子内存为不可读写,则会报溢出错误;若检测到影子内存为已释放,则会报释放后使用错误。
+
+- 在内存释放时,会检测被释放地址的影子内存状态值,若检测到影子内存非可读写,则会报重复释放错误。
+
+## 接口说明
+
+OpenHarmony LiteOS-M内核的LMS模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_m/blob/master/components/lms/los_lms.h)参考。
+
+
+1. 支持多内存池检测;
+
+2. 支持LOS_MemAlloc、LOS_MemAllocAlign、LOS_MemRealloc申请出的内存检测;
+
+3. 支持安全函数的访问检测(默认开启);
+
+4. 支持libc 高频函数的访问检测,包括:memset、memcpy、memmove、strcat、strcpy、strncat、strncpy。
+
+5. 可动态设置的功能如下:
+
+**表 1** LMS模块接口说明
+
+
功能分类
+ |
+接口名
+ |
+描述
+ |
+
---|
添加指定内存池被检测
+ |
+LOS_LmsCheckPoolAdd
+ |
+将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。
+ |
+
+删除指定内存池不被检测
+ |
+LOS_LmsCheckPoolDel
+ |
+不检测指定内存池地址范围内的合法性校验。
+ |
+
+使能指定内存段锁保护
+ |
+LOS_LmsAddrProtect
+ |
+为某段内存地址上锁,设置为不可读写,一旦访问则报错。
+ |
+
+去能指定内存段锁保护
+ |
+LOS_LmsAddrDisableProtect
+ |
+为某段内存地址解锁,设置为可读写。
+ |
+
+
+
+
+
+## 开发指导
+
+### 开发流程
+
+开启LMS调测的典型流程如下:
+
+1. 配置LMS模块相关宏。
+
+ 配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel->Enable Lite Memory Sanitizer"中打开:
+
+ | 配置项 | menuconfig选项 | 含义 | 设置值 |
+ | ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------ |
+ | LOSCFG_KERNEL_LMS | Enable Lms Feature | Lms模块的裁剪开关 | YES/NO |
+ | LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | LMS支持的检测内存池最大个数 | INT |
+ | LOSCFG_LMS_LOAD_CHECK | Enable lms read check | LMS内存读检测的裁剪开关 | YES/NO |
+ | LOSCFG_LMS_STORE_CHECK | Enable lms write check | LMS内存写检测的裁剪开关 | YES/NO |
+ | LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | LMS内存逐字节严格检测的裁剪开关 | YES/NO |
+
+2. 在被检测模块的编译脚本中,增加LMS检测编译选项-fsanitize=kernel-address。
+
+3. 为避免编译器优化,增加-O0编译选项。
+
+4. gcc与clang编译选项存在差异,参照如下示例:
+
+ ```
+ if ("$ohos_build_compiler_specified" == "gcc") {
+ cflags_c = [
+ "-O0",
+ "-fsanitize=kernel-address",
+ ]
+ } else {
+ cflags_c = [
+ "-O0",
+ "-fsanitize=kernel-address",
+ "-mllvm",
+ "-asan-instrumentation-with-call-threshold=0",
+ "-mllvm",
+ "-asan-stack=0",
+ "-mllvm",
+ "-asan-globals=0",
+ ]
+ }
+ ```
+
+5. 重新编译,查看串口输出。如果检测到内存问题,会输出检测结果。
+
+### 编程实例
+
+ 本实例实现如下功能:
+
+ 1. 创建一个用于Lms测试的任务。
+
+ 2. 构造内存溢出错误和释放后使用错误。
+
+ 3. 添加-fsanitize=kernel-address后编译执行,观察输出结果
+
+### 示例代码
+
+实例代码如下:
+
+```C
+#define PAGE_SIZE (0x1000U)
+#define INDEX_MAX 20
+
+UINT32 g_lmsTestTaskId;
+char g_testLmsPool[2 * PAGE_SIZE];
+
+STATIC VOID testPoolInit(void)
+{
+ UINT32 ret = LOS_MemInit(g_testLmsPool, 2 * PAGE_SIZE);
+ if (ret != 0) {
+ PRINT_ERR("%s failed, ret = 0x%x\n", __FUNCTION__, ret);
+ return;
+ }
+}
+
+static VOID LmsTestOsmallocOverflow(VOID)
+{
+ PRINTK("\n######%s start ######\n", __FUNCTION__);
+ UINT32 i;
+ CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX);
+ PRINTK("str[%2d]=0x%2x ", INDEX_MAX, str[INDEX_MAX]); /* trigger heap overflow at str[INDEX_MAX] */
+ PRINTK("\n######%s stop ######\n", __FUNCTION__);
+}
+
+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);
+ 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;
+ /* 创建用于lms测试的任务 */
+ memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
+ lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask;
+ lmsTestTask.pcName = "TestLmsTsk"; /* 测试任务名称 */
+ 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;
+ }
+ return LOS_OK;
+}
+```
+
+### 结果验证
+
+输出结果如下:
+
+```c
+######LmsTestOsmallocOverflow start ######
+[ERR]***** Kernel Address Sanitizer Error Detected Start *****
+[ERR]Heap buffer overflow error detected
+[ERR]Illegal READ address at: [0x4157a3c8]
+[ERR]Shadow memory address: [0x4157be3c : 4] Shadow memory value: [2]
+OsBackTrace fp = 0x402c0f88
+runTask->taskName = LmsTestCaseTask
+runTask->taskID = 2
+*******backtrace begin*******
+traceback fp fixed, trace using fp = 0x402c0fd0
+traceback 0 -- lr = 0x400655a4 fp = 0x402c0ff8
+traceback 1 -- lr = 0x40065754 fp = 0x402c1010
+traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038
+traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca
+
+[LMS] Dump info around address [0x4157a3c8]:
+
+ [0x4157a3a0]: 00 00 00 00 00 00 00 00 | [0x4157be3a | 0]: 1 1
+ [0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
+ [0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0
+ [0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
+ [0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0
+ [0x4157a3c8]: [ba] dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: [2] 2
+ [0x4157a3d0]: 2c 1a 00 00 00 00 00 00 | [0x4157be3d | 0]: 2 3
+ [0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3
+ [0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3
+ [0x4157a3e8]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 4]: 3 3
+ [0x4157a3f0]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 0]: 3 3
+[ERR]***** Kernel Address Sanitizer Error Detected End *****
+str[20]=0xffffffba
+######LmsTestOsmallocOverflow stop ######
+
+###### LmsTestUseAfterFree start ######
+[ERR]***** Kernel Address Sanitizer Error Detected Start *****
+[ERR]Use after free error detected
+[ERR]Illegal READ address at: [0x4157a3d4]
+[ERR]Shadow memory address: [0x4157be3d : 2] Shadow memory value: [3]
+OsBackTrace fp = 0x402c0f90
+runTask->taskName = LmsTestCaseTask
+runTask->taskID = 2
+*******backtrace begin*******
+traceback fp fixed, trace using fp = 0x402c0fd8
+traceback 0 -- lr = 0x40065680 fp = 0x402c0ff8
+traceback 1 -- lr = 0x40065758 fp = 0x402c1010
+traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038
+traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca
+
+[LMS] Dump info around address [0x4157a3d4]:
+
+ [0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
+ [0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0
+ [0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
+ [0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0
+ [0x4157a3c8]: ba dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: 2 2
+ [0x4157a3d0]: 2c 1a 00 00 [00] 00 00 00 | [0x4157be3d | 0]: 2 [3]
+ [0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3
+ [0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3
+ [0x4157a3e8]: ba dc cd ab c8 a3 57 41 | [0x4157be3e | 4]: 2 2
+ [0x4157a3f0]: 0c 1a 00 00 00 00 00 00 | [0x4157be3f | 0]: 2 3
+ [0x4157a3f8]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 4]: 3 3
+[ERR]***** Kernel Address Sanitizer Error Detected End *****
+str[ 0]=0x 0
+######LmsTestUseAfterFree stop ######
+```
+输出的关键信息包括:
+- 错误类型:
+ - Heap buffer overflow堆内存越界
+ - Use after free 释放后使用
+- 错误操作:
+ - Illegal Read非法读
+ - Illegal Write非法写
+ - Illegal Double free重复释放
+- 上下文:
+ - 当前任务信息(taskName, taskId)
+ - 回溯栈(backtrace)
+- 出错地址的内存信息:
+ - 内存的值、及对应影子内存的值
+ - 内存地址:内存值| [影子内存地址 | 影子内存字节内偏移]:影子内存值
+ - 影子内存值:0(可读可写)、3(已释放)、2(红区)、1(填充值)。
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-lms.md b/zh-cn/device-dev/kernel/kernel-small-debug-lms.md
new file mode 100644
index 0000000000000000000000000000000000000000..708a386da7455abb49651e1950331667ca0ca467
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-lms.md
@@ -0,0 +1,477 @@
+# LMS调测
+
+- [基本概念](#section1)
+
+- [运行机制](#section2)
+
+- [接口说明](#section3)
+
+ - [内核态](#section3.1)
+
+ - [用户态](#section3.2)
+
+- [开发指导](#section4)
+
+ - [内核态开发流程](#section4.1.1)
+
+ - [内核态编程实例](#section4.1.2)
+
+ - [内核态实例代码](#section4.1.3)
+
+ - [内核态结果验证](#section4.1.4)
+
+ - [用户态开发流程](#section4.2.1)
+
+ - [用户态编程实例](#section4.2.2)
+
+ - [用户态实例代码](#section4.2.3)
+
+ - [用户态结果验证](#section4.2.4)
+
+## 基本概念
+LMS全称为Lite Memory Sanitizer,是一种实时检测内存操作合法性的调测工具。LMS能够实时检测缓冲区溢出(buffer overflow),释放后使用(use after free) 和重复释放(double Free), 在异常发生的第一时间通知操作系统,结合backtrace等定位手段,能准确定位到产生内存问题的代码行,极大提升内存问题定位效率。
+
+## 运行机制
+LMS使用影子内存映射标记系统内存的状态,一共可标记为三个状态:可读写,不可读写,已释放。影子内存存放在内存池的尾部。
+
+- 内存从堆上申请后,会将数据区的影子内存设置为“可读写”状态,并将头结点区的影子内存设置为“不可读写”状态。
+
+- 内存在堆上被释放时,会将被释放内存的影子内存设置为“已释放”状态。
+
+- 编译代码时,会在代码中的读写指令前插入检测函数,对地址的合法性进行检验。主要是检测访问内存的影子内存的状态值,若检测到影子内存为不可读写,则会报溢出错误;若检测到影子内存为已释放,则会报释放后使用错误。
+
+- 在内存释放时,会检测被释放地址的影子内存状态值,若检测到影子内存非可读写,则会报重复释放错误。
+
+## 接口说明
+
+### 内核态
+
+OpenHarmony LiteOS-A内核的LMS模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_lms.h)参考。
+
+
+1. 支持多内存池检测;
+
+2. 支持LOS_MemAlloc、LOS_MemAllocAlign、LOS_MemRealloc申请出的内存检测;
+
+3. 支持安全函数的访问检测(默认开启);
+
+4. 支持libc 高频函数的访问检测,包括:memset、memcpy、memmove、strcat、strcpy、strncat、strncpy。
+
+5. 可动态设置的功能如下:
+
+**表 1** LMS模块接口说明
+
+功能分类
+ |
+接口名
+ |
+描述
+ |
+
---|
添加指定内存池被检测
+ |
+LOS_LmsCheckPoolAdd
+ |
+将指定内存池的地址范围添加到LMS的内存检测链表上,当访问的地址在链表范围内时,LMS才进行合法性校验;且LOS_MemInit接口会调用该接口,默认将初始化的内存池挂入到检测链表中。
+ |
+
+删除指定内存池不被检测
+ |
+LOS_LmsCheckPoolDel
+ |
+不检测指定内存池地址范围内的合法性校验。
+ |
+
+使能指定内存段锁保护
+ |
+LOS_LmsAddrProtect
+ |
+为某段内存地址上锁,设置为不可读写,一旦访问则报错。
+ |
+
+去能指定内存段锁保护
+ |
+LOS_LmsAddrDisableProtect
+ |
+为某段内存地址解锁,设置为可读写。
+ |
+
+
+
+
+
+### 用户态
+
+用户态仅提供LMS检测库,不提供对外接口。
+
+## 开发指导
+
+### 内核态开发流程
+
+开启LMS调测的典型流程如下:
+
+1. 配置LMS模块相关宏。
+
+ 配置LMS控制宏LOSCFG_KERNEL_LMS,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel->Enable Lite Memory Sanitizer"中打开:
+
+ | 配置项 | menuconfig选项 | 含义 | 设置值 |
+ | ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------ |
+ | LOSCFG_KERNEL_LMS | Enable Lms Feature | Lms模块的裁剪开关 | YES/NO |
+ | LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | LMS支持的检测内存池最大个数 | INT |
+ | LOSCFG_LMS_LOAD_CHECK | Enable lms read check | LMS内存读检测的裁剪开关 | YES/NO |
+ | LOSCFG_LMS_STORE_CHECK | Enable lms write check | LMS内存写检测的裁剪开关 | YES/NO |
+ | LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | LMS内存逐字节严格检测的裁剪开关 | YES/NO |
+
+2. 在被检测模块的编译脚本中,增加LMS检测编译选项-fsanitize=kernel-address。
+
+3. 为避免编译器优化,增加-O0编译选项。
+
+4. gcc与clang编译选项存在差异,参照如下示例:
+
+ ```
+ if ("$ohos_build_compiler_specified" == "gcc") {
+ cflags_c = [
+ "-O0",
+ "-fsanitize=kernel-address",
+ ]
+ } else {
+ cflags_c = [
+ "-O0",
+ "-fsanitize=kernel-address",
+ "-mllvm",
+ "-asan-instrumentation-with-call-threshold=0",
+ "-mllvm",
+ "-asan-stack=0",
+ "-mllvm",
+ "-asan-globals=0",
+ ]
+ }
+ ```
+
+5. 重新编译,查看串口输出。如果检测到内存问题,会输出检测结果。
+
+### 内核态编程实例
+
+ 本实例实现如下功能:
+
+ 1. 创建一个用于Lms测试的任务。
+
+ 2. 构造内存溢出错误和释放后使用错误。
+
+ 3. 添加-fsanitize=kernel-address后编译执行,观察输出结果
+
+### 内核态示例代码
+
+实例代码如下:
+
+```C
+#define PAGE_SIZE (0x1000U)
+#define INDEX_MAX 20
+
+UINT32 g_lmsTestTaskId;
+char g_testLmsPool[2 * PAGE_SIZE];
+
+STATIC VOID testPoolInit(void)
+{
+ UINT32 ret = LOS_MemInit(g_testLmsPool, 2 * PAGE_SIZE);
+ if (ret != 0) {
+ PRINT_ERR("%s failed, ret = 0x%x\n", __FUNCTION__, ret);
+ return;
+ }
+}
+
+static VOID LmsTestOsmallocOverflow(VOID)
+{
+ PRINTK("\n######%s start ######\n", __FUNCTION__);
+ UINT32 i;
+ CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX);
+ PRINTK("str[%2d]=0x%2x ", INDEX_MAX, str[INDEX_MAX]); /* trigger heap overflow at str[INDEX_MAX] */
+ PRINTK("\n######%s stop ######\n", __FUNCTION__);
+}
+
+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);
+ 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;
+ /* 创建用于lms测试的任务 */
+ memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
+ lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask;
+ lmsTestTask.pcName = "TestLmsTsk"; /* 测试任务名称 */
+ 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;
+ }
+ return LOS_OK;
+}
+LOS_MODULE_INIT(Example_Lms_test, LOS_INIT_LEVEL_KMOD_EXTENDED);
+```
+
+### 内核态结果验证
+
+输出结果如下:
+
+```c
+######LmsTestOsmallocOverflow start ######
+[ERR][KProcess:LmsTestCaseTask]***** Kernel Address Sanitizer Error Detected Start *****
+[ERR][KProcess:LmsTestCaseTask]Heap buffer overflow error detected
+[ERR][KProcess:LmsTestCaseTask]Illegal READ address at: [0x4157a3c8]
+[ERR][KProcess:LmsTestCaseTask]Shadow memory address: [0x4157be3c : 4] Shadow memory value: [2]
+OsBackTrace fp = 0x402c0f88
+runTask->taskName = LmsTestCaseTask
+runTask->taskID = 2
+*******backtrace begin*******
+traceback fp fixed, trace using fp = 0x402c0fd0
+traceback 0 -- lr = 0x400655a4 fp = 0x402c0ff8
+traceback 1 -- lr = 0x40065754 fp = 0x402c1010
+traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038
+traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca
+
+[LMS] Dump info around address [0x4157a3c8]:
+
+ [0x4157a3a0]: 00 00 00 00 00 00 00 00 | [0x4157be3a | 0]: 1 1
+ [0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
+ [0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0
+ [0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
+ [0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0
+ [0x4157a3c8]: [ba] dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: [2] 2
+ [0x4157a3d0]: 2c 1a 00 00 00 00 00 00 | [0x4157be3d | 0]: 2 3
+ [0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3
+ [0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3
+ [0x4157a3e8]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 4]: 3 3
+ [0x4157a3f0]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 0]: 3 3
+[ERR][KProcess:LmsTestCaseTask]***** Kernel Address Sanitizer Error Detected End *****
+str[20]=0xffffffba
+######LmsTestOsmallocOverflow stop ######
+
+###### LmsTestUseAfterFree start ######
+[ERR][KProcess:LmsTestCaseTask]***** Kernel Address Sanitizer Error Detected Start *****
+[ERR][KProcess:LmsTestCaseTask]Use after free error detected
+[ERR][KProcess:LmsTestCaseTask]Illegal READ address at: [0x4157a3d4]
+[ERR][KProcess:LmsTestCaseTask]Shadow memory address: [0x4157be3d : 2] Shadow memory value: [3]
+OsBackTrace fp = 0x402c0f90
+runTask->taskName = LmsTestCaseTask
+runTask->taskID = 2
+*******backtrace begin*******
+traceback fp fixed, trace using fp = 0x402c0fd8
+traceback 0 -- lr = 0x40065680 fp = 0x402c0ff8
+traceback 1 -- lr = 0x40065758 fp = 0x402c1010
+traceback 2 -- lr = 0x40044bd0 fp = 0x402c1038
+traceback 3 -- lr = 0x40004e14 fp = 0xcacacaca
+
+[LMS] Dump info around address [0x4157a3d4]:
+
+ [0x4157a3a8]: ba dc cd ab 00 00 00 00 | [0x4157be3a | 4]: 2 2
+ [0x4157a3b0]: 20 00 00 80 00 00 00 00 | [0x4157be3b | 0]: 2 0
+ [0x4157a3b8]: 00 00 00 00 00 00 00 00 | [0x4157be3b | 4]: 0 0
+ [0x4157a3c0]: 00 00 00 00 00 00 00 00 | [0x4157be3c | 0]: 0 0
+ [0x4157a3c8]: ba dc cd ab a8 a3 57 41 | [0x4157be3c | 4]: 2 2
+ [0x4157a3d0]: 2c 1a 00 00 [00] 00 00 00 | [0x4157be3d | 0]: 2 [3]
+ [0x4157a3d8]: 00 00 00 00 00 00 00 00 | [0x4157be3d | 4]: 3 3
+ [0x4157a3e0]: 00 00 00 00 00 00 00 00 | [0x4157be3e | 0]: 3 3
+ [0x4157a3e8]: ba dc cd ab c8 a3 57 41 | [0x4157be3e | 4]: 2 2
+ [0x4157a3f0]: 0c 1a 00 00 00 00 00 00 | [0x4157be3f | 0]: 2 3
+ [0x4157a3f8]: 00 00 00 00 00 00 00 00 | [0x4157be3f | 4]: 3 3
+[ERR][KProcess:LmsTestCaseTask]***** Kernel Address Sanitizer Error Detected End *****
+str[ 0]=0x 0
+######LmsTestUseAfterFree stop ######
+```
+输出的关键信息包括:
+- 错误类型:
+ - Heap buffer overflow堆内存越界
+ - Use after free 释放后使用
+- 错误操作:
+ - Illegal Read非法读
+ - Illegal Write非法写
+ - Illegal Double free重复释放
+- 上下文:
+ - 当前任务信息(taskName, taskId)
+ - 回溯栈(backtrace)
+- 出错地址的内存信息:
+ - 内存的值、及对应影子内存的值
+ - 内存地址:内存值| [影子内存地址 | 影子内存字节内偏移]:影子内存值
+ - 影子内存值:0(可读可写)、3(已释放)、2(红区)、1(填充值)。
+
+
+### 用户态开发流程
+在待检测的app编译脚本中,添加如下参数即可, 完整示例可参见/kernel/liteos_a/apps/lms/BUILD.gn
+```
+if ("$ohos_build_compiler_specified" == "gcc") {
+ cflags_c = [
+ "-O0",
+ "-fsanitize=kernel-address",
+ "-funwind-tables",
+ "-fasynchronous-unwind-tables",
+ ]
+ } else {
+ cflags_c = [
+ "-O0",
+ "-fsanitize=kernel-address",
+ "-mllvm",
+ "-asan-instrumentation-with-call-threshold=0",
+ "-mllvm",
+ "-asan-stack=0",
+ "-mllvm",
+ "-asan-globals=0",
+ "-funwind-tables",
+ "-fasynchronous-unwind-tables",
+ ]
+ }
+ ldflags = [
+ "-rdynamic",
+ "-lunwind",
+ "-lusrlms",
+ "-Wl,--wrap=realloc",
+ "-Wl,--wrap=calloc",
+ "-Wl,--wrap=malloc",
+ "-Wl,--wrap=free",
+ "-Wl,--wrap=valloc",
+ "-Wl,--wrap=aligned_alloc",
+ "-Wl,--wrap=memset",
+ "-Wl,--wrap=memcpy",
+ "-Wl,--wrap=memmove",
+ "-Wl,--wrap=strcpy",
+ "-Wl,--wrap=strcat",
+ ]
+ deps = [ "//kernel/liteos_a/kernel/extended/lms/usr:usrlmslib" ]
+ ```
+
+### 用户态编程实例
+
+ 本实例实现如下功能:
+
+ 1. 构造内存溢出错误和释放后使用错误。
+
+ 2. 添加对应编译选项后,重新编译执行
+
+### 用户态示例代码
+实例代码如下
+```c
+static void BufWriteTest(void *buf, int start, int end)
+{
+ for (int i = start; i <= end; i++) {
+ ((char *)buf)[i] = 'a';
+ }
+}
+
+static void BufReadTest(void *buf, int start, int end)
+{
+ char tmp;
+ for (int i = start; i <= end; i++) {
+ tmp = ((char *)buf)[i];
+ }
+}
+
+static void LmsMallocTest(void)
+{
+ printf("\n-------- LmsMallocTest Start --------\n");
+ char *buf = (char *)malloc(16);
+ BufReadTest(buf, -1, 16);
+ free(buf);
+ printf("\n-------- LmsMallocTest End --------\n");
+}
+
+static void LmsFreeTest(void)
+{
+ printf("\n-------- LmsFreeTest Start --------\n");
+ char *buf = (char *)malloc(16);
+ free(buf);
+ BufReadTest(buf, 1, 1);
+ free(buf);
+ printf("\n-------- LmsFreeTest End --------\n");
+}
+
+int main(int argc, char * const * argv)
+{
+ printf("\n############### Lms Test start ###############\n");
+ char *tmp = (char *)malloc(5000);
+ LmsMallocTest();
+ LmsFreeTest();
+ printf("\n############### Lms Test End ###############\n");
+}
+```
+### 用户态结果验证
+输出结果如下:
+
+```c
+***** Lite Memory Sanitizer Error Detected *****
+Heap buffer overflow error detected!
+Illegal READ address at: [0x1f8b3edf]
+Shadow memory address: [0x3d34d3ed : 6] Shadow memory value: [2]
+
+Accessable heap addr 0
+Heap red zone 2
+Heap freed buffer 3
+
+Dump info around address [0x1f8b3edf]:
+
+ [0x1f8b3eb8]: 74 55 8b 1f 74 55 8b 1f | [0x3d34d3eb | 4]: 0 0
+ [0x1f8b3ec0]: f8 9c 8b 1f 00 00 00 00 | [0x3d34d3ec | 0]: 0 0
+ [0x1f8b3ec8]: 00 00 00 00 9c fc fc fc | [0x3d34d3ec | 4]: 0 0
+ [0x1f8b3ed0]: 21 00 00 00 41 00 00 00 | [0x3d34d3ed | 0]: 0 0
+ [0x1f8b3ed8]: 60 55 8b 1f 60 55 8b [1f]| [0x3d34d3ed | 4]: 2 [2]
+ [0x1f8b3ee0]: 50 4e 0b 00 00 00 00 00 | [0x3d34d3ee | 0]: 0 0
+ [0x1f8b3ee8]: 09 00 00 00 00 00 00 00 | [0x3d34d3ee | 4]: 0 0
+ [0x1f8b3ef0]: 00 00 00 00 08 03 09 00 | [0x3d34d3ef | 0]: 2 2
+ [0x1f8b3ef8]: 00 00 00 00 00 00 00 00 | [0x3d34d3ef | 4]: 2 2
+***** Lite Memory Sanitizer Error Detected End *****
+
+Backtrace() returned 5 addresses
+ #01: [0x4d6c] -> ./sample_usr_lms
+ #02: <(null)+0x2004074>[0x4074] -> ./sample_usr_lms
+ #03: <(null)+0x2003714>[0x3714] -> ./sample_usr_lms
+ #04: [0x363c] -> ./sample_usr_lms
+ #05: <(null)+0x1f856f30>[0x56f30] -> /lib/libc.so
+-------- LMS_malloc_test End --------
+
+***** Lite Memory Sanitizer Error Detected *****
+Use after free error detected!
+Illegal Double free address at: [0x1f8b3ee0]
+Shadow memory address: [0x3d34d3ee : 0] Shadow memory value: [3]
+
+Accessable heap addr 0
+Heap red zone 2
+Heap freed buffer 3
+
+
+Dump info around address [0x1f8b3ee0]:
+
+ [0x1f8b3ec0]: f8 9c 8b 1f 00 00 00 00 | [0x3d34d3ec | 0]: 0 0
+ [0x1f8b3ec8]: 00 00 00 00 fc fd fc fc | [0x3d34d3ec | 4]: 0 0
+ [0x1f8b3ed0]: 21 00 00 00 20 01 00 00 | [0x3d34d3ed | 0]: 0 0
+ [0x1f8b3ed8]: 60 55 8b 1f 60 55 8b 1f | [0x3d34d3ed | 4]: 2 2
+ [0x1f8b3ee0]: [20] 60 9a 1f 40 61 9a 1f | [0x3d34d3ee | 0]: [3] 3
+ [0x1f8b3ee8]: 60 62 9a 1f 80 63 9a 1f | [0x3d34d3ee | 4]: 3 3
+ [0x1f8b3ef0]: 20 40 8b 1f 20 20 8b 1f | [0x3d34d3ef | 0]: 3 3
+ [0x1f8b3ef8]: 00 00 00 00 00 00 00 00 | [0x3d34d3ef | 4]: 3 3
+ [0x1f8b3f00]: 00 00 00 00 00 00 00 00 | [0x3d34d3f0 | 0]: 3 3
+***** Lite Memory Sanitizer Error Detected End *****
+
+Backtrace() returned 5 addresses
+ #01: [0x4d6c] -> ./sample_usr_lms
+ #02: [0x5548] -> ./sample_usr_lms
+ #03: <(null)+0x2003fc4>[0x3fc4] -> ./sample_usr_lms
+ #04: [0x3664] -> ./sample_usr_lms
+ #05: <(null)+0x1f856f30>[0x56f30] -> /lib/libc.so
+
+-------- LMS_free_test End --------
+```
+输出的Backtrace中包含地址所在的文件名,用户需查找对应文件中地址对应的代码行号。
diff --git a/zh-cn/device-dev/kernel/kernel-small-debug-perf.md b/zh-cn/device-dev/kernel/kernel-small-debug-perf.md
new file mode 100644
index 0000000000000000000000000000000000000000..6fa440f4f729f9b6ec94022148b1028ba5ee35f1
--- /dev/null
+++ b/zh-cn/device-dev/kernel/kernel-small-debug-perf.md
@@ -0,0 +1,506 @@
+# Perf调测
+
+- [基本概念](#section1)
+
+- [运行机制](#section2)
+
+- [接口说明](#section3)
+
+ - [内核态](#section3.1)
+
+ - [用户态](#section3.2)
+
+- [开发指导](#section4)
+
+ - [内核态开发流程](#section4.1.1)
+
+ - [内核态编程实例](#section4.1.2)
+
+ - [内核态实例代码](#section4.1.3)
+
+ - [内核态结果验证](#section4.1.4)
+
+ - [用户态开发流程](#section4.2.1)
+
+ - [用户态编程实例](#section4.2.2)
+
+ - [用户态实例代码](#section4.2.3)
+
+ - [用户态结果验证](#section4.2.4)
+
+## 基本概念
+Perf为性能分析工具,依赖PMU(Performance Monitoring Unit)对采样事件进行计数和上下文采集,统计出热点分布(hot spot)和热路径(hot path)。
+
+## 运行机制
+基于事件采样原理,以性能事件为基础,当事件发生时,相应的事件计数器溢出发生中断,在中断处理函数中记录事件信息,包括当前的pc、当前运行的任务ID以及调用栈等信息。
+
+Perf提供2种工作模式,计数模式和采样模式。
+
+计数模式仅统计事件发生的次数和耗时,采样模式会收集上下文数据到环形buffer中,需要IDE进行数据解析生成热点函数与热点路径。
+
+## 接口说明
+
+### 内核态
+
+OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h)参考。
+
+**表 1** Perf模块接口说明
+
+功能分类
+ |
+接口名
+ |
+描述
+ |
+
+
+开启/停止Perf采样
+ |
+LOS_PerfStart
+ |
+开启采样
+ |
+
+LOS_PerfStop
+ |
+停止采样
+ |
+
+配置Perf采样事件
+ |
+LOS_PerfConfig
+ |
+配置采样事件的类型、周期等
+ |
+
+读取采样数据
+ |
+LOS_PerfDataRead
+ |
+读取采样数据到指定地址
+ |
+
+注册采样数据缓冲区的钩子函数
+ |
+LOS_PerfNotifyHookReg
+ |
+注册缓冲区水线到达的处理钩子
+ |
+
+LOS_PerfFlushHookReg
+ |
+注册缓冲区刷cache的钩子
+ |
+
+
+
+
+1. Perf采样事件的结构体为PerfConfigAttr,详细字段含义及取值详见kernel\include\los_perf.h。
+
+2. 采样数据缓冲区为环形buffer,buffer中读过的区域可以覆盖写,未被读过的区域不能被覆盖写。
+
+3. 缓冲区有限,用户可通过注册水线到达的钩子进行buffer溢出提醒或buffer读操作。默认水线值为buffer总大小的1/2。
+ 示例如下:
+ ```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);
+ ```
+
+4. 若perf采样的buffer涉及到cpu 跨cache,则用户可通过注册刷cache的钩子,进行cache同步。
+ 示例如下:
+ ```c
+ VOID Example_PerfFlushHook(VOID *addr, UINT32 size)
+ {
+ OsCacheFlush(addr, size); /* platform interface */
+ }
+ LOS_PerfNotifyHookReg(Example_PerfFlushHook);
+ ```
+ 刷cache接口视具体的平台自行配置。
+
+### 用户态
+
+新增perf字符设备,位于"/dev/perf",通过对设备节点的read\write\ioctl,实现用户态perf的读写和控制:
+
+- read: 用户态读取perf记录数据
+
+- write: 用户态采样事件配置
+
+- ioctl: 用户态Perf控制操作,包括
+ ```C
+ #define PERF_IOC_MAGIC 'T'
+ #define PERF_START _IO(PERF_IOC_MAGIC, 1)
+ #define PERF_STOP _IO(PERF_IOC_MAGIC, 2)
+ ```
+ 分别对应Perf启动(LOS_PerfStart)、停止(LOS_PerfStop)
+
+具体的使用方法参见[用户态编程实例](#section4.2.2)
+
+
+
+## 开发指导
+
+### 内核态开发流程
+
+开启Perf调测的典型流程如下:
+
+1. 配置Perf模块相关宏。
+
+ 配置Perf控制宏LOSCFG_KERNEL_PERF,默认关,在kernel/liteos_a目录下执行 make update_config命令配置"Kernel->Enable Perf Feature"中打开:
+
+ | 配置项 | menuconfig选项 | 含义 | 设置值 |
+ | ------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------ |
+ | LOSCFG_KERNEL_PERF | Enable Perf Feature | Perf模块的裁剪开关 | YES/NO |
+ | LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming Calc Methods->By Tick | Perf计时单位为tick | YES/NO |
+ | LOSCFG_PERF_CALC_TIME_BY_CYCLE | Time-consuming Calc Methods->By Cpu Cycle | Perf计时单位为cycle | YES/NO |
+ | LOSCFG_PERF_BUFFER_SIZE | Perf Sampling Buffer Size | Perf采样buffer的大小 | INT |
+ | LOSCFG_PERF_HW_PMU | Enable Hardware Pmu Events for Sampling | 使能硬件PMU事件,需要目标平台支持硬件PMU | YES/NO |
+ | LOSCFG_PERF_TIMED_PMU | Enable Hrtimer Period Events for Sampling | 使能高精度周期事件,需要目标平台支持高精度定时器 | YES/NO |
+ | LOSCFG_PERF_SW_PMU | Enable Software Events for Sampling | 使能软件事件,需要开启LOSCFG_KERNEL_HOOK | INT |
+
+2. 调用LOS_PerfConfig配置需要采样的事件。
+
+ Perf提供2种模式的配置,及3大类型的事件配置:
+
+ 2种模式:计数模式(仅统计事件发生次数)、采样模式(收集上下文如任务ID、pc、backtrace等)。
+
+ 3种事件类型:CPU硬件事件(cycle、branch、icache、dcache等)、高精度周期事件(cpu clock)、OS软件事件(task switch、mux pend、irq等)。
+
+3. 在需要采样的代码起始点调用LOS_PerfStart(UINT32 sectionId), 入参sectionId标记不同的采样回话id。
+
+4. 在需要采样的代码结束点调用LOS_PerfStop。
+
+5. 调用输出缓冲区数据的接口LOS_PerfDataRead读取采样数据,并使用IDE工具进行解析。
+
+
+### 内核态编程实例
+
+ 本实例实现如下功能:
+
+ 1. 创建perf测试任务。
+
+ 2. 配置采样事件。
+
+ 3. 启动perf。
+
+ 4. 执行需要统计的算法。
+
+ 5. 停止perf。
+
+ 6. 输出统计结果。
+
+### 内核态示例代码
+
+前提条件:在menuconfig菜单中完成perf模块的配置。
+
+实例代码如下:
+
+```C
+#include "los_perf.h"
+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;
+
+ PerfConfigAttr attr = {
+ .eventsCfg = {
+ .type = PERF_EVENT_TYPE_HW,
+ .events = {
+ [0] = {PERF_COUNT_HW_CPU_CYCLES, 0xFFFF},
+ [1] = {PERF_COUNT_HW_BRANCH_INSTRUCTIONS, 0xFFFFFF00},
+ },
+ .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);
+ 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;
+ /* 创建用于perf测试的任务 */
+ memset(&perfTestTask, 0, sizeof(TSK_INIT_PARAM_S));
+ perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
+ perfTestTask.pcName = "TestPerfTsk"; /* 测试任务名称 */
+ perfTestTask.uwStackSize = 0x800;
+ perfTestTask.usTaskPrio = 5;
+ perfTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
+ ret = LOS_TaskCreate(&g_perfTestTaskId, &perfTestTask);
+ if(ret != LOS_OK){
+ PRINT_ERR("PerfTestTask create failed.\n");
+ return LOS_NOK;
+ }
+ return LOS_OK;
+}
+LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
+```
+
+### 内核态结果验证
+
+输出结果如下:
+
+```c
+--------count mode----------
+[EMG] [cycles] eventType: 0xff: 5466989440
+[EMG] [branches] eventType: 0xc: 602166445
+------- sample mode----------
+[EMG] dump section data, addr: 0x8000000 length: 0x800000
+num: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ...
+hex: 00 ef ef ef 00 00 00 00 14 00 00 00 60 00 00 00 00 00 00 00 70 88 36 40 08 00 00 00 6b 65 72 6e 65 6c 00 00 01 00 00 00 cc 55 30 40 08 00 00 00 6b 65 72 6e 65 6c 00 00
+```
+
+- 针对计数模式,系统在perf stop后会打印:
+
+ 事件名称(cycles)、事件类型(0xff)、事件发生的次数(5466989440)。
+
+ 当采样事件为硬件PMU事件时,打印的事件类型为实际的硬件事件id,非enum PmuHWId中定义的抽象类型。
+
+- 针对采样模式,系统在perf stop后会打印采样数据的地址和长度:
+
+ dump section data, addr: (0x8000000) length: (0x5000)
+
+ 用户可以通过JTAG口导出该片内存,再使用IDE线下工具解析。
+
+ 或者通过LOS_PerfDataRead将数据读到指定地址,进行查看或进一步处理。示例中OsPrintBuff为测试接口,其按字节打印Read到的采样数据,num表示第几个字节,hex表示该字节中的数值。
+
+### 用户态开发流程
+通过在menuconfig配置"Driver->Enable PERF DRIVER",开启Perf驱动。该配置仅在内核Enable Perf Feature后,才可在Driver的选项中可见。
+1. 打开“/dev/perf”字符文件,进行读写和IOCTL操作;
+2. 系统提供用户态的perf命令,该命令位于/bin目录下,cd bin 后可执行如下命令:
+- ./perf start [id] 启动perf采样, id 为可选项,默认值为0
+
+- ./perf stop 停止perf采样
+
+- ./perf read \ 从采样缓冲区中读取nBytes数据并打印内容
+
+- ./perf list 罗列-e支持的具体事件
+
+- ./perf stat/record [option] \ 计数/采样模式命令
+
+option可选如下:
+
+- -e,配置采样事件。可使用./perf list 中罗列的同类型事件。
+
+- -p,配置事件采样周期。
+
+- -o, 指定perf采样数据结果保存的文件路径。
+
+- -t,任务Id过滤(白名单),只采取指定任务中的上下文。如果不指定改参数,则默认采集所有的任务。
+
+- -s, 配置采样的具体上下文类型,可查阅los_perf.h中定义的PerfSampleType。
+
+- -P, 进程Id过滤(白名单),只采取指定进程中的上下文。如果不指定改参数,则默认采集所有进程。
+
+- -d, 是否进行分频(事件每发生64次累计+1),该选项仅在硬件cycle事件上生效。
+
+command 为待统计的子程序。
+
+用户态命令行的典型使用方法如下:
+
+./perf list 查看可使用的事件列表, 输出如下:
+
+```c
+cycles [Hardware event]
+instruction [Hardware event]
+dcache [Hardware event]
+dcache-miss [Hardware event]
+icache [Hardware event]
+icache-miss [Hardware event]
+branch [Hardware event]
+branch-miss [Hardware event]
+clock [Timed event]
+task-switch [Software event]
+irq-in [Software event]
+mem-alloc [Software event]
+mux-pend [Software event]
+```
+./perf stat -e cycles os_dump, 输出如下:
+
+```c
+type: 0
+events[0]: 255, 0xffff
+predivided: 0
+sampleType: 0x0
+needSample: 0
+usage os_dump [--help | -l | SERVICE]
+ --help: shows this help
+ -l: only list services, do not dump them
+ SERVICE: dumps only service SERVICE
+time used: 0.058000(s)
+[cycles] eventType: 0xff [core 0]: 21720647
+[cycles] eventType: 0xff [core 1]: 13583830
+```
+
+./perf record -e cycles os_dump, 输出如下:
+
+```c
+type: 0
+events[0]: 255, 0xffff
+predivided: 0
+sampleType: 0x60
+needSample: 1
+usage os_dump [--help | -l | SERVICE]
+ --help: shows this help
+ -l: only list services, do not dump them
+ SERVICE: dumps only service SERVICE
+dump perf data, addr: 0x408643d8 length: 0x5000
+time used: 0.059000(s)
+save perf data success at /storage/data/perf.data
+```
+> **说明**
+
+ > 在进行./perf stat/record命令后,用户可多次执行./perf start 和 ./perf stop进行采样, 采样的事件配置为最近一次执行./perf stat/record 中设置的参数。
+
+### 用户态编程实例
+
+ 本实例实现如下功能:
+
+ 1. 打开perf字符设备。
+
+ 4. 写perf配置事件。
+
+ 3. 启动perf。
+
+ 5. 停止perf。
+
+ 6. 读取perf采样数据。
+
+### 用户态示例代码
+实例代码如下
+```c
+#include "fcntl.h"
+#include "user_copy.h"
+#include "sys/ioctl.h"
+#include "fs/driver.h"
+#include "los_dev_perf.h"
+#include "los_perf.h"
+#include "los_init.h"
+
+/* perf ioctl */
+#define PERF_IOC_MAGIC 'T'
+#define PERF_START _IO(PERF_IOC_MAGIC, 1)
+#define PERF_STOP _IO(PERF_IOC_MAGIC, 2)
+
+int main(int argc, char **argv)
+{
+ char *buf = NULL;
+ ssize_t len;
+
+ int fd = open("/dev/perf", O_RDWR);
+ if (fd == -1) {
+ printf("Perf open failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ PerfConfigAttr attr = {
+ .eventsCfg = {
+#ifdef LOSCFG_PERF_HW_PMU
+ .type = PERF_EVENT_TYPE_HW,
+ .events = {
+ [0] = {PERF_COUNT_HW_CPU_CYCLES, 0xFFFF},
+ },
+#elif defined LOSCFG_PERF_TIMED_PMU
+ .type = PERF_EVENT_TYPE_TIMED,
+ .events = {
+ [0] = {PERF_COUNT_CPU_CLOCK, 100},
+ },
+#elif defined LOSCFG_PERF_SW_PMU
+ .type = PERF_EVENT_TYPE_SW,
+ .events = {
+ [0] = {PERF_COUNT_SW_TASK_SWITCH, 1},
+ },
+#endif
+ .eventsNr = 1, /* 1 event */
+ .predivided = 0,
+ },
+ .taskIds = {0},
+ .taskIdsNr = 0,
+ .processIds = {0},
+ .processIdsNr = 0,
+ .needSample = 1,
+ .sampleType = PERF_RECORD_IP | PERF_RECORD_CALLCHAIN,
+ };
+ (void)write(fd, &attr, sizeof(PerfConfigAttr)); /* perf config */
+
+ ioctl(fd, PERF_START, NULL); /* perf start */
+ test();
+ ioctl(fd, PERF_STOP, NULL); /* perf stop */
+
+ buf = (char *)malloc(LOSCFG_PERF_BUFFER_SIZE);
+ if (buf == NULL) {
+ printf("no memory for read perf 0x%x\n", LOSCFG_PERF_BUFFER_SIZE);
+ return -1;
+ }
+
+ len = read(fd, buf, LOSCFG_PERF_BUFFER_SIZE);
+ OsPrintBuff(buf, len); /* print data */
+
+ free(buf);
+ close(fd);
+ return 0;
+}
+```
+### 用户态结果验证
+输出结果如下:
+
+```c
+[EMG] dump section data, addr: 0x8000000 length: 0x800000
+num: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 ...
+hex: 00 ef ef ef 00 00 00 00 14 00 00 00 60 00 00 00 00 00 00 00 70 88 36 40 08 00 00 00 6b 65 72 6e 65 6c 00 00 01 00 00 00 cc 55 30 40 08 00 00 00 6b 65 72 6e 65 6c 00 00
+```