Use a bounce buffer for rtlsdr on ARM to work around zero-copy problems.

On 5.x kernels with the USB mmap problems fixed, the distributed librtlsdr
will use a zero-copy mapping for USB buffers. Unfortunately, there is
something about the nature of the mapping on ARM (at least on Pis) that
makes most access to the data extremely slow. The uc8_nodc converter is
about 35x slower in this case compared to working on a heap-allocated buffer.

Luckily, a plain memcpy() of the buffer is still reasonably fast, so
we can use a bounce buffer and copy the data out of the slow mapping, then
pass the copy to the converter. This mitigates most of the problem,
at the expense of always needing that extra copy (which does somewhat
defeat the purpose of zero-copy!)

Unfortunately, librtlsdr provides no reliable way to control or
detect the use of zero-copy mappings, so we have to assume the problem
is always there (at least on ARM) and pay the cost of an unnecessary
copy when zerocopy is _not_ in use, too.
This commit is contained in:
Oliver Jowett 2020-08-05 19:41:46 +08:00
parent d5d04060de
commit 653ad6127a
1 changed files with 23 additions and 3 deletions

View File

@ -53,12 +53,17 @@
#include <rtl-sdr.h>
#ifdef __arm__
// Assume we need to use a bounce buffer to avoid performance problems on Pis running kernel 5.x and using zerocopy
# define USE_BOUNCE_BUFFER
#endif
static struct {
rtlsdr_dev_t *dev;
bool digital_agc;
int ppm_error;
int direct_sampling;
uint8_t *bounce_buffer;
iq_convert_fn converter;
struct converter_state *converter_state;
} RTLSDR;
@ -73,6 +78,7 @@ void rtlsdrInitConfig()
RTLSDR.digital_agc = false;
RTLSDR.ppm_error = 0;
RTLSDR.direct_sampling = 0;
RTLSDR.bounce_buffer = NULL;
RTLSDR.converter = NULL;
RTLSDR.converter_state = NULL;
}
@ -262,6 +268,14 @@ bool rtlsdrOpen(void) {
return false;
}
#ifdef USE_BOUNCE_BUFFER
if (!(RTLSDR.bounce_buffer = malloc(MODES_RTL_BUF_SIZE))) {
fprintf(stderr, "rtlsdr: can't allocate bounce buffer\n");
rtlsdrClose();
return false;
}
#endif
return true;
}
@ -317,10 +331,13 @@ static void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx)
dropped = samples_read - to_convert;
}
#ifdef USE_BOUNCE_BUFFER
// Work around zero-copy slowness on Pis with 5.x kernels
memcpy(RTLSDR.bounce_buffer, buf, to_convert * 2);
buf = RTLSDR.bounce_buffer;
#endif
RTLSDR.converter(buf, &outbuf->data[outbuf->overlap], to_convert, RTLSDR.converter_state, &outbuf->mean_level, &outbuf->mean_power);
outbuf->validLength = outbuf->overlap + to_convert;
// Push to the demodulation thread
@ -353,4 +370,7 @@ void rtlsdrClose()
RTLSDR.converter = NULL;
RTLSDR.converter_state = NULL;
}
free(RTLSDR.bounce_buffer);
RTLSDR.bounce_buffer = NULL;
}