我的程序中有一个名为float valueAt(float3 v)的函数。它应该在给定点返回函数的值。该功能是用户指定的。我目前有这个功能的翻译,但是其他人建议我在网上编译这个功能,所以它在机器代码中更快。
我该怎么做?我相信我知道如何在生成PTX时加载该功能,但我不知道如何生成PTX。
答案 0 :(得分:3)
CUDA无法运行非PTX代码的运行时编译。
您可以做什么,但不能使用标准CUDA API。 PyCUDA为CUDA C代码提供了一种优雅的即时编译方法,其中包括工具链的幕后分支,以编译为设备代码并使用运行时API加载。 (可能的)缺点是您需要在应用程序的顶层使用Python,如果要将代码发送给第三方,您可能还需要发布一个可用的Python发行版。
我能想到的另一个替代方案是OpenCL,它支持运行时编译(直到最近才支持它)。 C99语言库比CUDA提供的限制更多,我发现API非常冗长,但运行时编译模型运行良好。
答案 1 :(得分:2)
我已经考虑过这个问题了一段时间,虽然我不认为这是一个很好的"解决方案,它似乎确实有效,所以我想我会分享它。
基本思想是使用linux生成进程来编译然后运行已编译的代码。我认为这几乎是不费脑子的,但是因为我把这些部分放在一起,所以我会在这里发布说明,以防它对其他人有用。
问题中的问题陈述是能够获取包含用户定义函数的文件,假设它是单个变量f(x)
的函数,即{{1} },x和y可以用y = f(x)
数量表示。
用户将编辑包含所需功能的名为float
的文件。该文件必须符合C语法规则。
fx.txt:
fx.txt
然后,该文件将包含在将保留它的y=1/x
函数中:
user_testfunc.cuh:
__device__
包含在通过包装器调用的内核中。
cudalib.cu:
__device__ float fx(float x){
float y;
#include "fx.txt"
;
return y;
}
cudalib.h:
#include <math.h>
#include "cudalib.h"
#include "user_testfunc.cuh"
__global__ void my_kernel(float x, float *y){
*y = fx(x);
}
float cudalib_compute_fx(float x){
float *d, *h_d;
h_d = (float *)malloc(sizeof(float));
cudaMalloc(&d, sizeof(float));
my_kernel<<<1,1>>>(x, d);
cudaMemcpy(h_d, d, sizeof(float), cudaMemcpyDeviceToHost);
return *h_d;
}
上述文件内置于共享库中:
float cudalib_compute_fx(float x);
我们需要一个主应用程序来使用这个共享库。
t452.cu:
nvcc -arch=sm_20 -Xcompiler -fPIC -shared cudalib.cu -o libmycudalib.so
编译如下:
#include <stdio.h>
#include <stdlib.h>
#include "cudalib.h"
int main(int argc, char* argv[]){
if (argc == 1){
// recompile lib, and spawn new process
int retval = system("nvcc -arch=sm_20 -Xcompiler -fPIC -shared cudalib.cu -o libmycudalib.so");
char scmd[128];
sprintf(scmd, "%s skip", argv[0]);
retval = system(scmd);}
else { // compute f(x) at x = 2.0
printf("Result is: %f\n", cudalib_compute_fx(2.0));
}
return 0;
}
此时,主应用程序(nvcc -arch=sm_20 -o t452 t452.cu -L. -lmycudalib
)可以执行,它将产生f(2.0)的结果,在这种情况下为0.5:
t452
然后,用户可以修改$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./t452
Result is: 0.500000
文件:
fx.txt
只需重新运行应用程序,即可使用新的功能行为:
$ vi fx.txt
$ cat fx.txt
y = 5/x
此方法利用了以下事实:在重新编译/替换共享库时,新的linux进程将获取新的共享库。另请注意,为清楚起见,我省略了几种错误检查。至少我会检查CUDA错误,我也可能在重新编译之前删除共享对象(.so)库,然后在编译后测试它的存在,以进行编译成功进行的基本测试。
此方法完全使用运行时API来实现此目标,因此用户必须在其计算机上安装CUDA工具包并进行适当设置,以便PATH中可以使用$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./t452
Result is: 2.500000
。使用带有PTX代码的驱动程序API可以使此过程更加清晰(并且不需要用户计算机上的工具包),但AFAIK无法在不使用nvcc
或者不使用nvcc
的情况下从CUDA C生成PTX用户创建的工具链构建在nvidia llvm编译器工具之上。在未来,可能会有更多的整合&#34; &#34;标准&#34;中可用的方法CUDA C工具链,或者甚至是驱动程序。
可以使用设备代码的单独编译和链接来安排类似的方法,以便需要向用户公开的唯一源代码位于user_testfunc.cu
(和fx.txt
)。
编辑:现在有一个CUDA runtime compilation facility,应该用它来代替上述内容。