Cuda 用Fortran&;库达
我试图在PGI的fortran编译器中制作一个简单的程序。这个简单的程序将使用图形卡,使用“镖靶”算法计算pi。在与这个程序斗争了很长一段时间之后,现在我终于让它在很大程度上正常工作了。然而,我目前仍然无法正确地传递结果。我必须说,这是一个相当棘手的程序调试,因为我不能再推任何打印语句到子程序。此程序当前返回所有零。我不确定到底发生了什么,但我有两个想法。我不知道如何解决这两个问题:Cuda 用Fortran&;库达,cuda,fortran,pgi,Cuda,Fortran,Pgi,我试图在PGI的fortran编译器中制作一个简单的程序。这个简单的程序将使用图形卡,使用“镖靶”算法计算pi。在与这个程序斗争了很长一段时间之后,现在我终于让它在很大程度上正常工作了。然而,我目前仍然无法正确地传递结果。我必须说,这是一个相当棘手的程序调试,因为我不能再推任何打印语句到子程序。此程序当前返回所有零。我不确定到底发生了什么,但我有两个想法。我不知道如何解决这两个问题: CUDA内核没有运行吗 我没有正确地转换值pi_零件=pi_零件 这就是我目前项目的状态。CUDA准备好的设备内
\u d
的所有变量,其中所有其他变量(CUDA内核除外)都是典型的Fortran CPU准备变量。现在有一些我已经注释掉的打印语句,我已经在CPU Fortran land上试用过了。这些命令是为了检查我是否真的正确生成了随机数。至于CUDA方法,我目前已经注释掉了计算结果,并将z
替换为静态等于1
,只是为了观察发生了什么
module calcPi
contains
attributes(global) subroutine pi_darts(x, y, results, N)
use cudafor
implicit none
integer :: id
integer, value :: N
real, dimension(N) :: x, y, results
real :: z
id = (blockIdx%x-1)*blockDim%x + threadIdx%x
if (id .lt. N) then
! SQRT NOT NEEDED, SQRT(1) === 1
! Anything above and below 1 would stay the same even with the applied
! sqrt function. Therefore using the sqrt function wastes GPU time.
z = 1.0
!z = x(id)*x(id)+y(id)*y(id)
!if (z .lt. 1.0) then
! z = 1.0
!else
! z = 0.0
!endif
results(id) = z
endif
end subroutine pi_darts
end module calcPi
program final_project
use calcPi
use cudafor
implicit none
integer, parameter :: N = 400
integer :: i
real, dimension(N) :: x, y, pi_parts
real, dimension(N), device :: x_d, y_d, pi_parts_d
type(dim3) :: grid, tBlock
! Initialize the random number generaters seed
call random_seed()
! Make sure we initialize the parts with 0
pi_parts = 0
! Prepare the random numbers (These cannot be generated from inside the
! cuda kernel)
call random_number(x)
call random_number(y)
!write(*,*) x, y
! Convert the random numbers into graphics card memory land!
x_d = x
y_d = y
pi_parts_d = pi_parts
! For the cuda kernel
tBlock = dim3(256,1,1)
grid = dim3((N/tBlock%x)+1,1,1)
! Start the cuda kernel
call pi_darts<<<grid, tblock>>>(x_d, y_d, pi_parts_d, N)
! Transform the results into CPU Memory
pi_parts = pi_parts_d
write(*,*) pi_parts
write(*,*) 'PI: ', 4.0*sum(pi_parts)/N
end program final_project
模块calcPi
包含
属性(全局)子例程pi_省道(x,y,结果,N)
使用cudafor
隐式无
整数::id
整数,值::N
实数,维数(N)::x,y,结果
real::z
id=(块IDX%x-1)*块DIM%x+线程IDX%x
如果(id.lt.N)那么
! 不需要SQRT,SQRT(1)==1
! 任何高于或低于1的值都将保持不变,即使应用了
! sqrt函数。因此,使用sqrt函数会浪费GPU时间。
z=1.0
!z=x(id)*x(id)+y(id)*y(id)
!如果(z.lt.1.0),则
! z=1.0
!其他的
! z=0.0
!恩迪夫
结果(id)=z
恩迪夫
结束子例程pi_省道
端模块calcPi
计划最终项目
使用calcPi
使用cudafor
隐式无
整数,参数::N=400
整数::i
实数,尺寸(N):x、y、pi\U零件
实数,维数(N),设备::x\u d,y\u d,pi\u parts\u d
类型(dim3):网格,tBlock
! 初始化随机数生成器种子
调用随机_seed()
! 确保我们使用0初始化部件
pi_部分=0
! 准备随机数(这些随机数不能从内部生成)
!cuda内核)
随机呼叫号码(x)
呼叫随机号码(y)
!写(*,*)x,y
! 将随机数转换为图形卡存储空间!
x_d=x
y_d=y
pi_零件d=pi_零件
! 对于cuda内核
tBlock=dim3(256,1,1)
网格=dim3((N/t块%x)+1,1,1)
! 启动cuda内核
调用pi_省道(x_d,y_d,pi_d,N)
! 将结果转换为CPU内存
圆周率=圆周率
编写(*,*)pi_零件
写入(*,*)“PI:”,4.0*和(PI_部分)/N
最终项目
编辑到代码:
更改了不同的行以反映所提到的修复:Robert Crovella
。当前状态:cuda memcheck捕获的错误显示:在我的机器上调用cuda API时程序命中错误8
如果有任何方法我可以用来测试这个程序,请让我知道。我正在投掷飞镖,看看它们落在哪里,以适应我目前使用CUDA进行调试的风格。这不是最理想的,但在我找到另一种方法之前,它将不得不这样做
在这个黑暗的时刻,愿福特兰神怜悯我的灵魂。当我编译并运行你的程序时,我得到了一个错误。这是由于您要传递给内核的最后一个参数(N\u d
):
当我对您发布的代码进行更改时,我会得到实际的打印输出(而不是seg故障),这是一个由1和0组成的数组(256个1,后跟144个0,总共N
=400个值),然后是计算出的PI值(在本例中正好是2.56)(4*256/400),因为您已经使内核基本上是一个虚拟内核)
这一行代码也可能不是您想要的:
grid = dim3(N/tBlock%x,1,1)
当N
=400和tBlock%x
=256(来自前面的代码行)时,计算结果为1(即grid
最终位于(1,1,1)
,相当于一个螺纹块)。但是您确实希望启动2个ThreadBlock,以便覆盖整个数据集范围(N
=400个元素)。有很多方法可以解决这个问题,但为了简单起见,我们总是在计算中加1:
grid = dim3((N/tBlock%x)+1,1,1)
在这种情况下,当我们启动的网格(总线程数)大于我们的数据集大小(在本例中为512个线程,但只有400个数据元素)时,通常会在内核的开头附近进行线程检查(在本例中,在初始化id
之后),以防止越界访问,像这样:
if (id .lt. N) then
(在内核代码的最末端有一个对应的endif
)这样,只有对应于实际有效数据的线程才允许执行任何工作
通过上述更改,您的代码应该基本上是功能性的,并且您应该能够将内核代码还原为正确的语句,并开始获得PI的估计值
请注意,您可以检查CUDA API中的错误返回代码,也可以使用CUDA memcheck
运行代码,了解内核是否正在进行越界访问。但是,其中的Niether将有助于解决这个特殊的seg故障。您是否有机会在GPU的帮助下查看这个用于π的蒙特卡罗计算的Fortran示例:非常感谢您回复我的问题
grid = dim3((N/tBlock%x)+1,1,1)
if (id .lt. N) then