Lecture2 Memory Hierarchies and Matrix Multiplication
Start with single processors… Why?
Looking Under the Hood
-
Most applications run at <10% of the “peak” performance
-
Most of the performance is lost on a single processor, moving data
Why we care about serial performance?
With only using a single core, the program get 131x speed up by doing basic optimizations.
并行化低效率的串行代码,只会产生低效率的并行代码。线性加速不是必须的。矩阵乘法在并行化后,一般能够获得10倍加速。
Costs in modern processors
Idealized Uniprocessor Model
理想情况下,处理器支持变量:整数、float、double、指针、数组、结构体等
处理器在这些变量上支持运算操作:算数操作,逻辑操作等
处理器控制执行方式顺序:if、循环、函数调用等
理想开销:
-
Each operations(+, multiply) has roughly the same cost
-
reading/writing variables is “free”
但是现实情况下,变量们都是一个个在内存中的字节。
并且编译器将控制指令翻译成低级指令;硬件执行这些指令;
有些运算操作有比较相近的时钟周期,但是读和写操作成本是运算操作成本的 100 倍左右。
如果时钟频率为 1GHz,则一个时钟周期差不多 1 纳秒,但是访问主存的时钟周期差不多 100 ns,非常慢。
Compilers and assembly code
这部分讲的是编译器做的工作。包括冲突图等
编译器可以做的一些优化工作:
-
Unrolls loops (because control isn’t free)
-
Fuses loops (merge two together)
-
Interchanges loops (reorder)
-
Eliminates dead code (the branch never taken)
-
Reorders instructions to improve register reuse and more
-
Strength reduction (e.g., shift left rather than multiply by 2)
Memory hierarchies
More Realistic Uniprocessor Model
Memory accesses (load/store) have two costs
-
Latency: cost to load or store 1 word
-
Bandwidth: Average rate (bytes/sec) to load/store a large chunk or inverse time/byte
这两种评价方式的不同:
Memory Bandwidth Gap
下面这两张图讲的是计算量与带宽发展水平的比值、计算量与内存延迟的比值。计算量的需求增长已经远远甩开了内存的发展。
这张图使用的 log 的比值,图中的直线表示 bandwidth 的发展速度比 latency 的发展速度要慢很多(每 5 年左右慢一倍)。
这张图表示 memory latency 的发展速度,发展的比 bandwidth 还要慢。
Memory Hierarchy
内存包含了很多层,每一层的速度都比下一层块,都比上一层慢;
每层大小都比下一层小,比上一层大。
缓存基础
-
cache hit
-
cache miss
-
cache line length: number of bytes loaded together in one entry
-
associativity: direct-mapped/
Approaches to Handling Memory Latency
-
Reuse values in fast memory (bandwidth filtering)
-
temporal locality
-
-
Move larger chunks (achieve higher bandwidth)
-
spatial locality
-
-
Issue multiple reads/writes in single instruction (higher bw)
-
vector operations require access set of locations (typically neighboring)
-
-
Issue multiple reads/writes in parallel (hide latency)
-
prefetching issues read hint
-
delay writes
-
How much concurrency do you need?
-
Little’s Law: concurrency = latency x bandwidth
-
e.g. latency = 10 sec; bandwidth = 2 bytes / sec
-
requires 20 bytes in flight to hit bandwidth speeds
-
means finding 20 independent things to issue
-
一个更加实际点的例子:60ns延迟,带宽6.4GB/s,则一次最多处理384字节内容。如果分在6条缓存线上,为了使得系统满载,则六条缓存线要同时使用。
Parallelism in a single processor
什么是 pipeline?课堂内给出了洗衣店例子,不同步骤之间可以并行操作,执行长度之间比单独串行执行要短。
带宽提升:
-
带宽由流水线上最慢的阶段决定。此时峰值带宽每个步骤 40 min,就是 1.5 步每小时
-
当任务数量越来越多时,实际带宽越来越接近峰值带宽,收益越来越大。
Case study: Matrix multiplication
在许多问题中矩阵乘法都很重要。
-
许多问题的主题就是稠密矩阵乘法
-
和一些算法关联紧密
-
在一些深度学习中应用广泛
优化思想可以在很多其他问题中使用
优化方法和效果:
Naïve 方法中性能下降主要由于没有放进 cache 中
A Simple Model of Memory
假设只有两级结构,一个快,一个慢。
最初所有数据都在慢内存中:
-
m 是在快慢内存中移动的内存(字)数量
-
t_m 是 time per slow memory operation
-
f 是算数运算数量
-
t_f 是算术运算时间远远小于 t_m
-
CI 是计算密度 Computational Intensity = f / m = average number of flops per slow memory access
最快的时间应该是 f \times t_f 此时所有数据都在快速内存中
实际时间:f\times t_f+m\times t_m=f\times t_f\times(1+t_m/t_f\times 1/CI)
一些简单的假设
-
Constant peak computation rate
-
快速内存非常大,可以存下三个向量
-
快速内存的存取时间都是 0。
-
Ok for registers
-
Not for cache (even L1)
-
-
内存 latency 是个常数
Naïve Matrix Multiply
稍微优化一下
Blocked (Tiled) Matrix Multiply