关键词:visual studio 2017、python转c++、cuda编程、opencl编程、生成dll等

背景描述

轮胎磨耗算法是用python写的,其中调用了外部显卡及cpu显卡,对应cuda编程及opencl编程。但是整个测试系统软件是找人做的,用c开发的,为了保持系统的统一性,由我来把python转成c++,转换期间遇到了不少问题,也都一一解决了,最后结果一致,生成了dll。

遇到的问题及解决办法

1、python的numpy库转到c++

用python写各种矩阵算法那是简单的很,但是转到c++就不好弄了,没有numpy里面的各种函数,如果每个都自己写那就麻烦的很,从网上找了一个叫numcpp的c++库,号称是c++里的numpy,里面有一些自带的函数与numpy的确相似,不过这个库只支持到二维矩阵,只好用了部分函数(reshape、tile、arange函数等),同时opencv里面也有一些矩阵操作函数,也用了一部分(pad函数等),向量操作为了方便用了c自带的vector、list等。
其中numcpp的索引如果用中括号[],那么索引是所有矩阵从前向后的,比如有一个两行两列的矩阵a,那么a[0]、a[1]、a[2]、a[3]是对矩阵a的四个元素的依次索引,如果对定向的行列索引,要用小括号,a(1,0)即是对第2行第1列的元素进行索引。
numcpp里面的元素必须是基本的c/c++数据类型,比如int、float等,定义为nc::NdArray,不能是vector、list等扩展类型,这个就比较坑了,而vector里面是可以放vector甚至是opencv的mat数据的,这个就非常好用。
感谢《C++用vector生成三维数组,并计算行、列、高》作者https://blog.csdn.net/sinich__eveen/article/details/86561698
附numcpp地址:
地址 https://github.com/dpilger26/NumCpp
文档地址 https://dpilger26.github.io/NumCpp/doxygen/html/index.html

2、cuda编程问题

c/c++的cuda编程之前没有接触过,通过这次转换,对cuda编程也有了一些了解,cuda编程问题也是本次转换遇到的最多的问题。对cuda编程了解可以看一看这两个博客:
https://blog.csdn.net/xiaohu2022/article/details/79599947
https://www.cnblogs.com/skyfsm/p/9673960.html
可以有个基本的认识。
遇到的问题有:

① __constant__常量的处理

在cuda编程中,如果是一些一般变量,要先通过申请一个指针变量,然后用cudaMalloc函数在device(GPU)上申请一个固定大小的空间,然后用cudaMemcpy把数据写入这个空间上,而__constant__变量不再需要申请空间,因为__constant__变量本身就是定义在device上的变量,而且要在定义的时候声明空间大小,比如__constant__ a[100],__constant__变量在传数据的时候只需用cudaMemcpyToSymbol函数即可,但是要注意__constant__变量最好和调用它的在device上运行的函数(一般是__globle__函数)在同一个文件里,否则需要在另外文件里用extern。因为.cu的文件不能用#include进行引入,需要用extern,包括函数、变量都是这样。
另外上面文章也有写,在cuda6.0以后引入了统一内存,这样就不用手动进行Memcpy了,统一内存使用一个托管内存来共同管理host和device中的内存,并且自动在host和device中进行数据传输。CUDA中使用cudaMallocManaged函数分配托管内存:
cudaError_t cudaMallocManaged(void **devPtr, size_t size, unsigned int flag=0);
值得注意的是kernel执行是与host异步的,由于托管内存自动进行数据传输,这里要用cudaDeviceSynchronize()函数保证device和host同步,这样后面才可以正确访问kernel计算的结果。

②__globle__函数调用

__globle__函数一定要在.cu文件里调用,也就是说要在cuda c++编译器里调用,右键源文件查看编译器是cuda c/c++才行,调用函数的时候已如下格式调用:
cuda_work<<<grid, block >>>(a,b,c)
其中grid、block是dim3类型的cuda线程操作层次结构。这里有个坑,一开始我在分配时用的grid(54, 32), block(32, 32),block代表每个block里的线程数是3232=1024个,grid代表block的排布是5432=1728的矩阵,这个地方我的MAX_REGISTERS_PRE_BLOCK的寄存器数量是65536个,所以能够满足,但是一开始怎么都运行不出数据,最后发现是寄存器没有分配,这时候要右键.cu文件选择属性,在Device里设定Max Used Register的值为64,因为我的是323264 = 65536,而默认值是0,肯定是不行的。这里感谢https://www.jianshu.com/p/8440d7d7b9c6文章作者
在运行完__globle__函数后最好读取一下运行一下cudaStatus = cudaGetLastError()来看看是否有错误,前面说的cudaMalloc、cudaMemcpy函数返回值也都是cudaError_t类型的变量,通过这个变量值可以查看是否有错误输出,以及错误输出的类型。

3、cuda写成的类封装成dll

用cuda写成的类或函数是.cu的文件,封装成dll与普通的cpp文件也没有什么不同,所以用这篇文章的方法即可实现,感谢作者(在2楼):
https://bbs.csdn.net/topics/300123936
https://blog.csdn.net/qq_37902078/article/details/80144696

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值