Optimization CUDA独立指令优化

Optimization CUDA独立指令优化,optimization,cuda,Optimization,Cuda,我需要关于我的内核和设备代码优化的建议。我知道CUDA文档和许多幻灯片都建议使用较大的线程块大小,以隐藏内存和算术延迟 我的内核和设备函数都是计算密集型的。因此,我尝试使用尽可能多的寄存器,显然正因为如此,我在占用率上做出了妥协。关键是,对于我的应用程序,指令级并行比大型线程块更重要 但ILP背后的基本理念是拥有独立的指令。我的问题是 1如何做到这一点?在计算中,始终存在可用于其他计算的变量。 2是否有人可以建议或提供一些示例,将依赖指令转换为独立指令? 3我还读到,对于算术计算,可以实现最大I

我需要关于我的内核和设备代码优化的建议。我知道CUDA文档和许多幻灯片都建议使用较大的线程块大小,以隐藏内存和算术延迟

我的内核和设备函数都是计算密集型的。因此,我尝试使用尽可能多的寄存器,显然正因为如此,我在占用率上做出了妥协。关键是,对于我的应用程序,指令级并行比大型线程块更重要

但ILP背后的基本理念是拥有独立的指令。我的问题是

1如何做到这一点?在计算中,始终存在可用于其他计算的变量。 2是否有人可以建议或提供一些示例,将依赖指令转换为独立指令? 3我还读到,对于算术计算,可以实现最大ILP=4,即一个线程计算4条独立指令。这是否意味着,如果存在这四条指令,并且在这四条指令之后存在依赖指令,warp将进入等待状态,直到满足依赖关系? 4有人能推荐一些利用ILP的阅读材料和代码吗

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

关键是我想达到最高的绩效;我想用ILP来解决这个问题。我的代码中还有其他设备功能;所以我用

螺纹块:192 14芯32芯:448芯 每个SM同时使用8个块:8 x 192:1536 当使用-ptxas options=-v编译代码时,每个线程占用大约33%的寄存器

方程式中使用的所有参数均为除n以外的double类型 e、 g.n=2。params数组在param[0]处包含S,在param[1]处包含I1,在param[2]处包含I2

#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。有几点意见:

通过引入多个简化变量,可以打破denom_prod连续更新导致的依赖链:

  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通过将循环分为两部分,可以消除循环内的条件:

  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]);
通过一次性计算i,j和j,i的结果,可以利用交换i和j不会改变denom_prod这一事实

d还原*还原比POWER还原更快且可能更准确,2

关于你的问题:

1和2见我的评论a

3这可能是指费米一代GPU计算能力2.x每个SM有两个独立的warp调度程序,每个调度程序每个周期能够发出两条指令,每个周期最多发出四条指令

然而,从属指令的问题远不止于此,因为从属指令的延迟约为16..24个周期。也就是说,两条相关指令中的第二条必须等待那么多周期才能发出。由于当前Nvidia GPU不能无序发出指令,因此,中间的周期可以由来自同一个扭曲的独立指令使用,这些扭曲必须位于从属指令之间。或者,它们也可以被来自其他warp的指令使用,这些warp始终是独立的。因此,为了获得最佳性能,您需要多个扭曲或连续的独立指令,或者理想情况下两者都需要

4瓦西里·沃尔科夫(Vasily Volkov)的出版物对这一主题,特别是他的演讲,有很好的阅读价值。

几点评论:

通过引入多个简化变量,可以打破denom_prod连续更新导致的依赖链:

  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通过将循环分为两部分,可以消除循环内的条件:

  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]);
通过一次性计算i,j和j,i的结果,可以利用交换i和j不会改变denom_prod这一事实

d还原*还原比POWER还原更快且可能更准确,2

关于你的问题:

1和2见我的评论a

3这可能是指费米一代GPU计算能力2.x每个SM有两个独立的warp调度程序,每个调度程序每个周期能够发出两条指令,每个周期最多发出四条指令

然而,从属指令的问题远不止于此,因为从属指令的延迟约为16..24个周期。也就是说,两条相关指令中的第二条必须等待那么多周期才能发出。由于当前Nvidia GPU不能无序发出指令,因此,中间的周期可以由来自同一个扭曲的独立指令使用,这些扭曲必须位于从属指令之间。或者,它们也可以被来自其他warp的指令使用,这些warp始终是独立的。因此,为了获得最佳性能,您需要多个扭曲或连续的独立插入 休战,或者理想情况下两者兼而有之


4瓦西里·沃尔科夫(Vasily Volkov)的出版物对这一主题的阅读非常有帮助,尤其是他的演讲。

谢谢你的回答。我想再深入一点,了解一下您描述的最佳性能时的意思,您需要很多扭曲,或者连续的独立指令,或者理想情况下两者都需要。我已经看过了您在这里链接的演示文稿,它还描述了独立指令如何提高性能,但没有提到代码转换。因此,为了获得最佳性能,您需要许多扭曲。。。您直接提到的是大螺纹块尺寸,是吗?我指的是占用率,因为翘曲是来自同一块还是来自其他块并不重要。使用查找每个SM同时活动的扭曲数。您是否阅读过CUDA工具包附带的CUDA C最佳实践指南,特别是第7章?谢谢您的回答。我想再深入一点,了解一下您描述的最佳性能时的意思,您需要很多扭曲,或者连续的独立指令,或者理想情况下两者都需要。我已经看过了您在这里链接的演示文稿,它还描述了独立指令如何提高性能,但没有提到代码转换。因此,为了获得最佳性能,您需要许多扭曲。。。您直接提到的是大螺纹块尺寸,是吗?我指的是占用率,因为翘曲是来自同一块还是来自其他块并不重要。使用查找每个SM同时活动的扭曲数。您是否阅读过CUDA工具包附带的CUDA C最佳实践指南,特别是第7章?