GPU每次运行结果不一样是什么原因

  • 6 replies
  • 771 views
GPU每次运行结果不一样是什么原因
« 于: 七月 25, 2019, 09:17:36 am »
代码是一样的但是每次运行结果都不一样,相差很大。感觉有点像是数值结果是一样的,但数值排列顺序每次运行出来都不一样。
想问问[名词2]们到底是什么原因?
« 最后编辑时间: 七月 25, 2019, 09:18:42 am 作者 Fenvi »

Re: GPU每次运行结果不一样是什么原因
« 回复 #1 于: 七月 25, 2019, 01:29:20 pm »
代码是一样的但是每次运行结果都不一样,相差很大。感觉有点像是数值结果是一样的,但数值排列顺序每次运行出来都不一样。
想问问[名词2]们到底是什么原因?

要么是你的代码有问题,要么是某些GPU算法本身就是结果不问题的,于是产生了你说的“数值结果是一样的,但排列顺序不同”。

不妨考虑一下CPU上的一些不稳定算法,是不是有类似现象?

Re: GPU每次运行结果不一样是什么原因
« 回复 #2 于: 七月 26, 2019, 10:29:18 am »
要么是你的代码有问题,要么是某些GPU算法本身就是结果不问题的,于是产生了你说的“数值结果是一样的,但排列顺序不同”。

不妨考虑一下CPU上的一些不稳定算法,是不是有类似现象?

找到原因了,是我在核函数内给三个全局变量相互赋值出了问题,例如初始化是p1=1,p2=2,p3=3。然后后面相互赋值p3=p2;p2=p1;但最后输p3结果不是2而是1。为什么会这样的?而且我加一个中间变量来赋值也还是不行,例如swap=p2,p3=swap;swap=p1,p2=swap;结果还是和上面的一样
« 最后编辑时间: 七月 26, 2019, 10:36:51 am 作者 娃娃脸 »

Re: GPU每次运行结果不一样是什么原因
« 回复 #3 于: 七月 26, 2019, 05:40:51 pm »
找到原因了,是我在核函数内给三个全局变量相互赋值出了问题,例如初始化是p1=1,p2=2,p3=3。然后后面相互赋值p3=p2;p2=p1;但最后输p3结果不是2而是1。为什么会这样的?而且我加一个中间变量来赋值也还是不行,例如swap=p2,p3=swap;swap=p1,p2=swap;结果还是和上面的一样

不妨发一下代码,例如考虑如下三个变量:
__device__ int a;
__device__ int b;
当同时有多个线程在进行tmp = a; a = b; b = tmp;的时候,因为多个GPU上的线程的执行在时间上可能是错开的,此时则会发生竞态,使得a,b并没有完成交换。这就是一种例子。

楼主不妨发一下代码,没啥可以保密的。

Re: GPU每次运行结果不一样是什么原因
« 回复 #4 于: 七月 26, 2019, 10:34:38 pm »
不妨发一下代码,例如考虑如下三个变量:
__device__ int a;
__device__ int b;
当同时有多个线程在进行tmp = a; a = b; b = tmp;的时候,因为多个GPU上的线程的执行在时间上可能是错开的,此时则会发生竞态,使得a,b并没有完成交换。这就是一种例子。

楼主不妨发一下代码,没啥可以保密的。

谢谢啦!问题已解决了,应该就是你说的那样,我限制了执行这几条命令的线程数,只有blockIdx.x==0的线程执行该命令就能实现了。
修改前:p2[tid] = p1[tid];
     p1[tid] = 1.0f;
修改后:if (blockIdx.y == 0)
   {
      p2[tid] = p1[tid];
     p1[tid] = 1.0f;
   }

Re: GPU每次运行结果不一样是什么原因
« 回复 #5 于: 七月 28, 2019, 02:54:26 pm »
谢谢啦!问题已解决了,应该就是你说的那样,我限制了执行这几条命令的线程数,只有blockIdx.x==0的线程执行该命令就能实现了。
修改前:p2[tid] = p1[tid];
     p1[tid] = 1.0f;
修改后:if (blockIdx.y == 0)
   {
      p2[tid] = p1[tid];
     p1[tid] = 1.0f;
   }

嗯嗯。以及,考虑到这问题这么普遍的存在,你也许应当额外看一下手册的“原子操作”和相关章节。很多问题可以变通的用其他方式解决的。

Re: GPU每次运行结果不一样是什么原因
« 回复 #6 于: 七月 30, 2019, 10:48:45 pm »
嗯嗯。以及,考虑到这问题这么普遍的存在,你也许应当额外看一下手册的“原子操作”和相关章节。很多问题可以变通的用其他方式解决的。
嗯嗯,看过了。我了解的原子操作只是用那几个函数,而且只对共享内存和全局内存的数据起到作用,好像不适合我用。不知道为什么  在我的工程里atomicAdd()和atomicExch()函数都能用而atomicSub()这个函数却用不了。