|
| 1 | +#include <pybind11/pybind11.h> |
| 2 | +#include <vector> |
| 3 | +#include <string> |
| 4 | +#include <cuda_runtime.h> |
| 5 | + |
| 6 | +namespace py = pybind11; |
| 7 | + |
| 8 | +// CUDA kernel declaration (defined in cuda_kernel.cu) |
| 9 | +extern "C" void add_vectors_cuda(float* a, float* b, float* c, int n); |
| 10 | + |
| 11 | +// Simple hello function |
| 12 | +std::string hello() { |
| 13 | + int device_count = 0; |
| 14 | + cudaError_t err = cudaGetDeviceCount(&device_count); |
| 15 | + |
| 16 | + std::string result = "v" + std::string(HELLO_CUDA_VERSION) + ": Hello from C++ with CUDA!"; |
| 17 | + |
| 18 | + if (err == cudaSuccess && device_count > 0) { |
| 19 | + result += "\nFound " + std::to_string(device_count) + " CUDA device(s)"; |
| 20 | + |
| 21 | + // Get device info |
| 22 | + cudaDeviceProp prop; |
| 23 | + if (cudaGetDeviceProperties(&prop, 0) == cudaSuccess) { |
| 24 | + result += "\nDevice 0: " + std::string(prop.name); |
| 25 | + result += " (Compute " + std::to_string(prop.major) + "." + std::to_string(prop.minor) + ")"; |
| 26 | + } |
| 27 | + } else { |
| 28 | + result += "\nCUDA devices not available"; |
| 29 | + } |
| 30 | + |
| 31 | + return result; |
| 32 | +} |
| 33 | + |
| 34 | +// Python function that uses CUDA kernel |
| 35 | +py::list add_vectors(py::list a, py::list b) { |
| 36 | + // Convert Python lists to vectors |
| 37 | + std::vector<float> vec_a, vec_b; |
| 38 | + for (auto item : a) { |
| 39 | + vec_a.push_back(py::cast<float>(item)); |
| 40 | + } |
| 41 | + for (auto item : b) { |
| 42 | + vec_b.push_back(py::cast<float>(item)); |
| 43 | + } |
| 44 | + |
| 45 | + if (vec_a.size() != vec_b.size()) { |
| 46 | + throw std::runtime_error("Vectors must have the same size"); |
| 47 | + } |
| 48 | + |
| 49 | + int n = vec_a.size(); |
| 50 | + if (n == 0) { |
| 51 | + return py::list(); |
| 52 | + } |
| 53 | + |
| 54 | + // Allocate device memory |
| 55 | + float *d_a, *d_b, *d_c; |
| 56 | + cudaMalloc(&d_a, n * sizeof(float)); |
| 57 | + cudaMalloc(&d_b, n * sizeof(float)); |
| 58 | + cudaMalloc(&d_c, n * sizeof(float)); |
| 59 | + |
| 60 | + // Copy data to device |
| 61 | + cudaMemcpy(d_a, vec_a.data(), n * sizeof(float), cudaMemcpyHostToDevice); |
| 62 | + cudaMemcpy(d_b, vec_b.data(), n * sizeof(float), cudaMemcpyHostToDevice); |
| 63 | + |
| 64 | + // Launch CUDA kernel |
| 65 | + add_vectors_cuda(d_a, d_b, d_c, n); |
| 66 | + |
| 67 | + // Copy result back |
| 68 | + std::vector<float> result(n); |
| 69 | + cudaMemcpy(result.data(), d_c, n * sizeof(float), cudaMemcpyDeviceToHost); |
| 70 | + |
| 71 | + // Free device memory |
| 72 | + cudaFree(d_a); |
| 73 | + cudaFree(d_b); |
| 74 | + cudaFree(d_c); |
| 75 | + |
| 76 | + // Convert to Python list |
| 77 | + py::list py_result; |
| 78 | + for (float val : result) { |
| 79 | + py_result.append(val); |
| 80 | + } |
| 81 | + |
| 82 | + return py_result; |
| 83 | +} |
| 84 | + |
| 85 | +PYBIND11_MODULE(hello_cuda, m) { |
| 86 | + m.doc() = "Hello world pybind11 module with CUDA support"; |
| 87 | + m.def("hello", &hello, "Return a friendly greeting from C++ with CUDA info"); |
| 88 | + m.def("add_vectors", &add_vectors, "Add two vectors using CUDA", |
| 89 | + py::arg("a"), py::arg("b")); |
| 90 | +} |
| 91 | + |
0 commit comments