如何在CUDA设备

时间:2015-06-22 19:45:18

标签: c++ arrays cuda sparse-matrix

我有一个稀疏矩阵结构,我与CUBLAS一起使用它来实现线性求解器类。我预计我将要解决的稀疏矩阵的维数将相当大(大约10 ^ 7乘10 ^ 7)。 我还预计解算器需要多次使用,并且该矩阵的一部分也需要多次更新(在计算解决方案之间)。

将整个矩阵结构从系统内存复制到设备内存可能会成为一个性能瓶颈,因为在给定时间内只需要更改一小部分矩阵条目。

我希望能够做的是有一种方法只更新特定的子集/子矩阵,而不是每次我需要更改矩阵时将整个矩阵结构从系统内存重新复制到设备内存

矩阵数据结构将驻留在数组中的CUDA设备上: d_col,d_row和d_val

在系统方面,我会有相应的数组I,J和val。

理想情况下,我只想更改与系统数组中的值相对应的d_val子集,即更改的值。

请注意,我预计不会在矩阵中添加或删除任何条目,只会显示现有条目的值会发生变化。

天真地我会认为要实现这一点,我会在主机端有一个整数数组或向量,例如updateInds,它将跟踪val中已更改的条目索引,但我不确定如何有效地告诉CUDA设备更新d_val的相应值。

实质上:如何将指示updateInds [1],updateInds [2],...,updateInds [n]中的CUDA设备端阵列(d_val)中的条目更改为一组新的值val [updatInds [1]],val [updateInds [2]],...,val [updateInds [3]],没有将整个val数组从系统内存重新复制到CUDA设备内存数组d_val中?

1 个答案:

答案 0 :(得分:1)

只要您只想更改与CSR(或CSC或COO)稀疏矩阵表示相关联的值数组的数值,该过程就不复杂了。

假设我有这样的代码(摘自CUDA共轭梯度sample):

checkCudaErrors(cudaMalloc((void **)&d_val, nz*sizeof(float)));
...
cudaMemcpy(d_val, val, nz*sizeof(float), cudaMemcpyHostToDevice);

现在,在代码中的这一点之后,我们假设我需要更改d_val数组中的某些值,这些值对应于我在val中所做的更改:

for (int i = 10; i < 25; i++)
  val[i] = 4.0f;

移动这些特定更改的过程在概念上与使用memcpy更新数组的过程相同,但我们将使用cudaMemcpy更新设备上的d_val数组:

cudaMemcpy(d_val+10, val+10, 15*sizeof(float), cudaMempcyHostToDevice);

由于这些值都是连续的,我可以使用一个cudaMemcpy调用来实现转移。

如果我有几个类似于上面的不相交区域,则需要多次调用cudaMemcpy,每个区域一个。如果偶然地,这些区域的间距相等且长度相等:

for (int i = 10; i < 5; i++)
  val[i] = 1.0f;
for (int i = 20; i < 5; i++)
  val[i] = 2.0f;
for (int i = 30; i < 5; i++)
  val[i] = 4.0f;

然后也可以通过一次调用cudaMemcpy2D来执行此转移。该方法概述为here

注意:

    相同数量的元素上的cudaMemcpy2D操作相比,
  1. cudaMemcpy比您预期的要慢。
  2. CUDA API调用有一些固有的开销。如果要以分散的方式更新矩阵的大部分,实际上传输整个d_val数组可能仍然更快,利用可以使用单个{{1操作。
  3. 如果非零值在稀疏矩阵中更改其位置,则无法使用此处描述的方法。在这种情况下,我无法提供如何通过手术更新设备上的CSR稀疏矩阵的一般答案。而且某些相对简单的更改可能需要更新大部分数组数据(3个向量)。