mandelbrot using openMP

时间:2016-08-31 17:01:36

标签: openmp mandelbrot

// return 1 if in set, 0 otherwise
int inset(double real, double img, int maxiter){
    double z_real = real;
    double z_img = img;
    for(int iters = 0; iters < maxiter; iters++){
        double z2_real = z_real*z_real-z_img*z_img;
        double z2_img = 2.0*z_real*z_img;
        z_real = z2_real + real;
        z_img = z2_img + img;
        if(z_real*z_real + z_img*z_img > 4.0) return 0;
    }
    return 1;
}

// count the number of points in the set, within the region
int mandelbrotSetCount(double real_lower, double real_upper, double img_lower, double img_upper, int num, int maxiter){
    int count=0;
    double real_step = (real_upper-real_lower)/num;
    double img_step = (img_upper-img_lower)/num;
    for(int real=0; real<=num; real++){
        for(int img=0; img<=num; img++){
            count+=inset(real_lower+real*real_step,img_lower+img*img_step,maxiter);
        }
    }
    return count;
}


// main
int main(int argc, char *argv[]){
    double real_lower;
    double real_upper;
    double img_lower;
    double img_upper;
    int num;
    int maxiter;
    int num_regions = (argc-1)/6;
    for(int region=0;region<num_regions;region++){
        // scan the arguments
        sscanf(argv[region*6+1],"%lf",&real_lower);
        sscanf(argv[region*6+2],"%lf",&real_upper);
        sscanf(argv[region*6+3],"%lf",&img_lower);
        sscanf(argv[region*6+4],"%lf",&img_upper);
        sscanf(argv[region*6+5],"%i",&num);
        sscanf(argv[region*6+6],"%i",&maxiter);     
        printf("%d\n",mandelbrotSetCount(real_lower,real_upper,img_lower,img_upper,num,maxiter));
    }
    return EXIT_SUCCESS;
}

I need to convert the above code into openMP. I know how to do it for a single matrix or image but i have to do it for 2 images at the same time

the arguments are as follows

$./mandelbrot -2.0 1.0 -1.0 1.0 100 10000 -1 1.0 0.0 1.0 100 10000

Any suggestion how to divide the work in to different threads for the two images and then further divide work for each image. thanks in advance

1 个答案:

答案 0 :(得分:2)

If you want to process multiple images at a time, you need to add a #pragma omp parallel for into the loop in the main body such as:

#pragma omp parallel for private(real_lower, real_upper, img_lower, img_upper, num, maxiter)
for(int region=0;region<num_regions;region++){
    // scan the arguments
    sscanf(argv[region*6+1],"%lf",&real_lower);
    sscanf(argv[region*6+2],"%lf",&real_upper);
    sscanf(argv[region*6+3],"%lf",&img_lower);
    sscanf(argv[region*6+4],"%lf",&img_upper);
    sscanf(argv[region*6+5],"%i",&num);
    sscanf(argv[region*6+6],"%i",&maxiter);
    printf("%d\n",mandelbrotSetCount(real_lower,real_upper,img_lower,img_upper,num,maxiter));
}

Notice that some variables need to be classified as private (i.e. each thread has its own copy).

Now, if you want additional parallelism you need nested OpenMP (see nested and NESTED_OMP in OpenMP specification) as the work will be spawned by OpenMP threads -- but note that nesting may not give you a performance boost always.

In this case, what about adding a #pragma omp parallel for (with the appropriate reduction clause so that each thread accumulates into count) into the mandelbrotSetCount routine such as

// count the number of points in the set, within the region

int mandelbrotSetCount(double real_lower, double real_upper, double img_lower, double img_upper, int num, int maxiter)
{
  int count=0;
  double real_step = (real_upper-real_lower)/num;
  double img_step = (img_upper-img_lower)/num;

  #pragma omp parallel for reduction(+:count)
  for(int real=0; real<=num; real++){
    for(int img=0; img<=num; img++){
        count+=inset(real_lower+real*real_step,img_lower+img*img_step,maxiter);
    }
  }
  return count;
}

The whole approach would split images between threads first and then the rest of the available threads would be able to split the loop iterations in this routine among all the available threads each time you invoke the routine.

EDIT

As user Hristo suggest's on the comments, the mandelBrotSetCount routine might be unbalanced (the best reason is that the user simply requests a different number of maxiter) on each invocation. One way to address this performance issue might be to use dynamic thread scheduling in the routine. So rather than having

  #pragma omp parallel for reduction(+:count)

we might want to have

  #pragma omp parallel for reduction(+:count) schedule(dynamic,N)

and here N should be a relatively small value (and likely larger than 1).