Currently timeout and buffer size are hard-coded in the fx2lawfw driver which is
non-optimal if we want to get good results at both high and low sample rates.
The timeout is hard-coded to 40ms, which does not work well when sampling at with
a low sample rate. E.g. at 20kHz filling all available buffer space alone takes
6 seconds. So naturally we'll see a lot of transfers timeout in this case.
The buffer size is hard-coded to 4096 bytes, which does not work well with high
sample rates. E.g. at 24MHz these 4096 bytes are enough space for 0.17 ms of
data. The total buffer size is enough for about 5ms of data. Sooner or later the
application wont be able to resubmit a transfer within this time span and the
device will abort data acquisition. Usually this happens within the first few
seconds of sampling.
This patch adds a few new helper functions which calculate the buffer size and
timeout based on the current sample rate.
The buffer size is chosen to be large enough to hold about 10ms of data and it
also must be a multiple of 512 bytes since the firmware will send us the data in
512 chunks.
The timeout is set to the time it would take to fill the whole available buffer
space plus a 25% headroom to accommodate for jitter. This more than enough, but
there is no need to make the timeout a tight deadline, since it is only meant as
a last resort in case the device stops submitting data. And in this case data
acquisition will be aborted anyway.
The patch also limits the the number of transfers so that the total buffer space
is not much more of 500 ms, this will ensure that we do not have to wait too
long when aborting data acquisition.
This patch also significantly reduces the number of context switches when
sampling at a higher sample rate. On my system for example the CPU load of
sigrok-cli when sampling at 24Mhz goes down from ~25% to 3-4%.
Signed-off-by: Lars-Peter Clausen <lars@...>
---
libsigrok/hardware/fx2lafw/fx2lafw.c | 67 +++++++++++++++++++++++-----------
1 file changed, 46 insertions(+), 21 deletions(-)
diff --git a/libsigrok/hardware/fx2lafw/fx2lafw.c b/libsigrok/hardware/fx2lafw/fx2lafw.c
index b56f810..40b9823 100644
--- a/libsigrok/hardware/fx2lafw/fx2lafw.c
+++ b/libsigrok/hardware/fx2lafw/fx2lafw.c
@@ -686,20 +686,6 @@ static void free_transfer(struct libusb_transfer *transfer)
static void resubmit_transfer(struct libusb_transfer *transfer)
{
- uint8_t *new_buf;
-
- /* Increase buffer size to 4096 */
- if (transfer->length != 4096) {
- new_buf = g_try_malloc(4096);
- /* If allocation of the new buffer fails, just vdo not bother and
- * continue to use the old one. */
- if (new_bufer) {
- g_free(transfer->buffer);
- transfer->buffer = new_buf;
- transfer->length = 4096;
- }
- }
-
if (libusb_submit_transfer(transfer) != 0) {
free_transfer(transfer);
/* TODO: Stop session? */
@@ -848,6 +834,43 @@ static void receive_transfer(struct libusb_transfer *transfer)
resubmit_transfer(transfer);
}
+static size_t get_buffer_size(struct context *ctx)
+{
+ size_t s;
+
+ /* The buffer should be large enough to hold 10ms of data and a multiple
+ * of 512. */
+ s = ctx->cur_samplerate / 100;
+ s = (s + 511) & ~511;
+
+ return s;
+}
+
+static unsigned int get_number_of_transfers(struct context *ctx)
+{
+ unsigned int n;
+
+ /* Total buffer size should be able to hold about 500ms of data */
+ n = ctx->cur_samplerate / get_buffer_size(ctx) / 2;
+
+ if (n > NUM_SIMUL_TRANSFERS)
+ return NUM_SIMUL_TRANSFERS;
+
+ return n;
+}
+
+static unsigned int get_timeout(struct context *ctx)
+{
+ size_t total_size;
+ unsigned int timeout;
+
+ total_size = get_buffer_size(ctx) * get_number_of_transfers(ctx);
+ timeout = total_size / (ctx->cur_samplerate / 1000);
+ timeout += timeout / 4; /* Leave a headroom of 25% percent */
+
+ return timeout;
+}
+
static int hw_dev_acquisition_start(int dev_index, void *cb_data)
{
struct sr_dev_inst *sdi;
@@ -857,7 +880,9 @@ static int hw_dev_acquisition_start(int dev_index, void *cb_data)
struct context *ctx;
struct libusb_transfer *transfer;
const struct libusb_pollfd **lupfd;
- int ret, size, i;
+ unsigned int num_transfers, i;
+ unsigned int timeout;
+ int ret, size;
unsigned char *buf;
if (!(sdi = sr_dev_inst_get(dev_insts, dev_index)))
@@ -866,9 +891,10 @@ static int hw_dev_acquisition_start(int dev_index, void *cb_data)
ctx->session_dev_id = cb_data;
ctx->num_samples = 0;
- /* Start with 2K transfer, subsequently increased to 4K. */
- size = 2048;
- for (i = 0; i < NUM_SIMUL_TRANSFERS; i++) {
+ size = get_buffer_size(ctx);
+ num_transfers = get_number_of_transfers(ctx);
+ timeout = get_timeout(ctx);
+ for (i = 0; i < num_transfers; i++) {
if (!(buf = g_try_malloc(size))) {
sr_err("fx2lafw: %s: buf malloc failed.", __func__);
return SR_ERR_MALLOC;
@@ -876,7 +902,7 @@ static int hw_dev_acquisition_start(int dev_index, void *cb_data)
transfer = libusb_alloc_transfer(0);
libusb_fill_bulk_transfer(transfer, ctx->usb->devhdl,
2 | LIBUSB_ENDPOINT_IN, buf, size,
- receive_transfer, ctx, 40);
+ receive_transfer, ctx, timeout);
if (libusb_submit_transfer(transfer) != 0) {
/* TODO: Free them all. */
libusb_free_transfer(transfer);
@@ -885,13 +911,12 @@ static int hw_dev_acquisition_start(int dev_index, void *cb_data)
}
ctx->submitted_transfers++;
- size = 4096;
}
lupfd = libusb_get_pollfds(usb_context);
for (i = 0; lupfd[i]; i++)
sr_source_add(lupfd[i]->fd, lupfd[i]->events,
- 40, receive_data, NULL);
+ timeout, receive_data, NULL);
free(lupfd); /* NOT g_free()! */
packet.type = SR_DF_HEADER;
--
1.7.10
|