首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux 和对称多处理(2)

Linux 和对称多处理(2)

内核配置为了在支持 SMP 的硬件上通过 Linux 使用 SMP,必须适当地配置内核。内核配置期间必须启用 CONFIG_SMP 选项,以使内核感知 SMP。通过在多 CPU 主机上运行感知 SMP 的内核,可使用 proc 文件系统了解处理器的数目及类型。
首先,使用 grep 在 /proc 下的 cpuinfo 文件中检索处理器的数目。如清单 1 所示,使用计数选项(-c)来统计以单词 processor 开头的行。然后显示 cpuinfo 文件的内容。显示的示例来自一个二芯片的 Xeon 主板。
清单 1. 使用 proc 文件系统检索 CPU 信息
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
46
47
48
49
50
51
52
53
54
55
56
57
58
mtj@camus:~$ grep -c ^processor /proc/cpuinfo
8
mtj@camus:~$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 15
model           : 6
model name      : Intel(R) Xeon(TM) CPU 3.73GHz
stepping        : 4
cpu MHz         : 3724.219
cache size      : 2048 KB
physical id     : 0
siblings        : 4
core id         : 0
cpu cores       : 2
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 6
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr
pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm
pbe nx lm pni monitor ds_cpl est cid xtpr

bogomips        : 7389.18

...

processor       : 7
vendor_id       : GenuineIntel
cpu family      : 15
model           : 6
model name      : Intel(R) Xeon(TM) CPU 3.73GHz
stepping        : 4
cpu MHz         : 3724.219
cache size      : 2048 KB
physical id     : 1
siblings        : 4
core id         : 3
cpu cores       : 2
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 6
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr
pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm
pbe nx lm pni monitor ds_cpl est cid xtpr

bogomips        : 7438.33

mtj@camus:~$




SMP 和 Linux 内核在 Linux 2.0 的早期,SMP 支持由一个 “大锁” 组成,这个 “大锁” 对跨系统的访问进行串行化。对于 SMP 支持的改进缓慢地进行着,但是直到 2.6 内核才显示出 SMP 的威力。
2.6 内核引入了新的 O(1) 调度程序,它包含更好的 SMP 系统支持。关键在于能在可用 CPU 之间进行负载平衡,同时维持亲合性以提高缓存效率。回顾图 4,当任务与单个 CPU 相关联时,如果将其移到另一个 CPU,就需要为该任务清空缓存。这就增加了任务的内存访问延迟,这些时间用来将其数据移入新 CPU 的内存中。
2.6 内核为每个处理器维护两个 runqueue(过期的和活动的 runqueue)。每个 runqueue 支持 140 个优先级,前面的 100 个用于实时任务,而后面的 40 个用于用户任务。任务分时间片执行,在使用它们分配到的时间片时,这些任务被从活动的 runqueue 移至过期的 runqueue。这就为所有的任务提供了公平访问 CPU 的机会(仅根据每个 CPU 锁定)。
利用每个 CPU 的任务队列,可以根据系统中所有 CPU 的负载进行负载平衡。每 200 毫秒,调度程序就执行一次负载平衡调节,以便重新分配任务负载,维持处理器之间的平衡。有关 Linux 2.6 调度程序的更多信息,请参阅 参考资料 部分。
用户空间线程:使用 SMP 的功能为使用 SMP,需要在 Linux 内核中执行大量工作,但仅靠操作系统本身还不够。回顾一下,SMP 的能力取决于 TLP。单个单片(非线程化的)程序不能使用 SMP,但是 SMP 可在由核心之间分布的多个线程组成的程序中使用。当一个线程由于等待完成 I/O 处理而被延迟时,另一个线程可执行一些有用的工作。这样,线程之间互相协作,隐藏了各自的延迟时间。
Portable Operating System Interface(POSIX)线程是构建可利用 SMP 的线程化应用程序的一种好方法。POSIX 线程提供了线程化机制和共享内存。当调用程序创建若干线程时,每个线程得到自身的堆栈(本地变量和状态),但共享父线程的数据空间。创建的所有线程共享这个相同的数据空间,但是问题就出在这里。
为支持多线程访问共享内存,需要具备协调机制。POSIX 提供了互斥函数来创建临界区,用于实施单线程对对象(一块内存)的独占访问。不这样做可能导致内存破坏(由于多个线程执行了不同步的操作)。清单 2 演示了如何使用 POSIX 互斥函数创建临界区。
清单 2. 使用 pthread_mutex_lock 和 pthread_mutex_unlock 创建临界区
1
2
3
4
5
6
7
8
9
10
11
pthread_mutex_t crit_section_mutex = PTHREAD_MUTEX_INITIALIZER;

...

pthread_mutex_lock( &crit_section_mutex );

/* Inside the critical section. Memory access is safe here
* for the memory protected by the crit_section_mutex.
*/

pthread_mutex_unlock( &crit_section_mutex );




如果多个线程在完成上面的初始调用后尝试锁定信号量,则这些线程会被阻塞,它们的请求进入队列,直到执行 pthread_mutex_unlock 调用。
SMP 的内核变量保护如果处理器中的多个核心为内核并发运作,则希望避免共享那些特定于给定核心的数据。出于此原因,2.6 内核引入了 per-CPU 变量的概念,这些变量与单个 CPU 相关联。这允许将某个 CPU 通常访问的变量声明为该 CPU 专有的变量。使用此方法使锁定需求最小化并提高了性能。
per-CPU 变量由 DEFINE_PER_CPU 宏进行定义,需要为该宏提供类型和变量名称。由于宏的运作方式与 l-value 类似,因此也可在宏中进行变量的初始化。下面的示例(来自 ./arch/i386/kernel/smpboot.c)定义了一个变量,它用于表示系统中每个 CPU 的状态。
1
2
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state) = { 0 };




该宏创建了一个变量数组(每个 CPU 一个变量)。要访问 per-CPU 变量,需将 per_cpu 宏和 smp_processor_id 结合使用,后者是一个函数,用于返回当前执行代码的当前 CPU 的标识符。
1
per_cpu( cpu_state, smp_processor_id() ) = CPU_ONLINE;




内核提供了用于 per-CPU 锁定和变量动态分配的其他函数。可在 ./include/linux/percpu.h 中查找这些函数。
结束语当处理器频率达到其极限时,一种流行的提高性能的方法是添加更多的处理器。在早期,这就意味着将更多的处理器添加到主板上,或将多个独立计算机集群到一起。现在,芯片级多处理能够在单个芯片上提供更多的 CPU,由于减少了内存延迟,因而可获得更高的性能。
您会发现 SMP 系统不仅存在于服务器中,还存在于桌面上,特别是在引入虚拟化以后。跟大多数先进技术一样,Linux 提供 SMP 支持。内核负责完成可用 CPU 间的负载优化(从线程到虚拟化操作系统)。惟一要做的就是确保应用程序可被充分地多线程化以便使用 SMP 的能力。
返回列表