• Linux 应用程序CPU调度优化


    缘起

           实时操作系统(Real-time operating system, RTOS),又称即时操作系统,它会按照排序运行、管理系统资源,并为开发应用程序提供一致的基础。实时操作系统与一般的操作系统相比,最大的特色就是实时性,如果有一个任务需要执行,实时操作系统会马上(在较短时间内)执行该任务,不会有较长的延时。这种特性保证了各个任务的及时执行。
          经常跟实时操作系统一起讲的,还有嵌入式操作系统这个概念,但实际上这是完全不同的两种东西,虽然大多数实时操作系统都是嵌入式操作系统,但嵌入式操作系统并不全都是实时的。
          对于实时操作系统有一些常见的误区,比如:速度快,吞吐量大,代码精简,代码规模小等等。其实这些都不算是实时操作系统的特性,别的操作系统也可以做到。只有实时性才是RTOS的最大特征,其它的都不算是。

           在了解了关于实时的概念后, 对于以下说描述的问题相对会更好理解一点. 本文采用的平台是RK3588 + Linux, 运行非实时操作系统编写一个C++程序, 用于从陀螺仪中读取数据并写入文件中, 陀螺仪的采样频率为 2000HZ, 也就是说0.5MS采样一次, 文件中写一行. 通过优化应用程序的CPU调度, 提高应用程序相应的实时性, 尽量接近实时操作系统.
    在这里插入图片描述

    过程

    神奇的现象: 频繁地打印时间间隔反而缩小了!

    	char buff[32];
    	while(true){
    		size_t read = read(fd, buff, 32);
    		//-----------打印-------------
    		//---------------------------
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    打印的方式有两种, 一种是次循环里都有打印, 另一种是每个 1秒打印一次.

    方式帧率
    每次循环2000HZ
    隔一秒1500-1900HZ

    多次测试后,结果依旧, 为了保证输出的稳定性, 于是做了一些尝试, 其中一种方法就是提高线程的优先级
    提高线程的优先级可以影响线程的调度顺序,使其在竞争资源时更有可能获得CPU时间片.

    	pthread_t thread = pthread_self(); // 获取底层线程句柄
        struct sched_param param;
        param.sched_priority = sched_get_priority_max(SCHED_FIFO);
        if (pthread_setschedparam(thread, SCHED_FIFO, &param) != 0) {
            std::cerr << "无法设置线程的优先级" << std::endl;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    很幸运, 方法有效.

    在前面读取数据的基础上, 加上了写入文件, 记录数据的功能, 整体性能和稳定性下降明显

    原因有两个

    1. 主控运行在性能自动调节模式
    2. 程序运行在低性能的小核

    第一点很好解决: 参考RK3588 CPU GPU DDR NPU定频和性能模式设置 设置高性能模式即可.
    在这里插入图片描述


    第二点需要用到taskset, 参考Linux性能优化(十五)——CPU绑定
         taskset用来查看和设定“CPU亲和力”,说白了就是查看或者配置进程和cpu的绑定关系,让某进程在指定的CPU核上运行,即是“绑核”。
    RK3588: CPU – 4x Cortex-A76 @ 2.4/2.6 GHz和 4x Cortex-A55 内核@ 1.8 GHz, 4个大核, 4个小核.
    需注意的是, 4个小核在0-3, 4个大核在4-7, 刚开始使用taskset是一直设置在小核上, 导致修改后效果不明显.

    • 指定CPU运行程序:
    #程序运行在 CPU 7上.
    taskset -c 7 /my_program
    
    • 1
    • 2
    • 修改运行中的程序
    #修改指定进程运行到 CPU 7 上
    taskset -pc 7 pid
    
    • 1
    • 2

    修改后可以通过命令查看, 参考判断Linux进程在哪个CPU核运行的4个方法

    ## 方法1
    $ taskset -cp pid
    pid pid's current affinity list: 0-15
    
    ## 方法2
    $ ps -eo pid,cmd,psr 4597
       4597 cat                          15
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Timer 与 Thread 的sleep

    为了稳定帧率, 减少帧误差, 稳定采样间隔在0.5MS, 尝试使用了线程和定时器的方法, 从测试结果看定时器的精度跟高

    #include 
    #include 
    #include 
    #include 
    #include  
    
    
    void  handle(union sigval v){
        time_t t;
        char p[32];
        time(&t);
        strftime(p, sizeof(p), "%T", localtime(&t));
        printf("%s thread %lu, val = %d, signal captured.\n", p, pthread_self(), v.sival_int);
        return;
    }
    
    int main(int argc, char *argv[]){
    
        struct sigevent evp;
        struct itimerspec ts;
        timer_t timer;
        int ret;
        memset   (&evp, 0, sizeof(evp));
        evp.sigev_value.sival_ptr = &timer;
        evp.sigev_notify = SIGEV_THREAD;
        evp.sigev_notify_function = handle;
        evp.sigev_value.sival_int = 3;   //作为handle()的参数
        ret = timer_create(CLOCK_REALTIME, &evp, &timer);
        if( ret){
            perror("timer_create");
        }
       
        ts.it_interval.tv_sec = 1;
        ts.it_interval.tv_nsec = 0;
        ts.it_value.tv_sec = 3;
        ts.it_value.tv_nsec = 0;
        ret = timer_settime(timer, TIMER_ABSTIME, &ts, NULL);
        if( ret )
        {
            perror("timer_settime");
        }
    
        while(1);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 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

    结语

    整个过程下来, 有效的优化有以下几点:

    1. 提高硬件工作频率, 如CPU, DDR, EMMC等
    2. 优化CPU调度, 把进程放到高性能的核上去运行
    3. 错开进程, 避免CPU资源抢占
    4. 提高线程优先级
    5. Timer的精确度优于 Thread 的 sleep

    另外还有内核实时补丁方法,有待验证

    ---------------------------------------------------------

        “有更好的方法或建议, 欢迎不吝指教”

    ---------------------------------------------------------

    引用

    RK3588 CPU GPU DDR NPU定频和性能模式设置
    判断Linux进程在哪个CPU核运行的4个方法
    Linux性能优化(十五)——CPU绑定
    什么是实时操作系统(RTOS)
    Linux 系统上最常用的定时器

  • 相关阅读:
    音频文件元数据修改:批量操作的技巧和方法
    wxWidgets Here
    python 装饰器
    龙芯3A5000上安装微信
    多级缓存(笔记)
    PostgreSQL的学习心得和知识总结(九十七)|PostgreSQL数据库开源时序数据库扩展TimescaleDB安装及使用
    PCB铺铜连接方式
    【Spring Boot】过滤敏感词的两种实现
    视频处理工具安利,要制作视频的快来
    RPC初识
  • 原文地址:https://blog.csdn.net/ansondroider/article/details/133997402