OpenMP Exercise

  1. Login to the SP machine

    Workshops differ in how this is done. The instructor will go over this beforehand.

  2. Copy the example files

    1. In your home directory, create a subdirectory for the example codes and then cd to it.

      mkdir openMP
      cd  openMP 

    2. Then, copy either the Fortran or the C version of the parallel OpenMP exercise files to your openMP subdirectory:

      C:
      cp  /usr/global/docs/training/blaise/openMP/C/*  ~/openMP
      
      Fortran:
      cp  /usr/global/docs/training/blaise/openMP/Fortran/*  ~/openMP
      

  3. List the contents of your openMP subdirectory

    You should notice the following files:

    C Files Fortran Files Description
    omp_hello.c omp_hello.f Hello world
    omp_workshare1.c omp_workshare1.f Loop work-sharing
    omp_workshare2.c omp_workshare2.f Sections work-sharing
    omp_reduction.c omp_reduction.f Combined parallel loop reduction
    omp_orphan.c omp_orphan.f Orphaned parallel loop reduction
    omp_mm.c omp_mm.f Matrix multiply
    omp_getEnvInfo.c omp_getEnvInfo.f Get and print environment information
    omp_bug1.c
    omp_bug1fix.c
    omp_bug2.c
    omp_bug3.c
    omp_bug4.c
    omp_bug4fix
    omp_bug5.c
    omp_bug5fix.c
    omp_bug6.c
    omp_bug1.f
    omp_bug1fix.f
    omp_bug2.f
    omp_bug3.f
    omp_bug4.f
    omp_bug4fix
    omp_bug5.f
    omp_bug5fix.f
    omp_bug6.f
    Programs with bugs

    Note: Most of these are simple example files. Their primary purpose is to demonstrate the basics of how to parallelize a code with OpenMP. Most execute in less than a second.

  4. Review / compile / run the Hello World example code

    1. Take a moment to examine the source code and note how OpenMP directives and library routines are being used.

    2. Depending upon your language preference, use one of the following commands to compile the code:

      C:
      xlc_r -q64 -O2 -qsmp=omp omp_hello.c -o hello
      Fortran:
      xlf_r -q64 -O2 -qsmp=omp omp_hello.f -o hello

    3. To run the code, simply type the command hello and the program should run.
      How many threads were created?
      Why?

  5. Vary the number of threads and re-run Hello World

    1. Set the number of threads to use by means of the OMP_NUM_THREADS environment variable.
      setenv OMP_NUM_THREADS 4
    2. Re-run the example code and notice the output.
      hello
    3. Your output should look similar to below. The actual order of output strings may vary.

      Hello World from thread = 0 
      Number of threads = 4
      Hello World from thread = 3
      Hello World from thread = 1
      Hello World from thread = 2

  6. Review / Compile / Run the workshare1 example code

    This example demonstrates use of the OpenMP loop work-sharing construct. Notice that it specifies dynamic scheduling of threads and assigns a specific number of iterations to be done by each thread.

    1. After reviewing the source code, use the following commands to compile and run the executable. (We're assuming your OMP_NUM_THREADS variable is still set to 4).

      C: xlc_r -q64 -O2 -qsmp=omp omp_workshare1.c -o workshare1
      workshare1 | sort
      Fortran: xlf_r -q64 -O2 -qsmp=omp omp_workshare1.f -o workshare1
      workshare1 | sort

    2. Review the output. Note that it is piped through the sort utility. This will make it easier to view how loop iterations were actually scheduled across the team of threads.

    3. Run the program a couple more times and review the output. What do you see? Typically, dynamic scheduling is not deterministic. Everytime you run the program, different threads can run different chunks of work. It is even possible that a thread might not do any work because another thread is quicker and takes more work. In fact, it might be possible for one thread to do all of the work.

    4. Edit the workshare1 source file and change the dynamic scheduling to static scheduling.

    5. Recompile and run the modified program. Notice the difference in output compared to dynamic scheduling. Specifically, notice that thread 0 gets the first chunk, thread 1 the second chunk, and so on.

    6. Run the program a couple more times. Does the output change? With static scheduling, the allocation of work is deterministic and should not change between runs, and every thread gets work to do.

    7. Reflect on possible performance differences between dynamic and static scheduling.

  7. Review / Compile / Run the workshare2 example code

    This example demonstrates use of the OpenMP SECTIONS work-sharing construct Note how the PARALLEL region is divided into separate sections, each of which will be executed by one thread.

    1. As before, compile and execute the program after reviewing it:

      C: xlc_r -q64 -O2 -qsmp=omp omp_workshare2.c -o workshare2
      workshare2
      Fortran: xlf_r -q64 -O2 -qsmp=omp omp_workshare2.f -o workshare2
      workshare2

    2. Run the program several times and observe any differences in output. Because there are only two sections, you should notice that some threads do not do any work. You may/may not notice that the threads doing work can vary. For example, the first time thread 0 and thread 1 may do the work, and the next time it may be thread 0 and thread 3. It is even possible for one thread to do all of the work. Which thread does work is non-deterministic in this case.

  8. Review / Compile / Run the orphan example code

    This example computes a dot product in parallel, however it differs from previous examples because the parallel loop construct is orphaned - it is contained in a subroutine outside the lexical extent of the main program's parallel region.

    1. After reviewing the source code, compile and run the program:

      C: xlc_r -q64 -O2 -qsmp=omp omp_orphan.c -o orphan
      orphan | sort
      Fortran: xlf_r -q64 -O2 -qsmp=omp omp_orphan.f -o orphan
      orphan | sort

    2. Note the result...and the fact that this example will come back to haunt as omp_bug6 later.

  9. Review / Compile / Run the matrix multiply example code

    This example performs a matrix multiple by distributing the iterations of the operation between available threads.

    1. After reviewing the source code, compile and run the program:

      C: xlc_r -q64 -O2 -qsmp=omp omp_mm.c -o matmult
      matmult
      Fortran: xlf_r -q64 -O2 -qsmp=omp omp_mm.f -o matmult
      matmult

    2. Review the output. It shows which thread did each iteration and the final result matrix.

    3. Run the program again, however this time sort the output to clearly see which threads execute which iterations:

      matmult | sort | grep Thread

      Do the loop iterations match the SCHEDULE(STATIC,CHUNK) directive for the matrix multiple loop in the code?

  10. Get environment information

    1. Starting from scratch, write a simple program that obtains information about your openMP environment. Alternately, you can modify the "hello" program to do this.

    2. Using the appropriate openMP routines/functions, have the master thread query and print the following:
      • The number of processors available
      • The number of threads being used
      • The maximum number of threads available
      • If you are in a parallel region
      • If dynamic threads are enabled
      • If nested parallelism is supported

      NOTE: IBM implements all of the necessary Fortran functions as integer instead of logical as the standard specifies.

    3. If you need help, you can consult the omp_getEnvInfo example file.

  11. When things go wrong...

    There are many things that can go wrong when developing OpenMP programs. The omp_bugX.X series of programs demonstrate just a few. See if you can figure out what the problem is with each case and then fix it.

    Compile each code as you did with the previous examples (C or Fortran).

    The buggy behavior will differ for each example. Some hints are provided below.

    Code Behavior Hints/Notes
    omp_bug1
    omp_bug1fix
    Fails compilation. Solution provided - must compile solution file.
    omp_bug2 Thread identifiers are wrong. Wrong answers.
    omp_bug3 Run-time error.
    omp_bug4
    omp_bug4fix
    Causes a segmentation fault. Solution provided - note that it is a script and will need to be "sourced". For example: "source omp_bug4fix". Be sure to examine the solution file to see what's going on - especially the last line, where you may need to change the name of the executable to match yours.
    omp_bug5
    omp_bug5fix
    Program hangs. Solution provided - must compile solution file.
    omp_bug6 Wrong result


This completes the exercise.

Evaluation Form       Please complete the online evaluation form if you have not already done so for this tutorial.

Where would you like to go now?