Source code for mstar.utils.profiler
"""Utilities for NVTX range annotations for profiling with nsys."""
from __future__ import annotations
from contextlib import contextmanager
from typing import Iterator
import torch
def _sync_if_available() -> None:
if torch.cuda.is_available():
torch.cuda.synchronize()
[docs]
def range_push(name: str, *, synchronize: bool = False) -> None:
"""Push an NVTX range, optionally syncing before the marker.
Default is ``synchronize=False`` so adding NVTX markers doesn't
serialize the execution. Set ``synchronize=True`` only when the
caller specifically wants the range to extend over the GPU work it
wraps (e.g. an ad-hoc benchmark of one kernel) — and remember that
each ``synchronize=True`` call drains the *entire* default stream
via ``torch.cuda.synchronize()``, not just the wrapped kernel.
"""
if synchronize:
_sync_if_available()
torch.cuda.nvtx.range_push(name)
[docs]
def range_pop(*, synchronize: bool = False) -> None:
"""Pop the current NVTX range, optionally syncing before the marker.
Same semantics as ``range_push`` — default is ``synchronize=False``.
"""
if synchronize:
_sync_if_available()
torch.cuda.nvtx.range_pop()
[docs]
def mark(name: str) -> None:
"""Emit an instant NVTX marker without CUDA synchronization."""
torch.cuda.nvtx.mark(name)
[docs]
@contextmanager
def nvtx_range(name: str, *, synchronize: bool = False) -> Iterator[None]:
"""Convenience context manager for `range_push`/`range_pop`."""
range_push(name, synchronize=synchronize)
try:
yield
finally:
range_pop(synchronize=synchronize)