关于SMP系统中的CC问题
NeilWong ()
一般的多通道并行处理系统分为密切耦合的SMP(Symmetrical Multi-Processing)系统和并非密切耦合的多节点处理系统,当然,如果单纯只是从系统资源的利用角度来讲,SMP系统因为多处理器共享全部的外围设备,因此相比多节点处理系统而言,其具备成本上和体积上的重大优势,因此目前流行的微处理器架构也已经将Multi-Threads和Multi-Core作为以后主要的发展方向,其包括Intel的Core 2 Duo和AMD的Athlon64 x2等多核心架构,其本质应该都属于或接近于SMP系统。
而传统的SMP系统,因为共享全部的外围设备,其必然存在CC(Cache Coherence)和MC(Memory Coherence)问题,多个核心必然会为了抢夺资源而发生竞争。
当然,目前的多核系统已经为提高多核的利用效率进行了很多的Hardware-Architecture方面的改进工作,例如AMD的多核处理器在多核芯片内部就已经利用申请序列的方式实现了多核的CC和MC问题,在此就不做详细分析了。
本文只是以早期的比较简陋的SUN4M CPU为例讲解一下多CPU的CC问题,供大家参考和学习。
Cache的概念是为了提高系统效率,减少访存周期而提出的,其一般速度比Memory快很多,有些系统将Cache做在CPU内部,其可以具备和CPU相同的时钟速度。当应用程序或Linux内核需要经常读取某地址的内容时,系统仲裁器(一般为Hardware)就会将该地址和其内容存放在相应的Cache缓冲区中,其一般情况下是存放一段连续的地址内容,并根据某种置换策略来定期维护和更新Cache。这样当应用程序经常读取该地址时,系统将不通过访存就可以快速得到其内容,提高了系统效率。
那么为什么针对多CPU系统就会存在Cache一致性的问题呢?
这是因为,针对单CPU系统,Cache中的数据和Memory中的实际数据是随时随地都可以保持一致的,但如果是多个CPU系统,这样的情况就不一定可以保证了。
这是为什么呢?
因为针对SMP系统,Memory是属于多个CPU的,并非只属于其中的某个CPU,因此就有可能会出现下列情况: 其中的某个CPU (CPU A)修改了Memory中某个地址的数据,但该地址正好存放于另外一个CPU (CPU B)的Cache中,如果此时该CPU (CPU A)的修改动作并没有通知拥有该地址 内容Cache的CPU (CPU B),CPU B将会发生读取该地址内容数据出错的问题。这就是Cache一致性问题,也就是CC问题。
查看Linux的内核代码,我们可以有更清楚的认识.
主CPU启动并完成必要的工作之后,当系统中的CONFIG_SMP选项为True,则其在特定的时间段会执行启动其他CPU的过程,详细程序段在 init/main.c 的start_kernel->init->smp_init函数中.
此时将执行某个特定架构的CPU启动过程,以SUN4M为例,其将执行smp4m_boot_one_cpu函数,其主要过程是为新CPU分配一定的环境,例如新CPU的MMU表地址,current_thread指针,新CPU需要跳到的地址等等参数,利用BIOS提供的多CPU结点信息和BIOS提供的启动某个CPU的函数指针来启动某个CPU.相应的函数为: (其中的entry为该CPU需要跳到的地址)
prom_startcpu(cpu_node,
&smp_penguin_ctable, 0, (char *)entry);
启动过程在此不做详细解释,我们主要关心下面的程序段:
/* wheee... it's going... */
for(timeout = 0; timeout < 10000; timeout++) {
if(cpu_callin_map[i])
break;
udelay(200);
}
if (!(cpu_callin_map[i])) {
printk("Processor %d is stuck.\n", i);
return -ENODEV;
}
当主CPU发出了启动某个次CPU的命令后,其将等待cpu_callin_map[]中的某一位是否被置位,该置位动作将由需要启动的CPU来完成,如果在规定时间内,次CPU并没有启动的话,则主CPU等待一定时间后显示错误信息退出。
次CPU的引导过程可以查看trampoline.S文件,其被唤醒启动后,将设置自己的中断向量表,初始化各种寄存器,Cache等等。最后将调用smp4m_callin函数,在该函数中次CPU将利用原子命令swap给相应的cpu_callin_map[cpu]赋值为1。然后等待smp_commenced_mask的相关位改变.(实际上是等待主CPU对该bit的修改动作)
/* Allow master to continue. */
swap(&cpu_callin_map[cpuid], 1);
...
while (!cpu_isset(cpuid, smp_commenced_mask))
mb();
...
如果主CPU侦测到次CPU的修改动作,其将正常退出,并执行以下程序段:
if (!ret) {
cpu_set(cpu, smp_commenced_mask);
while (!cpu_online(cpu))
mb();
}
如果设计的SUN 4M系统存在CC问题的话,即便次CPU修改了cpu_callin_map中的相应位,但主CPU并不知道,其仍然从自己的Cache中取到cpu_callin_map的原值0, 将造成其超时退出,并进而显示启动次CPU出错。
从上面的程序段我们也可以发现,当次CPU启动时,其需要多次和主CPU之间发生信息同步,CC的硬件设计也需要多次得到验证。
因此我们在实际的多CPU操作和内核处理过程中,一定要关心CC问题,这样出现启动其他CPU出错时不仅需要查看其是否真正被启动,还需要考虑CC是否存在硬件设计问题。
阅读(1552) | 评论(1) | 转发(0) |