2
// 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

Matt
  • 74,352
  • 26
  • 153
  • 180
Nancha
  • 21
  • 4
  • Please do not vandalize your post. Note that once you post a question or answer to this site, those posts become part of the collective efforts of others who have also contributed to that content. Posts that are potentially useful to others should not be removed except under extraordinary circumstances. Even if the post is no longer useful to the original author, that information is still beneficial to others who may run into similar problems in the future - this is the underlying philosophy of Stack Exchange. – Matt Sep 20 '16 at 18:08
  • You may also be interested in the code here, which uses SIMD vectorization to get extra speed-ups: https://stackoverflow.com/questions/48069990/multithreaded-simd-vectorized-mandelbrot-in-r-using-rcpp-openmp – Tom Wenseleers Jan 24 '18 at 16:24
  • how can it be done using OpenMPI? @Matt – Srijan Chaudhary Sep 13 '18 at 06:32

1 Answers1

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).

Harald
  • 3,110
  • 1
  • 24
  • 35
  • 2
    Computing the Mandelbrot set is a canonical example of a badly balanced problem. I would therefore add `schedule(dynamic[,something_small])` to the `parallel for` in `mandelbrotSetCount`. – Hristo Iliev Sep 01 '16 at 11:40
  • You may also be interested in the code here, which uses SIMD vectorization to get extra speed-ups: https://stackoverflow.com/questions/48069990/multithreaded-simd-vectorized-mandelbrot-in-r-using-rcpp-openmp – Tom Wenseleers Jan 24 '18 at 16:24