01 测试环境
xilinx zcu106 单板
xilinx vcu trd2020.1
02 介绍
嵌入式linux系统中,linux直接管理所有cpu。默认情况下,系统的目标是提高吞吐率,而不是实时性。为了保证实时性,可以根据应用场景,对cpu实行更加精确的控制。常见的办法有,进程cpu隔离、cpu亲和、中断cpu亲和、进程优先级。
03 工具
嵌入式linux系统中,一般使用busybox中的ps、top等工具。它们小巧,但是功能有限。如果需要更强大的工具,可以从ubuntu文件系统ubuntu-base-20.04.1-base-arm64.tar.gz中提取(点击阅读原文”查看链接)。
本测试中,从ubuntu文件系统提取了ps、top等工具,并改名为u-ps、u-top,以和busybox中的ps、top区别。
04 cpu隔离
linux还是可能把一个进程调度到任意一个cpu上,从而导致普通进程影响实时进程的性能。可以采用linux内核的命令行参数isolcpus,实现cpu隔离,完全禁止linux调度进程到某些cpu上,从而保证实时进程的响应时间。
在u-boot下,执行下列命令,可以使linux不再调度进程到cpu2和cpu3上。
setenv bootargs earlycon clk_ignore_unused consoleblank=0 cma=1700m uio_pdrv_genirq.of_id=generic-uio isolcpus=2,3
linux启动后,可以通过命令“cat /proc/cmdline” 查看linux内核的命令行参数。
root@vcu_trd:~# cat /proc/cmdline earlycon clk_ignore_unused consoleblank=0 cma=1700m uio_pdrv_genirq.of_id=generic-uio isolcpus=2,3
再使用ubuntu文件系统中的ps工具的psr选项,查看系统所有进程运行的cpu。下面输出的第二列,就是cpu号。可以看到,大部分进程,运行在在cpu0和cpu1上。运行在cpu2和cpu3上的进程,都是通过taskset设置了cpu亲和的进程。其中的u-ps是来自于软件包[ubuntu-base-20.04.1-base-arm64.tar.gz]。
root@vcu_trd:~# u-ps -axo pid,psr,cmd,ni pid psr cmd ni 1 1 init 0 2 1 [kthreadd] 0 3 0 [rcu_gp] -20 4 0 [rcu_par_gp] -20 6 0 [kworker/0:0h-kblockd] -20 8 0 [mm_percpu_wq] -20 9 0 [ksoftirqd/0] 0 10 1 [rcu_sched] 0 11 0 [migration/0] - 12 0 [cpuhp/0] 0 13 1 [cpuhp/1] 0 14 1 [migration/1] - 15 1 [ksoftirqd/1] 0 17 1 [kworker/1:0h-kblockd] -20 18 2 [cpuhp/2] 0 19 2 [migration/2] - 20 2 [ksoftirqd/2] 0 21 2 [kworker/2:0-events] 0 22 2 [kworker/2:0h] -20 23 3 [cpuhp/3] 0 24 3 [migration/3] - 25 3 [ksoftirqd/3] 0 26 3 [kworker/3:0-events] 0 27 3 [kworker/3:0h] -20 28 0 [kdevtmpfs] 0 29 1 [netns] -20 30 1 [kauditd] 0 32 1 [oom_reaper] 0 33 0 [writeback] -20 34 1 [kcompactd0] 0 35 1 [khugepaged] 19 37 0 [kworker/0:1-events] 0 38 1 [kworker/u8:1-events_unboun 0 87 1 [kblockd] -20 88 0 [blkcg_punt_bio] -20 89 0 [edac-poller] -20 90 1 [watchdogd] - 91 1 [rpciod] -20 92 0 [kworker/u9:0] -20 93 1 [xprtiod] -20 94 1 [cfg80211] -20 95 1 [kswapd0] 0 96 1 [ecryptfs-kthrea] 0 97 0 [nfsiod] -20 100 0 [irq/60-a00d0000] - 107 1 [ion_system_heap] - 108 2 [irq/61-a00d1000] - 109 0 [kpktgend_0] 0 110 1 [kpktgend_1] 0 111 2 [kpktgend_2] 0 112 3 [kpktgend_3] 0 113 1 [ipv6_addrconf] -20 114 0 [krfcommd] -10 115 2 [kworker/2:1-events] 0 116 3 [kworker/3:1-events] 0 117 0 [kworker/0:2-events_power_e 0 118 0 [irq/47-fd4a0000] - 120 1 [scsi_eh_0] 0 121 1 [scsi_tmf_0] -20 122 1 [scsi_eh_1] 0 123 1 [scsi_tmf_1] -20 125 1 [spi0] 0 128 1 [sdhci] -20 129 0 [irq/41-mmc0] - 134 0 [mmc_complete] -20 135 0 [kworker/0:1h-mmc_complete] -20 165 1 [kworker/1:1h-kblockd] -20 181 0 /sbin/udevd -d 0 231 1 [irq/63-xilinx-v] - 238 1 [xilinx-hdmi-rx] -20 242 1 [irq/54-xilinx-h] - 246 1 [irq/52-xilinx-h] - 419 0 [irq/62-a0220000] - 420 2 [irq/62-a0200000] - 808 0 udhcpc -r -b -p /var/run/ud 0 815 1 /usr/bin/dbus-daemon --syst 0 818 0 /usr/sbin/haveged -w 1024 - 0 827 1 xinit /etc/x11/xsession -- 0 831 0 /usr/bin/xorg :0 -br -pn -1 836 1 matchbox-window-manager -th 0 841 1 dbus-launch --sh-syntax --e 0 842 1 /usr/bin/dbus-daemon --sysl 0 862 0 /usr/sbin/dropbear -r /etc/ 0 864 0 /usr/libexec/at-spi-bus-lau 0 874 0 /usr/libexec/gconfd-2 0 882 0 /usr/bin/dbus-daemon --conf 0 885 1 /usr/sbin/inetd 0 888 0 /usr/bin/settings-daemon 0 898 0 /sbin/syslogd -n -o /var/lo 0 901 0 /sbin/klogd -n 0 910 0 matchbox-desktop 0 911 0 matchbox-panel --start-appl 0 921 0 /usr/sbin/tcf-agent -d -l- 0 929 0 /bin/sh /bin/start_getty 11 0 930 0 /sbin/getty 38400 tty1 0 934 1 /usr/libexec/at-spi2-regist 0 940 1 /usr/sbin/console-kit-daemo 0 1025 0 /bin/login -- 0 1050 1 -sh 0 1055 0 /usr/sbin/dropbear -r /etc/ 0 1057 0 -sh 0 1063 0 /usr/sbin/dropbear -r /etc/ 0 1065 0 -sh 0 1071 0 top 0 7174 0 /usr/sbin/dropbear -r /etc/ 0 7176 0 -sh 0 22378 0 /usr/sbin/dropbear -r /etc/ 0 22380 0 -sh 0 22588 0 /usr/sbin/dropbear -r /etc/ 0 22590 0 -sh 0 22600 1 [kworker/1:0-events] 0 22601 1 [kworker/u8:0-events_unboun 0 22602 1 [kworker/1:2-events_power_e 0 22603 1 [kworker/u8:2-events_unboun 0 22606 0 u-ps -axo pid,psr,cmd,ni 0
05 进程cpu亲和
设置进程cpu亲和时,需要知道进程号(pid)。ps和top等工具,可以查看进程号(pid)。
工具taskset可以查看和控制进程的cpu亲和。通过‘-p选项,指定进程号(pid),可以查看对应进程的cpu亲和。
root@vcu_trd:~# taskset -p 815 pid 815's current affinity mask: 1
采用如下脚本,可以检查所有进程的cpu亲和。
#!/bin/sh u-ps -axo pid,psr,cmd,ni | grep -v gst | grep -v xilinx | grep -v irq | grep -v kworker | grep -v grep | grep -v awk | awk '{print $1}' > process_list.txt echo -e read process list file: ; cat process_list.txt | while read line do # echo cpu affinity for process id: $line taskset -p $line done
linux系统中进程数量繁多,也可以采用如下脚本,设置所有进程的cpu亲和。
#!/bin/sh u-ps -axo pid,psr,cmd,ni | grep -v grep | grep -v awk | awk '{print $1}' > process_list.txt cat process_list.txt | while read line do echo -e check process id: $line if [ $line -gt 500 ]; then # echo original cpu affinity for process id: $line # taskset -p $line echo set priority for process id: $line taskset -a -p 1 $line # echo new cpu affinity for process id: $line # taskset -p $line fi done
对于新的任务,可以在启动时,就指定进程cpu亲和。taskset的帮助信息如下:
taskset [options] [mask | cpu-list] [pid|cmd [args...]]
如果要指定进程cpu亲和,可以采用下列命令启动新的任务。
taskset -a cpu-list cmd
比如以命令“ taskset -a 8 top”执行top,可以看到它确实运行在cpu-3上。
root@vcu_trd:~# u-ps -axo pid,psr,cmd,ni | grep top | grep -v grep | grep -v match 22629 3 top
06 中断cpu亲和
默认情况下,linux使用cpu0处理普通外设的中断。通过更改/proc/irq/irq_number/smp_affinity,可以改变处理中断的cpu。也可以查看/proc/interrupts,显示系统中各个cpu处理的中断数量。
linux系统中的中断也很多,也可以采用如下脚本,设置所有中断的cpu亲和。中断和cpu的对应关系,可以根据场景更改。
#!/bin/sh cat /proc/interrupts > interrupts_list_all.txt cat /proc/interrupts | grep -v cpu | grep -v ipi | grep -v err | awk '{print $1}' > interrupts_list.txt echo -e read interrupts list file: ; cat interrupts_list.txt | while read line do # remove colon : line_new=${line/:/} echo -e check interrupt: $line_new ls -l -h /proc/irq/$line_new/smp_affinity # 48: gicv2 122 level xilinx_framebuffer # 52: gicv2 123 level xilinx-hdmi-rx # 54: gicv2 125 level xilinx-hdmitxss # 55: gicv2 127 level xlnx-mixer # 61: gicv2 139 level a00d1000.sync_ip # 62: gicv2 128 level a0200000.al5e, a0220000.al5d # 63: gicv2 124 level xilinx-vphy if [ $line_new -eq 48 ]; then echo -e set cpu:1 affinity for interrupt: $line_new echo 2 > /proc/irq/$line_new/smp_affinity elif [ $line_new -eq 52 ]; then echo -e set cpu:1 affinity for interrupt: $line_new echo 2 > /proc/irq/$line_new/smp_affinity elif [ $line_new -eq 54 ]; then echo -e set cpu:1 affinity for interrupt: $line_new echo 2 > /proc/irq/$line_new/smp_affinity elif [ $line_new -eq 55 ]; then echo -e set cpu:1 affinity for interrupt: $line_new echo 2 > /proc/irq/$line_new/smp_affinity elif [ $line_new -eq 61 ]; then echo -e set cpu:2 affinity for interrupt: $line_new echo 4 > /proc/irq/$line_new/smp_affinity elif [ $line_new -eq 62 ]; then echo -e set cpu:2 affinity for interrupt: $line_new echo 4 > /proc/irq/$line_new/smp_affinity elif [ $line_new -eq 63 ]; then echo -e set cpu:2 affinity for interrupt: $line_new echo 2 > /proc/irq/$line_new/smp_affinity else echo -e set cpu:0 affinity for interrupt: $line_new echo 1 > /proc/irq/$line_new/smp_affinity fi echo -e new cpu affinity for interrupt: $line_new cat /proc/irq/$line_new/smp_affinity done
设置中断后,查看/proc/interrupts,可以看到cpu2/cpu3,处理了中断48、52、54、55、61、62。
root@vcu_trd:~# cat /proc/interrupts cpu0 cpu1 cpu2 cpu3 3: 115462 135783 31811 204151 gicv2 30 level arch_timer 6: 0 0 0 0 gicv2 67 level zynqmp_ipi 7: 0 0 0 0 gicv2 175 level arm-pmu 8: 0 0 0 0 gicv2 176 level arm-pmu 9: 0 0 0 0 gicv2 177 level arm-pmu 10: 0 0 0 0 gicv2 178 level arm-pmu 12: 349750 0 0 0 gicv2 156 level zynqmp-dma 13: 0 0 0 0 gicv2 157 level zynqmp-dma 14: 0 0 0 0 gicv2 158 level zynqmp-dma 15: 0 0 0 0 gicv2 159 level zynqmp-dma 16: 0 0 0 0 gicv2 160 level zynqmp-dma 17: 0 0 0 0 gicv2 161 level zynqmp-dma 18: 0 0 0 0 gicv2 162 level zynqmp-dma 19: 0 0 0 0 gicv2 163 level zynqmp-dma 20: 0 0 0 0 gicv2 164 level mali_gp_mmu, mali_gp, mali_pp0_mmu, mali_pp0, mali_pp1_mmu, mali_pp1 21: 0 0 0 0 gicv2 109 level zynqmp-dma 22: 0 0 0 0 gicv2 110 level zynqmp-dma 23: 0 0 0 0 gicv2 111 level zynqmp-dma 24: 0 0 0 0 gicv2 112 level zynqmp-dma 25: 0 0 0 0 gicv2 113 level zynqmp-dma 26: 0 0 0 0 gicv2 114 level zynqmp-dma 27: 0 0 0 0 gicv2 115 level zynqmp-dma 28: 0 0 0 0 gicv2 116 level zynqmp-dma 30: 463312 0 0 0 gicv2 95 level eth0, eth0 32: 525 0 0 0 gicv2 49 level cdns-i2c 33: 113 0 0 0 gicv2 50 level cdns-i2c 34: 0 0 0 0 gicv2 42 level ff960000.memory-controller 35: 0 0 0 0 gicv2 57 level axi-pmon, axi-pmon 36: 181 0 0 0 gicv2 155 level axi-pmon, axi-pmon 37: 28 0 0 0 gicv2 47 level ff0f0000.spi 38: 0 0 0 0 gicv2 58 level ffa60000.rtc 39: 0 0 0 0 gicv2 59 level ffa60000.rtc 40: 0 0 0 0 gicv2 165 level ahci-ceva[fd0c0000.ahci] 41: 233 0 0 0 gicv2 81 level mmc0 42: 133 0 0 0 gicv2 53 level xuartps 44: 0 0 0 0 gicv2 84 edge ff150000.watchdog 45: 0 0 0 0 gicv2 88 level ams-irq 46: 12 0 0 0 gicv2 154 level fd4c0000.dma 47: 0 0 0 0 gicv2 151 level fd4a0000.zynqmp-display 48: 0 34920 0 0 gicv2 122 level xilinx_framebuffer 49: 0 0 0 0 gicv2 141 level xilinx_framebuffer 50: 0 0 0 0 gicv2 142 level xilinx_framebuffer 51: 0 0 0 0 gicv2 143 level xilinx_framebuffer 52: 0 1142094 0 0 gicv2 123 level xilinx-hdmi-rx 53: 0 0 0 0 gicv2 121 level xilinx_framebuffer 54: 17669 151552 0 0 gicv2 125 level xilinx-hdmitxss 55: 17672 151552 0 0 gicv2 127 level xlnx-mixer 56: 0 0 0 0 gicv2 136 level xilinx-dma-controller 57: 0 0 0 0 gicv2 137 level xilinx-dma-controller 58: 0 0 0 0 gicv2 138 level xilinx-dma-controller 59: 0 0 0 0 gicv2 140 level xilinx-dma-controller 60: 81 0 0 0 gicv2 126 level a00d0000.i2c 61: 0 0 69841 0 gicv2 139 level a00d1000.sync_ip 62: 4 0 279353 0 gicv2 128 level a0220000.al5d, a0200000.al5e 63: 1184 163 0 0 gicv2 124 level xilinx-vphy 64: 0 0 0 0 gicv2 97 level xhci-hcd:usb1 67: 0 0 0 0 zynq-gpio 22 edge sw19 ipi0: 64845 46081 35 663483 rescheduling interrupts ipi1: 19 58 29 29 function call interrupts ipi2: 0 0 0 0 cpu stop interrupts ipi3: 0 0 0 0 cpu stop (for crash dump) interrupts ipi4: 0 0 0 0 timer broadcast interrupts ipi5: 0 0 0 0 irq work interrupts ipi6: 0 0 0 0 cpu wake-up interrupts err: 0
07 进程优先级
linux下进程的优先级概念比较复杂。一般而言,可以通过工具renice设置进程的nice值,来更改进程的优先级。nice值越大,改进程的优先级越低。
renice的常用格式为 renice priority -p pid。其中priority是nice值,pid是进程id。
下面的脚本,可以把所有名字中含有关键字(脚本第一个参数,$1)的进程的优先级设置为第二个参数($2)的值。
#!/bin/sh u-ps -axo pid,psr,cmd,ni u-ps -axo pid,psr,cmd,ni | grep $1 | grep -v grep | grep -v awk | awk '{print $1}' > process_list.txt echo -e read process list file: ; cat process_list.txt | while read line do echo -e set pid: $line to priority-nice value: $2 renice $2 -p $line done
08 其它
如果为了跟进一步提高实时性能,可以考虑为linux内核增加linux rt patch
原文标题:【工程师分享】嵌入式linux系统中的cpu控制
文章出处:【微信公众号:fpga开发圈】欢迎添加关注!文章转载请注明出处。
电子芯闻早报:英特尔并购Altera之后
2019年CES将正式拉开帷幕,更多黑科技等待解锁
极海智能扫地机器人应用方案
魅蓝S6评测 性价比再提升全面屏新可能
数字技术工程师培育项目加快推进,每年培养培训8万人左右
嵌入式Linux系统CPU控制常见办法测试
亿智AI芯片赋能多品类智慧终端
第11届电路保护与电磁兼容技术论坛
钠硫电池的结构组成_钠硫电池的作用
全自动点焊机的简单介绍
声音前处理技术可助力智能语音的市场发展
2016年各地如何应对工业危机?
面向氮化镓光电器件应用的氮化镓单晶衬底制备技术研发进展
无纺布在线缺陷检测系统的功能及检测原理的介绍
微软Surface Phone具有柔性转轴可折叠
大族激光两位高管合计减持6.9万股 公司基本面未发生重大变化
区块链平台如何才能加速实现大规模应用
高压接头测试的目的是什么
FSMR43信号分析仪FSMR50
CAN总线实现计算机与PLC的通信设计