From: Lars-Peter Clausen Date: Mon, 25 Jun 2012 20:15:59 +0000 (+0200) Subject: sr: fx2lafw: Calculate buffer size and timeout based on sample rate X-Git-Tag: dsupstream~891 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=5af666a94e67e8a18c0dfa1f4314e1c3e93aa993;p=libsigrok.git sr: fx2lafw: Calculate buffer size and timeout based on sample rate Currently timeout and buffer size are hard-coded in the fx2lafw 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 doesn't work well when sampling at 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.17ms of data. The total buffer size is enough for about 5ms of data. Sooner or later the application won't 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 byte 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 is 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 500ms. 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 --- diff --git a/hardware/fx2lafw/fx2lafw.c b/hardware/fx2lafw/fx2lafw.c index fce5472b..90434796 100644 --- a/hardware/fx2lafw/fx2lafw.c +++ b/hardware/fx2lafw/fx2lafw.c @@ -698,20 +698,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_buf) { - g_free(transfer->buffer); - transfer->buffer = new_buf; - transfer->length = 4096; - } - } - if (libusb_submit_transfer(transfer) != 0) { free_transfer(transfer); /* TODO: Stop session? */ @@ -860,6 +846,44 @@ static void receive_transfer(struct libusb_transfer *transfer) resubmit_transfer(transfer); } +static unsigned int to_bytes_per_ms(unsigned int samplerate) +{ + return samplerate / 1000; +} + +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 = 10 * to_bytes_per_ms(ctx->cur_samplerate); + return (s + 511) & ~511; +} + +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 = 500 * to_bytes_per_ms(ctx->cur_samplerate) / get_buffer_size(ctx); + + 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 / to_bytes_per_ms(ctx->cur_samplerate); + return timeout + timeout / 4; /* Leave a headroom of 25% percent */ +} + static int hw_dev_acquisition_start(int dev_index, void *cb_data) { struct sr_dev_inst *sdi; @@ -869,7 +893,8 @@ 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 i; + int ret; unsigned char *buf; if (!(sdi = sr_dev_inst_get(dev_insts, dev_index))) @@ -878,9 +903,11 @@ 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++) { + const unsigned int timeout = get_timeout(ctx); + const unsigned int num_transfers = get_number_of_transfers(ctx); + const size_t size = get_buffer_size(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; @@ -888,7 +915,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); @@ -897,13 +924,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;