单个CUDA函数的在线编译

单个CUDA函数的在线编译,cuda,compilation,Cuda,Compilation,我的程序中有一个名为float valueAtfloat3 v的函数。它应该返回函数在给定点的值。该函数由用户指定。目前我有一个用于此函数的解释器,但其他人建议我在线编译此函数,因此它是机器代码,速度更快 我该怎么做?我相信我知道在生成PTX时如何加载函数,但我不知道如何生成PTX。CUDA无法在运行时编译非PTX代码 您可以完成所需的操作,但不能使用标准的CUDA API。PyCUDA为CUDA C代码提供了一种优雅的即时编译方法,包括在后台分叉工具链以编译到设备代码,并使用运行时API加载。

我的程序中有一个名为float valueAtfloat3 v的函数。它应该返回函数在给定点的值。该函数由用户指定。目前我有一个用于此函数的解释器,但其他人建议我在线编译此函数,因此它是机器代码,速度更快


我该怎么做?我相信我知道在生成PTX时如何加载函数,但我不知道如何生成PTX。

CUDA无法在运行时编译非PTX代码

您可以完成所需的操作,但不能使用标准的CUDA API。PyCUDA为CUDA C代码提供了一种优雅的即时编译方法,包括在后台分叉工具链以编译到设备代码,并使用运行时API加载。可能的缺点是,您需要在应用程序的顶层使用Python,如果您要向第三方提供代码,您可能还需要提供一个可用的Python发行版


我能想到的另一种选择是OpenCL,它确实支持运行时编译,直到最近它才支持这种编译。C99语言基础比CUDA提供的限制要严格得多,我发现API非常详细,但是运行时编译模型工作得很好。

CUDA没有提供非PTX代码的运行时编译方法

您可以完成所需的操作,但不能使用标准的CUDA API。PyCUDA为CUDA C代码提供了一种优雅的即时编译方法,包括在后台分叉工具链以编译到设备代码,并使用运行时API加载。可能的缺点是,您需要在应用程序的顶层使用Python,如果您要向第三方提供代码,您可能还需要提供一个可用的Python发行版


我能想到的另一种选择是OpenCL,它确实支持运行时编译,直到最近它才支持这种编译。C99语言基础比CUDA提供的限制要严格得多,我发现API非常详细,但运行时编译模型工作得很好。

我已经考虑过这个问题一段时间了,虽然我认为这不是一个很好的解决方案,但它确实起作用,所以我想我会分享它

基本思想是使用linux生成编译进程,然后运行编译后的代码。我认为这是一个非常简单的问题,但既然我把这些部分放在一起,我会在这里发布说明,以防它对其他人有用

问题中的问题陈述是能够获取包含用户定义函数的文件,让我们假设它是单变量fx的函数,即y=fx,并且x和y可以用浮点量表示

用户将编辑一个名为fx.txt的文件,该文件包含所需的函数。此文件必须符合C语法规则

fx.txt:

y=1/x
然后,该文件将包含在保存该文件的_设备_)函数中:

用户_testfunc.cuh:

__device__ float fx(float x){
  float y;
#include "fx.txt"
;
  return y;
}
它包含在通过包装器调用的内核中

cudalib.cu:

#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;
  }
上述文件将内置到共享库中:

nvcc -arch=sm_20 -Xcompiler -fPIC -shared cudalib.cu -o libmycudalib.so
我们需要一个主应用程序来使用这个共享库

t452.cu:

#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;
}
此时,可以执行主应用程序t452,它将产生f2.0的结果,在本例中为0.5:

$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./t452
Result is: 0.500000
然后,用户可以修改fx.txt文件:

只需重新运行应用程序,即可使用新的功能行为:

$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./t452
Result is: 2.500000
此方法利用了一个事实,即在重新编译/替换共享库时,新的linux进程将获取新的共享库。还要注意,为了清晰起见,我省略了几种错误检查。至少,我会检查CUDA错误,我也可能会删除共享对象。因此,在重新编译之前,我会先删除库,然后在编译之后测试它是否存在,以进行一个基本测试,确保编译成功进行

此方法完全使用运行时API来实现此目标,因此用户必须在其计算机上安装CUDA工具包,并进行适当设置,以便nvcc在路径中可用。使用带有PTX代码的驱动程序API将使这个过程变得更干净,不需要用户机器上的工具包,但是没有使用NVCC或在英伟达LLVM编译器工具上建立的用户创建的工具链,就没有办法从CUDA C生成PTX。将来,标准CUDA C工具链中可能会有一种更为集成的方法,甚至可能由驱动程序提供

可以使用设备代码的单独编译和链接来安排类似的方法,以便需要向用户公开的唯一源代码位于user_testfunc.cu和fx.txt中


编辑:现在有一个CUDA,应该用它来代替上面的内容

我考虑这个问题已经有一段时间了,虽然我认为这不是一个很好的解决方案,但我 它似乎确实有效,所以我想我会分享它

基本思想是使用linux生成编译进程,然后运行编译后的代码。我认为这是一个非常简单的问题,但既然我把这些部分放在一起,我会在这里发布说明,以防它对其他人有用

问题中的问题陈述是能够获取包含用户定义函数的文件,让我们假设它是单变量fx的函数,即y=fx,并且x和y可以用浮点量表示

用户将编辑一个名为fx.txt的文件,该文件包含所需的函数。此文件必须符合C语法规则

fx.txt:

y=1/x
然后,该文件将包含在保存该文件的_设备_)函数中:

用户_testfunc.cuh:

__device__ float fx(float x){
  float y;
#include "fx.txt"
;
  return y;
}
它包含在通过包装器调用的内核中

cudalib.cu:

#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;
  }
上述文件将内置到共享库中:

nvcc -arch=sm_20 -Xcompiler -fPIC -shared cudalib.cu -o libmycudalib.so
我们需要一个主应用程序来使用这个共享库

t452.cu:

#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;
}
此时,可以执行主应用程序t452,它将产生f2.0的结果,在本例中为0.5:

$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./t452
Result is: 0.500000
然后,用户可以修改fx.txt文件:

只需重新运行应用程序,即可使用新的功能行为:

$ LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./t452
Result is: 2.500000
此方法利用了一个事实,即在重新编译/替换共享库时,新的linux进程将获取新的共享库。还要注意,为了清晰起见,我省略了几种错误检查。至少,我会检查CUDA错误,我也可能会删除共享对象。因此,在重新编译之前,我会先删除库,然后在编译之后测试它是否存在,以进行一个基本测试,确保编译成功进行

此方法完全使用运行时API来实现此目标,因此用户必须在其计算机上安装CUDA工具包,并进行适当设置,以便nvcc在路径中可用。使用带有PTX代码的驱动程序API将使这个过程变得更干净,不需要用户机器上的工具包,但是没有使用NVCC或在英伟达LLVM编译器工具上建立的用户创建的工具链,就没有办法从CUDA C生成PTX。将来,标准CUDA C工具链中可能会有一种更为集成的方法,甚至可能由驱动程序提供

可以使用设备代码的单独编译和链接来安排类似的方法,以便需要向用户公开的唯一源代码位于user_testfunc.cu和fx.txt中


编辑:现在有一个CUDA,应该用它来代替上面的内容

您可以使用nvcc-ptxmycode.cu从cuda C/C++源代码生成PTX。显然,用户定义的CUDA函数的运行时编译和导入要比这复杂得多,但我认为没有一种标准的编程方式可以做到这一点。您可以尝试在程序中的适当位置发出一个syscall并检查结果,假设您可以将所需函数放入一个表示语法正确、可编译CUDA函数的文件中。你的问题不是很简单就是很复杂。同样,我不确定是否有标准的方法来实现这一点。您可以使用nvcc-PTX mycode.cu从cuda C/C++源代码生成PTX。显然,用户定义的CUDA函数的运行时编译和导入要比这复杂得多,但我认为没有一种标准的编程方式可以做到这一点。您可以尝试在程序中的适当位置发出一个syscall并检查结果,假设您可以将所需函数放入一个表示语法正确、可编译CUDA函数的文件中。你的问题不是很简单就是很复杂。同样,我不确定是否有标准的方法来实现这一点。现在还有CUDA运行时编译系统可用,尽管它仍然有效地要求使用驱动程序API。现在还有CUDA运行时编译系统可用,尽管它仍然有效地要求使用驱动程序API。