Контекст:
Я младший инженер-программист, надеюсь, я не изобретаю колесо, пожалуйста, дайте мне знать.
Я хотел бы создать шаблонную функцию, которая оборачивает и вызывает другую функцию с точки зрения элемента. Например:
// returns a*x + y
__device__ float saxpy(float a, float x, float y) {
return a*x + y;
}
int main() {
int A[4] = { 1,2,3,4 };
int X[4] = { 1,2,3,4 };
int Y[4] = { 1,1,1,1 };
// A*X = 1,4,9,16
// A*X+Y = 2,5,10,17
float *C = cudaReduce(saxpy, A, X, Y);
for (int i = 0; i < 4; i++)
printf("%d, ", C[i]); // should print "2, 5, 10, 17, "
std::cin.ignore();
return 0;
}
Важно отметить, что я хочу создать эту оболочку, чтобы вызовы cuda были красиво упакованы, когда я выполняю поэлементные операции. Хотя это очень неполно, вот моя попытка псевдокода для оболочки функций.
Я хотел бы привести минимальный пример; тем не менее, я очень мало представляю, как работать с некоторыми аспектами C ++, поэтому, пожалуйста, простите большое количество прокомментированных псевдокодов:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <iostream>
// returns a*x + y
__device__ float saxpy(float a, float x, float y) {
return a*x + y;
}
// finds return type of function pointer
template<typename R, typename... A>
R ret(R(*)(A...));
template<typename C, typename R, typename... A>
R ret(R(C::*)(A...));
template<typename F, size_t N, typename... Args>
auto cudaReduce(F &f, Args(&...argsarray)[N]) {
cudaSetDevice(0);
// ret is function f's return type
typedef decltype(ret(f)) ret;
ret d_out[N], h_out[N];
// cudaMalloc((void**)&d_out, sizeof(d_out));
sendToCuda(argsarray...); // allocates and copies all contents of argsarray to cuda
// reduceKernel<<<1, N>>>(f, d_out, dev_argsarray...);
// cudaDeviceSynchronize();
// cudaMemcpy(h_out, d_out, sizeof(h_out), cudaMemcpyDeviceToHost);
// cudaFree(d_out);
// for d_args in d_argsarray
// cudaFree(d_args);
return h_out;
}
template<typename F, size_t N, typename Out, typename... Args>
__global__ void cudaReduceKernel(F &f, Out(&out)[N], Args(&...argsarray)[N]) {
int tid = threadIdx.x;
int i = tid + blockIdx.x * blockDim.x;
// Below is invalid syntax; however, the 'pseudo-code' is what I'd like to achieve.
// out[i] = f(argsarray[i]...);
}
// cuda malloc and memcpy
template<typename Arg, size_t N>
void sendToCuda(Arg(&args)[N]) {
size_t buffer = sizeof(args);
//cudaMalloc((void**)&dev_arg[ ??? ], buffer);
//cudaMemcpy((void**)&dev_arg[ ??? ], args, buffer, cudaMemcpyHostToDevice);
}
template<typename Arg, size_t N, typename... Args>
void sendToCuda(Arg(&args)[N], Args(&...argsarray)[N]) {
sendToCuda(args);
sendToCuda(argsarray...);
}
int main() {
int A[4] = { 1,2,3,4 };
int X[4] = { 1,2,3,4 };
int Y[4] = { 1,1,1,1 };
// A*X = 1,4,9,16
// A*X+Y = 2,5,10,17
float *C = cudaReduce(saxpy, A, X, Y);
for (int i = 0; i < 4; i++)
printf("%d, ", C[i]); // should print "2, 5, 10, 17, ", currently prints undefined behaviour
std::cin.ignore();
return 0;
}
Я понимаю, что не у всех есть время, чтобы полностью пересмотреть код, поэтому я буду разбивать ключевые проблемы на несколько пунктов:
1.
Можно ли дублировать входные данные шаблона, если да, то как?
EX (не реальный код):
template<typename... Args>
void foo(Args... args) {
Args... args2;
}
Это необходимо для того, чтобы я мог продублировать свои входные параметры для входных параметров для моего cuda malloc()
и memcpy()
.
2.
Как бы я сказал о i-м кортеже параметра массива variadic, например, о zipping в python.
EX (не реальный код):
template<typename... Args, size_t N>
void bar(Args(&...argsarray)[N]) {
// (python) ithvariadic = zip(*argsarray)[i]
auto ithvariadic = argsarray[i]...;
}