在具有多个源文件的程序中定义CUDA内核的位置

时间:2017-08-20 20:22:47

标签: c++ cuda

请参阅下面的粗体问题。

我有一个功能C ++程序,我想用CUDA重写。我已经从各种NVIDIA教程和Udacity课程中获得了对如何使用CUDA的合理理解。但我的问题是:在这些教程中的所有示例中,它们总是使用具有非常简单结构的程序作为示例。通常,它只是一个.cu文件,其中包含各种内核定义,后跟一个main()函数,它执行一些操作,分配一些设备内存,并运行内核。虽然这些简单的示例有助于我了解如何使用CUDA,但它们并不能帮助我理解如何将CUDA代码集成到包含类的更复杂的程序中。这是关于如何构建CUDA程序的问题。

让我们具体化:

我有一个串行粒子过滤器程序,包含以下源文件:

  • main.cpp运行主程序
  • particle_filter.hparticle_filter.cpp包含一个包含粒子过滤器所有逻辑的类
  • 与我的问题无关的其他一些头文件

粒子过滤器类中发生的大量计算是并行化的完美用例。在粒子过滤器类的许多方法中,我想用内核调用替换循环。

我的问题是:

这些内核的定义应该在哪里?

感谢您的帮助

根据下面的评论,这里是particle_filter.cpp中定义的一种方法的代码。该方法初始化粒子过滤器对象。我想用内核调用替换方法内的for循环。我在哪里定义内核?内核定义是否成为该类的另一种方法?或者我应该在别处定义内核?内核是应该在同一个源文件中还是在单独的源文件中定义?我知道这最终取决于我,但这里的最佳做法是什么?

void ParticleFilter::init(double x, double y, double theta, double std[]) {

  // Set the number of particles
  num_particles = 100;

  // Declare the random generator
  default_random_engine gen;

  // Extract the standard deviations for x, y, and theta
  double std_x = std[0];
  double std_y = std[1];
  double std_theta = std[2];

  // Creates normal distributions for x, y and theta.
  normal_distribution<double> dist_x(x, std_x);
  normal_distribution<double> dist_y(y, std_y);
  normal_distribution<double> dist_theta(theta, std_theta);

  // Create the vector to contain the `num_particles` particles
  particles = vector<Particle>(num_particles);

  // Create the vector to contain the weight for each particle
  weights = vector<double>(num_particles);

  // Loop over the particle vector and initialize each particle with the initial (x,y,theta) position
  // passed in the arguments with added Gaussian noise and weight 1
  for (int i = 0; i < num_particles; i++) {

    particles[i].id = i; // Set this particle's ID
    particles[i].x = dist_x(gen); // Generate a random value from `dist_x` to set as this particle's x position
    particles[i].y = dist_y(gen); // Generate a random value from `dist_y` to set as this particle's y position
    particles[i].theta = dist_theta(gen); // Generate a random value from `dist_theta` to set as this particle's orientation theta
    particles[i].weight = 1.0; // Set the initial weight for all particles to 1

  }

  is_initialized = true;

}

1 个答案:

答案 0 :(得分:3)

您描述的程序仍然非常简单(这就是为什么我能够冒险回答......也忽略了您的代码)。

我认为您需要做的是以下内容:

  1. 确定程序的哪些部分涉及大量可并行化的工作(不管现在的结构如何;考虑完成的整个工作抽象。)
  2. 确定数据是否完全适合GPU全局内存。

    2.1如果确实如此,初始化也可能与GPU相关。

    2.2如果没有,那么在GPU上初始化东西的可能性就越小,但是如果你在CPU上做它,它仍然需要有效且多线程,否则GPU可能只是相关的简单的缘故。

  3. 每个内核都有一个.cu文件(对于内核调用的设备端函数可能.cuh),或者可能是密切相关的内核组。 (还要记住,不同类型的相同功能=单个模板中的单个模板化内核。)
  4. 有一些包装器/网桥/任何代码片段,带有纯C ++标头但是CUDA实现,它实际上启动了东西(你必须从普通的C ++到CUDA)。现在,很可能其他人已经实现了你可以使用的东西,但你也可以自己写一些简单的东西。你可能需要这样一个包装器来存在每个内核,或者它可能是一个重要的东西。
  5. 你的main.cpp包含了包装器头,并使用它启动内核;这是有效的,因为您将CUDA编译和主机编译器编译的代码链接在一起。
  6. 我希望没有具体的例子我能够理解。

    部分具体示例

    上述建议中最棘手的一点是绝对没有。 4.这是我在自己的代码中使用的“桥接”正常编译和NVCC编译的代码:

    请注意,第一个文件是我的轻量级Modern-C ++ - ish CUDA Runtime API wrapper library的一部分,这使得主机端编码在几个方面更加方便。