【发布时间】:2018-05-08 01:46:52
【问题描述】:
我正在尝试在 Ubuntu Linux 16.04 上使用 Python 2.7.14 中的 ctypess 将 CUDA 9.0 中的 cublasXt*gemm 函数包装起来。这些函数接受主机内存中的数组作为它们的一些参数。我已经能够在 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);
}
但是,当我尝试按如下方式将它们包装在 Python 中时,我在 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)
奇怪的是,如果我稍微修改上面的 Python 包装器以接受我已转移到 GPU 的pycuda.gpuarray.GPUArray 矩阵,它们就会起作用。关于为什么在将主机内存传递给函数时我只在 Python 中遇到段错误的任何想法?
【问题讨论】:
-
你不能至少看看堆栈跟踪吗?段错误显然是因为ctypes版本中的一个或多个参数不正确
-
我的猜测是
ctypes.byref(ctypes.c_float(1.0))创建了一个对浮点数的引用,但该浮点数是一个临时对象,在ctypes.byref()返回后被释放。在函数调用之前保留对浮点数的引用。如果没有函数的实际 C 原型,很难判断您是否为每个函数正确分配了.argtypes和.restype。