xfs
[Top] [All Lists]

[PATCH 44/49] xfs: Reduce allocations during CIL insertion

To: xfs@xxxxxxxxxxx
Subject: [PATCH 44/49] xfs: Reduce allocations during CIL insertion
From: Dave Chinner <david@xxxxxxxxxxxxx>
Date: Fri, 19 Jul 2013 16:25:15 +1000
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <1374215120-7271-1-git-send-email-david@xxxxxxxxxxxxx>
References: <1374215120-7271-1-git-send-email-david@xxxxxxxxxxxxx>
From: Dave Chinner <dchinner@xxxxxxxxxx>

Now that we have the size of the object before the formatting pass
is called, we can allocation the log vector and it's buffer in a
single allocation rather than two separate allocations.

Store the size of the allocated buffer in the log vector so that
we potentially avoid allocation for future modifications of the
object.

While touching this code, remove the IOP_FORMAT definition.

Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
---
 fs/xfs/xfs_log.h     |  1 +
 fs/xfs/xfs_log_cil.c | 94 ++++++++++++++++++++++++++++++----------------------
 fs/xfs/xfs_trans.h   |  1 -
 3 files changed, 56 insertions(+), 40 deletions(-)

diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index e63d9e1..1c45848 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -27,6 +27,7 @@ struct xfs_log_vec {
        struct xfs_log_item     *lv_item;       /* owner */
        char                    *lv_buf;        /* formatted buffer */
        int                     lv_buf_len;     /* size of formatted buffer */
+       int                     lv_size;        /* size of allocated lv */
 };
 
 #define XFS_LOG_VEC_ORDERED    (-1)
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
index 4e10872..08943c8 100644
--- a/fs/xfs/xfs_log_cil.c
+++ b/fs/xfs/xfs_log_cil.c
@@ -80,6 +80,35 @@ xlog_cil_init_post_recovery(
                                                                
log->l_curr_block);
 }
 
+STATIC void
+xlog_cil_lv_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_vec      *lv)
+{
+       int     index;
+       char    *ptr;
+
+       /* format new vectors into array */
+       lip->li_ops->iop_format(lip, lv->lv_iovecp);
+
+       /* copy data into existing array */
+       ptr = lv->lv_buf;
+       for (index = 0; index < lv->lv_niovecs; index++) {
+               struct xfs_log_iovec *vec = &lv->lv_iovecp[index];
+
+               memcpy(ptr, vec->i_addr, vec->i_len);
+               vec->i_addr = ptr;
+               ptr += vec->i_len;
+       }
+
+       /*
+        * some size calculations for log vectors over-estimate, so we'll see
+        * this as not using the entire buffer here. Hence just check ofr
+        * overruns on debug kernels.
+        */
+       ASSERT(ptr > lv->lv_buf && ptr <= lv->lv_buf + lv->lv_buf_len);
+}
+
 /*
  * Format log item into a flat buffers
  *
@@ -111,7 +140,7 @@ xlog_cil_prepare_log_vecs(
        struct xfs_trans        *tp)
 {
        struct xfs_log_item_desc *lidp;
-       struct xfs_log_vec      *lv = NULL;
+       struct xfs_log_vec      *prev_lv = NULL;
        struct xfs_log_vec      *ret_lv = NULL;
 
 
@@ -123,12 +152,10 @@ xlog_cil_prepare_log_vecs(
 
        list_for_each_entry(lidp, &tp->t_items, lid_trans) {
                struct xfs_log_item *lip = lidp->lid_item;
-               struct xfs_log_vec *new_lv;
-               void    *ptr;
-               int     index;
-               int     len = 0;
-               uint    niovecs = 0;
-               uint    nbytes = 0;
+               struct xfs_log_vec *lv;
+               int     niovecs = 0;
+               int     nbytes = 0;
+               int     buf_size;
                bool    ordered = false;
 
                /* Skip items which aren't dirty in this transaction. */
@@ -150,48 +177,39 @@ xlog_cil_prepare_log_vecs(
                if (niovecs == XFS_LOG_VEC_ORDERED) {
                        ordered = true;
                        niovecs = 0;
+                       nbytes = 0;
                }
 
-               new_lv = kmem_zalloc(sizeof(*new_lv) +
-                               niovecs * sizeof(struct xfs_log_iovec),
-                               KM_SLEEP|KM_NOFS);
+               /* calc buffer size */
+               buf_size = sizeof(struct xfs_log_vec) + nbytes +
+                               niovecs * sizeof(struct xfs_log_iovec);
 
-               new_lv->lv_item = lip;
-               new_lv->lv_niovecs = niovecs;
+               /* allocate new data chunk */
+               lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS);
+               lv->lv_item = lip;
+               lv->lv_size = buf_size;
+               lv->lv_niovecs = niovecs;
                if (ordered) {
                        /* track as an ordered logvec */
-                       new_lv->lv_buf_len = XFS_LOG_VEC_ORDERED;
-                       goto next;
+                       ASSERT(lip->li_lv == NULL);
+                       lv->lv_buf_len = XFS_LOG_VEC_ORDERED;
+                       goto insert;
                }
 
                /* The allocated iovec region lies beyond the log vector. */
-               new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1];
-
-               /* build the vector array and calculate it's length */
-               IOP_FORMAT(new_lv->lv_item, new_lv->lv_iovecp);
-               for (index = 0; index < new_lv->lv_niovecs; index++)
-                       len += new_lv->lv_iovecp[index].i_len;
+               lv->lv_iovecp = (struct xfs_log_iovec *)&lv[1];
 
-               new_lv->lv_buf_len = len;
-               new_lv->lv_buf = kmem_alloc(new_lv->lv_buf_len,
-                               KM_SLEEP|KM_NOFS);
-               ptr = new_lv->lv_buf;
-
-               for (index = 0; index < new_lv->lv_niovecs; index++) {
-                       struct xfs_log_iovec *vec = &new_lv->lv_iovecp[index];
-
-                       memcpy(ptr, vec->i_addr, vec->i_len);
-                       vec->i_addr = ptr;
-                       ptr += vec->i_len;
-               }
-               ASSERT(ptr == new_lv->lv_buf + new_lv->lv_buf_len);
+               /* The allocated data region lies beyond the iovec region */
+               lv->lv_buf = (char *)lv + buf_size - nbytes;
+               lv->lv_buf_len = nbytes;
 
-next:
+               xlog_cil_lv_item_format(lip, lv);
+insert:
                if (!ret_lv)
-                       ret_lv = new_lv;
+                       ret_lv = lv;
                else
-                       lv->lv_next = new_lv;
-               lv = new_lv;
+                       prev_lv->lv_next = lv;
+               prev_lv = lv;
        }
 
        return ret_lv;
@@ -228,7 +246,6 @@ xfs_cil_prepare_item(
 
                *len += lv->lv_buf_len - old->lv_buf_len;
                *diff_iovecs += lv->lv_niovecs - old->lv_niovecs;
-               kmem_free(old->lv_buf);
                kmem_free(old);
        } else {
                /* new lv, must pin the log item */
@@ -354,7 +371,6 @@ xlog_cil_free_logvec(
 
        for (lv = log_vector; lv; ) {
                struct xfs_log_vec *next = lv->lv_next;
-               kmem_free(lv->lv_buf);
                kmem_free(lv);
                lv = next;
        }
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 97144ec..24bbdcd 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -77,7 +77,6 @@ struct xfs_item_ops {
        void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
 };
 
-#define IOP_FORMAT(ip,vp)      (*(ip)->li_ops->iop_format)(ip, vp)
 #define IOP_PIN(ip)            (*(ip)->li_ops->iop_pin)(ip)
 #define IOP_UNPIN(ip, remove)  (*(ip)->li_ops->iop_unpin)(ip, remove)
 #define IOP_PUSH(ip, list)     (*(ip)->li_ops->iop_push)(ip, list)
-- 
1.8.3.2

<Prev in Thread] Current Thread [Next in Thread>