# C++ Print Debugging Utilities
## Status
Implemented
Proposed by: Adam Gibson (20-11-2024)
Discussed with: Paul Dubs
## Context
We need a way to provide debugging utilities for C++ code in the nd4j library. These utilities help in identifying issues such as out-of-bounds crashes and unexpected behavior in mathematical operations. The goal is to have a set of tools that can be easily enabled or disabled via configuration flags.
## Decision
We implement three distinct debugging utilities that can be controlled through configuration flags:
1. Print Indices - For tracking loop execution and array access
2. Print Math - For debugging mathematical operations
3. Preprocessor Output - For debugging macro behavior
Each utility serves a specific debugging purpose and can be independently enabled or disabled through both Maven and CMake configuration.
## Configuration
### Maven Configuration (pom.xml)
```xml
OFF
OFF
OFF
```
### Build System Integration
The utilities are integrated into the build system through a shell script that configures CMake. The script:
1. Echoes configuration status:
```bash
echo PRINT_INDICES = "$PRINT_INDICES"
echo PRINT_MATH = "$PRINT_MATH"
echo PREPROCESS = "$PREPROCESS"
```
2. Passes configuration to CMake:
```bash
eval "$CMAKE_COMMAND" \
-DPRINT_MATH="$PRINT_MATH" \
-DPRINT_INDICES="$PRINT_INDICES" \
# ... other CMake configurations
```
3. Special handling for preprocessing:
```bash
if [ "$PREPROCESS" == "ON" ]; then
# Re-run CMake with preprocessing enabled
eval "$CMAKE_COMMAND" \
-DPRINT_MATH="$PRINT_MATH" \
-DPRINT_INDICES="$PRINT_INDICES" \
-DSD_PREPROCESS="$PREPROCESS" \
# ... other configurations
echo "Running preprocessing step..."
exit 0
fi
```
## Implementation Details
### 1. Print Indices Utility
#### Purpose
Tracks loop iterations and array access patterns to help identify out-of-bounds issues and iteration-related bugs.
#### Build Configuration
1. Set through Maven property `libnd4j.printindices`
2. Passed to CMake as `PRINT_INDICES`
3. Defines `PRINT_INDICES` macro in C++ code
#### Implementation
```cpp
#if defined(PRINT_INDICES)
printf("i: %lld xEws %lld ReduceBoolFunction::execScalar\n", i, xEws);
#endif
```
#### Example Usage
```cpp
else {
for (auto i = start; i < stop; i++) {
#if defined(PRINT_INDICES)
printf("i: %lld xEws %lld ReduceBoolFunction::execScalar\n", i, xEws);
#endif
intermediate[thread_id] = OpType::update(
intermediate[thread_id],
OpType::op(x[i * xEws], extraParams),
extraParams
);
}
}
```
### 2. Print Math Utility
#### Purpose
Provides detailed tracking of mathematical operations, including input values, outputs, and execution flow.
#### Build Configuration
1. Set through Maven property `libnd4j.printmath`
2. Passed to CMake as `PRINT_MATH`
3. Defines `SD_GCC_FUNCTRACE` macro in C++ code when enabled
#### Implementation
```cpp
template <>
SD_INLINE SD_HOST void sd_print_math2(char* func_name, uint16_t input1, uint16_t input2, uint16_t output) {
#if defined(SD_GCC_FUNCTRACE)
PRINT_IF_NECESSARY(func_name);
#endif
printf("%s: input1 = %d, input2 = %d, output = %d\n", func_name, input1, input2, output);
fflush(stdout);
}
```
### 3. Preprocessor Output Utility
#### Purpose
Generates preprocessed source files to help debug macro-related issues and understand macro expansion.
#### Build Configuration
1. Set through Maven property `libnd4j.preprocess`
2. Passed to CMake as `SD_PREPROCESS`
3. Triggers special build flow in shell script when enabled
#### Build Process
When preprocessing is enabled:
1. Maven sets `libnd4j.preprocess=ON`
2. Shell script detects `PREPROCESS=ON`
3. CMake is run with `-DSD_PREPROCESS=ON`
4. Build exits after preprocessing step
5. Preprocessed files are generated in the build directory
#### Implementation
```cmake
if("${SD_PREPROCESS}" STREQUAL "ON")
message("Preprocessing enabled ${CMAKE_BINARY_DIR}")
include_directories(${CMAKE_BINARY_DIR}/../../include)
list(REMOVE_DUPLICATES ALL_SOURCES)
# Generate preprocessed files
```
## Consequences
### Print Indices
#### Advantages
- Easily identifies loop boundary issues
- Helps debug array access patterns
- Minimal code overhead
#### Drawbacks
- Can generate large amounts of output
- Performance impact when enabled
### Print Math
#### Advantages
- Detailed visibility into mathematical operations
- Type-safe debugging
- Stack trace integration
#### Drawbacks
- Increased binary size
- Runtime overhead when enabled
- Additional complexity in template code
### Preprocessor Output
#### Advantages
- Clear visibility into macro expansion
- Helps debug complex macro interactions
- Useful for template debugging
- Early exit prevents unnecessary compilation steps
#### Drawbacks
- Increases build complexity
- Additional disk space requirements
- Requires separate build run for preprocessing
- Cannot be combined with normal build flow
## References
- platformmath.h
- templatemath.h
- CMakeLists.txt configuration
- pom.xml configuration
- build-dl4j-natives.sh script
- ReduceBoolFunction implementation