HYCOM modernization
Learn how to use Codee to modernize HYCOM, an ocean modeling system consisting of dozens of files.
This guide is part of the NERSC + Codee Training Series 2024. Code available for download at the previous link.
Getting started
First, navigate to the source code for HYCOM:
cd codee-demos/Fortran/HYCOM/src
Next, load the latest Codee version available on Perlmutter:
module load codee/2024.3.1
Walkthrough
1. Generate the compile_commands.json
The project comes with a Makefile
, so we can leverage the tool bear
(version 3 or later) to generate the compile_commands.json
file required
by Codee:
/global/cfs/cdirs/m4232pub/tools/bin/bear -- make ARCH=codee TYPE=demo
It's a simple as prepending bear --
to the make
invocation. This command
will produce a compile_commands.json
file with all the compiler invocations
needed to build the source files.
2. Run the screening report
To explore the recommendations of the Open
Catalog that are applicable to
HYCOM, let's run Codee's screening report; use --compile-commands
to point to
the compilation database:
codee screening --compile-commands compile_commands.json
Note: the compilation database entries will be analyzed in the order necessary to meet module dependencies between Fortran source files.
Configuration file 'compile_commands.json' successfully parsed.
Date: 2024-09-09 Codee version: 2024.3.1 License type: Full
[ 1/50] mod_dimensions.F90 ... Done
[ 2/50] mod_xc.F90 ... Done
<...>
[50/50] hycom.F90 ... Done
SCREENING REPORT
---Number of files---
Total | C C++ Fortran
----- | - --- -------
50 | 1 0 49
Lines of code Analysis time # checks Profiling
------------- ------------- -------- ---------
44679 1 m 2 s 2433 n/a
Lines of code : total lines of code found in the target (computed the same way as the sloccount tool)
Analysis time : time required to analyze the target
# checks : total actionable items (opportunities, recommendations, defects and remarks) detected
Profiling : estimation of overall execution time required by this target
RANKING OF CHECKERS
Checker Priority AutoFix # Title
------- -------- ------- --- --------------------------------------------------------------------------------------------------------------------------------------
PWR068 P27 (L1) 159 Encapsulate external procedures within modules to avoid the risks of calling implicit interfaces
RMK015 P27 (L1) 1 Tune compiler optimization flags to increase the speed of the code
PWR039 P27 (L1) x 1 Consider loop interchange to improve the locality of reference and enable vectorization
PWR008 P18 (L1) x 196 Declare the intent for each procedure parameter
PWR070 P18 (L1) 74 Declare array dummy arguments as assumed-shape arrays
PWR020 P18 (L1) 14 Consider loop fission to enable vectorization
PWR003 P18 (L1) 2 Explicitly declare pure functions
PWR021 P18 (L1) 1 Consider loop fission with scalar to vector promotion to enable vectorization
PWR053 P12 (L1) x 143 Consider applying vectorization to forall loop
PWR054 P12 (L1) x 27 Consider applying vectorization to scalar reduction loop
PWR063 P12 (L1) 19 Avoid using legacy Fortran constructs
PWR060 P12 (L1) 2 Consider loop fission to separate gather memory access pattern
PWR073 P9 (L2) 5 Transform common block into a module for better data encapsulation
PWR024 P8 (L2) 1 Loop can be rewritten in OpenMP canonical form
PWR071 P6 (L2) 831 Prefer real(kind=kind_value) for declaring consistent floating types
PWR007 P6 (L2) x 20 Disable implicit declaration of variables
PWR023 P6 (L2) 1 Add 'restrict' for pointer function parameters to hint the compiler that vectorization is safe
PWR022 P4 (L3) 51 Move invariant conditional out of the loop to facilitate vectorization
PWR034 P4 (L3) 14 Avoid strided array access to improve performance
PWR001 P3 (L3) 188 Declare global variables as function parameters
PWR069 P3 (L3) 180 Use the keyword only to explicitly state what to import from a module
PWR029 P3 (L3) 5 Remove integer increment preventing performance optimization
PWR035 P2 (L3) 214 Avoid non-consecutive array access to improve performance
PWR049 P2 (L3) 45 Move iterator-dependent condition outside of the loop
PWR036 P2 (L3) 36 Avoid indirect array access to improve performance
RMK010 P0 (L3) 192 The vectorization cost model states the loop is not a SIMD opportunity due to strided memory accesses in the loop body
RMK012 P0 (L3) 9 The vectorization cost model states the loop is not a SIMD opportunity because conditional execution renders vectorization inefficient
RMK014 P0 (L3) 2 The vectorization cost model states the loop is not a SIMD opportunity due to unpredictable memory accesses in the loop body
SUGGESTIONS
Use 'roi' to get a return of investment estimation report:
codee roi --compile-commands compile_commands.json
Focus the analysis on a specific file before proceeding with the Codee auto mode or the guided mode:
codee screening specific/file.c --compile-commands compile_commands.json
50 files, 251 functions, 2058 loops successfully analyzed (2433 checkers) and 0 non-analyzed files in 1 m 6 s
3. Run the checks report
Let's focus the analysis on one of the reported checkers. We can filter Codee's
output with the --check-id
flag. For example, let's pick PWR007, for which
Codee has autofix capabilities available.
Codee's checks report will help us identify all places where the checker is applicable:
codee checks --compile-commands compile_commands.json --check-id PWR007
Note: the compilation database entries will be analyzed in the order necessary to meet module dependencies between Fortran source files.
Configuration file 'compile_commands.json' successfully parsed.
Date: 2024-09-09 Codee version: 2024.3.1 License type: Full
[ 1/50] mod_dimensions.F90 ... Done
[ 2/50] mod_xc.F90 ... Done
<...>
[50/50] hycom.F90 ... Done
CHECKS REPORT
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/machine.F90:4:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:4:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:149:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:355:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:470:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:600:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:651:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:804:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:909:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:955:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1750:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1819:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1887:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1985:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:2081:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:2152:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:2176:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:2227:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:2258:7 [PWR007] (level: L2): Disable implicit declaration of variables
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:2305:7 [PWR007] (level: L2): Disable implicit declaration of variables
SUGGESTIONS
Use --verbose to get more details, e.g:
codee checks --verbose --compile-commands compile_commands.json --check-id PWR007
50 files, 251 functions, 2058 loops successfully analyzed (20 checkers) and 0 non-analyzed files in 1 m 1 s
Pick one of the occurrences of PWR007, and re-run the checks report with
--verbose
to get detailed information. It's important to filter by a specific
occurrence (for example, s8gefs.F90:1985
), or else the amount of information
shown in --verbose
mode can easily become overwhelming.
Note: The way bear
interacts with Perlmutter's filesystems causes the
compilation database to list project files under /global/u2
instead of
/global/home
. This will prevent Codee from locating the source files when
using file filters. To resolve this, we will use the realpath
command to
adjust the filters.
codee checks --compile-commands compile_commands.json --check-id PWR007 --verbose $(realpath s8gefs.F90):1985
Note: the compilation database entries will be analyzed in the order necessary to meet module dependencies between Fortran source files.
Configuration file 'compile_commands.json' successfully parsed.
Date: 2024-09-09 Codee version: 2024.3.1 License type: Full
[1/1] s8gefs.F90 ... Done
CHECKS REPORT
/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1985:7 [PWR007] (level: L2): Disable implicit declaration of variables
Suggestion: Add IMPLICIT NONE in the specification part of the procedure 'S8DOT'
Documentation: https://github.com/codee-com/open-catalog/tree/main/Checks/PWR007
AutoFix:
codee rewrite --modernization implicit-none --in-place /global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:S8DOT --compile-commands compile_commands.json
SUGGESTIONS
1 file, 1 function, 4 loops successfully analyzed (1 checker) and 0 non-analyzed files in 3335 ms
4. Autofix
Let's use Codee's autofix capabilities to automatically modernize the code:
codee rewrite --modernization implicit-none -o s8gefs_codee.F90 $(realpath s8gefs.F90):S8DOT --compile-commands compile_commands.json
Note: the compilation database entries will be analyzed in the order necessary to meet module dependencies between Fortran source files.
Configuration file 'compile_commands.json' successfully parsed.
Date: 2024-09-09 Codee version: 2024.3.1 License type: Full
Results for file '/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90':
Successfully applied AutoFix to the procedure at '/global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1985:7' [using insert implicit none]:
[INFO] Inserted implicit none:
- /global/u2/u/user/codee-demos/Fortran/HYCOM/src/s8gefs.F90:1985:7
Successfully created s8gefs_codee.F90
We can review the code changes to verify correctness:
!***END PROLOGUE S8DOT
!
+ ! Codee: Made all variable declarations explicit (2024-09-09 01:52:17)
+ implicit none
+ integer :: I
+ integer :: INCX
+ integer :: INCY
+ integer :: IX
+ integer :: IY
+ integer :: M
+ integer :: MP1
+ integer :: N
+ integer :: NS
+ real :: S8DOT
REAL SX(*),SY(*)
!***FIRST EXECUTABLE STATEMENT S8DOT