vrtsim: implement batched TX writes for channel modelling

- Move buffer allocation per-batch
- Convert and write per batch
- Fix saved_samples gap handling bug
This commit is contained in:
Merkebu Girmay
2026-02-09 23:23:10 -08:00
parent ccf5021072
commit a707094196
+26 -22
View File
@@ -450,11 +450,6 @@ static void perform_channel_modelling(void *arg)
int nb_tx_ant = channel_modelling_args->nbAnt; int nb_tx_ant = channel_modelling_args->nbAnt;
c16_t **input_samples = (c16_t **)channel_modelling_args->samples; c16_t **input_samples = (c16_t **)channel_modelling_args->samples;
int aligned_nsamps = ceil_mod(nsamps, (512 / 8) / sizeof(cf_t));
cf_t samples[aligned_nsamps] __attribute__((aligned(64)));
// Apply noise from global settings
get_noise_vector((float *)samples, nsamps * 2);
channel_desc_t *channel_desc = vrtsim_state->channel_desc; channel_desc_t *channel_desc = vrtsim_state->channel_desc;
if (channel_desc == NULL) { if (channel_desc == NULL) {
@@ -488,16 +483,25 @@ static void perform_channel_modelling(void *arg)
} }
for (int batch_index = 0; batch_index < channel_modelling_args->num_batches; batch_index++) { for (int batch_index = 0; batch_index < channel_modelling_args->num_batches; batch_index++) {
int start_sample = batch_index * channel_modelling_args->batch_size; const int start_sample = batch_index * channel_modelling_args->batch_size;
int num_samples = min(channel_modelling_args->batch_size, nsamps - start_sample); const int num_samples = min(channel_modelling_args->batch_size, nsamps - start_sample);
if (start_sample >= nsamps) { if (start_sample >= nsamps) {
break; break;
} }
const int aligned_batch = ceil_mod(num_samples, (512 / 8) / sizeof(cf_t));
cf_t samples[aligned_batch] __attribute__((aligned(64)));
memset(samples, 0, sizeof(samples));
// Apply noise from global settings (only valid samples)
get_noise_vector((float *)samples, num_samples * 2);
for (int aatx = 0; aatx < nb_tx_ant; aatx++) { for (int aatx = 0; aatx < nb_tx_ant; aatx++) {
for (int i = start_sample; i < start_sample + num_samples; i++) { cf_t *impulse_response = channel_impulse_response_p[aatx];
cf_t *impulse_response = channel_impulse_response_p[aatx]; for (int i = 0; i < num_samples; i++) {
const int gi = start_sample + i;
for (int l = 0; l < channel_desc->channel_length; l++) { for (int l = 0; l < channel_desc->channel_length; l++) {
int idx = i - l; const int idx = gi - l;
// TODO: Use AVX2 for this // TODO: Use AVX2 for this
c16_t tx_input = idx >= 0 ? input_samples[aatx][idx] c16_t tx_input = idx >= 0 ? input_samples[aatx][idx]
: channel_modelling_args->saved_samples[aatx][SAVED_SAMPLES_LEN + idx]; : channel_modelling_args->saved_samples[aatx][SAVED_SAMPLES_LEN + idx];
@@ -507,31 +511,32 @@ static void perform_channel_modelling(void *arg)
} }
} }
// Convert to c16_t // Convert to c16_t (only once per batch)
c16_t samples_out[aligned_nsamps] __attribute__((aligned(64))); c16_t samples_out[aligned_batch] __attribute__((aligned(64)));
#if defined(__AVX512F__) #if defined(__AVX512F__)
for (int i = 0; i < aligned_nsamps / 8; i++) { for (int i = 0; i < aligned_batch / 8; i++) {
simde__m512 *in = (simde__m512 *)&samples[i * 8]; simde__m512 *in = (simde__m512 *)&samples[i * 8];
simde__m256i *out = (simde__m256i *)&samples_out[i * 8]; simde__m256i *out = (simde__m256i *)&samples_out[i * 8];
*out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in)); *out = simde_mm512_cvtsepi32_epi16(simde_mm512_cvtps_epi32(*in));
} }
#elif defined(__AVX2__) #elif defined(__AVX2__)
for (int i = 0; i < aligned_nsamps / 4; i++) { for (int i = 0; i < aligned_batch / 4; i++) {
simde__m256 *in = (simde__m256 *)&samples[i * 4]; simde__m256 *in = (simde__m256 *)&samples[i * 4];
simde__m128i *out = (simde__m128i *)&samples_out[i * 4]; simde__m128i *out = (simde__m128i *)&samples_out[i * 4];
*out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in)); *out = simde_mm256_cvtsepi32_epi16(simde_mm256_cvtps_epi32(*in));
} }
#else #else
for (int i = 0; i < nsamps; i++) { for (int i = 0; i < num_samples; i++) {
samples_out[i].r = lroundf(samples[i].r); samples_out[i].r = lroundf(samples[i].r);
samples_out[i].i = lroundf(samples[i].i); samples_out[i].i = lroundf(samples[i].i);
} }
#endif #endif
// Write the batch as a single contiguous transfer
vrtsim_write_internal(channel_modelling_args->vrtsim_state, vrtsim_write_internal(channel_modelling_args->vrtsim_state,
channel_modelling_args->timestamp, channel_modelling_args->timestamp + start_sample,
samples_out, samples_out,
channel_modelling_args->nsamps, num_samples,
aarx, aarx,
channel_modelling_args->flags, channel_modelling_args->flags,
aarx); aarx);
@@ -582,7 +587,6 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state,
for (int aatx = 0; aatx < nbAnt; aatx++) for (int aatx = 0; aatx < nbAnt; aatx++)
memcpy(&args->saved_samples[aatx][0], saved_samples[aatx], sizeof(c16_t) * SAVED_SAMPLES_LEN); memcpy(&args->saved_samples[aatx][0], saved_samples[aatx], sizeof(c16_t) * SAVED_SAMPLES_LEN);
} }
memcpy(args->saved_samples, saved_samples, sizeof(saved_samples));
pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task); pushNotifiedFIFO(&vrtsim_state->channel_modelling_actors[aarx].fifo, task);
} }