快捷键

torch.cuda.memory 的源代码

# 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

© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

查看 PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源,获取您的疑问解答

查看资源