私はCUDA/C++を試していて、nボディシミュレータを作ることに決めました。 4096個の粒子間の重力引力をシミュレートします。それは約2または3FPSで動作し、私は完全になぜそうは分かりません。使用しているグラフィックスカードはGTX 980 Tiですので、プログラムがスムーズに動くことを期待しています。私はそれがおそらく最高のものに最適化されていないと理解していますが、それほどゆっくり動くとは思っていませんでした。CUDAプログラムが期待通りに動作しない
コードはプロトタイプであると仮定されているため、コードはどのような方法でもきちんと書かれていません。
main.cu
#include <Windows.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <vector>
#include <math.h>
#include "Particle.h"
#include <cuda_runtime.h>
#include <device_launch_parameters.h>
#include <ctime>
#include <string>
#define N 4096
#define DT 0.00001
# define M_PI 3.14159265358979323846 /* pi */
using namespace std;
Particle p[N];
int frames = 0;
clock_t starttime = clock();
clock_t timepassed = 0;
bool first = true;
float fps = 0.0f;
__global__ void updateParticle(Particle* out, Particle *pin)
{
int i = blockIdx.x * blockDim.x + threadIdx.x;
double velx = 0;
double vely = 0;
out[i].mass = pin[i].mass;
for(int j = 0; j < N; j++)
{
if (i == j || pin[j].mass == 0 || pin[i].mass == 0)
continue;
double difx = pin[i].posx - pin[j].posx;
double dify = pin[i].posy - pin[j].posy;
double len = difx * difx + dify * dify;
if (len == 0)
continue;
double force = (pin[i].mass * pin[j].mass)/len;
len = sqrt(len);
double dirx = -difx/len;
double diry = -dify/len;
dirx *= force;
diry *= force;
velx += (dirx/pin[i].mass + pin[i].velx) * DT;
vely += (diry/pin[i].mass + pin[i].vely) * DT;
}
out[i].posx = pin[i].posx + velx;
out[i].posy = pin[i].posy + vely;
out[i].velx = pin[i].velx;
out[i].vely = pin[i].vely;
while (out[i].posx > 1)
out[i].posx--;
while (out[i].posx < -1)
out[i].posx++;
while (out[i].posy > 1)
out[i].posy--;
while (out[i].posy < -1)
out[i].posy++;
}
void changeViewPort(int w, int h)
{
glViewport(0, 0, w, h);
}
void renderMore()
{
for (int i = 0; i < N; ++i)
{
if (p[i].mass == 0)
continue;
if (p[i].mass == 1)
glColor3f(1, 1, 1);
else
glColor3f(1, 0, 0);
glBegin(GL_LINE_LOOP);
for (int j = 0; j <= 4; j++) {
double angle = 2 * M_PI * j/300;
double x = cos(angle) * 0.001;
double y = sin(angle) * 0.001;
x *= p[i].mass;
y *= p[i].mass;
glVertex2d(x + p[i].posx, y + p[i].posy);
}
glEnd();
}
}
void render(void)
{
if(first)
{
frames = 0;
starttime = clock();
first = false;
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderMore();
glutSwapBuffers();
frames++;
}
void moveCuda(Particle* in, Particle* out)
{
Particle *device_p = nullptr;
Particle *device_res = nullptr;
cudaError_t cudaStatus;
int size = N * sizeof(Particle);
cudaStatus = cudaMalloc((void**)&device_res, size);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
}
cudaStatus = cudaMalloc((void**)&device_p, size);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMalloc failed!");
}
cudaStatus = cudaSetDevice(0);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaSetDevice failed! Do you have a CUDA-capable GPU installed?");
}
// Copy input vectors from host memory to GPU buffers.
cudaStatus = cudaMemcpy(device_p, in, size, cudaMemcpyHostToDevice);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
}
updateParticle << <N/1024, 1024 >> >(device_res, device_p);
cudaStatus = cudaGetLastError();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "kernel launch failed: %s\n", cudaGetErrorString(cudaStatus));
}
cudaStatus = cudaDeviceSynchronize();
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaDeviceSynchronize returned error code %d after launching addKernel!\n", cudaStatus);
}
cudaStatus = cudaMemcpy(out, device_res, size, cudaMemcpyDeviceToHost);
if (cudaStatus != cudaSuccess) {
fprintf(stderr, "cudaMemcpy failed!");
}
cudaFree(device_res);
cudaFree(device_p);
}
void update(int)
{
Particle temp[N] = {};
moveCuda(p, temp);
for (int i = 0; i < N; ++i)
p[i] = temp[i];
fps = (double)frames/((clock() - starttime)/1000);
const string a = "FPS: " + to_string(fps);
glutSetWindowTitle(a.c_str());
glutTimerFunc(100.0/60, update, -1);
}
void idle()
{
glutPostRedisplay();
}
int main(int argc, char* argv[])
{
for (int i = 0; i < N; ++i)
{
p[i] = Particle();
}
// Initialize GLUT
glutInit(&argc, argv);
// Set up some memory buffers for our display
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
// Set the window size
glutInitWindowSize(1000, 1000);
// Create the window with the title "Hello,GL"
glutCreateWindow("Hello World");
// Bind the two functions (above) to respond when necessary
glutReshapeFunc(changeViewPort);
glutDisplayFunc(render);
glutTimerFunc(100.0/60, update, -1);
glutIdleFunc(idle);
// Very important! This initializes the entry points in the OpenGL driver so we can
// call all the functions in the API.
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW error");
return 1;
}
render();
glutMainLoop();
return 0;
}
Particle.cpp
#include "Particle.h"
#include "stdlib.h"
#include <host_defines.h>
Particle::Particle()
{
posx = (((double)rand()/(RAND_MAX)) * 2) - 1;
posy = (((double)rand()/(RAND_MAX)) * 2) - 1;
velx = ((((double)rand()/(RAND_MAX)) * 2) - 1)/4;
vely = ((((double)rand()/(RAND_MAX)) * 2) - 1)/4;
mass = 1;
}
Particle.h
#pragma once
class Particle
{
public:
Particle();
void Update();
double posx;
double posy;
double velx;
double vely;
double mass;
};
Iは、グラフィックス・デバイスを設定する行を削除すると、それがエラーをスローするが、継続2〜3フレーム/秒で動作します。これは私がグラフィックカードを手に入れることができないことを示しているかもしれませんが、私はこれをどうしたらいいのか分かりません。私はそれをcudaSetDevice(0)に設定すると、エラーをスローしません。グラフィックスカードが動作しており、モニタが接続されていて動作しています。
誰かが指針やアドバイスを提供できるのであれば、私は大いに感謝しています。
エラー: 'Particle'にメンバー 'p'がありません。誰かがコンパイルできるコードを提供してください。 –
コードを更新しました。今すぐコンパイルされます。 –