Example OpenMP Program: Find minimum in an array

  • Problem description:

    • Given an array of double typed values x[MAX]

    • Find the minimum value stored in the array x[MAX]


  • Solution using N team threads:

    1. Split the array x[MAX] into N equal segments

    2. Thread k performs:

      • Finds the minimum in segment k of the array

      • Save the minimum found in variable Tmin[k]

    Post-processing after the parallel region:

    • Find the overall minimum in the Tmin[ ] outputs

Example OpenMP Program: Find minimum in an array

  • How to split the array into N equal segments:

  • Work load distribution for a specific thread s:

      Let   n = MAX/N   (MAX = # array elements, N = #threads)
    
      Thread 0:   finds minimum over    x[ 0]     .. x[ n-1]
      Thread 1:   finds minimum over    x[ n]     .. x[2n-1]
      ...
      Thread s:   finds minimum over    x[(s)n]   .. x[(s+1)n-1]
      ...
      Thread N-1: finds minimum over    x[(N-1)n] .. x[MAX]
    

Example OpenMP Program: Find minimum in an array

OpenMP program to find the minimum in an array:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel
   {
      int nThreads = omp_get_num_threads(); 
      int id = omp_get_thread_num();

      int n, start, stop;
      double my_min;

      n = MAX/nThreads;              // Step size

      start = id * n;
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

Example OpenMP Program: Find minimum in an array

Define the parallel region (code will be executed by num_threads threads):

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int id = omp_get_thread_num();


      int n, start, stop;
      double my_min;

      n = MAX/num_threads;              // Step size

      start = id * n;
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

Example OpenMP Program: Find minimum in an array

Find the thread ID and the number of threads:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads(); 
      int id = omp_get_thread_num();

      int n, start, stop;
      double my_min;

      n = MAX/nThreads;              // Step size

      start = id * n;
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

Example OpenMP Program: Find minimum in an array

Find the segment size for the thread    (work distribution: thread 0: [0..n), thread 1: [n..2n), etc):

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      int n, start, stop;
      double my_min;

      n = MAX/nThreads;              // Segment size

      start = id * n;
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

Example OpenMP Program: Find minimum in an array

Find the segment range for the thread    (work distribution: thread 0: [0..n), thread 1: [n..2n), etc):

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      int n, start, stop;
      double my_min;

      n = MAX/nThreads;              // Segment size

      start = id * n;                   // Start index for thread "id"
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

Example OpenMP Program: Find minimum in an array

Find the minimum value per thread:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      int n, start, stop;
      double my_min;

      n = MAX/nThreads;              // Segment size

      start = id * n;                   // Start index for thread "id"
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

Example OpenMP Program: Find minimum in an array

Store the minimum value in Tmin[id]:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      int n, start, stop;
      double my_min;

      n = MAX/nThreads;              // Segment size

      start = id * n;                   // Start index for thread "id"
      stop = ( (start + n < MAX) ? (start + n) : MAX );

      my_min = x[start];

      for ( int i = start+1; i < stop; i++ )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

DEMO: demo/OpenMP/openMP-min.c

An alternate way to distribute the work load

  • Alternate way to distribute the work load for 2 threads:

                    values handled by thread 0
       |   |   |   |   |   |   |   |   |   |   |   |   |   |
       V   V   V   V   V   V   V   V   V   V   V   V   V   V
       |-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|-|      
         ^   ^   ^   ^   ^   ^   ^   ^   ^   ^   ^   ^   ^   ^
         |   |   |   |   |   |   |   |   |   |   |   |   |   |
                    values handled by thread 1
    
              Thread 0                Thread 1
                  |                        |
                  |                        |
                  V                        V
               Tmin[0]                 Tmin[1]
                   \                      /
                    \                    /
                     \                  /
                      \                /
                       \              /
    		      main thread
    			   |
    			   |
    			   V
    		      Actual minimum
    

An alternate way to distribute the work load

OpenMP program to find the minimum in an array using the alternate work load distribution:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel
   {

      int id = omp_get_thread_num();

      double my_min;

      my_min = x[id];

      for ( int i = id+num_threads; i < MAX; i += num_threads )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

An alternate way to distribute the work load

Define the parallel region (code will be executed by num_threads threads):

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int id = omp_get_thread_num();


      double my_min;

      my_min = x[id];

      for ( int i = id+num_threads; i < MAX; i += num_threads )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

An alternate way to distribute the work load

Find the thread ID and the number of threads:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      double my_min;

      my_min = x[id];

      for ( int i = id+num_threads; i < MAX; i += num_threads )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

An alternate way to distribute the work load

Find the minimum value over the values x[id], x[id+num_threads], x[id+2*num_threads], ...:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      double my_min;

      my_min = x[id];

      for ( int i = id+nThreads; i < MAX; i += nThreads )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

 

An alternate way to distribute the work load

Store the minimum value in Tmin[id]:

double x[MAX];       // Input data
double Tmin[100];    // The min found by each thread

int main(int argc, char *argv[])
{
   omp_set_num_threads( num_threads );  // Set thread group size

   #pragma omp parallel 
   {
      int nThreads = omp_get_num_threads();
      int id = omp_get_thread_num();

      double my_min;

      my_min = x[id];

      for ( int i = id+nThreads; i < MAX; i += nThreads )
         if ( x[i] < my_min )
            my_min = x[i];

      Tmin[id] = my_min;
   }

   /* Post-processing: find min in Tmin[ ] (omitted for brevity) */
}

DEMO: demo/OpenMP/openMP-min2.c