Climate and weather simulations are crucial for understanding environmental patterns and forecasting future changes. In climate science, advanced simulation software enables accurate models that inform policy and enhance community preparedness. To optimize weather and climate simulations as models scale in complexity, their code must be thoroughly verified and optimized to ensure scientific efficiency and reliability. Achieving accurate, reliable, and efficient results demands more than just domain expertise—it requires code that’s error-free, modernized, and optimized for today’s hardware environments. Codee streamlines this process with its static code analysis tool designed for Fortran/C/C++, which are commonly used in climate research, by systematically checking for correctness, modernization, and optimization opportunities.
How Codee Ensures Code Correctness, Modernization and Optimization
Codee simplifies and accelerates code review and testing, enabling teams to develop high-quality, efficient software that meets industry standards. With Codee’s Static Code Analyzer, each line of Fortran/C/C++ code is checked against the Open Catalog of Code Guidelines for Correctness, Modernization and Optimization. This automated analysis detects improvement opportunities without requiring code execution, allowing you to optimize weather and climate simulations and capture and apply optimizations quickly and efficiently. Codee enforces coding guidelines, improves code quality, modernizes legacy code, enhances portability, optimizes performance, and ultimately accelerates software delivery.
Success Story: Weather Research and Forecasting Model (WRF) with OpenMP Offload and Codee
The Weather Research and Forecasting Model (WRF) is a numerical weather prediction system written in Fortran and widely used for both research and operational purposes. To enhance its computational efficiency, Codee collaborated with Berkeley Lab and the Pacific Northwest National Laboratory (PNNL) to optimize WRF’s performance on the Perlmutter supercomputer at NERSC. By offloading computationally intensive routines to GPUs using OpenMP, and guided by profilers and Codee’s static code analysis, this approach achieved a 2.08x speedup in a major winter storm simulation.
For a more detailed look at the methods and results, check out the full success story.
This work was showcased at SC24 in the WACCPD workshop.
Codee’s Suggested Workflow: Five Simple Commands
To make the most of Codee’s capabilities, we’ve standardized a workflow consisting of five core commands. These commands capture all correctness, modernization and optimization opportunities and present them in different formats, following a top-down approach. The workflow starts with management-oriented reports and progressively moves toward detailed technical analysis with precise, actionable feedback helping developers directly implement improvements in the code. This ensures that high-level strategic goals are aligned with the technical actions taken by the developers. These reports integrate with CI/CD pipelines, maintaining continuous code quality while preserving data privacy by running locally.
1. Technical Debt Report
Let’s take the WRF code as an example. The first action is generating a technical debt report, which quantifies the refactorings needed to leverage all identified improvements. Over time, your goal should be to reduce this technical debt score to zero.
$ codee technical-debt
<...>
TECHNICAL DEBT REPORT
This report quantifies the technical debt associated with the modernization of legacy code by assessing the extent of refactoring required for language constructs. The score is determined based on the number of language constructs necessitating refactoring to bring the source code up to modern standards. Additionally, the metric identifies the impacted source code segments, detailing affected files, functions, and loops.
Score Affected files Affected functions Affected loops
----- -------------- ------------------ --------------
79765 459 9037 10162
TECHNICAL DEBT BREAKDOWN
Lines of code Analysis time Checkers Technical debt score
------------- ------------- -------- --------------------
949428 4 h 23 m 14 s 76437 79765
The listing of language constructs associated with legacy code found in the source code is as follows:
- Unconditional GOTO
- BACKSPACE
- DATA
- Arithmetic IF
- PAUSE
- Equivalence
SUGGESTIONS
Use 'screening' to find out details about the detected checks:
codee screening -p compile_commands.json
508 files, 9700 functions, 26246 loops, 949428 LOCs successfully analyzed (76437 checkers) and 0 non-analyzed files in 4 h 23 m 59 s
2. ROI Report
Next, the ROI report estimates the time and effort saved through Codee’s automated analysis, and tailors the ROI estimation to your organization. This report contrasts, against the automated process of Codee, the manual time that would have been spent evaluating the applicability of each rule of the Open Catalog to the code.
$ codee roi
<...>
ROI ANALYSIS SUMMARY
This analysis underscores the tangible benefits Codee brings to the development process, not only in terms of savings in development effort, but also in realizing significant cost efficiencies for the organization.
Impact on Development Effort:
This report identifies critical areas within the source code that necessitate attention from the development team, and forecasts a significant reduction in workload by an estimated 1219073 hours.
Without Codee | With Codee | Hours saved
------------- | ----------- | -------------
1295510 hours | 76437 hours | 1219073 hours
Impact on Cost Savings:
Considering a standard developer's workload of approximately 1800 hours/year, Codee's intervention translates to saving an equivalent to 677.26 (1219073h / 1800h) developers working full-time. Assuming an average cost of a developer for the company (salary + associated costs) of €100,000, this amounts to cost savings of €67,726,272 (€100,000 x 677.26).
Developer hours/year | Number of devs. saved/year | Developer salary/year | Total costs saved/year
-------------------- | -------------------------- | --------------------- | ----------------------
1800 hours | 677.26 | €100,000 | €67,726,272
SUGGESTIONS
Set custom parameters for the ROI calculation, using --dev-cost-per-year, --dev-hours-per-year, and --checker-effort flags; e.g.:
codee roi --dev-cost-per-year 20000 --dev-hours-per-year 1600 --checker-effort 1.5 -p compile_commands.json
Use --check-id <list of checkers separated by comma> to calculate the ROI for an arbitrary subset of checkers to enable; e.g.:
codee roi --check-id PWR030,PWR039 -p compile_commands.json
508 files, 9700 functions, 26246 loops, 949428 LOCs successfully analyzed (76437 checkers) and 0 non-analyzed files in 4 h 23 m 35 s
3. Screening Report
While the technical debt report provides guidance on how many issues there are, the screening report details which recommendations of the Open Catalog are applicable to the code, and ranks them based on their estimated positive impact to help prioritize the refactoring efforts.
$ codee screening
<...>
SCREENING REPORT
----Number of files----
Total | C C++ Fortran
----- | --- --- -------
508 | 122 0 386
RANKING OF MODERNIZATION CHECKERS
Checker Priority AutoFix # Title
------- -------- ------- ----- --------------------------------------------------------------------
PWR072 P27 (L1) 100 Split the variable initialization from the declaration to prevent the implicit 'save' behavior
PWR008 P18 (L1) x 6316 Declare the intent for each procedure parameter
PWR007 P18 (L1) x 4927 Disable implicit declaration of variables
PWR063 P12 (L1) 120 Avoid using legacy Fortran constructs
PWR003 P6 (L2) 2627 Explicitly declare pure functions
PWR070 P6 (L2) 2238 Declare array dummy arguments as assumed-shape arrays
PWR069 P6 (L2) x 1090 Use the keyword only to explicitly state what to import from a module
PWR071 P3 (L3) 34388 Prefer real(kind=kind_value) for declaring consistent floating types
PWR068 P3 (L3) 5301 Encapsulate external procedures within modules to avoid the risks of calling implicit interfaces
PWR002 P3 (L3) 27 Declare scalar variables in the smallest possible scope
PWR073 P3 (L3) 3 Transform common block into a module for better data encapsulation
PWR012 P2 (L3) 139 Pass only required fields from derived type as parameters
PWR001 P1 (L3) 6077 Declare global variables as function parameters
RANKING OF OPTIMIZATION CHECKERS
Checker Priority AutoFix # Title
------- -------- ------- ---- --------------------------------------------------------------------
RMK015 P27 (L1) 130 Tune compiler optimization flags to increase the speed of the code
PWR039 P27 (L1) x 56 Consider loop interchange to improve the locality of reference and enable vectorization
PWR020 P18 (L1) 30 Consider loop fission to enable vectorization
PWR032 P18 (L1) 21 Avoid calls to mathematical functions with higher precision than required
PWR021 P18 (L1) 15 Consider loop fission with scalar to vector promotion to enable vectorization
PWR053 P12 (L1) x 3759 Consider applying vectorization to forall loop
PWR054 P12 (L1) x 324 Consider applying vectorization to scalar reduction loop
PWR060 P12 (L1) 324 Consider loop fission to separate gather memory access pattern
PWR044 P9 (L2) 70 Avoid unnecessary floating-point data conversions involving constants
PWR024 P8 (L2) 4 Loop can be rewritten in OpenMP canonical form
PWR017 P8 (L2) 2 Using countable while loops instead of for loops may inhibit vectorization
PWR018 P6 (L2) 32 Call to recursive function within a loop inhibits vectorization
PWR019 P6 (L2) 20 Consider interchanging loops to favor vectorization by maximizing inner loop's trip count
PWR025 P6 (L2) 1 Consider annotating pure function with OpenMP 'declare simd'
PWR022 P4 (L3) 2661 Move invariant conditional out of the loop to facilitate vectorization
PWR034 P4 (L3) 68 Avoid strided array access to improve performance
PWR010 P4 (L3) 14 Avoid column-major array access in C/C++
PWR029 P3 (L3) 263 Remove integer increment preventing performance optimization
PWR048 P3 (L3) 24 Replace multiplication/addition combo with an explicit call to fused multiply-add
PWR040 P3 (L3) 4 Consider loop tiling to improve the locality of reference
PWR035 P2 (L3) 1840 Avoid non-consecutive array access to improve performance
PWR036 P2 (L3) 845 Avoid indirect array access to improve performance
PWR049 P2 (L3) 281 Move iterator-dependent condition outside of the loop
PWR016 P2 (L3) 227 Use separate arrays instead of an Array-of-Structs
PWR028 P2 (L3) 29 Remove pointer increment preventing performance optimization
RMK010 P0 (L3) 1345 The vectorization cost model states the loop is not a SIMD opportunity due to strided memory accesses in the loop body
RMK012 P0 (L3) 457 The vectorization cost model states the loop is not a SIMD opportunity because conditional execution renders vectorization inefficient
RMK014 P0 (L3) 238 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 -p 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 -p compile_commands.json
508 files, 9700 functions, 26246 loops, 949428 LOCs successfully analyzed (76437 checkers) and 0 non-analyzed files in 4 h 24 m 45 s
At this point, we know the number of occurrences of each checker, divided into two separate lists: modernization checkers and performance optimization checkers.
Both lists are ordered by priority, with the intention of guiding the user in their next steps. It is a good idea to start picking one of the highest priority checkers that has AutoFixes available.
4. Screening report in Verbose mode
Once the user decides to see the details for a specific checker, such as PWR007, the end result with full details is provided in the codee checks report. However, for cases with many opportunities of the checker, the verbose mode helps break down first the occurrences by file.
$ codee screening --verbose --check-id PWR007
<...>
Target # checks Check IDs
----------------------------------------------------------- -------- -----------
/WRF/src/NERSC_WRF/frame/yy0.f90 281 PWR007(281)
/WRF/src/NERSC_WRF/frame/yy1.f90 281 PWR007(281)
. . .
/WRF/src/NERSC_WRF/frame/module_io_quilt.f90 65 PWR007(65)
/WRF/src/NERSC_WRF/frame/libmassv.f90 40 PWR007(40)
/WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90 40 PWR007(40)
/WRF/src/NERSC_WRF/phys/module_ra_rrtm.f90 34 PWR007(34)
/WRF/src/NERSC_WRF/phys/module_sf_ssib.f90 31 PWR007(31)
/WRF/src/NERSC_WRF/phys/module_sf_gecros.f90 19 PWR007(19)
/WRF/src/NERSC_WRF/phys/module_sf_sfclayrev.f90 13 PWR007(13)
/WRF/src/NERSC_WRF/phys/module_ra_gfdleta.f90 13 PWR007(13)
/WRF/src/NERSC_WRF/external/io_netcdf/wrf_io.f 11 PWR007(11)
/WRF/src/NERSC_WRF/share/dfi.f90 10 PWR007(10)
/WRF/src/NERSC_WRF/phys/module_fr_fire_util.f90 10 PWR007(10)
/WRF/src/NERSC_WRF/phys/module_diag_afwa.f90 10 PWR007(10)
<...>
----------------------------------------------------------- -------- -----------
Total 4927
<...>
From this point on, the user can analyze specific files where most of the occurrences of the given checker were reported. This would have the positive side effect of speeding up the analysis time.
In this case, we will pick the /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90 source file for the codee checks report. It is a file with a large number of occurrences of the PWR007 and is located in a core directory of WRF (phys/).
5. Checks Report and Autofix
The checks report pinpoints the exact locations in your source code where opportunities for improvement exist. Codee’s verbose mode provides even more detailed information, along with recommendations on how to proceed, including the available AutoFixes.
$ codee checks --verbose --check-id PWR007 /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90
CHECKS REPORT
/WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:2805:7 [PWR007] (level: L1): Disable implicit declaration of variables
Suggestion: Add IMPLICIT NONE in the specification part of the procedure 'ECOALDIAM'
Documentation: https://github.com/codee-com/open-catalog/tree/main/Checks/PWR007
AutoFix:
codee rewrite --modernization implicit-none --in-place /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:ECOALDIAM --b
/WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:2929:7 [PWR007] (level: L1): Disable implicit declaration of variables
Suggestion: Add IMPLICIT NONE in the specification part of the procedure 'COLLENERGY'
Documentation: https://github.com/codee-com/open-catalog/tree/main/Checks/PWR007
AutoFix:
codee rewrite --modernization implicit-none --in-place /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:COLLENERGY
/WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:3079:7 [PWR007] (level: L1): Disable implicit declaration of variables
Suggestion: Add IMPLICIT NONE in the specification part of the procedure 'laguer'
Documentation: https://github.com/codee-com/open-catalog/tree/main/Checks/PWR007
AutoFix:
codee rewrite --modernization implicit-none --in-place /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:laguer
<...>
For example, Codee might suggest adding implicit none in Fortran to disable implicit variable declarations. With Codee’s AutoFix features, you can automatically apply such recommendations, improving your code with a simple command-line invocation.
$ codee rewrite --modernization implicit-none -o phys/module_mp_full_sbm_codee.f90 /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:ECOALDIAM
Successfully applied AutoFix to the procedure at '/WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:2805:7' [using insert implicit none]:
[INFO] Inserted implicit none:
- /WRF/src/NERSC_WRF/phys/module_mp_full_sbm.f90:2805:7
$ diff phys/module_mp_full_sbm.f90 phys/module_mp_full_sbm_codee.f90
2807a2808,2809
> ! Codee: Made all variable declarations explicit (2024-11-05 13:38:46)
> implicit none
Conclusion
Codee provides automated, consistent, and architecture-specific guidance to optimize weather and climate simulations, helping scientists improve code correctness, modernization, and optimization—ultimately leading to more reliable, stable, and accurate results.
Build correct, secure, modern and fast Fortran, C and C++ scientific software
This company is capitalized by INNVIERTE, AN INVESTMENT PROGRAM OF CDTI, E.P.E
Leave a Reply