cuda中如何选择block尺寸

发布网友 发布时间:2022-04-24 14:41

我来回答

1个回答

热心网友 时间:2022-05-11 21:45

*16=1024
个线程,此时
SM
上还有
1024
个线程空闲,显然这种设置
无法有效利用
GPU


l

如果设置
block
尺寸为
16*16=256

根据
Threads Per Multiprocessor
的限
制每个
SM
可容纳
2048/256=8

block
,小于
Thread
Blocks
Per
Multiprocessor
的*;此时
SM
每次运行
8

block

2048
个线程,
能够占满整个
SM


l

如果设置
block
尺寸为
32*32=1024
,根据
Threads Per Multiprocessor

*每个
SM
可运行
2048/1024=2

block
,小于
Thread
Blocks
Per
Multiprocessor
的*;此时
SM
每次运行
2

block

2048
个线程,
能够占满整个
SM


注意事项
A
:根据
Max Thread Block Size
的*,
block
中线程个数上限为
1024


注意事项
B


CUDA
中,
线程调度单位称作
Warp

根据
Threads Per Warp
这个规格,每次以
32
个线程为单位进行调度,因此
Block
中的
Thread
数目应当

32
的倍数。

注意事项
C

Block
如果是*的,每个维度也都有大小*,图
5
中的
Threads
Dimensions







Block
Dimension
Limit





1024*1024*
,也就是
Block
的第一维不能超过
1024
,第二维不能超过
1024

第三位不能超过



综上所述,我们的初步设计结果是:在无需考虑向下兼容的情况下,对
GTX650
显卡将
block
尺寸设置为
32*32=1024
应该是比较恰当的(哦,忘了说,
我主要用
CUDA
做图像处理,因此
block
尺寸都习惯设为二维)


2.

SM
资源对
Block
尺寸设计的影响

制约
block
尺寸分配的还有其他资源的*,例如
shared
memory

register
等。在每一个
SM
上这些资源都是有限的,如果所有线程要求的资源总和过多,
CUDA
只能通过强制减少
Block
数来保证资源供应。

顺便提一下,
Shared Memory

Register
都位于
GPU
片上(相对的,
Global
Memory

Local Memory
位于显存)

速度超快的,
想要
CUDA
程序跑得快,

Shared Memory

Register
的细心设计是必不可少的。

2.1

Register

Block
尺寸设计的影响

根据
Register File Size
的*(
CUDA-Z
描述为
Regs Per Block
,不准确,
应该是
Regs Per Multiprocessor

,每个
SM
上只能供应
65536

Register


根据
Max Registers Per Thread
的*,
每个线程不能使用超过
63

Register


计算示例:

l

假设
Block
尺寸设计为
32*32=1024

每个
Thread
需要使用
32

Register

则一个
SM
上能承担的
Thread
数量为
65536/32=2048
,刚好可以满足需
求。

l

Block
尺寸同上,每个
Thread
需要使用
33

Register
,则一个
SM
上能
承担的
Thread
数量为
65536/33

1985.94
。但是,前面说过,如果请求
资源过多,
CUDA
将会通过强制减少
Block

(而不是
Thread
数)
来保
证资源供应。本示例中的情况可以满足
1

Block

1024

Thread
)的
需求,不能满足
2

Block

2048

Thread
)的需求,因此实际只有
1

Block

1024
个线程在运行。和上个示例相对比,因为多请求了
1

Register
,就灭掉了其他
1024

Thread
的生存机会,不划算啊。

2.2

Shared Memory

Block
尺寸设计的影响


2.1
基本类似。

根据
Max
Shared
Memory
Per
Multiprocessor
的*,每个
SM
上只能供应
49152 Byte

Shared Memory


首先需要明确一点:
Shared Memory
是分配给
Block
而不是
Thread
的,
被每

Block
内的所有
Thread
共享(所以才叫做
”Shared”


Block
中的
Thread
能够
合作运行也是基于这一点。

计算示例:

l

假设每个
Block
使用了
20000 Byte

Shared Memory
,则一个
SM
上能
承担的
Block
数量为
49152/20000=2.4576
,可以满足需求。

l

假设每个
Block
使用了
30000 Byte

Shared Memory
,则一个
SM
上能
承担的
Block
数量为
49152/30000=1.6384
。本示例中的情况只能满足
1

Block
的需求,因此实际只有
1

Block
在运行。如果这里
Block

尺寸为
32*32=1024
,则
SM
中另外
1024
个线程容量都被浪费了。

2.3

占用率计算器的使用

上面的计算乍一看比较复杂,所幸
nVidia
已经提供了一个很好的计算工具,
这就是刚才提到
CUDA_Occupancy_Calculator.xls
,如图
8
所示。

这个工具的使用非常简单,
只要遵循
3
个步骤即可。
1)

2)
是需要用户使用
下拉菜单进行选择的项目,
3)
是占用率计算结果。下面我们分别进行介绍。

1.)
是选择
GPU
的计算能力,
前面说过可以使用
CUDA-Z
软件查询,
GTX650
显卡选择
3.0


1.b)
在表
1
中已经给出了,数值为
49152


2.)
中的
Threads Per Block
就设为前面计算得到的
32*32=1024


那么一个程序使用的
Register

Shared Memory
如何得到呢?这时可以使用
--ptxas-options=-v
编译指令。

S
U
M
E

C
O
L
L
E
C
T
I
O
N


8 CUDA GPU
占用率计算器


VS2008
中可以如下操作:

a.

打开
Project
属性;


9

b.

将属性中
CUDA
Runtime
API\GPU
中的
Verbose
PTXAS
Output
设置为
Yes



10

c.

重新编译程序后,即可在
Output
窗口中看到类似下面的信息

ptxas info

: Compiling entry function '_Z8my_kernelPf' for 'sm_10'
ptxas info

: Used 5 registers, 8+16 bytes smem
可以看出本程序使用了
5

Register

8+16

Byte

Shared Memory

但是如果程序在运行时还定义了
2048 Byte

external shared memory array

则总的
Shared
Memory
占用应当是
2048+8+16=2072
。将
Register

Shared
Memory
信息填入图
5
中的
2.)
后即可看到计算器的计算结果,
如图
11
所示。


11

3.)
中显示的就是资源占用情况,可见
SM
的占用率是
100%
,没有计算能力
被浪费,说明这种配置是合理的。

S
U
M
E

C
O
L
L
E
C
T
I
O
N

至此,
Block
尺寸的设计基本完成。

3.

Block
尺寸的合理性

资源(
Register

Shared Memory
)是稀缺的,一定要分配给最重要的语句。
虽然
Thread
越多就越能隐藏访问延迟,但同时每个
Thread
能够使用的资源也就
相对减少了,如何在这两者之间找到平衡,只有程序实际运行时才能得到检验。
现实和理论总是有差别,
但如果能够把握基本的原理,
肯定不会在通往最终目标
的路上偏离太多。

热心网友 时间:2022-05-11 21:45

*16=1024
个线程,此时
SM
上还有
1024
个线程空闲,显然这种设置
无法有效利用
GPU


l

如果设置
block
尺寸为
16*16=256

根据
Threads Per Multiprocessor
的限
制每个
SM
可容纳
2048/256=8

block
,小于
Thread
Blocks
Per
Multiprocessor
的*;此时
SM
每次运行
8

block

2048
个线程,
能够占满整个
SM


l

如果设置
block
尺寸为
32*32=1024
,根据
Threads Per Multiprocessor

*每个
SM
可运行
2048/1024=2

block
,小于
Thread
Blocks
Per
Multiprocessor
的*;此时
SM
每次运行
2

block

2048
个线程,
能够占满整个
SM


注意事项
A
:根据
Max Thread Block Size
的*,
block
中线程个数上限为
1024


注意事项
B


CUDA
中,
线程调度单位称作
Warp

根据
Threads Per Warp
这个规格,每次以
32
个线程为单位进行调度,因此
Block
中的
Thread
数目应当

32
的倍数。

注意事项
C

Block
如果是*的,每个维度也都有大小*,图
5
中的
Threads
Dimensions







Block
Dimension
Limit





1024*1024*
,也就是
Block
的第一维不能超过
1024
,第二维不能超过
1024

第三位不能超过



综上所述,我们的初步设计结果是:在无需考虑向下兼容的情况下,对
GTX650
显卡将
block
尺寸设置为
32*32=1024
应该是比较恰当的(哦,忘了说,
我主要用
CUDA
做图像处理,因此
block
尺寸都习惯设为二维)


2.

SM
资源对
Block
尺寸设计的影响

制约
block
尺寸分配的还有其他资源的*,例如
shared
memory

register
等。在每一个
SM
上这些资源都是有限的,如果所有线程要求的资源总和过多,
CUDA
只能通过强制减少
Block
数来保证资源供应。

顺便提一下,
Shared Memory

Register
都位于
GPU
片上(相对的,
Global
Memory

Local Memory
位于显存)

速度超快的,
想要
CUDA
程序跑得快,

Shared Memory

Register
的细心设计是必不可少的。

2.1

Register

Block
尺寸设计的影响

根据
Register File Size
的*(
CUDA-Z
描述为
Regs Per Block
,不准确,
应该是
Regs Per Multiprocessor

,每个
SM
上只能供应
65536

Register


根据
Max Registers Per Thread
的*,
每个线程不能使用超过
63

Register


计算示例:

l

假设
Block
尺寸设计为
32*32=1024

每个
Thread
需要使用
32

Register

则一个
SM
上能承担的
Thread
数量为
65536/32=2048
,刚好可以满足需
求。

l

Block
尺寸同上,每个
Thread
需要使用
33

Register
,则一个
SM
上能
承担的
Thread
数量为
65536/33

1985.94
。但是,前面说过,如果请求
资源过多,
CUDA
将会通过强制减少
Block

(而不是
Thread
数)
来保
证资源供应。本示例中的情况可以满足
1

Block

1024

Thread
)的
需求,不能满足
2

Block

2048

Thread
)的需求,因此实际只有
1

Block

1024
个线程在运行。和上个示例相对比,因为多请求了
1

Register
,就灭掉了其他
1024

Thread
的生存机会,不划算啊。

2.2

Shared Memory

Block
尺寸设计的影响


2.1
基本类似。

根据
Max
Shared
Memory
Per
Multiprocessor
的*,每个
SM
上只能供应
49152 Byte

Shared Memory


首先需要明确一点:
Shared Memory
是分配给
Block
而不是
Thread
的,
被每

Block
内的所有
Thread
共享(所以才叫做
”Shared”


Block
中的
Thread
能够
合作运行也是基于这一点。

计算示例:

l

假设每个
Block
使用了
20000 Byte

Shared Memory
,则一个
SM
上能
承担的
Block
数量为
49152/20000=2.4576
,可以满足需求。

l

假设每个
Block
使用了
30000 Byte

Shared Memory
,则一个
SM
上能
承担的
Block
数量为
49152/30000=1.6384
。本示例中的情况只能满足
1

Block
的需求,因此实际只有
1

Block
在运行。如果这里
Block

尺寸为
32*32=1024
,则
SM
中另外
1024
个线程容量都被浪费了。

2.3

占用率计算器的使用

上面的计算乍一看比较复杂,所幸
nVidia
已经提供了一个很好的计算工具,
这就是刚才提到
CUDA_Occupancy_Calculator.xls
,如图
8
所示。

这个工具的使用非常简单,
只要遵循
3
个步骤即可。
1)

2)
是需要用户使用
下拉菜单进行选择的项目,
3)
是占用率计算结果。下面我们分别进行介绍。

1.)
是选择
GPU
的计算能力,
前面说过可以使用
CUDA-Z
软件查询,
GTX650
显卡选择
3.0


1.b)
在表
1
中已经给出了,数值为
49152


2.)
中的
Threads Per Block
就设为前面计算得到的
32*32=1024


那么一个程序使用的
Register

Shared Memory
如何得到呢?这时可以使用
--ptxas-options=-v
编译指令。

S
U
M
E

C
O
L
L
E
C
T
I
O
N


8 CUDA GPU
占用率计算器


VS2008
中可以如下操作:

a.

打开
Project
属性;


9

b.

将属性中
CUDA
Runtime
API\GPU
中的
Verbose
PTXAS
Output
设置为
Yes



10

c.

重新编译程序后,即可在
Output
窗口中看到类似下面的信息

ptxas info

: Compiling entry function '_Z8my_kernelPf' for 'sm_10'
ptxas info

: Used 5 registers, 8+16 bytes smem
可以看出本程序使用了
5

Register

8+16

Byte

Shared Memory

但是如果程序在运行时还定义了
2048 Byte

external shared memory array

则总的
Shared
Memory
占用应当是
2048+8+16=2072
。将
Register

Shared
Memory
信息填入图
5
中的
2.)
后即可看到计算器的计算结果,
如图
11
所示。


11

3.)
中显示的就是资源占用情况,可见
SM
的占用率是
100%
,没有计算能力
被浪费,说明这种配置是合理的。

S
U
M
E

C
O
L
L
E
C
T
I
O
N

至此,
Block
尺寸的设计基本完成。

3.

Block
尺寸的合理性

资源(
Register

Shared Memory
)是稀缺的,一定要分配给最重要的语句。
虽然
Thread
越多就越能隐藏访问延迟,但同时每个
Thread
能够使用的资源也就
相对减少了,如何在这两者之间找到平衡,只有程序实际运行时才能得到检验。
现实和理论总是有差别,
但如果能够把握基本的原理,
肯定不会在通往最终目标
的路上偏离太多。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com