CUDA 并行计算是如何工作的?
How does CUDA parallel computing work?
我是 CUDA 的新手,只是对它的工作原理感到困惑。
我创建了一个简单的 void 来在 GPU 上执行。
__global__ void Test (int *ch) {
long i = blockIdx.x;
ch[2] = i;
long u = threadIdx.x;
ch[3] = u;
if (i < 640)
{
ch[0]++;
if (u < 480)
{
ch[1]++;
}
}
}
我用<<<640,480>>>调用了虚空。在所有教程中,我都看到 If 正在替换 "CPU" for 循环。原来的 "CPU-Void" 看起来像这样:
void Test (int *ch) {
h_ch[2] = 640;
h_ch[3] = 480;
for(int a = 0;a < 640;a++)
{
ch[0]++;
for(int b = 0;b < 480;b++)
{
ch[1]++;
}
}
}
如果我打印由 CPU 生成的 ch 数组,我将看到类似这样的内容:ch[0] = 640 ch[1] = 307200 ch[2] = 640 ch[3] = 480但是 GPU 是做什么的?
我得到了这些结果:ch[0] = 1038(值每隔 运行 发生变化!)ch[1] = 1038(似乎等于 ch[0])ch[2] = 639 通道[3] = 31
发生了什么事?我假设得到与 CPU.
相同的结果
感谢您的回答
下面是完整的代码:(我只想要相同的结果)
您可以选择 CPU 或 gpu
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <iostream>
int *h_ch , *ch;
__global__ void Test (int *ch)
{
long i = blockIdx.x;
ch[2] = i;
long u = threadIdx.x;
ch[3] = u;
if (i < 640)
{
ch[0]++;
if (u < 480)
{
ch[1]++;
}
}
}
void test (int *h_ch)
{
h_ch[2] = 640;
h_ch[3] = 480;
for(int a = 0;a < 640;a++)
{
h_ch[0]++;
for(int b = 0;b < 480;b++)
{
h_ch[1]++;
}
}
}
int main()
{
h_ch = (int *)malloc(4*sizeof(int));
cudaMalloc((void **)&ch,4*sizeof(int));
h_ch[0] = 0;
h_ch[1] = 0;
h_ch[2] = 0;
h_ch[3] = 0;
cudaMemcpy(ch,h_ch,4*sizeof(int),cudaMemcpyHostToDevice);
//Test<<<640,480>>>(ch);
test(h_ch);
//cudaMemcpy(h_ch,ch,4*sizeof(int),cudaMemcpyDeviceToHost);
for(int i = 0;i < 4;i++) printf("%d ",h_ch[i]);
int a;
std::cin >> a;
return 0;
}
有几个问题。
您有多个线程在尝试更新两个位置 ch[0]
和 ch[1]
时相互踩踏。在 GPU 中,多个线程并行执行。当所有这些线程都试图同时更新同一个位置时,就会出现混乱。如果您想看到此代码正常工作,请将您的普通更新(例如 ch[1]++;
)替换为原子更新(例如 atomicAdd(ch+1, 1);
你的 GPU 代码和 CPU 代码在逻辑上是不一样的。您的 GPU 代码让每个线程更新 ch[0]
和 ch[1]
一次,因此如果上面 #1 中的问题得到解决,这些位置的结束数字应该分别为 640 和 480。但是您的 CPU 代码在循环中执行 ch[1]
的更新,每次 ch[0]
的更新执行 480 次。我们可以通过将 GPU 代码修改为类似于 CPU 代码来解决此问题,反之亦然,从逻辑上讲,将 CPU 代码修改为类似于 GPU 代码。
以下代码解决了上述 2 个问题,将 CPU 代码修改为类似于 GPU,ch[0]
和 ch[1]
中的预期结果均为 307200 CPU 和 GPU:
$ cat t609.cu
#include <stdio.h>
#include <iostream>
int *h_ch , *ch;
__global__ void Test (int *ch)
{
long i = blockIdx.x;
long u = threadIdx.x;
if (i < 640)
atomicAdd(ch,1);
if (u < 480)
atomicAdd(ch+1,1);
}
void test (int *h_ch)
{
for(int a = 0;a < 640;a++)
for(int b = 0;b < 480;b++){
h_ch[0]++;
h_ch[1]++;}
}
int main()
{
h_ch = (int *)malloc(4*sizeof(int));
cudaMalloc((void **)&ch,4*sizeof(int));
h_ch[0] = 0;
h_ch[1] = 0;
h_ch[2] = 0;
h_ch[3] = 0;
cudaMemcpy(ch,h_ch,4*sizeof(int),cudaMemcpyHostToDevice);
Test<<<640,480>>>(ch+2);
test(h_ch);
cudaMemcpy(h_ch+2,ch+2,2*sizeof(int),cudaMemcpyDeviceToHost);
for(int i = 0;i < 4;i++) printf("%d \n",h_ch[i]);
return 0;
}
$ nvcc -arch=sm_20 -o t609 t609.cu
$ ./t609
307200
307200
307200
307200
$
我是 CUDA 的新手,只是对它的工作原理感到困惑。
我创建了一个简单的 void 来在 GPU 上执行。
__global__ void Test (int *ch) {
long i = blockIdx.x;
ch[2] = i;
long u = threadIdx.x;
ch[3] = u;
if (i < 640)
{
ch[0]++;
if (u < 480)
{
ch[1]++;
}
}
}
我用<<<640,480>>>调用了虚空。在所有教程中,我都看到 If 正在替换 "CPU" for 循环。原来的 "CPU-Void" 看起来像这样:
void Test (int *ch) {
h_ch[2] = 640;
h_ch[3] = 480;
for(int a = 0;a < 640;a++)
{
ch[0]++;
for(int b = 0;b < 480;b++)
{
ch[1]++;
}
}
}
如果我打印由 CPU 生成的 ch 数组,我将看到类似这样的内容:ch[0] = 640 ch[1] = 307200 ch[2] = 640 ch[3] = 480但是 GPU 是做什么的?
我得到了这些结果:ch[0] = 1038(值每隔 运行 发生变化!)ch[1] = 1038(似乎等于 ch[0])ch[2] = 639 通道[3] = 31
发生了什么事?我假设得到与 CPU.
相同的结果感谢您的回答
下面是完整的代码:(我只想要相同的结果) 您可以选择 CPU 或 gpu
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
#include <iostream>
int *h_ch , *ch;
__global__ void Test (int *ch)
{
long i = blockIdx.x;
ch[2] = i;
long u = threadIdx.x;
ch[3] = u;
if (i < 640)
{
ch[0]++;
if (u < 480)
{
ch[1]++;
}
}
}
void test (int *h_ch)
{
h_ch[2] = 640;
h_ch[3] = 480;
for(int a = 0;a < 640;a++)
{
h_ch[0]++;
for(int b = 0;b < 480;b++)
{
h_ch[1]++;
}
}
}
int main()
{
h_ch = (int *)malloc(4*sizeof(int));
cudaMalloc((void **)&ch,4*sizeof(int));
h_ch[0] = 0;
h_ch[1] = 0;
h_ch[2] = 0;
h_ch[3] = 0;
cudaMemcpy(ch,h_ch,4*sizeof(int),cudaMemcpyHostToDevice);
//Test<<<640,480>>>(ch);
test(h_ch);
//cudaMemcpy(h_ch,ch,4*sizeof(int),cudaMemcpyDeviceToHost);
for(int i = 0;i < 4;i++) printf("%d ",h_ch[i]);
int a;
std::cin >> a;
return 0;
}
有几个问题。
您有多个线程在尝试更新两个位置
ch[0]
和ch[1]
时相互踩踏。在 GPU 中,多个线程并行执行。当所有这些线程都试图同时更新同一个位置时,就会出现混乱。如果您想看到此代码正常工作,请将您的普通更新(例如ch[1]++;
)替换为原子更新(例如atomicAdd(ch+1, 1);
你的 GPU 代码和 CPU 代码在逻辑上是不一样的。您的 GPU 代码让每个线程更新
ch[0]
和ch[1]
一次,因此如果上面 #1 中的问题得到解决,这些位置的结束数字应该分别为 640 和 480。但是您的 CPU 代码在循环中执行ch[1]
的更新,每次ch[0]
的更新执行 480 次。我们可以通过将 GPU 代码修改为类似于 CPU 代码来解决此问题,反之亦然,从逻辑上讲,将 CPU 代码修改为类似于 GPU 代码。
以下代码解决了上述 2 个问题,将 CPU 代码修改为类似于 GPU,ch[0]
和 ch[1]
中的预期结果均为 307200 CPU 和 GPU:
$ cat t609.cu
#include <stdio.h>
#include <iostream>
int *h_ch , *ch;
__global__ void Test (int *ch)
{
long i = blockIdx.x;
long u = threadIdx.x;
if (i < 640)
atomicAdd(ch,1);
if (u < 480)
atomicAdd(ch+1,1);
}
void test (int *h_ch)
{
for(int a = 0;a < 640;a++)
for(int b = 0;b < 480;b++){
h_ch[0]++;
h_ch[1]++;}
}
int main()
{
h_ch = (int *)malloc(4*sizeof(int));
cudaMalloc((void **)&ch,4*sizeof(int));
h_ch[0] = 0;
h_ch[1] = 0;
h_ch[2] = 0;
h_ch[3] = 0;
cudaMemcpy(ch,h_ch,4*sizeof(int),cudaMemcpyHostToDevice);
Test<<<640,480>>>(ch+2);
test(h_ch);
cudaMemcpy(h_ch+2,ch+2,2*sizeof(int),cudaMemcpyDeviceToHost);
for(int i = 0;i < 4;i++) printf("%d \n",h_ch[i]);
return 0;
}
$ nvcc -arch=sm_20 -o t609 t609.cu
$ ./t609
307200
307200
307200
307200
$