oneflow icon indicating copy to clipboard operation
oneflow copied to clipboard

flow.cat 对其进行切片时内存泄漏

Open shaoshitong opened this issue 2 years ago • 7 comments

这是一个非常神奇的问题,因为这个问题困扰了我2天,出现这个问题的原因是这次数据集的准备和以往不同,由于拼接nerf光线的原因,导致必须采用flow.cat进行数据集的拼接。

首先是oneflow的代码:

import oneflow as flow
import oneflow.nn as nn

A=[]
for i in range(160000):
    A.append(flow.ones(100,11)*2)
    print(i)

A = flow.cat(A,0)
print(A.shape)

A = flow.split(A,1,0)
"""
oneflow.Size([16000000, 11])
"""

Notes: 这里面并没有输出Process finished with exit code 0,这是由于发生了内存泄漏,最后电脑卡死死机。在调用flow.cat算子时并不会出错,但一旦切片就会发生内存泄漏,而且必须是大规模切片。事实上,在nerf复现中我是每一次getitem时通过A[idx]来调用一次,最后内存不断增长直到死机。

pytorch代码:


import torch

A=[]
for i in range(160000):
    A.append(torch.ones(100,11)*2)
A = torch.cat(A,0)
print(A.shape)
A = torch.split(A,1,0)
"""
torch.Size([16000000, 11])

Process finished with exit code 0
"""

我的电脑的cpu是:

架构:                           x86_64
CPU 运行模式:                   32-bit, 64-bit
字节序:                         Little Endian
Address sizes:                   39 bits physical, 48 bits virtual
CPU:                             16
在线 CPU 列表:                  0-15
每个核的线程数:                 2
每个座的核数:                   8
座:                             1
NUMA 节点:                      1
厂商 ID:                        GenuineIntel
CPU 系列:                       6
型号:                           167
型号名称:                       11th Gen Intel(R) Core(TM) i7-11700KF @ 3.60GHz
步进:                           1
CPU MHz:                        3600.000
CPU 最大 MHz:                   5000.0000
CPU 最小 MHz:                   800.0000
BogoMIPS:                       7200.00
虚拟化:                         VT-x
L1d 缓存:                       384 KiB
L1i 缓存:                       256 KiB
L2 缓存:                        4 MiB
L3 缓存:                        16 MiB
NUMA 节点0 CPU:                 0-15
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:        Mitigation; Enhanced IBRS, IBPB conditional, RSB filling
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
标记:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch
                                 _perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid s
                                 se4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced tpr_
                                 shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap avx512ifma clflushopt intel_pt avx512cd
                                  sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp hwp_pkg_req avx512vbmi umip pku ospke avx512_vbmi2 
                                 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid fsrm md_clear flush_l1d arch_capabilities

一旦运行oneflow代码,终端top命令变化:

1

2022-08-18 21-57-39 的屏幕截图

2

2022-08-18 21-57-55 的屏幕截图

3

2022-08-18 21-58-00 的屏幕截图

4

2022-08-18 21-58-10 的屏幕截图

由于再截图我电脑就要死机了,所以我结束了程序的运行

shaoshitong avatar Aug 18 '22 13:08 shaoshitong

好像是CPU的内存泄漏,binbin可以看一下是不是缓存占用了太多的cpu内存了 @clackhan

hjchen2 avatar Aug 18 '22 14:08 hjchen2

看起来就是这个PR (https://github.com/Oneflow-Inc/oneflow/pull/8662 )将tensor meta symbol化之后导致的,我这边跑了一下,这个PR之前的commit (60827b0500c808ae4c08f6aa958e99aa8c37df77) 还是正常的2.8G内存,在这个PR合并之后commit( 146288eea079468e05dfd793d36e8e3452c3bf18 )内存涨到了12G+。

我这里测试的是这个代码:

import oneflow as flow
import oneflow.nn as nn

A = flow.Tensor(16000000, 11, device="cuda")
A.numpy()
print(A.shape)

for i in range(A.shape[0]):
  A[i]

hjchen2 avatar Aug 19 '22 03:08 hjchen2

是不是一个很长的循环里的item 的key不一样,导致每个item 都被缓存了

yuanms2 avatar Aug 19 '22 04:08 yuanms2

是不是一个很长的循环里的item 的key不一样,导致每个item 都被缓存了

是的,我那段代码里的那个for循环里每次item不同导致view出来的Tensor的TensorMeta offset不一样,symbol化之后就必须要把它们都缓存起来。

另外原始的这段代码A = flow.split(A,1,0)即使没有symbol化tensor meta,也一样会因为split出来的大量的tensor没有被释放而占用非常大的内存。我对比了一下PyTorch,原始的代码在torch下占用了大约10G的内存,我们会占用20G,可能是我们的Tensor和TensorMeta数据结构上会多占一倍的存储。

hjchen2 avatar Aug 19 '22 04:08 hjchen2

目前有什么办法避免这个问题嘛,或者有flow.cat的替代形式

shaoshitong avatar Aug 20 '22 13:08 shaoshitong

目前有什么办法避免这个问题嘛,或者有flow.cat的替代形式

可以先禁用view(export ONEFLOW_DISABLE_VIEW=1),同时把flow.split改成for循环的方式,每次处理一个item。

for i in range(A.shape[0]):
    process A[i]

不过需要注意的是,禁用view可能会造成某些tensor setitem操作不能正确执行。

hjchen2 avatar Aug 21 '22 02:08 hjchen2

目前有什么办法避免这个问题嘛,或者有flow.cat的替代形式

可以先禁用view(export ONEFLOW_DISABLE_VIEW=1),同时把flow.split改成for循环的方式,每次处理一个item。

for i in range(A.shape[0]):
    process A[i]

不过需要注意的是,禁用view可能会造成某些tensor setitem操作不能正确执行。

好的非常感谢 我去试试

shaoshitong avatar Aug 21 '22 03:08 shaoshitong