# mypy: 允许未类型化定义
r"此软件包增加了对 CUDA 实现的设备内存管理的支持。"
导入
集合
导入 contextlib
导入 ctypes
导入
酸菜
导入
系统
导入
警告
来自
检查
导入
签名
来自
打字
导入 Any,
直接,
可选,
联合
来自 typing_extensions
导入
已弃用
导入
火炬
来自
火炬
导入 _C
来自 torch._utils
导入 _dummy_type
来自
torch 的类型
导入
设备
来自 .
导入 (
_get_amdsmi_device_index,
获取设备索引,
获取 nvml 设备索引,
_lazy_init,
已初始化,
)
来自 ._memory_viz
导入
内存
是
内存,
段落
是
_段落
全部 = [
"缓存分配器分配",
"缓存分配器删除",
"缓存分配器启用",
get_per_process_memory_fraction,
"设置每个进程内存分数",
清空缓存,
内存统计,
内存统计嵌套字典,
"重置累计内存统计",
"重置峰值内存统计",
"重置最大分配内存",
"重置最大缓存内存",
"host_memory_stats",
"host_memory_stats_as_nested_dict",
"重置累积的主机内存统计信息",
"重置峰值主机内存统计",
"内存分配",
"最大分配内存",
"内存保留",
"max_memory_reserved",
"内存缓存",
"max_memory_cached",
"内存快照",
内存摘要,
"列出 GPU 进程",
"mem_get_info",
获取分配器后端,
CUDA 可插拔分配器,
更改当前分配器,
"内存池",
"内存池上下文",
"使用内存池",
]
如果
不是
有属性(torch._C, "_cuda_CUDAAllocator"):
定义虚拟基类
torch._C.字典["_cuda_CUDAAllocator"] = _dummy_type("_cuda_CUDAAllocator")
如果
不是
有属性(torch._C,
_内存池):
定义虚拟基类
torch._C.字典[
_内存池] = _dummy_type(
_内存池)
torch._C.字典[
_内存池上下文] = _dummy_type(
_内存池上下文)
torch._C.字典["_cuda_beginAllocateToPool"] = _dummy_type(
"_cuda_beginAllocateToPool"
)
torch._C.字典["_cuda_endAllocateCurrentStreamToPool"] = _dummy_type(
"_cuda_endAllocateCurrentStreamToPool"
)
torch._C.字典[
_cuda_releasePool] = _dummy_type(
_cuda_releasePool)
来自 torch._C
导入 ( # noqa: F401
_cuda_beginAllocateToPool,
_cuda_CUDA 分配器,
_cuda_endAllocateCurrentStreamToPool,
_cuda_releasePool,
_MemPool,
_MemPoolContext,
)
def _host 分配器():
_lazy_init()
返回 torch._C.
_cuda_cudaHost 分配器()
@contextlib.contextmanager
def _free 互斥锁():
torch._C._cuda 锁互斥锁()
尝试:
产生
最后:
torch._C._cuda_unlock_mutex()
[文档]def 缓存分配器分配(size, device: 联合[Device, int] = None, stream=None):
r"""使用 CUDA 内存分配器进行内存分配。
为指定设备和流分配内存,
函数旨在与其他系统进行互操作性使用
框架。分配的内存通过
:func:`~torch.cuda.caching_allocator_delete`.
参数:
大小(int 类型):要分配的字节数。
设备(torch.device 或 int,可选):选定的设备。如果是
``None``,则使用默认的 CUDA 设备。
流(torch.cuda.Stream 或 int,可选):选定的流。如果是 ``None``,则
选择的设备默认流被使用。
.. 注意::
更多关于 GPU 内存管理的详细信息,请参阅 :ref:`cuda-memory-management`。
管理。
"""
如果设备为空:
设备 = torch.cuda.current_device()
设备 = _get_device_index(设备)
如果 stream 为 None:
stream = torch.cuda.current_stream(device)
如果 stream 是 torch.cuda.streams.Stream 的实例:
stream = stream.cuda_stream
如果 stream 不是 int 类型:
raise TypeError(
"stream 参数类型无效,必须是"
"`torch.cuda.Stream`或表示指针的 int 类型"
"指向现有流"
)
使用 torch.cuda.device(device):
返回 torch._C._cuda_cudaCachingAllocator_raw_alloc(size, stream)
[文档]def 缓存分配器删除(mem_ptr):
r"""使用 CUDA 内存分配器分配的内存删除。
使用 :func:`~torch.cuda.caching_allocator_alloc` 分配的内存。
在这里释放。关联的设备和流在内部跟踪。
分配器。
Args:
mem_ptr (int): 分配器要释放的内存地址。
.. 注意::
查看更多关于 GPU 内存管理的详细信息::ref:`cuda-memory-management`
管理信息。
"""
torch._C._cuda_cudaCachingAllocator_raw_delete(mem_ptr)
[文档]def caching_allocator_enable(value: bool = True) -> None:
r"""启用或禁用 CUDA 内存分配器。默认开启。"""
if is_initialized():
torch._C._cuda_cudaCachingAllocator_enable(value)
[文档]def set_per_process_memory_fraction(
分数,device: Union[Device, int] = None
) -> None:
r"""为进程设置内存分数。
分数用于限制缓存分配器在 CUDA 设备上分配的内存。
允许的值等于总可见内存乘以分数。
如果尝试在一个进程中分配超过允许的值,将在分配器中引发内存错误。
在分配器中引发内存错误。
Args:
分数(float): 范围:0~1。允许的内存等于总内存 * 分数。
设备 (torch.device 或 int, 可选): 选择设备。如果它是
``None``,则使用默认的 CUDA 设备。
.. 注意::
通常情况下,可用总内存小于总容量。
"""
_lazy_init()
如果设备为空:
设备 = torch.cuda.current_device()
设备 = _get_device_index(设备)
如果分数不是浮点数:
抛出 TypeError 异常("分数参数类型无效,必须是`float`类型")
如果分数小于 0 或大于 1:
抛出 ValueError 异常(f"无效的分数值:{fraction}。允许的范围:0~1")
torch._C._cuda_setMemoryFraction(fraction, device)
[文档]def get_per_process_memory_fraction(device: Union[torch.device, int] = None) -> float:
r"""获取进程的内存分数。
Args:
device (torch.device 或 int,可选):选定的设备。如果它是
使用默认的 CUDA 设备。
返回:
内存分数,范围在 0~1 之间。允许使用的内存等于总内存 * 分数。
"""
_lazy_init()
if 设备为 None:
设备 = torch.cuda.current_device()
设备 = _get_device_index(设备)
return torch._C._cuda_getMemoryFraction(device)
[文档]def empty_cache() -> None:
r"""释放当前由缓存分配器持有的所有未占用缓存内存,以便这些内存可以被其他 GPU 应用程序使用,并在`nvidia-smi`中可见。
r"""释放当前由缓存分配器持有的所有未占用缓存内存,以便这些内存可以被其他 GPU 应用程序使用,并在`nvidia-smi`中可见。
r"""释放当前由缓存分配器持有的所有未占用缓存内存,以便这些内存可以被其他 GPU 应用程序使用,并在`nvidia-smi`中可见。
.. 注意::
`~torch.cuda.empty_cache()` 并不会增加 PyTorch 可用的 GPU 内存量。然而,在某些情况下,它可能有助于减少 GPU 内存碎片。有关信息,请参阅 :ref:`cuda-memory-management`。
然而,它可能有助于减少 GPU 内存碎片。有关信息,请参阅 :ref:`cuda-memory-management`。
。有关信息,请参阅 :ref:`cuda-memory-management`。
更多关于 GPU 内存管理的详细信息。
"""
如果 is_initialized()返回 True:
torch._C._cuda_emptyCache()
[文档]def
内存统计(
设备:
联合[
设备, int] =
无) ->
字典[str, Any
]
r返回给定设备的 CUDA 内存分配器统计信息的字典。
该函数的返回值是一个包含统计信息的字典,
非负整数。
核心统计:
- ``"allocated.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
内存分配器接收到的分配请求的数量。
- ``"allocated_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
分配的内存量。
- ``"segment.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
从 `cudaMalloc()` 保留的段数。
- ``"reserved_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
预留内存量。
- ``"active.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
活跃内存块的数量。
- ``"active_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
活跃内存的总量。
inactive_split.{all,large_pool,small_pool}.{current,peak,allocated,freed}
无效且不可释放的内存块数量。
inactive_split_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}
无效且不可释放的内存量。
对于这些核心统计,值如下分解。
池类型:
- ``all``: 所有内存池的合并统计。
- ``large_pool``: 大分配池的统计信息
(截至 2019 年 10 月,对于大小≥1MB 的分配)。
- ``small_pool``: 小分配池的统计信息
截至 2019 年 10 月,对于小于 1MB 的分配。
指标类型:
- ``current``: 当前此指标的值。
- ``peak``: 此指标的最大值。
- ``allocated``: 此指标的历史总增长量。
- ``freed``: 此指标的历史总减少量。
除了核心统计信息外,我们还提供了一些简单的计数器:
counters:
- ``"num_alloc_retries"``: 失败的 ``cudaMalloc`` 调用次数
导致缓存刷新并重试。
- ``"num_ooms"``: 抛出的内存不足错误数量。
- ``"num_sync_all_streams"``: 调用 ``synchronize_and_free_events`` 事件的次数。
- ``"num_device_alloc"``: CUDA 分配调用次数。这包括 cuMemMap 和 cudaMalloc。
cuMemMap 和 cudaMalloc。
- ``"num_device_free"``: CUDA 空闲调用次数。这包括 cuMemUnmap
并且 cudaFree。
缓存分配器可以通过 ENV 配置,以不分割大于 a 的块
定义大小(参见 Cuda 语义文档中的内存管理部分)。
这有助于避免内存碎片化,但可能会影响性能
额外的输出有助于调整和评估影响
- ``"max_split_size"``: 大于此大小的块将不会分割。
- ``"oversize_allocations.{current,peak,allocated,freed}"``:
内存分配器接收到的超大小分配请求的数量。
- ``"oversize_segments.{current,peak,allocated,freed}"``:
cudaMalloc() 保留的过大段落数量。
缓存分配器可以通过 ENV 配置以四舍五入内存分配
为了减少碎片化。有时舍入带来的开销可能比
帮助减少的碎片化。以下统计数据可以用来检查
四舍五入添加了过多的开销:
- ``"requested_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
客户端代码请求的内存,与 allocated_bytes 进行比较,以检查
分配四舍五入添加了过多的开销。
参数:
设备(torch.device 或 int,可选):选定的设备。返回当前设备打印信息,由 :func:`~torch.cuda.current_device` 提供,
当前设备的统计信息,由:func:`~torch.cuda.current_device`提供,
如果 :attr:`device` 为 ``None``(默认)。
.. 注意::
查看 :ref:`cuda-memory-management` 以获取更多关于 GPU 内存管理的详细信息。
内存管理。
.. 注意::
使用:ref:`后端:cudaMallocAsync`, 一些统计信息可能没有意义,并且总是报告为零。
没有意义,并且总是报告为零。
"沉浸式翻译"
结果 =
输入文本为空,请提供需要翻译的文本
def _递归添加到结果(
前缀,
对象):
如果 isinstance(
对象,
字典):
如果
长度(
前缀) > 0:
前缀 += "."
for k, v 在
对象.
项目():
_递归添加到结果(
前缀 + k, v)
否则:
结果.append((
前缀,
对象))
统计 =
内存统计嵌套字典(
设备=
设备)
_递归添加到结果(
输入文本翻译为简体中文为:"",
统计)
结果.
排序()
返回
集合.
有序字典(
结果)
def 内存统计嵌套字典(
设备:
联合[
设备, int] =
无) ->
字典[str, Any
]
r返回 `torch.cuda.memory_stats` 的结果,以嵌套字典形式。
如果
不是
已初始化():
返回 {}
设备 =
获取设备索引(
设备,
可选的=
是)
返回 torch._C._cuda_memoryStats(
设备)
def 重置累积内存统计(
设备:
联合[
设备, int] =
无) ->
无:
r重置由 CUDA 内存分配器跟踪的“累计”(历史)统计信息。
详细信息请参阅 :func:`~torch.cuda.memory_stats`。累计统计信息对应于
每个单独的统计字典中的“已分配”和“已释放”键,以及
`"num_alloc_retries"` 和 `"num_ooms"`。
参数:
设备(torch.device 或 int,可选):选定的设备。返回当前设备打印信息,由 :func:`~torch.cuda.current_device` 提供,
当前设备的统计信息,由 :func:`~torch.cuda.current_device` 提供,
如果 :attr:`device` 为 ``None``(默认)。
.. 注意::
查看 :ref:`cuda-memory-management` 以获取更多关于 GPU 内存管理的详细信息。
内存管理。
"沉浸式翻译"
设备 =
获取设备索引(
设备,
可选的=
是)
返回 torch._C._cuda_resetAccumulatedMemoryStats(
设备)
[文档]def reset_peak_memory_stats(device: Union[Device, int] = None) -> None:
重置 CUDA 内存分配器跟踪的"峰值"统计信息。
详细信息请参阅 :func:`~torch.cuda.memory_stats`。峰值统计信息对应于每个单独的统计字典中的"峰值"键。
`"峰值"`键对应于每个单独的统计字典。
参数:
设备(torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由:func:`~torch.cuda.current_device`给出,
如果:attr:`device`为`None`(默认)。
.. note::
查看更多关于 GPU 内存管理的详细信息::ref:`cuda-memory-management`
管理信息。
"""
device = _get_device_index(device, optional=True)
return torch._C._cuda_resetPeakMemoryStats(device)
[文档]def host_memory_stats() ->
字典[str, Any
]
r返回给定设备的 CUDA 内存分配器统计信息的字典。
该函数的返回值是一个包含统计信息的字典,
非负整数。
核心统计:
- ``"allocated.{current,peak,allocated,freed}"``:
内存分配器接收到的分配请求的数量。
``"allocated_bytes.{current,peak,allocated,freed}"``:
分配的内存量。
``"segment.{current,peak,allocated,freed}"``:
从 `cudaMalloc()` 保留的段数。
``"reserved_bytes.{current,peak,allocated,freed}"``:
预留内存量。
对于这些核心统计,值如下分解。
指标类型:
- ``current``: 当前此指标的值。
- ``peak``: 此指标的最大值。
- ``allocated``: 此指标的历史总增长量。
- ``freed``: 此指标的历史总减少量。
除了核心统计信息外,我们还提供了一些简单的计数器:
counters:
- ``"num_host_alloc"``: CUDA 分配调用的数量。这包括 cudaHostAlloc 和 cudaHostRegister。
两种情况。
``"num_host_free"``: CUDA 空闲调用次数。这包括 cudaHostFree 和 cudaHostUnregister。
以及 cudaHostUnregister。
最后,我们还提供了一些简单的计时计数器:
``"host_alloc_time.{total,max,min,count,avg}"``:
通过 CUDA 调用进行的分配请求的时间。
- ``"host_free_time.{total,max,min,count,avg}"``:
通过 CUDA 调用进行的释放请求的时间。
对于这些时间统计,值如下分解。
指标类型:
- ``total``: 总耗时。
- ``max``: 每次调用的最大值。
- ``min``: 每次调用的最小值。
- ``count``: 调用次数。
- ``avg``: 每次调用平均时间。
"沉浸式翻译"
结果 =
输入文本为空,请提供需要翻译的文本
def _递归添加到结果(
前缀,
对象):
如果 isinstance(
对象,
字典):
如果
长度(
前缀) > 0:
前缀 += "."
for k, v 在
对象.
项目():
_递归添加到结果(
前缀 + k, v)
否则:
结果.append((
前缀,
对象))
统计 =
主机内存统计作为嵌套字典()
_递归添加到结果(
输入文本翻译为简体中文为:"",
统计)
结果.
排序()
返回
集合.
有序字典(
结果)
def 主机内存统计作为嵌套字典() ->
字典[str, Any
]
r返回 :func:`~torch.cuda.host_memory_stats` 的结果,以嵌套字典形式。
如果
不是
已初始化():
返回 {}
返回 torch._C._cuda_hostMemoryStats()
def 重置累积的主机内存统计信息() ->
无:
r重置由主机内存分配器跟踪的“累积”(历史)统计信息。
请参阅 :func:`~torch.cuda.host_memory_stats` 以获取详细信息。累积统计信息对应于每个统计字典中的 `"allocated"` 和 `"freed"` 键。
的 `"allocated"` 和 `"freed"` 键。
"沉浸式翻译"
返回 torch._C._cuda_resetAccumulatedHostMemoryStats()
[文档]def reset_peak_host_memory_stats() -> None:
重置主机内存分配器跟踪的“峰值”统计信息。
详细信息请参阅 :func:`~torch.cuda.host_memory_stats`。峰值统计信息对应于每个单独的统计字典中的“峰值”键。
`"峰值"`键对应于每个单独的统计字典。
"""
return torch._C._cuda_resetPeakHostMemoryStats()
[文档]def reset_max_memory_allocated(device: Union[Device, int] = None) -> None:
r"""重置跟踪给定设备张量占用的最大 GPU 内存的起始点。
详细信息请参阅 :func:`~torch.cuda.max_memory_allocated`。
参数:
设备(torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由:func:`~torch.cuda.current_device`给出,
如果:attr:`device`为`None`(默认)。
..警告::
现在这个函数现在调用 :func:`~torch.cuda.reset_peak_memory_stats`,用于重置
/all/ 的峰值内存统计。
.. 注意::
更多关于 GPU 内存管理的详细信息,请参阅 :ref:`cuda-memory-management`。
管理层。
"""
warnings.warn(
"torch.cuda.reset_max_memory_allocated 现在调用 torch.cuda.reset_peak_memory_stats, "
"重置所有峰值内存统计信息。"
FutureWarning
)
返回重置峰值内存统计信息(device=device)
[文档]def reset_max_memory_cached(device: Union[Device, int] = None) -> None:
r"""重置跟踪给定设备缓存分配器管理的最大 GPU 内存的起始点。
详细信息请参阅 :func:`~torch.cuda.max_memory_cached`。
参数:
设备(torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由:func:`~torch.cuda.current_device`给出,
如果:attr:`device`为`None`(默认)。
.. warning::
现在这个函数现在调用 :func:`~torch.cuda.reset_peak_memory_stats`,用于重置
/all/ 的峰值内存统计。
.. 注意::
更多关于 GPU 内存管理的详细信息,请参阅 :ref:`cuda-memory-management`。
管理层。
"""
warnings.warn(
"torch.cuda.reset_max_memory_cached 现在调用 torch.cuda.reset_peak_memory_stats, "
"重置所有峰值内存统计信息。"
FutureWarning
)
返回重置峰值内存统计信息(device=device)
[docs]def memory_allocated(device: Union[Device, int] = None) -> int:
返回给定设备上张量占用的当前 GPU 内存字节数。
参数:
device (torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由 :func:`~torch.cuda.current_device` 提供,
如果 :attr:`device` 为 ``None``(默认)。
.. 注意::
这可能小于 `nvidia-smi` 显示的数值,因为一些
空闲内存可以被缓存分配器保留,并且需要创建在 GPU 上。有关 GPU 内存管理的详细信息,请参阅::ref:`cuda-memory-management`。
需要创建在 GPU 上。有关 GPU 内存管理的详细信息,请参阅::ref:`cuda-memory-management`。
GPU 内存管理的详细信息。
"""
return memory_stats(device=device).get("allocated_bytes.all.current", 0)
[文档]def max_memory_allocated(device: Union[Device, int] = None) -> int:
返回给定设备中张量占用的最大 GPU 内存量(以字节为单位)。
默认情况下,这返回自开始以来的峰值分配内存。
该程序可以使用:func:`~torch.cuda.reset_peak_memory_stats` 来重置
追踪此指标的开始点。例如,这两个函数可以测量训练循环中每个迭代的峰值分配内存使用量。
这些函数可以测量训练循环中每个迭代的峰值分配内存使用量。
在训练循环中。
Args:
设备(torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由 :func:`~torch.cuda.current_device` 提供,
如果 :attr:`device` 为 ``None``(默认)。
.. 注意::
更多关于 GPU 内存管理的详细信息,请参阅 :ref:`cuda-memory-management`。
内存管理。
"""
return memory_stats(device=device).get("allocated_bytes.all.peak", 0)
[文档]def memory_reserved(device: Union[Device, int] = None) -> int:
返回当前设备缓存分配器管理的 GPU 内存字节数。
Args:
设备(torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由:func:`~torch.cuda.current_device`给出,
如果:attr:`device`为`None`(默认)。
.. note::
查看 :ref:`cuda-memory-management` 了解更多关于 GPU 内存管理的详细信息
管理。
"""
返回 memory_stats(device=device).get("reserved_bytes.all.current", 0)
[文档]def max_memory_reserved(device: Union[Device, int] = None) -> int:
r"""返回给定设备由缓存分配器管理的最大 GPU 内存(以字节为单位)。
默认情况下,这返回程序开始以来的峰值缓存内存。
可以使用 :func:`~torch.cuda.reset_peak_memory_stats` 来重置
跟踪此指标的开始点。例如,这两个函数
可以测量训练循环中每次迭代的峰值缓存内存量。
循环。
参数:
设备(torch.device 或 int,可选):选定的设备。返回
当前设备的统计信息,由:func:`~torch.cuda.current_device`给出,
如果:attr:`device`为`None`(默认)。
.. note::
查看 :ref:`cuda-memory-management` 了解更多关于 GPU 内存管理的详细信息
管理。
"""
返回 memory_stats(device=device).get("reserved_bytes.all.peak", 0)
[文档]@已弃用(
`torch.cuda.memory_cached` 已更名为 `torch.cuda.memory_reserved`
category=未来警告,
)
def memory_cached(device: Union[Device, int] = None) -> int:
已弃用;请参阅 :func:`~torch.cuda.memory_reserved`。
return memory_reserved(device=device)
[文档]@deprecated(
"torch.cuda.max_memory_cached 已更名为 torch.cuda.max_memory_reserved"
category=FutureWarning
)
def max_memory_cached(device: Union[Device, int] = None) -> int:
已弃用;请参阅 :func:`~torch.cuda.max_memory_reserved`。
返回指定设备的最大内存保留量
[文档]def memory_snapshot():
返回所有设备上 CUDA 内存分配器状态的快照。
解释此函数的输出需要熟悉内存分配器内部机制
更多关于 GPU 内存管理的详细信息,请参阅 :ref:`cuda-memory-management`
.. 注意::
请参阅 :ref:`cuda-memory-management` 了解更多详情
管理学。
"""
返回 `torch._C._cuda_memorySnapshot()` 的 `"segments"`。
[文档]def
内存摘要(
设备:
联合[
设备, int] =
无,
缩略语:
布尔值 =
错误) -> str:
r返回给定设备的当前内存分配器统计信息的可读打印输出。
这可以在训练期间定期显示,或者在处理内存不足异常时。
处理内存不足异常。
参数:
设备(torch.device 或 int,可选):选定的设备。返回当前设备打印信息,由 :func:`~torch.cuda.current_device` 提供,
当前设备打印信息,由 :func:`~torch.cuda.current_device` 提供,
如果 :attr:`device` 为 ``None``(默认)。
简略(bool,可选):是否返回简略摘要
(默认:False)。
.. 注意::
查看 :ref:`cuda-memory-management` 以获取更多关于 GPU 内存管理的详细信息。
内存管理。
"沉浸式翻译"
设备 =
获取设备索引(
设备,
可选的=
是)
统计 =
内存统计(
设备=
设备)
def 格式大小(
大小,
前缀_sz):
前缀 = ["B ", "KiB", "MiB", "GiB", "TiB", "PiB"]
前缀 =
前缀[0]
for 新前缀
在
前缀[1
]
如果
前缀缩写 < 768 * 1024:
断开
前缀 =
新前缀
sz //= 1024
前缀缩写 /= 1024
返回 f"{
大小:6d} {
前缀}"
def 格式计数(
计数,
偏好计数):
前缀 = [
输入文本为空,请提供需要翻译的文本, "K", "M"]
前缀 =
前缀[0]
for 新前缀
在
前缀[1
]
如果
偏计数 < 750 * 1000:
断开
前缀 =
新前缀
计数 //= 1000
偏计数 /= 1000
返回 f"{
计数:
7 天} {
前缀} "
显示的指标 = [
(分配的字节,
分配的内存,
格式大小),
("活跃字节数",
"活动内存",
格式大小),
("请求字节数",
"请求的内存",
格式大小),
("预留字节数",
"GPU 预留内存",
格式大小),
(无效分割字节数,
不可发布内存,
格式大小),
(分配,
分配项,
格式计数),
(活动,
"活跃分配",
格式计数),
("段",
"GPU 预留段",
格式计数),
("无效分割",
"不可发布分配",
格式计数),
]
行 =
输入文本为空,请提供需要翻译的文本
行.append("=" * 75)
行.append(" {_:16}
PyTorch CUDA 内存摘要,设备 ID
{设备:<17d>} ")
行.append(
"—" * 75)
行.append(
" {_:9}CUDA OOMs:
{num_ooms:<12d>} | {_:6}
cudaMalloc 重试:{num_alloc_retries:<8d} "
)
行.append("=" * 75)
行.append(
" 指标 | 当前使用 | 峰值使用 | 总分配 | 总释放 "
)
for metric_key, 指标名称,
格式化器
在
要显示的指标:
行.append(
"—" * 75)
子指标 =
[
所有,
指标名称)]
如果
不是
缩略语:
子指标.append((
"大池",
" 来自大池"))
子指标.append((
小池,
来自小池))
当前偏值,
顶点优先值,
分配优先值,
释放优先值 = (
无,
无,
无,
无,
)
for 子度量键,
子度量名称
在
子指标:
前缀 =
指标键 + "." +
子度量键 + "."
当前 =
统计[
前缀 +
"当前"]
峰值 =
统计[
前缀 +
"峰值"]
分配的 =
统计[
前缀 +
"分配的"]
释放的 =
统计[
前缀 +
"释放的"]
如果
当前偏值
是
无:
当前偏值 =
当前
顶峰优先值 =
峰值
分配优先值 =
分配的
释放优先值 =
释放的
行.append(
f" {子度量名称:<21} | {
格式化器(
当前,
当前偏值)} | {
格式化器(
山峰,
顶点优先值)}
|
(此处文本为空,无需翻译)
f"{格式化器(
分配,
分配优先值)} | {
格式化器(
释放,
自由偏好值)} ",
)
显示的指标 = [
(超大分配,
超大分配,
格式计数),
(超大段,
超大 GPU 段,
格式计数),
]
for metric_key, 指标名称,
格式化器
在
要显示的指标:
行.append(
"—" * 75)
前缀 =
指标键 + "."
当前 =
统计[
前缀 +
"当前"]
峰值 =
统计[
前缀 +
"峰值"]
分配的 =
统计[
前缀 +
"分配的"]
释放的 =
统计[
前缀 +
"释放的"]
行.append(
f" {指标名称:<21} | {
格式化器(
当前,
当前)} | {
格式化器(
山峰,
山峰)}
|
(此处文本为空,无需翻译)
f"{格式化器(
分配,
分配)} | {
格式化器(
释放,
释放)} ",
)
行.append("=" * 75)
fmt_dict = {“_”:
输入文本翻译为简体中文为:"",
"设备":
设备}
for k, v 在
统计.
项目():
fmt_dict[k.替换(
“。”,
破折号)] = v
返回
竖线 + "|
输入文本翻译为简体中文为:\n
"|.
连接(
行).
格式(**fmt_dict) + "|
输入文本翻译为简体中文为:\n"
[文档]def list_gpu_processes(
设备:
联合[
设备, int] =
无) -> str:
r返回给定设备上运行进程及其 GPU 内存使用的可读打印输出。
这可以在训练期间定期显示,或者在处理内存不足异常时。
处理内存不足异常。
参数:
设备(torch.device 或 int,可选):选定的设备。返回当前设备打印信息,由 :func:`~torch.cuda.current_device` 提供,
当前设备打印信息,由 :func:`~torch.cuda.current_device` 提供,
如果 :attr:`device` 为 ``None``(默认)。
"沉浸式翻译"
如果
不是 torch.
版本.hip:
尝试:
导入 pynvml # type: ignore[import]
除了
模块未找到错误:
返回
"未找到 pynvml 模块,请安装 pynvml"
来自 pynvml
导入 NVMLError_DriverNotLoaded
尝试:
pynvml.nvmlInit()
除了 NVMLError_DriverNotLoaded:
返回
"无法加载 cuda 驱动程序,cuda 是否已启用?"
设备 =
获取 nvml 设备索引(
设备)
handle = pynvml.通过索引获取 nvml 设备句柄(
设备)
进程 = pynvml.
获取 nvml 设备正在运行的进程(
处理)
否则:
尝试:
导入 amdsmi # type: ignore[import]
除了
模块未找到错误:
返回
"未找到 amdsmi 模块,请安装 amdsmi"
尝试:
amdsmi.amdsmi 初始化()
# 类型:忽略[已定义]
除了 amdsmi.
AmdSmiException 异常:
# 类型:忽略[已定义]
返回
"无法加载 amdsmi 驱动,是否已安装 ROCm?"
设备 = _get_amdsmi_device_index(
设备)
尝试:
handle = amdsmi.amdsmi_get_processor_handles()[设备]
# 类型:忽略[已定义]
进程 = amdsmi.amdsmi_get_gpu_process_list(
处理)
# 类型:忽略[已定义]
除了 amdsmi.
AmdSmiException 异常:
# 类型:忽略[已定义]
返回
"amdsmi 无法列出其他用户的进程"
行 =
输入文本为空,请提供需要翻译的文本
行.append(f
"GPU: "{
设备}")
如果
长度(
进程) == 0:
行.append(
没有进程正在运行)
for p 在
进程:
如果
不是 torch.
版本.hip:
内存 = p.
使用的 GPU 内存 / (1024 * 1024)
进程 ID = p.
进程 ID
否则:
尝试:
proc_info = amdsmi.amdsmi_get_gpu_process_info(处理, p) # type: ignore[possibly-undefined]
除了
属性错误:
# https://github.com/ROCm/amdsmi/commit/c551c3caedbd903ba828e7fdffa5b56d475a15e7
# 是一个向后不兼容的更改,从 amdsmi 中移除了 amdsmi_get_gpu_process_info API
proc_info = p
内存 =
进程信息[
内存使用情况
]
[显存内存] / (1024 * 1024)
进程 ID =
进程信息[
"进程 ID"]
行.append(f
"进程"{
进程 ID:
>10 天}
使用{
内存:>12.3f}
MB GPU 内存)
返回 "
输入文本翻译为简体中文为:\n".
连接(
行)
[文档]def mem_get_info(device: Union[Device, int] = None) -> tuple[int, int]:
r"""返回指定设备使用 cudaMemGetInfo 获取的全局空闲和总 GPU 内存。
Args:
device (torch.device 或 int 或 str, 可选): 选择设备。返回
当前设备的统计信息,由 :func:`~torch.cuda.current_device` 提供,
如果 :attr:`device` 为 ``None``(默认)或未指定设备索引。
.. note::
更多信息请参阅 :ref:`cuda-memory-management`。
硬件内存管理的详细信息。
"""
如果设备为 None:
设备 = torch.cuda.current_device()
# optional=True 允许使用 `device = torch.device('cuda')`,但此时 device.index 为 None
device = _get_device_index(device, optional=True)
返回 torch.cuda.cudart().cudaMemGetInfo(device)
def _record_memory_history_legacy(
启用: bool,
记录上下文=
是,
跟踪分配最大条目数=1,
跟踪分配记录上下文=
错误,
设备:
联合[
设备, int] =
无,
record_context_cpp=错误,
):
_C._cuda_record_memory_history_legacy(
启用,
记录上下文,
跟踪分配最大条目数,
跟踪分配记录上下文,
记录上下文_cpp,
)
[文档]def _record_memory_history(
enabled: Literal[None, "state", "all"] = "all", *args, **kwargs
) -> None:
启用与内存相关的堆栈跟踪记录
分配,因此您可以知道任何内存块是由谁分配的
:func:`torch.cuda.memory._snapshot()`.
此外,还保留每个当前分配和释放的堆栈跟踪
这也将启用记录所有分配/释放事件的记录。
使用 :func:`torch.cuda.memory._snapshot()` 来检索此信息,
以及 `_memory_viz.py` 中的工具来可视化快照。
Python 跟踪收集速度快(每个跟踪 2us),因此您可以考虑
在生产任务中启用此功能,如果您预计将来需要调试
内存问题。
C++ 跟踪收集也非常快(约 50 纳秒/帧),对于许多典型程序来说
每个跟踪大约为 2 微秒,但可能会根据堆栈深度而变化。
Args:
enabled (Literal[None, "state", "all"], optional):
`None`,禁用记录内存历史。
`"state"`,保留当前分配内存的信息。
`"all"`,另外还要记录所有分配/释放调用历史。
默认为 "all"。
context (Literal[None, "state", "alloc", "all"], 可选):
`None`,不记录任何跟踪信息。
`"状态"`,记录当前分配内存的回溯信息。
`"alloc"`,此外还保留 alloc 调用的回溯信息。
`"all"`,此外还保留 free 调用的回溯信息。
默认为 `"all"`。
stacks (Literal["python", "all"], 可选):
`"python"`,包括 Python、TorchScript 和 inductor 调试信息中的帧
`"all"`,此外还包括 C++ 帧信息
默认为 "all"。
最大条目数(int,可选):保留最多 `max_entries`
记录历史中记录的分配/释放事件。
"""
如果 enabled 是布尔类型:
return _record_memory_history_legacy(enabled, *args, **kwargs)
else:
return _record_memory_history_impl(enabled, *args, **kwargs)
def _记录内存历史实现(
启用:
可选[str] =
所有,
上下文:
可选[str] =
所有,
栈:
字符串 =
所有,
最大条目数:
整型 =
系统模块.
最大尺寸,
设备:
联合[
设备, int] =
无,
):
_C._cuda 记录内存历史(
启用,
上下文,
栈,
最大条目数)
_记录内存历史.
__签名__ =
签名(
_记录内存历史实现)
# 类型:忽略[已定义]
[文档]def
快照(
设备:
联合[
设备, int] =
无):
在调用时保存 CUDA 内存状态的快照。
状态以字典的形式表示,其结构如下。
.. 代码块 :: python
class Snapshot(TypedDict):
segments : List[Segment]
device_traces: List[List[TraceEntry]]
class Segment(TypedDict):
# Segments 是来自 cudaMalloc 调用的内存。
# 预留内存的大小是所有 Segments 的总和。
# Segments 被缓存并重复用于未来的分配。
如果重用小于段,则段将被拆分为多个块。
如果是空的,则将段拆分为多个块。
empty_cache() 释放完全不活跃的段。
address: 整数
total_size: 整数 # 分段 cudaMalloc 的尺寸
stream: 整数
segment_type: 文字常量['small', 'large'] # 'large' (>1MB)
allocated_size: 整数 # 使用中的内存大小
active_size: 整数 # 使用中或处于 active_awaiting_free 状态的内存大小
blocks : List[Block]
class Block(TypedDict):
# 从分配器返回的内存块,或
当前缓存但未激活。
size: int
请求大小:整数 # malloc 期间请求的大小,可能小于
# 由于四舍五入导致的大小
address: 整数
state: Literal['active_allocated', # 用于张量
'active_awaiting_free', # 等待另一个流完成使用
# 然后,它将变为空闲
'无效的,] # 可供重用'
'frames: List[Frame] # 从发生分配的堆栈跟踪'
'class Frame(TypedDict):'
'filename: str'
行:整型
名称:字符串
类 TraceEntry(TypedDict):
当 `torch.cuda.memory._record_memory_history()` 被启用时,
记录每个快照将包含 TraceEntry 对象
分配器所采取的操作。
操作: Literal[
'alloc' 内存分配
'free_requested' # 请求释放内存
'free_completed' # 请求释放的内存已
'' # 可用于未来的分配调用
'segment_alloc' # 缓存分配器请求 cudaMalloc 更多内存
# 添加到其缓存中作为一个段
'segment_free' # 缓存分配器调用 cudaFree 来归还内存
# 为了 cuda 可能尝试释放内存以
# 分配更多段或因为调用了 empty_caches
内存不足,分配器抛出了 OOM 异常。'size'是
请求的字节数未成功
快照 # 分配器生成了一个内存快照
有助于关联之前拍摄的
# 拍照包含此跟踪
]
addr: int # 不适用于内存溢出
frames: List[Frame]
size: int
stream: 整数
device_free: 整数 # 仅在 OOM 时存在,表示内存
# cuda 仍然报告为空闲的内存
返回:
快照字典对象
"沉浸式翻译"
返回 _C._cuda_memorySnapshot()
[文档]def _dump_snapshot(filename="dump_snapshot.pickle"):
"""
将 `torch.memory._snapshot()` 字典的序列化版本保存到文件中。
该文件可以通过 pytorch.org/memory_viz 上的交互式快照查看器打开
Args:
文件名(str,可选):要创建的文件名。默认为"dump_snapshot.pickle"。
"""
s = _snapshot()
with open(filename, "wb") as f:
pickle.dump(s, f)
def _save_segment_usage(文件名=
output.svg,
快照=
无):
如果
快照
是
无:
快照 =
快照()
与
打开(
文件名,
w)
是 f:
f.写(
段落(
快照))
def 保存内存使用情况(
文件名=
output.svg,
快照=
无):
如果
快照
是
无:
快照 =
快照()
与
打开(
文件名,
w)
是 f:
f.写(
内存(
快照))
def 设置分配器设置(
环境: str):
返回 torch._C._cuda_cudaCachingAllocator_set_allocator_settings(
环境)
[文档]def get_allocator_backend() -> str:
返回一个描述由设置的活动分配器后端的字符串
``PYTORCH_CUDA_ALLOC_CONF``. 目前可用的后端有
``native``(PyTorch 的本地缓存分配器)和 `cudaMallocAsync`
(CUDA 的内置异步分配器)。
.. 注意::
请参阅 :ref:`cuda-memory-management` 了解选择分配器后端的详细信息。
"""
返回 torch._C._cuda_getAllocatorBackend()
类 _CUDAAllocator:
r内部 CUDA 内存分配器的包装器。
def __init__(self, 分配器: torch._C.
_cuda_CUDA 分配器):
self._分配器 =
分配器
def 分配器(self):
返回 self.
_分配器
[文档]类 CUDAPluggableAllocator(_CUDAAllocator):
r"""从.so 文件加载的 CUDA 内存分配器。"""
r"""def __init__(self, path_to_so_file: str, alloc_fn_name: str, free_fn_name: str):"""
r"""内存分配器编译在.so 文件中,并使用 ctypes 动态加载。"""
使用 :func:`torch.memory.cuda.change_current_allocator` 函数更改活动分配器。
Args:
path_to_so_file(str): 文件系统中的路径,指向包含分配器函数的 `.so` 文件
的分配器函数
alloc_fn_name(str): 执行内存分配的函数名称
在 so 文件中。签名必须是:
void* alloc_fn_name(ssize_t size, int device, cudaStream_t stream);
free_fn_name(str): 执行内存释放的函数名称
在 so 文件中。签名必须是:
void free_fn_name(void* ptr, size_t size, cudaStream_t stream);
..警告::
目前仅支持在 Unix 操作系统上
.. 注意::
有关创建和使用自定义分配器的详细信息,请参阅 :ref:`cuda-memory-management`
"""
allocator = ctypes.CDLL(path_to_so_file)
alloc_fn = ctypes.cast(getattr(allocator, alloc_fn_name), ctypes.c_void_p).value
free_fn = ctypes.cast(getattr(allocator, free_fn_name), ctypes.c_void_p).value
assert alloc_fn is not None
assert free_fn is not None
self._allocator = torch._C._cuda_customAllocator(alloc_fn, free_fn)
[文档]def change_current_allocator(allocator: _CUDAAllocator) -> None:
将当前使用的内存分配器更改为提供的分配器。
如果当前分配器已经被使用/初始化,此函数将报错。
Args:
分配器(torch.cuda.memory._CUDAAllocator):要设置为活动状态的分配器。
.. 注意::
有关创建和使用自定义分配器的详细信息,请参阅 :ref:`cuda-memory-management`。
"""
torch._C._cuda_changeCurrentAllocator(allocator.allocator())
def 获取当前分配器() -> _CUDAAllocator:
r返回当前正在使用的分配器。
.. 注意::
请参阅:ref:`cuda-memory-management`以获取有关创建和使用自定义分配器的详细信息
"沉浸式翻译"
返回 _CUDAAllocator(torch._C._cuda_getAllocator())
[文档]类 MemPoolContext(_MemPoolContext):
r"""MemPoolContext 存储当前活动池并保存之前的
池。删除时将使上一个池变为活动状态。
Args:
pool(torch.cuda.MemPool):要激活的 MemPool 对象,以便
分配路由到此池。
"""
def __init__(self, 池: _MemPool):
调用父类构造函数(pool)
[文档] @staticmethod
def active_pool() -> Optional[_MemPool]:
r"""返回活动 MemPool"""
return _MemPoolContext.active_pool()
[文档]class MemPool(_MemPool):
内存池代表缓存分配器中的内存池。当前,
这只是 CUDACachingAllocator 中维护的池对象 ID。
参数:
allocator(torch._C._cuda_CUDAAllocator, 可选): 一个
torch._C._cuda_CUDAAllocator 对象,可用于
定义如何在池中分配内存。如果:attr:`分配器`
是 `None`(默认),内存分配遵循默认/
当前 CUDACachingAllocator 的配置。
"""
"""
def __init__(self, allocator: Optional[_cuda_CUDAAllocator] = None):
super().__init__(allocator, True)
@property
def id(self) -> tuple[int, int]:
r"""返回此池的 ID,以两个整数的元组形式。"""
return super().id
@property
def allocator(self) -> Optional[_cuda_CUDAAllocator]:
r"""返回 MemPool 路由分配的分配器。"""
return super().allocator
[文档] def use_count(self) -> int:
返回此池的引用计数。
返回 super().use_count() 的值
[文档] def 快照(self):
r"""返回所有设备上 CUDA 内存分配器池状态的快照。
理解此函数的输出需要熟悉相关内容。
Interpreting the output of this function requires familiarity with the
内存分配器内部机制。
.. 注意::
更多关于 GPU 内存管理的详细信息,请参阅 :ref:`cuda-memory-management`。
内存管理。
"""
尝试:
ctx = MemPoolContext(self)
snapshot = torch.cuda.memory_snapshot()
finally:
删除 ctx
返回快照
[文档]@contextlib.contextmanager
def use_mem_pool(pool: MemPool, device: Union[Device, int] = None):
"""一个上下文管理器,用于将分配路由到指定的池。
Args:
pool(torch.cuda.MemPool): 要激活的 MemPool 对象,以便
将分配路由到此池。
设备(torch.device 或 int,可选):选定的设备。使用 MemPool 在当前设备上,由 :func:`~torch.cuda.current_device` 给出,
如果 :attr:`device` 是 ``None``(默认)。
如果 :attr:`device` 是 ``None``(默认)。
"""
ctx = MemPoolContext(pool)
device_index = (
torch.cuda.current_device() if device is None else _get_device_index(device)
)
_cuda_beginAllocateToPool(device_index, pool.id)
try:
yield
finally:
_cuda_endAllocateCurrentStreamToPool(device_index, pool.id)
_cuda_releasePool(device_index, pool.id)
del ctx