qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 0/2] vnc buffer enhancements for 2.5
@ 2015-11-03  9:01 Peter Lieven
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully Peter Lieven
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance Peter Lieven
  0 siblings, 2 replies; 8+ messages in thread
From: Peter Lieven @ 2015-11-03  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Lieven, kraxel

These are 2 patches on top of Gerds improve buffer handling series.

Patch 1 is an updated version of the patch included in Gerds series and
Patch 2 is a further optimization open for discussion.

Peter

Peter Lieven (2):
  io/buffer: allow a buffer to shrink gracefully
  io/buffer: avoid memmove at each qio_buffer_advance

 include/io/buffer.h |  3 ++
 io/buffer.c         | 81 +++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 66 insertions(+), 18 deletions(-)

-- 
1.9.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully
  2015-11-03  9:01 [Qemu-devel] [PATCH 0/2] vnc buffer enhancements for 2.5 Peter Lieven
@ 2015-11-03  9:01 ` Peter Lieven
  2015-11-03 10:40   ` Gerd Hoffmann
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance Peter Lieven
  1 sibling, 1 reply; 8+ messages in thread
From: Peter Lieven @ 2015-11-03  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Lieven, kraxel

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 <pl@kamp.de>
---
 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

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance
  2015-11-03  9:01 [Qemu-devel] [PATCH 0/2] vnc buffer enhancements for 2.5 Peter Lieven
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully Peter Lieven
@ 2015-11-03  9:01 ` Peter Lieven
  2015-11-03 10:52   ` Gerd Hoffmann
  2015-11-03 11:17   ` Markus Armbruster
  1 sibling, 2 replies; 8+ messages in thread
From: Peter Lieven @ 2015-11-03  9:01 UTC (permalink / raw)
  To: qemu-devel; +Cc: Peter Lieven, kraxel

memmove isn't exactly cheap at it involves temporary buffers
if the memory areas are overlapping. So make qio_buffer_advance
basically a pointer adjustment, but still keep the wasted memory
in reasonable limits.

Signed-off-by: Peter Lieven <pl@kamp.de>
---
 include/io/buffer.h |  2 ++
 io/buffer.c         | 43 ++++++++++++++++++++++++++++++++-----------
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/include/io/buffer.h b/include/io/buffer.h
index f63869e..43688cc 100644
--- a/include/io/buffer.h
+++ b/include/io/buffer.h
@@ -39,6 +39,8 @@ struct QIOBuffer {
     size_t offset;
     uint64_t avg_size;
     uint8_t *buffer;
+    size_t base_offs;
+    uint8_t *base_ptr;
 };
 
 /**
diff --git a/io/buffer.c b/io/buffer.c
index d2a6043..f1e4570 100644
--- a/io/buffer.c
+++ b/io/buffer.c
@@ -21,24 +21,27 @@
 #include "io/buffer.h"
 #include "trace.h"
 
-#define QIO_BUFFER_MIN_INIT_SIZE     4096
-#define QIO_BUFFER_MIN_SHRINK_SIZE  65536
+#define QIO_BUFFER_MIN_INIT_SIZE        4096
+#define QIO_BUFFER_MIN_SHRINK_SIZE     65536
+#define QIO_BUFFER_MAX_WASTED_SIZE   1048576
 /* 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
+#define QIO_BUFFER_AVG_SIZE_SHIFT          7
 
 static size_t buf_req_size(QIOBuffer *buffer, size_t len)
 {
     return MAX(QIO_BUFFER_MIN_INIT_SIZE,
-               pow2ceil(buffer->offset + len));
+               pow2ceil(buffer->base_offs + buffer->offset + len));
 }
 
 static void buf_adj_size(QIOBuffer *buffer, size_t len)
 {
     size_t old = buffer->capacity;
     buffer->capacity = buf_req_size(buffer, len);
-    buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
+    buffer->base_ptr = g_realloc(buffer->base_ptr, buffer->capacity);
+    buffer->buffer = buffer->base_ptr + buffer->base_offs;
+
     trace_qio_buffer_resize(buffer->name ?: "unnamed",
                             old, buffer->capacity);
 
@@ -105,17 +108,21 @@ uint8_t *qio_buffer_end(QIOBuffer *buffer)
 void qio_buffer_reset(QIOBuffer *buffer)
 {
     buffer->offset = 0;
+    buffer->base_offs = 0;
+    buffer->buffer = buffer->base_ptr;
     qio_buffer_shrink(buffer);
 }
 
 void qio_buffer_free(QIOBuffer *buffer)
 {
     trace_qio_buffer_free(buffer->name ?: "unnamed", buffer->capacity);
-    g_free(buffer->buffer);
+    g_free(buffer->base_ptr);
     g_free(buffer->name);
     buffer->offset = 0;
+    buffer->base_offs = 0;
     buffer->capacity = 0;
     buffer->buffer = NULL;
+    buffer->base_ptr = NULL;
     buffer->name = NULL;
 }
 
@@ -127,10 +134,18 @@ void qio_buffer_append(QIOBuffer *buffer, const void *data, size_t len)
 
 void qio_buffer_advance(QIOBuffer *buffer, size_t len)
 {
-    memmove(buffer->buffer, buffer->buffer + len,
-            (buffer->offset - len));
+    if (buffer->offset - len == 0) {
+        return qio_buffer_reset(buffer);
+    }
+    buffer->buffer += len;
+    buffer->base_offs += len;
     buffer->offset -= len;
-    qio_buffer_shrink(buffer);
+    if (buffer->base_offs > QIO_BUFFER_MAX_WASTED_SIZE) {
+        memmove(buffer->base_ptr, buffer->buffer, buffer->offset);
+        buffer->buffer = buffer->base_ptr;
+        buffer->base_offs = 0;
+        qio_buffer_shrink(buffer);
+    }
 }
 
 void qio_buffer_move_empty(QIOBuffer *to, QIOBuffer *from)
@@ -140,14 +155,18 @@ void qio_buffer_move_empty(QIOBuffer *to, QIOBuffer *from)
                                 from->name ?: "unnamed");
     assert(to->offset == 0);
 
-    g_free(to->buffer);
+    g_free(to->base_ptr);
     to->offset = from->offset;
     to->capacity = from->capacity;
     to->buffer = from->buffer;
+    to->base_offs = from->base_offs;
+    to->base_ptr = from->base_ptr;
 
     from->offset = 0;
     from->capacity = 0;
     from->buffer = NULL;
+    from->base_offs = 0;
+    from->base_ptr = NULL;
 }
 
 void qio_buffer_move(QIOBuffer *to, QIOBuffer *from)
@@ -164,8 +183,10 @@ void qio_buffer_move(QIOBuffer *to, QIOBuffer *from)
     qio_buffer_reserve(to, from->offset);
     qio_buffer_append(to, from->buffer, from->offset);
 
-    g_free(from->buffer);
+    g_free(from->base_ptr);
     from->offset = 0;
     from->capacity = 0;
     from->buffer = NULL;
+    from->base_offs = 0;
+    from->base_ptr = NULL;
 }
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully Peter Lieven
@ 2015-11-03 10:40   ` Gerd Hoffmann
  2015-11-05 22:09     ` Peter Lieven
  0 siblings, 1 reply; 8+ messages in thread
From: Gerd Hoffmann @ 2015-11-03 10:40 UTC (permalink / raw)
  To: Peter Lieven; +Cc: qemu-devel

On Di, 2015-11-03 at 10:01 +0100, Peter Lieven wrote:
> 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 @@

Needs a rebase (current wip branch is available at
https://www.kraxel.org/cgit/qemu/log/?h=work/vnc-buffers)

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance Peter Lieven
@ 2015-11-03 10:52   ` Gerd Hoffmann
  2015-11-03 12:20     ` Peter Lieven
  2015-11-03 11:17   ` Markus Armbruster
  1 sibling, 1 reply; 8+ messages in thread
From: Gerd Hoffmann @ 2015-11-03 10:52 UTC (permalink / raw)
  To: Peter Lieven; +Cc: qemu-devel

> diff --git a/include/io/buffer.h b/include/io/buffer.h
> index f63869e..43688cc 100644
> --- a/include/io/buffer.h
> +++ b/include/io/buffer.h
> @@ -39,6 +39,8 @@ struct QIOBuffer {
>      size_t offset;
>      uint64_t avg_size;
>      uint8_t *buffer;
> +    size_t base_offs;
> +    uint8_t *base_ptr;

Why a separate base_ptr?

While being at it I'd much prefer to replace offset with start & end.
The buffer content is buffer[start] ... buffer[end-1] then.

We can allow the buffer to wrap around, i.e. end < start.  Buffer
content is buf[start] ... buffer[size-1] and buffer[0] .. buffer[end-1]
then.  Makes the buffer management a bit more complicated, but we never
have to memmove then (except when changing buffer size) and the
WASTED_SIZE logic isn't needed too ...

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance
  2015-11-03  9:01 ` [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance Peter Lieven
  2015-11-03 10:52   ` Gerd Hoffmann
@ 2015-11-03 11:17   ` Markus Armbruster
  1 sibling, 0 replies; 8+ messages in thread
From: Markus Armbruster @ 2015-11-03 11:17 UTC (permalink / raw)
  To: Peter Lieven; +Cc: qemu-devel, kraxel

Peter Lieven <pl@kamp.de> writes:

> memmove isn't exactly cheap at it involves temporary buffers
> if the memory areas are overlapping.

Really?  The memmove() I've seen detect whether to copy forward or
backward.  None of them copies through a bounce buffer.

Avoiding it can be worthwhile regardless.

>                                      So make qio_buffer_advance
> basically a pointer adjustment, but still keep the wasted memory
> in reasonable limits.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance
  2015-11-03 10:52   ` Gerd Hoffmann
@ 2015-11-03 12:20     ` Peter Lieven
  0 siblings, 0 replies; 8+ messages in thread
From: Peter Lieven @ 2015-11-03 12:20 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

Am 03.11.2015 um 11:52 schrieb Gerd Hoffmann:
>> diff --git a/include/io/buffer.h b/include/io/buffer.h
>> index f63869e..43688cc 100644
>> --- a/include/io/buffer.h
>> +++ b/include/io/buffer.h
>> @@ -39,6 +39,8 @@ struct QIOBuffer {
>>       size_t offset;
>>       uint64_t avg_size;
>>       uint8_t *buffer;
>> +    size_t base_offs;
>> +    uint8_t *base_ptr;
> Why a separate base_ptr?
>
> While being at it I'd much prefer to replace offset with start & end.
> The buffer content is buffer[start] ... buffer[end-1] then.
>
> We can allow the buffer to wrap around, i.e. end < start.  Buffer
> content is buf[start] ... buffer[size-1] and buffer[0] .. buffer[end-1]
> then.  Makes the buffer management a bit more complicated, but we never
> have to memmove then (except when changing buffer size) and the
> WASTED_SIZE logic isn't needed too ...

Then drop this patch and try to use your approach for 2.6+

Peter

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully
  2015-11-03 10:40   ` Gerd Hoffmann
@ 2015-11-05 22:09     ` Peter Lieven
  0 siblings, 0 replies; 8+ messages in thread
From: Peter Lieven @ 2015-11-05 22:09 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 456 bytes --]

Am 03.11.2015 um 11:40 schrieb Gerd Hoffmann:
> On Di, 2015-11-03 at 10:01 +0100, Peter Lieven wrote:
>> 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 @@
> Needs a rebase (current wip branch is available at
> https://www.kraxel.org/cgit/qemu/log/?h=work/vnc-buffers)

I found that the version is ok, just the comment above the BUFFER_AVG_SIZE_SHIFT is missing.

Peter


[-- Attachment #2: Type: text/html, Size: 1094 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-11-05 22:09 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-03  9:01 [Qemu-devel] [PATCH 0/2] vnc buffer enhancements for 2.5 Peter Lieven
2015-11-03  9:01 ` [Qemu-devel] [PATCH 1/2] io/buffer: allow a buffer to shrink gracefully Peter Lieven
2015-11-03 10:40   ` Gerd Hoffmann
2015-11-05 22:09     ` Peter Lieven
2015-11-03  9:01 ` [Qemu-devel] [PATCH 2/2] io/buffer: avoid memmove at each qio_buffer_advance Peter Lieven
2015-11-03 10:52   ` Gerd Hoffmann
2015-11-03 12:20     ` Peter Lieven
2015-11-03 11:17   ` Markus Armbruster

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).