[CRIU] [PATCH 14/15] bfd: Implement buffered writes

Pavel Emelyanov xemul at parallels.com
Mon Sep 29 01:50:29 PDT 2014


Dump times (top-5) look like

Before patch:
	writev:     1595  0.048337 (15.1%)
	openat:     1326  0.041976 (13.1%)
	 close:     1434  0.034661 (10.8%)
	  read:      988  0.028760 (9.0%)
	 wait4:      170  0.028271 (8.8%)

After patch:
	openat:     1326  0.040010 (16.4%)
	 close:     1434  0.030039 (12.3%)
	  read:      988  0.025827 (10.6%)
	 wait4:      170  0.025549 (10.5%)
	ptrace:      834  0.021624 (8.9%)

So write-s go away from top list (turn into 8th position).

Funny thing is that all object writes get merged with the
magic writes, so the total amount of write()-s (not writev-s)
in the strace remain intact :)

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
 bfd.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 70 insertions(+), 3 deletions(-)

diff --git a/bfd.c b/bfd.c
index 2572679..0bc9a64 100644
--- a/bfd.c
+++ b/bfd.c
@@ -84,10 +84,22 @@ int bfdopen(struct bfd *f)
 	return 0;
 }
 
+static int bflush(struct bfd *bfd);
+
 void bclose(struct bfd *f)
 {
-	if (bfd_buffered(f))
+	if (bfd_buffered(f)) {
+		if (bflush(f) < 0)
+			/*
+			 * FIXME -- propagate error up. It's
+			 * hardly possible by returning and
+			 * checking it, but setting a static
+			 * flag, failing further bfdopen-s and
+			 * checking one at the end would work.
+			 */
+			pr_err("Error flushing image\n");
 		buf_put(&f->b);
+	}
 	close(f->fd);
 }
 
@@ -178,14 +190,69 @@ again:
 	goto again;
 }
 
+static int bflush(struct bfd *bfd)
+{
+	struct xbuf *b = &bfd->b;
+	int ret;
+
+	if (!b->sz)
+		return 0;
+
+	ret = write(bfd->fd, b->data, b->sz);
+	if (ret != b->sz)
+		return -1;
+
+	b->sz = 0;
+	return 0;
+}
+
+static int __bwrite(struct bfd *bfd, const void *buf, int size)
+{
+	struct xbuf *b = &bfd->b;
+
+	if (b->sz + size > BUFSIZE) {
+		int ret;
+		ret = bflush(bfd);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (size > BUFSIZE)
+		return write(bfd->fd, buf, size);
+
+	memcpy(b->data + b->sz, buf, size);
+	b->sz += size;
+	return size;
+}
+
 int bwrite(struct bfd *bfd, const void *buf, int size)
 {
-	return write(bfd->fd, buf, size);
+	if (!bfd_buffered(bfd))
+		return write(bfd->fd, buf, size);
+
+	return __bwrite(bfd, buf, size);
 }
 
 int bwritev(struct bfd *bfd, const struct iovec *iov, int cnt)
 {
-	return writev(bfd->fd, iov, cnt);
+	int i, written = 0;
+
+	if (!bfd_buffered(bfd))
+		return writev(bfd->fd, iov, cnt);
+
+	for (i = 0; i < cnt; i++) {
+		int ret;
+
+		ret = __bwrite(bfd, (const void *)iov[i].iov_base, iov[i].iov_len);
+		if (ret < 0)
+			return ret;
+		if (ret < iov[i].iov_len)
+			break;
+
+		written += ret;
+	}
+
+	return written;
 }
 
 int bread(struct bfd *bfd, void *buf, int size)
-- 
1.8.4.2




More information about the CRIU mailing list