multidimensional-array - 使用 CUDA 的显式 FDM
问题描述
我正在为以下代码实现 CUDA。第一个版本是串行编写的,第二个版本是用 CUDA 编写的。我确信它在串行版本中的结果。我希望我添加了 CUDA 功能的第二个版本也能给我同样的结果,但似乎内核函数没有做任何事情,它给了我 u 和 v 的初始值。我知道由于我缺乏经验,错误可能很明显,但我无法弄清楚。另外,请不要推荐使用扁平数组,因为我很难理解代码中的索引。第一个版本:
#include <fstream>
#include <iostream>
#include <math.h>
#include <vector>
#include <chrono>
#include <omp.h>
using namespace std;
const int M = 1024;
const int N = 1024;
const double A = 1;
const double B = 3;
const double Du = 5 * pow(10, -5);
const double Dv = 5 * pow(10, -6);
const int Max_Itr = 1000;
const double h = 1.0 / static_cast<double>(M - 1);
const double delta_t = 0.0025;
const double s1 = (Du * delta_t) / pow(h, 2);
const double s2 = (Dv * delta_t) / pow(h, 2);
int main() {
double** u=new double* [M];
double** v=new double* [M];
for (int i=0; i<M; i++){
u[i]=new double [N];
v[i]=new double [N];
}
for (int j = 0; j < M; j++) {
for (int i = 0; i < N;i++) {
u[i][j]=0.02;
v[i][j]=0.02;
}
}
for (int k = 1; k < Max_Itr; k++) {
for (int i = 1; i < N - 1; i++) {
for (int j = 1; j < M - 1; j++) {
u[i][j] = ((1 - (4 * s1)) * u[i][j]) + (s1 * (u[i + 1][j] + u[i - 1][j] + u[i][j + 1] + u[i][j - 1])) +
(A * delta_t) + (delta_t * pow(u[i][j], 2) * v[i][j]) - (delta_t * (B + 1) * u[i][j]);
v[i][j] = ((1 - (4 * s2)) * v[i][j]) + (s2 * (v[i + 1][j] + v[i - 1][j] + v[i][j + 1] + v[i][j - 1])) + (B * delta_t * u[i][j])
- (delta_t * pow(u[i][j], 2) * v[i][j]);
}
}
}
cout<<"u: "<<u[512][512]<<" v: "<<v[512][512]<<endl;
return 0;
}
第二个版本:
#include <fstream>
#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
#define M 1024
#define N 1024
__global__ void my_kernel(double** v, double** u){
int i= blockIdx.y * blockDim.y + threadIdx.y;
int j= blockIdx.x * blockDim.x + threadIdx.x;
double A = 1;
double B = 3;
int Max_Itr = 1000;
double delta_t = 0.0025;
double Du = 5 * powf(10, -5);
double Dv = 5 * powf(10, -6);
double h = 1.0 / (M - 1);
double s1 = (Du * delta_t) / powf(h, 2);
double s2 = (Dv * delta_t) / powf(h, 2);
for (int k = 1; k < Max_Itr; k++) {
u[i][j] = ((1 - (4 * s1))
* u[i][j]) + (s1 * (u[i + 1][j] + u[i - 1][j] + u[i][j + 1] + u[i][j - 1])) +
(A * delta_t) + (delta_t * pow(u[i][j], 2) * v[i][j]) - (delta_t * (B + 1) * u[i][j]);
v[i][j] = ((1 - (4 * s2))
* v[i][j]) + (s2 * (v[i + 1][j] + v[i - 1][j] + v[i][j + 1] + v[i][j - 1])) + (B * delta_t * u[i][j])
- (delta_t * pow(u[i][j], 2) * v[i][j]);
__syncthreads();
}
}
int main() {
double** u=new double* [M];
double** v=new double* [M];
for (int i=0; i<M; i++){
u[i]=new double [N];
v[i]=new double [N];
}
dim3 blocks(32,32);
dim3 grids(M/32 +1, N/32 + 1);
for (int j = 0; j < M; j++) {
for (int i = 0; i < N;i++) {
u[i][j]=0.02;
v[i][j]=0.02;
}
}
double **u_d, **v_d;
int d_size = N * M * sizeof(double);
cudaMalloc(&u_d, d_size);
cudaMalloc(&v_d, d_size);
cudaMemcpy(u_d, u, d_size, cudaMemcpyHostToDevice);
cudaMemcpy(v_d, v, d_size, cudaMemcpyHostToDevice);
my_kernel<<<grids, blocks>>> (v_d,u_d);
cudaDeviceSynchronize();
cudaMemcpy(v, v_d, d_size, cudaMemcpyDeviceToHost);
cudaMemcpy(u, u_d, d_size, cudaMemcpyDeviceToHost);
cout<<"u: "<<u[512][512]<<" v: "<<v[512][512]<<endl;
return 0;
}
我对第二个版本的期望是:
u: 0.2815 v: 1.7581
解决方案
您的二维数组 - 在程序的第一个版本中 - 是使用指针数组实现的,每个指针指向一个单独分配的double
值数组。
在您的第二个版本中,您使用相同的指针到指针double
类型,但是 - 您没有为实际数据分配任何空间,只是为指针数组(并且没有将任何数据复制到GPU - 只是指针;无论如何复制都没有用,因为它们是指向主机端内存的指针。)
最有可能发生的是您的内核尝试访问无效地址的内存,并且它的执行被中止。
正如@njuffa 指出的那样,如果您要正确检查错误,您就会知道发生了什么。
现在,如果您要使用单个数据区域而不是为每个第二维一维数组单独分配,您可以避免进行多次内存分配;对于程序的第一个和第二个版本都是如此。那不完全是阵列展平。在此页面上查看如何执行此操作(C 语言样式)的说明。
但是请注意,您坚持在内核中执行的双重取消引用可能会显着减慢它。
推荐阅读
- java - ReactNative,Android 运行错误:无法从“11.0.1”确定 java 版本。视窗 10
- go - 如何在golang的额外包中使用主包记录器?
- vue.js - Vuex循环对象数组并为key:value创建条件语句
- javascript - 我的导航栏突然向页面左侧滚动,测试“获取”按钮。知道为什么吗?
- arrays - 如何获取 JSON 值以在 VBA-JSON 中工作?
- hadoop - Hive 插入和加载数据查询不起作用
- .net - “延迟”不是任务 .NET 的成员
- python - 我在加载 SpaCy 模型时遇到错误
- html - 在控制器中使用追加数据调用
- php - 在 php 中编写自动回复脚本时,如何更改来自电子邮件的部分?