nsight-python 0.9.5__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nsight/__init__.py +8 -4
- nsight/analyze.py +197 -70
- nsight/annotation.py +4 -0
- nsight/collection/core.py +223 -52
- nsight/collection/ncu.py +296 -114
- nsight/exceptions.py +19 -0
- nsight/extraction.py +147 -71
- nsight/thermovision.py +342 -78
- nsight/transformation.py +65 -31
- nsight/utils.py +25 -13
- nsight/visualization.py +32 -4
- {nsight_python-0.9.5.dist-info → nsight_python-1.0.0.dist-info}/METADATA +5 -4
- nsight_python-1.0.0.dist-info/RECORD +16 -0
- {nsight_python-0.9.5.dist-info → nsight_python-1.0.0.dist-info}/WHEEL +1 -1
- nsight_python-0.9.5.dist-info/RECORD +0 -16
- {nsight_python-0.9.5.dist-info → nsight_python-1.0.0.dist-info}/licenses/LICENSE +0 -0
nsight/__init__.py
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
|
+
from importlib.metadata import version
|
|
5
|
+
|
|
4
6
|
from nsight import analyze
|
|
5
7
|
from nsight.annotation import annotate
|
|
6
|
-
from nsight.
|
|
8
|
+
from nsight.collection.ncu import try_init_injection
|
|
9
|
+
from nsight.utils import VerbosityLevel, col_panel, row_panel
|
|
7
10
|
|
|
8
|
-
#
|
|
9
|
-
|
|
11
|
+
# Load injection library and symbols for NCU attach (if available)
|
|
12
|
+
try_init_injection()
|
|
10
13
|
|
|
14
|
+
__version__ = version("nsight-python")
|
|
11
15
|
|
|
12
|
-
__all__ = ["analyze", "annotate"]
|
|
16
|
+
__all__ = ["analyze", "annotate", "VerbosityLevel"]
|
nsight/analyze.py
CHANGED
|
@@ -7,14 +7,16 @@ import os
|
|
|
7
7
|
import tempfile
|
|
8
8
|
import warnings
|
|
9
9
|
from collections.abc import Callable, Iterable, Sequence
|
|
10
|
-
from typing import Any, Literal, overload
|
|
10
|
+
from typing import Any, Literal, Mapping, overload
|
|
11
11
|
|
|
12
12
|
import matplotlib
|
|
13
13
|
import matplotlib.figure
|
|
14
14
|
import numpy as np
|
|
15
|
+
from numpy.typing import NDArray
|
|
15
16
|
|
|
16
17
|
import nsight.collection as collection
|
|
17
18
|
import nsight.visualization as visualization
|
|
19
|
+
from nsight.utils import VerbosityLevel
|
|
18
20
|
|
|
19
21
|
|
|
20
22
|
# Overload 1: When used without parentheses: @kernel
|
|
@@ -31,15 +33,24 @@ def kernel(
|
|
|
31
33
|
*,
|
|
32
34
|
configs: Iterable[Any] | None = None,
|
|
33
35
|
runs: int = 1,
|
|
34
|
-
derive_metric:
|
|
36
|
+
derive_metric: (
|
|
37
|
+
Callable[
|
|
38
|
+
..., float | tuple[float, str] | Mapping[str, float | tuple[float, str]]
|
|
39
|
+
]
|
|
40
|
+
| None
|
|
41
|
+
) = None,
|
|
35
42
|
normalize_against: str | None = None,
|
|
36
|
-
|
|
43
|
+
verbosity: VerbosityLevel = VerbosityLevel.INFO,
|
|
37
44
|
metrics: Sequence[str] = ["gpu__time_duration.sum"],
|
|
38
45
|
ignore_kernel_list: Sequence[str] | None = None,
|
|
39
46
|
clock_control: Literal["base", "none"] = "none",
|
|
40
47
|
cache_control: Literal["all", "none"] = "all",
|
|
41
48
|
replay_mode: Literal["kernel", "range"] = "kernel",
|
|
42
|
-
|
|
49
|
+
thermal_mode: Literal["auto", "manual", "off"] = "auto",
|
|
50
|
+
thermal_wait: int | None = None,
|
|
51
|
+
thermal_cont: int | None = None,
|
|
52
|
+
thermal_timeout: int | None = None,
|
|
53
|
+
thermal_device: int | None = None,
|
|
43
54
|
combine_kernel_metrics: Callable[[float, float], float] | None = None,
|
|
44
55
|
output_prefix: str | None = None,
|
|
45
56
|
output_csv: bool = False,
|
|
@@ -52,15 +63,24 @@ def kernel(
|
|
|
52
63
|
*,
|
|
53
64
|
configs: Iterable[Any] | None = None,
|
|
54
65
|
runs: int = 1,
|
|
55
|
-
derive_metric:
|
|
66
|
+
derive_metric: (
|
|
67
|
+
Callable[
|
|
68
|
+
..., float | tuple[float, str] | Mapping[str, float | tuple[float, str]]
|
|
69
|
+
]
|
|
70
|
+
| None
|
|
71
|
+
) = None,
|
|
56
72
|
normalize_against: str | None = None,
|
|
57
|
-
|
|
73
|
+
verbosity: VerbosityLevel = VerbosityLevel.INFO,
|
|
58
74
|
metrics: Sequence[str] = ["gpu__time_duration.sum"],
|
|
59
75
|
ignore_kernel_list: Sequence[str] | None = None,
|
|
60
76
|
clock_control: Literal["base", "none"] = "none",
|
|
61
77
|
cache_control: Literal["all", "none"] = "all",
|
|
62
78
|
replay_mode: Literal["kernel", "range"] = "kernel",
|
|
63
|
-
|
|
79
|
+
thermal_mode: Literal["auto", "manual", "off"] = "auto",
|
|
80
|
+
thermal_wait: int | None = None,
|
|
81
|
+
thermal_cont: int | None = None,
|
|
82
|
+
thermal_timeout: int | None = None,
|
|
83
|
+
thermal_device: int | None = None,
|
|
64
84
|
combine_kernel_metrics: Callable[[float, float], float] | None = None,
|
|
65
85
|
output_prefix: str | None = None,
|
|
66
86
|
output_csv: bool = False,
|
|
@@ -86,6 +106,13 @@ def kernel(
|
|
|
86
106
|
- ``**kwargs``: Original function keyword arguments
|
|
87
107
|
- Returns ``ProfileResults`` object containing profiling data
|
|
88
108
|
|
|
109
|
+
.. note::
|
|
110
|
+
Configs are passed to the decorated function as positional arguments.
|
|
111
|
+
Both positional and keyword-only parameters are supported in the function
|
|
112
|
+
signature. If the function has ``*args`` or ``**kwargs``, they are tolerated
|
|
113
|
+
but will always be empty during profiling. Parameters with default values
|
|
114
|
+
may be omitted from configs — missing values will be filled from the defaults.
|
|
115
|
+
|
|
89
116
|
|
|
90
117
|
Parameters:
|
|
91
118
|
configs: An iterable of configurations to run the function with. Each configuration can be either:
|
|
@@ -98,6 +125,10 @@ def kernel(
|
|
|
98
125
|
|
|
99
126
|
configs = [1, 2, 3, 4]
|
|
100
127
|
|
|
128
|
+
If configs provide fewer values than the function has parameters,
|
|
129
|
+
the remaining parameters must have default values, which will be used
|
|
130
|
+
automatically.
|
|
131
|
+
|
|
101
132
|
If the configs are not provided at decoration time, they must be provided when calling the decorated function.
|
|
102
133
|
runs: Number of times each configuration should be executed.
|
|
103
134
|
derive_metric:
|
|
@@ -105,15 +136,25 @@ def kernel(
|
|
|
105
136
|
This can be used to compute derived metrics like TFLOPs that cannot
|
|
106
137
|
be captured by ncu directly. The function takes the metric values and
|
|
107
138
|
the arguments of the profile-decorated function and returns the new
|
|
108
|
-
|
|
139
|
+
metrics. Return value can be either:
|
|
140
|
+
|
|
141
|
+
- A single value (float/int): Will be added as a new metric with the function name as the metric name. For lambda functions, the metric name will be ``"<lambda>"``.
|
|
142
|
+
- A tuple (value, unit): A single metric value with its unit specified. The value will be added with the function name as the metric name, and the unit will be stored in the ``Unit`` column of the dataframe. Example: ``(tflops_value, "TFLOPS")``.
|
|
143
|
+
- A dictionary: Keys will be used as metric names, values can be either:
|
|
144
|
+
- Scalar values (float/int): Metric values without units. ``np.nan`` will be added to the ``Unit`` column and a warning will be issued.
|
|
145
|
+
- Tuples (value, unit): Metric values with units specified. The unit will be stored in the ``Unit`` column of the dataframe. Example: ``{"TFLOPS": (tflops_value, "TFLOPS"), "ArithIntensity": (intensity_value, "FLOP/byte")}``.
|
|
146
|
+
|
|
147
|
+
The parameter order requirements for the custom function:
|
|
109
148
|
|
|
110
149
|
- First several arguments: Must exactly match the order of metrics declared in the @kernel decorator. These arguments will receive the actual measured values of those metrics.
|
|
111
150
|
- Remaining arguments: Must exactly match the signature of the decorated function. In other words, the original function's parameters are passed in order.
|
|
112
151
|
|
|
152
|
+
**Note on units**: When units are not provided (returning scalar values instead of tuples), ``np.nan`` will be added to the ``Unit`` column in the dataframe and a warning will be issued. To avoid warnings and ensure proper unit tracking, return tuples ``(value, unit)`` for all derived metrics.
|
|
153
|
+
|
|
113
154
|
See the examples for concrete use cases.
|
|
114
155
|
normalize_against:
|
|
115
|
-
Annotation name to normalize metrics against.
|
|
116
|
-
|
|
156
|
+
Annotation name to normalize metrics against (computes current / baseline).
|
|
157
|
+
Combine with ``derive_metric`` to compute speedup (reciprocal of normalized value).
|
|
117
158
|
metrics: The metrics to collect. By default, kernel runtimes in nanoseconds
|
|
118
159
|
are collected. Default: ``["gpu__time_duration.sum"]``. To see the available
|
|
119
160
|
metrics on your system, use the command: ``ncu --query-metrics``.
|
|
@@ -147,12 +188,56 @@ def kernel(
|
|
|
147
188
|
|
|
148
189
|
Default: ``"kernel"``
|
|
149
190
|
|
|
150
|
-
|
|
151
|
-
|
|
191
|
+
thermal_mode: Controls GPU thermal management mode. Default: ``"auto"``
|
|
192
|
+
|
|
193
|
+
Monitors GPU thermal headroom (T.Limit) and pauses profiling when GPU gets
|
|
194
|
+
too hot, resuming after cooling. Prevents thermal throttling from affecting
|
|
195
|
+
profiling accuracy.
|
|
196
|
+
|
|
197
|
+
**Modes:**
|
|
198
|
+
|
|
199
|
+
- ``"auto"``: Adaptive mode - automatically adjusts thermal_cont threshold based on GPU heating behavior.
|
|
200
|
+
- ``"manual"``: Fixed mode - uses specified thermal_wait and thermal_cont thresholds without adaptation.
|
|
201
|
+
- ``"off"``: Thermal control disabled - no monitoring or pausing.
|
|
202
|
+
|
|
203
|
+
thermal_wait: Thermal headroom threshold (T.Limit in °C) that triggers cooling pause.
|
|
204
|
+
|
|
205
|
+
When GPU thermal headroom drops to this value, profiling pauses and waits
|
|
206
|
+
for the GPU to cool down. Lower values allow the GPU to run hotter before
|
|
207
|
+
pausing (more aggressive, faster profiling, higher throttling risk).
|
|
208
|
+
|
|
209
|
+
If ``None``, uses default value (10°C). Applied in both "auto" and "manual" modes.
|
|
210
|
+
|
|
211
|
+
thermal_cont: Thermal headroom threshold (T.Limit in °C) to resume profiling after cooling.
|
|
212
|
+
|
|
213
|
+
After a cooling pause, profiling resumes once GPU thermal headroom reaches
|
|
214
|
+
this value. Higher values mean the GPU cools more before resuming (safer,
|
|
215
|
+
fewer cooling cycles, but slower overall profiling time).
|
|
216
|
+
|
|
217
|
+
If ``None``, uses default value (20°C). In "auto" mode, this value adapts based on
|
|
218
|
+
workload characteristics. In "manual" mode, it remains fixed.
|
|
152
219
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
220
|
+
**Requirement:** Must be greater than thermal_wait.
|
|
221
|
+
|
|
222
|
+
thermal_timeout: Maximum wait time in seconds for GPU to cool down.
|
|
223
|
+
Default: 180 seconds
|
|
224
|
+
|
|
225
|
+
thermal_device: CUDA device ordinal to monitor for thermal throttling.
|
|
226
|
+
|
|
227
|
+
If set, monitor that CUDA device. If ``None``, monitor the current
|
|
228
|
+
CUDA device context. Device numbering follows CUDA runtime ordinals and
|
|
229
|
+
honors ``CUDA_VISIBLE_DEVICES``.
|
|
230
|
+
|
|
231
|
+
Default: ``None``
|
|
232
|
+
|
|
233
|
+
verbosity: Controls the verbosity level of the output. Selecting level N
|
|
234
|
+
enables output at all levels with value <= N. Default: ``VerbosityLevel.INFO``.
|
|
235
|
+
|
|
236
|
+
- ``VerbosityLevel.SILENT``: Suppresses all output.
|
|
237
|
+
- ``VerbosityLevel.INFO``: Shows a progress bar, profiling completion messages,
|
|
238
|
+
and report file paths.
|
|
239
|
+
- ``VerbosityLevel.DEBUG``: Adds configuration-specific logs, the full NCU CLI
|
|
240
|
+
command, and enables NCU verbose output.
|
|
156
241
|
|
|
157
242
|
output_prefix: When specified, all intermediate profiler files are created with this prefix.
|
|
158
243
|
For example, if `output_prefix="/home/user/run1_"`, the profiler will generate:
|
|
@@ -175,8 +260,8 @@ def kernel(
|
|
|
175
260
|
|
|
176
261
|
- ``Annotation``: Name of the annotated region being profiled
|
|
177
262
|
- ``Value``: Raw metric values collected by the profiler
|
|
178
|
-
- ``Metric``: The metrics being collected (e.g., ``gpu__time_duration.sum``)
|
|
179
|
-
- ``
|
|
263
|
+
- ``Metric``: The metrics being collected (e.g., ``gpu__time_duration.sum``) and the metrics being derived
|
|
264
|
+
- ``Unit``: Unit of measurement for the metric value (e.g., ``ns`` for nanoseconds)
|
|
180
265
|
- ``Kernel``: Name of the GPU kernel(s) launched
|
|
181
266
|
- ``GPU``: GPU device name
|
|
182
267
|
- ``Host``: Host machine name
|
|
@@ -197,8 +282,8 @@ def kernel(
|
|
|
197
282
|
- ``CI95_Upper``: Upper bound of the 95% confidence interval
|
|
198
283
|
- ``RelativeStdDevPct``: Standard deviation as a percentage of the mean
|
|
199
284
|
- ``StableMeasurement``: Boolean indicating if the measurement is stable (low variance). The measurement is stable if ``RelativeStdDevPct`` < 2 % .
|
|
200
|
-
- ``Metric``: The metrics being collected
|
|
201
|
-
- ``
|
|
285
|
+
- ``Metric``: The metrics being collected and the metrics being derived
|
|
286
|
+
- ``Unit``: Unit of measurement for the metric value (e.g., ``ns`` for nanoseconds)
|
|
202
287
|
- ``Kernel``: Name of the GPU kernel(s) launched
|
|
203
288
|
- ``GPU``: GPU device name
|
|
204
289
|
- ``Host``: Host machine name
|
|
@@ -208,33 +293,37 @@ def kernel(
|
|
|
208
293
|
# Strip whitespace
|
|
209
294
|
metrics = [m.strip() for m in metrics]
|
|
210
295
|
|
|
296
|
+
# Validate thermal parameters if both are provided
|
|
297
|
+
if thermal_wait is not None and thermal_cont is not None:
|
|
298
|
+
if thermal_cont <= thermal_wait:
|
|
299
|
+
raise ValueError(
|
|
300
|
+
f"Invalid thermal control parameters: thermal_cont ({thermal_cont}°C) "
|
|
301
|
+
f"must be greater than thermal_wait ({thermal_wait}°C). "
|
|
302
|
+
f"thermal_cont is the target thermal headroom after cooling, "
|
|
303
|
+
f"thermal_wait is the threshold that triggers cooling."
|
|
304
|
+
)
|
|
305
|
+
|
|
211
306
|
def _create_profiler() -> collection.core.NsightProfiler:
|
|
212
307
|
"""Helper to create the profiler with the given settings."""
|
|
213
|
-
if output not in ("quiet", "progress", "verbose"):
|
|
214
|
-
raise ValueError("output must be 'quiet', 'progress' or 'verbose'")
|
|
215
|
-
|
|
216
|
-
output_progress = output == "progress" or output == "verbose"
|
|
217
|
-
output_detailed = output == "verbose"
|
|
218
|
-
|
|
219
308
|
# Create the output paths needed for the ncu report, ncu logs and the CSVs
|
|
220
309
|
prefix = output_prefix
|
|
221
|
-
if
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
) # Adds a trailing forward/backward slash
|
|
227
|
-
else:
|
|
228
|
-
os.makedirs(os.path.dirname(prefix) or ".", exist_ok=True)
|
|
310
|
+
if prefix is None:
|
|
311
|
+
prefix = tempfile.mkdtemp(prefix="nspy_")
|
|
312
|
+
prefix = os.path.join(prefix, "") # Adds a trailing forward/backward slash
|
|
313
|
+
else:
|
|
314
|
+
os.makedirs(os.path.dirname(prefix) or ".", exist_ok=True)
|
|
229
315
|
|
|
230
316
|
settings = collection.core.ProfileSettings(
|
|
231
317
|
configs=configs,
|
|
232
318
|
runs=runs,
|
|
233
|
-
|
|
234
|
-
output_detailed=output_detailed,
|
|
319
|
+
verbosity=verbosity,
|
|
235
320
|
derive_metric=derive_metric,
|
|
236
321
|
normalize_against=normalize_against,
|
|
237
|
-
|
|
322
|
+
thermal_mode=thermal_mode,
|
|
323
|
+
thermal_wait=thermal_wait,
|
|
324
|
+
thermal_cont=thermal_cont,
|
|
325
|
+
thermal_timeout=thermal_timeout,
|
|
326
|
+
thermal_device=thermal_device,
|
|
238
327
|
output_prefix=prefix,
|
|
239
328
|
output_csv=output_csv,
|
|
240
329
|
)
|
|
@@ -259,29 +348,63 @@ def kernel(
|
|
|
259
348
|
return profiler(_func) # type: ignore[return-value]
|
|
260
349
|
|
|
261
350
|
|
|
262
|
-
def
|
|
351
|
+
def _legalize_metric(result: collection.core.ProfileResults, metric: str | None) -> str:
|
|
263
352
|
"""
|
|
264
|
-
|
|
353
|
+
Legalize the metric parameter for plotting.
|
|
354
|
+
|
|
355
|
+
This function ensures that the provided metric parameter is valid for plotting.
|
|
356
|
+
If the metric is None, it verifies there is exactly one metric available and
|
|
357
|
+
returns that metric's name. If a metric is specified, it validates that the
|
|
358
|
+
metric exists in the profile results and returns itself.
|
|
265
359
|
|
|
266
360
|
Args:
|
|
267
|
-
result: ProfileResults object
|
|
361
|
+
result: ProfileResults object containing profiling data.
|
|
362
|
+
metric: The name of the metric to plot, or None to use the single metric
|
|
363
|
+
if only one exists.
|
|
364
|
+
|
|
365
|
+
Returns:
|
|
366
|
+
The validated metric name for plotting.
|
|
268
367
|
|
|
269
368
|
Raises:
|
|
270
|
-
ValueError:
|
|
369
|
+
ValueError: Raised in the following cases:
|
|
370
|
+
1. When `metric` is None and multiple metrics are found.
|
|
371
|
+
2. When `metric` is None and no metrics are found.
|
|
372
|
+
3. When `metric` is specified but not present in the results.
|
|
271
373
|
"""
|
|
272
374
|
df = result.to_dataframe()
|
|
273
375
|
|
|
274
|
-
#
|
|
275
|
-
unique_metrics = df["Metric"].unique()
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
376
|
+
# Extract unique metric names from the DataFrame
|
|
377
|
+
unique_metrics: NDArray[Any] = df["Metric"].unique()
|
|
378
|
+
n_metrics = len(unique_metrics)
|
|
379
|
+
|
|
380
|
+
if metric is None:
|
|
381
|
+
# Case: No metric specified - ensure there is exactly one metric
|
|
382
|
+
if n_metrics > 1:
|
|
383
|
+
raise ValueError(
|
|
384
|
+
f"Cannot visualize multiple metrics ({n_metrics} > 1) with the "
|
|
385
|
+
"@nsight.analyze.plot decorator. Please specify a metric to plot. "
|
|
386
|
+
f"The metrics found are: {unique_metrics.tolist()}"
|
|
387
|
+
)
|
|
388
|
+
elif n_metrics == 0:
|
|
389
|
+
raise ValueError(
|
|
390
|
+
"No metrics found in the profile results. Please ensure that the "
|
|
391
|
+
"profiler is configured correctly."
|
|
392
|
+
)
|
|
393
|
+
else: # n_metrics == 1
|
|
394
|
+
return str(unique_metrics[0])
|
|
395
|
+
else:
|
|
396
|
+
# Case: Metric specified - ensure it exists in the results
|
|
397
|
+
if metric not in unique_metrics:
|
|
398
|
+
raise ValueError(
|
|
399
|
+
f"Metric '{metric}' not found in the profile results. Please check "
|
|
400
|
+
f"the metric name and try again. The metrics found are: {unique_metrics.tolist()}."
|
|
401
|
+
)
|
|
402
|
+
return metric
|
|
281
403
|
|
|
282
404
|
|
|
283
405
|
def plot(
|
|
284
406
|
filename: str = "plot.png",
|
|
407
|
+
metric: str | None = None,
|
|
285
408
|
*,
|
|
286
409
|
title: str = "Nsight Analyze Kernel Plot Results",
|
|
287
410
|
ylabel: str | None = None,
|
|
@@ -320,6 +443,10 @@ def plot(
|
|
|
320
443
|
def my_func(...):
|
|
321
444
|
|
|
322
445
|
Args:
|
|
446
|
+
metric: The specific metric to plot (e.g., ``gpu__time_duration.sum``).
|
|
447
|
+
If None (default), the function will plot the single metric found in
|
|
448
|
+
the ``ProfileResults`` object containing profiling data, if only one exists,
|
|
449
|
+
otherwise it will raise an error if multiple metrics are present. Default: ``None``
|
|
323
450
|
filename: Filename to save the plot. Default: ``'plot'``
|
|
324
451
|
title: Title for the plot. Default: ``'Nsight Analyze Kernel Plot Results'``
|
|
325
452
|
ylabel: Label for the y-axis in the generated plot.
|
|
@@ -357,29 +484,29 @@ def plot(
|
|
|
357
484
|
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
358
485
|
result = func(*args, **kwargs)
|
|
359
486
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
487
|
+
# Legalize the user-provided metric for plotting
|
|
488
|
+
legalized_metric = _legalize_metric(result, metric)
|
|
489
|
+
|
|
490
|
+
visualization.visualize(
|
|
491
|
+
result.to_dataframe(),
|
|
492
|
+
metric=legalized_metric,
|
|
493
|
+
row_panels=row_panels,
|
|
494
|
+
col_panels=col_panels,
|
|
495
|
+
x_keys=x_keys,
|
|
496
|
+
print_data=print_data,
|
|
497
|
+
title=title,
|
|
498
|
+
filename=filename,
|
|
499
|
+
ylabel=ylabel or "",
|
|
500
|
+
annotate_points=annotate_points,
|
|
501
|
+
show_avg=show_avg,
|
|
502
|
+
show_geomean=show_geomean,
|
|
503
|
+
plot_type=plot_type,
|
|
504
|
+
plot_width=plot_width,
|
|
505
|
+
plot_height=plot_height,
|
|
506
|
+
variant_fields=variant_fields,
|
|
507
|
+
variant_annotations=variant_annotations,
|
|
508
|
+
plot_callback=plot_callback,
|
|
509
|
+
)
|
|
383
510
|
return result
|
|
384
511
|
|
|
385
512
|
return wrapper
|
nsight/annotation.py
CHANGED
|
@@ -129,6 +129,10 @@ class annotate(nvtx.annotate): # type: ignore[misc]
|
|
|
129
129
|
Nested annotations are currently not supported. However, since each
|
|
130
130
|
annotation is expected to contain a single kernel launch by default,
|
|
131
131
|
nested annotations should not be necessary in typical usage scenarios.
|
|
132
|
+
Entering and exiting the annotation context pushes and pops an NVTX
|
|
133
|
+
range, so calling ``nvtx.pop_range()`` inside the annotation context
|
|
134
|
+
without a corresponding push would pop the annotation context's own
|
|
135
|
+
range instead, resulting in incorrect profiling results.
|
|
132
136
|
|
|
133
137
|
"""
|
|
134
138
|
|