Integrate CUDA Channel Pipeline into DL Simulator

This commit integrates the CUDA-based channel simulation pipeline into
the nr_dlsim.

A new `--cuda` command-line flag is added to enable the GPU path at
runtime. When activated, the simulator will:
- Allocate all necessary GPU and pinned host memory via the new
  `init_cuda_chsim_buffers` helper function.
- In the main simulation loop, call the `run_channel_pipeline_cuda`
  function to perform the channel simulation on the GPU, bypassing the
  CPU-based functions.
- Clean up all CUDA resources on exit using the
  `free_cuda_chsim_buffers` helper.
Additionally, dlsim is now using the float version of channel_multipath and add_noise functions.
Also, The input data is formatted as interleaved IQ, with separate antennas to ensure a fair comparison with the GPU operation.
This commit is contained in:
Nika Ghaderi
2026-02-23 13:14:26 +00:00
committed by Jaroslava Fiedlerova
parent 7fa4d018d4
commit 5fb9a9c665
3 changed files with 355 additions and 36 deletions
@@ -77,6 +77,153 @@ __global__ void sum_outputs_kernel(const short2 *__restrict__ *__restrict__ indi
}
extern "C" {
void init_cuda_chsim_buffers(int use_cuda,
int n_tx,
int n_rx,
void **d_tx_sig,
void **d_intermediate_sig,
void **d_final_output,
void **d_curand_states,
void **h_tx_sig_pinned,
void **h_final_output_pinned,
void **d_channel_coeffs_gpu)
{
if (use_cuda) {
int num_samples_alloc = 153600;
#if defined(USE_UNIFIED_MEMORY)
printf("Allocating CUDA Unified Memory...\n");
const int max_padding_alloc = 256 - 1;
size_t padded_tx_alloc_bytes = n_tx * (num_samples_alloc + max_padding_alloc) * 2 * sizeof(float);
CHECK_CUDA(cudaMallocManaged(d_tx_sig, padded_tx_alloc_bytes, cudaMemAttachGlobal));
CHECK_CUDA(cudaMallocManaged(d_intermediate_sig, n_rx * num_samples_alloc * sizeof(float) * 2, cudaMemAttachGlobal));
CHECK_CUDA(cudaMallocManaged(d_final_output, n_rx * num_samples_alloc * sizeof(short) * 2, cudaMemAttachGlobal));
*h_tx_sig_pinned = *d_tx_sig;
*h_final_output_pinned = *d_final_output;
int deviceId;
CHECK_CUDA(cudaGetDevice(&deviceId));
CHECK_CUDA(cudaMemAdvise(*d_tx_sig, padded_tx_alloc_bytes, cudaMemAdviseSetReadMostly, deviceId));
CHECK_CUDA(cudaMemAdvise(*d_intermediate_sig,
n_rx * num_samples_alloc * sizeof(float) * 2,
cudaMemAdviseSetPreferredLocation,
deviceId));
CHECK_CUDA(
cudaMemAdvise(*d_final_output, n_rx * num_samples_alloc * sizeof(short) * 2, cudaMemAdviseSetPreferredLocation, deviceId));
CHECK_CUDA(
cudaMemAdvise(*d_final_output, n_rx * num_samples_alloc * sizeof(short) * 2, cudaMemAdviseSetAccessedBy, cudaCpuDeviceId));
#elif defined(USE_ATS_MEMORY)
printf("Allocating memory for ATS Hybrid path...\n");
const int max_padding_alloc = 256 - 1;
size_t padded_tx_alloc_bytes = n_tx * (num_samples_alloc + max_padding_alloc) * 2 * sizeof(float);
*h_tx_sig_pinned = malloc(padded_tx_alloc_bytes);
CHECK_CUDA(cudaMalloc(d_intermediate_sig, n_rx * num_samples_alloc * sizeof(float) * 2));
CHECK_CUDA(cudaMalloc(d_final_output, n_rx * num_samples_alloc * sizeof(short) * 2));
*h_final_output_pinned = malloc(n_rx * num_samples_alloc * sizeof(short) * 2);
*d_tx_sig = NULL;
#else // Explicit copy method
printf("Pre-allocating GPU & Pinned memory for the channel pipeline...\n");
const int max_padding_alloc = 256 - 1;
size_t padded_tx_alloc_bytes = n_tx * (num_samples_alloc + max_padding_alloc) * 2 * sizeof(float);
CHECK_CUDA(cudaMalloc(d_tx_sig, padded_tx_alloc_bytes));
CHECK_CUDA(cudaMalloc(d_intermediate_sig, n_rx * num_samples_alloc * sizeof(float) * 2));
CHECK_CUDA(cudaMalloc(d_final_output, n_rx * num_samples_alloc * sizeof(short) * 2));
CHECK_CUDA(cudaMallocHost(h_tx_sig_pinned, padded_tx_alloc_bytes));
CHECK_CUDA(cudaMallocHost(h_final_output_pinned, n_rx * num_samples_alloc * sizeof(short) * 2));
#endif
const int max_taps_alloc = 256; // Upper bound for channel length
size_t channel_buffer_size = n_tx * n_rx * max_taps_alloc * sizeof(float) * 2;
CHECK_CUDA(cudaMalloc(d_channel_coeffs_gpu, channel_buffer_size));
int num_rand_elements = n_rx * num_samples_alloc;
*d_curand_states = create_and_init_curand_states_cuda(num_rand_elements, time(NULL));
}
}
void free_cuda_chsim_buffers(int use_cuda,
void **d_tx_sig_p,
void **d_intermediate_sig_p,
void **d_final_output_p,
void **d_curand_states_p,
void **h_tx_sig_pinned_p,
void **h_final_output_pinned_p,
float **h_channel_coeffs_p,
void **d_channel_coeffs_gpu_p)
{
if (use_cuda) {
printf("Freeing GPU and Pinned memory...\n");
#if defined(USE_UNIFIED_MEMORY)
if (*d_tx_sig_p) {
cudaFree(*d_tx_sig_p);
*d_tx_sig_p = NULL;
*h_tx_sig_pinned_p = NULL;
}
if (*d_intermediate_sig_p) {
cudaFree(*d_intermediate_sig_p);
*d_intermediate_sig_p = NULL;
}
if (*d_final_output_p) {
cudaFree(*d_final_output_p);
*d_final_output_p = NULL;
*h_final_output_pinned_p = NULL;
}
#elif defined(USE_ATS_MEMORY)
if (*h_tx_sig_pinned_p) {
free(*h_tx_sig_pinned_p);
*h_tx_sig_pinned_p = NULL;
}
if (*d_intermediate_sig_p) {
cudaFree(*d_intermediate_sig_p);
*d_intermediate_sig_p = NULL;
}
if (*d_final_output_p) {
cudaFree(*d_final_output_p);
*d_final_output_p = NULL;
}
if (*h_final_output_pinned_p) {
free(*h_final_output_pinned_p);
*h_final_output_pinned_p = NULL;
}
#else
if (*d_tx_sig_p) {
cudaFree(*d_tx_sig_p);
*d_tx_sig_p = NULL;
}
if (*d_intermediate_sig_p) {
cudaFree(*d_intermediate_sig_p);
*d_intermediate_sig_p = NULL;
}
if (*d_final_output_p) {
cudaFree(*d_final_output_p);
*d_final_output_p = NULL;
}
if (*h_tx_sig_pinned_p) {
cudaFreeHost(*h_tx_sig_pinned_p);
*h_tx_sig_pinned_p = NULL;
}
if (*h_final_output_pinned_p) {
cudaFreeHost(*h_final_output_pinned_p);
*h_final_output_pinned_p = NULL;
}
#endif
if (*d_channel_coeffs_gpu_p) {
cudaFree(*d_channel_coeffs_gpu_p);
*d_channel_coeffs_gpu_p = NULL;
}
destroy_curand_states_cuda(*d_curand_states_p);
*d_curand_states_p = NULL;
if (*h_channel_coeffs_p) {
free(*h_channel_coeffs_p);
*h_channel_coeffs_p = NULL;
}
} else {
if (*h_tx_sig_pinned_p) {
free(*h_tx_sig_pinned_p);
*h_tx_sig_pinned_p = NULL;
}
}
}
void run_channel_pipeline_cuda(c16_t **output_signal,
int nb_tx,
int nb_rx,
+21
View File
@@ -59,6 +59,27 @@ __global__ void add_noise_and_phase_noise_kernel(const float2 *__restrict__ r_si
extern "C" {
#endif
void init_cuda_chsim_buffers(int use_cuda,
int n_tx,
int n_rx,
void **d_tx_sig_p,
void **d_intermediate_sig_p,
void **d_final_output_p,
void **d_curand_states_p,
void **h_tx_sig_pinned_p,
void **h_final_output_pinned_p,
void **d_channel_coeffs_gpu_p);
void free_cuda_chsim_buffers(int use_cuda,
void **d_tx_sig_p,
void **d_intermediate_sig_p,
void **d_final_output_p,
void **d_curand_states_p,
void **h_tx_sig_pinned_p,
void **h_final_output_pinned_p,
float **h_channel_coeffs_p,
void **d_channel_coeffs_gpu_p);
void multipath_channel_cuda(float **rx_sig_re,
float **rx_sig_im,
int nb_tx,