Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【PaddlePaddle Hackathon 5 No.48】ContiguousKernel、StridedCopyKernel算子CPU、GPU性能优化 -part #57835

Merged
merged 10 commits into from
Oct 16, 2023

Conversation

WintersMontagne10335
Copy link
Contributor

@WintersMontagne10335 WintersMontagne10335 commented Sep 28, 2023

PR types

Performance optimization

PR changes

OPs

Description

目前ContiguousKernel、StridedCopyKernel两个 kernel 都是通过 numel index 计算数据偏移地址,需要一个 for 循环做计算,计算偏移地址效率低,导致 kernel 性能差。

  • 开发环境:
  1. 设备:Tesla V100
  2. 环境:CUDA 10.2
  • 优化方法
  1. 依靠线程配置信息,减少除法与取余操作。目前Paddle通过 numel index 计算数据偏移地址,会有大量除法与取余操作。可以利用线程配置中Grid与Block的6个参数(受硬件支持),减少除法与取余操作
  2. 去除依赖。由于kMaxRank为9,对于rank大于6或者不满足block参数配置要求(block.x * block.y * block.z <= 1024 && block.z <= 64)的情况下,还是需要计算部分偏移地址。目前Paddle中的实现存在依赖关系。下一个循环只能等本循环的index_tmp计算完毕后才能进行,但其实各个循环间的计算从逻辑实现上来说是独立的,完全可以并行计算。本方法,与上一个优化方法搭配,可以大幅缩短运行时间
  3. 预处理访存偏移量(可选优化点)。借鉴MegEngine卷积算子预处理访存偏移量的优化思路
  4. 改变访存(可选优化点)。《CUDA_C优化详解》中提到,“应尽可能避免非单位跨度的全局内存访问”,对于stride比较特殊的情况,可以优化访存
  • 测试数据
  1. 针对不同的input_shape,会使用不同的function,测试数据分开展示,会清晰一点。测试数据中fp32基于real实现,fp16基于slice实现。
  2. case zero:input_shape后三维(如 [ 1, 1, 1, 1000, 100, 10]的后三维c,b,a分别为1000,100,10),满足abc<=1024&&c<=64。完成优化后,Paddle与优化前的Paddle的前向推理性能对比效果如下:
Case No. device input_type input_shape original Paddle Perf(ms) current Paddle Perf(ms) faster than the original one
1 Tesla V100 float32 [ 1000000, 10, 10, 10] 28.013 10.893 157.2%
2 Tesla V100 float32 [ 1000, 1000, 10, 10, 10] 32.270 11.645 177.1%
3 Tesla V100 float32 [ 10000, 100, 10, 10, 10] 32.274 11.651 177.0%
4 Tesla V100 float32 [ 100, 10000, 10, 10, 10] 32.279 11.634 177.5%
5 Tesla V100 float32 [ 100, 100, 100, 10, 10, 10] 41.165 13.273 210.1%
6 Tesla V100 float32 [ 10000, 10, 10, 10, 10, 10] 41.160 13.306 209.3%
7 Tesla V100 float32 [ 10, 10000, 10, 10, 10, 10] 41.175 13.294 209.7%
8 Tesla V100 float32 [ 10, 10, 10000, 10, 10, 10] 41.173 13.223 211.4%
9 Tesla V100 float16 [ 1000000, 10, 10, 10] 14.354 4.2553 237.3%
10 Tesla V100 float16 [ 1000, 1000, 10, 10, 10] 16.401 5.2628 211.6%
11 Tesla V100 float16 [ 10000, 100, 10, 10, 10] 16.137 5.2022 210.2%
12 Tesla V100 float16 [ 100, 10000, 10, 10, 10] 16.322 5.1996 213.9%
13 Tesla V100 float16 [ 100, 100, 100, 10, 10, 10] 19.790 6.0221 228.6%
14 Tesla V100 float16 [ 10000, 10, 10, 10, 10, 10] 13.457 4.1210 226.5%
15 Tesla V100 float16 [ 10, 10000, 10, 10, 10, 10] 13.432 4.0956 228.0%
16 Tesla V100 float16 [ 10, 10, 10000, 10, 10, 10] 13.377 4.1144 225.1%
  1. case one:其它情况。这里rank>6的fp16数据不知道基于什么实现。完成优化后,Paddle与优化前的Paddle的前向推理性能对比效果如下:
Case No. device input_type input_shape original Paddle Perf(ms) current Paddle Perf(ms) faster than the original one
1 Tesla V100 float32 [10, 10, 10, 10000, 10, 10] 41.175 31.248 31.8%
2 Tesla V100 float32 [10, 100, 10, 10, 10, 1000] 41.173 31.266 31.7%
3 Tesla V100 float32 [100, 10, 100, 10, 10, 10, 10] 45.399 36.047 25.9%
4 Tesla V100 float32 [1000, 10, 10, 10, 10, 10, 10] 45.404 36.020 26.1%
5 Tesla V100 float32 [10, 10, 10, 10, 100, 100, 10] 45.405 35.299 28.6%
6 Tesla V100 float32 [10, 10, 10, 10, 10, 10, 1000] 45.385 35.646 27.3%
7 Tesla V100 float32 [100, 10, 10, 10, 10, 10, 10, 10] 54.382 45.532 19.4%
8 Tesla V100 float32 [10, 10, 100, 10, 10, 10, 10, 10] 54.377 45.476 19.6%
9 Tesla V100 float32 [10, 10, 10, 10, 100, 10, 10, 10] 54.385 45.511 19.5%
10 Tesla V100 float32 [10, 10, 10, 10, 10, 10, 100, 10] 54.379 45.534 19.4%
11 Tesla V100 float32 [10, 10, 10, 10, 10, 10, 10, 10, 10] 58.539 48.652 20.3%
12 Tesla V100 float16 [10, 10, 10, 10000, 10, 10] 13.432 10.237 31.2%
13 Tesla V100 float16 [10, 100, 10, 10, 10, 1000] 16.433 12.463 31.9%

经过优化,性能得到了较大的提升。

  • 关联PR
  1. 【PaddlePaddle Hackathon 5 No.48】StridedCopyKernel算子GPU性能优化-part1 #58033
  2. Fix bug that thread configuration parameters are out of bounds #58303
  3. 【PaddlePaddle Hackathon 5 No.48】Fix bug that thread configuration parameters are out of bounds #58307

目前,原有的case one还可以继续拆分,来加速kernel和减少极端线程配置参数情况的出现。这部分工作不难,但是比较繁琐、工作量很大。黑客松结束会全部做掉。

  • TODO
  1. c<=64&&abc<=1024&&rank>6拆分出来单独处理,成为新的case one
  2. !(c<=64&&abc<=1024)&&rank<=6拆分出来单独处理,成为新的case two
  3. case two一种新的线程配置方法,减少极端线程配置参数情况出现的概率
  4. case three一种新的线程配置方法,减少极端线程配置参数情况出现的概率

@paddle-bot
Copy link

paddle-bot bot commented Sep 28, 2023

你的PR提交成功,感谢你对开源项目的贡献!
请关注后续CI自动化测试结果,详情请参考Paddle-CI手册
Your PR has been submitted. Thanks for your contribution!
Please wait for the result of CI firstly. See Paddle CI Manual for details.

@paddle-ci-bot
Copy link

paddle-ci-bot bot commented Oct 8, 2023

Sorry to inform you that 5360925's CIs have passed for more than 7 days. To prevent PR conflicts, you need to re-run all CIs manually.

@@ -631,6 +631,8 @@ def istft(
'Abort istft because Nonzero Overlap Add (NOLA) condition failed. For more information about NOLA constraint please see `scipy.signal.check_NOLA`(https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.check_NOLA.html).'
)

print(out)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么需要改这个文件呢?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tao姐,这涉及一个很奇怪的现象。运行ctest -R test_signal -V时,out为全1的tensor。
CE2F22549E30244762ED566820AA4E88
但是我在638行加了一个print(out),out又是正常值了。
D0773A06CD7700F1BBFFA35556B4DEA8
前几天一直在尝试解决这个问题(哭),现在已经定位到大概的范围了。
最终代码不会改这个文件。

@wanghuancoder
Copy link
Contributor

wanghuancoder commented Oct 10, 2023

PR types

Performance optimization

PR changes

OPs

Description

目前ContiguousKernel、StridedCopyKernel两个 kernel 都是通过 numel index 计算数据偏移地址,需要一个 for 循环做计算,计算偏移地址效率低,导致 kernel 性能差。

  • 开发环境:
  1. 设备:Tesla V100
  2. 环境:CUDA 10.2
  • 优化方法
  1. 依靠线程配置信息,减少除法与取余操作。目前Paddle通过 numel index 计算数据偏移地址,会有大量除法与取余操作。可以利用线程配置中Grid与Block的6个参数(受硬件支持),减少除法与取余操作
  2. 去除依赖。由于kMaxRank为9,对于rank大于6或者不满足block参数配置要求(block.x * block.y * block.z <= 1024 && block.z <= 64)的情况下,还是需要计算部分偏移地址。目前Paddle中的实现存在依赖关系。下一个循环只能等本循环的index_tmp计算完毕后才能进行,但其实各个循环间的计算从逻辑实现上来说是独立的,完全可以并行计算。本方法,与上一个优化方法搭配,可以大幅缩短运行时间
  3. 预处理访存偏移量(可选优化点)。借鉴MegEngine卷积算子预处理访存偏移量的优化思路
  4. 改变访存(可选优化点)。《CUDA_C优化详解》中提到,“应尽可能避免非单位跨度的全局内存访问”,对于stride比较特殊的情况,可以优化访存

完成优化后,Paddle与优化前的Paddle的前向推理性能对比效果:

Case No. device input_type input_shape origin Paddle Perf(us) current Paddle Perf(us) diff
1 Tesla V100 float16 [ 4, 4, 4, 8, 8, 8] 4.2506 1.9681 faster than 116.0%
2 Tesla V100 float16 [ 2, 2, 2, 8, 8, 64] 4.2139 3.2855 faster than 28.3%
3 Tesla V100 float32 [ 4, 4, 4, 8, 8, 8] 4.2230 1.9842 faster than 113.3%
4 Tesla V100 float32 [ 2, 2, 2, 8, 8, 64] 4.2223 3.2884 faster than 28.4%
经过优化,性能得到了较大的提升。

  • 补充信息
  1. 目前只完成了ContiguousKernel优化,先提交一下代码看看CI
  2. StridedCopyKernel优化思路相同,后续会补充

大赞!有1个疑问和2个建议:
疑问:测试用的input的非连续的Tensor是如何制造的?
建议1:能否再多添加一些shape的测试,尤其是计算量较大的测试?
建议2:能否添加一下A100的测试数据,如果你没有A100的机器,可以把测试代码发我,我来帮你跑~

@WintersMontagne10335
Copy link
Contributor Author

PR types

Performance optimization

PR changes

OPs

Description

目前ContiguousKernel、StridedCopyKernel两个 kernel 都是通过 numel index 计算数据偏移地址,需要一个 for 循环做计算,计算偏移地址效率低,导致 kernel 性能差。

  • 开发环境:
  1. 设备:Tesla V100
  2. 环境:CUDA 10.2
  • 优化方法
  1. 依靠线程配置信息,减少除法与取余操作。目前Paddle通过 numel index 计算数据偏移地址,会有大量除法与取余操作。可以利用线程配置中Grid与Block的6个参数(受硬件支持),减少除法与取余操作
  2. 去除依赖。由于kMaxRank为9,对于rank大于6或者不满足block参数配置要求(block.x * block.y * block.z <= 1024 && block.z <= 64)的情况下,还是需要计算部分偏移地址。目前Paddle中的实现存在依赖关系。下一个循环只能等本循环的index_tmp计算完毕后才能进行,但其实各个循环间的计算从逻辑实现上来说是独立的,完全可以并行计算。本方法,与上一个优化方法搭配,可以大幅缩短运行时间
  3. 预处理访存偏移量(可选优化点)。借鉴MegEngine卷积算子预处理访存偏移量的优化思路
  4. 改变访存(可选优化点)。《CUDA_C优化详解》中提到,“应尽可能避免非单位跨度的全局内存访问”,对于stride比较特殊的情况,可以优化访存

完成优化后,Paddle与优化前的Paddle的前向推理性能对比效果:
Case No. device input_type input_shape origin Paddle Perf(us) current Paddle Perf(us) diff
1 Tesla V100 float16 [ 4, 4, 4, 8, 8, 8] 4.2506 1.9681 faster than 116.0%
2 Tesla V100 float16 [ 2, 2, 2, 8, 8, 64] 4.2139 3.2855 faster than 28.3%
3 Tesla V100 float32 [ 4, 4, 4, 8, 8, 8] 4.2230 1.9842 faster than 113.3%
4 Tesla V100 float32 [ 2, 2, 2, 8, 8, 64] 4.2223 3.2884 faster than 28.4%
经过优化,性能得到了较大的提升。

  • 补充信息
  1. 目前只完成了ContiguousKernel优化,先提交一下代码看看CI
  2. StridedCopyKernel优化思路相同,后续会补充

大赞!有1个疑问和2个建议: 疑问:测试用的input的非连续的Tensor是如何制造的? 建议1:能否再多添加一些shape的测试,尤其是计算量较大的测试? 建议2:能否添加一下A100的测试数据,如果你没有A100的机器,可以把测试代码发我,我来帮你跑~

老师您好~~

  1. 关于疑问。参照的test_stride.py文件里面slice( https://github.com/PaddlePaddle/Paddle/blob/develop/test/legacy_test/test_stride.py#L118 )和real( https://github.com/PaddlePaddle/Paddle/blob/develop/test/legacy_test/test_stride.py#L175 ) 的测试函数。
  2. 关于建议1。计算量较大的测试指的是numel较大的数据,还是rank较大(比如9)的数据呀?numel这个可以的,后续会传上来,只是不知道,多大的数量级比较好?rank为9并且input_type为float32的情况可以用先real后contiguous来实现,但是float16的数据暂时不知道用什么方式比较好(real不支持这个type,slice限制rank<=6,test_stride.py文件我暂时没有找到合适的实现方法)
  3. 关于建议2。确实没有A100,目前测试工具是用的OP Benchmark( https://github.com/PaddlePaddle/benchmark ),但是因为其中没有contiguous的测试方法,所以我自己模仿别的算子的测试方法写了一套,但是挺不成熟的。不知道您需要什么样的测试代码呀?需要基于OP Benchmark的嘛,还是您用自己的测试工具呀?

@wanghuancoder
Copy link
Contributor

PR types

Performance optimization

PR changes

OPs

Description

目前ContiguousKernel、StridedCopyKernel两个 kernel 都是通过 numel index 计算数据偏移地址,需要一个 for 循环做计算,计算偏移地址效率低,导致 kernel 性能差。

  • 开发环境:
  1. 设备:Tesla V100
  2. 环境:CUDA 10.2
  • 优化方法
  1. 依靠线程配置信息,减少除法与取余操作。目前Paddle通过 numel index 计算数据偏移地址,会有大量除法与取余操作。可以利用线程配置中Grid与Block的6个参数(受硬件支持),减少除法与取余操作
  2. 去除依赖。由于kMaxRank为9,对于rank大于6或者不满足block参数配置要求(block.x * block.y * block.z <= 1024 && block.z <= 64)的情况下,还是需要计算部分偏移地址。目前Paddle中的实现存在依赖关系。下一个循环只能等本循环的index_tmp计算完毕后才能进行,但其实各个循环间的计算从逻辑实现上来说是独立的,完全可以并行计算。本方法,与上一个优化方法搭配,可以大幅缩短运行时间
  3. 预处理访存偏移量(可选优化点)。借鉴MegEngine卷积算子预处理访存偏移量的优化思路
  4. 改变访存(可选优化点)。《CUDA_C优化详解》中提到,“应尽可能避免非单位跨度的全局内存访问”,对于stride比较特殊的情况,可以优化访存

完成优化后,Paddle与优化前的Paddle的前向推理性能对比效果:
Case No. device input_type input_shape origin Paddle Perf(us) current Paddle Perf(us) diff
1 Tesla V100 float16 [ 4, 4, 4, 8, 8, 8] 4.2506 1.9681 faster than 116.0%
2 Tesla V100 float16 [ 2, 2, 2, 8, 8, 64] 4.2139 3.2855 faster than 28.3%
3 Tesla V100 float32 [ 4, 4, 4, 8, 8, 8] 4.2230 1.9842 faster than 113.3%
4 Tesla V100 float32 [ 2, 2, 2, 8, 8, 64] 4.2223 3.2884 faster than 28.4%
经过优化,性能得到了较大的提升。

  • 补充信息
  1. 目前只完成了ContiguousKernel优化,先提交一下代码看看CI
  2. StridedCopyKernel优化思路相同,后续会补充

大赞!有1个疑问和2个建议: 疑问:测试用的input的非连续的Tensor是如何制造的? 建议1:能否再多添加一些shape的测试,尤其是计算量较大的测试? 建议2:能否添加一下A100的测试数据,如果你没有A100的机器,可以把测试代码发我,我来帮你跑~

老师您好~~

  1. 关于疑问。参照的test_stride.py文件里面slice( https://github.com/PaddlePaddle/Paddle/blob/develop/test/legacy_test/test_stride.py#L118 )和real( https://github.com/PaddlePaddle/Paddle/blob/develop/test/legacy_test/test_stride.py#L175 ) 的测试函数。
  2. 关于建议1。计算量较大的测试指的是numel较大的数据,还是rank较大(比如9)的数据呀?numel这个可以的,后续会传上来,只是不知道,多大的数量级比较好?rank为9并且input_type为float32的情况可以用先real后contiguous来实现,但是float16的数据暂时不知道用什么方式比较好(real不支持这个type,slice限制rank<=6,test_stride.py文件我暂时没有找到合适的实现方法)
  3. 关于建议2。确实没有A100,目前测试工具是用的OP Benchmark( https://github.com/PaddlePaddle/benchmark ),但是因为其中没有contiguous的测试方法,所以我自己模仿别的算子的测试方法写了一套,但是挺不成熟的。不知道您需要什么样的测试代码呀?需要基于OP Benchmark的嘛,还是您用自己的测试工具呀?

建议1,其实本质就是多制造一些shape的场景,因为目前一个提升20%一个100%,不能够很好的看出优化的效果。新的测试case尽量让numel大一些。

可以不用OPBenchmark,自己直接测试就行,可以参考如下demo:

import paddle
import time

paddle.set_device('gpu:0')

b = paddle.ones([1000,1000,100,10])
start = time.time()
for i in range(800):
    sliced = b[1:1000, 0:1000, 0:100, 0:20] # 这里多变换一些case
    sliced.contiguous() # 这个会触发kernel执行
paddle.fluid.core._cuda_synchronize(paddle.CUDAPlace(0)) # 这个是等待所有GPU的kernel执行完成
end = time.time()
print(end - start)

@WintersMontagne10335
Copy link
Contributor Author

@wanghuancoder 老师您好,两个gpu端优化的ci都已经过了,如果有时间的话,可以先审核一下代码嘛?测试数据和cpu端优化正在补,不久会传上来。

Copy link
Contributor

@wanghuancoder wanghuancoder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@WintersMontagne10335
Copy link
Contributor Author

@wanghuancoder 基于time.time()的方式,实际测试发现,多次测试误差巨大。目前数据依据是依据OP Benchmark实现的。
HTY7MFQRB2VDTV0P~}TWVK7
time.time()的测试文件如下。
test_contiguous.txt
OP Benchmark的测试文件如下。
contiguous.txt

@WintersMontagne10335
Copy link
Contributor Author

case one的情况其实通过拆分成case two(c<=64&&abc<=1024&&rank>6)、case three(!(c<=64&&abc<=1024)&&rank<=6)、case four(其他情况)来继续优化,其中case two与case three的性能提升在case zero与case four之间。
不过这样工作量会翻个倍。因为想冲一下开源之星(囧),暂时没那么时间。黑客松结束后会提个PR优化掉,不知道可不可以。

@wanghuancoder
Copy link
Contributor

case one的情况其实通过拆分成case two(c<=64&&abc<=1024&&rank>6)、case three(!(c<=64&&abc<=1024)&&rank<=6)、case four(其他情况)来继续优化,其中case two与case three的性能提升在case zero与case four之间。 不过这样工作量会翻个倍。因为想冲一下开源之星(囧),暂时没那么时间。黑客松结束后会提个PR优化掉,不知道可不可以。

可以的!这个PR我先合入了。

jiahy0825 pushed a commit to jiahy0825/Paddle that referenced this pull request Oct 26, 2023
…PU、GPU性能优化 (PaddlePaddle#57835)

* speed up ContiguousKernel

* fix bugs

* fix bugs

* test origin code

* fix bugs
@luotao1 luotao1 changed the title 【PaddlePaddle Hackathon 5 No.48】ContiguousKernel、StridedCopyKernel算子CPU、GPU性能优化 【PaddlePaddle Hackathon 5 No.48】ContiguousKernel、StridedCopyKernel算子CPU、GPU性能优化 -part Nov 2, 2023
danleifeng pushed a commit to danleifeng/Paddle that referenced this pull request Nov 14, 2023
…PU、GPU性能优化 (PaddlePaddle#57835)

* speed up ContiguousKernel

* fix bugs

* fix bugs

* test origin code

* fix bugs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants