qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2] iov: avoid memcpy for "simple" iov_from_buf/iov_to_buf
@ 2015-12-22 11:03 Paolo Bonzini
  2015-12-23  4:45 ` Stefan Hajnoczi
  0 siblings, 1 reply; 2+ messages in thread
From: Paolo Bonzini @ 2015-12-22 11:03 UTC (permalink / raw)
  To: qemu-devel; +Cc: stefanha

memcpy can take a large amount of time for small reads and writes.
For virtio it is a common case that the first iovec can satisfy the
whole read or write.  In that case, and if bytes is a constant to
avoid excessive growth of code, inline the first iteration
into the caller.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
        v1->v2: check for overflow in offset + bytes, which
        is covered by test-iov

 include/qemu/iov.h | 34 ++++++++++++++++++++++++++++++----
 util/iov.c         |  8 ++++----
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/include/qemu/iov.h b/include/qemu/iov.h
index 569b2c2..2847551 100644
--- a/include/qemu/iov.h
+++ b/include/qemu/iov.h
@@ -39,10 +39,36 @@ size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt);
  * such "large" value is -1 (sinice size_t is unsigned),
  * so specifying `-1' as `bytes' means 'up to the end of iovec'.
  */
-size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
-                    size_t offset, const void *buf, size_t bytes);
-size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
-                  size_t offset, void *buf, size_t bytes);
+size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
+                         size_t offset, const void *buf, size_t bytes);
+size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt,
+		       size_t offset, void *buf, size_t bytes);
+
+static inline size_t
+iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
+             size_t offset, const void *buf, size_t bytes)
+{
+    if (__builtin_constant_p(bytes) && iov_cnt &&
+        offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) {
+        memcpy(iov[0].iov_base + offset, buf, bytes);
+        return bytes;
+    } else {
+        return iov_from_buf_full(iov, iov_cnt, offset, buf, bytes);
+    }
+}
+
+static inline size_t
+iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+           size_t offset, void *buf, size_t bytes)
+{
+    if (__builtin_constant_p(bytes) && iov_cnt &&
+        offset <= iov[0].iov_len && bytes <= iov[0].iov_len - offset) {
+        memcpy(buf, iov[0].iov_base + offset, bytes);
+        return bytes;
+    } else {
+        return iov_to_buf_full(iov, iov_cnt, offset, buf, bytes);
+    }
+}
 
 /**
  * Set data bytes pointed out by iovec `iov' of size `iov_cnt' elements,
diff --git a/util/iov.c b/util/iov.c
index a0d5934..f113467 100644
--- a/util/iov.c
+++ b/util/iov.c
@@ -19,8 +19,8 @@
 #include "qemu/iov.h"
 #include "qemu/sockets.h"
 
-size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
-                    size_t offset, const void *buf, size_t bytes)
+size_t iov_from_buf_full(const struct iovec *iov, unsigned int iov_cnt,
+                         size_t offset, const void *buf, size_t bytes)
 {
     size_t done;
     unsigned int i;
@@ -38,8 +38,8 @@ size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
     return done;
 }
 
-size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
-                  size_t offset, void *buf, size_t bytes)
+size_t iov_to_buf_full(const struct iovec *iov, const unsigned int iov_cnt,
+                       size_t offset, void *buf, size_t bytes)
 {
     size_t done;
     unsigned int i;
-- 
2.5.0

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

* Re: [Qemu-devel] [PATCH v2] iov: avoid memcpy for "simple" iov_from_buf/iov_to_buf
  2015-12-22 11:03 [Qemu-devel] [PATCH v2] iov: avoid memcpy for "simple" iov_from_buf/iov_to_buf Paolo Bonzini
@ 2015-12-23  4:45 ` Stefan Hajnoczi
  0 siblings, 0 replies; 2+ messages in thread
From: Stefan Hajnoczi @ 2015-12-23  4:45 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, stefanha

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

On Tue, Dec 22, 2015 at 12:03:33PM +0100, Paolo Bonzini wrote:
> memcpy can take a large amount of time for small reads and writes.
> For virtio it is a common case that the first iovec can satisfy the
> whole read or write.  In that case, and if bytes is a constant to
> avoid excessive growth of code, inline the first iteration
> into the caller.
> 
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>         v1->v2: check for overflow in offset + bytes, which
>         is covered by test-iov
> 
>  include/qemu/iov.h | 34 ++++++++++++++++++++++++++++++----
>  util/iov.c         |  8 ++++----
>  2 files changed, 34 insertions(+), 8 deletions(-)

Thanks, applied to my block tree:
https://github.com/stefanha/qemu/commits/block

Stefan

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

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

end of thread, other threads:[~2015-12-23  4:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-12-22 11:03 [Qemu-devel] [PATCH v2] iov: avoid memcpy for "simple" iov_from_buf/iov_to_buf Paolo Bonzini
2015-12-23  4:45 ` Stefan Hajnoczi

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).