admin 管理员组文章数量: 887007
基于Zynq7000平台VxWorks6.9开发应用——SMP多核任务篇
前言
本篇文章主要讲解在Xilinx ZedBoard上开发基于VxWorks6.9 SMP架构的多核任务调度,创建两个任务,并分别指定运行在Zynq7000上的两个CortexA9核上,研究多核CPU根据使用场景进行最优化任务部署。本文力求讲述清楚SMP基本概念,以及系统适配SMP模式的要求,SMP模式多任务运行在CPU实现方法,并配套完整的演示软件和相关代码进行验证。下面将从以下几个方面进行讲解。
- VxWorks6.9创建SMP模式
- 多核任务调度
开发使用工具说明:
- WorkBench3.3
- ZebBoard开发套件
术语和定义
- SMP :即对称多处理器(Symmetric Multi-Processing),是指在一个计算机上汇集了一组指令集相同的CPU,各CPU之间共享内存子系统以及总线结构,通常称作为多核CPU系统。
- AMP: 即异构多处理器(Asynchronous Multiprocessing),是指在一个计算机上汇集了一组指令集各异、功能各不相同的CPU集合,它们之间通常以松耦合的组织方式联系起来,各自负责处理不同的数据。
1、VxWorks6.9 SMP概述
VxWorks SMP是VxWorks的一个配置,设计用于对称多处理(SMP)系统。SMP VxWorks映像提供了与单处理器(UP)配置相同的通用功能。对于对称多处理,操作系统的一个实例控制多个处理单元。这与非对称多处理(AMP)系统不同,在AMP系统中,操作系统的一个单独实例在系统中的每个处理单元上执行。SMP改变了传统的基于优先级的多任务抢占式编程模式,因为它允许多个线程真正并发执行。这是因为操作系统的一个实例运行在并行执行的多个cpu上。当将代码从传统的多任务系统迁移到SMP系统时,必须考虑到这个基本区别。
为了运行VxWorks SMP,需要搞清楚以下概念:
(1)多核
系统必须包含至少两个能够完全独立执行的处理单元。
(2)共享内存
每个CPU必须看到完全相同的物理内存子系统。拥有共享内存意味着,在访问内存时,系统上执行的代码不需要考虑是哪个CPU在执行代码。也就是说,不像在松散耦合的多处理系统中那样,CPU的内存是本地的。
(3)原子操作
cpu必须能够使用内存位置上的原子操作彼此同步。这种能力是构建自旋锁的基础。自旋锁是SMP系统中重要的同步和互斥机制。
(4)缓存一致性
假设每个CPU都有一个或多个专用缓存,硬件必须保持这些缓存之间的一致性。这对于数据缓存尤其重要——对于指令缓存则不那么重要。如果在不同CPU上的不同数据缓存中的两个数据缓存线指向相同的内存位置,硬件应该管理这些缓存线的状态,以便每个CPU获得正确的值。如果一个CPU将一条线刷新到内存中,那么所有引用相同位置的其他缓存线都必须自动更新(无效,或刷新,取决于一致性算法)。
(5)一种cpu间中断的机制
处理器必须支持一个CPU中断另一个CPU的能力。这通常是通过全局中断控制器设备来完成的(参见配置中断控制器驱动程序)。必须有一种方法将处理器间中断(IPIs)设置为优先级高于所有其他中断。此外,根据目标硬件的不同,可以访问所有cpu的设备。也就是说,每个CPU应该能够访问所有设备,并且能够通过一个全局可编程中断控制器将这些设备的中断路由到任何一个CPU。
对称多处理(SMP)系统开发,建议使用vxbus的设备驱动程序。风河不提供SMP安全的遗留模型驱动程序。如果希望在SMP系统中使用遗留模型设备驱动程序,则必须确保该驱动程序是SMP安全的。
2、VxWorks6.9创建SMP工程
利用WorkBench3.3工作台创建一个SMP BSP项目:
(1)创建一个VxWorks映像项目(File>New->Project)
(2)在项目设置对话框中,单击BSP列表旁边的Browse按钮,浏览到您的BSP目录。
(3)在Options对话框中,选择内核中的SMP支持。
VxWorks SMP内核相关配置如表1所示。
表1 VxWorks SMP相关配置宏
WRS_CONFIG_SMP | Configuration | Kernel libraries have been built with SMP support. |
VX_SMP_NUM_CPUS | Parameter | Number of CPUs assigned to run the SMP image. |
INCLUDE_SMP_DEMO | Component | Include SMP demo code in the image. |
3、SMP多核任务机制
VxWorks SMP提供了CPU Affinity这种机制。通过这种机制可以将中断或者任务分配给指定的CPU执行。
(1)任务级 CPU Affinity
VxWorks SMP 具有将任务分配给指定 CPU 执行的能力。从另一个角度来说,即将指定CPU 预留给指定任务。
SMP 的默认操作——任何任务可以运行在任何 CPU 上——这会根据系统的整体性能而定。但是有些时候将指定任务分配给指定的 CPU 对系统性能是有帮助的。例如一个CPU上只运行一个单独的任务而不做其他事情,则这块 CPU 的 cache 中就只保存了这个任务所需要的数据和代码。这样做节省了任务在 CPU 之间切换的消耗。
当多个任务争夺一个spinlock时,如果这些任务运行在不同的CPU上,则会有大量的时间被浪费在等待spinlock上。若将争夺同一个 spinlock 的任务指定在同一个CPU 上运行,则这会给另一块 CPU 上执行其他程序带来便利。
关于任务级 CPU affinity 的使用方法如下:
a. 一个任务可以通过调用 taskCpuAffinitySet()设置自己的 CPU affinity,也可以设置其他任务的 CPU affinity;
b. 子任务会继承父任务的CPU affinity。一个任务中调用如下API就会自动继承CPUaffinity: taskSpawn(), taskCreate(), taskInit(), taskOpen(), taskInitExcStk()。任务级 CPU affinity 的 API 如表 2 所示。
表2 任务级CPU affinity API
API | 描述 |
STATUS taskCpuAffinitySet(int tid, cpuset_t newAffinity) | 分配一个任务在指定 CPU 上执行。 |
STATUS taskCpuAffinityGet(int tid, cpuset_t* pAffinity) | 获得指定任务在哪个 CPU 上执行。 |
taskCpuAffinitySet()和 taskCpuAffinityGet()都使用cpuset_t结构对CPU 信息进行标示。前者用于分配任务到指定 CPU;后者获取指定任务的cpu_set_t。CPUSET_ZERO()宏定义用于将 cpuset_t 清0(类似FD_ZERO),它必须被最先调用。CPUSET_SET()宏定义在 CPUSET_ZERO()之后使用。
任务级 CPU Affinity 示例:
#include <vxWorks.h> #include <vsbConfig.h> #include <stdio.h> #include <tickLib.h> #include <string.h> #include <stdlib.h> #include <eventLib.h> #include <taskLib.h> #include <vxLib.h> #include <fioLib.h> /* fioRdString */
#ifdef _WRS_CONFIG_SMP #include <private/cpcLibP.h> #include <logLib.h> #include <cpuset.h> #include <vxCpuLib.h> #endif
static void myCpu0Task(void) { int a = 0;
while(1) { a++; printf ("\n myCpu0Task running %d times on cpu%d\n", a, vxCpuIndexGet()); taskDelay(60);; } }
static void myCpu1Task(void) { int b = 0;
while(1) { b++; printf ("\n myCpu1Task running %d times on cpu%d\n", b, vxCpuIndexGet()); taskDelay(120);; } }
int affinityTaskDemo(void) { TASK_ID tid1, tid2; cpuset_t affinity1, affinity2;
/* Create the task1 but only activate it after setting its affinity */ tid1 = taskCreate ("Cpu0Task", 100, 0, 5000, (FUNCPTR)myCpu0Task, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (tid1 == (TASK_ID)NULL) return ERROR;
/* Clear the affinity1 CPU set and set index for CPU 0 */ CPUSET_ZERO(affinity1); CPUSET_SET(affinity1, 0);
if (taskCpuAffinitySet(tid1, affinity1) == ERROR) { taskDelete(tid1); return ERROR; }
/* Now let the task run on CPU 0 */ taskActivate(tid1);
/* Create the task2 but only activate it after setting its affinity */ tid2 = taskCreate ("Cpu1Task", 100, 0, 5000, (FUNCPTR)myCpu1Task, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); if (tid2 == (TASK_ID)NULL) return ERROR;
/* Clear the affinity2 CPU set and set index for CPU 2 */ CPUSET_ZERO(affinity2); CPUSET_SET(affinity2, 1);
if (taskCpuAffinitySet(tid2, affinity2) == ERROR) { taskDelete(tid2); return ERROR; }
/* Now let the task run on CPU 1 */ taskActivate(tid2);
return OK; }
|
上述SMP多核任务示例代码运行结果如下,可见结果符合预期。
myCpu0Task running 1 times on cpu0 myCpu0Task running 2 times on cpu0 myCpu1Task running 2 times on cpu1 myCpu0Task running 3 times on cpu0 myCpu0Task running 4 times on cpu0 myCpu1Task running 3 times on cpu1 myCpu0Task running 5 times on cpu0 myCpu0Task running 6 times on cpu0 myCpu1Task running 4 times on cpu1 myCpu0Task running 7 times on cpu0 myCpu0Task running 8 times on cpu0 myCpu1Task running 5 times on cpu1 myCpu0Task running 9 times on cpu0 myCpu0Task running 10 times on cpu0 myCpu1Task running 6 times on cpu1 myCpu0Task running 11 times on cpu0 myCpu0Task running 12 times on cpu0 myCpu1Task running 7 times on cpu1 myCpu0Task running 13 times on cpu0 |
(2)中断级 CPU Affinity
SMP硬件需要可编程中断控制设备。VxWorks SMP利用这些硬件可以分配中断到指定CPU。默认情况下,中断是在VxWorks的CPU 0中触发的。
通过中断级 CPU Affinity,可以将中断合理平均的分配到不同 CPU 上(而不是在一个CPU 上存在很多中断)。
运行时刻分配中断到指定CPU是在启动时发生的,当系统启动从 BSP 中读取中断配置信息的时候。中断控制器收到一条命令,该命令用于指示一条中断运行在指定的CPU上。
该小节内容将在后续的篇章里面详细介绍。
本文标签: 基于Zynq7000平台VxWorks69开发应用SMP多核任务篇
版权声明:本文标题:基于Zynq7000平台VxWorks6.9开发应用——SMP多核任务篇 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1732361918h1535460.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论