Btrfs: improve jitter performance of the sequential buffered write
authorMiao Xie <miaox@cn.fujitsu.com>
Thu, 26 Sep 2013 05:15:27 +0000 (13:15 +0800)
committerChris Mason <chris.mason@fusionio.com>
Tue, 12 Nov 2013 02:54:38 +0000 (21:54 -0500)
The performance was slowed down sometimes when we ran sysbench to measure
the performance of the sequential buffered write by 2 or more threads.

It was because the write order of the test threads might be confused
by the task scheduler, and the coming write would be beyond the end of
the file, in this case, we need insert dummy file extents and create
a hole for the area we skip. But in order to avoid the ongoing ordered
extents which are in the area, we need wait for them. Unfortunately,
the current code doesn't check if there are ordered extents in the area
or not, try to find and flush the dirty pages directly, but in fact,
there is no dirty page in that area, this step of the current code is
unnecessary, and just wastes time. Sometimes, it would increase
the contention of some locks, and makes the performance slow down suddenly.

So we remove the ordered extent flush function before the check, and flush
the dirty pages and wait for the ordered extents only when we find them.

According to my test, we got 1-2 times of the performance regression when
we ran the test by 10 times before applying this patch. After applying
this patch, the regression went away.

Test Environment:
 CPU: 1CPU * 4Cores
 Memory: 6GB
 Partition: 20GB

Test Command:
 # sysbench --test=fileio --file-total-size=16G --file-test-mode=seqwr \
 > --num-threads=512 --file-block-size=16384 --max-time=60 --max-requests=0 run

Signed-off-by: Miao Xie <miaox@cn.fujitsu.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
fs/btrfs/inode.c

index c0dcb4c3d72dab3c3d6b93c2f8e20a2cee06b1db..1ca49eaba3bb4aee7e18aba92e38bbc500e71e69 100644 (file)
@@ -4239,15 +4239,16 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
 
        while (1) {
                struct btrfs_ordered_extent *ordered;
-               btrfs_wait_ordered_range(inode, hole_start,
-                                        block_end - hole_start);
+
                lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
                                 &cached_state);
-               ordered = btrfs_lookup_ordered_extent(inode, hole_start);
+               ordered = btrfs_lookup_ordered_range(inode, hole_start,
+                                                    block_end - hole_start);
                if (!ordered)
                        break;
                unlock_extent_cached(io_tree, hole_start, block_end - 1,
                                     &cached_state, GFP_NOFS);
+               btrfs_start_ordered_extent(inode, ordered, 1);
                btrfs_put_ordered_extent(ordered);
        }