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

!14334 [翻译完成】#I6868S

Merge pull request !14334 from Annie_wang/PR12967C
......@@ -26,6 +26,7 @@
- [Exception Debugging](kernel-mini-memory-exception.md)
- [Trace](kernel-mini-memory-trace.md)
- [LMS](kernel-mini-memory-lms.md)
- [Shell](kernel-mini-debug-shell.md)
- Appendix
- [Kernel Coding Specification](kernel-mini-appx-code.md)
- [Standard Libraries](kernel-mini-appx-lib.md)
......
......@@ -177,7 +177,7 @@ int main (void) {
// ...
osKernelInitialize(); // Initialize CMSIS-RTOS.
osThreadNew(app_main, NULL, NULL); // Create the main thread of the application.
osThreadNew(app_main, NULL, NULL); // Create the main thread of the application.
osKernelStart(); // Start to execute the thread.
for (;;) {}
}
......@@ -196,14 +196,14 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
#### Available APIs
**Table 1** APIs for process management
**Table 11** APIs for process management
| Header File| API| Description|
| -------- | -------- | -------- |
| \#include <stdlib.h> | void abort(void); | Terminates the thread.|
| \#include <assert.h> | void assert(scalar expression); | Terminates the thread if the assertion is false.|
| \#include <pthread.h> | int pthread_cond_destroy(pthread_cond_t *cond); | Destroys a condition variable.|
| \#include <pthread.h> | int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t \*restrict attr); | Initializes a condition variable.|
| \#include <pthread.h> | int pthread_cond_destroy(pthread_cond_t \*cond); | Destroys a condition variable.|
| \#include <pthread.h> | int pthread_cond_init(pthread_cond_t \*restrict cond, const pthread_condattr_t \*restrict attr); | Initializes a condition variable.|
| \#include <pthread.h> | int pthread_cond_timedwait(pthread_cond_t \*restrict cond, pthread_mutex_t \*restrict mutex, const struct timespec \*restrict abstime); | Waits for the condition.|
| \#include <pthread.h> | int pthread_condattr_init(pthread_condattr_t \*attr); | Initializes the condition variable attribute.|
| \#include <pthread.h> | int pthread_mutex_unlock(pthread_mutex_t \*mutex); | Unlocks a mutex.|
......@@ -212,13 +212,13 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <pthread.h> | pthread_t pthread_self(void); | Obtains the ID of the current thread.|
| \#include <pthread.h> | int pthread_getschedparam(pthread_t thread, int \*policy, struct sched_param \*param); | Obtains the scheduling policy and parameters of a thread.|
| \#include <pthread.h> | int pthread_setschedparam(pthread_t thread, intpolicy, const struct sched_param \*param); | Sets a scheduling policy and parameters for a thread.|
| \#include <pthread.h> | int pthread_mutex_init(pthread_mutex_t \* __restrict m, const pthread_mutexattr_t \*__restrict a); | Initializes a mutex.|
| \#include <pthread.h> | int pthread_mutex_init(pthread_mutex_t *\_restrict m, const pthread_mutexattr_t \*__restrict a); | Initializes a mutex.|
| \#include <pthread.h> | int pthread_mutex_lock(pthread_mutex_t \*m); | Locks a mutex.|
| \#include <pthread.h> | int pthread_mutex_trylock(pthread_mutex_t \*m); | Attempts to lock a mutex.|
| \#include <pthread.h> | int pthread_mutex_destroy(pthread_mutex_t \*m); | Destroys a mutex.|
| \#include <pthread.h> | int pthread_attr_init(pthread_attr_t \*attr); | Initializes a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_destroy(pthread_attr_t \*attr); | Destroys a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_getstacksize(const pthread_attr_t \*attr, size_t \*stacksize); | Obtains the stack size of a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_getstacksize(const pthread_attr*t \*attr, size*t \*stacksize); | Obtains the stack size of a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_setstacksize(pthread_attr_t \*attr, size_t stacksize); | Sets the stack size for a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_getschedparam(const pthread_attr_t \*attr, struct sched_param \*param); | Obtains scheduling parameter attributes of a thread attribute object.|
| \#include <pthread.h> | int pthread_attr_setschedparam(pthread_attr_t \*attr, const struct sched_param \*param); | Sets scheduling parameter attributes for a thread attribute object.|
......@@ -226,9 +226,9 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <pthread.h> | int pthread_setname_np(pthread_t pthread, constchar \*name); | Sets the thread name.|
| \#include <pthread.h> | int pthread_cond_broadcast(pthread_cond_t \*c); | Unblocks all threads that are currently blocked on the condition variable **cond**.|
| \#include <pthread.h> | int pthread_cond_signal(pthread_cond_t \*c); | Unblocks a thread.|
| \#include <pthread.h> | int pthread_cond_wait(pthread_cond_t \*__restrictc, pthread_mutex_t \*__restrict m); | Waits for the condition.|
| \#include <pthread.h> | int pthread_cond_wait(pthread_cond_t *\__restrictc, pthread_mutex_t \*__restrict m); | Waits for the condition.|
**Table 2** APIs for file system management
**Table 12** APIs for file system management
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -250,7 +250,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <sys/stat.h> | int fstat(int fd, struct stat \*buf); | Obtains file status.|
| \#include <sys/statfs.h> | int statfs(const char \*path, struct statfs \*buf); | Obtains the file system information for a file in a specified path.|
**Table 3** APIs for time management
**Table 13** APIs for time management
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -265,19 +265,19 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <unistd.h> | int usleep(useconds_t usec); | Goes to hibernation, in microseconds.|
| \#include <time.h> | int nanosleep(const struct timespec \*tspec1, structtimespec \*tspec2); | Suspends the current thread till the specified time.|
| \#include <time.h> | int clock_gettime(clockid_t id, struct timespec \*tspec); | Obtains the clock time.|
| \#include <time.h> | int timer_create(clockid_t id, struct sigevent \*__restrict evp, timer_t \*__restrict t); | Creates a timer for a thread.|
| \#include <time.h> | int timer_create(clockid_t id, struct sigevent *\__restrict evp, timer_t \*__restrict t); | Creates a timer for a thread.|
| \#include <time.h> | int timer_delete(timer_t t); | Deletes the timer for a thread.|
| \#include <time.h> | int timer_settime(timer_t t, int flags, const structitimerspec \*__restrict val, struct itimerspec \*__restrict old); | Sets a timer for a thread.|
| \#include <time.h> | int timer_settime(timer_t t, int flags, const struct itimerspec *\__restrict val, struct itimerspec \*_restrict old); | Sets a timer for a thread.|
| \#include <time.h> | time_t time (time_t \*t); | Obtains the time.|
| \#include <time.h> | char \*strptime(const char \*s, const char \*format, struct tm \*tm); | Converts the time string into the time **tm** structure.|
**Table 4** APIs for util
**Table 14** APIs for util
| Header File| API| Description|
| -------- | -------- | -------- |
| \#include <stdlib.h> | int atoi(const char \*nptr); | Converts the string pointed to by **nptr** into an integer (**int** type).|
| \#include <stdlib.h> | long atol(const char \*nptr); | Converts the string pointed to by **nptr** into a long Integer (long type).|
| \#include <stdlib.h> | long long atoll(const char \*nptr); | Converts the string pointed to by **nptr** into a long long Integer (long long type).|
| \#include <stdlib.h> | int atoi(const char \*nptr); | Converts a string into an integer (**int** type).|
| \#include <stdlib.h> | long atol(const char \*nptr); | Converts the string into a long Integer (**long** type).|
| \#include <stdlib.h> | long long atoll(const char \*nptr); | Converts a string into a long longer integer (**long long** type).|
| \#include <ctype.h> | int isalnum(int c); | Checks whether the passed character is alphanumeric.|
| \#include <ctype.h> | int isascii(int c); | Checks whether the passed character is an ASCII character.|
| \#include <ctype.h> | int isdigit(int c); | Checks whether the passed character is a digit.|
......@@ -302,17 +302,17 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <strings.h> | int strncasecmp(const char \*s1, const char \*s2, size_t n); | Compares the bytes of the specified length in two strings, ignoring case.|
| \#include <strings.h> | int strcasecmp(const char \*s1, const char \*s2); | Compares two strings, ignoring case.|
| \#include <string.h> | int strncmp(const char \*s1, const char \*s2, size_t n); | Compares the bytes of the specified length in two strings.|
| \#include <string.h> | char \*strrchr(const char \*s, int c); | Searches for the last occurrence of a character in a string.|
| \#include <string.h> | char \*strrchr(const char \*s, int c); | Searches for a character in a string.|
| \#include <string.h> | char \*strstr(const char \*haystack, const char \*needle); | Searches for the specified substring in a string.|
| \#include <stdlib.h> | long int strtol(const char \*nptr, char \*\*endptr, int base); | Converts the string pointed to by **nptr** into a **long int** value according to the given **base**.|
| \#include <stdlib.h> | unsigned long int strtoul(const char \*nptr, char\*\*endptr, int base); | Converts the string pointed to by **nptr** into an unsigned long integer.|
| \#include <stdlib.h> | unsigned long long int strtoull(const char \*nptr,char \*\*endptr, int base); | Converts the string pointed to by **nptr** into an unsigned long long integer.|
| \#include <stdlib.h> | unsigned long int strtoul(const char \*nptr, char\*\*endptr, int base); | Converts a string into an unsigned long integer.|
| \#include <stdlib.h> | unsigned long long int strtoull(const char \*nptr,char \*\*endptr,int base); | Converts a string into an unsigned long long integer.|
| \#include <regex.h> | int regcomp(regex_t \*preg, const char \*regex,int cflags); | Compiles a regular expression.|
| \#include <regex.h> | int regexec(const regex_t \*preg, const char \*string, size_t nmatch, regmatch_t pmatch[], int eflags); | Executes the compiled regular expression.|
| \#include <regex.h> | void regfree(regex_t \*preg); | Releases the regular expression.|
| \#include <string.h> | char \*strerror(int errnum); | Obtains an error message string of the specified error code.|
**Table 5** APIs for math operations
**Table 15** APIs for math operations
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -322,7 +322,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <math.h> | double round(double x); | Rounds off the value from zero to the nearest integer.|
| \#include <math.h> | double sqrt(double x); | Obtains the square root of **x**.|
**Table 6** APIs for I/O operations
**Table 16** APIs for I/O operations
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -335,16 +335,16 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <stdio.h> | int fileno(FILE \*stream); | Obtains the file descriptor for a stream.|
| \#include <stdio.h> | FILE \*fopen(const char \*path, const char \*mode); | Opens a stream.|
| \#include <stdio.h> | int fputs(const char \*s, FILE \*stream); | Writes a line to the specified stream.|
| \#include <stdio.h> | size_t fread(void \*ptr, size_t size, size_t nmemb,FILE \*stream); | Reads a stream.|
| \#include <stdio.h> | size_t fread(void \*ptr, size_t size, size_t nmemb, FILE \*stream); | Reads a stream.|
| \#include <stdio.h> | int fseek(FILE \*stream, long offset, int whence); | Sets the position of the stream pointer.|
| \#include <stdio.h> | long ftell(FILE \*stream); | Obtains the position of the stream pointer.|
| \#include <stdio.h> | size_t fwrite(const void \*ptr, size_t size, size_tnmemb,FILE \*stream); | Writes data to a stream.|
| \#include <stdio.h> | size_t fwrite(const void \*ptr, size_t size, size_tnmemb, FILE \*stream); | Writes data to a stream.|
| \#include <stdio.h> | void perror(const char \*s); | Prints system error information.|
| \#include <stdio.h> | void rewind(FILE \*stream); | Sets the position to the beginning of the file of the specified stream.|
| \#include <unistd.h> | ssize_t write(int fd, const void \*buf, size_t size); | Writes data a file.|
| \#include <unistd.h> | ssize_t read(int fd, void \*buf, size_t size); | Reads data from a file.|
**Table 7** APIs for network
**Table 17** APIs for network
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -363,7 +363,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <sys/socket.h> | ssize_t sendto(int sockfd, const void \*buf, size_t len, intflags,const struct sockaddr \*dest_addr, socklen_t addrlen); | Sends a message on a socket.|
| \#include <sys/socket.h> | int setsockopt(int sockfd, int level, int optname,constvoid \*optval, socklen_t optlen); | Sets options associated with a socket.|
**Table 8** APIs for memory management
**Table 18** APIs for memory management
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -374,7 +374,7 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <stdlib.h> | void \*malloc(size_t size); | Dynamically allocates memory blocks.|
| \#include <stdlib.h> | void free(void \*ptr); | Release the memory space pointed to by **ptr**.|
**Table 9** APIs for IPC
**Table 19** APIs for IPC
| Header File| API| Description|
| -------- | -------- | -------- |
......@@ -386,11 +386,11 @@ The OpenHarmony kernel uses the **musl libc** library and self-developed APIs an
| \#include <mqueue.h> | mqd_t mq_open(const char \*mqName, int openFlag, ...); | Opens an existing message queue with the specified name or creates a message queue.|
| \#include <mqueue.h> | int mq_close(mqd_t personal); | Closes a message queue with the specified descriptor.|
| \#include <mqueue.h> | int mq_unlink(const char \*mqName); | Deletes the message queue of the specified name.|
| \#include <mqueue.h> | int mq_send(mqd_t personal, const char \*msg,size_t msgLen, unsigned int msgPrio); | Puts a message with the specified content and length into a message queue.|
| \#include <mqueue.h> | ssize_t mq_receive(mqd_t personal, char \*msg,size_t msgLen, unsigned int \*msgPrio); | Deletes the oldest message from a message queue and puts it in the buffer pointed to by **msg_ptr**.|
| \#include <mqueue.h> | int mq_send(mqd_t personal, const char \*msg, size_t msgLen, unsigned int msgPrio); | Puts a message with the specified content and length into a message queue.|
| \#include <mqueue.h> | ssize_t mq_receive(mqd_t personal, char \*msg, size_t msgLen, unsigned int \*msgPrio); | Deletes the oldest message from a message queue and puts it in the buffer pointed to by **msg_ptr**.|
| \#include <mqueue.h> | int mq_timedsend(mqd_t personal, const char\*msg, size_t msgLen, unsigned int msgPrio, const struct timespec \*absTimeout) | Puts a message with the specified content and length into a message queue at the specified time.|
| \#include <mqueue.h> | ssize_t mq_timedreceive(mqd_t personal, char\*msg, size_t msgLen, unsigned int \*msgPrio, const struct timespec \*absTimeout); | Obtains a message with the specified content and length from a message queue.|
| \#include <mqueue.h> | int mq_setattr(mqd_t mqdes, const struct mq_attr \*__restrict newattr, struct mq_attr \*__restrict oldattr); | Sets the message queue attributes specified by the descriptor.|
| \#include <mqueue.h> | int mq_setattr(mqd_t mqdes, const struct mq_attr \*\_\_restrict newattr, struct mq_attr *\__restrict oldattr); | Sets the message queue attributes specified by the descriptor.|
| \#include <libc.h> | const char \*libc_get_version_string(void); | Obtains the libc version string.|
| \#include <libc.h> | int libc_get_version(void); | Obtains the libc version.|
......@@ -459,6 +459,8 @@ Example:
Creates a thread, transfers the information in the parent thread to the child thread, and prints the transferred information and the thread ID in the child thread.
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **DemoForTest** function is called in **TestTaskEntry**.
```
#include <stdio.h>
......
# Shell
The shell provided by the OpenHarmony kernel supports basic debugging functions and provides commands related to the system, files, and network. It also supports commands customized based on service requirements.
The shell function is used for debugging only. Currently, it does not support the functions such as tab completion and undo with a key.
Some commands can be used only after the corresponding options are enabled by using **make menuconfig**.
## Common Shell Commands
### cat
Displays the content of a text file. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
cat [FILE]
#### Parameters
| Parameter| Description | Value Range |
| ---- | ---------- | -------------- |
| FILE | File path.| An existing file.|
### cd
Changes the current directory. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
cd [path]
#### Parameters
| Parameter| Description | Value Range |
| ---- | ---------- | -------------- |
| path | File path.| Path of the new directory.|
### cp
Copies a file. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
cp [SOURCEFILE] [DESTFILE]
#### Parameters
| Parameter | Description | Value Range |
| ---------- | -------------- | ----------------------------------------- |
| SOURCEFILE | Path of the file to copy. | Currently, only files are supported. Directories are not supported. The file cannot be empty.|
| DESTFILE | Path of the file created.| Directory and file names are supported. The directory must exist. |
### date
Queries the system date and time.
#### Format
date
#### Parameters
None.
### free
Displays the memory usage of the system.
#### Format
free [ -k | -m ]
#### Parameters
| Parameter| Description | Value Range|
| ---- | ----------------- | -------- |
| -k | Display the memory usage in KiB.| N/A |
| -m | Display the memory usage in MiB.| N/A |
### help
Displays all commands in this operating system.
#### Format
help
#### Parameters
None.
### ifconfig
Displays the IP address, network mask, gateway, and MAC address of a network adapter. This command can be used only after **LWIP_SHELLCMD_ENABLE** is enabled.
#### Format
ifconfig
#### Parameters
None.
### ls
Displays the content of a directory. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
ls [DIRECTORY]
#### Parameters
| Parameter | Description | Value Range |
| --------- | ---------- | ------------------------------------------------------------ |
| DIRECTORY | Path of the directory.| If **DIRECTORY** is not specified, the content of the current directory is displayed.<br>If **DIRECTORY** is a valid directory, the content of the specified directory is displayed.<br>Currently, LiteOS-M does not support the root directory /.|
### memusage
Displays the memory waterline.
#### Format
memusage [-k/-m]
#### Parameters
| Parameter| Description | Value Range|
| ---- | ----------------- | -------- |
| -k | Display the memory usage in KiB.| N/A |
| -m | Display the memory usage in MiB.| N/A |
### mkdir
Creates a directory. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
mkdir [DIRECTORY]
#### Parameters
| Parameter | Description | Value Range |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | Path of the directory.| The value of **DIRECTORY** can be an absolute path or a relative path.|
### ping
Checks whether the network is connected. This command can be used only after **LWIP_SHELLCMD_ENABLE** is enabled.
#### Format
ping [ip]
#### Parameters
| Parameter| Description | Value Range|
| ---- | ------------------------------ | -------- |
| ip | IPv4 address of the network to test.| N/A |
### pwd
Displays the current path. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
pwd
### rm
Deletes a file or folder. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
rm [FILE] or rm [-r/-R] [FILE]
#### Parameters
| Parameter | Description | Value Range |
| ----- | ------------------------------- | -------------------------------- |
| FILE | File or folder name.| The value of **FILE** can be an absolute path or a relative path.|
| -r/-R | If **FILE** is a folder, -r/-R needs to be set. | N/A |
### rmdir
Deletes a folder. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
rmdir [DIRECTORY]
#### Parameters
| Parameter | Description | Value Range |
| --------- | ---------- | ------------------------------------- |
| DIRECTORY | Path of the directory.| The value of **DIRECTORY** can be an absolute path or a relative path.|
### task
Displays the status of each task.
#### Format
task
The displayed information includes the task No., priority, status, stack information, signal, event, CPU usage, and task name.
### touch
Creates a file. This command can be used only after **LOSCFG_FS_VFS** is enabled.
#### Format
touch [FILE]
#### Parameters
| Parameter| Description| Value Range |
| ---- | -------- | -------------------------------- |
| FILE | File name.| The value of **FILE** can be an absolute path or a relative path.|
### stack
Displays the stack information of a task. This command can be used only after **LOSCFG_DEBUG_TOOLS** is enabled. Enabling this function affects the performance.
#### Format
stack [ID]
#### Parameters
| Parameter| Description| Value Range |
| ---- | -------- | ------------------------ |
| ID | Task ID.| The task corresponding to the task ID must exist.|
### hwi
Queries the interrupt usage. This command can be used only after **LOSCFG_DEBUG_TOOLS** is enabled. Enabling this function affects the performance.
#### Format
hwi
### st
Queries scheduling information. This command can be used only afterf **LOSCFG_DEBUG_TOOLS** is enabled. Enabling this function affects the performance.
#### Format
st -s | st -e
#### Parameters
| Parameter| Description | Value Range|
| ---- | ---------------------- | -------- |
| -s | Start to record scheduling information. | N/A |
| -e | Stop recording and print scheduling information.| N/A |
# CPUP
## Basic Concepts
The central processing unit percent \(CPUP\) includes the system CPUP and task CPUP.
The central processing unit percent (CPUP) includes the system CPUP and task CPUP.
The 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**
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.
The 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 CPUP ranges from 0 to 100, in percentage. The value **100** indicates that the system runs with full load.
With the system CPUP, you can determine whether the current system load exceeds the designed specifications.
**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 task CPUP ranges from 0 to 100, in percentage. The value **100** indicates that the task is being executed for the given period of time.
With the CPUP of each task, you can determine whether the CPU usage of each task meets expectations of the design.
**Interrupt CPUP**
In addition, you can enable the interrupt usage statistics function after the CPUP function is enabled.
Interrupt CPUP indicates the CPU usage of a single interrupt out of the total interrupt duration. The interrupt CPUP ranges from 0 to 100. The value **100** indicates that only the interrupt is triggered within a period of time.
## Working Principles
The OpenHarmony LiteOS-M CPUP records the system CPU usage on a task basis. When task switching occurs, the task start time and task switch-out or exit time are recorded. Each time when a task exits, the system accumulates the CPU time used by the task.
You can configure this function in **target\_config.h**.
You can configure this function in **target_config.h**.
The OpenHarmony LiteOS-M provides the following types of CPUP information:
- System CPUP
- Task CPUP
- System CPUP
- Task CPUP
In addition, the system provides the capability of querying the interrupt CPUP (the CPUP and timer must be enabled).
The CPUP is calculated as follows:
......@@ -29,156 +43,148 @@ System CPUP = Total running time of all tasks except idle tasks/Total running ti
Task CPUP = Total running time of the task/Total running time of the system
## Available APIs<a name="section158501652121514"></a>
**Table 1** Functions
<a name="table18293928155615"></a>
<table><thead align="left"><tr id="row129362875613"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p19444103765618"><a name="p19444103765618"></a><a name="p19444103765618"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p944473716569"><a name="p944473716569"></a><a name="p944473716569"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p144445378565"><a name="p144445378565"></a><a name="p144445378565"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row1143613475615"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p942993405610"><a name="p942993405610"></a><a name="p942993405610"></a>Obtaining the system CPU usage</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p242973419563"><a name="p242973419563"></a><a name="p242973419563"></a>LOS_SysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p7429163416565"><a name="p7429163416565"></a><a name="p7429163416565"></a>Obtains the current system CPUP.</p>
</td>
</tr>
<tr id="row15436163435611"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p20429183410563"><a name="p20429183410563"></a><a name="p20429183410563"></a>LOS_HistorySysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p542953465617"><a name="p542953465617"></a><a name="p542953465617"></a>Obtains the historical CPUP of the system.</p>
</td>
</tr>
<tr id="row143610342562"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p174295347568"><a name="p174295347568"></a><a name="p174295347568"></a>Obtaining the task CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p124291734155614"><a name="p124291734155614"></a><a name="p124291734155614"></a>LOS_TaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1042963410568"><a name="p1042963410568"></a><a name="p1042963410568"></a>Obtains the CPUP of a specified task.</p>
</td>
</tr>
<tr id="row12436143414561"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p6429834185613"><a name="p6429834185613"></a><a name="p6429834185613"></a>LOS_HistoryTaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p74302034175614"><a name="p74302034175614"></a><a name="p74302034175614"></a>Obtains the historical CPUP of a specified task.</p>
</td>
</tr>
<tr id="row2435834135618"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p843073420563"><a name="p843073420563"></a><a name="p843073420563"></a>LOS_AllCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p4430134185614"><a name="p4430134185614"></a><a name="p4430134185614"></a>Obtains the CPUP of all tasks.</p>
</td>
</tr>
<tr id="row15435934155618"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1543033435615"><a name="p1543033435615"></a><a name="p1543033435615"></a>Outputting the task CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1643016342562"><a name="p1643016342562"></a><a name="p1643016342562"></a>LOS_CpupUsageMonitor</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p84301234115617"><a name="p84301234115617"></a><a name="p84301234115617"></a>Outputs the historical CPUP of a task.</p>
</td>
</tr>
</tbody>
</table>
Interrupt CPUP = Running time of a single interrupt/Total running time of all interrupts
## Available APIs
**Table 1** APIs for CPUP
| Category| Description|
| -------- | -------- |
| Obtaining the system CPUP| **LOS_SysCpuUsage**: obtains the current system CPUP.<br>**LOS_HistorySysCpuUsage**: obtains the historical CPUP of the system.|
| Obtaining the task CPUP| **LOS_TaskCpuUsage**: obtains the CPUP of a task.<br>**LOS_HistoryTaskCpuUsage**: obtains the historical CPUP of a task.<br>**LOS_AllTaskCpuUsage**: obtains the CPUP of all tasks.|
| Outputting the task CPUP| **LOS_CpupUsageMonitor**: outputs the historical CPUP of a task.|
| Obtaining the interrupt CPUP| **LOS_GetAllIrqCpuUsage**: obtains the CPUP of all interrupts.|
## How to Develop
In the **kernel/liteos_m** directory, run the **make menuconfig** command and choose **Kernel > Enable Cpup** to enable CPUP.
Choose **Enable Cpup include irq** to enable interrupt CPUP.
The typical CPUP development process is as follows:
1. Call **LOS\_SysCpuUsage** to obtain the system CPUP.
2. Call **LOS\_HistorySysCpuUsage** to obtain the historical CPUP of the system.
3. Call **LOS\_TaskCpuUsage** to obtain the CPUP of a specified task.
- If the task has been created, disable interrupt, obtain the CPUP, and then enable interrupt.
- If the task is not created, return an error code.
1. Call **LOS_SysCpuUsage** to obtain the system CPUP.
2. Call **LOS_HistorySysCpuUsage** to obtain the historical CPUP of the system.
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.
3. Call **LOS_TaskCpuUsage** to obtain the CPUP of a task.
- If the task has been created, disable interrupt, obtain the CPUP, and then enable interrupt.
- If the task is not created, return an error code.
5. Call **LOS\_AllCpuUsage** to obtain the CPUP of all tasks.
- 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 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_AllCpuUsage** to obtain the CPUP of all tasks.
- If 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
### Example Description
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.
3. Obtain the historical system CPUP in different modes.
4. Obtain the CPUP of the created task.
5. Obtain the CPUP of the created task in different modes.
### Sample Code
Prerequisites
**Prerequisites**
In **target\_config.h**, the **LOSCFG\_BASE\_CORE\_CPUP** parameter is enabled.
CPUP is enabled.<br>To enable CPUP, run **make menuconfig** in the **kernel/liteos_m** directory and choose **Kernel->Enable Cpup** to enable CPUP.
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleCpup** function is called in **TestTaskEntry**.
```
#include "los_task.h"
#include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
#include "los_cpup.h"
#define TEST_TASK_PRIO 5
#define TASK_DELAY_TIME 100
VOID CpupTask(VOID)
{
printf("entry cpup test example\n");
while(1) {
usleep(100);
}
usleep(TASK_DELAY_TIME);
usleep(TASK_DELAY_TIME);
printf("exit cpup test example\n");
}
UINT32 ItCpupTest(VOID)
{
UINT32 ExampleCpup(VOID)
{
UINT32 ret;
UINT32 cpupUse;
UINT32 taskID;
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;
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)CpupTask;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
cpupTestTask.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &cpupTestTask);
if(ret != LOS_OK) {
printf("cpupTestTask create failed .\n");
return LOS_NOK;
}
usleep(100);
usleep(TASK_DELAY_TIME);
/* Obtain the current CPUP of the system. */
/* Obtain the current system CPUP. */
cpupUse = LOS_SysCpuUsage();
printf("the current system cpu usage is: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
/* Obtain the CPUP of the specified task (cpupTestTask in this example).*/
printf("the history system CPUP in all time: %u.%u\n",
/* Obtain the historical CPUP of the system. */
cpupUse = LOS_HistorySysCpuUsage(CPUP_LESS_THAN_1S);
printf("the history system cpu usage in all time: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_TaskCpuUsage(g_cpuTestTaskID);
/* Obtain the CPUP of the specified historical task (cpupTestTask in this example) since the system startup. */
/* Obtain the CPUP of a specified task. */
cpupUse = LOS_TaskCpuUsage(taskID);
printf("cpu usage of the cpupTestTask:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* Obtain the CPUP of a specified task since the system starts. */
cpupUse = LOS_HistoryTaskCpuUsage(taskID, CPUP_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;
taskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
}
```
### Verification
The development is successful if the return result is as follows:
The development is successful if the return result is as follows:
```
entry cpup test example
the current system cpu usage is : 1.5
the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask: TaskID:10 usage: 0.0
cpu usage of the cpupTestTask&nbsp;in all time: TaskID:10 usage: 0.0
entry cpup test example
the current system cpu usage is: 8.2
the history system cpu usage in all time: 8.9
cpu usage of the cpupTestTask:
TaskID: 5
usage: 0.5
cpu usage of the cpupTestTask in all time:
TaskID: 5
usage: 0.5
exit cpup test example
The preceding data may vary depending on the running environment.
```
# File System
# File Systems
The OpenHarmony LiteOS-M kernel supports File Allocation Table file system (FATFS) and LittleFS file systems. Like the OpenHarmony LiteOS-A kernel, the OpenHarmony LiteOS-M kernel provides POSIX over the virtual file system (VFS) to ensure interface consistency. However, the VFS of the LiteOS-M kernel is light due to insufficient resources and does not provide advanced functions (such as pagecache). Therefore, the VFS of the LiteOS-M kernel implements only API standardization and adaptation. The file systems handle specific transactions.
## VFS
The following tables list the APIs supported by the file systems of the LiteOS-M kernel.
### Basic Concepts
**Table 1** File management operations
The Virtual File System (VFS) is not a real file system. It is an abstract layer on top of a heterogeneous file system and provides you with a unified Unix-like interface for file operations. Different types of file systems use different file operation interfaces. If there are multiple types of file systems in a system, different and non-standard interfaces are required for accessing these file systems. The VFS is introduced as an abstract layer to shield the differences between these heterogeneous file systems. With the VFS, you do not need to care about the underlying storage medium and file system type.
| API| Description| FATFS | LITTLEFS |
The OpenHarmony LiteOS-M kernel supports the File Allocation Table (FAT) and LittleFS file systems. It provides the Portable Operating System Interface (POSIX) over the VFS to ensure interface consistency. However, the VFS of the LiteOS-M kernel is light and does not provide advanced functions (such as pagecache) due to insufficient resources. Therefore, the VFS of the LiteOS-M kernel implements only API standardization and adaptation. The file systems handle specific transactions. The following tables describe the APIs supported by the file systems of the LiteOS-M kernel.
### Available APIs
**Table 1** APIs for file operations
| API| Description| FAT | LittleFS |
| -------- | -------- | -------- | -------- |
| open | Opens a file.| Supported| Supported|
| close | Closes a file.| Supported| Supported|
| read | Reads the file content.| Supported| Supported|
| write | Writes data to a file.| Supported| Supported|
| lseek | Sets the file offset.| Supported| Supported|
| read | Reads the file content. | Supported | Supported |
| write | Writes data to a file. | Supported | Supported |
| lseek | Sets the file offset. | Supported | Supported |
| stat | Obtains file information based on the file path name.| Supported | Supported |
| unlink | Deletes a file.| Supported| Supported|
| rename | Renames the file.| Supported| Supported|
| fstat | Obtains file information based on the file handle.| Supported| Supported|
| stat | Obtains file information based on the file path name.| Supported| Supported|
| fsync | Saves file updates to a storage device.| Supported| Supported|
| fstat | Obtains file information based on the file handle. | Supported | Supported |
| fsync | Saves a file to a storage device. | Supported | Supported |
**Table 2** Directory management operations
**Table 2** APIs for directory operations
| API| Description| FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- |
......@@ -31,8 +36,7 @@ The following tables list the APIs supported by the file systems of the LiteOS-M
| closedir | Closes a directory.| Supported| Supported|
| rmdir | Deletes a directory.| Supported| Supported|
**Table 3** Partition operations
**Table 3** APIs for partition operations
| API| Description| FATFS | LITTLEFS |
| -------- | -------- | -------- | -------- |
......@@ -41,14 +45,18 @@ The following tables list the APIs supported by the file systems of the LiteOS-M
| umount2 | Forcibly unmounts a partition using the **MNT_FORCE** parameter.| Supported| Not supported|
| statfs | Obtains partition information.| Supported| Not supported|
Interfaces, such as **ioctl** and **fcntl**, are supported by different libraries and are irrelevant to the underlying file system.
## FAT
### Basic Concepts
File Allocation Table (FAT) is a file system developed for personal computers. It consists of the DOS Boot Record (DBR) region, FAT region, and Data region. Each entry in the FAT region records information about the corresponding cluster in the storage device. The cluster information includes whether the cluster is used, number of the next cluster of the file, whether the file ends with the cluster. The FAT file system supports multiple formats, such as FAT12, FAT16, and FAT32. The numbers 12, 16, and 32 indicate the number of bits per cluster within the FAT, respectively. The FAT file system supports multiple media, especially removable media (such as USB flash drives, SD cards, and removable hard drives). The FAT file system ensures good compatibility between embedded devices and desktop systems (such as Windows and Linux) and facilitates file management.
As a file system designed for personal computers, the FAT file system consists of the DOS Boot Record (DBR) region, FAT region, and Data region. Each entry in the FAT region records information about the corresponding cluster in the storage device. The cluster information includes whether the cluster is used, number of the next cluster of the file, whether the file ends with the cluster.
The FAT file system supports a variety of formats, including FAT12, FAT16, and FAT32. The numbers 12, 16, and 32 indicate the number of bits per cluster within the FAT, respectively. The FAT file system also supports diversified storage media, especially removable media (such as USB flash drives, SD cards, and removable hard drives). It features good compatibility between embedded devices and desktop systems (such as Windows and Linux) and facilitates file management.
The OpenHarmony kernel supports FAT12, FAT16, and FAT32 file systems. These file systems require a tiny amount of code to implement, use less resources, support a variety of physical media, and are tailorable and compatible with Windows and Linux systems. They also support identification of multiple devices and partitions. The kernel supports multiple partitions on hard drives and allows creation of the FAT file system on the primary partition and logical partition.
The OpenHarmony kernel supports FAT12, FAT16, and FAT32 file systems. These file systems require a tiny amount of code to implement, use less resources, support a variety of physical media, and are tailorable and compatible with Windows and Linux systems. They also support identification of multiple devices and partitions. The kernel supports multiple partitions on hard drives and allows creation of the FAT file system on the primary and logical partitions.
### Development Guidelines
......@@ -56,11 +64,13 @@ The OpenHarmony kernel supports FAT12, FAT16, and FAT32 file systems. These file
#### Driver Adaptation
The use of the FAT file system requires support from the underlying MultiMediaCard (MMC) drivers. To run FatFS on a board with an MMC storage device, you must:
The use of a FAT file system requires support from the underlying MultiMediaCard (MMC) driver. Before using a FAT file system on a board with an MMC, you must perform the following operations:
1. Implement the **disk_status**, **disk_initialize**, **disk_read**, **disk_write**, and **disk_ioctl** APIs to adapt to the embedded MMC (eMMC) driver on the board.
1. Implement the **disk_status**, **disk_initialize**, **disk_read**, **disk_write**, and **disk_ioctl** APIs to adapt to the embedded MMC (eMMC) drivers on the board.
2. Add the **fs_config.h** file with information such as **FS_MAX_SS** (maximum sector size of the storage device) and **FF_VOLUME_STRS** (partition names) configured.
2. Add the **fs_config.h** file with information such as **FS_MAX_SS** (maximum sector size of the storage device) and **FF_VOLUME_STRS** (partition names) configured. The following is an example:
The following is an example:
```
......@@ -69,29 +79,115 @@ The use of the FAT file system requires support from the underlying MultiMediaCa
#define FAT_MAX_OPEN_FILES 50
```
#### Mounting Partitions
Before using a FAT file system on a device, you need to initialize the flash drive and partition the device storage.
API for partitioning the storage:
**int LOS_DiskPartition(const char \*dev, const char \*fsType, int \*lengthArray, int \*addrArray, int partNum);**
- **dev**: pointer to the device name, for example, **spinorblk0**.
- **fsType**: pointer to the file system type, which is **vfat** for the FAT file system.
- **lengthArray**: pointer to a list of partition lengths (in percentage for a FAT file system) of the device.
- **addrArray**: pointer to a list of partition start addresses of the device.
- **partNum**: number of partitions.
API for formatting a partition:
**int LOS_PartitionFormat(const char \*partName, char \*fsType, void \*data);**
- **partName**: pointer to the partition name, in the *Device_name*+**p**+*Partition_ number* format. For example, **spinorblk0p0**.
- **fsType**: pointer to the file system type, which is **vfat** for the FAT file system.
- **data**: pointer to the private data that passes in **(VOID \*) formatType**, for example, **FMT_FAT** or **FMT_FAT32**.
API for mounting a partition:
**int mount(const char \*source, const char \*target, const char \*filesystemtype, unsigned long mountflags, const void \*data);**
- **source**: pointer to the partition name, in the *Device_name*+**p**+*Partition_ number* format. For example, **spinorblk0p0**.
- **target**: pointer to the target path to mount.
- **filesystemtype**: pointer to the file system type, which is **vfat** for the FAT file system.
- **mountflags**: parameters used for the mount operation.
- **data**: pointer to the private data that passes in **(VOID \*) formatType**, for example, **FMT_FAT** or **FMT_FAT32**.
The sample code is implemented in **./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c** and can be directly used on the Quick EMUlator (QEMU) that uses the LiteOS-M kernel. You can modify the code based on the hardware you use.
#include "fatfs_conf.h"
#include "fs_config.h"
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 FatfsLowLevelInit()
{
INT32 ret;
INT32 i;
UINT32 addr;
int data = FMT_FAT32;
const char * const pathName[FF_VOLUMES] = {FF_VOLUME_STRS};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* Function for obtaining the partition lengths and start addresses. Modify it as required. */
INT32 lengthArray[FF_VOLUMES] = {25, 25, 25, 25};
INT32 addrArray[FF_VOLUMES];
/* Set the address and length for each partition. */
for (i = 0; i < FF_VOLUMES; i++) {
addr = halPartitionsInfo[FLASH_PARTITION_DATA1].partitionStartAddr + i * 0x10000;
addrArray[i] = addr;
FlashInfoInit(i, addr);
}
/* Set partition information. */
SetupDefaultVolToPartTable();
ret = LOS_DiskPartition("spinorblk0", "vfat", lengthArray, addrArray, FF_VOLUMES);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = LOS_PartitionFormat("spinorblk0p0", "vfat", &data);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount("spinorblk0p0", "/system", "vfat", 0, &data);
printf("%s: mount fs on '%s' %s\n", __func__, pathName[0], (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
#### How to Develop
Note the following when managing FatFS files and directories:
Observe the following when managing files and directories in a FAT file system:
- A file cannot exceed 4 GB.
- **FAT_MAX_OPEN_FILES** specifies the maximum number files you can open at a time, and **FAT_MAX_OPEN_DIRS** specifies the maximum number of folders you can open at a time.
- Root directory management is not supported. File and directory names start with the partition name. For example, **user/testfile** indicates the file or directory **testfile** in the **user** partition.
- To open a file multiple times, use **O_RDONLY** (read-only mode). **O_RDWR** or **O_WRONLY** (writable mode) can open a file only once.
- Root directory management is not supported. File and directory names start with the partition name. For example, **user/testfile** indicates the **testfile** file or directory in the **user** partition.
- To open a file multiple times at the same time, use **O_RDONLY** (read-only mode). **O_RDWR** or **O_WRONLY** (writable mode) can open a file only once at a time.
- The read and write pointers are not separated. If a file is open in **O_APPEND** mode, the read pointer is also at the end of the file. If you want to read the file from the beginning, you must manually set the position of the read pointer.
- File and directory permission management is not supported.
- The **stat** and **fstat** APIs do not support query of the modification time, creation time, and last access time. The Microsoft FAT protocol does not support time before A.D. 1980.
Note the following when mounting and unmounting FatFS partitions:
- Partitions can be mounted with the read-only attribute. When the input parameter of the **mount** function is **MS_RDONLY**, all APIs with the write attribute, such as **write**, **mkdir**, **unlink**, and **open** with **non-O_RDONLY** attributes, will be rejected.
- You can use the **MS_REMOUNT** flag with **mount** to modify the permission for a mounted partition.
Observe the following when managing files and directories in a FAT file system:
- Partitions can be mounted with the read-only attribute. If the input parameter of **mount()** is **MS_RDONLY**, all APIs with the write attribute, such as **write()**, **mkdir()**, **unlink()**, and **open()** with **non-O_RDONLY** attributes, will be rejected.
- You can use the **MS_REMOUNT** flag in **mount()** to modify the permissions for a mounted partition.
- Before unmounting a partition, ensure that all directories and files in the partition are closed.
- You can use **umount2** with the **MNT_FORCE** parameter to forcibly close all files and folders and unmount the partition. However, this may cause data loss. Therefore, exercise caution when running **umount2**.
- You can use **umount2** with the **MNT_FORCE** parameter to forcibly close all files and folders and unmount the partition. However, this may cause data loss. Therefore, exercise caution when using **umount2**.
You can use **fatfs_fdisk()** and **fatfs_format()** to re-partition the device storage and format the partitions. Observe the following:
The FAT file system supports re-partitioning and formatting of storage devices using **fatfs_fdisk** and **fatfs_format**.
- If a partition is mounted before being formatted using **fatfs_format**, you must close all directories and files in the partition and unmount the partition first.
- Before calling **fatfs_fdisk**, ensure that all partitions in the device are unmounted.
- Before using **fatfs_format()**, ensure that the target partition is unmounted and all directories and files in the partition are closed.
- Before using **fatfs_fdisk**, ensure that all partitions in the device are unmounted.
- Using **fatfs_fdisk** and **fatfs_format** may cause data loss. Exercise caution when using them.
......@@ -102,9 +198,9 @@ The FAT file system supports re-partitioning and formatting of storage devices u
This example implements the following:
1. Create the **user/test** directory.
1. Create a **system/test** directory.
2. Create the **file.txt** file in the **user/test** directory.
2. Create a **file.txt** file in the **system/test** directory.
3. Write **Hello OpenHarmony!** at the beginning of the file.
......@@ -123,99 +219,103 @@ This example implements the following:
#### Sample Code
**Prerequisites**
**Prerequisites**
The MMC device partition is mounted to the **user** directory.
- The **system** partition is mounted to the QEMU.
- FAT is enabled.
1. In the **kernel/liteos_m** directory, run the **make menuconfig** command and choose **FileSystem->Enable FS VFS** to enable VFS.
2. Select **Enable FAT** to enable the FAT file system.
The sample code is as follows:
```
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
**Implementation**
#define LOS_OK 0
#define LOS_NOK -1
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleFatfs** function is called in **TestTaskEntry**.
int FatfsTest(void)
{
```
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "system" /* Set the test root directory. */
VOID ExampleFatfs(VOID)
{
int ret;
int fd = -1;
int fd;
ssize_t len;
off_t off;
char dirName[20] = "user/test";
char fileName[20] = "user/test/file.txt";
char writeBuf[20] = "Hello OpenHarmony!";
char readBuf[20] = {0};
char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[BUF_SIZE] = {0};
/* Create the user/test directory. */
/* Create a test directory. */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return LOS_NOK;
return;
}
/* Create a readable and writable file named file.txt in the user/test/ directory. */
/* Create a file that is readable and writable. */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return LOS_NOK;
return;
}
/* Write the content from writeBuf to the file. */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return LOS_NOK;
return;
}
/* Save the file to a storage device. */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return LOS_NOK;
return;
}
/* Move the read/write pointer to the beginning of the file. */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return LOS_NOK;
return;
}
/* Read the file content with the length of readBuf to readBuf. */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return LOS_NOK;
return;
}
printf("%s\n", readBuf);
/* Close the file. */
/* Close the test file. */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return LOS_NOK;
return;
}
/* Delete file.txt from the user/test directory. */
/* Delete the test file. */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return LOS_NOK;
return;
}
/* Delete the user/test directory. */
/* Delete the test directory. */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return LOS_NOK;
return;
}
return LOS_OK;
}
return;
}
```
......@@ -232,102 +332,219 @@ Hello OpenHarmony!
### Basic Concepts
LittleFS is a small file system designed for flash. By combining the log-structured file system and the copy-on-write (COW) file system, LittleFS stores metadata in log structure and data in the COW structure. This special storage empowers LittleFS high power-loss resilience. LittleFS uses the statistical wear leveling algorithm when allocating COW data blocks, effectively prolonging the service life of flash devices. LittleFS is designed for small-sized devices with limited resources, such as ROM and RAM. All RAM resources are allocated through a buffer with the fixed size (configurable). That is, the RAM usage does not grow with the file system.
LittleFS is a small file system designed for the flash drive. It stores metadata in log structure and data in the copy-on-write (COW) structure. This feature empowers LittleFS high power-loss resilience. LittleFS uses the statistical wear leveling algorithm when allocating COW data blocks, effectively prolonging the service life of flash devices. LittleFS is designed for small-sized devices with limited resources, such as ROM and RAM. All RAM resources are allocated through a buffer with the fixed size (configurable). That is, the RAM usage does not grow with the file system.
LittleFS is a good choice when you look for a flash file system that is power-cut resilient and has wear leveling support on a small device with limited resources.
### Development Guidelines
Before porting LittleFS to a new hardware device, you need to declare **lfs_config**:
Before using a LittleFS to a device, you need to initialize the flash drive and partition the device storage
API for partitioning the storage:
**int LOS_DiskPartition(const char \*dev, const char \*fsType, int \*lengthArray, int \*addrArray, int partNum);**
- **dev**: pointer to the device name.
- **fsType**: pointer to the file system type, which is **littlefs** for LittleFS.
- **lengthArray**: pointer to a list of partition lengths of the device.
- **addrArray**: pointer to a list of partition start addresses of the device.
- **partNum**: number of partitions.
API for formatting a partition:
**int LOS_PartitionFormat(const char \*partName, char \*fsType, void \*data);**
- **partName**: pointer to the partition name.
- **fsType**: pointer to the file system type, which is **littlefs** for LittleFS.
- **data**: pointer to the private data that passes in **void pass (VOID \*) struct fs_cfg**.
API for mounting a partition:
**int mount(const char \*source, const char \*target, const char \*filesystemtype, unsigned long mountflags, const void \*data);**
- **source**: pointer to the partition name.
- **target**: pointer to the target path to mount.
- **filesystemtype**: pointer to the file system type, which is **littlefs** for LittleFS.
- **mountflags**: parameters used for the mount operation.
- **data**: pointer to the private data that passes in **void pass (VOID \*) struct fs_cfg**.
The sample code is implemented in **./device/qemu/arm_mps2_an386/liteos_m/board/fs/fs_init.c** and can be directly used on the QEMU that uses the LiteOS-M kernel. You can modify the code based on the hardware you use.
```
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
.erase = user_provided_block_device_erase,
.sync = user_provided_block_device_sync,
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
#include "los_config.h"
#include "ram_virt_flash.h"
#include "los_fs.h"
struct fs_cfg {
CHAR *mount_point;
struct PartitionCfg partCfg;
};
INT32 LfsLowLevelInit()
{
INT32 ret;
struct fs_cfg fs[LOSCFG_LFS_MAX_MOUNT_SIZE] = {0};
HalLogicPartition *halPartitionsInfo = getPartitionInfo(); /* Function for obtaining the partition lengths and start addresses. You can modify the function to match your development. */
INT32 lengthArray[2];
lengthArray[0]= halPartitionsInfo[FLASH_PARTITION_DATA0].partitionLength;
INT32 addrArray[2];
addrArray[0] = halPartitionsInfo[FLASH_PARTITION_DATA0].partitionStartAddr;
ret = LOS_DiskPartition("flash0", "littlefs", lengthArray, addrArray, 2);
printf("%s: DiskPartition %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
fs[0].mount_point = "/littlefs";
fs[0].partCfg.partNo = 0;
fs[0].partCfg.blockSize = 4096; /* 4096, lfs block size */
fs[0].partCfg.blockCount = 1024; /* 2048, lfs block count */
fs[0].partCfg.readFunc = virt_flash_read; /* Function for reading data from the flash drive. You can modify it to match your development. */
fs[0].partCfg.writeFunc = virt_flash_write; /* Function for writing data to the flash drive. You can modify it to match your development. */
fs[0].partCfg.eraseFunc = virt_flash_erase; /* Function for erasing the flash driver. You can modify it to match your development. */
fs[0].partCfg.readSize = 256; /* 256, lfs read size */
fs[0].partCfg.writeSize = 256; /* 256, lfs prog size */
fs[0].partCfg.cacheSize = 256; /* 256, lfs cache size */
fs[0].partCfg.lookaheadSize = 16; /* 16, lfs lookahead size */
fs[0].partCfg.blockCycles = 1000; /* 1000, lfs block cycles */
ret = LOS_PartitionFormat("flash0", "littlefs", &fs[0].partCfg);
printf("%s: PartitionFormat %s\n", __func__, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
ret = mount(NULL, fs[0].mount_point, "littlefs", 0, &fs[0].partCfg);
printf("%s: mount fs on '%s' %s\n", __func__, fs[0].mount_point, (ret == 0) ? "succeed" : "failed");
if (ret != 0) {
return -1;
}
return 0;
}
```
**.read**, **.prog**, **.erase**, and **.sync** correspond to the read, write, erase, and synchronization APIs at the bottom layer of the hardware platform, respectively.
The **.readFunc**, **.writeFunc**, and **.eraseFunc** functions correspond to **read()**, **write()**, and **erase()** of the underlying hardware platform.
**read_size** indicates the number of bytes read each time. You can set it to a value greater than the physical read unit to improve performance. This value determines the size of the read cache. However, if the value is too large, more memory is consumed.
**readSize** indicates the number of bytes read each time. You can set it to a value greater than the physical read unit to improve performance. This value determines the size of the read cache. However, if the value is too large, more memory is consumed.
**prog_size** indicates the number of bytes written each time. You can set it to a value greater than the physical write unit to improve performance. This value determines the size of the write cache and must be an integral multiple of **read_size**. However, if the value is too large, more memory is consumed.
**writeSize** indicates the number of bytes written each time. You can set it to a value greater than the physical write unit to improve performance. This value determines the size of the write cache and must be an integral multiple of **readSize**. However, if the value is too large, more memory is consumed.
**block_size**: indicates the number of bytes in each erase block. The value can be greater than that of the physical erase unit. However, a smaller value is recommended because each file occupies at least one block. The value must be an integral multiple of **prog_size**.
**blockSize** indicates the number of bytes in each erase block. The value can be greater than that of the physical erase unit. However, a smaller value is recommended because each file occupies at least one block. The value must be an integral multiple of **writeSize**.
**block_count** indicates the number of blocks that can be erased, which depends on the capacity of the block device and the size of the block to be erased (**block_size**).
**blockCount** indicates the number of blocks that can be erased, which depends on the capacity of the block device and the size of the block to be erased (**blockSize**).
### Sample Code
The sample code is as follows:
**Prerequisites**
- **/littlefs** is mounted to the QEMU.
- LittleFS is enabled.
1. In the **kernel/liteos_m** directory, run the **make menuconfig** command and choose **FileSystem->Enable FS VFS** to enable VFS.
2. Select **Enable Little FS** to enable the LittleFS.
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleLittlefs** function is called in **TestTaskEntry**.
```
#include "lfs.h"
#include "stdio.h"
lfs_t lfs;
lfs_file_t file;
const struct lfs_config cfg = {
// block device operations
.read = user_provided_block_device_read,
.prog = user_provided_block_device_prog,
.erase = user_provided_block_device_erase,
.sync = user_provided_block_device_sync,
// block device configuration
.read_size = 16,
.prog_size = 16,
.block_size = 4096,
.block_count = 128,
.cache_size = 16,
.lookahead_size = 16,
.block_cycles = 500,
};
int main(void) {
// mount the filesystem
int err = lfs_mount(&lfs, &cfg);
// reformat if we can't mount the filesystem
// this should only happen on the first boot
if (err) {
lfs_format(&lfs, &cfg);
lfs_mount(&lfs, &cfg);
#include <stdio.h>
#include <string.h>
#include "sys/stat.h"
#include "fcntl.h"
#include "unistd.h"
#define BUF_SIZE 20
#define TEST_ROOT "/littlefs" /* Set the test root directory. */
VOID ExampleLittlefs(VOID)
{
int ret;
int fd;
ssize_t len;
off_t off;
char dirName[BUF_SIZE] = TEST_ROOT"/test";
char fileName[BUF_SIZE] = TEST_ROOT"/test/file.txt";
char writeBuf[BUF_SIZE] = "Hello OpenHarmony!";
char readBuf[BUF_SIZE] = {0};
/* Create a test directory. */
ret = mkdir(dirName, 0777);
if (ret != LOS_OK) {
printf("mkdir failed.\n");
return;
}
// read current count
uint32_t boot_count = 0;
lfs_file_open(&lfs, &file, "boot_count", LFS_O_RDWR | LFS_O_CREAT);
lfs_file_read(&lfs, &file, &boot_count, sizeof(boot_count));
// update boot count
boot_count += 1;
lfs_file_rewind(&lfs, &file);
lfs_file_write(&lfs, &file, &boot_count, sizeof(boot_count));
// remember the storage is not updated until the file is closed successfully
lfs_file_close(&lfs, &file);
// release any resources we were using
lfs_unmount(&lfs);
// print the boot count
printf("boot_count: %d\n", boot_count);
/* Create a file that is readable and writable. */
fd = open(fileName, O_RDWR | O_CREAT, 0777);
if (fd < 0) {
printf("open file failed.\n");
return;
}
/* Write the content from writeBuf to the file. */
len = write(fd, writeBuf, strlen(writeBuf));
if (len != strlen(writeBuf)) {
printf("write file failed.\n");
return;
}
/* Save the file to a storage device. */
ret = fsync(fd);
if (ret != LOS_OK) {
printf("fsync failed.\n");
return;
}
/* Move the read/write pointer to the beginning of the file. */
off = lseek(fd, 0, SEEK_SET);
if (off != 0) {
printf("lseek failed.\n");
return;
}
/* Read the file content with the length of readBuf to readBuf. */
len = read(fd, readBuf, sizeof(readBuf));
if (len != strlen(writeBuf)) {
printf("read file failed.\n");
return;
}
printf("%s\n", readBuf);
/* Close the test file. */
ret = close(fd);
if (ret != LOS_OK) {
printf("close failed.\n");
return;
}
/* Delete the test file. */
ret = unlink(fileName);
if (ret != LOS_OK) {
printf("unlink failed.\n");
return;
}
/* Delete the directory. */
ret = rmdir(dirName);
if (ret != LOS_OK) {
printf("rmdir failed.\n");
return;
}
return LOS_OK;
}
```
**Verification**
**Verification**
The development is successful if the return result is as follows:
```
Say hello 1 times.
Hello OpenHarmony!
```
......@@ -11,16 +11,16 @@ The purpose of memory debugging is to locate problems related to dynamic memory.
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.
- 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.
- 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:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
- Other parameters: You can call APIs described in [Memory Management](../kernel/kernel-mini-basic-memory.md) to scan node information in the memory pool and collect statistics.
- You can use [APIs for memory management](kernel-mini-basic-memory.md) to scan node information in the memory pool and collect statistics.
### Function Configuration
**LOSCFG_MEM_WATERLINE**: specifies the setting of the memory information statistics function. This function is enabled by default. To disable the function, set this macro to **0** in **target_config.h**. If you want to obtain the memory waterline, you must enable this macro.
**LOSCFG_MEM_WATERLINE** specifies the setting of the memory information statistics function. This function is enabled by default. To disable the function, set this macro to **0** in **target_config.h**. If you want to obtain the memory waterline, you must enable this macro.
### Development Guidelines
......@@ -33,20 +33,20 @@ Key structure:
```
typedef struct {
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) //The function is enabled by default. To disable it, set this macro to 0 in target_config.h.
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) // The function is enabled by default. To disable it, set this macro to 0 in target_config.h.
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**. 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 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:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
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:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
#### Development Example
......@@ -62,7 +62,9 @@ This example implements the following:
#### Sample Code
The sample code is as follows:
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemTest** function is called in **TestTaskEntry**.
```
#include <stdio.h>
......@@ -71,20 +73,20 @@ This example implements the following:
#include "los_memory.h"
#include "los_config.h"
#define TEST_TASK_PRIO 5
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;
float fragment = 100 - poolStatus.maxFreeNodeSize * 100.0 / 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);
float usage = LOS_MemTotalUsedGet(pool) * 100.0 / LOS_MemPoolSizeGet(pool);
printf("usage = %f, fragment = %f, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment,
poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
}
int MemTest(void)
......@@ -93,9 +95,9 @@ int MemTest(void)
unsigned int taskID;
TSK_INIT_PARAM_S taskStatus = {0};
taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc;
taskStatus.uwStackSize = 0x1000;
taskStatus.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
taskStatus.pcName = "memInfo";
taskStatus.usTaskPrio = 10;
taskStatus.usTaskPrio = TEST_TASK_PRIO;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
......@@ -112,7 +114,9 @@ The result is as follows:
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
usage = 0.458344, fragment = 0.000000, maxFreeSize = 16474928, totalFreeSize = 16474928, waterLine = 76816
The preceding data may vary depending on the running environment.
```
## Memory Leak Check
......@@ -124,14 +128,15 @@ As an optional function of the kernel, memory leak check is used to locate dynam
### Function Configuration
1. **LOSCFG_MEM_LEAKCHECK**: specifies the setting of the memory leak check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
**LOSCFG_MEM_LEAKCHECK** specifies the setting of the memory leak check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
2. **LOSCFG_MEM_RECORD_LR_CNT**: specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void\*)** bytes.
**LOSCFG_MEM_RECORD_LR_CNT** specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void \*)** bytes.
3. **LOSCFG_MEM_OMIT_LR_CNT**: specifies the number of ignored LRs. The default value is **4**, 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 **LOSCFG_MEM_RECORD_LR_CNT** is limited.
**LOSCFG_MEM_OMIT_LR_CNT** specifies the number of ignored LRs. The default value is **4**, 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 **LOSCFG_MEM_RECORD_LR_CNT** is limited.
Correctly setting this macro can ignore invalid LRs and reduce memory consumption.
......@@ -156,7 +161,8 @@ node size LR[0] LR[1] LR[2]
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
```
> ![icon-caution.gif](../public_sys-resources/icon-caution.gif) **CAUTION**<br/>
> **CAUTION**
>
> Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
......@@ -179,6 +185,12 @@ This example implements the following:
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemLeakTest** function is called in **TestTaskEntry**.
When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**.
After the memory check function is enabled, other tasks running on certain platforms may frequently print memory-related information such as "psp, start = xxxxx, end = xxxxxxx". Ignore the information or delete the print information called by **OsStackAddrGet**.
```
#include <stdio.h>
......@@ -216,7 +228,9 @@ node size LR[0] LR[1] LR[2]
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
The preceding data may vary depending on the running environment.
```
The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak.
......@@ -224,7 +238,9 @@ The difference between the two logs is as follows. The following memory nodes ar
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
The preceding data may vary depending on the running environment.
```
The following is part of the assembly file:
......@@ -246,6 +262,8 @@ The following is part of the assembly file:
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0
The preceding data may vary depending on the running environment.
```
The memory node addressed by **0x080041ee** is not released after being requested in **MemLeakTest**.
......@@ -260,15 +278,16 @@ As an optional function of the kernel, memory corruption check is used to check
### Function Configuration
**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK**: specifies the setting of the memory corruption check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** specifies the setting of the memory corruption check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**.
1. If this macro is enabled, the memory pool integrity will be checked in real time upon each memory allocation.
2. 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).
2. 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.
> ![icon-caution.gif](../public_sys-resources/icon-caution.gif) **CAUTION**<br/>
> **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.
......@@ -295,6 +314,12 @@ This example implements the following:
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemIntegrityTest** function is called in **TestTaskEntry**.
When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**.
Because the exception is triggered intentionally, you need to restart QEMU when the execution is complete. For example, open a new terminal and run **killall qemu-system-arm**.
```
#include <stdio.h>
......@@ -320,20 +345,28 @@ 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. */
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. */
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. */
LR[0]:0x08004144
LR[1]:0x08000cc2
LR[2]:0x00000000
[ERR]Memory integrity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* Addresses of the corrupted node and its previous node */
/* Error information indicating the field corrupted. In this example, the first four bytes of the next node are cleared, that is, the magic number field is corrupted. */
[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error!
memory used but magic num wrong, magic num = 0x0
/* 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: 0x2103d7e8 0x0 0x80000020, prev node head: 0x2103c7cc 0xabcddcba 0x80000020
/*The node LR information can be output only after the memory leak check is enabled. */
broken node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* Based on the LR information, you can determine where the previous node in requsted in the assembly file and check the use of the node. */
pre node head LR info:
LR[0]:0x2101906c
LR[1]:0x0
LR[2]:0x0
/* Addresses of the corrupted node and its previous node. */
[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0
The preceding data may vary depending on the running environment.
```
# Exception Debugging
## Basic Concepts
The OpenHarmony LiteOS-M provides exception handling and debugging measures to help locate and analyze problems. Exception handling involves a series of actions taken by the OS to respond to exceptions occurred during the OS running, for example, printing the exception type, system status, call stack information of the current function, CPU information, and call stack information of tasks.
## Working Principles
A stack frame contains information such as function parameters, variables, and return value in a function call process. When a function is called, a stack frame of the subfunction is created, and the input parameters, local variables, and registers of the function are stored into the stack. Stack frames grow towards lower addresses. The ARM32 CPU architecture is used as an example. Each stack frame stores the historical values of the program counter \(PC\), LR \(link register\), stack pointer \(SP\), and frame pointer \(FP\) registers. The LR points to the return address of a function, and the FP points to the start address of the stack frame of the function's parent function. The FP helps locate the parent function's stack frame, which further helps locate the parent function's FP. The parent function's FP helps locate the grandparent function's stack frame and FP... In this way, the call stack of the program can be traced to obtain the relationship between the functions called.
A stack frame contains information such as function parameters, variables, and return value in a function call process. When a function is called, a stack frame of the subfunction is created, and the input parameters, local variables, and registers of the function are stored into the stack. Stack frames grow towards lower addresses. The ARM32 CPU architecture is used as an example. Each stack frame stores the historical values of the program counter (PC), link register (LR), stack pointer (SP), and frame pointer (FP) registers. The LR points to the return address of a function, and the FP points to the start address of the stack frame of the function's parent function. The FP helps locate the parent function's stack frame, which further helps locate the parent function's FP. The parent function's FP helps locate the grandparent function's stack frame and FP... In this way, the call stack of the program can be traced to obtain the relationship between the functions called.
When an exception occurs in the system, the system prints the register information in the stack frame of the abnormal function as well as the LRs and FPs in the stack frames of its parent function and grandfather function. The relationships between the functions help you locate the cause of the exception.
The following figure illustrates the stack analysis mechanism for your reference. The actual stack information varies depending on the CPU architecture.
**Figure 1** Stack analysis mechanism
**Figure 1** Stack analysis mechanism
![](figures/stack-analysis-mechanism.png "stack-analysis-mechanism")
In the figure, the registers in different colors indicate different functions. The registers save related data when functions are called. The FP register helps track the stack to the parent function of the abnormal function and further presents the relationships between the functions called.
## Available APIs
The following table describes APIs available for the OpenHarmony LiteOS-M stack trace module. For more details about the APIs, see the API reference.
**Table 1** APIs of the stack trace module
<a name="table1415203765610"></a>
<table><thead align="left"><tr id="row134151837125611"><th class="cellrowborder" valign="top" width="12.85128512851285%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="29.8029802980298%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="57.34573457345735%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row1841519376561"><td class="cellrowborder" rowspan="2" valign="top" width="12.85128512851285%" headers="mcps1.2.4.1.1 "><p id="p294964222410"><a name="p294964222410"></a><a name="p294964222410"></a>Stack trace</p>
</td>
<td class="cellrowborder" valign="top" width="29.8029802980298%" headers="mcps1.2.4.1.2 "><p id="p4166128181614"><a name="p4166128181614"></a><a name="p4166128181614"></a>LOS_BackTrace</p>
</td>
<td class="cellrowborder" valign="top" width="57.34573457345735%" headers="mcps1.2.4.1.3 "><p id="p1516617282165"><a name="p1516617282165"></a><a name="p1516617282165"></a>Prints the call stack relationship at the function calling point.</p>
</td>
</tr>
<tr id="row1187514443616"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p682431610715"><a name="p682431610715"></a><a name="p682431610715"></a>LOS_RecordLR</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p4969192715710"><a name="p4969192715710"></a><a name="p4969192715710"></a>Obtains the call stack relationship at the function calling point when print is unavailable.</p>
</td>
</tr>
</tbody>
</table>
## Usage Guidelines
**Table 1** APIs of the stack trace module
| Category| API|
| -------- | -------- |
| Stack tracing| **LOS_BackTrace**: prints the call stack relationship at the calling point.<br>**LOS_RecordLR**: obtains the call stack relationship at the calling point when print is unavailable.|
## Development Guidelines
### How to Develop
The typical process for enabling exception debugging is as follows:
1. Configure the macros related to exception handling.
Modify the configuration in the **target\_config.h** file.
<a name="table1078714915105"></a>
<table><thead align="left"><tr id="row1280518971010"><th class="cellrowborder" valign="top" width="20.1%" id="mcps1.1.4.1.1"><p id="p1380510912104"><a name="p1380510912104"></a><a name="p1380510912104"></a>Parameter</p>
</th>
<th class="cellrowborder" valign="top" width="37.47%" id="mcps1.1.4.1.2"><p id="p08051291106"><a name="p08051291106"></a><a name="p08051291106"></a>Description</p>
</th>
<th class="cellrowborder" valign="top" width="42.43%" id="mcps1.1.4.1.3"><p id="p12805149151012"><a name="p12805149151012"></a><a name="p12805149151012"></a>Value</p>
</th>
</tr>
</thead>
<tbody><tr id="row168052913104"><td class="cellrowborder" valign="top" width="20.1%" headers="mcps1.1.4.1.1 "><p id="p180618915101"><a name="p180618915101"></a><a name="p180618915101"></a>LOSCFG_BACKTRACE_DEPTH</p>
</td>
<td class="cellrowborder" valign="top" width="37.47%" headers="mcps1.1.4.1.2 "><p id="p198061196105"><a name="p198061196105"></a><a name="p198061196105"></a>Depth of the function call stack. The default value is <strong id="b1041811416176"><a name="b1041811416176"></a><a name="b1041811416176"></a>15</strong>.</p>
</td>
<td class="cellrowborder" valign="top" width="42.43%" headers="mcps1.1.4.1.3 "><p id="p1980609121010"><a name="p1980609121010"></a><a name="p1980609121010"></a>15</p>
</td>
</tr>
<tr id="row4806990105"><td class="cellrowborder" valign="top" width="20.1%" headers="mcps1.1.4.1.1 "><p id="p18940141181618"><a name="p18940141181618"></a><a name="p18940141181618"></a>LOSCFG_BACKTRACE_TYPE</p>
</td>
<td class="cellrowborder" valign="top" width="37.47%" headers="mcps1.1.4.1.2 "><p id="p280620917109"><a name="p280620917109"></a><a name="p280620917109"></a>Type of the stack trace.</p>
<p id="p9133142211184"><a name="p9133142211184"></a><a name="p9133142211184"></a><strong id="b9882230181814"><a name="b9882230181814"></a><a name="b9882230181814"></a>0</strong>: disabled</p>
<p id="p1133122212183"><a name="p1133122212183"></a><a name="p1133122212183"></a><strong id="b1863620373182"><a name="b1863620373182"></a><a name="b1863620373182"></a>1</strong>: supports function call stack analysis of the Cortex-m series hardware.</p>
<p id="p1133822101814"><a name="p1133822101814"></a><a name="p1133822101814"></a><strong id="b106211355191914"><a name="b106211355191914"></a><a name="b106211355191914"></a>2</strong>: supports function call stack analysis of the RISC-V series hardware.</p>
</td>
<td class="cellrowborder" valign="top" width="42.43%" headers="mcps1.1.4.1.3 "><p id="p780614919107"><a name="p780614919107"></a><a name="p780614919107"></a>Set this parameter to <strong id="b1926720398209"><a name="b1926720398209"></a><a name="b1926720398209"></a>1</strong> or <strong id="b149341042172017"><a name="b149341042172017"></a><a name="b149341042172017"></a>2</strong> based on the toolchain type.</p>
</td>
</tr>
</tbody>
</table>
1. Use the error code in the example to build and run a project, and check the error information displayed on the serial port terminal. The sample code simulates error code. During actual product development, use the exception debugging mechanism to locate exceptions.
The following example demonstrates the exception output through a task. The task entry function simulates calling of multiple functions and finally calls a function that simulates an exception. The sample code is as follows:
```
#include <stdio.h>
#include "los_config.h"
#include "los_interrupt.h"
#include "los_task.h"
UINT32 g_taskExcId;
#define TSK_PRIOR 4
/* Simulate an abnormal function. */
UINT32 Get_Result_Exception_0(UINT16 dividend){
UINT32 divisor = 0;
UINT32 result = dividend / divisor;
return result;
}
UINT32 Get_Result_Exception_1(UINT16 dividend){
return Get_Result_Exception_0(dividend);
}
UINT32 Get_Result_Exception_2(UINT16 dividend){
return Get_Result_Exception_1(dividend);
}
UINT32 Example_Exc(VOID)
{
UINT32 ret;
printf("Enter Example_Exc Handler.\r\n");
/* Simulate the function calling. */
ret = Get_Result_Exception_2(TSK_PRIOR);
printf("Divided result =%u.\r\n", ret);
printf("Exit Example_Exc Handler.\r\n");
return ret;
}
/* Task entry function used to create a task with an exception. */
UINT32 Example_Exc_Entry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam;
/* Lock task scheduling to prevent newly created tasks from being scheduled prior to this task due to higher priority.*/
LOS_TaskLock();
printf("LOS_TaskLock() Success!\r\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Exc;
initParam.usTaskPrio = TSK_PRIOR;
initParam.pcName = "Example_Exc";
initParam.uwStackSize = LOSCFG_SECURE_STACK_DEFAULT_SIZE;
/* Create a task with higher priority. The task will not be executed immediately after being created, because task scheduling is locked.*/
ret = LOS_TaskCreate(&g_taskExcId, &initParam);
if (ret != LOS_OK) {
LOS_TaskUnlock();
printf("Example_Exc create Failed!\r\n");
return LOS_NOK;
}
printf("Example_Exc create Success!\r\n");
/* Unlock task scheduling. The task with the highest priority in the Ready queue will be executed.*/
LOS_TaskUnlock();
return LOS_OK;
}
```
1. The error information displayed on the serial port terminal is as follows:
```
entering kernel init...
LOS_TaskLock() Success!
Example_Exc create Success!
Entering scheduler
Enter Example_Exc Handler.
*************Exception Information**************
Type = 10
ThrdPid = 4
Phase = exc in task
FaultAddr = 0xabababab
Current task info:
Task name = Example_Exc
Task ID = 4
Task SP = 0x200051ac
Task ST = 0x20004ff0
Task SS = 0x200
Exception reg dump:
PC = 0x80037da
LR = 0x80037fe
SP = 0x20005190
R0 = 0x4
R1 = 0x40
R2 = 0x4
R3 = 0x0
R4 = 0x4040404
R5 = 0x5050505
R6 = 0x6060606
R7 = 0x20005190
R8 = 0x8080808
R9 = 0x9090909
R10 = 0x10101010
R11 = 0x11111111
R12 = 0x12121212
PriMask = 0x0
xPSR = 0x41000000
----- backtrace start -----
backtrace 0 -- lr = 0x800381a
backtrace 1 -- lr = 0x8003836
backtrace 2 -- lr = 0x8005a4e
backtrace 3 -- lr = 0x8000494
backtrace 4 -- lr = 0x8008620
backtrace 5 -- lr = 0x800282c
backtrace 6 -- lr = 0x80008a0
backtrace 7 -- lr = 0x80099f8
backtrace 8 -- lr = 0x800a01a
backtrace 9 -- lr = 0x800282c
backtrace 10 -- lr = 0x80008a0
backtrace 11 -- lr = 0x80099f8
backtrace 12 -- lr = 0x8009bf0
backtrace 13 -- lr = 0x8009c52
backtrace 14 -- lr = 0x80099aa
----- backtrace end -----
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID name
--- -------- -------- --------- ---------- ---------- ---------- --------- ----- ----
0 0 Pend 0x2d0 0x104 0x200029bc 0x200027f0 0x0 0xffff Swt_Task
1 31 Ready 0x500 0x44 0x20002f84 0x20002ac8 0x0 0xffff IdleCore000
2 6 Ready 0x1000 0x44 0x20003f94 0x20002fd8 0x0 0xffff TaskSampleEntry1
3 7 Ready 0x1000 0x44 0x20004f9c 0x20003fe0 0x0 0xffff TaskSampleEntry2
4 4 Running 0x200 0xec 0x200051ac 0x20004ff0 0x0 0xffff Example_Exc
OS exception NVIC dump:
interrupt enable register, base address: 0xe000e100, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt pending register, base address: 0xe000e200, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt active register, base address: 0xe000e300, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt priority register, base address: 0xe000e400, size: 0xf0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt exception register, base address: 0xe000ed18, size: 0xc
0x0 0x0 0xf0f00000
interrupt shcsr register, base address: 0xe000ed24, size: 0x4
0x70008
interrupt control register, base address: 0xe000ed04, size: 0x4
0x400f806
memory pools check:
system heap memcheck over, all passed!
memory pool check end!
```
1. Configure the macros related to exception handling
in the **target_config.h** file.
| Configuration Item| Description| Value|
| -------- | -------- | -------- |
| LOSCFG_BACKTRACE_DEPTH | Depth of the function call stack. The default value is **15**.| 15 |
| LOSCFG_BACKTRACE_TYPE | Type of the stack tracing.<br>**0**: The stack tracing is disabled.<br>**1**: supports call stack analysis of the Cortex-M series hardware.<br>**2**: supports call stack analysis of the RISC-V series hardware.| Set this parameter to **1** or **2** based on the toolchain type.|
1. Use the error code in the example to build and run a project, and check the error information displayed on the serial port terminal. The sample code simulates error code. During actual product development, use the exception debugging mechanism to locate exceptions.
The following example demonstrates the exception output through a task. The task entry function simulates calling of multiple functions and finally calls a function that simulates an exception. The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleExcEntry** function is called in **TestTaskEntry**.
```
#include <stdio.h>
#include "los_config.h"
#include "los_interrupt.h"
#include "los_task.h"
UINT32 g_taskExcId;
#define TSK_PRIOR 4
/* Simulate an exception. */
UINT32 GetResultException0(UINT16 dividend){
UINT32 result = *(UINT32 *)(0xffffffff);
printf("Enter GetResultException0. %u\r\n", result);
return result;
}
UINT32 GetResultException1(UINT16 dividend){
printf("Enter GetResultException1.\r\n");
return GetResultException0(dividend);
}
UINT32 GetResultException2(UINT16 dividend){
printf("Enter GetResultException2.\r\n");
return GetResultException1(dividend);
}
UINT32 ExampleExc(VOID)
{
UINT32 ret;
printf("Enter Example_Exc Handler.\r\n");
/* Simulate the triggering of the exception. */
ret = GetResultException2(TSK_PRIOR);
printf("Divided result =%u.\r\n", ret);
printf("Exit Example_Exc Handler.\r\n");
return ret;
}
/* Create a task with an exception in the task entry function. */
UINT32 ExampleExcEntry(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S initParam = { 0 };
/* Lock task scheduling to prevent newly created tasks from being scheduled prior to this task due to higher priority. */
LOS_TaskLock();
printf("LOS_TaskLock() Success!\r\n");
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleExc;
initParam.usTaskPrio = TSK_PRIOR;
initParam.pcName = "Example_Exc";
initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
/* Create a task with a higher priority. The task will not be executed because task scheduling is locked. */
ret = LOS_TaskCreate(&g_taskExcId, &initParam);
if (ret != LOS_OK) {
LOS_TaskUnlock();
printf("Example_Exc create Failed!\r\n");
return LOS_NOK;
}
printf("Example_Exc create Success!\r\n");
/* Unlock task scheduling. The task with the highest priority in the Ready queue will be executed. */
LOS_TaskUnlock();
return LOS_OK;
}
```
The error information output by the serial port terminal is as follows:
```
LOS_TaskLock() Success!
Example_Exc create Success!
Enter Example_Exc Handler.
Enter GetResultException2.
Enter GetResultException1.
*************Exception Information**************
Type = 4
ThrdPid = 5
Phase = exc in task
FaultAddr = 0xfffffffc
Current task info:
Task name = Example_Exc
Task ID = 5
Task SP = 0x210549bc
Task ST = 0x21053a00
Task SS = 0x1000
Exception reg dump:
PC = 0x2101c61a
LR = 0x2101c64d
SP = 0x210549a8
R0 = 0x4
R1 = 0xa
R2 = 0x0
R3 = 0xffffffff
R4 = 0x2103fb20
R5 = 0x5050505
R6 = 0x6060606
R7 = 0x210549a8
R8 = 0x8080808
R9 = 0x9090909
R10 = 0x10101010
R11 = 0x11111111
R12 = 0x0
PriMask = 0x0
xPSR = 0x41000000
----- backtrace start -----
backtrace 0 -- lr = 0x2101c64c
backtrace 1 -- lr = 0x2101c674
backtrace 2 -- lr = 0x2101c696
backtrace 3 -- lr = 0x2101b1ec
----- backtrace end -----
TID Priority Status StackSize WaterLine StackPoint TopOfStack EventMask SemID CPUUSE CPUUSE10s CPUUSE1s TaskEntry name
--- -------- -------- --------- --------- ---------- ---------- --------- ------ ------- --------- -------- ---------- ----
0 0 Pend 0x1000 0xdc 0x2104730c 0x210463e8 0 0xffff 0.0 0.0 0.0 0x2101a199 Swt_Task
1 31 Ready 0x500 0x44 0x210478e4 0x21047428 0 0xffff 0.0 0.0 0.0 0x2101a9c9 IdleCore000
2 5 PendTime 0x6000 0xd4 0x2104e8f4 0x210489c8 0 0xffff 5.7 5.7 0.0 0x21016149 tcpip_thread
3 3 Pend 0x1000 0x488 0x2104f90c 0x2104e9e8 0x1 0xffff 8.6 8.6 0.0 0x21016db5 ShellTaskEntry
4 25 Ready 0x4000 0x460 0x21053964 0x2104f9f0 0 0xffff 9.0 8.9 0.0 0x2101c765 IT_TST_INI
5 4 Running 0x1000 0x458 0x210549bc 0x21053a00 0 0xffff 76.5 76.6 0.0 0x2101c685 Example_Exc
OS exception NVIC dump:
interrupt enable register, base address: 0xe000e100, size: 0x20
0x2001 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt pending register, base address: 0xe000e200, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt active register, base address: 0xe000e300, size: 0x20
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt priority register, base address: 0xe000e400, size: 0xf0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
interrupt exception register, base address: 0xe000ed18, size: 0xc
0x0 0x0 0xf0f00000
interrupt shcsr register, base address: 0xe000ed24, size: 0x4
0x70002
interrupt control register, base address: 0xe000ed04, size: 0x4
0x1000e805
memory pools check:
system heap memcheck over, all passed!
memory pool check end!
The preceding data may vary depending on the running environment.
```
### How to Locate Exceptions
The procedure for locating the exception is as follows:
1. Open the image disassembly file \(.asm\) generated after compilation. If the file is not generated by default, use the objdump tool to generate it. Run the following command:
```
arm-none-eabi-objdump -S -l XXX.elf
```
1. Search for the PC \(pointing to the instruction being executed\) in the ASM file to locate the abnormal function.
The PC address directs to the instruction being executed when the exception occurs. In the ASM file corresponding to the currently executed binary file, search for the PC value **0x80037da** and locate the instruction being executed by the CPU. Disassemble the code as follows:
```
UINT32 Get_Result_Exception_0(UINT16 dividend){
80037c8: b480 push {r7}
80037ca: b085 sub sp, #20
80037cc: af00 add r7, sp, #0
80037ce: 4603 mov r3, r0
80037d0: 80fb strh r3, [r7, #6]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:10
UINT32 divisor = 0;
80037d2: 2300 movs r3, #0
80037d4: 60fb str r3, [r7, #12]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:11
UINT32 result = dividend / divisor;
80037d6: 88fa ldrh r2, [r7, #6]
80037d8: 68fb ldr r3, [r7, #12]
80037da: fbb2 f3f3 udiv r3, r2, r3
80037de: 60bb str r3, [r7, #8]
```
1. <a name="li18973161743110"></a>As indicated by the code:
1. When the exception occurs, the CPU is executing **udiv r3, r2, r3**. The value of **r3** is **0**, which causes the divide-by-zero error.
2. The exception occurs in the **Get\_Result\_Exception\_0** function.
2. Locate the parent function of the abnormal function based on the LR value.
The code disassembly of the LR value **0x80037fe** is as follows:
```
080037ec <Get_Result_Exception_1>:
Get_Result_Exception_1():
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:15
UINT32 Get_Result_Exception_1(UINT16 dividend){
80037ec: b580 push {r7, lr}
80037ee: b082 sub sp, #8
80037f0: af00 add r7, sp, #0
80037f2: 4603 mov r3, r0
80037f4: 80fb strh r3, [r7, #6]
kernel_liteos_m\targets\cortex-m7_nucleo_f767zi_gcc/Core/Src/exc_example.c:16
return Get_Result_Exception_0(dividend);
80037f6: 88fb ldrh r3, [r7, #6]
80037f8: 4618 mov r0, r3
80037fa: f7ff ffe5 bl 80037c8 <Get_Result_Exception_0>
80037fe: 4603 mov r3, r0
```
1. The previous line of LR **80037fe** is **bl 80037c8 <Get\_Result\_Exception\_0\>**, which calls the abnormal function. The parent function that calls the abnormal function is **Get\_Result\_Exception\_1\(\)**.
2. Repeat [3](#li18973161743110) to analyze the LR values between **backtrace start** and **backtrace end** in the exception information to obtain the call stack relationship and find the exception cause.
1. Ensure that the compiler optimization is disabled. Otherwise, the following problems may be optimized during the compilation process.
2. Open the image disassembly file (.asm) generated. If the file is not generated, use the objdump tool to generate it. The command is as follows:
```
arm-none-eabi-objdump -S -l XXX.elf
```
3. Search for the PC (pointing to the instruction being executed) in the .asm file to locate the abnormal function.
The PC address directs to the instruction being executed when the exception occurs. In the .asm file corresponding to the currently executed binary file, search for the PC value **0x2101c61a** and locate the instruction being executed by the CPU. Disassemble the code as follows:
```
2101c60c <GetResultException0>:
2101c60c: b580 push {r7, lr}
2101c60e: b084 sub sp, #16
2101c610: af00 add r7, sp, #0
2101c612: 4603 mov r3, r0
2101c614: 80fb strh r3, [r7, #6]
2101c616: f04f 33ff mov.w r3, #4294967295 ; 0xffffffff
2101c61a: 681b ldr r3, [r3, #0]
2101c61c: 60fb str r3, [r7, #12]
2101c61e: 68f9 ldr r1, [r7, #12]
2101c620: 4803 ldr r0, [pc, #12] ; (2101c630 <GetResultException0+0x24>)
2101c622: f001 f92b bl 2101d87c <printf>
2101c626: 68fb ldr r3, [r7, #12]
2101c628: 4618 mov r0, r3
2101c62a: 3710 adds r7, #16
2101c62c: 46bd mov sp, r7
2101c62e: bd80 pop {r7, pc}
2101c630: 21025f90 .word 0x21025f90
```
As indicated by the information displayed:
- The CPU is executing **ldr r3, [r3, #0]** when an exception occurs. The value of **r3** is **0xffffffff**, which causes an invalid address.
- The exception occurs in the **GetResultException0** function.
4. Search for the parent function of the abnormal function based on the LR value.
The code disassembly of the LR value **0x2101c64d** is as follows:
```
2101c634 <GetResultException1>:
2101c634: b580 push {r7, lr}
2101c636: b082 sub sp, #8
2101c638: af00 add r7, sp, #0
2101c63a: 4603 mov r3, r0
2101c63c: 80fb strh r3, [r7, #6]
2101c63e: 4806 ldr r0, [pc, #24] ; (2101c658 <GetResultException1+0x24>)
2101c640: f001 f91c bl 2101d87c <printf>
2101c644: 88fb ldrh r3, [r7, #6]
2101c646: 4618 mov r0, r3
2101c648: f7ff ffe0 bl 2101c60c <GetResultException0>
2101c64c: 4603 mov r3, r0
2101c64e: 4618 mov r0, r3
2101c650: 3708 adds r7, #8
2101c652: 46bd mov sp, r7
2101c654: bd80 pop {r7, pc}
2101c656: bf00 nop
2101c658: 21025fb0 .word 0x21025fb0
```
The previous line of LR **2101c648** is **bl2101c60c <GetResultException0>**, which calls the abnormal function. The parent function is **GetResultException1**.
5. Parse the LR value between **backtrace start** and **backtrace end** in the exception information to obtain the call stack relationship where the exception occurs and find the cause of the exception.
\ No newline at end of file
# LMS
## Basic Concepts
Lite Memory Sanitizer \(LMS\) is a tool used to detect memory errors on a real-time basis. LMS can detect buffer overflow, Use-After-Free \(UAF\), and double free errors in real time, and notify the operating system immediately. Together with locating methods such as Backtrace, LMS can locate the code line that causes the memory error. It greatly improves the efficiency of locating memory errors.
Lite Memory Sanitizer (LMS) is a tool used to detect memory errors on a real-time basis. It can detect buffer overflow, Use-After-Free (UAF), and double free errors in real time, and notify the operating system immediately. Together with Backtrace, the LMS can locate the code line that causes the memory error. It greatly improves the efficiency of locating memory errors.
The LMS module of the OpenHarmony LiteOS-M kernel provides the following functions:
- Supports check of multiple memory pools.
- Checks the memory allocated by **LOS\_MemAlloc**, **LOS\_MemAllocAlign**, and **LOS\_MemRealloc**.
- Checks the memory when bounds-checking functions are called \(enabled by default\).
- Checks the memory when libc frequently accessed functions, including **memset**, **memcpy**, **memmove**, **strcat**, **strcpy**, **strncat** and **strncpy**, are called.
- Supports check of multiple memory pools.
- Checks the memory allocated by **LOS_MemAlloc**, **LOS_MemAllocAlign**, and **LOS_MemRealloc**.
- Checks the memory when bounds-checking functions are called (enabled by default).
- Checks the memory when libc frequently accessed functions, including **memset**, **memcpy**, **memmove**, **strcat**, **strcpy**, **strncat** and **strncpy**, are called.
## Working Principles
LMS uses shadow memory mapping to mark the system memory state. There are three states: **Accessible**, **RedZone**, and **Freed**. The shadow memory is located in the tail of the memory pool.
The LMS uses shadow memory mapping to mark the system memory state. There are three states: **Accessible**, **RedZone**, and **Freed**. The shadow memory is located in the tail of the memory pool.
- After memory is allocated from the heap, the shadow memory in the data area is set to the **Accessible** state, and the shadow memory in the head node area is set to the **RedZone** state.
- When memory is released from the heap, the shadow memory of the released memory is set to the **Freed** state.
- During code compilation, a function is inserted before the read/write instructions in the code to check the address validity. The tool checks the state value of the shadow memory that accesses the memory. If the shadow memory is in the **RedZone** statue, an overflow error will be reported. If the shadow memory is in the **Freed** state, a UAF error will be reported.
- When memory is released, the tool checks the state value of the shadow memory at the released address. If the shadow memory is in the **RedZone** state, a double free error will be reported.
- After memory is allocated from the heap, the shadow memory in the data area is set to the **Accessible** state, and the shadow memory in the head node area is set to the **RedZone** state.
- When memory is released from the heap, the shadow memory of the released memory is set to the **Freed** state.
- During code compilation, a function is inserted before the read/write instructions in the code to check the address validity. The tool checks the state value of the shadow memory that accesses the memory. If the shadow memory is in the **RedZone** statue, an overflow error will be reported. If the shadow memory is in the **Freed** state, a UAF error will be reported.
- When memory is released, the tool checks the state value of the shadow memory at the released address. If the shadow memory is in the **RedZone** state, a double free error will be reported.
## Available APIs
The LMS module of the OpenHarmony LiteOS-M kernel provides the following APIs. For more details about the APIs, see the [API](https://gitee.com/openharmony/kernel_liteos_m/blob/master/components/lms/los_lms.h) reference.
**Table 1** LMS module APIs
<a name="table15483333125018"></a>
<table><thead align="left"><tr id="row04831333145018"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p2968123815504"><a name="p2968123815504"></a><a name="p2968123815504"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p896843825020"><a name="p896843825020"></a><a name="p896843825020"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p10968123865011"><a name="p10968123865011"></a><a name="p10968123865011"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row12671943185014"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p926044310503"><a name="p926044310503"></a><a name="p926044310503"></a>Adding a memory pool to be checked</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1226094375013"><a name="p1226094375013"></a><a name="p1226094375013"></a>LOS_LmsCheckPoolAdd</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1226024365018"><a name="p1226024365018"></a><a name="p1226024365018"></a>Adds the address range of a memory pool to the LMS check linked list. LMS performs a validity check when the accessed address is within the linked list. In addition, <strong id="b126321851183511"><a name="b126321851183511"></a><a name="b126321851183511"></a>LOS_MemInit</strong> calls this API to add the initialized memory pool to the LMS check linked list by default.</p>
</td>
</tr>
<tr id="row4267104318501"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p926164395017"><a name="p926164395017"></a><a name="p926164395017"></a>Deleting a memory pool from the LMS check linked list</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p13261134310503"><a name="p13261134310503"></a><a name="p13261134310503"></a>LOS_LmsCheckPoolDel</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p62611438504"><a name="p62611438504"></a><a name="p62611438504"></a>Cancels the validity check on the specified memory pool.</p>
</td>
</tr>
<tr id="row1226794310500"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p2026154317502"><a name="p2026154317502"></a><a name="p2026154317502"></a>Protecting a specified memory chunk</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p5261643145019"><a name="p5261643145019"></a><a name="p5261643145019"></a>LOS_LmsAddrProtect</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p9261134365018"><a name="p9261134365018"></a><a name="p9261134365018"></a>Locks a memory chunk to prevent it from being read or written. Once the locked memory chunk is accessed, an error will be reported.</p>
</td>
</tr>
<tr id="row32662437507"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1261164325018"><a name="p1261164325018"></a><a name="p1261164325018"></a>Disabling protection of a specified memory chunk</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1426115437506"><a name="p1426115437506"></a><a name="p1426115437506"></a>LOS_LmsAddrDisableProtect</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p426194395019"><a name="p426194395019"></a><a name="p426194395019"></a>Unlocks a memory chunk to make it readable and writable.</p>
</td>
</tr>
</tbody>
</table>
The LMS module of the OpenHarmony LiteOS-A kernel provides the following APIs. For more details, see [API reference](https://gitee.com/openharmony/kernel_liteos_m/blob/master/components/lms/los_lms.h).
**Table 1** APIs of the LMS module
| Category| API | Description|
| -------- | -------- | -------- |
| Adding a memory pool to be checked| LOS_LmsCheckPoolAdd | Adds the address range of a memory pool to the LMS check linked list. LMS performs a validity check when the accessed address is within the linked list. In addition, **LOS_MemInit** calls this API to add the initialized memory pool to the LMS check linked list by default.|
| Deleting a memory pool from the LMS check linked list| LOS_LmsCheckPoolDel | Cancels the validity check on the specified memory pool.|
| Protecting a specified memory chunk| LOS_LmsAddrProtect | Locks a memory chunk to prevent it from being read or written. Once the locked memory chunk is accessed, an error will be reported.|
| Disabling protection of a specified memory chunk| LOS_LmsAddrDisableProtect | Unlocks a memory chunk to make it readable and writable.|
## Development Guidelines
### How to Develop
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\_m** directory, choose **Kernel**, and set **Enable Lite Memory Sanitizer** to **Yes**.
<a name="table1475284717333"></a>
<table><thead align="left"><tr id="row10752747163310"><th class="cellrowborder" valign="top" width="25%" id="mcps1.1.5.1.1"><p id="p3575105253315"><a name="p3575105253315"></a><a name="p3575105253315"></a>Macro</p>
</th>
<th class="cellrowborder" valign="top" width="25%" id="mcps1.1.5.1.2"><p id="p1957565253310"><a name="p1957565253310"></a><a name="p1957565253310"></a>menuconfig Option</p>
</th>
<th class="cellrowborder" valign="top" width="25%" id="mcps1.1.5.1.3"><p id="p657510523332"><a name="p657510523332"></a><a name="p657510523332"></a>Description</p>
</th>
<th class="cellrowborder" valign="top" width="25%" id="mcps1.1.5.1.4"><p id="p157520521332"><a name="p157520521332"></a><a name="p157520521332"></a>Value</p>
</th>
</tr>
</thead>
<tbody><tr id="row446814582334"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.1 "><p id="p645995893313"><a name="p645995893313"></a><a name="p645995893313"></a>LOSCFG_KERNEL_LMS</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.2 "><p id="p645916586337"><a name="p645916586337"></a><a name="p645916586337"></a>Enable Lms Feature</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.3 "><p id="p7459165883314"><a name="p7459165883314"></a><a name="p7459165883314"></a>Whether to enable LMS.</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.4 "><p id="p1345916584332"><a name="p1345916584332"></a><a name="p1345916584332"></a>YES/NO</p>
</td>
</tr>
<tr id="row846815810336"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.1 "><p id="p945915812332"><a name="p945915812332"></a><a name="p945915812332"></a>LOSCFG_LMS_MAX_RECORD_POOL_NUM</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.2 "><p id="p12459135823316"><a name="p12459135823316"></a><a name="p12459135823316"></a>Lms check pool max num</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.3 "><p id="p445975819335"><a name="p445975819335"></a><a name="p445975819335"></a>Maximum number of memory pools that can be checked by LMS.</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.4 "><p id="p7459165812336"><a name="p7459165812336"></a><a name="p7459165812336"></a>INT</p>
</td>
</tr>
<tr id="row74689584332"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.1 "><p id="p145913583333"><a name="p145913583333"></a><a name="p145913583333"></a>LOSCFG_LMS_LOAD_CHECK</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.2 "><p id="p1045985863318"><a name="p1045985863318"></a><a name="p1045985863318"></a>Enable lms read check</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.3 "><p id="p74591158183311"><a name="p74591158183311"></a><a name="p74591158183311"></a>Whether to enable LMS read check.</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.4 "><p id="p144590588332"><a name="p144590588332"></a><a name="p144590588332"></a>YES/NO</p>
</td>
</tr>
<tr id="row1146755819337"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.1 "><p id="p54591258163318"><a name="p54591258163318"></a><a name="p54591258163318"></a>LOSCFG_LMS_STORE_CHECK</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.2 "><p id="p645925814331"><a name="p645925814331"></a><a name="p645925814331"></a>Enable lms write check</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.3 "><p id="p1045918585334"><a name="p1045918585334"></a><a name="p1045918585334"></a>Whether to enable LMS write check.</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.4 "><p id="p1745920587338"><a name="p1745920587338"></a><a name="p1745920587338"></a>YES/NO</p>
</td>
</tr>
<tr id="row17467185818337"><td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.1 "><p id="p134594582336"><a name="p134594582336"></a><a name="p134594582336"></a>LOSCFG_LMS_CHECK_STRICT</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.2 "><p id="p1645925893319"><a name="p1645925893319"></a><a name="p1645925893319"></a>Enable lms strict check, byte-by-byte</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.3 "><p id="p7459258103311"><a name="p7459258103311"></a><a name="p7459258103311"></a>Whether to enable LMS byte-by-byte check.</p>
</td>
<td class="cellrowborder" valign="top" width="25%" headers="mcps1.1.5.1.4 "><p id="p1745985814336"><a name="p1745985814336"></a><a name="p1745985814336"></a>YES/NO</p>
</td>
</tr>
</tbody>
</table>
2. Modify the compile 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:
```
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",
]
}
```
1. Configure the macros related to the LMS module.
Configure the LMS macro **LOSCFG_KERNEL_LMS**, which is disabled by default.
Run the **make menuconfig** command in the **kernel/liteos_m** directory, and set **Kernel-&gt;Enable Lite Memory Sanitizer** to **YES**. If this option is unavailable, select **Enable Backtrace**.
| Macro| menuconfig Option| Description| Value|
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_LMS | Enable&nbsp;Lms&nbsp;Feature | Whether to enable LMS.| YES/NO |
| LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms&nbsp;check&nbsp;pool&nbsp;max&nbsp;num | Maximum number of memory pools that can be checked by LMS.| INT |
| LOSCFG_LMS_LOAD_CHECK | Enable&nbsp;lms&nbsp;read&nbsp;check | Whether to enable LMS read check.| YES/NO |
| LOSCFG_LMS_STORE_CHECK | Enable&nbsp;lms&nbsp;write&nbsp;check | Whether to enable LMS write check.| YES/NO |
| LOSCFG_LMS_CHECK_STRICT | Enable&nbsp;lms&nbsp;strict&nbsp;check,&nbsp;byte-by-byte | Whether to enable LMS byte-by-byte check.| YES/NO |
2. Modify the build script of the target module.
Add **-fsanitize=kernel-address** to insert memory access checks, and add **-O0** to disable optimization performed by the compiler.
The modifications vary depending on the compiler (GCC or Clang) used. The following is an example:
```
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",
]
}
```
3. Recompile the code and check the serial port output.
The memory problem detected will be displayed.
3. Recompile the code and check the serial port output. The memory problem detected will be displayed.
### Development Example
This example implements the following:
1. Create a task for LMS.
2. Construct a buffer overflow error and a UAF error.
3. Add "-fsanitize=kernel-address", execute the compilation, and check the output.
1. Create a task for LMS.
2. Construct a buffer overflow error and a UAF error.
3. Add "-fsanitize=kernel-address", execute the compilation, and check the output.
### Sample Code
The code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **Example_Lms_test** function is called in **TestTaskEntry**.
Modify **./kernel/liteos_m/testsuites/BUILD.gn** corresponding to **osTest.c**.
```
#define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20
......@@ -214,10 +151,10 @@ VOID LmsTestCaseTask(VOID)
UINT32 Example_Lms_test(VOID){
UINT32 ret;
TSK_INIT_PARAM_S lmsTestTask;
/* Create a task for LMS. */
/* Create a task for LMS. */
memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask;
lmsTestTask.pcName = "TestLmsTsk"; /* Task name. */
lmsTestTask.pcName = "TestLmsTsk"; /* Test task name. */
lmsTestTask.uwStackSize = 0x800;
lmsTestTask.usTaskPrio = 5;
lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
......@@ -230,89 +167,137 @@ UINT32 Example_Lms_test(VOID){
}
```
### Verification
The output is as follows:
The following is an example of the command output. The data may vary depending on the running environment.
```
######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
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected Start *****
[ERR][TestLmsTsk]Heap buffer overflow error detected
[ERR][TestLmsTsk]Illegal READ address at: [0x21040414]
[ERR][TestLmsTsk]Shadow memory address: [0x21041e84 : 6] Shadow memory value: [2]
psp, start = 21057d88, end = 21057e80
taskName = TestLmsTsk
taskID = 5
----- traceback start -----
traceback 0 -- lr = 0x210099f4
traceback 1 -- lr = 0x2101da6e
traceback 2 -- lr = 0x2101db38
traceback 3 -- lr = 0x2101c494
----- traceback end -----
[LMS] Dump info around address [0x21040414]:
[0x21040390]: 00 00 00 00 00 00 00 00 | [0x21041e7c | 4]: 1 1
[0x21040398]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 0]: 1 1
[0x210403a0]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 4]: 1 1
[0x210403a8]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 0]: 1 1
[0x210403b0]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 4]: 1 1
[0x210403b8]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 0]: 1 1
[0x210403c0]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 4]: 1 1
[0x210403c8]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 0]: 1 1
[0x210403d0]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 4]: 1 1
[0x210403d8]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 0]: 1 1
[0x210403e0]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 4]: 1 1
[0x210403e8]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 0]: 1 1
[0x210403f0]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 4]: 1 1
[0x210403f8]: 40 1e 04 21 05 07 00 80 | [0x21041e83 | 0]: 2 2
[0x21040400]: 00 00 00 00 00 00 00 00 | [0x21041e83 | 4]: 0 0
[0x21040408]: 00 00 00 00 00 00 00 00 | [0x21041e84 | 0]: 0 0
[0x21040410]: 00 00 00 00 [f8] 03 04 21 | [0x21041e84 | 4]: 0 [2]
[0x21040418]: 00 8b 06 00 00 00 00 00 | [0x21041e85 | 0]: 2 3
[0x21040420]: 00 00 00 00 00 00 00 00 | [0x21041e85 | 4]: 3 3
[0x21040428]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 0]: 3 3
[0x21040430]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 4]: 3 3
[0x21040438]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 0]: 3 3
[0x21040440]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 4]: 3 3
[0x21040448]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 0]: 3 3
[0x21040450]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 4]: 3 3
[0x21040458]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 0]: 3 3
[0x21040460]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 4]: 3 3
[0x21040468]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 0]: 3 3
[0x21040470]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 4]: 3 3
[0x21040478]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 0]: 3 3
[0x21040480]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 4]: 3 3
[0x21040488]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 0]: 3 3
[0x21040490]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 4]: 3 3
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected End *****
str[20]=0xfffffff8
######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 *****
######LmsTestUseAfterFree start ######
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected Start *****
[ERR][TestLmsTsk]Use after free error detected
[ERR][TestLmsTsk]Illegal READ address at: [0x2104041c]
[ERR][TestLmsTsk]Shadow memory address: [0x21041e85 : 2] Shadow memory value: [3]
psp, start = 21057d90, end = 21057e80
taskName = TestLmsTsk
taskID = 5
----- traceback start -----
traceback 0 -- lr = 0x210099f4
traceback 1 -- lr = 0x2101daec
traceback 2 -- lr = 0x2101db3c
traceback 3 -- lr = 0x2101c494
----- traceback end -----
[LMS] Dump info around address [0x2104041c]:
[0x21040398]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 0]: 1 1
[0x210403a0]: 00 00 00 00 00 00 00 00 | [0x21041e7d | 4]: 1 1
[0x210403a8]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 0]: 1 1
[0x210403b0]: 00 00 00 00 00 00 00 00 | [0x21041e7e | 4]: 1 1
[0x210403b8]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 0]: 1 1
[0x210403c0]: 00 00 00 00 00 00 00 00 | [0x21041e7f | 4]: 1 1
[0x210403c8]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 0]: 1 1
[0x210403d0]: 00 00 00 00 00 00 00 00 | [0x21041e80 | 4]: 1 1
[0x210403d8]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 0]: 1 1
[0x210403e0]: 00 00 00 00 00 00 00 00 | [0x21041e81 | 4]: 1 1
[0x210403e8]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 0]: 1 1
[0x210403f0]: 00 00 00 00 00 00 00 00 | [0x21041e82 | 4]: 1 1
[0x210403f8]: 40 1e 04 21 05 07 00 80 | [0x21041e83 | 0]: 2 2
[0x21040400]: 00 00 00 00 00 00 00 00 | [0x21041e83 | 4]: 0 0
[0x21040408]: 00 00 00 00 00 00 00 00 | [0x21041e84 | 0]: 0 0
[0x21040410]: 00 00 00 00 f8 03 04 21 | [0x21041e84 | 4]: 0 2
[0x21040418]: 05 8b 06 00 [00] 00 00 00 | [0x21041e85 | 0]: 2 [3]
[0x21040420]: 00 00 00 00 00 00 00 00 | [0x21041e85 | 4]: 3 3
[0x21040428]: 00 00 00 00 00 00 00 00 | [0x21041e86 | 0]: 3 3
[0x21040430]: 14 04 04 21 00 84 06 00 | [0x21041e86 | 4]: 2 2
[0x21040438]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 0]: 3 3
[0x21040440]: 00 00 00 00 00 00 00 00 | [0x21041e87 | 4]: 3 3
[0x21040448]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 0]: 3 3
[0x21040450]: 00 00 00 00 00 00 00 00 | [0x21041e88 | 4]: 3 3
[0x21040458]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 0]: 3 3
[0x21040460]: 00 00 00 00 00 00 00 00 | [0x21041e89 | 4]: 3 3
[0x21040468]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 0]: 3 3
[0x21040470]: 00 00 00 00 00 00 00 00 | [0x21041e8a | 4]: 3 3
[0x21040478]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 0]: 3 3
[0x21040480]: 00 00 00 00 00 00 00 00 | [0x21041e8b | 4]: 3 3
[0x21040488]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 0]: 3 3
[0x21040490]: 00 00 00 00 00 00 00 00 | [0x21041e8c | 4]: 3 3
[0x21040498]: 00 00 00 00 00 00 00 00 | [0x21041e8d | 0]: 3 3
[ERR][TestLmsTsk]***** Kernel Address Sanitizer Error Detected End *****
str[ 0]=0x 0
######LmsTestUseAfterFree stop ######
```
The key output information is as follows:
- Error type:
- Heap buffer overflow
- UAF
- Incorrect operations:
- Illegal read
- Illegal write
- Illegal double free
- Context:
- Task information \(**taskName** and **taskId**\)
- Backtrace
- Error type:
- Heap buffer overflow
- UAF
- Memory information of the error addresses:
- Memory value and the value of the corresponding shadow memory
- Memory address: memory value|\[shadow memory address|shadow memory byte offset\]: shadow memory value
- Shadow memory value. **0** \(Accessible\), **3** \(Freed\), **2** \(RedZone\), and **1** \(filled value\)
- Incorrect operations:
- Illegal read
- Illegal write
- Illegal double free
- Context:
- Task information (**taskName** and **taskId**)
- Backtrace
- Memory information of the error addresses:
- Memory value and the value of the corresponding shadow memory
- Memory address: memory value|[shadow memory address|shadow memory byte offset]: shadow memory value
- Shadow memory value. **0** (Accessible), **3** (Freed), **2** (RedZone), and **1** (filled value)
# 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
### Kernel Mode
The Perf module of the OpenHarmony LiteOS-A kernel provides the following functions. For details about the interfaces, 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
| API| Description|
| -------- | -------- |
| LOS_PerfStart| Starts sampling.|
| LOS_PerfStop| Stops sampling.|
| LOS_PerfConfig| Sets the event type and sampling interval.|
| LOS_PerfDataRead| Reads the sampling data.|
| LOS_PerfNotifyHookReg| Registers the hook to be called when the buffer waterline is reached.|
| LOS_PerfFlushHookReg| Registers the hook for flushing the cache in the buffer.|
- The structure of the perf sampling event is **PerfConfigAttr**. For details, see **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.
Example:
```
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.
Example:
```
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.
### User Mode
The perf character device is located in **/dev/perf**. You can read, write, and control the user-mode perf by running the following commands on the device node:
- **read**: reads perf data in user mode.
- **write**: writes user-mode sampling events.
- **ioctl**: controls the user-mode perf, which includes the following:
```
#define PERF_IOC_MAGIC 'T'
#define PERF_START _IO(PERF_IOC_MAGIC, 1)
#define PERF_STOP _IO(PERF_IOC_MAGIC, 2)
```
The operations correspond to **LOS_PerfStart** and **LOS_PerfStop**.
For details, see [User-Mode Development Example](#user-mode-development-example).
## How to Develop
### 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**.
| Item| menuconfig Option| Description| Value|
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_PERF | Enable Perf Feature | Whether to enable perf.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming Calc Methods-&gt;By Tick | Whether to use tick as the perf timing unit.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_CYCLE | Time-consuming Calc Methods-&gt;By Cpu Cycle | Whether to use cycle as the perf timing unit.| YES/NO |
| LOSCFG_PERF_BUFFER_SIZE | Perf Sampling Buffer Size | Size of the buffer used for perf sampling.| INT |
| LOSCFG_PERF_HW_PMU | Enable Hardware Pmu Events for Sampling | Whether to enable hardware PMU events. The target platform must support the hardware PMU.| YES/NO |
| LOSCFG_PERF_TIMED_PMU | Enable Hrtimer Period Events for Sampling | Whether to enable high-precision periodical events. The target platform must support the high precision event timer (HPET).| YES/NO |
| LOSCFG_PERF_SW_PMU | Enable Software Events for Sampling | Whether to enable software events. **LOSCFG_KERNEL_HOOK** must also be enabled.| YES/NO |
2. Call **LOS_PerfConfig** to configure the events to be sampled.
perf provides two working modes and three types of events.
Working modes: counting mode (counts only the number of event occurrences) and sampling mode (collects context information such as task IDs, PC, and backtrace)
Events: 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.
#### Kernel-Mode 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.
#### Kernel-Mode Sample Code
Prerequisites: The perf module configuration is complete in **menuconfig**.
The sample code is as follows:
```
#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;
/* Create a perf task. */
memset(&perfTestTask, 0, sizeof(TSK_INIT_PARAM_S));
perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
perfTestTask.pcName = "TestPerfTsk"; /* Test task name. */
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);
```
#### Kernel-Mode Verification
The output is as follows:
```
--------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
```
- 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.
### User-Mode Development Process
Choose **Driver** > **Enable PERF DRIVER** in **menuconfig** to enable the perf driver. This option is available in **Driver** only after **Enable Perf Feature** is selected in the kernel.
1. Open the **/dev/perf** file and perform read, write, and ioctl operations.
2. Run the **perf** commands in user mode in the **/bin** directory.
After running **cd bin**, you can use the following commands:
- **./perf start [*id*]**: starts perf sampling. *id* is optional and is **0** by default.
- **./perf stop**: stops perf sampling.
- **./perf read <*nBytes*>**: reads n-byte data from the sampling buffer and displays the data.
- **./perf list**: lists the events supported by **-e**.
- **./perf stat/record [*option*] <*command*>**: sets counting or sampling parameters.
- The [*option*] can be any of the following:
- -**-e**: sets sampling events. Events of the same type listed in **./perf list** can be used.
- -**-p**: sets the event sampling interval.
- -**-o**: specifies the path of the file for saving the perf sampling data.
- -**-t**: specifies the task IDs for data collection. Only the contexts of the specified tasks are collected. If this parameter is not specified, all tasks are collected by default.
- -**-s**: specifies the context type for sampling. For details, see **PerfSampleType** defined in **los_perf.h**.
- -**-P**: specifies the process IDs for data collection. Only the contexts of the specified processes are collected. If this parameter is not specified, all processes are collected by default.
- -**-d**: specifies whether to divide the frequency (the value is incremented by 1 each time an event occurs 64 times). This option is valid only for hardware cycle events.
- *command* specifies the program to be checked by perf.
Examples:
Run the **./perf list** command to display available events.
The output is as follows:
```
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]
```
Run **./perf stat -e cycles os_dump**.
The output is as follows:
```
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
```
Run **./perf record -e cycles os_dump**.
The output is as follows:
```
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) **NOTE**<br>
> After running the **./perf stat/record** command, you can run the **./perf start** and **./perf stop** commands multiple times. The sampling event configuration is as per the parameters set in the latest **./perfstat/record** command.
#### User-Mode Development Example
This example implements the following:
1. Open the perf character device.
2. Write the perf events.
3. Start perf.
4. Stop perf.
5. Read the perf sampling data.
#### User-Mode Sample Code
The code is as follows:
```
#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;
}
```
#### User-Mode Verification
The output is as follows:
```
[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
```
# Trace
## Basic Concepts
Trace helps you learn about the kernel running process and the execution sequence of modules and tasks. With the information, you can better understand the code running process of the kernel and locate time sequence problems.
Trace helps you learn about the kernel running process and the execution sequence of modules and tasks. With the traced information, you can better understand the code running process of the kernel and locate time sequence problems.
## Working Principles
......@@ -16,265 +18,168 @@ In offline mode, trace frames are stored in a circular buffer. If too many frame
![](figures/kernel-small-mode-process.png)
The online mode must be used with the integrated development environment \(IDE\). Trace frames are sent to the IDE in real time. The IDE parses the records and displays them in a visualized manner.
The online mode must be used with the integrated development environment (IDE). Trace frames are sent to the IDE in real time. The IDE parses the records and displays them in a visualized manner.
## Available APIs
The trace module of the OpenHarmony LiteOS-M kernel provides the following functions. For more details about the APIs, see the API reference.
**Table 1** Trace module APIs
<a name="table208266479117"></a>
<table><thead align="left"><tr id="row19826947121114"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.1"><p id="p16415637105612"><a name="p16415637105612"></a><a name="p16415637105612"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.2"><p id="p11415163718562"><a name="p11415163718562"></a><a name="p11415163718562"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.2.4.1.3"><p id="p1641533755612"><a name="p1641533755612"></a><a name="p1641533755612"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row7235182719585"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p92241727105816"><a name="p92241727105816"></a><a name="p92241727105816"></a>Starting and stopping trace</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p222418279581"><a name="p222418279581"></a><a name="p222418279581"></a>LOS_TraceStart</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p18224112711581"><a name="p18224112711581"></a><a name="p18224112711581"></a>Starts trace.</p>
</td>
</tr>
<tr id="row142340271586"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p2224152795812"><a name="p2224152795812"></a><a name="p2224152795812"></a>LOS_TraceStop</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p722492710584"><a name="p722492710584"></a><a name="p722492710584"></a>Stops trace.</p>
</td>
</tr>
<tr id="row12341278583"><td class="cellrowborder" rowspan="3" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p14224627175816"><a name="p14224627175816"></a><a name="p14224627175816"></a>Managing trace records</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p0224827145816"><a name="p0224827145816"></a><a name="p0224827145816"></a>LOS_TraceRecordDump</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p16224427125810"><a name="p16224427125810"></a><a name="p16224427125810"></a>Exports data in the trace buffer.</p>
</td>
</tr>
<tr id="row14234527185811"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p152241327165810"><a name="p152241327165810"></a><a name="p152241327165810"></a>LOS_TraceRecordGet</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1422412274584"><a name="p1422412274584"></a><a name="p1422412274584"></a>Obtains the start address of the trace buffer.</p>
</td>
</tr>
<tr id="row16234112725816"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p122244272582"><a name="p122244272582"></a><a name="p122244272582"></a>LOS_TraceReset</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1222413276581"><a name="p1222413276581"></a><a name="p1222413276581"></a>Clears events in the trace buffer.</p>
</td>
</tr>
<tr id="row14234727155817"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p19224227205814"><a name="p19224227205814"></a><a name="p19224227205814"></a>Filtering trace records</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p1922410277585"><a name="p1922410277585"></a><a name="p1922410277585"></a>LOS_TraceEventMaskSet</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p122242272585"><a name="p122242272585"></a><a name="p122242272585"></a>Sets the event mask to trace only events of the specified modules.</p>
</td>
</tr>
<tr id="row5234627145818"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p152244272589"><a name="p152244272589"></a><a name="p152244272589"></a>Masking events of specified interrupt IDs</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p182244276586"><a name="p182244276586"></a><a name="p182244276586"></a>LOS_TraceHwiFilterHookReg</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p12224627135819"><a name="p12224627135819"></a><a name="p12224627135819"></a>Registers a hook to filter out events of specified interrupt IDs.</p>
</td>
</tr>
<tr id="row22341027115815"><td class="cellrowborder" rowspan="2" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.1 "><p id="p1222462716588"><a name="p1222462716588"></a><a name="p1222462716588"></a>Performing function instrumentation</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.2 "><p id="p42242271585"><a name="p42242271585"></a><a name="p42242271585"></a>LOS_TRACE_EASY</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.2.4.1.3 "><p id="p1622416274584"><a name="p1622416274584"></a><a name="p1622416274584"></a>Performs simple instrumentation.</p>
</td>
</tr>
<tr id="row16234627175820"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p622515274583"><a name="p622515274583"></a><a name="p622515274583"></a>LOS_TRACE</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p2225527185810"><a name="p2225527185810"></a><a name="p2225527185810"></a>Performs standard instrumentation.</p>
</td>
</tr>
</tbody>
</table>
- You can perform function instrumentation in the source code to trace specific events. The system provides the following APIs for instrumentation:
- **LOS\_TRACE\_EASY\(TYPE, IDENTITY, params...\)** for simple instrumentation
- You only need to insert this API into the source code.
- **TYPE** specifies the event type. The value range is 0 to 0xF. The meaning of each value is user-defined.
- **IDENTITY** specifies the object of the event operation. The value is of the **UIntPtr** type.
- **Params** specifies the event parameters. The value is of the **UIntPtr** type.
- Example:
```
Perform simple instrumentation for reading and writing files fd1 and fd2.
Set TYPE to 1 for read operations and 2 for write operations.
Insert the following to the position where the fd1 file is read:
LOS_TRACE_EASY(1, fd1, flag, size);
Insert the following to the position where the fd2 file is read:
LOS_TRACE_EASY(1, fd2, flag, size);
Insert the following to the position where the fd1 file is written:
LOS_TRACE_EASY(2, fd1, flag, size);
Insert the following in the position where the fd2 file is written:
LOS_TRACE_EASY(2, fd2, flag, size);
```
- **LOS\_TRACE\(TYPE, IDENTITY, params...\)** for standard instrumentation.
- Compared with simple instrumentation, standard instrumentation supports dynamic event filtering and parameter tailoring. However, you need to extend the functions based on rules.
- **TYPE** specifies the event type. You can define the event type in **enum LOS\_TRACE\_TYPE** in the header file **los\_trace.h**. For details about methods and rules for defining events, see other event types.
- The **IDENTITY** and **Params** are the same as those of simple instrumentation.
- Example:
```
1. Set the event mask (module-level event type) in enum LOS_TRACE_MASK.
Format: TRACE_#MOD#_FLAG (MOD indicates the module name)
Example:
TRACE_FS_FLAG = 0x4000
2. Define the event type in enum LOS_TRACE_TYPE.
Format: #TYPE# = TRACE_#MOD#_FLAG | NUMBER
Example:
FS_READ = TRACE_FS_FLAG | 0; // Read files
FS_WRITE = TRACE_FS_FLAG | 1; // Write files
3. Set event parameters in the #TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ... format.
#TYPE# is the #TYPE# defined in step 2.
Example:
#define FS_READ_PARAMS(fp, fd, flag, size) fp, fd, flag, size
The parameters defined by the macro correspond to the event parameters recorded in the trace buffer. You can modify the parameters as required.
If no parameter is specified, events of this type are not traced.
#define FS_READ_PARAMS(fp, fd, flag, size) // File reading events are not traced.
4. Insert a code stub in a proper position.
Format: LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...))
LOS_TRACE(FS_READ, fp, fd, flag, size); // Code stub for reading files
The parameters following #TYPE# are the input parameter of the FS_READ_PARAMS function in step 3.
```
>![](../public_sys-resources/icon-note.gif) **NOTE:**
>The trace event types and parameters can be modified as required. For details about the parameters, see **kernel\\include\\los\_trace.h**.
- For **LOS\_TraceEventMaskSet\(UINT32 mask\)**, only the most significant 28 bits \(corresponding to the enable bit of the module in **LOS\_TRACE\_MASK**\) of the mask take effect and are used only for module-based tracing. Currently, fine-grained event-based tracing is not supported. For example, in **LOS\_TraceEventMaskSet\(0x202\)**, the effective mask is **0x200 \(TRACE\_QUE\_FLAG\)** and all events of the QUE module are collected. The recommended method is **LOS\_TraceEventMaskSet\(TRACE\_EVENT\_FLAG | TRACE\_MUX\_FLAG | TRACE\_SEM\_FLAG | TRACE\_QUE\_FLAG\);**.
- To enable trace of only simple instrumentation events, set **Trace Mask** to **TRACE\_MAX\_FLAG**.
- The trace buffer has limited capacity. When the trace buffer is full, events will be overwritten. You can use **LOS\_TraceRecordDump** to export data from the trace buffer and locate the latest records by **CurEvtIndex**.
- The typical trace operation process includes **LOS\_TraceStart**, **LOS\_TraceStop**, and **LOS\_TraceRecordDump**.
- You can filter out interrupt events by interrupt ID to prevent other events from being overwritten due to frequent triggering of a specific interrupt in some scenarios. You can customize interrupt filtering rules.
## Available APIs
The trace module of the OpenHarmony LiteOS-M kernel provides the following APIs. For more details about the APIs, see the API reference.
**Table 1** APIs of the trace module
| Category| API|
| -------- | -------- |
| Starting/Stopping trace| - **LOS_TraceStart**: starts a trace.<br>- **LOS_TraceStop**: stops the trace.|
| Managing trace records| - **LOS_TraceRecordDump**: dumps data from the trace buffer.<br>- **LOS_TraceRecordGet**: obtains the start address of the trace buffer.<br>- **LOS_TraceReset**: clears events in the trace buffer.|
| Filtering trace records| **LOS_TraceEventMaskSet**: sets the event mask to trace only events of the specified modules.|
| Masking events of specified interrupt IDs| **LOS_TraceHwiFilterHookReg**: registers a hook to filter out events of specified interrupt IDs.|
| Performing function instrumentation| - **LOS_TRACE_EASY**: performs simple instrumentation.<br>- **LOS_TRACE**: performs standard instrumentation.|
- You can perform function instrumentation in the source code to trace specific events. The system provides the following APIs for instrumentation:
- **LOS_TRACE_EASY(TYPE, IDENTITY, params...)** for simple instrumentation
- You only need to insert this API into the source code.
- **TYPE** specifies the event type. The value range is 0 to 0xF. The meaning of each value is user-defined.
- **IDENTITY** specifies the object of the event operation. The value is of the **UIntPtr** type.
- **Params** specifies the event parameters. The value is of the **UIntPtr** type.
- Example of simple instrumentation for reading and writing data based on the file FDs:
```
/* Set TYPE to 1 for read operation and 2 for write operations. */
LOS_TRACE_EASY(1, fd, flag, size); /* Add it to a proper position. */
LOS_TRACE_EASY(2, fd, flag, size); /* Add it to a proper position. */
```
- **LOS_TRACE(TYPE, IDENTITY, params...)** for standard instrumentation.
- Compared with simple instrumentation, standard instrumentation supports dynamic event filtering and parameter tailoring. However, you need to extend the functions based on rules.
- **TYPE** specifies the event type. You can define the event type in **enum LOS_TRACE_TYPE** in the header file **los_trace.h**. For details about methods and rules for defining events, see other event types.
- The **IDENTITY** and **Params** are the same as those of simple instrumentation.
- Example:
1. Define the type of the FS module (event mask of the FS module) in **enum LOS_TRACE_MASK**.
```
/* Define the event mask in the format of TRACE_#MOD#_FLAG, where #MOD# indicates the module name. */
TRACE_FS_FLAG = 0x4000
```
2. Define the event types of the FS module.
```
/* Define the event type in the format: #TYPE# = TRACE_#MOD#_FLAG | NUMBER */
FS_READ = TRACE_FS_FLAG | 0; /* Read data. */
FS_WRITE = TRACE_FS_FLAG | 1; /* Write data. */
```
3. Define event parameters.
```
/* Define the parameters in the format: #TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ... */
#define FS_READ_PARAMS(fp, fd, flag, size) fp, fd, flag, size /* The parameters defined by the macro correspond to the event parameters recorded in the trace buffer. You can tailor the parameters as required. */
#define FS_READ_PARAMS(fp, fd, flag, size) /* If no parameters are defined, events of this type are not traced. */
```
4. Add the code stubs in the code.
```
/* Format: LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...)) */
LOS_TRACE(FS_READ, fp, fd, flag, size); /* Code stub for reading data. */
```
> **NOTE**<br>
> You can modify the traced event types and parameters as required. For details about the parameters, see **kernel\include\los_trace.h**.
- For **LOS_TraceEventMaskSet(UINT32 mask)**, only the most significant 28 bits (corresponding to the enable bit of the module in **LOS_TRACE_MASK**) of the mask take effect and are used only for module-based tracing. Currently, fine-grained event-based tracing is not supported. For example, in **LOS_TraceEventMaskSet(0x202)**, the effective mask is **0x200 (TRACE_QUE_FLAG)** and all events of the QUE module are collected. The recommended method is **LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG);**.
- To enable trace of only simple instrumentation events, set **Trace Mask** to **TRACE_MAX_FLAG**.
- The trace buffer has limited capacity. When the trace buffer is full, events will be overwritten. You can use **LOS_TraceRecordDump** to export data from the trace buffer and locate the latest records by **CurEvtIndex**.
- The typical trace operation process includes **LOS_TraceStart**, **LOS_TraceStop**, and **LOS_TraceRecordDump**.
- You can filter out interrupt events by interrupt ID to prevent other events from being overwritten due to frequent triggering of a specific interrupt in some scenarios. You can customize interrupt filtering rules.<br>
The sample code is as follows:
```
BOOL Example_HwiNumFilter(UINT32 hwiNum)
{
if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) {
return TRUE;
}
return FALSE;
}
LOS_TraceHwiFilterHookReg(Example_HwiNumFilter);
```
```
BOOL Example_HwiNumFilter(UINT32 hwiNum)
{
if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) {
return TRUE;
}
return FALSE;
}
LOS_TraceHwiFilterHookReg(Example_HwiNumFilter);
```
The interrupt events with interrupt ID of **TIMER\_INT** or **DMA\_INT** are not traced.
The interrupt events with interrupt ID of **TIMER_INT** or **DMA_INT** are not traced.
## Development Guidelines
### How to Develop
The typical trace process is as follows:
1. Configure the macro related to the trace module.
Modify the configuration in the **target\_config.h** file.
<a name="table86631147151516"></a>
<table><thead align="left"><tr id="row5664134715156"><th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.1"><p id="p1466404761518"><a name="p1466404761518"></a><a name="p1466404761518"></a>Configuration</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.2"><p id="p18664347131518"><a name="p18664347131518"></a><a name="p18664347131518"></a>Description</p>
</th>
<th class="cellrowborder" valign="top" width="33.33333333333333%" id="mcps1.1.4.1.3"><p id="p166413478159"><a name="p166413478159"></a><a name="p166413478159"></a>Value</p>
</th>
</tr>
</thead>
<tbody><tr id="row22591620121620"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p225117203162"><a name="p225117203162"></a><a name="p225117203162"></a>LOSCFG_KERNEL_TRACE</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p72519205167"><a name="p72519205167"></a><a name="p72519205167"></a>Specifies whether to enable the trace feature.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p925182081614"><a name="p925182081614"></a><a name="p925182081614"></a>YES/NO</p>
</td>
</tr>
<tr id="row4259182012168"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p72515204168"><a name="p72515204168"></a><a name="p72515204168"></a>LOSCFG_RECORDER_MODE_OFFLINE</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p4251620111614"><a name="p4251620111614"></a><a name="p4251620111614"></a>Specifies whether to enable the online trace mode.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p425162020167"><a name="p425162020167"></a><a name="p425162020167"></a>YES/NO</p>
</td>
</tr>
<tr id="row1825902061611"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p122511220191613"><a name="p122511220191613"></a><a name="p122511220191613"></a>LOSCFG_RECORDER_MODE_ONLINE</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p7251192018169"><a name="p7251192018169"></a><a name="p7251192018169"></a>Specifies whether to enable the offline trace mode.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p1225115205163"><a name="p1225115205163"></a><a name="p1225115205163"></a>YES/NO</p>
</td>
</tr>
<tr id="row3259152015163"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p225118205169"><a name="p225118205169"></a><a name="p225118205169"></a>LOSCFG_TRACE_CLIENT_INTERACT</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p225182016163"><a name="p225182016163"></a><a name="p225182016163"></a>Specifies whether to enable interaction with Trace IDE (dev tools), including data visualization and process control.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p182512208167"><a name="p182512208167"></a><a name="p182512208167"></a>YES/NO</p>
</td>
</tr>
<tr id="row02591120201618"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p82511920101615"><a name="p82511920101615"></a><a name="p82511920101615"></a>LOSCFG_TRACE_FRAME_CORE_MSG</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p425192015165"><a name="p425192015165"></a><a name="p425192015165"></a>Specifies whether to enable recording of the CPU ID, interruption state, and lock task state.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p1925119204166"><a name="p1925119204166"></a><a name="p1925119204166"></a>YES/NO</p>
</td>
</tr>
<tr id="row1525916202166"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p3251162017161"><a name="p3251162017161"></a><a name="p3251162017161"></a>LOSCFG_TRACE_FRAME_EVENT_COUNT</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p18251142021619"><a name="p18251142021619"></a><a name="p18251142021619"></a>Specifies whether to enables recording of the event sequence number.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p1251020171616"><a name="p1251020171616"></a><a name="p1251020171616"></a>YES/NO</p>
</td>
</tr>
<tr id="row1025920204167"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p2025172010166"><a name="p2025172010166"></a><a name="p2025172010166"></a>LOSCFG_TRACE_FRAME_MAX_PARAMS</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p172511020141611"><a name="p172511020141611"></a><a name="p172511020141611"></a>Specifies the maximum number of parameters for event recording.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p12251182041610"><a name="p12251182041610"></a><a name="p12251182041610"></a>INT</p>
</td>
</tr>
<tr id="row225982091614"><td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.1 "><p id="p1725114206168"><a name="p1725114206168"></a><a name="p1725114206168"></a>LOSCFG_TRACE_BUFFER_SIZE</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.2 "><p id="p4251142014161"><a name="p4251142014161"></a><a name="p4251142014161"></a>Specifies the trace buffer size.</p>
</td>
<td class="cellrowborder" valign="top" width="33.33333333333333%" headers="mcps1.1.4.1.3 "><p id="p2251152014162"><a name="p2251152014162"></a><a name="p2251152014162"></a>INT</p>
</td>
</tr>
</tbody>
</table>
2. \(Optional\) Preset event parameters and stubs \(or use the default event parameter settings and event stubs\).
3. \(Optional\) Call **LOS\_TraceStop** to stop trace and call **LOS\_TraceReset** to clear the trace buffer. \(Trace is started by default.\)
4. \(Optional\) Call **LOS\_TraceEventMaskSet** to set the event mask for trace \(only the interrupts and task events are enabled by default\). For details about the event mask, see **LOS\_TRACE\_MASK** in **los\_trace.h**.
5. Call **LOS\_TraceStart** at the start of the code where the event needs to be traced.
6. Call **LOS\_TraceStop** at the end of the code where the event needs to be traced.
7. Call **LOS\_TraceRecordDump** to output the data in the buffer. \(The input parameter of the function is of the Boolean type. The value **FALSE** means to output data in the specified format, and the value **TRUE** means to output data to a Windows client.\)
The typical development process is as follows:
1. Configure the macros related to the trace module in the **target_config.h** file.
| Configuration Item| Description| Value|
| -------- | -------- | -------- |
| LOSCFG_KERNEL_TRACE | Whether to enable the trace feature. | YES/NO |
| LOSCFG_RECORDER_MODE_OFFLINE | Whether to enable the online trace mode. | YES/NO |
| LOSCFG_RECORDER_MODE_ONLINE | Whether to enable the offline trace mode. | YES/NO |
| LOSCFG_TRACE_CLIENT_INTERACT | Whether to enable interaction with Trace IDE (dev tools), including data visualization and process control. | YES/NO |
| LOSCFG_TRACE_FRAME_CORE_MSG | Whether to enable trace of the CPU ID, interruption state, and lock task state. | YES/NO |
| LOSCFG_TRACE_FRAME_EVENT_COUNT | Whether to enable trace of the event sequence number. | YES/NO |
| LOSCFG_TRACE_FRAME_MAX_PARAMS | Specifies the maximum number of parameters for event tracing. | INT |
| LOSCFG_TRACE_BUFFER_SIZE | Specifies the trace buffer size.| INT |
2. (Optional) Preset event parameters and stubs (or use the default event parameter settings and event stubs).
3. (Optional) Call **LOS_TraceStop** to stop trace and **LOS_TraceReset** to clear the trace buffer. (Trace is started by default.)
4. (Optional) Call **LOS_TraceEventMaskSet** to set the event mask for trace (only the interrupts and task events are enabled by default). For details about the event mask, see **LOS_TRACE_MASK** in **los_trace.h**.
5. Call **LOS_TraceStart** at the start of the code where the event needs to be traced.
6. Call **LOS_TraceStop** at the end of the code where the event needs to be traced.
7. Call **LOS_TraceRecordDump** to output the data in the buffer. (The input parameter of the function is of the Boolean type. The value **FALSE** means to output data in the specified format, and the value **TRUE** means to output data to a Windows client.)
The methods in steps 3 to 7 are encapsulated with shell commands. After the shell is enabled, the corresponding commands can be executed. The mapping is as follows:
- LOS\_TraceReset —— trace\_reset
- LOS\_TraceEventMaskSet —— trace\_mask
- LOS\_TraceStart —— trace\_start
- LOS\_TraceStop —— trace\_stop
- LOS\_TraceRecordDump —— trace\_dump
- LOS_TraceReset —— trace_reset
- LOS_TraceEventMaskSet —— trace_mask
- LOS_TraceStart —— trace_start
- LOS_TraceStop —— trace_stop
- LOS_TraceRecordDump —— trace_dump
### Development Example
This example implements the following:
1. Create a trace task.
2. Set the event mask.
3. Start trace.
4. Stop trace.
5. Output trace data in the specified format.
1. Create a trace task.
2. Set the event mask.
3. Start trace.
4. Stop trace.
5. Output trace data in the specified format.
### Sample Code
The sample code is as follows:
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleTraceTest** function is called in **TestTaskEntry**.
```
#include "los_trace.h"
UINT32 g_traceTestTaskId;
......@@ -288,21 +193,21 @@ VOID Example_Trace(VOID)
dprintf("trace start error\n");
return;
}
/* Trigger a task switching event.*/
/* Trigger a task switching event. */
LOS_TaskDelay(1);
LOS_TaskDelay(1);
LOS_TaskDelay(1);
/* Stop trace.*/
/* Stop trace. */
LOS_TraceStop();
LOS_TraceRecordDump(FALSE);
}
UINT32 Example_Trace_test(VOID){
UINT32 ExampleTraceTest(VOID){
UINT32 ret;
TSK_INIT_PARAM_S traceTestTask;
/* Create a trace task. */
TSK_INIT_PARAM_S traceTestTask = { 0 };
/* Create a trace task. */
memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
traceTestTask.pcName = "TestTraceTsk"; /* Trace task name*/
traceTestTask.pcName = "TestTraceTsk"; /* Trace task name. */
traceTestTask.uwStackSize = 0x800;
traceTestTask.usTaskPrio = 5;
traceTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
......@@ -311,21 +216,23 @@ UINT32 Example_Trace_test(VOID){
dprintf("TraceTestTask create failed .\n");
return LOS_NOK;
}
/* Trace is started by default. Therefore, you can stop trace, clear the buffer, and then restart trace. */
/* Trace is started by default. You can stop trace, clear the buffer, and restart trace. */
LOS_TraceStop();
LOS_TraceReset();
/* Enable trace of the Task module events. */
/* Enable trace of the Task module events. */
LOS_TraceEventMaskSet(TRACE_TASK_FLAG);
return LOS_OK;
}
```
### Verification
The output is as follows:
```
*******TraceInfo begin*******
***TraceInfo begin***
clockFreq = 50000000
CurEvtIndex = 7
Index Time(cycles) EventType CurTask Identity params
......@@ -337,36 +244,43 @@ Index Time(cycles) EventType CurTask Identity params
5 0x36eec810 0x45 0xc 0x1 0x9 0x8 0x1f
6 0x3706f804 0x45 0x1 0x0 0x1f 0x4 0x0
7 0x37070e59 0x45 0x0 0x1 0x0 0x8 0x1f
*******TraceInfo end*******
***TraceInfo end***
The preceding data may vary depending on the running environment.
```
The output event information includes the occurrence time, event type, task in which the event occurs, object of the event operation, and other parameters of the event.
- **EventType**: event type. For details, see **enum LOS\_TRACE\_TYPE** in the header file **los\_trace.h**.
- **CurrentTask**: ID of the running task.
- **Identity**: object of the event operation. For details, see **\#TYPE\#\_PARAMS** in the header file **los\_trace.h**.
- **params**: event parameters. For details, see **\#TYPE\#\_PARAMS** in the header file **los\_trace.h**.
- **EventType**: event type. For details, see **enum LOS_TRACE_TYPE** in the header file **los_trace.h**.
- **CurrentTask**: ID of the running task.
- **Identity**: object of the event operation. For details, see **#TYPE#_PARAMS** in the header file **los_trace.h**.
- **params**: event parameters. For details, see **#TYPE#_PARAMS** in the header file **los_trace.h**.
The following uses output No. 0 as an example.
```
Index Time(cycles) EventType CurTask Identity params
0 0x366d5e88 0x45 0x1 0x0 0x1f 0x4
```
- **Time \(cycles\)** can be converted into time \(in seconds\) by dividing the cycles by clockFreq.
- **0x45** indicates the task switching event. **0x1** is the ID of the task in running.
- For details about the meanings of **Identity** and **params**, see the **TASK\_SWITCH\_PARAMS** macro.
- **Time (cycles)** can be converted into time (in seconds) by dividing the cycles by clockFreq.
- **0x45** indicates the task switching event. **0x1** is the ID of the task in running.
- For details about the meanings of **Identity** and **params**, see the **TASK_SWITCH_PARAMS** macro.
```
#define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \
taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus
```
Because of **\#TYPE\#\_PARAMS\(IDENTITY, parma1...\) IDENTITY, ...**, **Identity** is **taskId \(0x0\)** and the first parameter is **oldPriority \(0x1f\)**.
>![](../public_sys-resources/icon-note.gif) **NOTE:**
>The number of parameters in **params** is specified by the **LOSCFG\_TRACE\_FRAME\_MAX\_PARAMS** parameter. The default value is **3**. Excess parameters are not recorded. You need to set **LOSCFG\_TRACE\_FRAME\_MAX\_PARAMS** based on service requirements.
Task 0x1 is switched to Task 0x0. The priority of task 0x1 is **0x1f**, and the state is **0x4**. The priority of the task 0x0 is **0x0**.
**Identity** is **taskId (0x0)**, and the first parameter is **oldPriority (0x1f)**.
> **NOTE**<br>
> The number of parameters in **params** is specified by **LOSCFG_TRACE_FRAME_MAX_PARAMS**. The default value is **3**. Excess parameters are not recorded. Set **LOSCFG_TRACE_FRAME_MAX_PARAMS** based on service requirements.
Task 0x1 is switched to Task 0x0. The priority of task 0x1 is **0x1f**, and the state is **0x4**. The priority of task 0x0 is **0x0**.
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册