Created by: wanghuancoder
PR types
Performance optimization
PR changes
Others
Describe
一、背景
ERNIE DOC模型优化中,发现Fetch性能占比很高,去掉Fetch性能提升明显。 通过分析发现,Fetch性能损耗主要有两部分: 1)Fetch Var的数据经过多次深拷贝导致; 深拷贝分析: - Executor&CPU: 1)原始数据->FetchVar; 2)TensorToPyArray错误使用pybind带来一次深拷贝;3)as_numpy中使用np.array()带来一次深拷贝; - Executor&GPU: 与Executor&CPU相同; - PE&CPU: 1)多Place TensorMerge;2)TensorToPyArray错误使用pybind带来一次深拷贝;3)as_numpy中使用np.array()带来一次深拷贝; - PE&GPU: 1)原始数据->FetchTensors;2)多Place TensorMerge;3)TensorToPyArray错误使用pybind带来一次深拷贝;4)as_numpy中使用np.array()带来一次深拷贝; - 动态图: 只有一次深拷贝,是合理的。 2)Fetch阻塞等待所依赖的GPU kernel执行完成,造成GPU浪费;
在PR26447中,已经优化掉了Tensor转numpy带来的两次深拷贝。
本PR目标:1)优化多Place TensorMerge的深拷贝;2)优化Fetch的GPU调度策略;
二、GPU调度不合理分析
timeline图如下:
不合理处在于:
1)使用cudaStreamSynchronize等待,影响了其它kernel的拉起;
2)Memcpy没有使用单独Stream,占用了主Stream的计算;
3)MemcpyAsync使用错误,在GPU->CPU情况下,MemcpyAsync=MemcpySync
三、GPU调度修改方案
1)该用RecordEvent/WaitEvent等待方式;
2)使用单独的Stream进行内存拷贝;
3)目标Place由CPUPlace改为CUDAPinnedPlace;
修改后timeline效果如下:
1)CPU与GPU异步执行;
2)CPU堵塞时间大幅缩短,且允许其它线程并行拉起kernel;
3)使用单独Stream执行;
4)GPU主Stream kernel几乎无缝衔接;
四、TensorMerge的优化方案
旧的FetchOpHandle中,为了完成Merge操作,需要先等待GPU数据拷贝到CPU后,再将多个Tensor的数据拷贝到一个Tensor中去。 新的方案:提前分配目标Tensor内存,并将内存切分成place对应的N个Slice,直接将各个Place上的数据拷贝到对应的Slice中去。 Merge算法,与原有逻辑严格保持一致。