diff options
Diffstat (limited to 'tools/test/cuda_drv_test.c')
| -rw-r--r-- | tools/test/cuda_drv_test.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/test/cuda_drv_test.c b/tools/test/cuda_drv_test.c new file mode 100644 index 0000000..6868a2e --- /dev/null +++ b/tools/test/cuda_drv_test.c @@ -0,0 +1,87 @@ +/* cuda_drv_test.c - minimal CUDA driver-API smoke test (dlopen, no toolkit). + * + * Run inside the guest. Exercises the paths CUDA needs beyond NVML: + * cuInit -> cuDeviceGetCount/Get -> cuCtxCreate -> cuMemAlloc -> + * cuMemcpyHtoD/DtoH -> cuMemFree -> cuCtxDestroy + * + * Expected output on success: "ALL OK". + * + * Status (2026-09-23): cuInit returns 3 (CUDA_ERROR_NOT_INITIALIZED) on the + * emulated GPU. strace shows every nvidia.ko ioctl succeeding (RM status 0), + * the driver completing RmInitAdapter and then closing the device, and + * libcuda opening /dev/nvidia-uvm before /dev/nvidia0 - i.e. the next blocker + * is the UVM driver (nvidia-uvm.ko), which needs the GPU MMU/VAS model that + * the GSP-RM emulation does not provide yet. Build in the guest with: + * gcc -O1 -o /tmp/cdt cuda_drv_test.c -ldl + */ +#include <stdio.h> +#include <string.h> +#include <dlfcn.h> +#include <stdint.h> + +typedef int CUresult; +typedef int CUdevice; +typedef void *CUcontext; +typedef uint64_t CUdeviceptr; + +#define CHECK(expr) do { \ + CUresult r = (expr); \ + if (r) { printf("%-24s FAILED rc=%d\n", #expr, r); return 1; } \ + printf("%-24s OK\n", #expr); \ +} while (0) + +int main(void) +{ + void *h = dlopen("libcuda.so.1", RTLD_NOW); + if (!h) { printf("dlopen libcuda.so.1 failed: %s\n", dlerror()); return 1; } + + CUresult (*cuInit)(unsigned int) = dlsym(h, "cuInit"); + CUresult (*cuDeviceGetCount)(int *) = dlsym(h, "cuDeviceGetCount"); + CUresult (*cuDeviceGet)(CUdevice *, int) = dlsym(h, "cuDeviceGet"); + CUresult (*cuCtxCreate)(CUcontext *, unsigned int, CUdevice) = dlsym(h, "cuCtxCreate_v2"); + CUresult (*cuMemAlloc)(CUdeviceptr *, size_t) = dlsym(h, "cuMemAlloc_v2"); + CUresult (*cuMemcpyHtoD)(CUdeviceptr, const void *, size_t) = dlsym(h, "cuMemcpyHtoD_v2"); + CUresult (*cuMemcpyDtoH)(void *, CUdeviceptr, size_t) = dlsym(h, "cuMemcpyDtoH_v2"); + CUresult (*cuMemFree)(CUdeviceptr) = dlsym(h, "cuMemFree_v2"); + CUresult (*cuCtxDestroy)(CUcontext) = dlsym(h, "cuCtxDestroy_v2"); + + if (!cuInit || !cuDeviceGetCount || !cuDeviceGet || !cuCtxCreate || + !cuMemAlloc || !cuMemcpyHtoD || !cuMemcpyDtoH || !cuMemFree || !cuCtxDestroy) { + printf("dlsym failed\n"); + return 1; + } + + int count = 0; + CUdevice dev; + CUcontext ctx = NULL; + CUdeviceptr dptr = 0; + unsigned int buf[64]; + unsigned int back[64]; + size_t i; + + CHECK(cuInit(0)); + CHECK(cuDeviceGetCount(&count)); + printf("device count = %d\n", count); + if (count < 1) return 1; + + CHECK(cuDeviceGet(&dev, 0)); + printf("device 0 = %d\n", dev); + + CHECK(cuCtxCreate(&ctx, 0, dev)); + printf("context = %p\n", ctx); + + CHECK(cuMemAlloc(&dptr, sizeof(buf))); + printf("device ptr = 0x%llx (%zu bytes)\n", (unsigned long long)dptr, sizeof(buf)); + + for (i = 0; i < 64; i++) buf[i] = (unsigned int)(i * 3 + 1); + CHECK(cuMemcpyHtoD(dptr, buf, sizeof(buf))); + memset(back, 0, sizeof(back)); + CHECK(cuMemcpyDtoH(back, dptr, sizeof(buf))); + printf("roundtrip %s (back[7]=%u expected 22)\n", + memcmp(buf, back, sizeof(buf)) ? "MISMATCH" : "match", back[7]); + + CHECK(cuMemFree(dptr)); + CHECK(cuCtxDestroy(ctx)); + printf("ALL OK\n"); + return 0; +} |
