在共享内存系统中的多个处理器间传递消息是不是也更加耗时,这点并不一定
概述
流水线 CPU
- (80年代初)典型的微处理器在处理下一条指令之前,至少需要三个时钟周期来完成本条指令
- 取值
- 解码
- 执行
- (90年代末开始)CPU可以同时处理多条指令
- 流水线
- 带有长流水线的CPU想要达到最佳性能,就需要程序给出高度可预测的控制流
- 分支预测
- CPU 可以正确预测在大多数情况下代码循环结束后的分支走向
- 循环,向量计算等情况
- 流水线可以一直保持满负荷状态,CPU全速运行
- 意外中断跳出执行,会影响性能
- goto
- if
- exception
- 意外中断跳出执行,会影响性能
- 当CPU难以预测分支走向时
- 要么,等待控制流进行到可以知道分支走向的时候
- 要么,只能猜测
- 无论哪一种都会导致,流水线空着
- CPU需要等待流水线被新指令填充
- 降低了CPU的性能
- CPU需要等待流水线被新指令填充
内存引用
- 现代CPU,从内存读取数值的时间要远多于CPU执行指令的时间
- 即:内存读取是很耗时的操作
- 缓存
- 多级
- 但是只有高度可预测的数据访问模式才能让缓存发挥最大效用
- 难以预测
- 链表遍历
- 难以预测
- 多线程会为 CPU 带来额外的性能障碍
原子操作
- 严格来讲,并不是指CPU一次执行一条汇编操作
- 虽然某些指令实际上不是原子操作,CPU使用了一些聪明的小手段,让这些操作看起来是原子的
- 也有些指令,流水线必须等待甚至需要清空,以便指令原子操作完成
- 通常只适用于单个数据元素
- 由于许多并行算法都要求,在更新多个数据元素时保证正确的执行顺序,因此绝大多数 CPU 都提供了内存屏障
内存屏障
spin_lock(&mylock); // 1
a = a + 1; // 2
spin_unlock(&mylock); // 3
- 为了保障line 2的数据安全
- 锁操作原语必须包含或显式或隐式的内存屏障
- 内存屏障的作用是防止 CPU 为了提升性能而进行的乱序执行
- 所以内存屏障几乎一定会降低 CPU 性能
缓存失效
Cache Miss
- 缓存缺失
- 现代 CPU 使用大容量高速缓存来减少内存速度慢带来的性能损耗
- 但是, CPU 高速缓存事实上对多 CPU 间,频繁访问的变量起反效果
- 当某个 CPU 想去更改变量的值时,极有可能该变量的值刚被其他 CPU 修改过
- 这种情况下,变量存在于其他 CPU 而不是当前CPU 的缓存中,这将导致代价高昂的缓存失效
I/O 操作
速度慢
通信的代价
- 分布式并行计算的程序则很可能遭遇网络通信延迟
开销
硬件体系结构
- 上图是一个粗略的八核计算机系统概要图
- 每个管芯(die)有两个 CPU 核
- 每个核带有自己的高速缓存
- 管芯内还带有一个互联模块
- 使管芯内的两个核可以互相通信
- 图中央的系统互联模块可以让四个管芯相互通信,并且将管芯与主存连接起来
数据以缓存行(cache line)为单位在系统中传输
- 缓存行对应于内存中一个 2^n 大小的字节块
- 大小通常为 32 到 256 字节之间
- 当 CPU 从内存中读取一个变量到它的寄存器中时
- 必须首先将包含了该变量的缓存行读取到 CPU 高速缓存
- 同样地, CPU 将寄存器中的一个值存储到内存时
- 不仅必须将包含了该值的缓存行读到 CPU 高速缓存
- 还必须确保没有其他 CPU 拥有该缓存行的拷贝
比如,如果 CPU0 在对一个变量执行“比较并交换”(CAS)操作,而该变 量所在的缓存行在 CPU7 的高速缓存中,就会发生以下经过简化的事件序列:
- CPU0 检查本地高速缓存,没有找到该缓存行。
- 请求被转发到 CPU0 和 CPU1 的互联模块,检查 CPU1 的本地高速缓存,没有找到该缓存行。
- 请求被转发到系统互联模块,检查其他三个管芯,得知该缓存行被 CPU6和 CPU7 所在的管芯持有。
- 请求被转发到 CPU6 和 CPU7 的互联模块,检查这两个 CPU 的高速缓存,在 CPU7 的高速缓存中找到缓存行。
- CPU7 将该缓存行发送给所属的互联模块,并且刷新自己高速缓存中的缓存行。
- CPU6 和 CPU7 的互联模块将该缓存行发送给系统互联模块。
- 系统互联模块将该缓存行发送给 CPU0 和 CPU1 的互联模块。
- CPU0 和 CPU1 的互联模块将该缓存行发送给 CPU0 的高速缓存。
- CPU0 现在可以对高速缓存中的变量执行 CAS 操作了。
操作的开销
现代微处理器来说每时钟周期执行多条指令是常见的
原子操作/CAS/同步锁,指令数量相差,可能是指数级别的
硬件优化
3D 集成
3 Dimensional Integration
- 是一种将极薄的硅制管芯垂直层叠起来的工艺
缩短硬件线路的长度,增加集成度
最重要的好处是降低系统的光程(path length)
专用加速器
很多微处理器提供专用的操作指令
- 向量计算指令
软件设计要点
- 并行算法必须将每个线程设计成尽可能独立运行的线 程
- 越少使用线程间通信手段,应用程序的性能和可扩展性就会更好
- 原子操作
- 同样需要跨线程,跨CPU核心
- 缓存行失效
- 锁
- 其它消息传递方法
- 原子操作
- 越少使用线程间通信手段,应用程序的性能和可扩展性就会更好