Search code examples
c++multithreadingopenmp

C++ omp no significant improvement


I am on MSVC 2019 with the default compiler. The code I am working on is a Mandelbrot image. Relevant bits of my code looks like:

#pragma omp parallel for
for (int y = 0; y < HEIGHT; y++)
    {
       for (int x = 0; x < WIDTH; x++)
           {  
               unsigned int retVal = mandel(x_val + x_incr * x, y_val + y_incr * y);
               mtest.setPixels(x, y,
                        static_cast<unsigned char>(retVal / 6),
                        static_cast<unsigned char>(retVal / 5),
                        static_cast<unsigned char>(retVal / 4));

           } 
     }

All of the variables outside of the loop are constexpr, eliminating any dependencies. The mandel function does about 1000 iterations with each call. I would expect the outer loop to run on several threads but my msvc records each run at about 5-6 seconds with or without the omp directive.

Edit (The mandel function):

unsigned int mandel(long double x, long double y)
{
    long double z_x = 0;
    long double z_y = 0;

    for (int i = 0; i < ITER; i++)
    {
        long double temp = z_x;
        z_x = (z_x * z_x) - (z_y * z_y) + x;
        z_y = 2 * temp * z_y + y;

        if ((z_x * z_x + z_y * z_y) > 4)
            return i;
    }
    return ITER; //ITER is a #define macro
}

Solution

  • Your mandel function has a vastly differing runtime cost depending on whether the if condition within the loop has been met. As a result, each iteration of your loop will run in a different time. By default omp uses static scheduling (i.e. break loop into N partitions). This is kinda bad, because you don't have a workload that fits static scheduling. See what happens when you use dynamic scheduling.

    #pragma omp parallel for schedule(dynamic, 1)
    for (int y = 0; y < HEIGHT; y++)
        {
           for (int x = 0; x < WIDTH; x++)
               {  
                   unsigned int retVal = mandel(x_val + x_incr * x, y_val + y_incr * y);
                   mtest.setPixels(x, y,
                            static_cast<unsigned char>(retVal / 6),
                            static_cast<unsigned char>(retVal / 5),
                            static_cast<unsigned char>(retVal / 4));
    
               } 
         }
    

    Also time to rule out the really dumb stuff.....

    1. Have you included omp.h at least once in your program?
    2. Have you enabled omp in the project settings?

    IIRC, if you haven't done those two things, omp will be disabled under MSVC.