]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: cache minimum realtime summary level
authorOmar Sandoval <osandov@fb.com>
Wed, 27 Feb 2019 23:13:45 +0000 (17:13 -0600)
committerEric Sandeen <sandeen@redhat.com>
Wed, 27 Feb 2019 23:13:45 +0000 (17:13 -0600)
Source kernel commit: 355e3532132b487ebf6a4900fad8f3525fa3e137

The realtime summary is a two-dimensional array on disk, effectively:

u32 rsum[log2(number of realtime extents) + 1][number of blocks in the bitmap]

rsum[log][bbno] is the number of extents of size 2**log which start in
bitmap block bbno.

xfs_rtallocate_extent_near() uses xfs_rtany_summary() to check whether
rsum[log][bbno] != 0 for any log level. However, the summary array is
stored in row-major order (i.e., like an array in C), so all of these
entries are not adjacent, but rather spread across the entire summary
file. In the worst case (a full bitmap block), xfs_rtany_summary() has
to check every level.

This means that on a moderately-used realtime device, an allocation will
waste a lot of time finding, reading, and releasing buffers for the
realtime summary. In particular, one of our storage services (which runs
on servers with 8 very slow CPUs and 15 8 TB XFS realtime filesystems)
spends almost 5% of its CPU cycles in xfs_rtbuf_get() and
xfs_trans_brelse() called from xfs_rtany_summary().

One solution would be to also store the summary with the dimensions
swapped. However, this would require a disk format change to a very old
component of XFS.

Instead, we can cache the minimum size which contains any extents. We do
so lazily; rather than guaranteeing that the cache contains the precise
minimum, it always contains a loose lower bound which we tighten when we
read or update a summary block. This only uses a few kilobytes of memory
and is already serialized via the realtime bitmap and summary inode
locks, so the cost is minimal. With this change, the same workload only
spends 0.2% of its CPU cycles in the realtime allocator.

Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
include/xfs_mount.h
libxfs/xfs_rtbitmap.c

index 1d31f60bf242294484cd9f23b6f04a279353bfe6..8651d6a856a67f9e6d25e3a229f3079d69641aaa 100644 (file)
@@ -28,6 +28,13 @@ typedef struct xfs_mount {
        xfs_agnumber_t          m_maxagi;       /* highest inode alloc group */
        uint                    m_rsumlevels;   /* rt summary levels */
        uint                    m_rsumsize;     /* size of rt summary, bytes */
+       /*
+        * Optional cache of rt summary level per bitmap block with the
+        * invariant that m_rsum_cache[bbno] <= the minimum i for which
+        * rsum[i][bbno] != 0. Reads and writes are serialized by the rsumip
+        * inode lock.
+        */
+       uint8_t                 *m_rsum_cache;
        struct xfs_inode        *m_rbmip;       /* pointer to bitmap inode */
        struct xfs_inode        *m_rsumip;      /* pointer to summary inode */
        struct xfs_buftarg      *m_ddev_targp;
index e2f05cf59b3ab4bda573167757e8b6871fc395ef..d7cde0d6538a06bdab7c409df4bad2e152840723 100644 (file)
@@ -500,6 +500,12 @@ xfs_rtmodify_summary_int(
                uint first = (uint)((char *)sp - (char *)bp->b_addr);
 
                *sp += delta;
+               if (mp->m_rsum_cache) {
+                       if (*sp == 0 && log == mp->m_rsum_cache[bbno])
+                               mp->m_rsum_cache[bbno]++;
+                       if (*sp != 0 && log < mp->m_rsum_cache[bbno])
+                               mp->m_rsum_cache[bbno] = log;
+               }
                xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
        }
        if (sum)