zoukankan      html  css  js  c++  java
  • Branch Prediction 与 Branch Predication的区别

        Branch PredictionBranch Predication都是针对程序分支语句影响硬件执行效率而提出的技术。Branch Prediction应用于CPU,目标是保证最高的线程执行效率。Branch Predication应用于SPMD结构的运算设备,这类设备以吞吐量为首要目标,GPU就是这类设备的代表。

    Branch Prediction

        Branch Prediction,即分支预测,目的是保证大部分时间下CPU流水线都处于满负荷状态,保证正在执行的线程以最高效率运行。CPU流水线可大致划分为4个阶段:指令预取、指令解码、执行和结果回写。当程序代码出现条件分支语句时,条件分支语句的下条指令直到条件结果计算完毕后才能确定。在结果计算完毕前,CPU流水线都无法进行指令预取和指令解码(这是因为无法确定下一条指令),也就是流水线stall了。为了解决流水线stall,提升执行效率,CPU的分支预测硬件模块在条件结果计算完毕前,根据程序的历史运行记录,预判下一条指令的位置并将其应用于流水线。如果条件结果计算符合预期或者说预判正确,CPU的流水线就不会stall,执行效率最高。

        如果CPU不引入分支预测,那么,条件分支语句的执行效率永远是最低(因为流水线必然stall),引入分支预测后,CPU流水线就会有一定几率不stall,提升了执行效率,特别地,当程序编写时有意迎合CPU分支预测机制,那么程序就能高效的执行,例如对一个int数组内大于100的元素进行操作,那么一个已排序的数组跟一个没有排序的数组执行相同的代码,执行效率显然是已排序数组的情况下高。下面是伪代码:

    for (int i in IntArray)

    {

        if (i > 100)

        {

            // do 

        }

    }

    当这段代码应用于已排序的数组时,CPU分支预测失败的情况(也就是说流水线stall)可能只发在i满足大于100这个条件的前几次循环里,而大部分时间,CPU的流水线都是满载运行。如果数组没有排序,CPU分支预测失败的情况就会很普遍,代码的运行效率就会下降。

    最后,分支预测需要硬件模块的支持,所以必然会提升硬件复杂度和功耗。

    Branch Predication

        首先解析SPMD及对应的硬件结构。SPMD就是Single Program Multiple Data,可以理解为SIMD的扩展。在SIMD情况下,对多数据的处理只限于单条指令,而SPMD情况下,程序编写者可以按需要编写一个处理多数据的程序,这个程序在多个线程中并行执行。GPUShader程序就是SPMD的一个例子。

        硬件结构上,将多个ALU绑定一起,共享一个PC(Program Counter),就能组成一个SPMD运算单元,例如NV GPUSMXAMD GPUCU都是SPMD运算单元。一个SPMD运算单元包含的ALU数量决定了线程的理论最大并行数量。为了简化硬件结构,降低功耗,SPMD运算单元并没有为每个ALU配备分支预测硬件模块,更重要的是,在共享PC前提下,为每个ALU配备分支预测硬件模块对执行效率根本没有任何提升。

        条件分支的出现将导致SPMD运算单元内ALU的执行路径不一致。由于这些ALU共享同一个PC,所以,要求ALU并行执行不同路径是不可能的。要在SPMD上实现条件分支,就需要编译器对条件分支程序代码进行等价变换,把不一致的执行路径转换成一致的执行路径,看下面这个例子:

    A.原始代码,执行路径不一致

    int condition = threadid + 100;

    int result = 0

    if (condition > 220)

    {

        result += 10;

    }

    else

    {

        result -= 10

    }

    B.一种可能的转换后的代码

    int result = 0;

    int condition = threadid + 100;

    int temp1 = result + 10;

    int temp2 = result - 10;

    result = (condition > 220) ? temp1 : temp2;

    转换后的代码在每个ALU上的执行路径都一致,不存在条件分支。两个分支都执行,根据条件选择接受哪个分支的结果,就叫Branch Predication分支断定。

        Branch Predication需要硬件指令集的支持,支持Branch Predication的指令根据某些状态寄存器的值,执行不一样的逻辑,例如x86cmov系列指令,又例如某些厂商GPU指令会根据状态寄存器的值选择执行还是NOP(传说中的指令级多态?)

        使用Branch Predication转换后的代码,执行时间比条件分支代码长,因为转换后的代码,所有分支都会执行。于是,有人提出了一种类似动态指令融合的技术,在SPMD里既可保留条件分支,也保证执行效率——Dynamic warp formation。

    Dynamic warp formation

        Warp就是线程组threadgroup的意思,是SPMD运算单元的最小并行粒度,最小调度单位(NV称为warpAMD称为wavefront)。例如,NVwarp32线程,就是说,在SPMD运算单元内,每32ALU并行执行相同的指令。也可以把warp看作是一条硬件线程,它的执行宽度为32ALU。相对于CPU的线程,其执行宽度通常为1ALU。当然了,GPU一个ALU的宽度可达4*64 bit,那么,GPU一个warp的宽度就是32*4*64 bit,并且,GPU在同一时间可执行多个warp,所以单比吞吐量,GPUCPU不在一个数量级。

        以下均使用warp表示线程组,并以32线程为一个warp为前提展开。回顾SPMD出现条件分支的情况,例如出现分支A及分支B,那么,warp32个线程既执行分支A也执行分支B,最后,这些线程根据分支条件的结果选择接受A的结果还是接受B的结果。无论如何,总有一部分结果对于这些线程来说是没有意义的。

        把一个warp按分支路径拆分成多个子warp,并行执行,也不会带来任何效率的提升,因为拆分的子warp宽度肯定不够32。如果把这种思路应用于多个warp的话,情况会有所不同,例如warp1warp2warp3执行相同的代码并到达相同条件分支语句,分支将产生路径A和路径B,按路径拆分出的子warp重组成新warp并行执行,分支路径执行完毕后还原为原来的warp,这样就能高效应对条件分支,不会出现没有意义的运算,这就是Dynamic warp formation,更详细的介绍可自行google

  • 相关阅读:
    树莓派笔记——了解与购买树莓派(1)
    SQLserver 备份和还原 失败
    lua coroutine
    lua for循环
    leetcode 46. 全排列
    sprintf、vsprintf、sprintf_s、vsprintf_s、_snprintf、_vsnprintf、snprintf、vsnprintf 函数辨析
    rapidxml的常见读写操作
    C++11 可变参数模板构造string列表
    Fedora 28 设置yum代理
    Linux命令计算文件中某一列的平均值
  • 原文地址:https://www.cnblogs.com/rickerliang/p/2969893.html
Copyright © 2011-2022 走看看