使用 FFI 从 Haskell 调用 CUDA "Hello World" 给出了错误的结果
Calling a CUDA "Hello World" from Haskell using the FFI gives wrong results
这是标准的 Hello World CUDA 文件:
#include <stdio.h>
#include "hello.h"
const int N = 7;
const int blocksize = 7;
__global__ void hello_kernel(char *a, int *b) {
a[threadIdx.x] += b[threadIdx.x];
}
#define cudaCheckError() { \
cudaError_t e=cudaGetLastError(); \
if(e!=cudaSuccess) { \
printf("Cuda failure %s:%d: '%s'\n",__FILE__,__LINE__,cudaGetErrorString(e)); \
exit(0); \
} \
}
void hello() {
char a[N] = "Hello ";
int b[N] = {15, 10, 6, 0, -11, 1, 0};
char *ad;
int *bd;
const int csize = N*sizeof(char);
const int isize = N*sizeof(int);
printf("%s", a);
cudaMalloc( (void**)&ad, csize );
cudaMemcpy( ad, a, csize, cudaMemcpyHostToDevice );
cudaCheckError();
cudaMalloc( (void**)&bd, isize );
cudaMemcpy( bd, b, isize, cudaMemcpyHostToDevice );
cudaCheckError();
dim3 dimBlock( blocksize, 1 );
dim3 dimGrid( 1, 1 );
hello_kernel<<<dimGrid, dimBlock>>>(ad, bd);
cudaMemcpy( a, ad, csize, cudaMemcpyDeviceToHost );
cudaCheckError();
cudaFree( ad );
cudaCheckError();
printf("%s\n", a);
}
及其 header:
-- hello.h
extern "C"
void hello();
那是一个 Haskell 文件调用了这样的函数:
-- test.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello
我正在编译它:
nvcc hello.c -c -o hello.o
ghc test.hs -o test hello.o -L/usr/local/cuda/lib -optl-lcudart
运行 ./test
的程序结果:
Hello Cuda failure hello.cu:32: 'no CUDA-capable device is detected'
运行 带有 C main()
的同一个程序只调用 hello
产生 Hello World
,正如预期的那样。
如何让 Haskell 正确检测到设备?
使用 ghc 7.8.3
和 nvcc V6.5.12
,我发现您的代码可以按预期工作。我所做的唯一不同的事情是将 hello.c
命名为 hello.cu
.
/:cuda_haskell> nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2014 NVIDIA Corporation
Built on Thu_Jul_17_19:13:24_CDT_2014
Cuda compilation tools, release 6.5, V6.5.12
/:cuda_haskell> nvcc -o hello.o -c hello.cu
/:cuda_haskell> ghc main.hs -o hello_hs hello.o -L/usr/local/cuda/lib -optl-lcudart
Linking hello_hs ...
/:cuda_haskell> ./hello_hs
Hello World!
/:cuda_haskell> cat main.hs
-- main.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello
可能不相关,但我能够在 Mac 上使用单独的板载和独立显卡重现您的错误。在系统偏好设置中启用 "Automatic graphics switching" 时(没有 3D 图形应用程序 运行),我得到相同的 "no CUDA-capable device is detected" 错误。
当我关闭自动切换显卡时,会强制Mac使用独立显卡,然后程序正常运行。
纯 C/CUDA-based 版本的代码似乎不受此首选项的影响,并且无论是否启用自动切换都始终有效。
这是标准的 Hello World CUDA 文件:
#include <stdio.h>
#include "hello.h"
const int N = 7;
const int blocksize = 7;
__global__ void hello_kernel(char *a, int *b) {
a[threadIdx.x] += b[threadIdx.x];
}
#define cudaCheckError() { \
cudaError_t e=cudaGetLastError(); \
if(e!=cudaSuccess) { \
printf("Cuda failure %s:%d: '%s'\n",__FILE__,__LINE__,cudaGetErrorString(e)); \
exit(0); \
} \
}
void hello() {
char a[N] = "Hello ";
int b[N] = {15, 10, 6, 0, -11, 1, 0};
char *ad;
int *bd;
const int csize = N*sizeof(char);
const int isize = N*sizeof(int);
printf("%s", a);
cudaMalloc( (void**)&ad, csize );
cudaMemcpy( ad, a, csize, cudaMemcpyHostToDevice );
cudaCheckError();
cudaMalloc( (void**)&bd, isize );
cudaMemcpy( bd, b, isize, cudaMemcpyHostToDevice );
cudaCheckError();
dim3 dimBlock( blocksize, 1 );
dim3 dimGrid( 1, 1 );
hello_kernel<<<dimGrid, dimBlock>>>(ad, bd);
cudaMemcpy( a, ad, csize, cudaMemcpyDeviceToHost );
cudaCheckError();
cudaFree( ad );
cudaCheckError();
printf("%s\n", a);
}
及其 header:
-- hello.h
extern "C"
void hello();
那是一个 Haskell 文件调用了这样的函数:
-- test.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello
我正在编译它:
nvcc hello.c -c -o hello.o
ghc test.hs -o test hello.o -L/usr/local/cuda/lib -optl-lcudart
运行 ./test
的程序结果:
Hello Cuda failure hello.cu:32: 'no CUDA-capable device is detected'
运行 带有 C main()
的同一个程序只调用 hello
产生 Hello World
,正如预期的那样。
如何让 Haskell 正确检测到设备?
使用 ghc 7.8.3
和 nvcc V6.5.12
,我发现您的代码可以按预期工作。我所做的唯一不同的事情是将 hello.c
命名为 hello.cu
.
/:cuda_haskell> nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2014 NVIDIA Corporation
Built on Thu_Jul_17_19:13:24_CDT_2014
Cuda compilation tools, release 6.5, V6.5.12
/:cuda_haskell> nvcc -o hello.o -c hello.cu
/:cuda_haskell> ghc main.hs -o hello_hs hello.o -L/usr/local/cuda/lib -optl-lcudart
Linking hello_hs ...
/:cuda_haskell> ./hello_hs
Hello World!
/:cuda_haskell> cat main.hs
-- main.hs
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C
import Foreign.Ptr (Ptr,nullPtr)
foreign import ccall "hello" hello :: IO ()
main = hello
可能不相关,但我能够在 Mac 上使用单独的板载和独立显卡重现您的错误。在系统偏好设置中启用 "Automatic graphics switching" 时(没有 3D 图形应用程序 运行),我得到相同的 "no CUDA-capable device is detected" 错误。
当我关闭自动切换显卡时,会强制Mac使用独立显卡,然后程序正常运行。
纯 C/CUDA-based 版本的代码似乎不受此首选项的影响,并且无论是否启用自动切换都始终有效。