我在列主要排序中有一个尺寸为 MxN 的设备矩阵 U。现在我想将第 K 行提取到向量 u 中。有没有实现这个功能的功能?请注意,副本需要考虑 K 的偏移量和 M 的步幅。
我正在查看函数cudaMemcpy2D但它没有响铃,来自更 LAPACK 风格的 API 我不明白这些音高参数是什么,为什么不将它们简单地称为行和列或 M 和 N?
我在列主要排序中有一个尺寸为 MxN 的设备矩阵 U。现在我想将第 K 行提取到向量 u 中。有没有实现这个功能的功能?请注意,副本需要考虑 K 的偏移量和 M 的步幅。
我正在查看函数cudaMemcpy2D但它没有响铃,来自更 LAPACK 风格的 API 我不明白这些音高参数是什么,为什么不将它们简单地称为行和列或 M 和 N?
您可以使用
cublas<t>copy(handle, N, U+K, M, u, 1);
作为
#include<stdio.h>
#include<conio.h>
#include<assert.h>
#include<cublas_v2.h>
/***********************/
/* CUDA ERROR CHECKING */
/***********************/
#define gpuErrchk(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, char *file, int line, bool abort=true)
{
if (code != cudaSuccess)
{
fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
if (abort) exit(code);
}
}
/*************************/
/* cuBLAS ERROR CHECKING */
/*************************/
#ifndef cublasSafeCall
#define cublasSafeCall(err) __cublasSafeCall(err, __FILE__, __LINE__)
#endif
inline void __cublasSafeCall(cublasStatus_t err, const char *file, const int line)
{
if( CUBLAS_STATUS_SUCCESS != err) {
fprintf(stderr, "CUBLAS error in file '%s', line %d\n \nerror %d \nterminating!\n",__FILE__, __LINE__,err);
getch(); cudaDeviceReset(); assert(0);
}
}
int main() {
const int M = 5;
const int N = 4;
const int K = 2;
cublasHandle_t handle;
cublasSafeCall(cublasCreate(&handle));
float* U = (float*)malloc(M*N*sizeof(float));
float* d_U;
gpuErrchk(cudaMalloc((void**)&d_U,M*N*sizeof(float)));
float* u = (float*)malloc(M*sizeof(float));
float* d_u;
gpuErrchk(cudaMalloc((void**)&d_u,N*sizeof(float)));
for (int j=0; j<N; j++)
for (int i=0; i<M; i++)
U[j*M+i] = (float)(i*j); // Column-major ordering
printf("K-th row - Input\n");
for (int j=0; j<N; j++) printf("U(K,%i) = %f\n",j,U[j*M+K]);
printf("\n\n");
gpuErrchk(cudaMemcpy(d_U,U,M*N*sizeof(float),cudaMemcpyHostToDevice));
cublasSafeCall(cublasScopy(handle, N, d_U+K, M, d_u, 1));
gpuErrchk(cudaMemcpy(u,d_u,N*sizeof(float),cudaMemcpyDeviceToHost));
printf("K-th row - Output\n");
for (int j=0; j<N; j++) printf("u(%i) = %f\n",j,u[j]);
getchar();
}
第一部分的答案是否定的。GPU 内部的内存是线性的,就像主机端一样。如果您只想访问以列优先顺序保存的 2D 矩阵的行元素,由于非合并访问,成本会很高。由于 GPU 内存是按段配置的,因此对元素的每次访问不仅需要获取元素本身,还需要获取段中的相邻元素,在列优先排序中,这些元素恰好是元素所在列的大部分元素。而如果如果您以行优先顺序存储矩阵并访问行的元素,GPU 会尝试将同时的内存请求合并到最小段事务。
cudaMallocPitch
,这是保存 2D 数据的首选,填充内存分配,以便每一行/列的起始地址具有长度width
驻留在段的起始地址。因此,当您访问行/列的所有元素时,提取的段将被最小化。使用这种方法的代价是浪费内存空间。
正如@Farzad 所指出的,您想要的操作的内存访问模式效率低下,但除此之外,您可以通过调用 cudaMemcpy2D 来完成您想要的操作(假设 u 和 U 是 int 类型):
cudaMemcpy2D((void*)u, sizeof(int), (void*)(U+K), sizeof(int)*M, sizeof(int), N, cudaMemcpyDeviceToDevice);