From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33010) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZtXTF-0005pf-PH for qemu-devel@nongnu.org; Tue, 03 Nov 2015 04:01:43 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZtXTD-0006qb-Tk for qemu-devel@nongnu.org; Tue, 03 Nov 2015 04:01:37 -0500 Received: from mx-v6.kamp.de ([2a02:248:0:51::16]:48216 helo=mx01.kamp.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZtXTD-0006qV-LO for qemu-devel@nongnu.org; Tue, 03 Nov 2015 04:01:35 -0500 From: Peter Lieven Date: Tue, 3 Nov 2015 10:01:15 +0100 Message-Id: <1446541276-32467-2-git-send-email-pl@kamp.de> In-Reply-To: <1446541276-32467-1-git-send-email-pl@kamp.de> References: <1446541276-32467-1-git-send-email-pl@kamp.de> Subject: [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: Peter Lieven , kraxel@redhat.com the idea behind this patch is to allow the buffer to shrink, but make this a seldom operation. The buffers average size is measured exponentionally smoothed with am alpha of 1/128. Signed-off-by: Peter Lieven --- include/io/buffer.h | 1 + io/buffer.c | 42 +++++++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/include/io/buffer.h b/include/io/buffer.h index f6668cb..f63869e 100644 --- a/include/io/buffer.h +++ b/include/io/buffer.h @@ -37,6 +37,7 @@ struct QIOBuffer { char *name; size_t capacity; size_t offset; + uint64_t avg_size; uint8_t *buffer; }; diff --git a/io/buffer.c b/io/buffer.c index 0fd3cea..d2a6043 100644 --- a/io/buffer.c +++ b/io/buffer.c @@ -23,6 +23,10 @@ #define QIO_BUFFER_MIN_INIT_SIZE 4096 #define QIO_BUFFER_MIN_SHRINK_SIZE 65536 +/* define the factor alpha for the expentional smoothing + * that is used in the average size calculation. a shift + * of 7 results in an alpha of 1/2^7. */ +#define QIO_BUFFER_AVG_SIZE_SHIFT 7 static size_t buf_req_size(QIOBuffer *buffer, size_t len) { @@ -37,6 +41,11 @@ static void buf_adj_size(QIOBuffer *buffer, size_t len) buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); trace_qio_buffer_resize(buffer->name ?: "unnamed", old, buffer->capacity); + + /* make it even harder for the buffer to shrink, reset average size + * to currenty capacity if it is larger than the average. */ + buffer->avg_size = MAX(buffer->avg_size, + buffer->capacity << QIO_BUFFER_AVG_SIZE_SHIFT); } void qio_buffer_init(QIOBuffer *buffer, const char *name, ...) @@ -48,21 +57,34 @@ void qio_buffer_init(QIOBuffer *buffer, const char *name, ...) va_end(ap); } -void qio_buffer_shrink(QIOBuffer *buffer) +static uint64_t get_buf_avg_size(QIOBuffer *buffer) { - /* - * Only shrink in case the used size is *much* smaller than the - * capacity, to avoid bumping up & down the buffers all the time. + return buffer->avg_size >> QIO_BUFFER_AVG_SIZE_SHIFT; +} + +void qio_buffer_shrink(QIOBuffer *buffer) + { + size_t new; + + /* Calculate the average size of the buffer as + * avg_size = avg_size * ( 1 - a ) + required_size * a + * where a is 1 / 2 ^ QIO_BUFFER_AVG_SIZE_SHIFT. */ + buffer->avg_size *= (1 << QIO_BUFFER_AVG_SIZE_SHIFT) - 1; + buffer->avg_size >>= QIO_BUFFER_AVG_SIZE_SHIFT; + buffer->avg_size += buf_req_size(buffer, 0); + + /* And then only shrink if the average size of the buffer is much + * too big, to avoid bumping up & down the buffers all the time. * realloc() isn't exactly cheap ... */ - if (buffer->offset < (buffer->capacity >> 3) && - buffer->capacity > QIO_BUFFER_MIN_SHRINK_SIZE) { - return; + new = buf_req_size(buffer, get_buf_avg_size(buffer)); + if (new < buffer->capacity >> 3 && + new >= QIO_BUFFER_MIN_SHRINK_SIZE) { + buf_adj_size(buffer, get_buf_avg_size(buffer)); } - - buf_adj_size(buffer, 0); } + void qio_buffer_reserve(QIOBuffer *buffer, size_t len) { if ((buffer->capacity - buffer->offset) < len) { @@ -83,6 +105,7 @@ uint8_t *qio_buffer_end(QIOBuffer *buffer) void qio_buffer_reset(QIOBuffer *buffer) { buffer->offset = 0; + qio_buffer_shrink(buffer); } void qio_buffer_free(QIOBuffer *buffer) @@ -107,6 +130,7 @@ void qio_buffer_advance(QIOBuffer *buffer, size_t len) memmove(buffer->buffer, buffer->buffer + len, (buffer->offset - len)); buffer->offset -= len; + qio_buffer_shrink(buffer); } void qio_buffer_move_empty(QIOBuffer *to, QIOBuffer *from) -- 1.9.1