【问题标题】:How to copy on GPU a vector-of-vector-pointer-memory-allocated in OpenACC如何在 GPU 上复制 OpenACC 中分配的向量指针内存向量
【发布时间】:2019-05-20 11:46:30
【问题描述】:

我正在尝试在 GPU 上复制向量数组的向量。

我尝试使用 OpenACC 复制子句。 copyin 子句不会复制我的数组的所有基础数​​据。当我尝试访问底层矢量数据时,在运行时出现“非法地址访问”错误。

vector<int32_t> *k1p = new vector<int32_t>[bin_num];
for (int i = 0; i < bin_mum; i++) {
  //......
  k1p[i].push_back(i);
}
#pragma acc kernels loop independent copyin(k1p[0:bin_num])
for (int i = 0; i < bin_mum; i++) {
  //........
  for (vector<int32_t>::const_iterator i2_it=k1p[i].begin(); i2_it!=k1p[i].end(); i2_it++) {
    //.......
  }
  //..........
}

我想访问底层向量k1p[i]的元素,但实际上这段代码是用pgi编译器编译的,但是当我运行这段代码时,我得到了

调用 cuStreamSynchronize 返回错误 700:内核执行期间地址非法

【问题讨论】:

    标签: c++ stdvector openacc


    【解决方案1】:

    OpenACC 数据子句只执行对象的浅拷贝。由于“向量”是三个指针的集合,这意味着将向量放在 copyin 子句中只会复制指针,而不是它指向的数据。

    假设您使用 PGI,最简单的做法是使用 CUDA 统一内存(即添加标志“-ta=tesla:managed”),并让 CUDA 运行时为您管理数据移动。

    否则,您需要对向量执行手动深拷贝。这可能有点棘手,尤其是向量,所以如果你需要一个例子,请告诉我。

    【讨论】:

    • 感谢您的回复@Mat Colgrove。拜托,我需要一个例子。
    【解决方案2】:

    再次,我强烈建议在设备上使用 C++ 向量时使用 CUDA 统一内存(托管)。向量是具有三个私有指针的容器类型。给定 OpenACC 复制或更新执行浅复制,当将向量放入数据区域时,您将复制指针,而不是它们指向的数据。更糟糕的是,由于指针是私有的,它们不能用设备指针更新。

    相反,您需要创建一个临时指针数组来隐藏向量数组的数据,然后在设备上使用这个临时变量。类似于以下内容:

    % cat vector.data.cpp
    #include <iostream>
    #include <vector>
    #include <cstdint>
    
    using namespace std;
    
    int main() {
       const int bin_num = 1024;
       long sum = 0;
    
       vector<int32_t> *k1p = new vector<int32_t>[bin_num];
       for (int i = 0; i < bin_num; i++) {
           k1p[i].push_back(i);
       }
    
       int32_t ** temp = new int32_t*[bin_num];
       int * sizes = new int[bin_num];
       #pragma acc enter data create(temp[0:bin_num][0:0])
       for (int i = 0; i < bin_num; i++) {
          int sze = k1p[i].size();
          sizes[i] = sze;
          temp[i] = k1p[i].data();
          #pragma acc enter data copyin(temp[i:1][:sze])
       }
       #pragma acc enter data copyin(sizes[:bin_num])
    
      #pragma acc parallel loop gang vector reduction(+:sum) present(temp,sizes)
      for (int i = 0; i < bin_num; i++) {
         for (int j=0; j< sizes[i]; ++j) {
             sum += temp[i][j];
         }
      }
      cout << "Sum: " << sum << endl;
      #pragma acc exit data delete(sizes)
      #pragma acc exit data delete(temp)
      delete [] sizes;
      delete [] k1p;
    }
    
    % pgc++ vector.data.cpp --c++11 -ta=tesla  -V18.10
    % a.out
    Sum: 523776
    

    使用托管内存时,地址位于主机和设备均可访问的统一内存空间中。因此,当您访问“开始”和“结束”时,它们在设备上返回的地址是有效的。例如:

    % cat vector.cpp
    #include <iostream>
    #include <vector>
    #include <cstdint>
    using namespace std;
    
    int main() {
       const int bin_num = 1024;
       long sum = 0;
       vector<int32_t>::const_iterator i2_it;
    
       vector<int32_t> *k1p = new vector<int32_t>[bin_num];
       for (int i = 0; i < bin_num; i++) {
           k1p[i].push_back(i);
       }
    
    #pragma acc parallel loop reduction(+:sum) private(i2_it)
      for (int i = 0; i < bin_num; i++) {
        for (i2_it=k1p[i].begin(); i2_it!=k1p[i].end(); i2_it++) {
             sum += *i2_it;
         }
      }
      cout << "Sum: " << sum << endl;
    }
    
    % pgc++ vector.cpp --c++11 -ta=tesla:managed -V18.10
    % a.out
    Sum: 523776
    

    另一种选择是编写你自己的类向量。作为Parallel Programming with OpenACC 第 5 章的一部分,我编写了一个基本示例来说明如何执行此操作。代码示例可以在https://github.com/rmfarber/ParallelProgrammingWithOpenACC找到

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-03-11
      • 2014-03-13
      • 2021-12-26
      • 2023-03-23
      • 1970-01-01
      • 2015-12-08
      • 1970-01-01
      相关资源
      最近更新 更多