OpenMP (Open Multi-Processing) is an application programming interface (API) that supports multi-platform shared-memory parallel programming in C, C++, and Fortran. It is used to exploit parallelism in multi-core processors, allowing Fortran programs to execute more efficiently by utilizing multiple processor cores. This can lead to significant performance improvements, especially for computationally intensive tasks.
Before you can use OpenMP in Fortran, you must ensure that your compiler supports it and that you enable OpenMP-specific flags during compilation. This guide will walk you through the process of setting up OpenMP in Fortran, including installing the necessary tools, configuring the compiler, and understanding OpenMP directives.
What is OpenMP?
OpenMP is a set of compiler directives, libraries, and environment variables that allow developers to write parallel programs. It simplifies the task of parallelizing programs by enabling the programmer to specify parallel sections of code using simple compiler directives.
The key feature of OpenMP is that it provides shared-memory parallelism, which means that all threads created during parallel execution share the same address space. OpenMP works by breaking the task into smaller chunks, which are then distributed among multiple threads to be executed simultaneously.
Step 1: Ensure Compiler Supports OpenMP
Common Fortran Compilers Supporting OpenMP
Several popular Fortran compilers support OpenMP. Among them are:
- Intel Fortran Compiler (
ifort) - GNU Fortran Compiler (
gfortran) - Cray Fortran Compiler (
ftn)
Most modern versions of these compilers have OpenMP support built-in. However, it’s always a good idea to ensure that your compiler version is up-to-date and supports OpenMP.
Checking OpenMP Support
If you’re not sure whether your Fortran compiler supports OpenMP, you can check the documentation for your specific compiler. Most compilers will have specific flags to enable OpenMP. Below are the flags used by popular Fortran compilers:
- Intel Fortran:
-qopenmp - GNU Fortran:
-fopenmp - Cray Fortran:
-fopenmp(or--openmp)
You can also check for OpenMP support by running a simple Fortran program with OpenMP directives and verifying if it compiles successfully.
Step 2: Enable OpenMP Support in the Compiler
To enable OpenMP in your Fortran program, you need to use specific flags during compilation. Here’s how you can compile a Fortran program with OpenMP support for the most commonly used compilers.
2.1 Intel Fortran Compiler (ifort)
For the Intel Fortran compiler, you can enable OpenMP with the -qopenmp flag. Here’s the syntax:
ifort -qopenmp program.f90
The -qopenmp flag tells the Intel Fortran compiler to recognize and process OpenMP directives in the program.
2.2 GNU Fortran Compiler (gfortran)
For the GNU Fortran compiler, the flag -fopenmp is used to enable OpenMP:
gfortran -fopenmp program.f90
This flag directs the GNU Fortran compiler to compile the program with OpenMP support.
2.3 Cray Fortran Compiler (ftn)
For Cray Fortran, the flag -fopenmp (or sometimes --openmp) enables OpenMP support:
ftn -fopenmp program.f90
This tells the Cray Fortran compiler to recognize the OpenMP directives in the program.
Step 3: Writing OpenMP Directives in Fortran
Once OpenMP is enabled in your compiler, you can start using OpenMP directives in your Fortran code. OpenMP directives are usually added as comments with specific syntax, which the compiler will recognize and handle accordingly during parallel execution.
Here are the most commonly used OpenMP directives in Fortran:
3.1 Parallel Region
The !$OMP PARALLEL directive begins a parallel region, instructing the compiler to execute the code inside it in parallel. All threads in the parallel region execute the code concurrently.
Example:
program parallel_example
implicit none
integer :: i, result
! Initialize result
result = 0
! Parallelize the loop
!$OMP PARALLEL DO REDUCTION(+:result)
do i = 1, 100
result = result + i
end do
!$OMP END PARALLEL DO
print *, "Result = ", result
end program parallel_example
In this example, the PARALLEL DO directive parallelizes the loop that calculates the sum of integers from 1 to 100. The REDUCTION clause ensures that the variable result is updated correctly by each thread.
3.2 Parallelizing a Section of Code
You can also parallelize specific sections of code using !$OMP PARALLEL without the DO loop if you want to execute a block of code in parallel:
program parallel_section
implicit none
integer :: a, b, result
a = 5
b = 10
result = 0
!$OMP PARALLEL
result = a + b
!$OMP END PARALLEL
print *, "Result = ", result
end program parallel_section
In this case, the addition of a and b is done in parallel, even though it is just a simple operation. Each thread in the parallel region will perform the addition independently.
3.3 Synchronization with Critical Sections
In many cases, you may need to ensure that only one thread can execute a certain block of code at a time. This can be achieved using the !$OMP CRITICAL directive, which creates a critical section where only one thread can execute the code at a time.
program critical_example
implicit none
integer :: i, result
result = 0
!$OMP PARALLEL DO
do i = 1, 100
!$OMP CRITICAL
result = result + i
!$OMP END CRITICAL
end do
!$OMP END PARALLEL DO
print *, "Result = ", result
end program critical_example
The CRITICAL section ensures that the update to the result variable is done in a way that avoids race conditions, meaning only one thread can access the variable at any given time.
3.4 Using Private Variables
OpenMP allows you to declare private variables inside a parallel region. These private variables are local to each thread, meaning that each thread will have its own copy of the variable.
program private_example
implicit none
integer :: i, result
result = 0
!$OMP PARALLEL PRIVATE(i)
do i = 1, 100
result = result + i
end do
!$OMP END PARALLEL
print *, "Result = ", result
end program private_example
In this case, the variable i is declared private, ensuring that each thread has its own copy of i and does not interfere with the others.
Step 4: Compiling and Running the Program
Once your code is written with OpenMP directives, the next step is to compile and run your program. The exact command depends on the compiler you’re using. Below are examples for each major compiler:
4.1 Intel Fortran (ifort)
To compile and run an Intel Fortran program with OpenMP, use the following commands:
ifort -qopenmp program.f90 -o program
./program
4.2 GNU Fortran (gfortran)
For a program compiled with the GNU Fortran compiler:
gfortran -fopenmp program.f90 -o program
./program
4.3 Cray Fortran (ftn)
For Cray Fortran:
ftn -fopenmp program.f90 -o program
./program
Step 5: Optimizing Performance
Once you have your program running in parallel, it’s important to analyze its performance. OpenMP provides a variety of ways to optimize parallel execution, including:
- Dynamic Scheduling: You can dynamically allocate work to threads during execution, which can help with load balancing.
- Work-sharing Constructs: You can use directives like
!$OMP DO,!$OMP SECTION, and others to divide work efficiently between threads. - Environment Variables: OpenMP allows you to control aspects of parallelism, such as the number of threads used, via environment variables like
OMP_NUM_THREADS.
Example of setting the number of threads:
export OMP_NUM_THREADS=4
This command sets the number of threads to 4. You can adjust this number based on your machine’s capabilities and the nature of your program.
Leave a Reply