2017-11-24 1 views
1

Ubuntu Linux 16.04에서 Python 2.7.14의 ctypess를 사용하여 CUDA 9.0에서 cublasXt*gemm 함수를 래핑하려고합니다. 이 함수는 호스트 메모리에있는 배열을 인수로 받아들입니다. 그러나cublasXt 행렬이 C++에서 성공하고 파이썬에서 실패합니다

#include <iostream> 
#include <cstdlib> 
#include "cublasXt.h" 
#include "cuda_runtime_api.h" 

void rand_mat(float* &x, int m, int n) { 
    x = new float[m*n]; 
    for (int i=0; i<m; ++i) { 
     for (int j=0; j<n; ++j) { 
      x[i*n+j] = ((float)rand())/RAND_MAX; 
     } 
    } 
} 

int main(void) { 
    cublasXtHandle_t handle; 
    cublasXtCreate(&handle); 

    int devices[1] = {0}; 
    if (cublasXtDeviceSelect(handle, 1, devices) != 
     CUBLAS_STATUS_SUCCESS) { 
     std::cout << "initialization failed" << std::endl; 
     return 1; 
    } 

    float *a, *b, *c; 
    int m = 4, n = 4, k = 4; 

    rand_mat(a, m, k); 
    rand_mat(b, k, n); 
    rand_mat(c, m, n); 

    float alpha = 1.0; 
    float beta = 0.0; 

    if (cublasXtSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, 
         m, n, k, &alpha, a, m, b, k, &beta, c, m) != 
      CUBLAS_STATUS_SUCCESS) { 
     std::cout << "matrix multiply failed" << std::endl; 
     return 1; 
    } 
    delete a; delete b; delete c; 
    cublasXtDestroy(handle); 
} 

내가 파이썬을 포장 할 때 다음과 같이 나는 cublasXt*gemm 전화에서 세그먼트 폴트가 발생, :

import ctypes 
import numpy as np 

_libcublas = ctypes.cdll.LoadLibrary('libcublas.so') 
_libcublas.cublasXtCreate.restype = int 
_libcublas.cublasXtCreate.argtypes = [ctypes.c_void_p] 
_libcublas.cublasXtDestroy.restype = int 
_libcublas.cublasXtDestroy.argtypes = [ctypes.c_void_p] 
_libcublas.cublasXtDeviceSelect.restype = int 
_libcublas.cublasXtDeviceSelect.argtypes = [ctypes.c_void_p, 
              ctypes.c_int, 
              ctypes.c_void_p] 
_libcublas.cublasXtSgemm.restype = int 
_libcublas.cublasXtSgemm.argtypes = [ctypes.c_void_p, 
            ctypes.c_int, 
            ctypes.c_int, 
            ctypes.c_int, 
            ctypes.c_int, 
            ctypes.c_int, 
            ctypes.c_void_p, 
            ctypes.c_void_p, 
            ctypes.c_int, 
            ctypes.c_void_p, 
            ctypes.c_int, 
            ctypes.c_void_p, 
            ctypes.c_void_p, 
            ctypes.c_int] 

handle = ctypes.c_void_p() 
_libcublas.cublasXtCreate(ctypes.byref(handle)) 
deviceId = np.array([0], np.int32) 
status = _libcublas.cublasXtDeviceSelect(handle, 1, 
             deviceId.ctypes.data) 
if status: 
    raise RuntimeError 

a = np.random.rand(4, 4).astype(np.float32) 
b = np.random.rand(4, 4).astype(np.float32) 
c = np.zeros((4, 4), np.float32) 

status = _libcublas.cublasXtSgemm(handle, 0, 0, 4, 4, 4, 
            ctypes.byref(ctypes.c_float(1.0)), 
            a.ctypes.data, 4, b.ctypes.data, 4, 
            ctypes.byref(ctypes.c_float(0.0)), 
            c.ctypes.data, 4) 
if status: 
    raise RuntimeError 
print 'success? ', np.allclose(np.dot(a.T, b.T).T, c_gpu.get()) 
_libcublas.cublasXtDestroy(handle) 

호기심을 다음과 같이 나는 ++ C에 성공적으로 사용 할 수있게되었습니다 , 내가 GPU로 옮긴 pycuda.gpuarray.GPUArray 행렬을 받아들이도록 약간 수정하면 위의 파이썬 래퍼가 작동합니다. 함수에 호스트 메모리를 전달할 때 파이썬에서만 segfault가 발생하는 이유는 무엇입니까?

+0

적어도 스택 추적을 볼 수 없습니까? 세그 폴트는 분명히 ctypes 버전의 하나 이상의 인수가 올바르지 않기 때문에 분명합니다. – talonmies

+1

내 생각에'ctypes.byref (ctypes.c_float (1.0))'는 float에 대한 참조를 생성하지만 float는 임시 객체이며 해제됩니다. 'ctypes.byref()'가 리턴 한 후에. 함수 호출 전에 float에 대한 참조를 보유하십시오. 함수의 실제 C 프로토 타입이 없으면 각 함수에'.argtypes'와'.restype'을 올바르게 할당했는지 알기가 어렵습니다. –

답변

2

Xt<t>gemm 함수에 대한 CUBLAS 설명서에 오류가있는 것으로 보입니다. 적어도 CUDA 8부터는 파라미터 m, n, k, lda, ldb, ldc은 모두 size_t입니다. 헤더 파일 cublasXt.h을 보면이 사실을 알 수 있습니다.

래퍼 다음과 같은 수정 나를 위해 제대로 작동하는 것 같다 :

$ cat t1340.py 
import ctypes 
import numpy as np 

_libcublas = ctypes.cdll.LoadLibrary('libcublas.so') 
_libcublas.cublasXtCreate.restype = int 
_libcublas.cublasXtCreate.argtypes = [ctypes.c_void_p] 
_libcublas.cublasXtDestroy.restype = int 
_libcublas.cublasXtDestroy.argtypes = [ctypes.c_void_p] 
_libcublas.cublasXtDeviceSelect.restype = int 
_libcublas.cublasXtDeviceSelect.argtypes = [ctypes.c_void_p, 
              ctypes.c_int, 
              ctypes.c_void_p] 
_libcublas.cublasXtSgemm.restype = int 
_libcublas.cublasXtSgemm.argtypes = [ctypes.c_void_p, 
            ctypes.c_int, 
            ctypes.c_int, 
            ctypes.c_size_t, 
            ctypes.c_size_t, 
            ctypes.c_size_t, 
            ctypes.c_void_p, 
            ctypes.c_void_p, 
            ctypes.c_size_t, 
            ctypes.c_void_p, 
            ctypes.c_size_t, 
            ctypes.c_void_p, 
            ctypes.c_void_p, 
            ctypes.c_size_t] 

handle = ctypes.c_void_p() 
_libcublas.cublasXtCreate(ctypes.byref(handle)) 
deviceId = np.array([0], np.int32) 
status = _libcublas.cublasXtDeviceSelect(handle, 1, 
             deviceId.ctypes.data) 
if status: 
    raise RuntimeError 

a = np.random.rand(4, 4).astype(np.float32) 
b = np.random.rand(4, 4).astype(np.float32) 
c = np.zeros((4, 4), np.float32) 
alpha = ctypes.c_float(1.0) 
beta = ctypes.c_float(0.0) 

status = _libcublas.cublasXtSgemm(handle, 0, 0, 4, 4, 4, 
           ctypes.byref(alpha), 
           a.ctypes.data, 4, b.ctypes.data, 4, 
           ctypes.byref(beta), 
           c.ctypes.data, 4) 
if status: 
    raise RuntimeError 
print 'success? ', np.allclose(np.dot(a.T, b.T).T, c) 
_libcublas.cublasXtDestroy(handle) 
$ python t1340.py 
success? True 
$ 

내가 변경 한 열거 :

  1. m에 대한 argtypes 변경을 n, k, lda, ldb, ldccublasXtSgemm에 대한 매개 변수 c_int ~ c_size_t
  2. 알파 및 베타 인수에 명시적인 변수가 제공되었습니다. 이 단지 c

위의 내가 문서를 업데이트해야하는 NVIDIA와 내부 버그를 제기 한 CUDA 8 CUDA 9에서 테스트했다 (심지어 현재 귀하의 np.allclose 기능에

  • c_gpu.get을 변경 아마도 무관 CUDA 9 문서는 헤더 파일의 현재 상태를 반영하지 않습니다.)

  • +0

    잘 잡으세요! 감사! – lebedov

    관련 문제