0
# Automatic Profiling
1
2
Automatically annotate all function calls in your program with configurable detail levels, including line numbers and C function support. The Profile class provides comprehensive automatic annotation without manual code modification.
3
4
## Capabilities
5
6
### Profile Class
7
8
The `Profile` class enables automatic annotation of all function calls using Python's profiling hooks with configurable detail levels and C function support.
9
10
```python { .api }
11
class Profile:
12
def __init__(self, linenos: bool = True, annotate_cfuncs: bool = True):
13
"""
14
Create a Profile object for automatic function call annotation.
15
16
Parameters:
17
- linenos: Include file and line number information in annotations
18
- annotate_cfuncs: Also annotate C-extension and builtin functions
19
"""
20
21
def enable(self):
22
"""
23
Start annotating function calls automatically.
24
Sets up profiling hooks for current thread and all new threads.
25
"""
26
27
def disable(self):
28
"""
29
Stop annotating function calls automatically.
30
Removes profiling hooks from current thread and new threads.
31
"""
32
```
33
34
**Basic Usage Example:**
35
36
```python
37
import nvtx
38
import time
39
40
# Create profiler with default settings
41
profiler = nvtx.Profile()
42
43
# Enable automatic annotation
44
profiler.enable()
45
46
# All function calls are now automatically annotated
47
def process_data():
48
time.sleep(0.1) # This will be annotated
49
compute_results()
50
51
def compute_results():
52
time.sleep(0.2) # This will also be annotated
53
54
process_data()
55
56
# Stop automatic annotation
57
profiler.disable()
58
59
# Function calls after disable() are not annotated
60
process_data() # Not annotated
61
```
62
63
### Configuration Options
64
65
#### Line Number Information
66
67
Control whether file names and line numbers are included in annotation messages:
68
69
```python
70
import nvtx
71
72
# Include line numbers (default)
73
profiler_with_lines = nvtx.Profile(linenos=True)
74
75
# Example annotation message: "main.py:42(process_data)"
76
77
# Exclude line numbers for cleaner display
78
profiler_clean = nvtx.Profile(linenos=False)
79
80
# Example annotation message: "process_data"
81
```
82
83
**Usage Example:**
84
85
```python
86
import nvtx
87
import time
88
89
def detailed_profiling():
90
# Detailed profiling with file and line info
91
profiler = nvtx.Profile(linenos=True)
92
profiler.enable()
93
94
def func_a():
95
time.sleep(0.1)
96
func_b()
97
98
def func_b():
99
time.sleep(0.1)
100
101
func_a() # Annotations show: "example.py:123(func_a)", "example.py:126(func_b)"
102
profiler.disable()
103
104
def clean_profiling():
105
# Clean profiling with function names only
106
profiler = nvtx.Profile(linenos=False)
107
profiler.enable()
108
109
def func_a():
110
time.sleep(0.1)
111
func_b()
112
113
def func_b():
114
time.sleep(0.1)
115
116
func_a() # Annotations show: "func_a", "func_b"
117
profiler.disable()
118
```
119
120
#### C Function Annotation
121
122
Control whether C extensions and builtin functions are annotated:
123
124
```python
125
import nvtx
126
127
# Annotate C functions (default)
128
profiler_full = nvtx.Profile(annotate_cfuncs=True)
129
130
# Skip C functions for focus on Python code
131
profiler_python_only = nvtx.Profile(annotate_cfuncs=False)
132
```
133
134
**Usage Example:**
135
136
```python
137
import nvtx
138
import time
139
import json
140
141
def c_function_profiling():
142
# Profile including C functions
143
profiler = nvtx.Profile(annotate_cfuncs=True)
144
profiler.enable()
145
146
data = {"key": "value"}
147
json_str = json.dumps(data) # json.dumps is C function - will be annotated
148
time.sleep(0.1) # time.sleep is C function - will be annotated
149
150
profiler.disable()
151
152
def python_only_profiling():
153
# Profile Python functions only
154
profiler = nvtx.Profile(annotate_cfuncs=False)
155
profiler.enable()
156
157
data = {"key": "value"}
158
json_str = json.dumps(data) # json.dumps is C function - NOT annotated
159
time.sleep(0.1) # time.sleep is C function - NOT annotated
160
161
def python_func():
162
return "python"
163
164
result = python_func() # Python function - will be annotated
165
166
profiler.disable()
167
```
168
169
### Thread Handling
170
171
The Profile class automatically handles both current thread and new thread annotation:
172
173
```python
174
import nvtx
175
import threading
176
import time
177
178
def automatic_thread_profiling():
179
# Create and enable profiler
180
profiler = nvtx.Profile()
181
profiler.enable()
182
183
def worker_function(worker_id):
184
time.sleep(0.1)
185
print(f"Worker {worker_id} completed")
186
187
# Main thread function calls are annotated
188
main_work()
189
190
# New threads are also automatically profiled
191
threads = []
192
for i in range(3):
193
thread = threading.Thread(target=worker_function, args=(i,))
194
threads.append(thread)
195
thread.start()
196
197
# Wait for all threads
198
for thread in threads:
199
thread.join()
200
201
profiler.disable()
202
```
203
204
## Command-Line Interface
205
206
NVTX provides a command-line interface for automatic profiling of entire Python programs:
207
208
```bash
209
python -m nvtx [options] scriptfile [args] ...
210
```
211
212
### Command-Line Options
213
214
```bash
215
--linenos # Include file and line number information (default)
216
--no-linenos # Do not include file and line number information
217
--annotate-cfuncs # Also annotate C-extension and builtin functions
218
```
219
220
**Usage Examples:**
221
222
```bash
223
# Profile with default settings (line numbers, no C functions)
224
python -m nvtx my_script.py
225
226
# Profile with line numbers and C functions
227
python -m nvtx --annotate-cfuncs my_script.py
228
229
# Profile with clean function names only
230
python -m nvtx --no-linenos my_script.py arg1 arg2
231
232
# Full profiling with all options
233
python -m nvtx --linenos --annotate-cfuncs my_script.py --input data.txt
234
```
235
236
## Integration Patterns
237
238
### Context-Managed Profiling
239
240
Use profiling for specific code sections:
241
242
```python
243
import nvtx
244
245
class ProfiledSection:
246
def __init__(self, **profile_kwargs):
247
self.profiler = nvtx.Profile(**profile_kwargs)
248
249
def __enter__(self):
250
self.profiler.enable()
251
return self.profiler
252
253
def __exit__(self, exc_type, exc_val, exc_tb):
254
self.profiler.disable()
255
256
# Usage
257
with ProfiledSection(linenos=True, annotate_cfuncs=False) as profiler:
258
# All function calls in this block are automatically annotated
259
complex_algorithm()
260
data_processing()
261
```
262
263
### Conditional Profiling
264
265
Enable profiling based on environment or configuration:
266
267
```python
268
import nvtx
269
import os
270
271
class ConditionalProfiler:
272
def __init__(self):
273
self.profiler = None
274
self.enabled = os.getenv('ENABLE_NVTX_PROFILING', 'false').lower() == 'true'
275
276
if self.enabled:
277
self.profiler = nvtx.Profile(
278
linenos=os.getenv('NVTX_LINENOS', 'true').lower() == 'true',
279
annotate_cfuncs=os.getenv('NVTX_C_FUNCS', 'false').lower() == 'true'
280
)
281
282
def enable(self):
283
if self.profiler:
284
self.profiler.enable()
285
286
def disable(self):
287
if self.profiler:
288
self.profiler.disable()
289
290
# Global profiler instance
291
profiler = ConditionalProfiler()
292
293
def main():
294
profiler.enable()
295
try:
296
run_application()
297
finally:
298
profiler.disable()
299
```
300
301
### Decorator-Based Profiling
302
303
Create decorators for automatic profiling of specific functions:
304
305
```python
306
import nvtx
307
from functools import wraps
308
309
def auto_profile(linenos=True, annotate_cfuncs=False):
310
def decorator(func):
311
@wraps(func)
312
def wrapper(*args, **kwargs):
313
profiler = nvtx.Profile(linenos=linenos, annotate_cfuncs=annotate_cfuncs)
314
profiler.enable()
315
try:
316
return func(*args, **kwargs)
317
finally:
318
profiler.disable()
319
return wrapper
320
return decorator
321
322
# Usage
323
@auto_profile(linenos=True, annotate_cfuncs=True)
324
def critical_function():
325
# All nested function calls will be automatically annotated
326
helper_function_1()
327
helper_function_2()
328
return results
329
```
330
331
## Performance Considerations
332
333
### Overhead
334
335
- **Python Functions**: Minimal overhead for Python function annotation
336
- **C Functions**: Higher overhead when `annotate_cfuncs=True` due to additional hook processing
337
- **Line Numbers**: Slight additional overhead when `linenos=True` for file path resolution
338
- **Frequency**: Very high-frequency function calls may benefit from selective profiling
339
340
### Optimization Strategies
341
342
```python
343
import nvtx
344
345
# Strategy 1: Profile specific modules only
346
def selective_profiling():
347
profiler = nvtx.Profile(annotate_cfuncs=False) # Skip C functions
348
profiler.enable()
349
350
# Only profile specific parts of application
351
critical_business_logic()
352
353
profiler.disable()
354
355
# Strategy 2: Use sampling for long-running applications
356
import time
357
358
def sampled_profiling():
359
profiler = nvtx.Profile()
360
361
for iteration in range(1000):
362
if iteration % 100 == 0: # Profile every 100th iteration
363
profiler.enable()
364
process_iteration(iteration)
365
profiler.disable()
366
else:
367
process_iteration(iteration)
368
```
369
370
### Memory Usage
371
372
- **String Registration**: Function names are registered as NVTX strings for efficiency
373
- **Thread Locals**: Each thread maintains separate profiling state
374
- **Cleanup**: Profiler automatically cleans up when disabled
375
376
## Error Handling
377
378
- **Exception Safety**: Profiling continues even when annotated functions raise exceptions
379
- **Thread Safety**: Multiple threads can use profiling simultaneously
380
- **Nested Enable/Disable**: Multiple enable() calls are safe; last disable() stops profiling
381
- **NVTX Disabled**: All profiling becomes no-op when NVTX_DISABLE environment variable is set
382
383
## Limitations
384
385
- **Recursive Functions**: Deep recursion may create very nested annotation hierarchies
386
- **Generator Functions**: Generator yields/resumes create separate annotation ranges
387
- **Async Functions**: Each await point creates separate ranges for async function calls
388
- **Import Time**: Functions called during module import are profiled if profiler is already enabled