发布网友 发布时间: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
能够使用的资源也就
相对减少了,如何在这两者之间找到平衡,只有程序实际运行时才能得到检验。
现实和理论总是有差别,
但如果能够把握基本的原理,
肯定不会在通往最终目标
的路上偏离太多。