使用Thust OMP在CPU上并行化蒙特卡罗

时间:2014-08-14 20:21:58

标签: multithreading thrust montecarlo openmp

目标是使用thrust :: omp

并行化蒙特卡罗过程
int main()
{
  unsigned Nsimulations = 1000;
  // construct some objects here that will be required for Monte Carlo
  A a;
  B b;
  C c;

  /*
   * use thrust::omp to run the simulation Nsimulation times
   * and write a custom reduction function (a sum for objects of type R)
   */
}

// this is the Monte Carlo function - it needs the global variables a, b, c
// passed by reference because they are very large; the return type is R
R monteCarlo(A& a, B& b, C& c)
{
   // something supercomplicated here
   return r;
}

我需要知道:

  1. if / how如何访问全局变量a,b,c(只读,所以这里没有竞争条件问题)
  2. 如何设置线程数量(Nsimulations的数量可能更多,所以我不希望这样做太过分了。
  3. 我想运行monteCarlo函数Nsimulation次,并可能将它们存储在一个向量中,最终要么减少推力,要么减少序列,因为这不是耗时的部分。

1 个答案:

答案 0 :(得分:1)

正如我在your previous question中所说,你必须learn more about thrust才能回答这样的问题对你有任何意义。

你可以这样做:

thrust::generate(...);

to generate您的初始随机数。这里矢量的长度是你想要的模拟数量。

然后你可以这样做:

thrust::for_each(...);

传递先前生成的随机数向量作为输入,可能用结果向量压缩。 for_each operation将使用自定义函数来执行monteCarlo例程,作为对输入向量中每个随机数元素的单独调用。每个输入元素的monteCarlo例程的输出将进入结果向量中的相应位置。 A,B,C全局变量中的参数/数据可以通过引用作为初始化参数传递给for_each使用的仿函数。

然后你可以这样做:

thrust::reduce(...);

在先前生成的结果向量上,创建最终缩减。

我不会关心你想要做的模拟到OMP线程的映射。 Thrust会处理这个问题,正如#pragma omp parallel for会在OMP案例中处理它一样。

这是一个完全有效的例子:

$ cat t536.cpp
#include <iostream>
#include <stdlib.h>
#include <thrust/system/omp/execution_policy.h>
#include <thrust/system/omp/vector.h>
#include <thrust/reduce.h>
#include <thrust/for_each.h>
#include <thrust/iterator/zip_iterator.h>


struct A {
  unsigned a;
};

struct B {

  int b;
};

struct C {

  float c;
};

A a;
B b;
C c;

float monteCarlo(int rn){

  return ((rn % a.a)+ b.b)/c.c;
}

struct my_functor
{
  template <typename Tuple>
  void operator()(const Tuple &data) const{

    thrust::get<1>(data) = monteCarlo(thrust::get<0>(data));
   }
};


int main(int argc, char *argv[]){
  a.a = 10;
  b.b = 2;
  c.c = 4.5f;
  unsigned N = 10;
  if (argc > 1) N = atoi(argv[1]);
  thrust::omp::vector<unsigned> rands(N);
  thrust::omp::vector<float> result(N);
  thrust::generate(thrust::omp::par, rands.begin(), rands.end(), rand);
  thrust::for_each(thrust::omp::par, thrust::make_zip_iterator(thrust::make_tuple(rands.begin(), result.begin())), thrust::make_zip_iterator(thrust::make_tuple(rands.end(), result.end())), my_functor());
  float answer = thrust::reduce(thrust::omp::par, result.begin(), result.end());
  std::cout << answer << std::endl;
  return 0;
}
$ g++ -O2 -I/usr/local/cuda/include -o t536 t536.cpp -fopenmp -lgomp
$ ./t536 10
14.8889
$

(答案应该在1.444 * N的数据类型限制内收敛,因为N变大,对于a,b,c的这些选择)

正如@JaredHoberock在你上一个问题中提到的那样,推力monte carlo example可能会引起人们的兴趣。它演示了操作的“融合”,以便类似的活动可以减少到单个推力调用。上述计划也可能减少到一个推力调用。