处理器效率低,几乎相同的CUDA内核

时间:2018-04-08 22:30:26

标签: performance cuda gpgpu nvprof

我已经创建了三个合成的CUDA内核,它们几乎都只进行算术运算。除了每个内核执行不同数量的操作外,所有三个内核都是相同的。内核#1执行8次操作,内核#2执行16次操作,内核#3执行32次操作。以下是所有三种内核的CUDA内核实现。

内核#1:

#ifndef kernelWGSXMAPIXLLXOPS8_H_
#define kernelWGSXMAPIXLLXOPS8_H_

__global__ void WGSXMAPIXLLXOPS8 (const float *GIn, float *GOut, const float M, const float N, const float P) {

        int gid = blockIdx.x * blockDim.x + threadIdx.x;

        float MF = (float) M;
  float NF = (float) N;
  float PF = (float) P;

  for (int lcdd = 0; lcdd < 1; lcdd++) {
    float temp1 = 1.0;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    ... // 8 FMA operations
    temp1 = temp1 * MF + temp1;

    GOut[gid] = temp1;
  }

}

void WGSXMAPIXLLXOPS8_wrapper (const float *GIn, float *GOut,
                               const float M, const float N, const float P,
                               int numBlocks, int threadPerBlock) {
        WGSXMAPIXLLXOPS8<<<numBlocks, threadPerBlock>>> (GIn, GOut, M, N, P); 
}


#endif     

内核#2:

#ifndef kernelWGSXMAPIXLLXOPS16_H_
#define kernelWGSXMAPIXLLXOPS16_H_

__global__ void WGSXMAPIXLLXOPS16 (const float *GIn, float *GOut, const float M, const float N, const float P) {

        int gid = blockIdx.x * blockDim.x + threadIdx.x;

        float MF = (float) M;
  float NF = (float) N;
  float PF = (float) P;

  for (int lcdd = 0; lcdd < 1; lcdd++) {
    float temp1 = 1.0;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    ... // 16 FMA operations
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;

    GOut[gid] = temp1;
  }

}

void WGSXMAPIXLLXOPS16_wrapper (const float *GIn, float *GOut,
                               const float M, const float N, const float P,
                               int numBlocks, int threadPerBlock) {
        WGSXMAPIXLLXOPS16<<<numBlocks, threadPerBlock>>> (GIn, GOut, M, N, P); 
}

#endif

内核#3:

#ifndef kernelWGSXMAPIXLLXOPS32_H_
#define kernelWGSXMAPIXLLXOPS32_H_

__global__ void WGSXMAPIXLLXOPS32 (const float *GIn, float *GOut, const float M, const float N, const float P) {

        int gid = blockIdx.x * blockDim.x + threadIdx.x;

        float MF = (float) M;
  float NF = (float) N;
  float PF = (float) P;

  for (int lcdd = 0; lcdd < 1; lcdd++) {
    float temp1 = 1.0;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    ... // 32 FMA operations
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;

    GOut[gid] = temp1;
  }

}

void WGSXMAPIXLLXOPS32_wrapper (const float *GIn, float *GOut,
                               const float M, const float N, const float P,
                               int numBlocks, int threadPerBlock) {
        WGSXMAPIXLLXOPS32<<<numBlocks, threadPerBlock>>> (GIn, GOut, M, N, P); 
}

#endif

线程总数已设置为16384,块大小为256.我已经计算了每个内核的GFlops总数,并且等于20.44,56.53和110.12 GFlops。我试图想出一个解释,但没有任何想法。所以我尝试使用nvprof并监控所有指标。所有指标几乎相等,以下是一些对我来说很重要的指标(我还包括内核1到3的结果):

sm_efficiency_instance:   14.99, 16.78, 19.82 %
ipc_instance:             0.57 , 0.93 , 1.53   
inst_replay_overhead:     0.399, 0.268, 0.165
dram_write_throughput:    18.08, 17.72, 16.9 GB/s
issued_ipc:               0.99 , 1.18 , 1.52
issue_slot_utilization:   19.48, 24.64, 33.76 %
stall_exec_dependency:    21.84, 26.38, 42.95 %

很明显,它们都具有相同的dram_write_throughput,因为所有数据都写入相同数量的DRAM,并且线程总数相同。我不明白的是效率。我的内核都在做算术(同样的),为什么他们的sm_efficiency不一样。另外,为什么在同一个内核中有更多算术可以提高效率呢?我的理解是,所有这些都应该有同样的问题,找到在SM上定位的warp。

任何人都可以使用以下指标帮助我理解GFlops的区别吗?

1 个答案:

答案 0 :(得分:2)

基本问题是你没有“饱和”GPU的工作。内核启动会产生各种开销。如果内核花费的时间与此开销相比较小,那么您的计算将受到开销的影响。

T =开销时间(OT)+计算时间(CT)

触发器/ s =触发器/ T =触发器/(OT + CT)

如果计算时间与开销时间(您的内核的情况)相比较小,那么您的计算将受到开销时间的影响。另一方面,如果计算时间与开销相比足够大,那么开销对结果的影响相对较小。

这是一个完整的测试案例,有几个案例运行,CUDA 9.1,Tesla P100 PCIE:

$ cat t79.cu
#ifndef SLEN
#define SLEN (8)
#endif
#ifndef NTPB
#define NTPB (256)
#endif
#ifndef BLKS
#define BLKS (16384/NTPB)
#endif
const size_t blks = BLKS;
const size_t ntpb = NTPB;
typedef float Ftype;
#include <iostream>
template <int LEN>
__global__ void WGSXMAPIXLLXOPS (Ftype *GOut, const Ftype M) {

        int gid = blockIdx.x * blockDim.x + threadIdx.x;

        Ftype MF = (Ftype) M;

  for (int lcdd = 0; lcdd < 1; lcdd++) {
    float temp1 = 1.0;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    temp1 = temp1 * MF + temp1;
    if (LEN > 8){
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;}
    if (LEN > 16){
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;}
    if (LEN > 32){
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;}
    if (LEN > 64){
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;}
    if (LEN > 128){
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;}
    if (LEN > 256){
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;
      temp1 = temp1 * MF + temp1;}


#ifdef NO_WRITE
      if (temp1 == -10.0)
#endif
        GOut[gid] = temp1;
  }

}


int main(){

  float et;
  Ftype *GOut;
  const Ftype M = 1.0;
  cudaMalloc(&GOut, blks*ntpb*sizeof(Ftype));
  cudaEvent_t start, stop;
  cudaEventCreate(&start); cudaEventCreate(&stop);
  WGSXMAPIXLLXOPS<SLEN><<<blks, ntpb>>> (GOut, M);
  cudaDeviceSynchronize();
  cudaEventRecord(start);
  WGSXMAPIXLLXOPS<SLEN><<<blks, ntpb>>> (GOut, M);
  cudaEventRecord(stop);
  cudaEventSynchronize(stop);
  cudaEventElapsedTime(&et, start, stop);
  unsigned long long flpcnt = SLEN*2*blks*ntpb;
  float Kflops_s = flpcnt/et;
  std::cout << "MFlops per sec: " << Kflops_s/1000 << " kernel time: " << et << "ms" << std::endl;
  cudaDeviceSynchronize();
}
$ nvcc -arch=sm_60 -o t79 t79.cu
$ ./t79
MFlops per sec: 14371.9 kernel time: 0.01824ms
$ nvprof ./t79
==14676== NVPROF is profiling process 14676, command: ./t79
MFlops per sec: 10101.1 kernel time: 0.025952ms
==14676== Profiling application: ./t79
==14676== Profiling result:
            Type  Time(%)      Time     Calls       Avg       Min       Max  Name
 GPU activities:  100.00%  3.2320us         2  1.6160us  1.2480us  1.9840us  void WGSXMAPIXLLXOPS<int=8>(float*, float)
      API calls:   98.31%  389.62ms         1  389.62ms  389.62ms  389.62ms  cudaMalloc
                    1.10%  4.3574ms       376  11.588us     357ns  465.31us  cuDeviceGetAttribute
                    0.42%  1.6829ms         4  420.73us  272.19us  642.45us  cuDeviceTotalMem
                    0.12%  487.27us         4  121.82us  90.094us  164.09us  cuDeviceGetName
                    0.02%  80.363us         2  40.181us  15.789us  64.574us  cudaLaunch
                    0.00%  17.118us         2  8.5590us  8.1400us  8.9780us  cudaDeviceSynchronize
                    0.00%  13.118us         2  6.5590us  5.4290us  7.6890us  cudaEventRecord
                    0.00%  10.603us         2  5.3010us  1.2440us  9.3590us  cudaEventCreate
                    0.00%  8.5080us         8  1.0630us     460ns  1.7500us  cuDeviceGet
                    0.00%  8.4590us         1  8.4590us  8.4590us  8.4590us  cudaEventElapsedTime
                    0.00%  7.1350us         1  7.1350us  7.1350us  7.1350us  cudaEventSynchronize
                    0.00%  6.8430us         4  1.7100us     180ns  5.9720us  cudaSetupArgument
                    0.00%  4.7800us         3  1.5930us     437ns  2.8480us  cuDeviceGetCount
                    0.00%  2.3490us         2  1.1740us     361ns  1.9880us  cudaConfigureCall
$ nvcc -arch=sm_60 -o t79 t79.cu -DSLEN=512 -DBLKS=32768 -DNTPB=1024
$ ./t79
MFlops per sec: 8.08072e+06 kernel time: 4.25206ms
$
$ nvprof --metrics  sm_efficiency_instance,ipc_instance,issued_ipc,issue_slot_utilization,stall_exec_dependency    ./t79
==15447== NVPROF is profiling process 15447, command: ./t79
==15447== Some kernel(s) will be replayed on device 0 in order to collect all events/metrics.
Replaying kernel "void WGSXMAPIXLLXOPS<int=512>(float*, float)" (done)
Replaying kernel "void WGSXMAPIXLLXOPS<int=512>(float*, float)" (done)
MFlops per sec: 193432 kernel time: 177.632ms
==15447== Profiling application: ./t79
==15447== Profiling result:
==15447== Metric result:
Invocations                               Metric Name                           Metric Description         Min         Max         Avg
Device "Tesla P100-PCIE-16GB (0)"
    Kernel: void WGSXMAPIXLLXOPS<int=512>(float*, float)
          2                                issued_ipc                                   Issued IPC    1.972106    1.972388    1.972247
          2                    issue_slot_utilization                       Issue Slot Utilization      98.23%      98.24%      98.24%
          2                     stall_exec_dependency   Issue Stall Reasons (Execution Dependency)      16.35%      16.36%      16.36%
          2                                       ipc                                 Executed IPC    1.971976    1.972254    1.972115
          2                             sm_efficiency                      Multiprocessor Activity      99.78%      99.78%      99.78%
$

第一次运行,其数字与您的匹配(16384个线程,每个块256个线程,8个FFMA指令),显示内核持续时间约为17us。但是当我们在分析器中运行这种情况时,我们发现实际的内核执行只有大约1.5us,其余的是各种开销,包括内核启动延迟,以及使用cudaEvent的延迟计时系统。所以这会让数字偏离。

另一方面,当我们启动大量的块和每个块的线程,并且每个线程工作时,我们得到的数字是P100峰值能力的80%。

从内核1到3,大多数指标都在增加(越来越好)(除了dram吞吐量,这是明智的。随着内核时间的增加,对于相同数量的数据写入,平均吞吐量会下降)。这与为GPU提供更多工作是一致的,因此它可以隐藏各种延迟并在大量工作中分摊开销。

让我们看一下上面最终运行/“大”内核的一些指标:

2                 issued_ipc                                   Issued IPC    1.972106    1.972388    1.972247
2     issue_slot_utilization                       Issue Slot Utilization      98.23%      98.24%      98.24%
2      stall_exec_dependency   Issue Stall Reasons (Execution Dependency)      16.35%      16.36%      16.36%
2                        ipc                                 Executed IPC    1.971976    1.972254    1.972115
2              sm_efficiency                      Multiprocessor Activity      99.78%      99.78%      99.78%

IPC每时钟大约2,高于内核3.请注意,IPC为2是一个合理的上限:sm_60 SM有64个单精度单位,足以为每个调度2个FFMA指令时钟。

SM效率和issue_slot_utilization是类似的指标。这意味着大约98%的时间,SM可以在任何给定的时钟周期内发出一个或多个指令。

失速(exec依赖)正在回答这个问题,“在所有实际失速情况下,执行依赖性的百分比是多少?”。您的内核在每行源代码之间都有执行依赖关系 - 因为每个源代码依赖于前一行的结果。这意味着在汇编级别,每条FFMA指令将取决于前一条指令的结果,因此在前一条指令完成之前无法发出。

如果SM被取消订阅了可用的工作,那么停止exec依赖性会上升,因为阻止发布额外工作的事情将是exec依赖。这里有16%的数字意味着大约5/6的时间,当存在停顿情况时,它不是由于exec依赖性。换句话说,即使我们在这个内核中有足够的执行依赖性,大部分时间都存在停顿,但这并不是因为GPU本来希望转到下一行代码来发布 - 这是为了一些其他原因。

要点:

似乎至少有两个问题,都与不同类型的延迟有关:

  1. 在非常小的内核大小(例如总共16384个线程)下,内核执行时间很短,因此测量结果会被例如内核启动延迟和可能的测量延迟。
  2. 内核大小非常小,并没有使用尽可能多的并行工作使GPU饱和,因此像IPC和sm_efficiency这样的东西比它们需要的要低,并且停止原因:exec依赖性相对较高。
  3. 每当你看到sm_efficiency那么低时,可能的结论是没有足够的并行工作暴露给GPU,因此计算吞吐量和内存都不是限制因素,而是延迟是性能的限制因素。

    这与the analysis-driven optimization logic(幻灯片46及以上)

    一致

    可以通过向GPU公开更多工作来纠正。