CPU的设计是用来运行少量比较复杂的任务(latency oriented design),GPU的设计则是用来运行大量比较简单的任务(throughput oriented design)。CPU具有powerful ALU(reduced operation latency),lager caches(convert long latency memory access to short latency cache accesses),Sophisticated control(branch predication、data prefecth)。GPU具有energy efficient ALU(many long latency but heavily pipelined for high throughput、require massive number of threads to hide latency)、small cache(to boost memory throughput)、simple control(No branch predication/data prefetch)
尤其需要注意GPU的cache是为了合并访问的!!当连续的线程发出读取内存的指令时,读取操作会被合并或组合在一起执行!由于合并,内存读取会返回整组线程所需要的数据。
关于缓存:
CPU遵循缓存一致性:一个内存的写操作需要通知所有核的各个级别的缓存。无论何时,所有处理器核看到的内存视图是完全一样的。随着处理器中核的数量的增加,这个“通知”开销也随之增大,使得缓存一致性成为限制处理器中核数不能太多的一个重要因素。缓存一致最坏的情况:一个内存写操作会强迫所有核的缓存都进行更新,因此每个核都要对相邻的内存单元进行写操作。
GPU不遵循缓存一致性:一个内存的写操作不会更新其它核的缓存。所以GPU能够具有很多的核心(流处理器簇)。
关于执行方式:
CPU大多采用SIMD的方式,而GPU采用SIMT的方式
SIMT是SIMD的线程等效项,都使用单一指令控制多个处理元素,SIMD使用执行单元或向量单元,而SIMT对其进行扩展以利用线程,不需要将数据凑成向量单元。在SIMT中,多个线程对不同的数据集执行相同的指令(也可以是向量化指令)。SIMT的主要优点是它减少了指令预期带来的等待时间(取一个指令,并将指令广播到线程束warp中所占用的所有流处理器中)。每当GPU需要执行特定指令时,都会从内存中获取数据和指令,在这种情况下,需要使用同一条指令执行的所有数据集将使用处理器可用的各种线程同时预取并同时执行。SIMD中向量中的元素相互之间可以*通信,因为它们存在于相同的地址空间(如CPU的某一个寄存器中),而SIMT的向量中的元素存在于多个线程之间,而且多个线程中寄存器都是私有的,线程之间只能通过共享内存或同步机制进行通信。
分支处理:
在cpu上,指令流通常都会被预提取,然后放入cpu的指令管线中。如果预测错误,cpu则需要重新执行预测指令,然后获取另一个分支的指令,再将其放入指令管线中。
对于gpu来说,gpu会使用一个线程执行分支1,另一个线程执行分支2。对于不满足分支条件的分支,GPU会在执行这块代码的时候将它们设置为未**状态。后续执行的时候,如果这个不满足条件的线程如果满足当前的分支条件则会被再次**。
寄存器用法:
cpu上寄存器远少于GPU,cpu通过寄存器重命名和栈来执行多线程,为了运行一个新任务,cpu需要进行上下文切换,将当前所有寄存器的状态保存到栈中。gpu不使用寄存器重命名机制,而是致力于为每一个线程都分配真实的寄存器。因此当需要上下文切换时,所需要的操作就是将当前寄存器组的指针更新,指向下一个执行的线程寄存器组。