mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 13:14:02 +02:00
btrfs: stop sleeping for one jiffy in non-ssd mounts during log commit
Joining/starting a log transaction tracks if we ever had more than one task
concurrently logging by setting the flag BTRFS_ROOT_MULTI_LOG_TASKS in the
respective root. Once set, this flag remains for the rest of the lifetime
of the transaction, only cleared when we don't have a log root and need to
create a new one (transaction commits drop log roots).
During log commit, if we are not on a ssd mount (or use the -o nossd mount
option) and the BTRFS_ROOT_MULTI_LOG_TASKS flag is set, we sleep for one
jiffy with the excuse to allow future log writers to join and log inodes
and then commit a larger log transaction to reduce overall IO. However
this is extremely inefficient because:
1) If at some point we had multiple tasks logging concurrently but now
we have only one task at a time, we force it to wait for 1 jiffy;
2) One jiffy can vary between 1ms to 10ms, depending on the kernel
config option CONFIG_HZ, which by default has a value of 250HZ and
that corresponds to 4ms - that is a lot.
This massively reduces the latency of fsyncs for non-ssd mounts, even
on consumer grade spinning disks.
Remove this mechanism to track if we have (or ever had) multiple tasks
logging and wait for 1 jiffy.
The following fio test was used to benchmark:
$ cat fio-buffered-fsync.sh
DEV=/dev/sdj
MNT=/mnt/sdj
MOUNT_OPTIONS=""
MKFS_OPTIONS=""
if [ $# -ne 6 ]; then
echo "Use $0 NUM_JOBS FILE_SIZE IO_SIZE FSYNC_FREQ BLOCK_SIZE [write|randwrite]"
exit 1
fi
NUM_JOBS=$1
FILE_SIZE=$2
IO_SIZE=$3
FSYNC_FREQ=$4
BLOCK_SIZE=$5
WRITE_MODE=$6
if [ "$WRITE_MODE" != "write" ] && [ "$WRITE_MODE" != "randwrite" ]; then
echo "Invalid WRITE_MODE, must be 'write' or 'randwrite'"
exit 1
fi
cat <<EOF > /tmp/fio-job.ini
[writers]
rw=$WRITE_MODE
fsync=$FSYNC_FREQ
fallocate=none
group_reporting=1
direct=0
bs=$BLOCK_SIZE
ioengine=psync
filesize=$FILE_SIZE
io_size=$IO_SIZE
directory=$MNT
numjobs=$NUM_JOBS
EOF
echo
echo "Using config:"
echo
cat /tmp/fio-job.ini
echo
umount $MNT &> /dev/null
mkfs.btrfs -f $MKFS_OPTIONS $DEV
mount $MOUNT_OPTIONS $DEV $MNT
fio /tmp/fio-job.ini
umount $MNT
Running the script as: ./fio-buffered-fsync.sh 8 64M 64M 1 4K randwrite
Before patch:
WRITE: bw=2647KiB/s (2711kB/s), 2647KiB/s-2647KiB/s (2711kB/s-2711kB/s), io=512MiB (537MB), run=198055-198055msec
After patch:
WRITE: bw=14.9MiB/s (15.6MB/s), 14.9MiB/s-14.9MiB/s (15.6MB/s-15.6MB/s), io=512MiB (537MB), run=34471-34471msec
That's about 5.7 times faster.
Reviewed-by: Boris Burkov <boris@bur.io>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
a26f792036
commit
5093038fc2
|
|
@ -131,7 +131,6 @@ enum {
|
|||
BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
|
||||
BTRFS_ROOT_DEFRAG_RUNNING,
|
||||
BTRFS_ROOT_FORCE_COW,
|
||||
BTRFS_ROOT_MULTI_LOG_TASKS,
|
||||
BTRFS_ROOT_DIRTY,
|
||||
BTRFS_ROOT_DELETING,
|
||||
|
||||
|
|
@ -216,7 +215,6 @@ struct btrfs_root {
|
|||
* to access this field.
|
||||
*/
|
||||
int last_log_commit;
|
||||
pid_t log_start_pid;
|
||||
|
||||
u64 last_trans;
|
||||
|
||||
|
|
|
|||
|
|
@ -316,13 +316,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
|
|||
wait_log_commit(root, root->log_transid - 1);
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (!root->log_start_pid) {
|
||||
clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state);
|
||||
root->log_start_pid = current->pid;
|
||||
} else if (root->log_start_pid != current->pid) {
|
||||
set_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* This means fs_info->log_root_tree was already created
|
||||
|
|
@ -340,8 +333,6 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
|
|||
goto out;
|
||||
|
||||
set_bit(BTRFS_ROOT_HAS_LOG_TREE, &root->state);
|
||||
clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state);
|
||||
root->log_start_pid = current->pid;
|
||||
}
|
||||
|
||||
atomic_inc(&root->log_writers);
|
||||
|
|
@ -3347,13 +3338,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
|||
|
||||
while (1) {
|
||||
int batch = atomic_read(&root->log_batch);
|
||||
/* when we're on an ssd, just kick the log commit out */
|
||||
if (!btrfs_test_opt(fs_info, SSD) &&
|
||||
test_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state)) {
|
||||
mutex_unlock(&root->log_mutex);
|
||||
schedule_timeout_uninterruptible(1);
|
||||
mutex_lock(&root->log_mutex);
|
||||
}
|
||||
|
||||
wait_for_writer(root);
|
||||
if (batch == atomic_read(&root->log_batch))
|
||||
break;
|
||||
|
|
@ -3414,7 +3399,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
|||
|
||||
btrfs_set_root_log_transid(root, root->log_transid + 1);
|
||||
log->log_transid = root->log_transid;
|
||||
root->log_start_pid = 0;
|
||||
/*
|
||||
* IO has been started, blocks of the log tree have WRITTEN flag set
|
||||
* in their headers. new modifications of the log will be written to
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user