C++ CUDA矩阵乘法,执行时间长
我是CUDA的新手,我一直在努力找出我做错了什么。CUDA所用的时间比仅仅使用CPU乘法矩阵要长。如果我做错了什么,请告诉我。 这是我的密码:C++ CUDA矩阵乘法,执行时间长,c++,c,cuda,C++,C,Cuda,我是CUDA的新手,我一直在努力找出我做错了什么。CUDA所用的时间比仅仅使用CPU乘法矩阵要长。如果我做错了什么,请告诉我。 这是我的密码: #include "cuda_runtime.h" #include "device_launch_parameters.h" #include <stdio.h> #include <stdlib.h> #include <cstdlib> #include <assert.h> #include <
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <stdlib.h>
#include <cstdlib>
#include <assert.h>
#include <time.h>
#define size 100 // Matrix size
#define cols size // Matrix width
#define rows size // Matrix height
void checkCUDAError(const char *msg)
{
cudaError_t err = cudaGetLastError();
if( cudaSuccess != err)
{
fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString( err) );
exit(EXIT_FAILURE);
}
}
__global__ void matrixMul( int *A, int *B, int *C)
{
int bx = blockIdx.x; // Block index
int tx = threadIdx.x; // Thread index
int ts = blockDim.x; // number of threads
// Declaration of the shared memory C element
extern __shared__ int c_element_sum[];
c_element_sum[tx] = A[tx+((bx/ts)*ts)] * B[(bx%ts)+(tx*ts)];
//Block until all threads in the block have written their data to shared mem
__syncthreads();
int sum;
for(int i=0; i<ts; i++){
if(i==0){
sum=c_element_sum[i];
}
else{
sum+=c_element_sum[i];
}
}
C[bx] = sum;
}
/////////////////////////////////////////////////////////
// Program main
/////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
//create timer.
clock_t t1, t2;
//start timer
t1=clock();
//allocate host memory for matrices
unsigned int size_A = cols * rows;
unsigned int mem_size_A = sizeof(int) * size_A;
int* mA = (int*) malloc(mem_size_A);
unsigned int size_B = cols * rows;
unsigned int mem_size_B = sizeof(int) * size_B;
int* mB = (int*) malloc(mem_size_B);
unsigned int size_C = cols * rows;
unsigned int mem_size_C = sizeof(int) * size_C;
int* mC = (int*) malloc(mem_size_C);
//initialize host memory
for (int i = 0; i < size_A; ++i){
mA[i] = 1;
mB[i] = 1;
mC[i] = 0;
}
// allocate device memory
int* d_mA;
int* d_mB;
int* d_mC;
cudaMalloc((void**) &d_mA, mem_size_A);
cudaMalloc((void**) &d_mB, mem_size_B);
cudaMalloc((void**) &d_mC, mem_size_C);
//copy host memory to device (A and B)
cudaMemcpy(d_mA, mA, mem_size_A, cudaMemcpyHostToDevice);
cudaMemcpy(d_mB, mB, mem_size_B, cudaMemcpyHostToDevice);
cudaMemcpy(d_mC, mC, mem_size_C, cudaMemcpyHostToDevice);
// setup execution parameters
int numThreadsPerBlock = cols;
int numBlocks = (cols * rows);
int sharedMemSize = numThreadsPerBlock * sizeof(int);
dim3 dimGrid(numBlocks);
dim3 dimBlock(numThreadsPerBlock);
// execute the kernel
matrixMul <<< dimGrid, dimBlock, sharedMemSize >>>(d_mA, d_mB, d_mC);
//Block until device has completed
cudaThreadSynchronize();
// check if kernel execution generated an error
// Check for any CUDA errors
checkCUDAError("kernel invocation");
//copy result from device to host
cudaMemcpy(mC, d_mC, mem_size_C, cudaMemcpyDeviceToHost);
// Check for any CUDA errors
checkCUDAError("memcpy");
//stop timer
t2 = clock();
//check results
for (int i = 0; i < size_C; ++i){
assert(mC[i] == cols);
}
//clean up memory
free(mA);
free(mB);
free(mC);
cudaFree(d_mA);
cudaFree(d_mB);
cudaFree(d_mC);
printf("WITH CUDA - clocks: %d \n\n", t2-t1);
//////////////////////////////
///////// CPU ONLY //////////
/////////////////////////////
//create timer.
clock_t cpu_t1, cpu_t2;
//start timer
cpu_t1=clock();
//allocate host memory for matrices
unsigned int cpu_size_A = cols * rows;
unsigned int cpu_mem_size_A = sizeof(int) * cpu_size_A;
int* cpu_mA = (int*) malloc(cpu_mem_size_A);
unsigned int cpu_size_B = cols * rows;
unsigned int cpu_mem_size_B = sizeof(int) * cpu_size_B;
int* cpu_mB = (int*) malloc(cpu_mem_size_B);
unsigned int cpu_size_C = cols * rows;
unsigned int cpu_mem_size_C = sizeof(int) * cpu_size_C;
int* cpu_mC = (int*) malloc(cpu_mem_size_C);
//initialize host memory
for (int i = 0; i < cpu_size_A; ++i){
cpu_mA[i] = 1;
cpu_mB[i] = 1;
cpu_mC[i] = 0;
}
int ts = cols;
for(int bx=0; bx<(cols*rows);bx++){
int sum = 0;
for(int tx=0; tx<cols; tx++){
sum += cpu_mA[tx+((bx/ts)*ts)] * cpu_mB[(bx%ts)+(tx*ts)];
}
cpu_mC[bx]=sum;
}
//stop timer
cpu_t2 = clock();
//check results
for (int i = 0; i < cpu_size_C; ++i){
assert(cpu_mC[i] == cols);
}
//clean up memory
free(cpu_mA);
free(cpu_mB);
free(cpu_mC);
printf("CPU ONLY - clocks: %d \n\n", cpu_t2-cpu_t1);
return 0;
}
#包括“cuda_runtime.h”
#包括“设备启动参数.h”
#包括
#包括
#包括
#包括
#包括
#定义大小100//矩阵大小
#定义cols大小//矩阵宽度
#定义行大小//矩阵高度
无效检查CUDAERROR(常量字符*msg)
{
cudaError_t err=cudaGetLastError();
如果(cudaSuccess!=错误)
{
fprintf(标准,“Cuda错误:%s:%s.\n”,消息,cudaGetErrorString(err));
退出(退出失败);
}
}
__全局无效矩阵mul(int*A,int*B,int*C)
{
int bx=blockIdx.x;//块索引
int tx=threadIdx.x;//线程索引
int ts=blockDim.x;//线程数
//共享内存C元素的声明
外部共享内部c元素和[];
c_元素之和[tx]=A[tx+((bx/ts)*ts)]*B[(bx%ts)+(tx*ts)];
//块,直到块中的所有线程都已将其数据写入共享mem
__同步线程();
整数和;
对于(int i=0;i(d_mA,d_mB,d_mC);
//阻止,直到设备完成
cudaThreadSynchronize();
//检查内核执行是否产生错误
//检查任何CUDA错误
checkCUDAError(“内核调用”);
//将结果从设备复制到主机
cudaMemcpy(mC、d_mC、mem_size_C、cudamemcydevicetohost);
//检查任何CUDA错误
检查CUDAERROR(“memcpy”);
//停止计时器
t2=时钟();
//检查结果
对于(int i=0;i 对于(int bx=0;bx,根据您的程序,这是意料之中的。您的计时器看起来像是为程序的整个执行计时,包括复制到设备、计算时间和复制回结果。考虑到您为程序提供的工作量相当小(100x100矩阵),内存拷贝的开销远远超过使用内核进行计算时获得的任何计算好处。内核本身也不是最有效的实现
我不认为你做错了什么,只是你没有为GPU提供足够大的工作块,你有可能进一步优化你的内核。请注意,简单地扩大块的大小可能不会显著提高CPU的性能,因为你也会扩大内存管理时间。虽然在CUDA上编写程序的第一个实现相对简单,但要从中获得良好的性能要困难得多。使用CUDA最有效的方法是拥有较高的计算内存事务比率。例如,拥有多个计算密集型内核的流水线来成功操作在数据块上进行复制,只需要在开始和结束时复制主机设备
如果这只是一个帮助您学习为CUDA编写代码的程序,这是一个伟大的步骤,深入了解如何优化矩阵乘法内核将在许多其他情况下为您提供很好的帮助。如果您编写此内核用于软件生产件,我建议您使用高度优化的线性代数库拉瑞·库布拉斯:(或者其他一些已经为你完成了艰苦工作的图书馆).您应该在调用内核后立即测量内存,否则,您会考虑复制和分配内存所需的时间,这相当慢。您有什么理由编写自己的矩阵乘法例程吗?IIRC CUDA内置了这个函数供您调用。@fontanini:谢谢,我会记住这一点迈克·班特吉:我写这篇文章是为了练习,在我休息的时候教我自己CUDA,但是谢谢你的建议,我不知道有一个内置函数,当我开始处理更复杂的东西时,它会派上用场。谢谢你的解释,它非常有帮助。我写这个程序只是为了练习。我试着我在大学里的时候,每个人都会用CUDA和更多的C,因为大学在教我任何有价值的东西方面做得很糟糕。我想我最好自己去学一些东西,否则我毕业时只需要一些半途而废的Java课程,还有一张我将在未来几年支付的纸。我一直认为大学的真正目的是教你如何教自己,所以在这方面,似乎做得不错。