Added two versions of channel convolution and noise generation: - accelerated via threadpool - accelerated using CUDA The main difference between this and previous versions of channel convolution implementations is that these functions take a real-world approach to input/output where both could be split unevenly over a set of buffers, e.g. ring buffers used in vrtsim. The CUDA-accelerated version only works on systems with unified memory, e.g. NVidia DGX Spark or GH
240 lines
6.5 KiB
C++
240 lines
6.5 KiB
C++
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cmath>
|
|
#include <vector>
|
|
#include <time.h>
|
|
#include <getopt.h>
|
|
#include "oai_cuda.h"
|
|
#include "common/config/config_userapi.h"
|
|
#include <memory>
|
|
#include "benchmark/benchmark.h"
|
|
#include "test_channel_pipeline_tools.h"
|
|
#include "channel_pipeline.h"
|
|
extern "C" {
|
|
#include "openair1/SIMULATION/TOOLS/sim.h"
|
|
}
|
|
configmodule_interface_t *uniqCfg = NULL;
|
|
|
|
extern "C" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
|
{
|
|
fprintf(stderr, "FATAL: %s at %s:%s:%d\n", s, file, function, line);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
#ifdef CUDA_ENABLE
|
|
static void BM_channel_convolution_gpu(benchmark::State &state)
|
|
{
|
|
int nb_rx = state.range(0);
|
|
int nb_tx = state.range(1);
|
|
int num_samples = state.range(2);
|
|
int channel_length = 16;
|
|
|
|
size_t num_input_samples = num_samples + channel_length - 1;
|
|
std::vector<c16_t *> input(nb_tx);
|
|
for (int i = 0; i < nb_tx; ++i) {
|
|
input[i] = new c16_t[num_input_samples];
|
|
}
|
|
|
|
std::vector<c16_t *> output(nb_rx);
|
|
for (int i = 0; i < nb_rx; ++i) {
|
|
output[i] = new c16_t[num_samples];
|
|
}
|
|
|
|
std::vector<cf_t *> channel(nb_rx * nb_tx);
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i) {
|
|
channel[i] = new cf_t[channel_length];
|
|
}
|
|
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i) {
|
|
generate_random_signal_float(channel[i], channel_length);
|
|
}
|
|
|
|
void *gpu_context = cuda_channel_pipeline_init(61440 * 4);
|
|
|
|
for (int aatx = 0; aatx < nb_tx; aatx++) {
|
|
generate_random_signal(input[aatx], num_input_samples);
|
|
}
|
|
|
|
size_t total_samples = 0;
|
|
for (auto _ : state) {
|
|
cuda_channel_pipeline(gpu_context,
|
|
(const cf_t **)channel.data(),
|
|
(const c16_t **)input.data(),
|
|
nullptr,
|
|
num_input_samples,
|
|
output.data(),
|
|
nullptr,
|
|
num_samples,
|
|
num_samples,
|
|
channel_length,
|
|
nb_tx,
|
|
nb_rx,
|
|
0.0f);
|
|
total_samples += num_samples;
|
|
}
|
|
state.counters["MSPS"] = benchmark::Counter(total_samples / 1000000.f, benchmark::Counter::kIsRate);
|
|
|
|
cuda_channel_pipeline_shutdown(gpu_context);
|
|
}
|
|
#endif
|
|
|
|
static void BM_channel_convolution_cpu(benchmark::State &state)
|
|
{
|
|
int nb_rx = state.range(0);
|
|
int nb_tx = state.range(1);
|
|
int num_samples = state.range(2);
|
|
int channel_length = 16;
|
|
|
|
size_t num_input_samples = num_samples + channel_length - 1;
|
|
std::vector<c16_t *> input(nb_tx);
|
|
for (int i = 0; i < nb_tx; ++i) {
|
|
input[i] = new c16_t[num_input_samples];
|
|
}
|
|
|
|
std::vector<c16_t *> output(nb_rx);
|
|
for (int i = 0; i < nb_rx; ++i) {
|
|
output[i] = new c16_t[num_samples];
|
|
}
|
|
|
|
std::vector<cf_t *> channel(nb_rx * nb_tx);
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i) {
|
|
channel[i] = new cf_t[channel_length];
|
|
}
|
|
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i) {
|
|
generate_random_signal_float(channel[i], channel_length);
|
|
}
|
|
for (int aatx = 0; aatx < nb_tx; aatx++) {
|
|
generate_random_signal(input[aatx], num_input_samples);
|
|
}
|
|
|
|
size_t total_samples = 0;
|
|
for (auto _ : state) {
|
|
channel_convolution_cpu((const cf_t **)channel.data(),
|
|
(const c16_t **)input.data(),
|
|
nullptr,
|
|
num_input_samples,
|
|
output.data(),
|
|
nullptr,
|
|
num_samples,
|
|
num_samples,
|
|
channel_length,
|
|
nb_tx,
|
|
nb_rx);
|
|
total_samples += num_samples;
|
|
}
|
|
state.counters["MSPS"] = benchmark::Counter(total_samples / 1000000.0f, benchmark::Counter::kIsRate);
|
|
|
|
for (int i = 0; i < nb_tx; ++i)
|
|
delete[] input[i];
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i)
|
|
delete[] channel[i];
|
|
for (int i = 0; i < nb_rx; ++i) {
|
|
delete[] output[i];
|
|
}
|
|
}
|
|
|
|
static void BM_channel_convolution_tpool(benchmark::State &state)
|
|
{
|
|
int nb_rx = state.range(0);
|
|
int nb_tx = state.range(1);
|
|
int num_samples = state.range(2);
|
|
int channel_length = 16;
|
|
|
|
size_t num_input_samples = num_samples + channel_length - 1;
|
|
std::vector<c16_t *> input(nb_tx);
|
|
for (int i = 0; i < nb_tx; ++i) {
|
|
input[i] = new c16_t[num_input_samples];
|
|
}
|
|
|
|
std::vector<c16_t *> output(nb_rx);
|
|
for (int i = 0; i < nb_rx; ++i) {
|
|
output[i] = new c16_t[num_samples];
|
|
}
|
|
|
|
std::vector<cf_t *> channel(nb_rx * nb_tx);
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i) {
|
|
channel[i] = new cf_t[channel_length];
|
|
}
|
|
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i) {
|
|
generate_random_signal_float(channel[i], channel_length);
|
|
}
|
|
for (int aatx = 0; aatx < nb_tx; aatx++) {
|
|
generate_random_signal(input[aatx], num_input_samples);
|
|
}
|
|
|
|
void *tpool = init_tpool(16);
|
|
channel_pipeline_init(0.0f);
|
|
|
|
size_t total_samples = 0;
|
|
for (auto _ : state) {
|
|
channel_pipeline(tpool,
|
|
(const cf_t **)channel.data(),
|
|
(const c16_t **)input.data(),
|
|
nullptr,
|
|
num_input_samples,
|
|
output.data(),
|
|
nullptr,
|
|
num_samples,
|
|
num_samples,
|
|
channel_length,
|
|
nb_tx,
|
|
nb_rx,
|
|
0.0f);
|
|
total_samples += num_samples;
|
|
}
|
|
state.counters["MSPS"] = benchmark::Counter(total_samples / 1000000.f, benchmark::Counter::kIsRate);
|
|
|
|
channel_pipeline_shutdown();
|
|
|
|
destroy_tpool(tpool);
|
|
|
|
for (int i = 0; i < nb_tx; ++i)
|
|
delete[] input[i];
|
|
for (int i = 0; i < nb_rx * nb_tx; ++i)
|
|
delete[] channel[i];
|
|
for (int i = 0; i < nb_rx; ++i) {
|
|
delete[] output[i];
|
|
}
|
|
}
|
|
|
|
#ifdef CUDA_ENABLE
|
|
BENCHMARK(BM_channel_convolution_gpu)
|
|
->ArgsProduct({
|
|
{1, 2, 4, 16, 64}, // nb_rx
|
|
{1, 2, 4, 16, 64}, // nb_tx
|
|
{61440}, // num_samples
|
|
})
|
|
->Iterations(100);
|
|
#endif
|
|
|
|
BENCHMARK(BM_channel_convolution_cpu)
|
|
->ArgsProduct({
|
|
{1, 2, 4}, // nb_rx
|
|
{1, 2, 4}, // nb_tx
|
|
{61440}, // num_samples
|
|
})
|
|
->Iterations(50);
|
|
|
|
BENCHMARK(BM_channel_convolution_tpool)
|
|
->ArgsProduct({
|
|
{1, 2, 4, 8, 16}, // nb_rx
|
|
{1, 2, 4, 8, 16}, // nb_tx
|
|
{61440}, // num_samples
|
|
})
|
|
->Iterations(50);
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
logInit();
|
|
randominit();
|
|
benchmark::Initialize(&argc, argv);
|
|
benchmark::RunSpecifiedBenchmarks();
|
|
return 0;
|
|
}
|