首页 / 资讯中心 / 文章详情

cuDF libcudf 内存资源管理(Memory Resource Management)API 详解:设备内存、临时资源与固定内存调优

cuDF libcudf 内存资源管理(Memory Resource Management)API 详解:设备内存、临时资源与固定内存调优 ★ FEATURED ARTICLE
数据分析数据工程机器学习【免费下载链接】cudfcuDF - GPU DataFrame Library项目地址https://gitcode.com/gh_mirrors/cu/cudf点击查看免费下载cuDFGPU DataFrame Library的 C 核心 libcudf 提供了一组用于管理设备内存资源Device Memory Resource的公开 API允许开发者自定义内存分配策略、区分输出与临时分配并配置主机侧固定内存pinned memory的池化与拷贝阈值。本文以 libcudf 的memory_resourceDoxygen 组为骨架逐一对齐头文件声明与实现源码帮助读者掌握在 cuDF 应用中注入自定义内存资源的完整方法以及在 IO 密集场景下通过固定内存池和阈值环境变量进行性能调优的实战手段。一、memory_resource组是什么RST 文档页与 Doxygen 组的映射关系文档页 memory_resource.rst 本身只有寥寥数行Memory Resource Management .. doxygengroup:: memory_resource :members:这并非空文档而是 cuDF 使用 Sphinx Breathe 自动生成 API 文档的标准写法.. doxygengroup::指令告诉文档构建器把名为memory_resource的 Doxygen 组中所有带ingroup标记的成员函数、类、结构体自动展开渲染到该页。组的定义位于 doxygen_groups.h/** * defgroup default_stream Default Stream * defgroup memory_resource Memory Resource Management * ... */而组内的实际成员则通过addtogroup memory_resource挂接主要分布在两个头文件cpp/include/cudf/utilities/memory_resource.hpp获取/设置/重置当前设备内存资源的 API 与memory_resources类cpp/include/cudf/utilities/pinned_memory.hpp固定内存资源的配置与拷贝阈值 API。因此要理解这一文档页本质上就是理解上述头文件与 host_memory.cpp 中的实现。下文依次展开。二、设备内存资源的获取、设置与重置libcudf 的设备内存资源管理建立在 RAPIDS Memory ManagerRMM与 CUDA C 标准库的cuda::mr之上全部 API 定义在namespace cudf中。核心是三个函数族get获取当前资源、set设置当前资源、reset重置为初始资源。2.1 获取当前设备内存资源inline rmm::device_async_resource_ref get_current_device_resource_ref() { return rmm::mr::get_current_device_resource_ref(); }对应 memory_resource.hpp。该函数是对 RMM 同名 API 的一层薄封装返回当前线程可见的设备异步资源引用rmm::device_async_resource_ref。它是一个非拥有non-owning引用只描述当前分配行为由谁负责不持有资源对象的生命周期。2.2 设置当前设备内存资源inline cuda::mr::any_resourcecuda::mr::device_accessible set_current_device_resource( cuda::mr::any_resourcecuda::mr::device_accessible mr) { return rmm::mr::set_current_device_resource(std::move(mr)); }对应 memory_resource.hpp。参数接受任何可构造为cuda::mr::any_resourcecuda::mr::device_accessible的资源对象如 RMM 的pool_memory_resource、cuda_async_memory_resource等返回值是持有旧资源的any_resource——调用方应当保存它以便在作用域结束时恢复之前的资源// 示例临时切换资源并恢复 auto old cudf::set_current_device_resource(my_pool_mr); // ... 执行需要该资源的 cuDF 操作 ... cudf::set_current_device_resource(std::move(old)); // 恢复与之配套的还有一个已废弃版本set_current_device_resource_ref(rmm::device_async_resource_ref)memory_resource.hpp它接收非拥有的资源引用。源码中明确标注[[deprecated(Use set_current_device_resource instead.)]]原因是引用指向的对象必须比资源的最后一次使用存活更久否则行为未定义生命周期管理极易出错。新代码一律使用返回拥有型any_resource的set_current_device_resource。2.3 重置当前设备内存资源inline cuda::mr::any_resourcecuda::mr::device_accessible reset_current_device_resource() { return rmm::mr::reset_current_device_resource(); }对应 memory_resource.hpp将当前资源恢复为进程初始化时的初始资源同样返回持有旧资源的any_resource。同样存在一个已废弃的reset_current_device_resource_ref()版本memory_resource.hpp语义一致仅调用形式不同。三、memory_resources类输出资源与临时资源分离除全局当前资源外libcudf 还引入了memory_resources类memory_resource.hpp用于在单次 cuDF 操作内部区分两类分配成员用途说明get_output_mr()输出资源分配返回给调用方的内存即操作结果get_temporary_mr()临时资源分配操作过程中的中间内存在操作返回前即被释放这种区分带来的收益很直接可以把结果内存与临时内存路由到不同的资源策略——例如输出走稳定的池化资源以控制碎片临时内存走更激进的回收策略。该类提供两个构造函数均为模板、接受满足std::constructible_fromrmm::device_async_resource_ref, ...约束的类型// 1) 仅指定输出资源临时资源自动捕获当前设备资源 memory_resources(Resource output_mr) : _output_mr{...}, _temporary_mr{cudf::get_current_device_resource_ref()} {} // 2) 显式指定输出资源与临时资源不再查询当前设备资源 memory_resources(OutputResource output_mr, TemporaryResource temporary_mr) : _output_mr{...}, _temporary_mr{...} {}第一个构造函数是有意隐式的源码注释This constructor is intentionally implicit因此现有的资源对象或资源引用可以直接传给接受memory_resources参数的 API无需显式构造。源码注释还给出了一条重要的生命周期约束memory_resource.hppIf allocations are made from a resource ref, callers must construct an owning resource from the resource ref, keep that owning resource alive for the allocations lifetime, and use it for deallocation.即若分配经由资源引用完成调用方必须从该引用构造一个拥有型资源、保证其在分配存活期内不析构并用它完成释放。四、固定内存Pinned Memory资源管理设备与主机之间的数据传输如 IO 读取、cudaMemcpyAsync通常需要固定内存page-locked memory以获得更高的拷贝带宽与异步能力。libcudf 在 pinned_memory.hpp 中提供了完整的固定内存资源管理 API实现在 host_memory.cpp。4.1 获取与设置固定内存资源rmm::host_device_async_resource_ref set_pinned_memory_resource( rmm::host_device_async_resource_ref mr); rmm::host_device_async_resource_ref get_pinned_memory_resource();对应 pinned_memory.hpp。set_pinned_memory_resource返回之前正在使用的资源实现中通过互斥锁保护替换过程host_memory.cpp。4.2 配置默认固定内存池struct pinned_mr_options { std::optionalsize_t pool_size; // 池大小未设置时使用默认池大小 }; bool config_default_pinned_memory_resource(pinned_mr_options const opts);对应 pinned_memory.hpp。该函数只能配置尚未配置过的默认固定内存资源若资源已配置则返回false成功配置返回true由 host_memory.cpp 中的make_host_mr通过did_configure标志判定。默认固定内存池的构造逻辑在make_default_pinned_mrhost_memory.cpp其默认参数规则可依据源码复现参数默认计算方式环境变量覆盖初始池大小min(设备总内存 / 200, 64MB)即设备内存的 0.5%上限 64 MBLIBCUDF_PINNED_POOL_SIZE最大池大小初始池大小 * 16LIBCUDF_PINNED_POOL_MAX_SIZE池大小会被向上对齐到 RMM 的CUDA_ALLOCATION_ALIGNMENT256 字节倍数host_memory.cpp。4.3 池耗尽时的回退机制默认固定内存资源实际是pinned_pool_with_fallback_memory_resourcehost_memory.cpp其行为值得注意正常路径优先从 RMMpool_memory_resource池中分配回退路径当池被耗尽pool_-allocate抛出异常时直接回退到上游pinned_host_memory_resource分配新的固定内存并通过一个带共享锁的unordered_set记录这些回退分配fallback_-allocations以便释放时正确路由——回退分配归还给上游池内分配归还给池特殊情形若max_pool_size_ 0则完全不使用池所有分配直接走上游。这一设计保证了池大小配置过小或分配需求突发时程序不会因池耗尽而失败只会退化为逐次分配源码日志Pinned pool exhausted, falling back to new pinned allocation for %zu bytes见 host_memory.cpp。五、两个关键阈值内核拷贝与主机分配策略pinned_memory.hpp 还提供两组阈值 API用于精细控制主机内存的使用策略实现同样位于 host_memory.cpp5.1 内核固定拷贝阈值void set_kernel_pinned_copy_threshold(size_t threshold); size_t get_kernel_pinned_copy_threshold();对应 pinned_memory.hpp。语义源码注释拷贝小于该阈值字节时使用内核kernel执行固定内存拷贝拷贝大于等于该阈值时调用 CUDA 运行时 APIcudaMemcpyAsync或cudaMemcpyBatchAsync。其底层存储为原子变量默认值由环境变量LIBCUDF_KERNEL_PINNED_COPY_THRESHOLD决定未设置时默认0host_memory.cpp此时所有固定内存拷贝都走cudaMemcpyAsync。5.2 主机内存按固定内存分配的阈值void set_allocate_host_as_pinned_threshold(size_t threshold); size_t get_allocate_host_as_pinned_threshold();对应 pinned_memory.hpp。语义分配大小小于等于该阈值字节时主机内存按固定内存分配分配大小大于该阈值时按可分页内存pageable分配。同样由原子变量存储默认值来自环境变量LIBCUDF_ALLOCATE_HOST_AS_PINNED_THRESHOLD未设置时默认0host_memory.cpp即默认所有主机分配都使用可分页内存。5.3 环境变量速查表综合 host_memory.cpp 中的实现四个可影响 libcudf 内存行为的常用环境变量如下环境变量默认值作用LIBCUDF_PINNED_POOL_SIZE设备内存 0.5%上限 64MB默认固定内存池初始大小LIBCUDF_PINNED_POOL_MAX_SIZE初始池 × 16默认固定内存池最大大小LIBCUDF_KERNEL_PINNED_COPY_THRESHOLD0全部走cudaMemcpyAsync小于该字节数用内核拷贝否则用 CUDA 运行时 APILIBCUDF_ALLOCATE_HOST_AS_PINNED_THRESHOLD0全部用可分页内存小于等于该字节数按固定内存分配否则用可分页内存这些阈值均可在运行时通过对应 setter 函数动态调整适合在应用启动阶段根据数据规模与硬件特性进行探测式调优。六、Python 侧的集成pylibcudf 如何消费当前资源libcudf 的内存资源管理不仅限于 C 层Python 端pylibcudf也直接复用了当前设备资源这一概念。以 utils.pyx 为例cdef DeviceMemoryResource _get_memory_resource(DeviceMemoryResource mr None): if mr is None: return get_current_device_resource() return mrpylibcudf 的各类 API如 binaryop.pyx 中的mr _get_memory_resource(mr)在调用方未显式传入DeviceMemoryResource时自动回落到当前设备资源——即 C 侧cudf::get_current_device_resource_ref()所对应的 RMM 当前资源。因此在 Python 应用中通过 RMM 设置当前设备资源例如配置池化内存即可透明地影响后续所有 pylibcudf/libcudf 操作的分配行为无需逐调用点修改。此外cuDF Python 包内部对 RMM 资源栈有更细粒度的管理可参考 spill_manager.py 中的get_rmm_memory_resource_stack用于向上回溯资源上游链见 test_spilling.py 对应的单元测试。七、实践建议与注意事项综合上文源码证据在实际项目中应用 libcudf 内存资源管理时建议遵循以下几点优先使用拥有型 API始终使用set_current_device_resource/reset_current_device_resource避免已废弃的*_ref版本带来的生命周期悬垂风险保存并妥善恢复返回值中的旧资源。区分输出与临时资源对于高频、结果可复用的操作可借助memory_resources类把输出分配路由到池化资源减少分配次数与碎片。固定内存池按需配置IO 密集场景Parquet/ORC/CSV 读取、Kafka 等受益于固定内存池可通过config_default_pinned_memory_resource(pinned_mr_options{pool_size})或LIBCUDF_PINNED_POOL_SIZE环境变量设置注意该配置仅在资源尚未初始化时生效返回false表示已被占用。阈值调优以实测为准LIBCUDF_KERNEL_PINNED_COPY_THRESHOLD与LIBCUDF_ALLOCATE_HOST_AS_PINNED_THRESHOLD的默认值都是 0即走 CUDA 运行时 API、主机分配默认可分页是否调高需要结合具体工作负载的拷贝大小分布进行基准测试避免编造最优值。八、延伸阅读文档入口页docs/cudf/source/libcudf/api_docs/memory_resource.rstDoxygen 组定义cpp/include/doxygen_groups.h设备资源 API 声明cpp/include/cudf/utilities/memory_resource.hpp固定内存 API 声明cpp/include/cudf/utilities/pinned_memory.hpp固定内存池与阈值实现cpp/src/utilities/host_memory.cppPython 侧资源回落逻辑python/pylibcudf/pylibcudf/utils.pyxPython 侧资源栈管理python/cudf/cudf/core/buffer/spill_manager.py赞分享数据分析数据工程机器学习【免费下载链接】cudfcuDF - GPU DataFrame Library项目地址https://gitcode.com/gh_mirrors/cu/cudf点击查看免费下载相关推荐multipleWindow3dScene内存管理与资源优化multipleWindow3dScene内存管理与资源优化 引言多窗口3D场景的内存挑战 在现代Web应用中多窗口3D场景同步是一个极具挑战性的技术难题。前端3D渲染图形学monolith性能调优内存与CPU资源管理monolith性能调优内存与CPU资源管理 在使用monolith单文件网页保存工具处理大型网页或批量任务时内存占用过高和CPU使用率飙升是常见问题。CLI网页爬虫从任何语言控制ad编辑器9p协议与ad.sh脚本库实战教程从任何语言控制ad编辑器9p协议与ad.sh脚本库实战教程 前言为什么你需要学会控制ad编辑器 adan adaptable text editor是上一篇Power BI主题模板库10分钟打造专业级数据报表下一篇如何使用PyCaret与Elasticsearch存储ML预测结果完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站