求助关于CUDA编程的若干问题

刚开始学习CUDA,遇到很多问题,希望大神解答,谢谢!

1、线程及线程块数量的限制:查询硬件特性中写明GTX580有16个SM,每个SM线程数量上限为1536,是否允许的线程总数为161536,还是说只是同时运行的数量?线程块数量上限是否受SP控制,还是6553565535?

2、共享内存及寄存器总量:查询硬件特性列出的共享内存及寄存器为每个block的限制,对GTX580分别为49152B和32768,那么二者的总量有限制吗?怎么查?

3、循环的时效:对庞大的计算量,内存限制不得不使用循环时,是在每个线程内部使用循环还是线程外运算更快?

4、怎么判断所用GPU是否支持双精度运算?

5、#define定义的参数是什么类型?取值范围?

毕设要用,比较着急,十分感谢各位的解答!


代为编辑了一下字号

楼主您好。

(1)该数量(SM数目*1536)是同时能在运行中的线程总数,而不是您的一次kernel启动的线程数目限制。

(2)能启动的总blocks数目取决与GPU的计算能力,而和SM数目,和SP数目,均无关。
例如,只有1个SM,48个SP的GT520和16个SM,512SP的GTX580能启动的blocks总数是一样的。

(3)关于48KB的shared memory和32K个32位寄存器,是SM的硬件限制(硬件资源如此),而不是block的软件限制。
(4)"二者的总量"无法理解,shared memory的大小和寄存器的大小相加得到的和,我无法理解其含义。

(5)如何拆分算法,是在线程内部循环快,还是将循环拆开更快,取决与具体算法,没有定论的。

(6)如何判定GPU是否支持双精度,您可以用cudaGetDeviceProperties(), 并检查结果的major和minor字段表示的计算能力是否>=CC1.3。(贵卡,GTX580, 是支持的)

(7)"#define是什么类型的“—该问题无法理解,无法回答。

感谢您的来访,祝您午夜愉快!

非常感谢您的回答!追问:
1、“能启动的总blocks数目取决与GPU的计算能力”是指计算能力版本吗?那么对2.0是多少?

2、每个block的shared memory在GTX580中限制为49152B,我想问的是所有block的shared memory总和限制是多少?怎么查看?对寄存器呢?

3、cuda计时常用的clock_t,我在用的时候出错说undefined,是需要include什么文件吗?

再次感谢!
PS:发另一个与此贴内容相同的帖子,是因为本帖调了字号后在我的电脑上显示很混乱看不清,抱歉!

1:是指计算能力版本(Compute Capabality),详细信息见CUDA C Programming Guide Appendix F。如果没记错的话,对于2.0是655356553565535.

2:无论寄存器资源,还是shared memory资源,都是SM上的硬件资源,和block这个软件概念没有直接关系。同时resident在一个SM上的blocks,分享了该SM上的寄存器资源和shared memory资源。这两项资源可能会限制SM所能resident的block的数量,也可能不限制(而被其他因素限制)。

所以您说的“所有block的shared memory总和限制是多少”这不是一个有意义的问题。

3:这不是CUDA提供的内容,请前往下述链接学习:https://zh.wikipedia.org/zh/Time.h

另:顶楼字号已经代为修改。

祝您编码愉快~

以及,稍微补充一下,如果是在kernel中使用clock_t,您可以直接使用。(以及,在kernel中的clock()和普通的C库的clock()含义不同,注意区别)。

感谢您的回答!
实际上我一直想知道的是硬件的shared memory大小,但是CUDA自带的查询设备的程序运行后关于shared memory大小的说明只有shared memory per block一项,所以会想到以上的问题,追问下:那硬件的shared memory大小怎么查?

您好!感谢您的补充!
我#include <time.h>后已能用,但是现在有个问题,clock_t是long型,4Byte共32bit,上限是2的31次方,即2147483648,现在我计时的上限超过了这个值怎么办?我试过将定义为clock_t型改为double,但没有效果。恳请回答,谢谢!

楼主您好,
我没有补充过,您需要在kernel里需要#include <time.h>的信息。该信息由ICE提供,请询问正确的人。

以及,补充下,如果您需要在kernel里使用更大的数据范围,您可以考虑clock64()。

此外,作为严肃的Windows用户,我强烈建议楼主不使用clock()函数。

我给出我这个建议的理由:
(1)clock()在windows上的精确度可能无法满足您的要求。(CLOCKS_PER_SEC的值是1000不假,但您一般得不到1ms的精度,一般您可能会得到几个到10几个ms的精度)
(2)clock()存在严重的移植性问题。
(3)以及,使用clock()来测时是windows "专用"的做法,您在*NIX下无法这么用(和精度无关,是clock()的含义不同)。

因为以上三点,强烈不建议使用它来测试。
您可以使用QueryPerformanceCounter()和QueryPerformanceFrequency()来替代。

以及,在kernel中的clock()和clock64()还是值得使用的。

[

当一个SM上只运行一个block的时候,此时该block的最大可用shared memory数量就是SM的shared memory数量。

所以您查到的单block最大可用shared memory数量即是SM上的总量。

同时,如果您一个block上用的shared memory数量超过最大可用量的一半,那么一个SM上至多只能有一个block。

大致如上,看上去有点绕。
祝您好运!

另外前文中我是按照楼主的说法,估计楼主打算用clock()在host端大致计时的。

关于在kernel中使用clock(),和CPU端使用clock()请参考横扫版主的详细回答。

您好!我的程序运行时间比较长,10ms的精度足够了。但是现在有个问题,我的程序运行时间只有10s到20s的样子,但是用clock()函数计时,两次返回的差值非常大,达到10000000的量级!请问可能是什么原因?谢谢!

如果楼主非要用clock()的话,请注意只在windows下有意义(其他平台下是cpu时间,而不是wall time, 导致你的测试无意义的).

如果楼主在非windows平台下,可以不用往下看了。请改为gettimeofday()。

如果在windows平台下,误差却能达到10000000。这不可能。windows下一般clocks_per_sec是1000. 这相当与差上了10000秒,也就是3个小时。所以您不可能在windows下。

而我一再强调非windows平台请不要使用clock()。以及本贴的前半部分已经说明了请改用gettimeofday(), 在非windows平台上。请修正。

以及,再次强调,您可以使用QueryPerformanceCounter(), 如果需要在windows上测试的话。

这个,关键就是Windows平台,所以我也觉得肯定不对,就是搞不清错在哪了。是在kernel中使用clock()时两次返回值都很大,差值也很大,主机端计时的话返回值只有几百到一千多的样子,感觉是正常的。之所以没有按你的建议使用QueryPerformanceCounter(), 是因为网上查了一下,发现好像使用比较复杂,没有clock()那样简便,而且我对计时精度要求确实不高,因为程序需要运行十几秒到几十秒的样子。

哦。你是kernel中啊。

这个很正常。因为返回的是时钟值,因为warp间复杂的调度,不能保证2个操作之间的延迟是固定的,GPU只保证最大吞吐率,为了整个目标它可以选择任何它喜欢的调度方式。

如果想尽量精确的测试kernel中2条语句间的延迟,建议尽量只上1个warp。没有更多的建议了。

以及,需要说明的是,kernel中clock()唯一的用途就是测量延迟。而完全不能代表你的kernel的运行时间。你一个线程用时1ms, 你100000个线程很可能也是1ms或者几个ms. 因为他们可以在“几乎同时”的运行。

我不是想测延迟,就是想测程序运行时间,本来考虑的是在主机端测时,同时在设备端也测时,这样同时估计得到数据在CPU与GPU之间来回拷贝的时间。但是主机端两次clock()返回值只差只有500多太小,设备端的计时也太大很不正常。我看张舒的那本书,clock()是可以用于计时的,的确像你说的“100000个线程很可能也是1ms或者几个ms”,实际计时是对每个block而言的,最后将所有block结束时间最大值与开始时间最小值求差,得到所有block的总运行时间。

我不认为用clock()可以有实际意义的在kernel中测量它自身的运行时间。已经在上文阐述过了我的理由了。

请在host端测量,例如cudaEvent, 例如clock(), 例如QueryPerformanceCounter(), 例如gettimeofday()。

但永远不建议使用device built-in的clock()来测量。这是第二次给出建议。

您可以再次忽略此建议,并使用你指出的那本书。但是我不能对此书的方法提供任何建议,请直接联系你买的书的出版商或者作者。

感谢回复!!!

您好,请不要无意义地挖别人的帖子,您未参与上文中任何讨论,19#中也是一句空洞的“谢谢回复”。
此做法有灌水之嫌,请勿再这样。

这是第二次劝告您。