Whamcloud - gitweb
LU-13799 lov: Cache stripe offset calculation 45/39445/25
authorPatrick Farrell <farr0186@gmail.com>
Thu, 10 Jun 2021 17:23:19 +0000 (13:23 -0400)
committerOleg Drokin <green@whamcloud.com>
Thu, 6 Jan 2022 22:01:10 +0000 (22:01 +0000)
Calculating the page offset relative to the stripe (etc)
in a file is surprisingly expensive.  Because i/o has
already been split up to stripes by the cl_io code,
calculating the stripe each time is unnecessary.

We cache most of the values requiring calculation.

This improves AIO/DIO page submission significantly,
improving performance by a bit over 10%.

Also remove lpg_generation, which isn't doing anything
useful.  This suggests the possibility of removing
lov_page, but that's for another patch.

This patch reduces i/o time in ms/GiB by:
Write: 17 ms/GiB
Read: 22 ms/GiB

Totals:
Write: 119 ms/GiB
Read: 121 ms/GiB

mpirun -np 1  $IOR -w -r -t 64M -b 64G -o ./iorfile --posix.odirect

With previous patches in series:
write        7531 MiB/s
read         7179 MiB/s

Plus this patch:
write        8637 MiB/s
read         8488 MiB/s

Signed-off-by: Patrick Farrell <farr0186@gmail.com>
Change-Id: I89e994592853d0fe93a034bfe8bdfb459bdaf584
Reviewed-on: https://review.whamcloud.com/39445
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Yingjin Qian <qian@ddn.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/lov/lov_cl_internal.h
lustre/lov/lov_io.c
lustre/lov/lov_page.c

index 40a5836..9563315 100644 (file)
@@ -450,8 +450,6 @@ struct lov_lock {
 
 struct lov_page {
        struct cl_page_slice    lps_cl;
 
 struct lov_page {
        struct cl_page_slice    lps_cl;
-       /* the layout gen when this page was created */
-       __u32                   lps_layout_gen;
 };
 
 /*
 };
 
 /*
@@ -521,6 +519,7 @@ struct lov_io_sub {
 /**
  * IO state private for LOV.
  */
 /**
  * IO state private for LOV.
  */
+#define LIS_CACHE_ENTRY_NONE   -ENOENT
 struct lov_io {
         /** super-class */
         struct cl_io_slice lis_cl;
 struct lov_io {
         /** super-class */
         struct cl_io_slice lis_cl;
@@ -586,7 +585,12 @@ struct lov_io {
         * All sub-io's created in this lov_io.
         */
        struct list_head        lis_subios;
         * All sub-io's created in this lov_io.
         */
        struct list_head        lis_subios;
-
+       /* Cached results from stripe & offset calculations for page init */
+       int                     lis_cached_entry;
+       int                     lis_cached_stripe;
+       loff_t                  lis_cached_off;
+       loff_t                  lis_cached_suboff;
+       struct lov_io_sub       *lis_cached_sub;
 };
 
 struct lov_session {
 };
 
 struct lov_session {
index 2b37380..1adb722 100644 (file)
@@ -480,6 +480,7 @@ static int lov_io_slice_init(struct lov_io *lio,
 
        io->ci_result = 0;
        lio->lis_object = obj;
 
        io->ci_result = 0;
        lio->lis_object = obj;
+       lio->lis_cached_entry = LIS_CACHE_ENTRY_NONE;
 
        switch (io->ci_type) {
        case CIT_READ:
 
        switch (io->ci_type) {
        case CIT_READ:
@@ -1071,6 +1072,11 @@ static void lov_io_end(const struct lu_env *env, const struct cl_io_slice *ios)
 {
        int rc;
 
 {
        int rc;
 
+       /* Before ending each i/o, we must set lis_cached_entry to tell the
+        * next i/o not to use stale cached lis information.
+        */
+       cl2lov_io(env, ios)->lis_cached_entry = LIS_CACHE_ENTRY_NONE;
+
        rc = lov_io_call(env, cl2lov_io(env, ios), lov_io_end_wrapper);
        LASSERT(rc == 0);
 }
        rc = lov_io_call(env, cl2lov_io(env, ios), lov_io_end_wrapper);
        LASSERT(rc == 0);
 }
index 37f3d79..887b304 100644 (file)
@@ -55,8 +55,7 @@ static int lov_comp_page_print(const struct lu_env *env,
        struct lov_page *lp = cl2lov_page(slice);
 
        return (*printer)(env, cookie,
        struct lov_page *lp = cl2lov_page(slice);
 
        return (*printer)(env, cookie,
-                         LUSTRE_LOV_NAME"-page@%p, gen: %u\n",
-                         lp, lp->lps_layout_gen);
+                         LUSTRE_LOV_NAME"-page@%p\n", lp);
 }
 
 static const struct cl_page_operations lov_comp_page_ops = {
 }
 
 static const struct cl_page_operations lov_comp_page_ops = {
@@ -75,33 +74,65 @@ int lov_page_init_composite(const struct lu_env *env, struct cl_object *obj,
        struct lov_layout_raid0 *r0;
        loff_t offset;
        loff_t suboff;
        struct lov_layout_raid0 *r0;
        loff_t offset;
        loff_t suboff;
+       bool stripe_cached = false;
        int entry;
        int stripe;
        int rc;
 
        ENTRY;
 
        int entry;
        int stripe;
        int rc;
 
        ENTRY;
 
+       /* Direct i/o (CPT_TRANSIENT) is split strictly to stripes, so we can
+        * cache the stripe information.  Buffered i/o is differently
+        * organized, and stripe calculation isn't a significant cost for
+        * buffered i/o, so we only cache this for direct i/o.
+        */
+       stripe_cached = lio->lis_cached_entry != LIS_CACHE_ENTRY_NONE &&
+                       page->cp_type == CPT_TRANSIENT;
+
        offset = cl_offset(obj, index);
        offset = cl_offset(obj, index);
-       entry = lov_io_layout_at(lio, offset);
+
+       if (stripe_cached) {
+               entry = lio->lis_cached_entry;
+               stripe = lio->lis_cached_stripe;
+               /* Offset can never go backwards in an i/o, so this is valid */
+               suboff = lio->lis_cached_suboff + offset - lio->lis_cached_off;
+       } else {
+               entry = lov_io_layout_at(lio, offset);
+
+               stripe = lov_stripe_number(loo->lo_lsm, entry, offset);
+               rc = lov_stripe_offset(loo->lo_lsm, entry, offset, stripe,
+                                      &suboff);
+               LASSERT(rc == 0);
+               lio->lis_cached_entry = entry;
+               lio->lis_cached_stripe = stripe;
+               lio->lis_cached_off = offset;
+               lio->lis_cached_suboff = suboff;
+       }
+
        if (entry < 0 || !lsm_entry_inited(loo->lo_lsm, entry)) {
                /* non-existing layout component */
                lov_page_init_empty(env, obj, page, index);
                RETURN(0);
        }
 
        if (entry < 0 || !lsm_entry_inited(loo->lo_lsm, entry)) {
                /* non-existing layout component */
                lov_page_init_empty(env, obj, page, index);
                RETURN(0);
        }
 
-       r0 = lov_r0(loo, entry);
-       stripe = lov_stripe_number(loo->lo_lsm, entry, offset);
-       LASSERT(stripe < r0->lo_nr);
-       rc = lov_stripe_offset(loo->lo_lsm, entry, offset, stripe, &suboff);
-       LASSERT(rc == 0);
+       CDEBUG(D_PAGE, "offset %llu, entry %d, stripe %d, suboff %llu\n",
+              offset, entry, stripe, suboff);
 
        page->cp_lov_index = lov_comp_index(entry, stripe);
 
        page->cp_lov_index = lov_comp_index(entry, stripe);
-       lpg->lps_layout_gen = loo->lo_lsm->lsm_layout_gen;
        cl_page_slice_add(page, &lpg->lps_cl, obj, &lov_comp_page_ops);
 
        cl_page_slice_add(page, &lpg->lps_cl, obj, &lov_comp_page_ops);
 
-       sub = lov_sub_get(env, lio, page->cp_lov_index);
-       if (IS_ERR(sub))
-               RETURN(PTR_ERR(sub));
+       if (!stripe_cached) {
+               sub = lov_sub_get(env, lio, page->cp_lov_index);
+               if (IS_ERR(sub))
+                       RETURN(PTR_ERR(sub));
+       } else {
+               sub = lio->lis_cached_sub;
+       }
+
+       lio->lis_cached_sub = sub;
+
+       r0 = lov_r0(loo, entry);
+       LASSERT(stripe < r0->lo_nr);
 
        subobj = lovsub2cl(r0->lo_sub[stripe]);
        cl_object_for_each(o, subobj) {
 
        subobj = lovsub2cl(r0->lo_sub[stripe]);
        cl_object_for_each(o, subobj) {