0
# Debugging and Profiling
1
2
Cython provides comprehensive debugging and profiling capabilities for analyzing and optimizing Cython code. These tools enable source-level debugging, performance analysis, and identification of bottlenecks in compiled extensions.
3
4
## Capabilities
5
6
### Cython Debugger (cygdb)
7
8
GDB-based debugger that enables source-level debugging of both Python and Cython code.
9
10
```bash { .api }
11
cygdb [options] [path-to-project-directory] [gdb-args...]
12
13
Options:
14
--gdb-executable GDB GDB executable to use (default: gdb)
15
--verbose Verbose output
16
-h, --help Show help
17
18
Requirements:
19
- cython_debug/ directory with debug information
20
- Python executable compiled with debug symbols
21
- GDB with Python support
22
```
23
24
### Debug Build Configuration
25
26
Compiler directives and build options for debugging support.
27
28
```python { .api }
29
# Compilation options for debugging
30
compiler_directives = {
31
'linetrace': True, # Enable line tracing
32
'binding': True, # Enable function binding
33
'profile': True, # Enable profiling hooks
34
'emit_code_comments': True, # Add code comments in C output
35
}
36
37
# Build with debugging information
38
cythonize("module.pyx", gdb_debug=True, **compiler_directives)
39
```
40
41
### Profiling Integration
42
43
Integration with Python profiling tools and performance analysis.
44
45
```python { .api }
46
@cython.profile(True)
47
def profiled_function():
48
"""Function with profiling enabled."""
49
pass
50
51
@cython.linetrace(True)
52
@cython.binding(True)
53
def traced_function():
54
"""Function with line tracing for detailed profiling."""
55
pass
56
```
57
58
### Annotation and Performance Analysis
59
60
HTML annotation generation for performance analysis and optimization.
61
62
```bash { .api }
63
# Generate annotated HTML output
64
cython -a source.pyx # Basic annotation
65
cython -a --annotate-coverage coverage.xml source.pyx # With coverage data
66
67
# Via cythonize
68
cythonize --annotate source.pyx
69
```
70
71
## Usage Examples
72
73
### Setting Up Debug Environment
74
75
```python
76
# setup.py for debug builds
77
from setuptools import setup
78
from Cython.Build import cythonize
79
80
debug_args = {
81
'gdb_debug': True,
82
'compiler_directives': {
83
'linetrace': True,
84
'binding': True,
85
'profile': True,
86
'emit_code_comments': True,
87
'language_level': 3,
88
}
89
}
90
91
setup(
92
ext_modules=cythonize("src/*.pyx", **debug_args),
93
zip_safe=False,
94
)
95
```
96
97
### Basic Debugging Session
98
99
```bash
100
# 1. Build with debug information
101
python setup.py build_ext --inplace --debug
102
103
# 2. Start debugging session
104
cygdb
105
106
# 3. In GDB, set breakpoints and run
107
(gdb) cy break module.pyx:42
108
(gdb) cy run
109
(gdb) cy step
110
(gdb) cy print variable_name
111
(gdb) cy list
112
```
113
114
### Advanced Debugging Commands
115
116
```bash
117
# Cython-specific GDB commands
118
(gdb) cy break my_module.fast_function # Break at Cython function
119
(gdb) cy step # Step through Cython code
120
(gdb) cy next # Next line in Cython code
121
(gdb) cy print cython_var # Print Cython variable
122
(gdb) cy print local_vars # Print all local variables
123
(gdb) cy list # List current Cython source
124
(gdb) cy bt # Cython backtrace
125
(gdb) cy up # Move up Cython call stack
126
(gdb) cy down # Move down Cython call stack
127
```
128
129
### Debugging with IPython
130
131
```python
132
%load_ext cython
133
134
%%cython --gdb
135
def debug_function(int n):
136
cdef int i, total = 0
137
138
for i in range(n):
139
total += i * i # Breakpoint can be set here
140
141
return total
142
143
# Function is compiled with debug information
144
result = debug_function(100)
145
```
146
147
### Profiling with cProfile
148
149
```python
150
import cProfile
151
import pstats
152
153
# Enable profiling in Cython
154
%%cython -X profile=True -X linetrace=True -X binding=True
155
def slow_function(int n):
156
cdef int i, result = 0
157
for i in range(n):
158
result += expensive_operation(i)
159
return result
160
161
def expensive_operation(int x):
162
return x * x * x
163
164
# Profile the function
165
cProfile.run('slow_function(10000)', 'profile_stats')
166
167
# Analyze results
168
stats = pstats.Stats('profile_stats')
169
stats.sort_stats('cumulative')
170
stats.print_stats()
171
```
172
173
### Line-by-Line Profiling with line_profiler
174
175
```python
176
# Install: pip install line_profiler
177
178
%load_ext line_profiler
179
180
%%cython -X linetrace=True -X binding=True
181
@profile
182
def line_profiled_function(double[:] arr):
183
cdef int i
184
cdef double total = 0.0
185
cdef int n = arr.shape[0]
186
187
for i in range(n): # This line will be profiled
188
total += arr[i] * 2.0 # This line will be profiled
189
190
return total
191
192
# Run with line profiler
193
%lprun -f line_profiled_function line_profiled_function(data)
194
```
195
196
### Memory Profiling
197
198
```python
199
# Install: pip install memory_profiler
200
201
%load_ext memory_profiler
202
203
%%cython -X profile=True
204
@profile
205
def memory_intensive_function(int n):
206
cdef list data = []
207
cdef int i
208
209
for i in range(n):
210
data.append(i * i) # Memory allocation tracked
211
212
return sum(data)
213
214
# Profile memory usage
215
%mprun -f memory_intensive_function memory_intensive_function(100000)
216
```
217
218
### Annotation Analysis
219
220
```cython
221
# After running: cython -a my_module.pyx
222
# Open my_module.html in browser
223
224
%%cython -a
225
import numpy as np
226
cimport numpy as cnp
227
228
def analyze_performance(cnp.double_t[:] data):
229
"""Function to analyze with annotations."""
230
cdef int i
231
cdef double total = 0.0
232
cdef int n = data.shape[0]
233
234
# Yellow lines indicate Python interaction overhead
235
# White lines indicate pure C code
236
for i in range(n):
237
total += data[i] # Should be white (fast)
238
239
return total # May be yellow (Python object creation)
240
```
241
242
### Coverage-Based Annotation
243
244
```bash
245
# 1. Run tests with coverage
246
python -m pytest --cov=my_module --cov-report=xml
247
248
# 2. Generate annotated output with coverage data
249
cython -a --annotate-coverage coverage.xml my_module.pyx
250
251
# 3. View coverage-annotated HTML
252
# Green highlighting shows well-tested code
253
# Red highlighting shows untested code paths
254
```
255
256
### Debugging C Extensions
257
258
```python
259
# For debugging at the C level
260
%%cython --gdb -X emit_code_comments=True
261
def c_level_debug(int x):
262
cdef int* ptr = <int*>malloc(sizeof(int) * 10)
263
264
if ptr == NULL:
265
raise MemoryError("Failed to allocate memory")
266
267
ptr[0] = x # Can inspect C-level memory in GDB
268
269
cdef int result = ptr[0] * 2
270
free(ptr)
271
272
return result
273
```
274
275
### Performance Benchmarking
276
277
```python
278
import timeit
279
280
%%cython -X boundscheck=False -X wraparound=False -X cdivision=True
281
def optimized_function(double[:] data):
282
cdef int i
283
cdef double total = 0.0
284
cdef int n = data.shape[0]
285
286
for i in range(n):
287
total += data[i]
288
289
return total
290
291
# Benchmark against Python version
292
import numpy as np
293
data = np.random.random(1000000)
294
295
cython_time = timeit.timeit(
296
lambda: optimized_function(data),
297
number=100
298
)
299
300
python_time = timeit.timeit(
301
lambda: sum(data),
302
number=100
303
)
304
305
print(f"Cython: {cython_time:.4f}s")
306
print(f"Python: {python_time:.4f}s")
307
print(f"Speedup: {python_time/cython_time:.2f}x")
308
```
309
310
### Debugging Build Issues
311
312
```bash
313
# Verbose compilation for debugging build problems
314
cython --verbose my_module.pyx
315
316
# Generate intermediate C code for inspection
317
cython --output-file my_module.c my_module.pyx
318
319
# Check generated C code
320
less my_module.c
321
322
# Debug compilation errors
323
cython -Werror my_module.pyx # Treat warnings as errors
324
```
325
326
### Custom GDB Configuration
327
328
```bash
329
# Create .cygdbinit file for custom GDB commands
330
echo "set print pretty on" > .cygdbinit
331
echo "set pagination off" >> .cygdbinit
332
echo "define cy-locals" >> .cygdbinit
333
echo " cy print local_vars" >> .cygdbinit
334
echo "end" >> .cygdbinit
335
336
# Use custom configuration
337
cygdb --gdb-executable gdb-multiarch
338
```
339
340
### Integration with IDEs
341
342
```python
343
# VS Code configuration for Cython debugging
344
# In .vscode/launch.json:
345
{
346
"name": "Python: Cython Debug",
347
"type": "python",
348
"request": "launch",
349
"program": "${workspaceFolder}/test_script.py",
350
"console": "integratedTerminal",
351
"justMyCode": false,
352
"env": {
353
"CYTHON_DEBUG": "1"
354
}
355
}
356
```
357
358
The debugging and profiling capabilities in Cython provide comprehensive tools for analyzing performance bottlenecks, identifying optimization opportunities, and debugging both Python and C-level code in compiled extensions.