编辑
2025-03-03
工作知识
0
请注意,本文编写于 95 天前,最后修改于 95 天前,其中某些信息可能已经过时。

目录

一:编译内核
二:测试任务上下文切换时间
2.1 通过mqueue来测试
2.2 通过管道传递令牌
三:测试消息传递延迟时间
四:中断响应时间
五:结论

RK3588的实时内核,这里测试验证其指标,用于后续评估判断RK3588相关的实时指标作为参考借鉴。测试结果或有偏差,最终以实际测试为准

一:编译内核

RT内核两笔补丁需要修改,如下:

diff --git a/include/trace/hooks/dtask.h b/include/trace/hooks/dtask.h index 9890bfe5c41d..fc2a51ce547e 100644 --- a/include/trace/hooks/dtask.h +++ b/include/trace/hooks/dtask.h @@ -58,7 +58,7 @@ DECLARE_HOOK(android_vh_sched_show_task, TP_ARGS(task)); DECLARE_HOOK(android_vh_alter_mutex_list_add, TP_PROTO(struct mutex *lock, - struct mutex_waiter *waiter, + struct rt_mutex_waiter *waiter, struct list_head *list, bool *already_on_list), TP_ARGS(lock, waiter, list, already_on_list)); diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index a2506b92e0c1..8d794db5e4d6 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -67,6 +67,7 @@ #ifdef CONFIG_PRINTK_TIME_FROM_ARM_ARCH_TIMER #include <clocksource/arm_arch_timer.h> +#if 0 static u64 get_local_clock(void) { u64 ns; @@ -76,6 +77,7 @@ static u64 get_local_clock(void) return ns; } +#endif #else static inline u64 get_local_clock(void) {

编译命令:

export ARCH=arm64 export CROSS_COMPILE=aarch64-none-linux-gnu- export PATH=$PATH:/path/to/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin make rockchip_linux_defconfig rockchip_rt.config make kylin.img -j123

这里项目有kylin.dts,故编译为kylin.img的内核,其他项目自行修改

二:测试任务上下文切换时间

2.1 通过mqueue来测试

#ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <stdlib.h> #include <string.h> #include <inttypes.h> #include <unistd.h> #include <stdio.h> #include <limits.h> #include <sched.h> #include <signal.h> #include <netinet/if_ether.h> #include <netinet/ip.h> #include <stdbool.h> #include <pthread.h> //#include <lock.h> #include <fcntl.h> #include <time.h> #include <mqueue.h> #include <semaphore.h> #include <stdarg.h> #include <sys/mman.h> #define TESTMQ_NAME "/testmsg" #define MSG_SIZE 8 char *testmsg = "Testing"; static int print_mode, TestCount; mqd_t sendsyncmq, recvsyncmq, testmq; struct timespec tv_s[10], tv_e[10]; static int over; struct mq_attr mqstat; pthread_t send_tid, recv_tid, send_recv_tid; static int tracemark_fd = -1; #define FILE_TRACEMARK "/sys/kernel/debug/tracing/trace_marker" static void open_tracemark() { if ((tracemark_fd = open(FILE_TRACEMARK, O_WRONLY)) == -1) printf("unable to open trace_marker file: %s\n", FILE_TRACEMARK); } static void close_tracemark() { close(tracemark_fd); } #define TRACEBUFSIZ 1024 static __thread char tracebuf[TRACEBUFSIZ]; static void tracemark(char *fmt, ...) __attribute__((format(printf, 1, 2))); static void tracemark(char *fmt, ...) { va_list ap; int len; /* bail out if we're not tracing */ /* or if the kernel doesn't support trace_mark */ if (tracemark_fd < 0) return; va_start(ap, fmt); len = vsnprintf(tracebuf, TRACEBUFSIZ, fmt, ap); va_end(ap); write(tracemark_fd, tracebuf, len); } /* * * * 终止ftrace,这样可以在ftrace的ringbuffer的底部保留问题现场 * * */ static int trace_fd = -1; #define FILE_TRACEON "/sys/kernel/debug/tracing/tracing_on" static void open_tracingon() { if ((trace_fd = open(FILE_TRACEON, O_WRONLY)) == -1) printf("unable to open trace_on file: %s\n", FILE_TRACEON); } static void close_tracingon() { close(trace_fd); } static void disable_trace() { if (trace_fd < 0) return; write(trace_fd, "0", 1); } pthread_t test_task_create(char *name, void *thread_func, size_t stack_size, int prio, int core) { int ret; struct sched_param param; pthread_attr_t attr; pthread_t thread_id; cpu_set_t mask; ret = pthread_attr_init(&attr); if (ret) { printf("ERROR: pthread_attr_init failed\n"); return -1; } ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); if (ret) { printf("ERROR: pthread_attr_setscope failed\n"); goto out; } ret = pthread_attr_setstacksize(&attr, stack_size); if (ret) { printf("ERROR: pthread_attr_setstacksize failed\n"); goto out; } ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (ret) { printf("ERROR: pthread_attr_setinheritsched failed\n"); goto out; } /* ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (ret) { printf("ERROR: pthread_attr_setdetachstate failed\n"); goto out; } */ ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); if (ret) { printf("ERROR: pthread_attr_setschedpolicy failed\n"); goto out; } param.sched_priority = prio; ret = pthread_attr_setschedparam(&attr, &param); if (ret) { printf("ERROR: pthread_attr_setschedparam failed\n"); goto out; } ret = pthread_create(&thread_id, &attr, thread_func, NULL); if (ret) { printf("ERROR: pthread_create %s failed\n", name); goto out; } CPU_ZERO(&mask); CPU_SET(core, &mask); if (pthread_setaffinity_np(thread_id, sizeof(mask), &mask) == -1) printf("ERROR: %s pthread_setaffinity_np failed, cpu_core = %d\n", name, core); return thread_id; out: pthread_attr_destroy(&attr); return -1; } struct timespec send_tv, recv_tv; bool flag = false; bool flag_send = false; void send_task_pthread(int core) { int i, ret; struct timespec tv1, tv2; unsigned int send_diff, send_sum; unsigned int send_mindiff, send_avg, send_maxdiff; char recvtestmsg[MSG_SIZE]; send_sum = 0; send_avg =0; send_mindiff = 100000000; send_maxdiff = 0; for (i = 0; i < TestCount; i++) { if (over) break; /* * send the test massege and calculate the cost time */ if (i > 1) { send_diff = (recv_tv.tv_sec * 1000000000 + recv_tv.tv_nsec) - (send_tv.tv_sec * 1000000000 + send_tv.tv_nsec); send_sum += send_diff; send_avg = send_sum / (i + 1); if (send_diff < send_mindiff) { send_mindiff = send_diff; } /* * 从第三次开始计入最大时间 * 原因:第二次发送消息时,如果接受线程未创建成功,mq_send阻塞, * 等待接受线程创建,第二次计算时间并不准确。 * 所以等接收线程接收一次消息后,开始统计最大时间 */ if ((send_diff > send_maxdiff) && (i > 1)) { send_maxdiff = send_diff; } // if (((i % 10) == 0)) printf("Task Switch Time, loop: %d, Min: %4d ns, Cur: %4d ns, Avg: %4d ns, Max: %4d ns\n\n", i, send_mindiff, send_diff, send_avg, send_maxdiff); } flag_send = false; ret = mq_send(testmq, testmsg, strlen(testmsg), 1); clock_gettime(CLOCK_REALTIME, &send_tv); flag_send = true; flag = false; while (!flag) { usleep(10000); } // if (!flag){ // usleep(10000); // flag = true; // printf("ERROR: send test message failed\n"); // sleep(1); // goto retry; // } } over = 1; printf("mq_send test count: %d \n", i); printf("Final result, Min: %4d ns, Cur: %4d ns, Avg: %4d ns, Max: %4d ns\n\n", send_mindiff, send_diff, send_avg, send_maxdiff); /* close_tracemark(); close_tracingon(); */ pthread_kill(recv_tid, SIGTERM); return; } void recv_task_pthread(int core) { int i, ret; ssize_t recv_length; struct timespec tv1, tv2; unsigned int recv_diff, recv_sum; unsigned int recv_mindiff, recv_avg, recv_maxdiff; char recvsyncmsg[MSG_SIZE]; char recvtestmsg[MSG_SIZE]; while (!over) { /* * receive the test massege and calculate the cost time */ recv_length = mq_receive(testmq, recvtestmsg, MSG_SIZE, NULL); while (!flag_send) { } clock_gettime(CLOCK_REALTIME, &recv_tv); flag = true; if ( recv_length != strlen(testmsg)) { perror("could not receive test message"); over = 1; } } return; } void send_recv_pthread(int core) { int i, ret; ssize_t recv_length; struct timespec tv1, tv2; unsigned int recv_diff, recv_sum; unsigned int recv_mindiff, recv_avg, recv_maxdiff; char recvtestmsg[MSG_SIZE]; recv_sum = 0; recv_avg =0; // recv_mindiff = UINT_MAX; recv_mindiff = 100000000; recv_maxdiff = 0; for (i = 0; i < TestCount; i++) { /* * send the test massege */ ret = mq_send(testmq, testmsg, strlen(testmsg), 1); if (ret < 0) { printf("ERROR: send test message failed\n"); over = 1; } usleep(200); /* * receive the test massege and calculate the cost time */ clock_gettime(CLOCK_REALTIME, &tv1); recv_length = mq_receive(testmq, recvtestmsg, MSG_SIZE, NULL); clock_gettime(CLOCK_REALTIME, &tv2); if ( recv_length != strlen(testmsg)) { perror("could not receive test message"); over = 1; } recv_diff = (tv2.tv_sec * 1000000000 + tv2.tv_nsec) - (tv1.tv_sec * 1000000000 + tv1.tv_nsec); recv_sum += recv_diff; recv_avg = recv_sum / (i + 1); if (recv_diff < recv_mindiff) { recv_mindiff = recv_diff; } if ((recv_diff > recv_maxdiff) && (i > 0)) { recv_maxdiff = recv_diff; } if (((i % 10) == 0)) printf("MQ Receive Time,loop: %d, Min: %4d ns, Cur: %4d ns, Avg: %4d ns, Max: %4d ns\n\n", i, recv_mindiff, recv_diff, recv_avg, recv_maxdiff); usleep(100); } printf("mq_receive test count: %d \n", i); printf("Final result, Min: %4d ns, Cur: %4d ns, Avg: %4d ns, Max: %4d ns\n\n", recv_mindiff, recv_diff, recv_avg, recv_maxdiff); return; } int main(int argc, char **argv) { int SendCore, SendThreadPrio, RecvCore, RecvThreadPrio, mode; if (argc != 7) { printf("Wrong CMD, check the parameters, please!\n"); printf("./mq_task_switch 1 90 2 90 10000 1\n"); return -1; } if (mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { perror("mlockall"); return -1; } SendCore = atoi(argv[1]); SendThreadPrio = atoi(argv[2]); RecvCore = atoi(argv[3]); RecvThreadPrio = atoi(argv[4]); TestCount = atoi(argv[5]); mode = atoi(argv[6]); over = 0; memset(&mqstat, 0, sizeof(mqstat)); mqstat.mq_maxmsg = 1; mqstat.mq_msgsize = 8; mqstat.mq_flags = 0; mq_unlink(TESTMQ_NAME); testmq = mq_open(TESTMQ_NAME, O_RDWR | O_CREAT, 0666, &mqstat); if (testmq < 0) { printf("open test message queue failed\n"); return -1; } if (mode == 0) { send_recv_tid = test_task_create("SndRECVTask", send_recv_pthread, 262144, SendThreadPrio, SendCore); if (send_recv_tid < 0) { printf("ERROR: Create send_recv_pthread failed!\n"); return -1; } pthread_join(send_recv_tid, NULL); } else { send_tid = test_task_create("sndTask", send_task_pthread, 262144, SendThreadPrio, SendCore); if (recv_tid < 0) { printf("ERROR: Create send_task_pthread failed!\n"); return -1; } usleep(10); recv_tid = test_task_create("RcvTask", recv_task_pthread, 262144, RecvThreadPrio, RecvCore); if (recv_tid < 0) { printf("ERROR: Create recv_task_pthread failed!\n"); return -1; } pthread_join(recv_tid, NULL); pthread_join(send_tid, NULL); } munlockall(); return 0; }

编译得到二进制mq_task_switch,开始测试

./mq_task_switch 1 90 2 90 10000 1

输出结果

Final result, Min: 10208 ns, Cur: 11084 ns, Avg: 11113 ns, Max: 24791 ns

这里可以确定最大值是24791ns ,平时值是11113ns.

2.2 通过管道传递令牌

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <time.h> #include <sched.h> #include <sys/types.h> #include <unistd.h> //pipe() int main() { int x, i, fd[2], p[2]; int tv[2]; //用于进程间数据通信 char send = 's'; char receive; pipe(fd); pipe(p); pipe(tv); struct timeval tv_start,tv_end; struct sched_param param; param.sched_priority = 0; while ((x = fork()) == -1); if (x==0) { //子进程 sched_setscheduler(getpid(), SCHED_FIFO, &param); gettimeofday(&tv_start, NULL); write(tv[1], &tv_start, sizeof(tv_start));//保存数据,以便传递到父进程中进行计算 for (i = 0; i < 10000; i++) { read(fd[0], &receive, 1); //printf("Child read!\n"); write(p[1], &send, 1); //printf("Child write!\n"); } exit(0); } else { //父进程 sched_setscheduler(getpid(), SCHED_FIFO, &param); for (i = 0; i < 10000; i++) { write(fd[1], &send, 1); //printf("Parent write!\n"); read(p[0], &receive, 1); //printf("Parent read!\n"); } gettimeofday(&tv_end, NULL); } read(tv[0], &tv_start, sizeof(tv_start)); printf("Task Switch Time: %f us\n", (1000000*(tv_end.tv_sec-tv_start.tv_sec) + tv_end.tv_usec - tv_start.tv_usec)/20000.0); return 0; }

编译:

gcc task_switch_pipe.c -o task_switch_pipe

运行:

root@kylin:~# while((1));do ./task_switch_pipe ; done Task Switch Time: 7.925000 us Task Switch Time: 7.978100 us Task Switch Time: 7.542050 us Task Switch Time: 9.470300 us Task Switch Time: 7.518850 us Task Switch Time: 8.346700 us Task Switch Time: 8.005150 us Task Switch Time: 7.560750 us Task Switch Time: 7.625400 us Task Switch Time: 8.143850 us Task Switch Time: 6.504850 us Task Switch Time: 8.422350 us Task Switch Time: 8.029650 us Task Switch Time: 7.612400 us Task Switch Time: 7.706200 us Task Switch Time: 6.831750 us Task Switch Time: 6.637150 us Task Switch Time: 9.136150 us Task Switch Time: 7.259700 us Task Switch Time: 9.774700 us Task Switch Time: 6.781400 us Task Switch Time: 7.425350 us Task Switch Time: 7.738900 us Task Switch Time: 8.812100 us Task Switch Time: 7.271150 us Task Switch Time: 8.677250 us Task Switch Time: 7.514600 us Task Switch Time: 6.683600 us Task Switch Time: 7.421900 us Task Switch Time: 8.019550 us Task Switch Time: 8.250450 us Task Switch Time: 8.571800 us Task Switch Time: 7.957400 us Task Switch Time: 7.837050 us Task Switch Time: 7.161250 us Task Switch Time: 8.998750 us Task Switch Time: 7.160500 us Task Switch Time: 6.629200 us Task Switch Time: 7.082150 us Task Switch Time: 7.570450 us Task Switch Time: 8.423500 us Task Switch Time: 7.531950 us Task Switch Time: 7.856900 us Task Switch Time: 8.980750 us Task Switch Time: 7.072300 us Task Switch Time: 9.112650 us Task Switch Time: 7.871100 us Task Switch Time: 7.168500 us Task Switch Time: 7.774850 us Task Switch Time: 7.308050 us Task Switch Time: 6.532000 us Task Switch Time: 6.994950 us Task Switch Time: 7.805700 us Task Switch Time: 7.980750 us Task Switch Time: 7.990150 us Task Switch Time: 8.017550 us Task Switch Time: 6.781300 us Task Switch Time: 6.755500 us Task Switch Time: 6.418300 us Task Switch Time: 8.239600 us Task Switch Time: 8.661350 us Task Switch Time: 8.688850 us Task Switch Time: 7.245000 us Task Switch Time: 8.793250 us Task Switch Time: 7.628300 us Task Switch Time: 6.593100 us Task Switch Time: 8.685100 us Task Switch Time: 6.575550 us Task Switch Time: 8.380500 us Task Switch Time: 8.607750 us Task Switch Time: 6.581850 us Task Switch Time: 6.862200 us Task Switch Time: 6.401400 us Task Switch Time: 6.690150 us Task Switch Time: 7.945100 us Task Switch Time: 7.820750 us Task Switch Time: 7.935500 us Task Switch Time: 8.156100 us Task Switch Time: 7.198700 us Task Switch Time: 7.230950 us Task Switch Time: 7.623400 us Task Switch Time: 7.438650 us Task Switch Time: 7.172000 us Task Switch Time: 8.439000 us Task Switch Time: 6.927050 us Task Switch Time: 8.215500 us Task Switch Time: 7.361300 us Task Switch Time: 7.231800 us Task Switch Time: 7.303450 us Task Switch Time: 8.140700 us Task Switch Time: 8.331800 us Task Switch Time: 7.962950 us Task Switch Time: 6.757600 us Task Switch Time: 7.251000 us

这里测试最大延迟为9.774700 us

三:测试消息传递延迟时间

安装测试包

apt install rt-tests

测试命令:

pmqtest -p 90 -t 2 -i 1000 -l 7200000

测试结果

root@kylin:~# pmqtest -p 90 -t 2 -i 1000 -l 7200000 #0: ID2607, P90, CPU5, I1000; #1: ID2608, P90, CPU4, TO 0, Cycles 782505 #2: ID2609, P89, CPU6, I1500; #3: ID2610, P89, CPU7, TO 0, Cycles 524798 #1 -> #0, Min 3, Cur 6, Avg 6, Max 27 #3 -> #2, Min 3, Cur 6, Avg 7, Max 36

这里可以确定最小值3us,平均值7us,最大值36us

四:中断响应时间

测试命令:

cyclictest -p 90 -m -c 0 -i 1000 -t 4 -l 7200000

测试结果:

root@kylin:~# cyclictest -p 90 -m -c 0 -i 1000 -t 4 -l 7200000 policy: fifo: loadavg: 2.61 1.48 0.68 1/288 257policy: fifo: loadavg: 2.91 2.71 2.14 1/285 2595 # /dev/cpu_dma_latency set to 0us T: 0 ( 2567) P:90 I:1000 C:1217830 Min: 4 Act: 4 Avg: 4 Max: 19 T: 1 ( 2568) P:90 I:1500 C: 811877 Min: 4 Act: 4 Avg: 4 Max: 15 T: 2 ( 2569) P:90 I:2000 C: 608904 Min: 4 Act: 5 Avg: 4 Max: 14 T: 3 ( 2570) P:90 I:2500 C: 487120 Min: 4 Act: 4 Avg: 4 Max: 13

这里可以确定最大延迟19us,平均延迟4us

五:结论

当前测试结论如下:

3588任务上下文切换最大时间为:24.791us,通过pipe令牌测试最大延迟为9.774700 us

3588消息传递最大延迟为:36us

3588中断响应最大延迟为:19us

当前测试结果不代表实际测试结果,并且测试结果仅供参考,具体情况根据系统负载,硬件情况决定。