From: Darrick J. Wong <djwong@xxxxxxxxxx> Avoid the costs of integer division (32-bit and 64-bit) if the realtime extent size is a power of two. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- include/xfs_mount.h | 2 ++ libxfs/libxfs_priv.h | 24 ++++++++++++++++++++++++ libxfs/xfs_rtbitmap.h | 20 ++++++++++++++++++++ libxfs/xfs_sb.c | 2 ++ 4 files changed, 48 insertions(+) diff --git a/include/xfs_mount.h b/include/xfs_mount.h index 4347098dc7e..6de360d33d3 100644 --- a/include/xfs_mount.h +++ b/include/xfs_mount.h @@ -67,6 +67,7 @@ typedef struct xfs_mount { uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ uint8_t m_sectbb_log; /* sectorlog - BBSHIFT */ uint8_t m_agno_log; /* log #ag's */ + int8_t m_rtxblklog; /* log2 of rextsize, if possible */ uint m_blockmask; /* sb_blocksize-1 */ uint m_blockwsize; /* sb_blocksize in words */ uint m_blockwmask; /* blockwsize-1 */ @@ -88,6 +89,7 @@ typedef struct xfs_mount { uint m_ag_max_usable; /* max space per AG */ struct radix_tree_root m_perag_tree; uint64_t m_features; /* active filesystem features */ + uint64_t m_rtxblkmask; /* rt extent block mask */ unsigned long m_opstate; /* dynamic state flags */ bool m_finobt_nores; /* no per-AG finobt resv. */ uint m_qflags; /* quota status flags */ diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 71abfdbe401..268c52b508d 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -371,6 +371,30 @@ howmany_64(uint64_t x, uint32_t y) return x; } +/* If @b is a power of 2, return log2(b). Else return -1. */ +static inline int8_t log2_if_power2(unsigned long b) +{ + unsigned long mask = 1; + unsigned int i; + unsigned int ret = 1; + + if (!is_power_of_2(b)) + return -1; + + for (i = 0; i < NBBY * sizeof(unsigned long); i++, mask <<= 1) { + if (b & mask) + ret = i; + } + + return ret; +} + +/* If @b is a power of 2, return a mask of the lower bits, else return zero. */ +static inline unsigned long long mask64_if_power2(unsigned long b) +{ + return is_power_of_2(b) ? b - 1 : 0; +} + /* buffer management */ #define XBF_TRYLOCK 0 #define XBF_UNMAPPED 0 diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h index bc51d3bfc7c..9dd791181ca 100644 --- a/libxfs/xfs_rtbitmap.h +++ b/libxfs/xfs_rtbitmap.h @@ -11,6 +11,9 @@ xfs_rtx_to_rtb( struct xfs_mount *mp, xfs_rtxnum_t rtx) { + if (mp->m_rtxblklog >= 0) + return rtx << mp->m_rtxblklog; + return rtx * mp->m_sb.sb_rextsize; } @@ -19,6 +22,9 @@ xfs_rtxlen_to_extlen( struct xfs_mount *mp, xfs_rtxlen_t rtxlen) { + if (mp->m_rtxblklog >= 0) + return rtxlen << mp->m_rtxblklog; + return rtxlen * mp->m_sb.sb_rextsize; } @@ -28,6 +34,9 @@ xfs_extlen_to_rtxmod( struct xfs_mount *mp, xfs_extlen_t len) { + if (mp->m_rtxblklog >= 0) + return len & mp->m_rtxblkmask; + return len % mp->m_sb.sb_rextsize; } @@ -36,6 +45,9 @@ xfs_extlen_to_rtxlen( struct xfs_mount *mp, xfs_extlen_t len) { + if (mp->m_rtxblklog >= 0) + return len >> mp->m_rtxblklog; + return len / mp->m_sb.sb_rextsize; } @@ -45,6 +57,11 @@ xfs_rtb_to_rtx( xfs_rtblock_t rtbno, xfs_extlen_t *mod) { + if (mp->m_rtxblklog >= 0) { + *mod = rtbno & mp->m_rtxblkmask; + return rtbno >> mp->m_rtxblklog; + } + return div_u64_rem(rtbno, mp->m_sb.sb_rextsize, mod); } @@ -53,6 +70,9 @@ xfs_rtb_to_rtxt( struct xfs_mount *mp, xfs_rtblock_t rtbno) { + if (mp->m_rtxblklog >= 0) + return rtbno >> mp->m_rtxblklog; + return div_u64(rtbno, mp->m_sb.sb_rextsize); } diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c index 55a5c5fc631..8605c91e212 100644 --- a/libxfs/xfs_sb.c +++ b/libxfs/xfs_sb.c @@ -950,6 +950,8 @@ xfs_sb_mount_common( mp->m_blockmask = sbp->sb_blocksize - 1; mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; mp->m_blockwmask = mp->m_blockwsize - 1; + mp->m_rtxblklog = log2_if_power2(sbp->sb_rextsize); + mp->m_rtxblkmask = mask64_if_power2(sbp->sb_rextsize); mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1); mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);