mmap 行为优化 - #17
Conversation
|
torch2.7 后新增了 用形如下的样例进行测试, SHAPE = (1024, 1024, 1024)
DEVICE = "cuda:2"
# gds
src = torch.randn(*SHAPE, device=DEVICE)
file = torch.cuda.gds.GdsFile("temp1.pt", os.O_CREAT | os.O_RDWR)
file.save_storage(src.untyped_storage(), offset=0)
num_bytes = src.numel() * src.element_size()
src_dtype = src.dtype
src_shape = src.shape
fo = open("temp1.pt", "rb")
mm = mmap.mmap(fo.fileno(), length=num_bytes, access=mmap.ACCESS_READ)
dest = torch.frombuffer(mm, dtype=src_dtype).reshape(src_shape)
# old
src = torch.randn(*SHAPE, device=DEVICE)
src_cpu = src.cpu()
torch.save(src_cpu, "temp2.pt")
dest = torch.load("temp2.pt", map_location="cpu", mmap=True, weights_only=False)可得到结果, 发现提升还是较大的 |
|
当前 gds 实现: 00c0028 可以看到耗时有比较明显的增加,但在降低内存峰值上同样也有较明显的提高 进一步降低峰值可能考虑使用 save_storage 与 load_storage 配套使用完全代替 offload 2 cpu, 即 disk_offload 完全绕开 CPU, 但需要改动的内容可能较大, 进一步测试看需求再做考虑. |
8a3cd7d to
7878e48
Compare
|
5090 回归测试结果: 云函数:fnki5mlg84 测试版本v31 CI:https://github.com/siliconflow/cce/actions/runs/30423523771/job/90487820035
测试正常 |
596cf8e to
977bf6e
Compare
- keep mmap resources alive for shared tensor storage - use copy-on-write mappings and restrict GDS to CUDA tensors - base mmap pressure on loaded model weights - move custom-node directory dumps to debug logging
66cf2e8 to
97ecec3
Compare
主要改动
|
| for custom_node_path in node_paths: | ||
| possible_modules = os.listdir(custom_node_path) | ||
| possible_modules = sorted(os.listdir(custom_node_path)) | ||
| logging.debug("!!!possible_modules1!!!:\n" + "\n".join(possible_modules)) |
There was a problem hiding this comment.
这个是不是临时调试日志,可以删除或者改为正常文案了?
| t_type = t.dtype | ||
| t_shape = t.shape | ||
| num = t.numel() * t.element_size() | ||
| del file |
There was a problem hiding this comment.
这里改成 file.close() 更好吧(顺便注意下和上面那个 file.save_storage(t.untyped_storage(), offset=0) 做下合并。
| del file | |
| try: | |
| file.save_storage(t.untyped_storage(), offset=0) | |
| finally: | |
| file.close() |
There was a problem hiding this comment.
虽然名字叫做 file, 但实际 torch.cuda.gds.GdsFile 为一个无 close() 方法的 class, 对应句柄的关闭有在其析构函数中处理. 因此我将变量 file 改为 gds, 但仍保留显示的 del 操作
class GdsFile:
...
def __del__(self) -> None:
if self.handle is not None:
self.deregister_handle()
os.close(self.fd)
使用方法与 #13 保持一致,设置环境变量MMAP_MEM_THRESHOLD_GB=x表示若 cpu mem 小于 xG 时,遇到 offload 会 offload 到 mmap考虑到 gds 对性能存在影响,额外增加了环境变量
USE_GDS_OFFLOAD用于控制行为:MMAP_MEM_THRESHOLD_GB=x, USE_GDS_OFFLOAD=False时行为同 offload to mmap #13 一致,表示若 cpu mem 小于 xG 时,遇到 offload 使用 torch.save 卸载到磁盘再 torch.load(mmap=True) 读回 cpuMMAP_MEM_THRESHOLD_GB=x, USE_GDS_OFFLOAD=True时表示若 cpu mem 小于 xG 时,遇到 offload 使用 gds 卸载到磁盘再 mmap 读回 cpuUSE_GDS_OFFLOAD默认为 Falsemmap 当前存在一些问题
OOM 时将
memory_to_free置为 1e30, 若模型model_loaded_size > available_memory - mmap_mem_threshold, 则会始终走 partially_unload; 应该是希望 memory_to_free 够大时 partially_unload 也可以将模型完整 offload, 但实际仅能卸载较小一部分内容, 导致显存一直在被占用, 再次请求仍旧发生 OOM 然后重复上述逻辑.https://github.com/siliconflow/cce/issues/176#issuecomment-4249756325
目前是注意到 to_mmap 过程中有个 .cpu 会存在较明显的内存峰值
https://github.com/siliconflow/ComfyGridRuntime/issues/181#issuecomment-4220391298
API Node PR Checklist
Scope
Pricing & Billing
If Need pricing update:
QA
Comms