簡體   English   中英

進行最終歸約的策略

[英]Strategy for doing final reduction

我正在嘗試實現一個 OpenCL 版本來減少浮點數組。

為了實現它,我在網上找到了以下代碼片段:

__kernel void sumGPU ( __global const double *input, 
                       __global double *partialSums,
               __local double *localSums)
 {
  uint local_id = get_local_id(0);
  uint group_size = get_local_size(0);

  // Copy from global memory to local memory
  localSums[local_id] = input[get_global_id(0)];

  // Loop for computing localSums
  for (uint stride = group_size/2; stride>0; stride /=2)
     {
      // Waiting for each 2x2 addition into given workgroup
      barrier(CLK_LOCAL_MEM_FENCE);

      // Divide WorkGroup into 2 parts and add elements 2 by 2
      // between local_id and local_id + stride
      if (local_id < stride)
        localSums[local_id] += localSums[local_id + stride];
     }

  // Write result into partialSums[nWorkGroups]
  if (local_id == 0)
    partialSums[get_group_id(0)] = localSums[0];
 }                  

此內核代碼運行良好,但我想通過添加每個工作組的所有部分總和來計算最終總和。 目前,我通過一個簡單的循環和迭代nWorkGroups來完成 CPU 最終求和的這一步。

我還看到了另一個帶有原子函數的解決方案,但它似乎是為 int 實現的,而不是為浮點數實現的。 我認為只有 CUDA 為浮點數提供原子函數。

我還看到我可以使用另一個內核代碼來執行這個 sum 操作,但我想避免這個解決方案,以保持一個簡單的可讀源。 也許我不能沒有這個解決方案......

我必須告訴你,我在 Radeon HD 7970 Tahiti 3GB 上使用 OpenCL 1.2(由clinfo返回)(我認為我的卡不支持 OpenCL 2.0)。

更一般地說,我想獲得有關使用我的顯卡模型和 OpenCL 1.2 執行最后一次求和的最簡單方法的建議。

抱歉之前的代碼。 它也有問題。

CLK_GLOBAL_MEM_FENCE 僅影響當前工作組。 我糊塗了。 =[

如果你想通過 GPU 減少 sum,你應該在 clFinish(commandQueue) 之后通過 NDRangeKernel 函數將減少內核入隊。

Plaese只是采取概念。

 
 
 
  
  __kernel void sumGPU ( __global const double *input, __global double *partialSums, __local double *localSums) { uint local_id = get_local_id(0); uint group_size = get_local_size(0); // Copy from global memory to local memory localSums[local_id] = input[get_global_id(0)]; // Loop for computing localSums for (uint stride = group_size/2; stride>0; stride /=2) { // Waiting for each 2x2 addition into given workgroup barrier(CLK_LOCAL_MEM_FENCE); // Divide WorkGroup into 2 parts and add elements 2 by 2 // between local_id and local_id + stride if (local_id < stride) localSums[local_id] += localSums[local_id + stride]; } // Write result into partialSums[nWorkGroups] if (local_id == 0) partialSums[get_group_id(0)] = localSums[0]; barrier(CLK_GLOBAL_MEM_FENCE); if(get_group_id(0)==0){ if(local_id < get_num_groups(0)){ // 16384 for(int n=0 ; n<get_num_groups(0) ; n+= group_size ) localSums[local_id] += partialSums[local_id+n]; barrier(CLK_LOCAL_MEM_FENCE); for(int s=group_size/2;s>0;s/=2){ if(local_id < s) localSums[local_id] += localSums[local_id+s]; barrier(CLK_LOCAL_MEM_FENCE); } if(local_id == 0) partialSums[0] = localSums[0]; } } }
 
 

如果該浮點數的數量級小於exa比例,則:

而不是

if (local_id == 0)
  partialSums[get_group_id(0)] = localSums[0];

你可以用

if (local_id == 0)
{
    if(strategy==ATOMIC)
    {
        long integer_part=getIntegerPart(localSums[0]);
        atom_add (&totalSumIntegerPart[0] ,integer_part);
        long float_part=1000000*getFloatPart(localSums[0]);
         // 1000000 for saving meaningful 7 digits as integer
        atom_add (&totalSumFloatPart[0] ,float_part);
    }
}

這將溢出浮點部分,所以當你在另一個內核中將它除以 1000000 時,它可能有超過 1000000 的值,所以你得到它的整數部分並將其添加到實數部分:

   float value=0;
   if(strategy==ATOMIC)
   {
       float float_part=getFloatPart_(totalSumFloatPart[0]);
       float integer_part=getIntegerPart_(totalSumFloatPart[0])
       + totalSumIntegerPart[0];
       value=integer_part+float_part;
   }

在整個內核時間內,只有幾個原子操作不應該有效。

其中一些get___part可以使用 floor 和類似函數輕松編寫。 有些需要除以1M。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM