Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 108 additions & 83 deletions backends/tfhe-cuda-backend/cuda/src/fft128/fft128.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -769,34 +769,44 @@ __host__ void host_fourier_transform_forward_as_integer_f128(
double *im0, double *im1, const __uint128_t *standard, const uint32_t N,
const uint32_t number_of_samples) {

// allocate device buffers
double *d_re0 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_re1 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_im0 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_im1 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
__uint128_t *d_standard = (__uint128_t *)cuda_malloc_async(
safe_mul_sizeof<__uint128_t>(N), stream, gpu_index);
// allocate device buffers; each kernel block processes its own sample, so
// every buffer is sized for the whole batch
size_t re_im_size = safe_mul_sizeof<double>(
static_cast<size_t>(number_of_samples), static_cast<size_t>(N / 2));
size_t standard_size = safe_mul_sizeof<__uint128_t>(
static_cast<size_t>(number_of_samples), static_cast<size_t>(N));
double *d_re0 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_re1 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_im0 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_im1 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
__uint128_t *d_standard = static_cast<__uint128_t *>(
cuda_malloc_async(standard_size, stream, gpu_index));

// copy input into device
cuda_memcpy_async_to_gpu(d_standard, standard,
safe_mul_sizeof<__uint128_t>(N), stream, gpu_index);
cuda_memcpy_async_to_gpu(d_standard, standard, standard_size, stream,
gpu_index);

// setup launch parameters
size_t required_shared_memory_size =
safe_mul_sizeof<double>((size_t)(N / 2), (size_t)4);
size_t required_shared_memory_size = safe_mul_sizeof<double>(
static_cast<size_t>(N / 2), static_cast<size_t>(4));
int grid_size = number_of_samples;
int block_size = params::degree / params::opt;
bool full_sm =
(required_shared_memory_size <= cuda_get_max_shared_memory(gpu_index));
size_t buffer_size =
full_sm ? 0
: safe_mul((size_t)number_of_samples, (size_t)(N / 2), (size_t)4);
size_t shared_memory_size = full_sm ? required_shared_memory_size : 0;
double *buffer = (double *)cuda_malloc_async(buffer_size, stream, gpu_index);
// global scratch is only needed by the NOSM kernel variant, when the FFT
// working set does not fit in shared memory; each block uses one
// shared-memory-sized slice of it
double *buffer = full_sm
? nullptr
: static_cast<double *>(cuda_malloc_async(
safe_mul(static_cast<size_t>(number_of_samples),
required_shared_memory_size),
stream, gpu_index));

// configure shared memory for batch fft kernel
if (full_sm) {
Expand Down Expand Up @@ -826,20 +836,17 @@ __host__ void host_fourier_transform_forward_as_integer_f128(
}
check_cuda_error(cudaGetLastError());

cuda_memcpy_async_to_cpu(re0, d_re0, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(re1, d_re1, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(im0, d_im0, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(im1, d_im1, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(re0, d_re0, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_cpu(re1, d_re1, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_cpu(im0, d_im0, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_cpu(im1, d_im1, re_im_size, stream, gpu_index);

cuda_drop_async(d_standard, stream, gpu_index);
cuda_drop_async(d_re0, stream, gpu_index);
cuda_drop_async(d_re1, stream, gpu_index);
cuda_drop_async(d_im0, stream, gpu_index);
cuda_drop_async(d_im1, stream, gpu_index);
cuda_drop_async(buffer, stream, gpu_index);
}

template <class params>
Expand All @@ -848,34 +855,44 @@ __host__ void host_fourier_transform_forward_as_torus_f128(
double *im0, double *im1, const __uint128_t *standard, const uint32_t N,
const uint32_t number_of_samples) {

// allocate device buffers
double *d_re0 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_re1 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_im0 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_im1 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
__uint128_t *d_standard = (__uint128_t *)cuda_malloc_async(
safe_mul_sizeof<__uint128_t>(N), stream, gpu_index);
// allocate device buffers; each kernel block processes its own sample, so
// every buffer is sized for the whole batch
size_t re_im_size = safe_mul_sizeof<double>(
static_cast<size_t>(number_of_samples), static_cast<size_t>(N / 2));
size_t standard_size = safe_mul_sizeof<__uint128_t>(
static_cast<size_t>(number_of_samples), static_cast<size_t>(N));
double *d_re0 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_re1 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_im0 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_im1 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
__uint128_t *d_standard = static_cast<__uint128_t *>(
cuda_malloc_async(standard_size, stream, gpu_index));

// copy input into device
cuda_memcpy_async_to_gpu(d_standard, standard,
safe_mul_sizeof<__uint128_t>(N), stream, gpu_index);
cuda_memcpy_async_to_gpu(d_standard, standard, standard_size, stream,
gpu_index);

// setup launch parameters
size_t required_shared_memory_size =
safe_mul_sizeof<double>((size_t)(N / 2), (size_t)4);
size_t required_shared_memory_size = safe_mul_sizeof<double>(
static_cast<size_t>(N / 2), static_cast<size_t>(4));
int grid_size = number_of_samples;
int block_size = params::degree / params::opt;
bool full_sm =
(required_shared_memory_size <= cuda_get_max_shared_memory(gpu_index));
size_t buffer_size =
full_sm ? 0
: safe_mul((size_t)number_of_samples, (size_t)(N / 2), (size_t)4);
size_t shared_memory_size = full_sm ? required_shared_memory_size : 0;
double *buffer = (double *)cuda_malloc_async(buffer_size, stream, gpu_index);
// global scratch is only needed by the NOSM kernel variant, when the FFT
// working set does not fit in shared memory; each block uses one
// shared-memory-sized slice of it
double *buffer = full_sm
? nullptr
: static_cast<double *>(cuda_malloc_async(
safe_mul(static_cast<size_t>(number_of_samples),
required_shared_memory_size),
stream, gpu_index));

// configure shared memory for batch fft kernel
if (full_sm) {
Expand All @@ -891,6 +908,7 @@ __host__ void host_fourier_transform_forward_as_torus_f128(
batch_convert_u128_to_f128_as_torus<params>
<<<grid_size, block_size, 0, stream>>>(d_re0, d_re1, d_im0, d_im1,
d_standard);
check_cuda_error(cudaGetLastError());

// call negacyclic 128 bit forward fft.
if (full_sm) {
Expand All @@ -902,21 +920,19 @@ __host__ void host_fourier_transform_forward_as_torus_f128(
<<<grid_size, block_size, shared_memory_size, stream>>>(
d_re0, d_re1, d_im0, d_im1, d_re0, d_re1, d_im0, d_im1, buffer);
}
check_cuda_error(cudaGetLastError());

cuda_memcpy_async_to_cpu(re0, d_re0, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(re1, d_re1, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(im0, d_im0, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(im1, d_im1, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_cpu(re0, d_re0, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_cpu(re1, d_re1, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_cpu(im0, d_im0, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_cpu(im1, d_im1, re_im_size, stream, gpu_index);

cuda_drop_async(d_standard, stream, gpu_index);
cuda_drop_async(d_re0, stream, gpu_index);
cuda_drop_async(d_re1, stream, gpu_index);
cuda_drop_async(d_im0, stream, gpu_index);
cuda_drop_async(d_im1, stream, gpu_index);
cuda_drop_async(buffer, stream, gpu_index);
}

template <class params>
Expand All @@ -925,40 +941,46 @@ __host__ void host_fourier_transform_backward_as_torus_f128(
double const *re0, double const *re1, double const *im0, double const *im1,
const uint32_t N, const uint32_t number_of_samples) {

// allocate device buffers
double *d_re0 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_re1 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_im0 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
double *d_im1 = (double *)cuda_malloc_async(safe_mul_sizeof<double>(N / 2),
stream, gpu_index);
__uint128_t *d_standard = (__uint128_t *)cuda_malloc_async(
safe_mul_sizeof<__uint128_t>(N), stream, gpu_index);

// // copy input into device
cuda_memcpy_async_to_gpu(d_re0, re0, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_gpu(d_re1, re1, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_gpu(d_im0, im0, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
cuda_memcpy_async_to_gpu(d_im1, im1, safe_mul_sizeof<double>(N / 2), stream,
gpu_index);
// allocate device buffers; each kernel block processes its own sample, so
// every buffer is sized for the whole batch
size_t re_im_size = safe_mul_sizeof<double>(
static_cast<size_t>(number_of_samples), static_cast<size_t>(N / 2));
size_t standard_size = safe_mul_sizeof<__uint128_t>(
static_cast<size_t>(number_of_samples), static_cast<size_t>(N));
double *d_re0 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_re1 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_im0 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
double *d_im1 =
static_cast<double *>(cuda_malloc_async(re_im_size, stream, gpu_index));
__uint128_t *d_standard = static_cast<__uint128_t *>(
cuda_malloc_async(standard_size, stream, gpu_index));

// copy input into device
cuda_memcpy_async_to_gpu(d_re0, re0, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_gpu(d_re1, re1, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_gpu(d_im0, im0, re_im_size, stream, gpu_index);
cuda_memcpy_async_to_gpu(d_im1, im1, re_im_size, stream, gpu_index);

// setup launch parameters
size_t required_shared_memory_size =
safe_mul_sizeof<double>((size_t)(N / 2), (size_t)4);
size_t required_shared_memory_size = safe_mul_sizeof<double>(
static_cast<size_t>(N / 2), static_cast<size_t>(4));
int grid_size = number_of_samples;
int block_size = params::degree / params::opt;
bool full_sm =
(required_shared_memory_size <= cuda_get_max_shared_memory(gpu_index));
size_t buffer_size =
full_sm ? 0
: safe_mul((size_t)number_of_samples, (size_t)(N / 2), (size_t)4);
size_t shared_memory_size = full_sm ? required_shared_memory_size : 0;
double *buffer = (double *)cuda_malloc_async(buffer_size, stream, gpu_index);
// global scratch is only needed by the NOSM kernel variant, when the FFT
// working set does not fit in shared memory; each block uses one
// shared-memory-sized slice of it
double *buffer = full_sm
? nullptr
: static_cast<double *>(cuda_malloc_async(
safe_mul(static_cast<size_t>(number_of_samples),
required_shared_memory_size),
stream, gpu_index));

// configure shared memory for batch fft kernel
if (full_sm) {
Expand All @@ -976,18 +998,21 @@ __host__ void host_fourier_transform_backward_as_torus_f128(
<<<grid_size, block_size, shared_memory_size, stream>>>(
d_re0, d_re1, d_im0, d_im1, d_re0, d_re1, d_im0, d_im1, buffer);
}
check_cuda_error(cudaGetLastError());

batch_convert_f128_to_u128_as_torus<params>
<<<grid_size, block_size, 0, stream>>>(d_standard, d_re0, d_re1, d_im0,
d_im1);
check_cuda_error(cudaGetLastError());

cuda_memcpy_async_to_cpu(standard, d_standard,
safe_mul_sizeof<__uint128_t>(N), stream, gpu_index);
cuda_memcpy_async_to_cpu(standard, d_standard, standard_size, stream,
gpu_index);
cuda_drop_async(d_standard, stream, gpu_index);
cuda_drop_async(d_re0, stream, gpu_index);
cuda_drop_async(d_re1, stream, gpu_index);
cuda_drop_async(d_im0, stream, gpu_index);
cuda_drop_async(d_im1, stream, gpu_index);
cuda_drop_async(buffer, stream, gpu_index);
}

#undef NEG_TWID
Expand Down