使用Cython调用CUDA Kernel函数
技术背景
前面写过一篇关于Cython和C语言混合编程的文章,在Cython中可以使用非常Pythonic的方法去调用C语言中的函数。另外我们也曾在文章中介绍过Python中使用CUDA计算的一种方案。其实从Python中去调用CUDA有很多种解决方案,例如直接使用MindSpore、PyTorch、Jax等成熟的框架进行GPU加速,也可以使用Numba的CUDA即时编译JIT来直接对Python函数进行GPU加速,还可以使用PyCuda或者Cupy来实现Python中的GPU加速。但是不论是哪一种方案,其实本质上都绕不开到C语言和Kernel函数的转换。这里提供了另外一个思路,允许我们给出Python的API接口,又可以同时使用熟悉的Python函数和C函数、CUDA函数,以达到不同的目的,这就是Python+Cython+C/CUDA的方案。
构建思路
随着Python语言在机器学习领域的大力推广,Python编程对于众多的科技工作者而言总是一个较为靠前的选项。所以不论使用何种方式构建自己的项目,一般我们都会选择面向用户开放一个Python的API接口。如果做一个项目,项目的本身对于程序性能的要求并不高的情况下,我们可以直接使用Python进行相关的计算。但如果对计算性能要求比较高,那么C/CUDA会是一个更好的选择。那么剩下一个待解决的问题就是,如何构建Python API与C/CUDA之间的交互。其实这里本身有两个方案:1. 直接把C/CUDA代码编译成*.so
动态链接库,然后在Python中加载动态链接库的函数作为接口。2. 只用C/CUDA执行计算,把C/CUDA代码编译成*.so
动态链接库,从Cython中对两者函数进行调度和管理。
从用户面的角度来说,第一个方案虽然可能性能还不错,但凡是需要新增一些功能模块,都需要去修改C/CUDA代码。如果只是功能模块还好说,如果涉及到任务调度和接口传输的问题,那门槛就更高了。第二个方案在性能上有可能略有衰减,但是因为接口传输和调度都是在Cython中完成的,即使是只会Python的开发者,也可以以Cython为入口来开发自己需要的模块。
案例演示
这里我们演示一个简单的Hello World
程序,首先我们可以写一个hello.cu
的CUDA文件:
#include<stdio.h>
__global__ void HelloKernel(void){
printf("Hello World From GPU!\n");
}
int main(){
HelloKernel<<<1,3>>>();
cudaDeviceReset();
return 1;
}
然后使用nvcc
对这个CUDA项目进行编译:
$ nvcc -c ./hello.cu -Xcompiler -fPIC -o ./libhello.so
得到了一个libhello.so
的动态链接文件。然后在hello.pyx
中引入这个动态链接库:
# cythonize -i hello.pyx
import ctypes
libcuda = ctypes.CDLL('./libhello.so')
cpdef int run_cuda():
cdef int res
res = libcuda.main()
if res:
print ('Load cuda function successfully!')
else:
print ('Failed to load cuda function.')
return 1
这里我们可以使用cythonize
指令编译pyx文件,也可以使用python的setup.py
配置编译指令。为了方便我们就用cythonize
演示一下这个案例:
$ cythonize -i hello.pyx
那么会得到一个hello.c
文件和一个hello.cpython-37m-x86_64-linux-gnu.so
动态链接文件。到这里相当于我们对CUDA文件中的main函数
封装了一层cython的调用,然后就可以在python文件中调用这个cython的run_cuda()
函数:
# $ python3 hello.py
from hello import run_cuda
run_cuda()
然后运行这个python文件,输出为:
$ python3 hello.py
Hello World From GPU!
Hello World From GPU!
Hello World From GPU!
Load cuda function successfully!
成功的从Python侧调用了CUDA Kernel函数。
总结概要
从Python接口调用GPU进行加速的方案有很多,包括Cupy和PyCuda以及之前介绍过的Numba,还可以使用MindSpore、PyTorch和Jax等成熟的深度学习框架,这里介绍了一种直接写CUDA Kernel函数的方案。为了能够做到CUDA-C和Python编程的分离,这里引入了Cython作为中间接口,这样一来Python开发者和C开发者可以去共同开发相应的高性能方法。
版权声明
本文首发链接为:https://www.cnblogs.com/dechinphy/p/cython-cuda.html
作者ID:DechinPhy
更多原著文章:https://www.cnblogs.com/dechinphy/
请博主喝咖啡:https://www.cnblogs.com/dechinphy/gallery/image/379634.html
使用Cython调用CUDA Kernel函数的更多相关文章
- CUDA学习,第一个kernel函数及代码讲解
前一篇CUDA学习,我们已经完成了编程环境的配置,现在我们继续深入去了解CUDA编程.本博文分为三个部分,第一部分给出一个代码示例,第二部分对代码进行讲解,第三部分根据这个例子介绍如何部署和发起一个k ...
- VS2013 VC++的.cpp文件调用CUDA的.cu文件中的函数
CUDA 8.0在函数的调用中方便的让人感动.以下是从网上学到的VC++的.cpp文件调用CUDA的.cu文件中的函数方法,和一般的VC++函数调用的方法基本没差别. 使用的CUDA版本为CUDA 8 ...
- 如何在cuda内核函数中产生随机数(host端调用,device端产生)
最近,需要在kernel函数中调用浮点型的随机数.于是上网搜了下相关资料,一种方式是自己手动写一个随机数的__device__函数,然后在调用的时候调用这个函数.另一种,原来cuda在toolkit中 ...
- 【VS开发】【CUDA开发】如何在MFC中调用CUDA
如何在MFC中调用CUDA 有时候,我们需要在比较大的项目中调用CUDA,这就涉及到MFC+CUDA的环境配置问题,以矩阵相乘为例,在MFC中调用CUDA程序.我们参考罗振东iylzd@163.com ...
- C++使用类调用CUDA核函数
正如CUDA C所称,CUDA对C语言进行了很好的扩展,直接使用C语言可以非常简单方便的调用CUDA核函数.但是当想使用C++的类成员函数直接调用核函数是不可行的,第一,核函数不能作为类的成员函数,第 ...
- linux字符设备驱动中内核如何调用驱动入口函数 一点记录
/* 内核如何调用驱动入口函数 ? *//* 答: 使用module_init()函数,module_init()函数定义一个结构体,这个结构体里面有一个函数指针,指向first_drv_init() ...
- ASP.NET后台调用前台JS函数的三种常见方法
第一种:使用普通的添加控件中的Attributes属性进行调用 例如,像一般的普通的按钮:Button1.Attributes.Add("onclick","MyFun( ...
- unity中三种调用其他脚本函数的方法
第一种,被调用脚本函数为static类型,调用时直接用 脚本名.函数名()第二种,GameObject.Find("脚本所在的物体的名字").SendMessage(" ...
- MyEclipse调用Matlab打包函数
本文部分内容参考了http://www.360doc.com/content/15/1103/16/1180274_510463048.shtml 一.检查Java环境 对于已经装上JAVA环境的计算 ...
- C#调用Windows API函数截图
界面如下: 下面放了一个PictureBox 首先是声明函数: //这里是调用 Windows API函数来进行截图 //首先导入库文件 [System.Runtime.InteropServices ...
随机推荐
- [brief]虚拟机安装UbuntuServer
1.下载Ubuntu--Server镜像官网点击 2.Vmware15.x配置 2G /boot 4G swap(一倍或两倍于分配内存量) rest / or /+/home 3.terminal下安 ...
- 8.18考试总结(NOIP模拟43)[第一题·第二题·第三题·第四题]
愿你和重要的人,在来日重逢. 前言 题目名字起的很随意... 这天 Luogu 的运势好像是大凶(忌:打模拟赛,注意报零). 但是考得还不错,拿到了这么多场模拟赛以来第二三个场上AC. 所以说,我爱大 ...
- scala怎么退出
scala怎么退出 scala> :help //查看帮助 All commands can be abbreviated, e.g., :he instead of :help. :edit ...
- P7322
P7322 好神仙! \(\color{#5bc9}\text{提醒,本文有大量没有推到过程的式子,所以读者可以自己遮住先推一下}\) Inscription: 有一个长度为 \(k\) 的窗口,在一 ...
- The remote name could not be resolved
HTTP The remote name could not be resolved HTTP Status:NameResolutionFailure
- 思迅Pay PC ,WIN7 ,KB3042058
思迅Pay PC ,WIN7, COM , 串口 . 577,驱动. WIN7 SHA256补丁,KB3033929,https://www.microsoft.com/zh-CN/download/ ...
- C# 循环枚举
foreach (int eemun in Enum.GetValues(typeof(类名))) { string sName = Enum.GetName(typeof(类名), eemun);/ ...
- ITMS-90717: 无效的应用程序商店图标
PS导入照片 图像->模式->索引颜色 透明度去掉打勾保存即可
- Pycharm创建的虚拟环境,使用命令行指定库的版本进行安装
Pycharm创建的项目,使用了虚拟环境,对库的版本进行管理:有些项目的对第三方库的版本 要求不同,可使用虚拟环境进行管理 直接想通过pip命令安装,直接看第3点 操作步骤: 1.找到当前项目的虚拟环 ...
- Linux 内核:设备驱动模型(4)uevent与热插拔
Linux 内核:设备驱动模型(4)uevent与热插拔 背景 我们简单回顾一下Linux的设备驱动模型(Linux Device Driver Model,LDDM): 1.在<sysfs与k ...