深入理解并行编程2

原创
2018/04/24 21:31
阅读数 556

在共享内存系统中的多个处理器间传递消息是不是也更加耗时,这点并不一定

概述

流水线 CPU

  • (80年代初)典型的微处理器在处理下一条指令之前,至少需要三个时钟周期来完成本条指令
    1. 取值
    2. 解码
    3. 执行
  • (90年代末开始)CPU可以同时处理多条指令
    • 流水线
    • 带有长流水线的CPU想要达到最佳性能,就需要程序给出高度可预测的控制流
      • 分支预测
      • CPU 可以正确预测在大多数情况下代码循环结束后的分支走向
        • 循环,向量计算等情况
      • 流水线可以一直保持满负荷状态,CPU全速运行
        • 意外中断跳出执行,会影响性能
          • goto
          • if
          • exception
      • 当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 操作

速度慢

通信的代价

  • 分布式并行计算的程序则很可能遭遇网络通信延迟

开销

硬件体系结构

image

  • 上图是一个粗略的八核计算机系统概要图
  • 每个管芯(die)有两个 CPU 核
  • 每个核带有自己的高速缓存
  • 管芯内还带有一个互联模块
    • 使管芯内的两个核可以互相通信
  • 图中央的系统互联模块可以让四个管芯相互通信,并且将管芯与主存连接起来

数据以缓存行(cache line)为单位在系统中传输

  • 缓存行对应于内存中一个 2^n 大小的字节块
    • 大小通常为 32 到 256 字节之间
    • 当 CPU 从内存中读取一个变量到它的寄存器中时
      • 必须首先将包含了该变量的缓存行读取到 CPU 高速缓存
    • 同样地, CPU 将寄存器中的一个值存储到内存时
      • 不仅必须将包含了该值的缓存行读到 CPU 高速缓存
      • 还必须确保没有其他 CPU 拥有该缓存行的拷贝

比如,如果 CPU0 在对一个变量执行“比较并交换”(CAS)操作,而该变 量所在的缓存行在 CPU7 的高速缓存中,就会发生以下经过简化的事件序列:

  1. CPU0 检查本地高速缓存,没有找到该缓存行。
  2. 请求被转发到 CPU0 和 CPU1 的互联模块,检查 CPU1 的本地高速缓存,没有找到该缓存行。
  3. 请求被转发到系统互联模块,检查其他三个管芯,得知该缓存行被 CPU6和 CPU7 所在的管芯持有。
  4. 请求被转发到 CPU6 和 CPU7 的互联模块,检查这两个 CPU 的高速缓存,在 CPU7 的高速缓存中找到缓存行。
  5. CPU7 将该缓存行发送给所属的互联模块,并且刷新自己高速缓存中的缓存行。
  6. CPU6 和 CPU7 的互联模块将该缓存行发送给系统互联模块。
  7. 系统互联模块将该缓存行发送给 CPU0 和 CPU1 的互联模块。
  8. CPU0 和 CPU1 的互联模块将该缓存行发送给 CPU0 的高速缓存。
  9. CPU0 现在可以对高速缓存中的变量执行 CAS 操作了。

操作的开销

现代微处理器来说每时钟周期执行多条指令是常见的

原子操作/CAS/同步锁,指令数量相差,可能是指数级别的

硬件优化

3D 集成

3 Dimensional Integration

  • 是一种将极薄的硅制管芯垂直层叠起来的工艺

缩短硬件线路的长度,增加集成度

最重要的好处是降低系统的光程(path length)

专用加速器

很多微处理器提供专用的操作指令

  • 向量计算指令

软件设计要点

  • 并行算法必须将每个线程设计成尽可能独立运行的线 程
    • 越少使用线程间通信手段,应用程序的性能和可扩展性就会更好
      • 原子操作
        • 同样需要跨线程,跨CPU核心
        • 缓存行失效
      • 其它消息传递方法
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部