.. _sp-fortran_c_cpp: Fortran, C and C++ ================== Scientific computing traces its roots to the very origin of computers. The first electro-mechanical computers originally were created to compute large numerical calculations much faster than humans can do. With the evolution of computers came new ways of expressing algorithms in ways closer to human languages but still very close to the internal operation of electronic machines. With the new electronic computers in the 1950's, programmers used assembly language (or assembler language), low-level programming language with a close correspondence between the instructions in the language and the architecture's machine code instructions. Programming in assembly is very time consuming and prone to error. New programming languages evolved to facilitate the translation of algorithms into code, avoiding almost entirely the need for writing in assembler. Today, three dominant low level languages for scientific computing are Fortran, C and C++. **Fortran** is the oldest of those three, and many algorithms that are fundamental for most problems in science were written in it. Fortran 77 was for many years the standard de facto for scientific computing and have evolve over the years with Fortran 90, 95, 2003 and 2008. **C** is a general purpose language and used in most of the basic software written in Unix environments. The language itself is not targeted to write scientific programs so it less expressive for vectors and matrices compared to Fortran. **C++** is in many ways an extension of C with high element constructs such as classes. C++ is widely used in desktop applications, games and also scientific applications. Fortran, C and C++ shared a number of attributes. These languages make use of a compiler that translates the source code into machine code. Parallelization interfaces such as MPI are written with explicit support for those three languages and compiler suites such as GCC, Intel and NVIDIA HPC include those languages by default. Implementations of C, C++, and Fortran Compilers ------------------------------------------------ In an HPC cluster is customary to include compilers for Fortran, C and C++ by default. On Linux machines the usual compilers are from the GNU Compiler Collection (GCC). Apart from GCC, there are other vendors of compilers for these three languages. Each vendor brings its own advantages and particular options to optimize the resulting binaries, support for CPU extensions, support for language extensions and support for various standards of the languages that are standarized and reviewed over time. Intel® oneAPI HPC Toolkit and NVIDIA HPC SDK are two examples of alternative compilers that are available in many HPC clusters. Each compiler for the three languages has its own name. The table below shows the names of the compilers for each of the three languages from each vendor. .. list-table:: Name of compiler commands from different vendors :widths: 50 25 25 25 :header-rows: 1 :stub-columns: 1 * - Language - GNU Compiler Collection (GCC) - Intel® oneAPI HPC Toolkit - NVIDIA HPC SDK * - Fortran - gfortran - ifort - nvfortran * - C - gcc - icc - nvc * - C++ - g++ - icpc - nvc++ The compiler installed by default with the Operating System is usually too old. That is due to the tendency of having more stable software packages on production systems and that is the case on HPC clusters too. The versions of those installed compilers are old for the purpose of many scientific packages and do not support recent CPU extensions and language extensions such as OpenMP or OpenACC. On Thorny Flat the default version of the compilers is 4.8, one way of identifying the version of gcc compilers is running the command:: $> gfortran -v Using built-in specs. COLLECT_GCC=gfortran COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --disable-libgcj --with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install --enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64 --build=x86_64-redhat-linux Thread model: posix gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) Environment Modules ------------------- It is usually better to use environment modules to access newer versions of GCC or compilers from other vendors such as Intel or NVIDIA. The table below shows the modules that can be used on Thorny Flat to load the modules for compilers from different vendors and from several versions +----------+-------------------------------+--------------------------------------------------+ | Vendor | Modules | Advantages | +==========+===============================+==================================================+ | GCC | | ``lang/gcc/9.3.0`` | | Standard *de-facto* on Linux/UNIX | | | | ``lang/gcc/12.2.0`` | | Most codes compile correctly with GCC | | | | | | Relative good support for OpenMP and AVX | | | | | | extensions | +----------+-------------------------------+--------------------------------------------------+ | Intel | | ``lang/intel/2018`` | | Compilers that optimize particularly well | | | | ``lang/intel/2019`` | | on Intel Hardware. | | | | ``compiler/2021.4.0`` | | Good support for OpenMP but not OpenACC | | | | ``compiler/2022.1.0`` | | | | | ``compiler/2023.1.0`` | | +----------+-------------------------------+--------------------------------------------------+ | NVIDIA | | ``lang/nvidia/nvhpc/22.3`` | | Good support for OpenACC in addition to | | | | ``lang/nvidia/nvhpc/23.3`` | | OpenMP. | | | | ``lang/nvidia/nvhpc/23.7`` | | Informative parallelization information | +----------+-------------------------------+--------------------------------------------------+ Compiling Source Code --------------------- We will now demonstrate how to compile simple codes using compilers from the 3 vendors above. For doing that, consider the algorithm that compule the `Sieve of Eratosthenes `_. We have the same algorithm implemented in C and Fortran. The code can be copied into files and we will proceed to compile it. To download the code you can execute the following command directly on the cluster:: $> wget https://docs.hpc.wvu.edu/_static/sieve.c $> wget https://docs.hpc.wvu.edu/_static/sieve.f90 Or download the files :download:`sieve.c <../_static/sieve.c>` and :download:`sieve.f90 <../_static/sieve.f90>`. If you download the files to your own computer you can later upload them to the cluster using :ref:`qs-file-transfer` C version (:download:`sieve.c <../_static/sieve.c>`) .. literalinclude:: ../_static/sieve.c :language: C Fortran version (:download:`sieve.f90 <../_static/sieve.f90>`) .. literalinclude:: ../_static/sieve.f90 :language: Fortran Using the GNU Compiler Collection (GCC) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We will start compiling this code with a modern version of GCC. Load the module for GCC 12.2:: $> module load lang/gcc/12.2.0 The module for GCC 12.2 includes compilers for Fortran, C, and C++. We can compile the codes above with the commands:: $> gcc sieve.c -o sieve_c_gcc122 $> gfortran sieve.f90 -o sieve_f90_gcc122 Now we can execute the binaries:: $> ./sieve_c_gcc122 100000000 Sieve for prime numbers up to 100000000 Total number of primes: 5761455 $> ./sieve_f90_gcc122 100000000 Sieve for prime numbers up to 100000000 Total number of primes: 5761455 Using NVIDIA HPC SDK ~~~~~~~~~~~~~~~~~~~~ Another suite that can be use for compiling this code is the NVIDIA HPC SDK Load the module for NVIDIA HPC SDK 23.7:: $> module load lang/nvidia/nvhpc/23.7 The module for the NVIDIA compilers includes compilers for Fortran, C, and C++. We can compile the codes above with the commands:: $> nvc sieve.c -o sieve_c_nv237 $> nvfortran sieve.f90 -o sieve_f90_nv237 Now we can execute the binaries:: $> ./sieve_c_nv237 100000000 Sieve for prime numbers up to 100000000 Total number of primes: 5761455 $> ./sieve_f90_nv237 100000000 Sieve for prime numbers up to 100000000 Total number of primes: 5761455 Using Intel® oneAPI HPC Toolkit ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are several suites currently offered by Intel. Intel® oneAPI HPC Toolkit includes compilers for Fortran, C, and C++. In addition it also includes Intel MKL which is an optimized implementation of BLAS and LAPACK linear algebra routines. Load the module for the Intel compilers:: $> module load compiler/2021.4.0 The module includes Intel compilers for Fortran, C, and C++. We can compile the codes above with the commands:: $> icc sieve.c -o sieve_c_intel2021 $> ifort sieve.f90 -o sieve_f90_intel2021 Now we can execute the binaries:: $> ./sieve_c_intel2021 100000000 Sieve for prime numbers up to 100000000 Total number of primes: 5761455 $> ./sieve_f90_intel2021 100000000 Sieve for prime numbers up to 100000000 Total number of primes: 5761455