C/C++ Basic Workflow
Walk you through the suggested basic workflow for using Codee, demonstrated with a C project.
Getting ready
For this demonstration, we will use a C implementation of a matrix multiplication. Start by cloning the repository:
git clone https://github.com/codee-com/codee-demos.git
Walkthrough of the workflow
Codee has multiple reports that can be useful, but in this basic workflow we will focus on the Codee checkers.
0. Compiler Invocation
Firstly navigate to the source code directory:
- Linux
- Windows
cd codee-demos/C/MATMUL
cd codee-demos\C\MATMUL
Before using Codee, ensure you have a working compiler invocation for the
code to analyze. We will focus on the main.c
file, which contains the core
computational code. The file can be compiled as:
gcc main.c -c -I include/ -O3
To generate any Codee report, simply add the compiler invocation to the
right of the codee
invocation after a --
separator.
1. Checks Report
To apply the recommendations from the Open Catalog, the checks report identifies the precise locations in the source code where the improvement opportunities have been found. The default checks report pinpoints the file, line, and column for each opportunity:
codee checks -- gcc main.c -c -I include/ -O3
CHECKS REPORT
main.c:16:9 [PWR039] (level: L1): Consider loop interchange to improve the locality of reference and enable vectorization
main.c:9:9 [PWR053] (level: L1): Consider applying vectorization to forall loop
main.c:17:13 [PWR010] (level: L3): Avoid column-major array access in C/C++
main.c:18:17 [PWR048] (level: L3): Replace multiplication/addition combo with an explicit call to fused multiply-add
main.c:15:5 [PWR035] (level: L3): Avoid non-consecutive array access to improve performance
main.c:17:13 [RMK010] (level: L4): Strided memory accesses in the loop body may prevent vectorization
SUGGESTIONS
Use --verbose to get more details, e.g:
codee checks --verbose -- gcc main.c -c -I include/ -O3
Use --check-id to focus on specific subsets of checkers, e.g.:
codee checks --check-id PWR039 -- gcc main.c -c -I include/ -O3
1 file, 2 functions, 6 loops, 55 LOCs successfully analyzed (6 checkers) and 0 non-analyzed files in 110 ms
Typically, you will also use the verbose mode of the checks report to generate detailed information on how to address each improvement opportunity:
codee checks --verbose -- gcc main.c -c -I include/ -O3
CHECKS REPORT
main.c:16:9 [PWR039] (level: L1): Consider loop interchange to improve the locality of reference and enable vectorization
Loops to interchange:
16: for (size_t j = 0; j < n; j++) {
17: for (size_t k = 0; k < p; k++) {
Suggestion: Interchange inner and outer loops in the loop nest to improve performance
Documentation: https://github.com/codee-com/open-catalog/tree/main/Checks/PWR039
AutoFix:
codee rewrite --check-id pwr039 --in-place main.c:16:9 -- gcc main.c -c -I include/ -O3
main.c:9:9 [PWR053] (level: L1): Consider applying vectorization to forall loop
Suggestion: Use 'rewrite' to automatically optimize the code
Documentation: https://github.com/codee-com/open-catalog/tree/main/Checks/PWR053
AutoFix (choose one option):
* Using OpenMP pragmas (recommended):
codee rewrite --check-id pwr053 --variant omp --in-place main.c:9:9 -- gcc main.c -c -I include/ -O3
* Using Clang compiler pragmas:
codee rewrite --check-id pwr053 --variant clang --in-place main.c:9:9 -- gcc main.c -c -I include/ -O3
* Using GCC pragmas:
codee rewrite --check-id pwr053 --variant gcc --in-place main.c:9:9 -- gcc main.c -c -I include/ -O3
* Using ICC pragmas:
codee rewrite --check-id pwr053 --variant icc --in-place main.c:9:9 -- gcc main.c -c -I include/ -O3
* Using combined pragmas, for example (for GCC and Clang pragmas):
codee rewrite --check-id pwr053 --variant gcc,clang --in-place main.c:9:9 -- gcc main.c -c -I include/ -O3
<...>
2. Autofix
In certain scenarios, Codee can automatically apply the suggested improvements to your code. The autofix feature is closely integrated with the verbose output of the checks report, as command-line invocations will be generated for all available autofixes.
codee rewrite --check-id pwr039 --in-place main.c:16:9 -- gcc main.c -c -I include/ -O3
Results for file '/home/user/codee-demos/C/MATMUL/main.c':
Successfully applied AutoFix to the loop at 'main.c:16:9' [using loop interchange]:
[INFO] Loops interchanged:
- main.c:16:9
- main.c:17:13
Successfully created main_codee.c
Codee automatically marks the rewritten code with comments, allowing you to double-check the changes to ensure correctness:
diff --git a/C/MATMUL/main.c b/C/MATMUL/main.c
index ecc66be..3f71fbf 100644
--- a/C/MATMUL/main.c
+++ b/C/MATMUL/main.c
@@ -13,8 +13,10 @@ void matmul(size_t m, size_t n, size_t p, double **A, double **B, double **C) {
// Accumulation
for (size_t i = 0; i < m; i++) {
- for (size_t j = 0; j < n; j++) {
- for (size_t k = 0; k < p; k++) {
+ // Codee: Loop modified by Codee (2025-04-15 10:42:53)
+ // Codee: Technique applied: loop interchange
+ for (size_t k = 0; k < p; k++) {
+ for (size_t j = 0; j < n; j++) {
C[i][j] += A[i][k] * B[k][j];
}
}
3. Compilation Database
Codee requires the compiler invocation for each file to analyze. Sometimes the compiler invocation can be a huge command and there can be also multi-file projects. The recommended approach for this is to use a compilation database to efficiently handle the compiler invocations for different source files.
The generation of the compilation database depends on the particular build system used:
-
CMake: Add
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
to your usual CMake invocation; for instance:cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -G "Ninja" -B build
-
Makefiles: Since they do not natively support the generation of compilation databases, we recommend using
bear
. This tool is available on Linux systems through common package managers.To generate the compilation database, prepend
bear --
to your typicalmake
invocation; for example:bear -- make
MATMUL supports both CMake and make
.
Any of the above commands will generate a compile_commands.json
file containing the
compiler invocation for each file in the project.
[
{
"directory": "/home/user/codee-demos/C/MATMUL/build",
"command": "/usr/bin/cc -I/home/user/codee-demos/C/MATMUL/include -fopenmp -o CMakeFiles/matmul.dir/matrix.c.o -c /home/user/codee-demos/C/MATMUL/matrix.c",
"file": "/home/user/codee-demos/C/MATMUL/matrix.c",
"output": "CMakeFiles/matmul.dir/matrix.c.o"
},
{
"directory": "/home/user/codee-demos/C/MATMUL/build",
"command": "/usr/bin/cc -I/home/user/codee-demos/C/MATMUL/include -fopenmp -o CMakeFiles/matmul.dir/clock.c.o -c /home/user/codee-demos/C/MATMUL/clock.c",
"file": "/home/user/codee-demos/C/MATMUL/clock.c",
"output": "CMakeFiles/matmul.dir/clock.c.o"
},
{
"directory": "/home/user/codee-demos/C/MATMUL/build",
"command": "/usr/bin/cc -I/home/user/codee-demos/C/MATMUL/include -fopenmp -o CMakeFiles/matmul.dir/main.c.o -c /home/user/codee-demos/C/MATMUL/main.c",
"file": "/home/user/codee-demos/C/MATMUL/main.c",
"output": "CMakeFiles/matmul.dir/main.c.o"
}
]
Now you can use the JSON generated to substitute the compilation command in the Codee invocation. For example:
codee checks -p build/compile_commands.json