# Performance Profiling and Debugging with cuml.accel

This notebook demonstrates how to use the profiling capabilities in `cuml.accel` to understand which operations are being accelerated on GPU and which are falling back to CPU execution. This can be particularly useful for debugging performance issues or understanding why certain operations might not be accelerated.

`cuml.accel` provides two types of profilers:

1. **Function Profiler**: Shows statistics about potentially accelerated function and method calls
2. **Line Profiler**: Shows per-line statistics on your script with GPU utilization percentages

Let’s explore both profilers with practical examples.

## Setup

First, let’s load the cuml.accel extension and import the necessary libraries.

```none
[1]:
```

```none
[2]:
```

## Function Profiler

The function profiler gathers statistics about potentially accelerated function and method calls. It can show:

- Which method calls `cuml.accel` had the potential to accelerate
- Which methods were accelerated on GPU, and their total runtime
- Which methods required a CPU fallback, their total runtime, and why a fallback was needed

### Example 1: Ridge Regression with Mixed GPU/CPU Execution

Let’s start with a simple example that demonstrates both GPU acceleration and CPU fallback using Ridge regression.

```none
[3]:
```

```none
[4]:
```

The function profiler output above shows:

- **GPU calls**: Methods that ran successfully on GPU
- **GPU time**: Total time spent on GPU operations
- **CPU calls**: Methods that fell back to CPU execution
- **CPU time**: Total time spent on CPU operations
- **Fallback reasons**: Why certain operations couldn’t run on GPU

### Example 2: Random Forest Classification

Let’s try a more complex example with Random Forest classification.

```none
[5]:
```

```none
[6]:
```

## Line Profiler

The line profiler collects per-line statistics on your script. It can show:

- Which lines took the most cumulative time
- Which lines (if any) were able to benefit from acceleration
- The percentage of each line’s runtime that was spent on GPU through `cuml.accel`

⚠️ **Warning**: The line profiler can add non-negligible overhead. It’s useful for understanding what parts of your code were accelerated, but you shouldn’t compare runtimes when run with the line profiler enabled to other runs.

### Example 3: Line Profiling with Ridge Regression

Let’s use the line profiler to see detailed per-line statistics.

```none
[7]:
```

The line profiler output shows:

- **#**: Line number
- **N**: Number of times the line was executed
- **Time**: Total time spent on that line
- **GPU %**: Percentage of time spent on GPU for that line
- **Source**: The actual code line

At the bottom, you’ll see the total runtime and the percentage of time spent on GPU.

### Example 4: Line Profiling with Multiple Algorithms

Let’s try a more comprehensive example with multiple machine learning algorithms.

```none
[8]:
```

```none
[9]:
```

## Programmatic Profiling

You can also use the profilers programmatically with context managers. This is useful when you want to profile specific sections of code rather than entire cells.

```none
[10]:
```

```none
[11]:
```

## Logging

In addition to profiling, `cuml.accel` also provides logging capabilities. You can enable different levels of logging to see what’s happening behind the scenes.

### Setting Log Levels

You can set the logging level when installing cuml.accel programmatically:

```none
[12]:
```

### Example with Info Logging

Let’s demonstrate what info-level logging looks like. First, let’s reinstall cuml.accel with info logging:

```none
[13]:
```

```none
[14]:
```

```none
[14]:
```

## Key Takeaways

1. **Function Profiler** (`%%cuml.accel.profile`): Best for understanding which methods were accelerated and why some fell back to CPU
2. **Line Profiler** (`%%cuml.accel.line_profile`): Best for understanding which specific lines of code benefited from acceleration and the overall GPU utilization percentage
3. **Logging**: Useful for real-time feedback on what’s happening during execution
4. **Performance Insights**:
   - High GPU utilization percentages indicate good acceleration
   - CPU fallbacks are clearly identified with reasons
   - Small datasets may show higher GPU times due to transfer overhead
   - Larger datasets typically show better GPU acceleration benefits
5. **Debugging**: Use these tools to identify why certain operations aren’t being accelerated and optimize your code accordingly.

The profiling tools in `cuml.accel` are essential for understanding and optimizing your GPU-accelerated machine learning workflows!
