【问题标题】:Branch and predicated instructions分支和谓词指令
【发布时间】:2015-07-29 02:23:40
【问题描述】:

Section 5.4.2 CUDA C 编程指南指出分支分歧由“分支指令”或在某些条件下“谓词指令”处理。我不明白两者之间的区别,以及为什么一个比另一个带来更好的性能。

This comment 建议分支指令导致更多的执行指令,由于“分支地址解析和获取”而停止,以及由于“分支本身”和“为分歧而记账”导致的开销,而谓词指令仅产生“进行条件测试和设置谓词的指令执行延迟”。为什么?

【问题讨论】:

    标签: cuda simd


    【解决方案1】:

    指令谓词是指一条指令由一个线程根据谓词有条件地执行。谓词为真的线程执行指令,其余线程不执行任何操作。

    例如:

    var = 0;
    
    // Not taken by all threads
    if (condition) {
        var = 1;
    } else {
        var = 2;
    }
    
    output = var;
    

    会导致(不是实际的编译器输出):

           mov.s32 var, 0;       // Executed by all threads.
           setp pred, condition; // Executed by all threads, sets predicate.
    
    @pred  mov.s32 var, 1;       // Executed only by threads where pred is true.
    @!pred mov.s32 var, 2;       // Executed only by threads where pred is false.
           mov.s32 output, var;  // Executed by all threads.
    

    总而言之,这是if 的 3 条指令,没有分支。效率很高。

    具有分支的等效代码如下所示:

           mov.s32 var, 0;       // Executed by all threads.
           setp pred, condition; // Executed by all threads, sets predicate.
    
    @!pred bra IF_FALSE;         // Conditional branches are predicated instructions.
    IF_TRUE:                    // Label for clarity, not actually used.
           mov.s32 var, 1;
           bra IF_END;
    IF_FALSE:
           mov.s32 var, 2;
    IF_END:
           mov.s32 output, var;
    

    注意它有多长(if 的 5 条指令)。条件分支需要禁用部分扭曲,执行第一条路径,然后回滚到扭曲发散的点并执行第二条路径,直到两者收敛。它需要更长的时间,需要额外的簿记,更多的代码加载(特别是在有很多指令要执行的情况下),因此需要更多的内存。所有这些都使得分支比简单的谓词慢。

    实际上,在这个非常简单的条件赋值的情况下,编译器可以做得更好,只需 2 条指令用于 if

    mov.s32 var, 0;       // Executed by all threads.
    setp pred, condition; // Executed by all threads, sets predicate.
    selp var, 1, 2, pred; // Sets var depending on predicate (true: 1, false: 2).
    

    【讨论】:

    • 如果我理解正确:在这两种情况下,warp 都必须按顺序执行两条路径,但是由于额外的bra 指令,分支指令的分支分歧惩罚甚至更高?您能否详细说明簿记方面,不是所有线程都有自己的程序计数器吗?对了,你不是说代码中有分支的@!pred bra IF_FALSE; 吗?
    • 在 SM 5.x 和旧设备上,warp 中的所有线程共享相同的程序计数器。经线维护活动通道(线程)的掩码。每个线程都有自己的谓词和控制代码寄存器。分支的代价是(a)解决分支的延迟和(b)获取下一条指令的延迟。如果谓词比上述两个成本便宜,编译器将使用谓词。这通常是 6-10 条指令。如果分支是多路发散的,则成本会更高,因为分支 (BRX) 必须执行多次。
    猜你喜欢
    • 2014-03-17
    • 1970-01-01
    • 2014-09-17
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多