提交 d3855b41 编写于 作者: W wangchen

fix: A核资料描述和示例代码问题修改

方案描述:
1,按测试沟通的文档问题进行修改

fix #I69MYM
Signed-off-by: Nwangchen <wangchen240@huawei.com>
上级 1dad82b7
......@@ -136,7 +136,7 @@
- [魔法键使用方法](kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](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)
- [进程调测](kernel-small-debug-process-cpu.md)
- 内核态内存调测
......
......@@ -24,7 +24,7 @@ musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony
#### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数testcase 或新建文件由主函数调用
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ExamplePosix。
示例代码如下:
......@@ -33,12 +33,6 @@ musl libc库支持POSIX标准,涉及的系统调用相关接口由OpenHarmony
#include <unistd.h>
#include <pthread.h>
#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define THREAD_NUM 3
int g_startNum = 0; /* 启动的线程数 */
int g_wakenNum = 0; /* 唤醒的线程数 */
......@@ -48,10 +42,8 @@ struct testdata {
pthread_cond_t cond;
} g_td;
/*
* 子线程入口函数
*/
static void *ChildThreadFunc(void *arg)
/* 子线程入口函数 */
static VOID *ChildThreadFunc(VOID *arg)
{
int rc;
pthread_t self = pthread_self();
......@@ -59,7 +51,7 @@ static void *ChildThreadFunc(void *arg)
/* 获取mutex锁 */
rc = pthread_mutex_lock(&g_td.mutex);
if (rc != 0) {
printf("ERROR:take mutex lock failed, error code is %d!\n", rc);
dprintf("ERROR:take mutex lock failed, error code is %d!\n", rc);
goto EXIT;
}
......@@ -69,7 +61,7 @@ static void *ChildThreadFunc(void *arg)
/* 等待cond条件变量 */
rc = pthread_cond_wait(&g_td.cond, &g_td.mutex);
if (rc != 0) {
printf("ERROR: pthread condition wait failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition wait failed, error code is %d!\n", rc);
(void)pthread_mutex_unlock(&g_td.mutex);
goto EXIT;
}
......@@ -77,7 +69,7 @@ static void *ChildThreadFunc(void *arg)
/* 尝试获取mutex锁,正常场景,此处无法获取锁 */
rc = pthread_mutex_trylock(&g_td.mutex);
if (rc == 0) {
printf("ERROR: mutex gets an abnormal lock!\n");
dprintf("ERROR: mutex gets an abnormal lock!\n");
goto EXIT;
}
......@@ -87,14 +79,14 @@ static void *ChildThreadFunc(void *arg)
/* 释放mutex锁 */
rc = pthread_mutex_unlock(&g_td.mutex);
if (rc != 0) {
printf("ERROR: mutex release failed, error code is %d!\n", rc);
dprintf("ERROR: mutex release failed, error code is %d!\n", rc);
goto EXIT;
}
EXIT:
return NULL;
}
static int testcase(void)
static int ExamplePosix(VOID)
{
int i, rc;
pthread_t thread[THREAD_NUM];
......@@ -102,14 +94,14 @@ static int testcase(void)
/* 初始化mutex锁 */
rc = pthread_mutex_init(&g_td.mutex, NULL);
if (rc != 0) {
printf("ERROR: mutex init failed, error code is %d!\n", rc);
dprintf("ERROR: mutex init failed, error code is %d!\n", rc);
goto ERROROUT;
}
/* 初始化cond条件变量 */
rc = pthread_cond_init(&g_td.cond, NULL);
if (rc != 0) {
printf("ERROR: pthread condition init failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition init failed, error code is %d!\n", rc);
goto ERROROUT;
}
......@@ -117,10 +109,11 @@ static int testcase(void)
for (i = 0; i < THREAD_NUM; i++) {
rc = pthread_create(&thread[i], NULL, ChildThreadFunc, NULL);
if (rc != 0) {
printf("ERROR: pthread create failed, error code is %d!\n", rc);
dprintf("ERROR: pthread create failed, error code is %d!\n", rc);
goto ERROROUT;
}
}
dprintf("pthread_create ok\n");
/* 等待所有子线程都完成mutex锁的获取 */
while (g_startNum < THREAD_NUM) {
......@@ -130,14 +123,14 @@ static int testcase(void)
/* 获取mutex锁,确保所有子线程都阻塞在pthread_cond_wait上 */
rc = pthread_mutex_lock(&g_td.mutex);
if (rc != 0) {
printf("ERROR: mutex lock failed, error code is %d\n", rc);
dprintf("ERROR: mutex lock failed, error code is %d\n", rc);
goto ERROROUT;
}
/* 释放mutex锁 */
rc = pthread_mutex_unlock(&g_td.mutex);
if (rc != 0) {
printf("ERROR: mutex unlock failed, error code is %d!\n", rc);
dprintf("ERROR: mutex unlock failed, error code is %d!\n", rc);
goto ERROROUT;
}
......@@ -145,7 +138,7 @@ static int testcase(void)
/* 在cond条件变量上广播信号 */
rc = pthread_cond_signal(&g_td.cond);
if (rc != 0) {
printf("ERROR: pthread condition failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition failed, error code is %d!\n", rc);
goto ERROROUT;
}
}
......@@ -154,52 +147,42 @@ static int testcase(void)
/* 检查是否所有子线程都已被唤醒 */
if (g_wakenNum != THREAD_NUM) {
printf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum);
dprintf("ERROR: not all threads awaken, only %d thread(s) awaken!\n", g_wakenNum);
goto ERROROUT;
}
dprintf("all threads awaked\n");
/* join所有子线程,即等待其结束 */
for (i = 0; i < THREAD_NUM; i++) {
rc = pthread_join(thread[i], NULL);
if (rc != 0) {
printf("ERROR: pthread join failed, error code is %d!\n", rc);
dprintf("ERROR: pthread join failed, error code is %d!\n", rc);
goto ERROROUT;
}
}
dprintf("all threads join ok\n");
/* 销毁cond条件变量 */
rc = pthread_cond_destroy(&g_td.cond);
if (rc != 0) {
printf("ERROR: pthread condition destroy failed, error code is %d!\n", rc);
dprintf("ERROR: pthread condition destroy failed, error code is %d!\n", rc);
goto ERROROUT;
}
return 0;
ERROROUT:
return -1;
}
```
/*
* 示例代码主函数
*/
int main(int argc, char *argv[])
{
int rc;
#### 验证结果
/* 启动测试函数 */
rc = testcase();
if (rc != 0) {
printf("ERROR: testcase failed!\n");
}
输出结果如下:
return 0;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
```
pthread_create ok
all threads awaked
all threads join ok
```
## 与Linux标准库差异
......@@ -217,20 +200,17 @@ int main(int argc, char *argv[])
### 内存
**h2与Linux mmap的差异**
**与Linux mmap的差异**
mmap接口原型为:void \*mmap (void \*addr, size_t length, int prot, int flags, int fd, off_t offset)。
其中,参数fd的生命周期实现与Linux glibc存在差异。具体体现在,glibc在成功调用mmap进行映射后,可以立即释放fd句柄。在OpenHarmony内核中,不允许用户在映射成功后立即关闭相关fd,只允许在取消映射munmap后再进行fd的close操作。如果用户不进行fd的close操作,操作系统将在进程退出时对该fd进行回收。
**h2代码举例**
**代码举例**
Linux目前支持的情况如下:
```
int main(int argc, char *argv[])
{
......@@ -247,7 +227,7 @@ int main(int argc, char *argv[])
perror("mmap");
exit(EXIT_FAILURE);
}
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
close(fd); /* OpenHarmony does not support closing fd immediately after the mapping is successful. */
...
exit(EXIT_SUCCESS);
}
......@@ -255,7 +235,7 @@ int main(int argc, char *argv[])
OpenHarmony支持的情况如下:
```
int main(int argc, char *argv[])
{
......@@ -274,7 +254,7 @@ int main(int argc, char *argv[])
}
...
munmap(addr, length);
close(fd); /* Close fd after the munmap is canceled. */
close(fd); /* Close fd after the munmap is canceled. */
exit(EXIT_SUCCESS);
}
```
......
......@@ -31,7 +31,7 @@ OpenHarmony LiteOS-A的事件模块提供的事件,具有如下特点:
### 事件控制块
```
/**
* 事件控制块数据结构
......@@ -144,21 +144,21 @@ UINT32 g_testTaskId;
EVENT_CB_S g_exampleEvent;
/* 等待的事件类型 */
#define EVENT_WAIT 0x00000001
#define EVENT_WAIT 0x00000001
#define EVENT_TIMEOUT 500
/* 用例任务入口函数 */
VOID Example_Event(VOID)
{
UINT32 event;
/* 超时等待方式读事件,超时时间为100 ticks, 若100 ticks后未读取到指定事件,读事件超时,任务直接唤醒 */
printf("Example_Event wait event 0x%x \n", EVENT_WAIT);
dprintf("Example_Event wait event 0x%x \n", EVENT_WAIT);
event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, 100);
event = LOS_EventRead(&g_exampleEvent, EVENT_WAIT, LOS_WAITMODE_AND, EVENT_TIMEOUT);
if (event == EVENT_WAIT) {
printf("Example_Event,read event :0x%x\n", event);
dprintf("Example_Event,read event :0x%x\n", event);
} else {
printf("Example_Event,read event timeout\n");
dprintf("Example_Event,read event timeout\n");
}
}
......@@ -170,7 +170,7 @@ UINT32 Example_EventEntry(VOID)
/* 事件初始化 */
ret = LOS_EventInit(&g_exampleEvent);
if (ret != LOS_OK) {
printf("init event failed .\n");
dprintf("init event failed .\n");
return -1;
}
......@@ -182,30 +182,23 @@ UINT32 Example_EventEntry(VOID)
task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId, &task1);
if (ret != LOS_OK) {
printf("task create failed.\n");
dprintf("task create failed.\n");
return LOS_NOK;
}
/* 写g_testTaskId 等待事件 */
printf("Example_TaskEntry write event.\n");
dprintf("Example_TaskEntry write event.\n");
ret = LOS_EventWrite(&g_exampleEvent, EVENT_WAIT);
if (ret != LOS_OK) {
printf("event write failed.\n");
dprintf("event write failed.\n");
return LOS_NOK;
}
/* 清标志位 */
printf("EventMask:%d\n", g_exampleEvent.uwEventID);
dprintf("EventMask:%d\n", g_exampleEvent.uwEventID);
LOS_EventClear(&g_exampleEvent, ~g_exampleEvent.uwEventID);
printf("EventMask:%d\n", g_exampleEvent.uwEventID);
/* 删除任务 */
ret = LOS_TaskDelete(g_testTaskId);
if (ret != LOS_OK) {
printf("task delete failed.\n");
return LOS_NOK;
}
dprintf("EventMask:%d\n", g_exampleEvent.uwEventID);
return LOS_OK;
}
......@@ -216,7 +209,7 @@ UINT32 Example_EventEntry(VOID)
编译运行得到的结果为:
```
Example_Event wait event 0x1
Example_TaskEntry write event.
......
......@@ -104,13 +104,13 @@
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数Example_MutexEntry。
示例代码如下:
```
#include <string.h>
#include "los_mux.h"
/* 互斥锁 */
LosMux g_testMux;
LosMux g_testMutex;
/* 任务ID */
UINT32 g_testTaskId01;
UINT32 g_testTaskId02;
......@@ -118,48 +118,49 @@ UINT32 g_testTaskId02;
VOID Example_MutexTask1(VOID)
{
UINT32 ret;
LOS_TaskDelay(50);
printf("task1 try to get mutex, wait 10 ticks.\n");
dprintf("task1 try to get mutex, wait 10 ticks.\n");
/* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMux, 10);
ret = LOS_MuxLock(&g_testMutex, 10);
if (ret == LOS_OK) {
printf("task1 get mutex g_testMux.\n");
dprintf("task1 get mutex g_testMux.\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux);
LOS_MuxUnlock(&g_testMutex);
return;
}
if (ret == LOS_ETIMEDOUT ) {
printf("task1 timeout and try to get mutex, wait forever.\n");
/* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMux, LOS_WAIT_FOREVER);
if (ret == LOS_OK) {
printf("task1 wait forever, get mutex g_testMux.\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux);
/* 删除互斥锁 */
LOS_MuxDestroy(&g_testMux);
printf("task1 post and delete mutex g_testMux.\n");
return;
}
}
if (ret == LOS_ETIMEDOUT) {
dprintf("task1 timeout and try to get mutex, wait forever.\n");
/* 申请互斥锁 */
ret = LOS_MuxLock(&g_testMutex, LOS_WAIT_FOREVER);
if (ret == LOS_OK) {
dprintf("task1 wait forever, get mutex g_testMux.\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMutex);
/* 删除互斥锁 */
LOS_MuxDestroy(&g_testMutex);
dprintf("task1 post and delete mutex g_testMux.\n");
return;
}
}
return;
}
VOID Example_MutexTask2(VOID)
{
printf("task2 try to get mutex, wait forever.\n");
dprintf("task2 try to get mutex, wait forever.\n");
/* 申请互斥锁 */
(VOID)LOS_MuxLock(&g_testMux, LOS_WAIT_FOREVER);
(VOID)LOS_MuxLock(&g_testMutex, LOS_WAIT_FOREVER);
printf("task2 get mutex g_testMux and suspend 100 ticks.\n");
dprintf("task2 get mutex g_testMux and suspend 100 ticks.\n");
/* 任务休眠100Ticks */
LOS_TaskDelay(100);
printf("task2 resumed and post the g_testMux\n");
dprintf("task2 resumed and post the g_testMux\n");
/* 释放互斥锁 */
LOS_MuxUnlock(&g_testMux);
LOS_MuxUnlock(&g_testMutex);
return;
}
......@@ -170,7 +171,7 @@ UINT32 Example_MutexEntry(VOID)
TSK_INIT_PARAM_S task2;
/* 初始化互斥锁 */
LOS_MuxInit(&g_testMux, NULL);
LOS_MuxInit(&g_testMutex, NULL);
/* 锁任务调度 */
LOS_TaskLock();
......@@ -183,7 +184,7 @@ UINT32 Example_MutexEntry(VOID)
task1.usTaskPrio = 5;
ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) {
printf("task1 create failed.\n");
dprintf("task1 create failed.\n");
return LOS_NOK;
}
......@@ -195,7 +196,7 @@ UINT32 Example_MutexEntry(VOID)
task2.usTaskPrio = 4;
ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) {
printf("task2 create failed.\n");
dprintf("task2 create failed.\n");
return LOS_NOK;
}
......@@ -210,11 +211,11 @@ UINT32 Example_MutexEntry(VOID)
编译运行得到的结果为:
```
task1 try to get mutex, wait 10 ticks.
task2 try to get mutex, wait forever.
task2 get mutex g_testMux and suspend 100 ticks.
task1 try to get mutex, wait 10 ticks.
task1 timeout and try to get mutex, wait forever.
task2 resumed and post the g_testMux
task1 wait forever, get mutex g_testMux.
......
......@@ -31,7 +31,7 @@
### 队列控制块
```
/**
* 队列控制块数据结构
......@@ -137,7 +137,9 @@ typedef struct {
### 编程示例
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ExampleQueue。
本演示代码在./kernel/liteos_a/testsuites/kernel/src/osTest.c中编译验证,在TestTaskEntry中调用验证入口函数ExampleQueue,
为方便用户观察,建议调用ExampleQueue前先调用 LOS_Msleep(5000) 进行短时间延时,避免其他打印过多。
示例代码如下:
......@@ -155,7 +157,7 @@ VOID SendEntry(VOID)
ret = LOS_QueueWriteCopy(g_queue, abuf, len, 0);
if(ret != LOS_OK) {
printf("send message failure, error: %x\n", ret);
dprintf("send message failure, error: %x\n", ret);
}
}
......@@ -165,30 +167,36 @@ VOID RecvEntry(VOID)
CHAR readBuf[BUFFER_LEN] = {0};
UINT32 readLen = BUFFER_LEN;
//休眠1s
usleep(1000000);
LOS_Msleep(1000);
ret = LOS_QueueReadCopy(g_queue, readBuf, &readLen, 0);
if(ret != LOS_OK) {
printf("recv message failure, error: %x\n", ret);
dprintf("recv message failure, error: %x\n", ret);
}
printf("recv message: %s\n", readBuf);
dprintf("recv message: %s\n", readBuf);
ret = LOS_QueueDelete(g_queue);
if(ret != LOS_OK) {
printf("delete the queue failure, error: %x\n", ret);
dprintf("delete the queue failure, error: %x\n", ret);
}
printf("delete the queue success!\n");
dprintf("delete the queue success!\n");
}
UINT32 ExampleQueue(VOID)
{
printf("start queue example\n");
dprintf("start queue example\n");
UINT32 ret = 0;
UINT32 task1, task2;
TSK_INIT_PARAM_S initParam = {0};
ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50);
if(ret != LOS_OK) {
dprintf("create queue failure, error: %x\n", ret);
}
dprintf("create the queue success!\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)SendEntry;
initParam.usTaskPrio = 9;
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
......@@ -197,7 +205,8 @@ UINT32 ExampleQueue(VOID)
LOS_TaskLock();
ret = LOS_TaskCreate(&task1, &initParam);
if(ret != LOS_OK) {
printf("create task1 failed, error: %x\n", ret);
dprintf("create task1 failed, error: %x\n", ret);
LOS_QueueDelete(g_queue);
return ret;
}
......@@ -205,17 +214,13 @@ UINT32 ExampleQueue(VOID)
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)RecvEntry;
ret = LOS_TaskCreate(&task2, &initParam);
if(ret != LOS_OK) {
printf("create task2 failed, error: %x\n", ret);
dprintf("create task2 failed, error: %x\n", ret);
LOS_QueueDelete(g_queue);
return ret;
}
ret = LOS_QueueCreate("queue", 5, &g_queue, 0, 50);
if(ret != LOS_OK) {
printf("create queue failure, error: %x\n", ret);
}
printf("create the queue success!\n");
LOS_TaskUnlock();
LOS_Msleep(5000);
return ret;
}
```
......@@ -225,9 +230,9 @@ UINT32 ExampleQueue(VOID)
编译运行得到的结果为:
```
start test example
start queue example
create the queue success!
recv message: test message
delete the queue success!
......
......@@ -22,7 +22,7 @@
**信号量控制块**
```
/**
* 信号量控制块数据结构
......@@ -129,7 +129,8 @@ static UINT32 g_testTaskId01;
static UINT32 g_testTaskId02;
/* 测试任务优先级 */
#define TASK_PRIO_TEST 5
#define TASK_PRIO_LOW 5
#define TASK_PRIO_HI 4
/* 信号量结构体id */
static UINT32 g_semId;
......@@ -138,11 +139,10 @@ VOID ExampleSemTask1(VOID)
{
UINT32 ret;
printf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
dprintf("ExampleSemTask1 try get sem g_semId, timeout 10 ticks.\n");
/* 定时阻塞模式申请信号量,定时时间为10ticks */
ret = LOS_SemPend(g_semId, 10);
/* 申请到信号量 */
if (ret == LOS_OK) {
LOS_SemPost(g_semId);
......@@ -150,12 +150,13 @@ VOID ExampleSemTask1(VOID)
}
/* 定时时间到,未申请到信号量 */
if (ret == LOS_ERRNO_SEM_TIMEOUT) {
printf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
dprintf("ExampleSemTask1 timeout and try get sem g_semId wait forever.\n");
/*永久阻塞模式申请信号量*/
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
printf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
dprintf("ExampleSemTask1 wait_forever and get sem g_semId.\n");
if (ret == LOS_OK) {
dprintf("ExampleSemTask1 post sem g_semId.\n");
LOS_SemPost(g_semId);
return;
}
......@@ -165,19 +166,18 @@ VOID ExampleSemTask1(VOID)
VOID ExampleSemTask2(VOID)
{
UINT32 ret;
printf("ExampleSemTask2 try get sem g_semId wait forever.\n");
dprintf("ExampleSemTask2 try get sem g_semId wait forever.\n");
/* 永久阻塞模式申请信号量 */
ret = LOS_SemPend(g_semId, LOS_WAIT_FOREVER);
if (ret == LOS_OK) {
printf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
dprintf("ExampleSemTask2 get sem g_semId and then delay 20 ticks.\n");
}
/* 任务休眠20 ticks */
LOS_TaskDelay(20);
printf("ExampleSemTask2 post sem g_semId.\n");
dprintf("ExampleSemTask2 post sem g_semId.\n");
/* 释放信号量 */
LOS_SemPost(g_semId);
return;
......@@ -200,10 +200,10 @@ UINT32 ExampleSem(VOID)
task1.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask1;
task1.pcName = "TestTask1";
task1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task1.usTaskPrio = TASK_PRIO_TEST;
task1.usTaskPrio = TASK_PRIO_LOW;
ret = LOS_TaskCreate(&g_testTaskId01, &task1);
if (ret != LOS_OK) {
printf("task1 create failed .\n");
dprintf("task1 create failed .\n");
return LOS_NOK;
}
......@@ -212,16 +212,19 @@ UINT32 ExampleSem(VOID)
task2.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleSemTask2;
task2.pcName = "TestTask2";
task2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
task2.usTaskPrio = (TASK_PRIO_TEST - 1);
task2.usTaskPrio = TASK_PRIO_HI;
ret = LOS_TaskCreate(&g_testTaskId02, &task2);
if (ret != LOS_OK) {
printf("task2 create failed.\n");
dprintf("task2 create failed.\n");
return LOS_NOK;
}
/* 解锁任务调度 */
LOS_TaskUnlock();
/* 任务休眠400 ticks */
LOS_TaskDelay(400);
ret = LOS_SemPost(g_semId);
/* 任务休眠400 ticks */
......@@ -238,12 +241,13 @@ UINT32 ExampleSem(VOID)
编译运行得到的结果为:
```
ExampleSemTask2 try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
ExampleSemTask1 try get sem g_semId, timeout 10 ticks.
ExampleSemTask1 timeout and try get sem g_semId wait forever.
ExampleSemTask2 get sem g_semId and then delay 20 ticks.
ExampleSemTask2 post sem g_semId.
ExampleSemTask1 wait_forever and get sem g_semId.
ExampleSemTask1 post sem g_semId.
```
......@@ -14,7 +14,7 @@
## 功能配置
LOSCFG_MEM_WATERLINE:开关宏,默认关闭;若需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable memory pool waterline or not”。如需获取内存水线,需要打开该配置。
LOSCFG_MEM_WATERLINE:开关宏,默认关闭;若需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable MEM Debug-&gt; Enable memory pool waterline or not”。如需获取内存水线,需要打开该配置。
## 开发指导
......@@ -55,8 +55,9 @@ typedef struct {
**示例代码**
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试。
代码实现如下:
本演示代码在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证,在TestTaskEntry中调用验证入口函数MemTest。
代码实现如下:
```c
#include <stdio.h>
......@@ -69,14 +70,14 @@ void MemInfoTaskFunc(void)
{
LOS_MEM_POOL_STATUS poolStatus = {0};
/* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */
/* pool为要统计信息的内存地址,此处以OS_SYS_MEM_ADDR为例 */
void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus);
/* 算出内存池当前的碎片率百分比 */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
/* 算出内存池当前的使用率百分比 */
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)
......@@ -90,7 +91,7 @@ int MemTest(void)
taskStatus.usTaskPrio = 10;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
dprintf("task create failed\n");
return LOS_NOK;
}
return LOS_OK;
......@@ -103,7 +104,7 @@ int MemTest(void)
编译运行输出的结果如下:
根据实际运行环境,数据会有差异
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
......
......@@ -8,7 +8,7 @@
## 功能配置
1. LOSCFG_MEM_LEAKCHECK:开关宏,默认关闭;如需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable Function call stack of Mem operation recorded”。
1. LOSCFG_MEM_LEAKCHECK:开关宏,默认关闭;如需要打开这个功能,可以在配置项中开启“Debug-&gt; Enable MEM Debug-&gt; Enable Function call stack of Mem operation recorded”。
2. LOS_RECORD_LR_CNT:记录的LR层数,默认3层;每层LR消耗sizeof(void \*)字节数的内存。
......@@ -61,8 +61,10 @@ node size LR[0] LR[1] LR[2]
**示例代码**
本演示代码在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证,在TestTaskEntry中调用验证入口函数MemLeakTest。
为了方便展示建议创建新的内存池,需要在target_config.h 中定义 LOSCFG_MEM_MUL_POOL
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试.
代码实现如下:
```c
......@@ -71,12 +73,24 @@ node size LR[0] LR[1] LR[2]
#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;
/* 由于原内存池分配过多, 为了方便展示, 创建新的内存池 */
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);
/* 释放内存池 */
(VOID)LOS_MemDeInit(pool);
}
```
......@@ -87,51 +101,50 @@ void MemLeakTest(void)
编译运行输出log如下:
```
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
/* 第一次OsMemUsedNodeShow打印,由于该内存池未分配,所以无内存节点 */
node LR[0] LR[1] LR[2]
/* 第二次OsMemUsedNodeShow打印,有两个新的内存节点 */
node LR[0] LR[1] LR[2]
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
```
对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块:
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
```
部分汇编文件如下:
```
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>
```
其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。
其中,通过查找0x4009f040,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。
......@@ -17,9 +17,6 @@ Perf提供2种工作模式,计数模式和采样模式。
## 接口说明
### 内核态
OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细信息可以查看[API](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h)参考。
**表1** Perf模块接口说明
......@@ -63,30 +60,6 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
刷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)
具体的使用方法参见[用户态编程实例](#用户态编程实例)
## 开发指导
......@@ -140,14 +113,33 @@ OpenHarmony LiteOS-A内核的Perf模块提供下面几种功能,接口详细
#### 内核态示例代码
前提条件:在menuconfig菜单中完成perf模块的配置。
前提条件:在menuconfig菜单中完成perf模块的配置, 并勾选Enable Hook Feature,Enable Software Events for Sampling
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试
为方便学习,本演示代码直接在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证即可
实例代码如下:
实例代码如下:
```c
#include "los_perf.h"
#define TEST_MALLOC_SIZE 200
#define TEST_TIME 5
/* 验证函数中进行malloc和free */
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;
......@@ -167,12 +159,18 @@ STATIC VOID perfTestHwEvent(VOID)
UINT32 ret;
CHAR *buf = NULL;
UINT32 len;
//LOS_PerfInit(NULL, 0);
PerfConfigAttr attr = {
.eventsCfg = {
.type = PERF_EVENT_TYPE_HW,
.type = PERF_EVENT_TYPE_SW,
.events = {
[0] = {PERF_COUNT_HW_CPU_CYCLES, 0xFFFF},
[1] = {PERF_COUNT_HW_BRANCH_INSTRUCTIONS, 0xFFFFFF00},
[0] = {PERF_COUNT_SW_TASK_SWITCH, 0xff}, /* 抓取调度 */
[1] = {PERF_COUNT_SW_MEM_ALLOC, 0xff}, /* 抓取内存分配 */
PERF_COUNT_SW_TASK_SWITCH
},
.eventsNr = 2,
.predivided = 1, /* cycle counter increase every 64 cycles */
......@@ -207,20 +205,20 @@ STATIC VOID perfTestHwEvent(VOID)
OsPrintBuff(buf, len); /* print data */
(VOID)LOS_MemFree(m_aucSysMem1, buf);
}
UINT32 Example_Perf_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S perfTestTask;
TSK_INIT_PARAM_S perfTestTask = {0};
UINT32 taskID;
/* 创建用于perf测试的任务 */
memset(&perfTestTask, 0, sizeof(TSK_INIT_PARAM_S));
perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
perfTestTask.pcName = "TestPerfTsk"; /* 测试任务名称 */
perfTestTask.uwStackSize = 0x800; // 0x8000: perf test task stack size
perfTestTask.uwStackSize = 0x1000; // 0x8000: perf test task stack size
perfTestTask.usTaskPrio = 5; // 5: perf test task priority
perfTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
ret = LOS_TaskCreate(&g_perfTestTaskId, &perfTestTask);
ret = LOS_TaskCreate(&taskID, &perfTestTask);
if (ret != LOS_OK) {
PRINT_ERR("PerfTestTask create failed.\n");
PRINT_ERR("PerfTestTask create failed. 0x%x\n", ret);
return LOS_NOK;
}
return LOS_OK;
......@@ -234,13 +232,29 @@ LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
输出结果如下:
```
--------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
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
根据实际运行环境,过程打印会有差异
```
- 针对计数模式,系统在perf stop后会打印:
......@@ -254,184 +268,3 @@ 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
用户可以通过JTAG口导出该片内存,再使用IDE线下工具解析。
或者通过LOS_PerfDataRead将数据读到指定地址,进行查看或进一步处理。示例中OsPrintBuff为测试接口,其按字节打印Read到的采样数据,num表示第几个字节,hex表示该字节中的数值。
### 用户态开发流程
通过在menuconfig配置"Driver-&gt;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 &lt;nBytes&gt; 从采样缓冲区中读取nBytes数据并打印内容
- ./perf list 罗列-e支持的具体事件
- ./perf stat/record [option] &lt;command&gt; 计数/采样模式命令
- option可选如下:
- -e,配置采样事件。可使用./perf list 中罗列的同类型事件。
- -p,配置事件采样周期。
- -o,指定perf采样数据结果保存的文件路径。
- -t,任务Id过滤(白名单),只采取指定任务中的上下文。如果不指定改参数,则默认采集所有的任务。
- -s,配置采样的具体上下文类型,可查阅los_perf.h中定义的PerfSampleType。
- -P,进程Id过滤(白名单),只采取指定进程中的上下文。如果不指定改参数,则默认采集所有进程。
- -d,是否进行分频(事件每发生64次累计+1),该选项仅在硬件cycle事件上生效。
- command 为待统计的子程序。
用户态命令行的典型使用方法如下:
./perf list 查看可使用的事件列表, 输出如下:
```
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, 输出如下:
```
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, 输出如下:
```
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
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 在进行./perf stat/record命令后,用户可多次执行./perf start 和 ./perf stop进行采样, 采样的事件配置为最近一次执行./perfstat/record 中设置的参数。
#### 用户态编程实例
本实例实现如下功能:
1. 打开perf字符设备。
2. 写perf配置事件。
3. 启动perf。
4. 停止perf。
5. 读取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;
}
```
#### 用户态结果验证
输出结果如下
```
[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
```
......@@ -103,7 +103,7 @@ CPU占用率的典型开发流程:
**示例代码**
该示例代码的测试函数可以加在 kernel /liteos_a/testsuites /kernel /src /osTest.c 中的 TestTaskEntry 中进行测试
本演示代码在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证,在TestTaskEntry中调用验证入口函数CpupTest
代码实现如下:
......@@ -114,12 +114,13 @@ CPU占用率的典型开发流程:
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
printf("entry cpup test example\n");
while (1) {
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;
......@@ -138,12 +139,12 @@ UINT32 ItCpupTest(VOID)
usleep(100); // 100: delay for 100ms
/* 获取当前系统历史CPU占用率 */
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
printf("the history system cpu usage in all time:%u.%u\n",
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);
/* 获取指定任务的CPU占用率,该测试例程中指定的任务为以上创建的cpup测试任务 */
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",
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;
}
......@@ -158,4 +159,6 @@ UINT32 ItCpupTest(VOID)
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
根据实际运行环境,打印会有差异
```
......@@ -34,38 +34,35 @@
新增一个内核模块,需要在内核初始化时进行该模块的初始化,则通过内核启动框架将该模块的初始化函数注册进内核启动流程中。
为方便学习,本演示代码直接在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证即可。
**示例代码**
```c
/* 内核启动框架头文件 */
#include "los_init.h"
......
/* 新增模块的初始化函数 */
unsigned int OsSampleModInit(void)
{
PRINTK("OsSampleModInit SUCCESS!\n");
......
}
......
/* 在启动框架的目标层级中注册新增模块 */
LOS_MODULE_INIT(OsSampleModInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
```
**结果验证**
```
main core booting up...
/* 根据实际运行环境,过程打印会有差异 */
......
/* 打印测试代码新增模块初始化函数 */
OsSampleModInit SUCCESS!
releasing 1 secondary cores
cpu 1 entering scheduler
cpu 0 entering scheduler
```
......
......@@ -27,7 +27,7 @@ LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
}
```
> 上述启动代码在 kernel/liteos_a/kernel/user/src/los_user_init.c 中,g_initPath 根据启动设置的不同,其值为 /dev/shm/init 或 /bin/init。
> 上述启动代码在 kernel/liteos_a/kernel/user/src/los_user_init.c 中,g_initPath 根据启动设置的不同,其值为 /dev/shm/init 或 /bin/init。
系统启动阶段,OsUserInitProcess启动init进程。具体过程如下:
......
......@@ -290,7 +290,7 @@
- [魔法键使用方法](kernel/kernel-small-debug-shell-magickey.md)
- [用户态异常信息说明](kernel/kernel-small-debug-shell-error.md)
- [Trace调测](kernel/kernel-small-debug-trace.md)
- [Perf调测](kernel/kernel-mini-memory-perf.md)
- [Perf调测](kernel/kernel-small-debug-perf.md)
- [LMS调测](kernel/kernel-small-memory-lms.md)
- [进程调测](kernel/kernel-small-debug-process-cpu.md)
- 内核态内存调测
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册