首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CUDA独立教学优化

CUDA独立教学优化
EN

Stack Overflow用户
提问于 2013-05-24 17:55:34
回答 1查看 440关注 0票数 1

我需要关于优化我的内核和设备代码的建议。我理解CUDA文档(以及这么多的幻灯片)建议使用大线程块大小来隐藏内存和算术延迟。

我的内核和设备功能计算量很大。因此,我尝试使用尽可能多的寄存器,而且(显然)由于这一点,我在占用方面做出了妥协。重点是,对于我的应用程序来说,指令级并行比大型线程块更重要。

但是ILP背后的基本思想是有独立的指令。我的问题是

1)如何做到这一点?在计算中,总是有可重用的变量用于其他计算。

( 2)有人能提出或提供一些例子,说明依赖指令可以转化为独立指令吗?

3)我还读到(某处),对于算术计算,最大ILP =4是可以实现的,即一个线程计算4个独立的指令。这是否意味着,如果存在这四个指令,并且在此之后存在依赖指令,则翘曲将进入等待状态,直到满足依赖关系为止?

( 4)有人能建议使用ILP的一些阅读材料和代码吗?

我在这里还介绍了一些分析代码,它可能没有任何意义。代码表示以下等式:

公式

关键是我想要达到最大的性能;我想为此使用ILP。我的代码中也有其他设备功能;所以我使用

线程块: 192

14 SM (32个核心):448 (核心)

每个SM同时使用8个块:8x192: 1536

在用"-ptxas-options=-v"编译代码时,我每个线程得到50个寄存器(占33%左右)

方程中使用的所有参数都是double型(n除外)。

例如n= 2. params数组包含S在param,I1在param1,I2在param2

代码语言:javascript
复制
#define N 3.175e-3
__device__ double gpu_f_different_mean(double x, double params[], int n) {

   double S = params[0];
   double product_I = 1.0;

   for (int i = 1; i <= n; i++) {
      product_I = product_I * params[i];
   }

   double tmp   = S * exp(-N * S * x);
   double outer = product_I * tmp;

   double result = 0.0;

   for (int i = 1; i <=n; i++) {

      double reduction = (params[i] + S * x);
      double numerator = 1 + N * reduction;

      double denom_prod = 1.0;
      for (int j = 1; j<= n; j++) {
         if ( i != j)
            denom_prod = denom_prod * (params[j] - params[i]);
      }

      double denominator = pow(reduction, 2) * denom_prod;
      result             = result + (numerator / denominator);
   }

   return outer * result;
}

硬件

我使用费米架构GPU GTX470,计算能力2.0

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-05-24 19:06:23

若干评论意见:

( a)可以通过引入多个约简变量来打破依赖链,如denom_prod的持续更新所造成的依赖链:

代码语言:javascript
复制
  double denom_prod1 = 1.0;
  double denom_prod2 = 1.0;
  int j;
  for (j = 1; j <= n-1; j += 2) {
     if ( i != j)
        denom_prod1 *= (params[j  ] - params[i]);
     if ( i != j+1)
        denom_prod2 *= (params[j+1] - params[i]);
  }
  if (j < n) {
     if ( i != j)
        denom_prod1 = denom_prod * (params[j  ] - params[i]);
  }
  double denom_prod = denom_prod1 * denom_prod2;

( b)可以通过将循环分解为两部分来消除循环中的条件:

代码语言:javascript
复制
  double denom_prod = 1.0;
  for (int j = 1; j < i; j++)
     denom_prod = denom_prod * (params[j] - params[i]);
  for (int j = i+1; j <= n; j++)
     denom_prod = denom_prod * (params[j] - params[i]);

( c)通过一次计算(i,j)和(j,i)的结果,您可以利用这样一个事实:交换ij不会改变denom_prod

( d) reduction * reductionpow(reduction, 2)更快(而且可能更精确)

关于你的问题:

1)和2)见我的评论a)。

3)这很可能是指费米代GPU(计算能力2.x)每个SM有两个独立的翘曲调度器,每个周期能够发出两个指令,每个周期总共有四个指令。

然而,依赖指令的问题比这个问题更严重,因为依赖指令的延迟约为16.24周期。也就是说,两个依赖指令中的第二个必须等待那么多周期才能发出。中间的循环可以由来自同一翘曲的独立指令使用(这些指令必须位于依赖指令之间,因为当前的Nvidia GPU不能按顺序发出指令)。或者它们可以被其他经纱的指令所使用,而这些翘曲总是独立的。因此,为了获得最佳性能,您需要许多偏差,或连续的独立指令,或者理想情况下两者兼而有之。

4)瓦西里·沃尔科夫的著作对这一主题进行了出色的阅读,特别是他的“较低入住率的业绩更佳”演讲。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16740911

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档