在VxWorks多核系统里,把周期采集任务绑定到CPU 1之后,任务不再跨核迁移,但同一核心上仍可能有其他任务参与调度。这里有两项容易混用的设置:任务亲和性规定一个任务能在哪个核心运行,CPU保留则限制哪些任务能进入指定核心。两者可以配合使用,是否有必要一起开,要看干扰来自任务迁移,还是同核竞争。
一、VxWorks任务亲和性怎么设置
以下以VxWorks 6.8的SMP内核任务接口为例。设置前应核对目标系统实际启用的逻辑CPU,板上有几个物理核心,与当前镜像能调度几个核心,是两回事。
1、构造CPU集合并绑定任务
这里把采集任务固定到逻辑CPU 1。传入设置接口的是CPU集合,不能直接把核心编号当成集合值。
①调用【vxCpuEnabledGet()】获取已启用的CPU集合,确认逻辑CPU 1在其中。
②声明【cpuset_t affinity】,使用【CPUSET_ZERO(affinity)】清空集合,再用【CPUSET_SET(affinity,1)】加入逻辑CPU 1。
③将采集任务的ID传给【taskCpuAffinitySet(tid,affinity)】;若由采集任务设置自身,则把任务ID参数传为【0】。
④检查返回值。若返回【ERROR】,记录错误信息,核对任务ID、SMP配置和目标CPU是否已启用。
2、在首次执行前完成绑定
①用【taskCreate()】创建尚未激活的内核任务,保存返回的任务ID。
②调用【taskCpuAffinitySet()】设置亲和性,再用【taskCpuAffinityGet()】读回并核对。
③确认设置成功后调用【taskActivate()】,让任务进入调度。
如果先启动任务,后设置亲和性,任务的初始化代码可能已在另一个核心上执行。对从入口就依赖每核资源的任务,创建与激活分开更合适。已经在运行的任务也可以调整亲和性,但调整可能触发重新调度,不宜把这个调用放进每周期执行的路径。
二、VxWorks任务亲和性与CPU保留有何区别
假设采集任务和后台日志任务都处于就绪状态。只给采集任务绑定CPU 1,日志任务仍可能被调度到这个核心。保留CPU 1后,没有该核心亲和性的任务会被排除在这个核心的任务调度范围之外。
1、亲和性约束的是任务去哪里
①对采集任务调用【taskCpuAffinitySet()】,只指定逻辑CPU 1。
②通过【vxCpuReservedGet()】确认CPU 1未被保留。
③在采集任务内用【vxCpuIndexGet()】记录实际运行的逻辑CPU编号,并查看同一测试期间其他任务的调度情况。
亲和性可以让采集任务固定在一个核心,但不会替它改优先级,也不会禁止同核任务抢占。看到任务一直在CPU 1运行,只能说明绑定符合预期,不能据此认定它独占了CPU 1。
2、CPU保留限制谁可以进入该核心
CPU保留作用在核心一侧。若两个任务都对CPU 1设置了亲和性,保留该核心后,它们仍可在这里调度。要把核心留给一个任务,还应检查是否有其他任务绑定到了同一核心。
①在【cpuset_t】集合中明确指定待保留的核心,按目标版本的接口声明调用【vxCpuReserve()】,检查返回状态。
②调用【vxCpuReservedGet()】核对实际保留的CPU集合。
③对准备使用该核心的任务调用【taskCpuAffinitySet()】,确认它们的亲和性与保留核心对应。
3、保留CPU后仍要检查中断
①在【BSP】及中断控制器配置中查看设备中断的目标核心。
②在【CPU保留】配置下施加代表性的设备负载,记录采集任务的响应时间。
③如果仍有长延迟,按时间对照【中断记录】和任务调度记录,判断延迟出现在哪个环节。
CPU保留改变的是任务调度范围,已路由到该核心的中断仍可被处理。跨核共享锁、内存访问竞争也可能带来等待。如果保留前后仍有延迟尖峰,可以先查这些干扰,再决定要不要调整核心分配。
三、VxWorks设置后怎样判断是否有必要保留CPU
有些任务固定到一个核心后,响应时间就足够稳定。也有些任务在后台负载上来时仍会错过周期,需要进一步减少同核竞争。做对照时应保持输入负载一致,同时看其他核心是否因此变得更忙。
1、把迁移和同核竞争分开测
①在同一负载下,分别记录【未绑定】、【仅设置亲和性】和【亲和性加CPU保留】三种状态。
②在采集任务内用【vxCpuIndexGet()】抽样记录核心编号,同时记录响应时间和超期次数。
③查看【调度记录】中延迟较长的周期,对照当时的就绪任务、中断活动和共享资源等待情况。
如果只设置亲和性就解决了问题,可以保留其余核心的调度弹性。如果必须保留CPU才能满足周期要求,还要确认后台任务集中到剩余核心后,日志、网络或其他周期任务仍能按时处理。
2、撤销时分别清理两类设置
取消CPU保留后,已绑定的任务仍受原亲和性约束。调试结束后想恢复原来的调度方式,这两项要分别核对。
①按项目原有配置调用【vxCpuUnreserve()】,解除本次测试新增的保留。
②若任务原先没有亲和性,使用【CPUSET_ZERO()】构造空集合,通过【taskCpuAffinitySet()】清除绑定;若原先已有绑定,则恢复原集合。
③分别调用【vxCpuReservedGet()】和【taskCpuAffinityGet()】,确认核心和任务都恢复到预期状态。
总结
只想让任务留在固定核心,任务亲和性就能满足要求;如果还要让没有相应亲和性的任务避开这个核心,再考虑CPU保留。现场判断可以看两个现象:任务还会不会跨核,固定之后延迟还会不会随同核负载上升。CPU保留会减少其他任务可用的调度空间,保留之前,最好确认实时任务得到的收益足以抵消这部分代价。有相关需求,欢迎交流。
