【发布时间】:2016-08-07 20:02:21
【问题描述】:
我正在编写一个程序来并行执行多个集成副本,以加快对 50000 个不同输入的评估。代码通常需要大约 0.0005 秒才能在单个 CPU 内核上的 C++ 及其内部循环中运行我的测试运行了大约 3000 个周期,所以我认为在 gpu 线程上运行可能不会太复杂。另外,我使用 Visual Studio 2013 和 GTX 860m 编写程序,没有编译其他用 CUDA C 编写的程序。
这是我的代码:(你可以从这里获取数据文件ElCentro-import2.txt)
#include <stdio.h>
#include<iostream>
#include <math.h>
#include <fstream>
#include <cmath>
#include <cuda_runtime.h>
using namespace std;
__global__ void
vectorAdd(const float *A, const float *p, float *u, float *v, float *a, float *fs, float *rhat, float *phat, int j, int numElements)
{
int ni = blockDim.x * blockIdx.x + threadIdx.x;
int ti = 10000 * ni;
float t = A[ni];
float m = 1.0f;
float epsilon = 10.0f;
float gamma = 0.5f;
float beta = 1.0f / 4.0f;
float pi = 3.14159f;
float ksy = 0.04f;
float dt = 0.02f;
float fy = 1000.0f;
float c = 4.0f * ksy * pi / t;
float a1 = m / (beta * dt * dt) + gamma * c / (beta * dt);
float a2 = m / (beta * dt) + c*(gamma / beta - 1.0f);
float a3 = (1.0f / (2.0f *beta) - 1.0f)* m + dt*(gamma / (2.0f *beta) - 1.0f) *c;
float k = m * (2.0f*pi / t)*(2.0f*pi / t);
float fz;
float ab;
if (ni < numElements)
{
v[10000 * ni] = 0.0f;
u[10000 * ni] = 0.0f;
fs[10000 * ni] = 0.0f;
a[10000 * ni] = 0.0f;
for (size_t i = 0 + 10000 * ni; i < j-1 + 10000 * ni; i++)
{
u[i + 1] = u[i];
fs[i + 1] = fs[i];
phat[i + 1] = p[i + 1] + a1 * u[i] + a2*v[i] + a3*a[i];
rhat[i + 1] = phat[i + 1] - fs[i + 1] - a1 * u[i + 1];
ab = std::fabsf(rhat[i + 1]);
while (ab >= epsilon)
{
u[i + 1] = u[i + 1] + rhat[i + 1] / (k + a1);
fz = fs[i] + k*(u[i + 1] - u[i]);
if (fz > 0.0)
{
fs[i + 1] = fminf(fz, fy);
}
else
{
fs[i + 1] = fmaxf(fz, -fy);
}
rhat[i + 1] = phat[i + 1] - fs[i + 1] - a1 * u[i + 1];
ab = std::fabsf(rhat[i + 1]);
}
v[i + 1] = gamma*(u[i + 1] - u[i]) / beta / dt + (1.0f - gamma / beta)*v[i] + dt*(1.0f - gamma / 2.0f / beta)*a[i];
a[i + 1] = (u[i + 1] - u[i]) / beta / dt / dt - (1.0f / beta / dt)*v[i] + (1.0f - 1.0f / 2.0f / beta)*a[i];
}
}
}
int
main(void)
{
int numElements = 16;
int kore;
FILE* myfile;
size_t size = numElements * sizeof(float);
printf("[Vector addition of %d elements]\n", numElements);
float *h_data = (float *)malloc(10000);
float *h_datat = (float *)malloc(10000);
myfile = fopen("ElCentro-import2.txt", "r");
std::cout << "file is opened\n";
kore = 0;
while (EOF != fscanf(myfile, "%f %f \n", &h_datat[kore], &h_data[kore]))
{
kore++;
}
std::cout << kore << "file is read\n";
kore--;
size_t nsize = 10000 * numElements * sizeof(float);
float *h_A = (float *)malloc(size);
float *h_u = (float *)malloc(nsize);
float *h_v = (float *)malloc(nsize);
float *h_a = (float *)malloc(nsize);
float *h_p = (float *)malloc(nsize);
for (int i = 0; i < kore; ++i)
{
h_p[i] = -10000 * h_data[i];
}
for (int i = 0; i < numElements; ++i)
{
h_A[i] = 1.0f;
}
float *d_A = NULL;
err = cudaMalloc((void **)&d_A, size);
float *d_p = NULL;
err = cudaMalloc((void **)&d_p, nsize);
float *d_u = NULL;
err = cudaMalloc((void **)&d_u, nsize);
float *d_v = NULL;
err = cudaMalloc((void **)&d_v, nsize);
float *d_a = NULL;
err = cudaMalloc((void **)&d_a, nsize);
float *d_fs = NULL;
err = cudaMalloc((void **)&d_fs, nsize);
float *d_rhat = NULL;
err = cudaMalloc((void **)&d_rhat, nsize);
float *d_phat = NULL;
err = cudaMalloc((void **)&d_phat, nsize);
printf("Copy input data from the host memory to the CUDA device\n");
err = cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
err = cudaMemcpy(d_p, h_p, nsize, cudaMemcpyHostToDevice);
int threadsPerBlock = 1;
int blocksPerGrid = (numElements + threadsPerBlock - 1) / threadsPerBlock;
printf("CUDA kernel launch with %d blocks of %d threads\n", blocksPerGrid, threadsPerBlock);
vectorAdd <<<blocksPerGrid, threadsPerBlock >>>(d_A, d_p, d_u, d_v, d_a, d_fs, d_rhat, d_phat, kore-1, numElements);
err = cudaGetLastError();
cudaDeviceSynchronize();
printf("Copy output data from the CUDA device to the host memory\n");
err = cudaMemcpy(h_u, d_u, nsize, cudaMemcpyDeviceToHost);
}
for (int i = 0; i < numElements; ++i)
{
std::cout << h_u[1000+kore * i] << "\n";;
}
printf("Test PASSED\n");
err = cudaFree(d_A);
err = cudaFree(d_p);
err = cudaFree(d_u);
err = cudaFree(d_v);
err = cudaFree(d_a);
err = cudaFree(d_fs);
err = cudaFree(d_rhat);
err = cudaFree(d_phat);
free(h_A);
free(h_p);
free(h_u);
free(h_v);
free(h_a);
free(h_data);
free(h_datat);
err = cudaDeviceReset();
printf("Done\n");
return 0;
}
我的问题是,当我尝试将结果从设备复制到主机时(比如将 d_u 复制到 h_u),它会生成我的错误检查短语:
Failed to copy vector u from device to host (error code uspecified launch failure)
此外,如果我将内核同步代码 (cudaDeviceSynchronize()) 移到内核调用之后,它还会生成有关内核启动的错误报告。我对 C++ 和 CUDA 编程很陌生,这个问题让我困惑了好几天。
这部分应该多次打印相同的值(~21.8)(对于numElements>1)
for (int i = 0; i < numElements; ++i)
{
std::cout << h_u[1000+kore * i] << "\n";;
}
更新
如果我将numElements 的值设置为1,则代码运行良好,但这不是并行计算的重点。我还检查了 GPU-Z 中的 GPU 统计数据,内存利用率小于 1 MB,最大 GPU 负载小于 1%。 (发布构建)
【问题讨论】:
-
请编辑您的问题并重新格式化您的代码。从字面上看,您发布的内容中有一半是无意义的 cmets 或空行。如果你希望别人看你的一百行代码,至少让他们的工作不那么艰巨。
-
为什么在内核代码中使用
std::fabsf?您是在 Visual Studio 中构建调试项目还是发布项目?你在什么GPU上运行这个?您是否为该 GPU 正确设置了编译目标? -
@RobertCrovella 我猜这是一个坏习惯(std::)。不过非常感谢您指出可能的设置!
标签: c++ visual-c++ parallel-processing cuda