Skip to content

Commit f18c9a9

Browse files
Dave Chinnerdjwong
authored andcommitted
xfs: reduce free inode accounting overhead
Shaokun Zhang reported that XFS was using substantial CPU time in percpu_count_sum() when running a single threaded benchmark on a high CPU count (128p) machine from xfs_mod_ifree(). The issue is that the filesystem is empty when the benchmark runs, so inode allocation is running with a very low inode free count. With the percpu counter batching, this means comparisons when the counter is less that 128 * 256 = 32768 use the slow path of adding up all the counters across the CPUs, and this is expensive on high CPU count machines. The summing in xfs_mod_ifree() is only used to fire an assert if an underrun occurs. The error is ignored by the higher level code. Hence this is really just debug code and we don't need to run it on production kernels, nor do we need such debug checks to return error values just to trigger an assert. Finally, xfs_mod_icount/xfs_mod_ifree are only called from xfs_trans_unreserve_and_mod_sb(), so get rid of them and just directly call the percpu_counter_add/percpu_counter_compare functions. The compare functions are now run only on debug builds as they are internal to ASSERT() checks and so only compiled in when ASSERTs are active (CONFIG_XFS_DEBUG=y or CONFIG_XFS_WARN=y). Reported-by: Shaokun Zhang <[email protected]> Signed-off-by: Dave Chinner <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Darrick J. Wong <[email protected]>
1 parent dc3ffbb commit f18c9a9

File tree

3 files changed

+13
-39
lines changed

3 files changed

+13
-39
lines changed

fs/xfs/xfs_mount.c

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,39 +1189,6 @@ xfs_log_sbcount(xfs_mount_t *mp)
11891189
return xfs_sync_sb(mp, true);
11901190
}
11911191

1192-
/*
1193-
* Deltas for the inode count are +/-64, hence we use a large batch size
1194-
* of 128 so we don't need to take the counter lock on every update.
1195-
*/
1196-
#define XFS_ICOUNT_BATCH 128
1197-
int
1198-
xfs_mod_icount(
1199-
struct xfs_mount *mp,
1200-
int64_t delta)
1201-
{
1202-
percpu_counter_add_batch(&mp->m_icount, delta, XFS_ICOUNT_BATCH);
1203-
if (__percpu_counter_compare(&mp->m_icount, 0, XFS_ICOUNT_BATCH) < 0) {
1204-
ASSERT(0);
1205-
percpu_counter_add(&mp->m_icount, -delta);
1206-
return -EINVAL;
1207-
}
1208-
return 0;
1209-
}
1210-
1211-
int
1212-
xfs_mod_ifree(
1213-
struct xfs_mount *mp,
1214-
int64_t delta)
1215-
{
1216-
percpu_counter_add(&mp->m_ifree, delta);
1217-
if (percpu_counter_compare(&mp->m_ifree, 0) < 0) {
1218-
ASSERT(0);
1219-
percpu_counter_add(&mp->m_ifree, -delta);
1220-
return -EINVAL;
1221-
}
1222-
return 0;
1223-
}
1224-
12251192
/*
12261193
* Deltas for the block count can vary from 1 to very large, but lock contention
12271194
* only occurs on frequent small block count updates such as in the delayed

fs/xfs/xfs_mount.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,6 @@ extern int xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount,
392392
xfs_agnumber_t *maxagi);
393393
extern void xfs_unmountfs(xfs_mount_t *);
394394

395-
extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta);
396-
extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta);
397395
extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
398396
bool reserved);
399397
extern int xfs_mod_frextents(struct xfs_mount *mp, int64_t delta);

fs/xfs/xfs_trans.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,12 @@ xfs_trans_apply_sb_deltas(
545545
* used block counts are not updated in the on disk superblock. In this case,
546546
* XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we
547547
* still need to update the incore superblock with the changes.
548+
*
549+
* Deltas for the inode count are +/-64, hence we use a large batch size of 128
550+
* so we don't need to take the counter lock on every update.
548551
*/
552+
#define XFS_ICOUNT_BATCH 128
553+
549554
void
550555
xfs_trans_unreserve_and_mod_sb(
551556
struct xfs_trans *tp)
@@ -585,13 +590,17 @@ xfs_trans_unreserve_and_mod_sb(
585590
}
586591

587592
if (idelta) {
588-
error = xfs_mod_icount(mp, idelta);
589-
ASSERT(!error);
593+
percpu_counter_add_batch(&mp->m_icount, idelta,
594+
XFS_ICOUNT_BATCH);
595+
if (idelta < 0)
596+
ASSERT(__percpu_counter_compare(&mp->m_icount, 0,
597+
XFS_ICOUNT_BATCH) >= 0);
590598
}
591599

592600
if (ifreedelta) {
593-
error = xfs_mod_ifree(mp, ifreedelta);
594-
ASSERT(!error);
601+
percpu_counter_add(&mp->m_ifree, ifreedelta);
602+
if (ifreedelta < 0)
603+
ASSERT(percpu_counter_compare(&mp->m_ifree, 0) >= 0);
595604
}
596605

597606
if (rtxdelta == 0 && !(tp->t_flags & XFS_TRANS_SB_DIRTY))

0 commit comments

Comments
 (0)