• Filipe Manana's avatar
    btrfs: skip backref walking during fiemap if we know the leaf is shared · e2fd8306
    Filipe Manana authored
    During fiemap, when checking if a data extent is shared we are doing the
    backref walking even if we already know the leaf is shared, which is a
    waste of time since if the leaf shared then the data extent is also
    shared. So skip the backref walking when we know we are in a shared leaf.
    
    The following test was measures the gains for a case where all leaves
    are shared due to a snapshot:
    
       $ cat test.sh
       #!/bin/bash
    
       DEV=/dev/sdj
       MNT=/mnt/sdj
    
       umount $DEV &> /dev/null
       mkfs.btrfs -f $DEV
       # Use compression to quickly create files with a lot of extents
       # (each with a size of 128K).
       mount -o compress=lzo $DEV $MNT
    
       # 40G gives 327680 extents, each with a size of 128K.
       xfs_io -f -c "pwrite -S 0xab -b 1M 0 40G" $MNT/foobar
    
       # Add some more files to increase the size of the fs and extent
       # trees (in the real world there's a lot of files and extents
       # from other files).
       xfs_io -f -c "pwrite -S 0xcd -b 1M 0 20G" $MNT/file1
       xfs_io -f -c "pwrite -S 0xef -b 1M 0 20G" $MNT/file2
       xfs_io -f -c "pwrite -S 0x73 -b 1M 0 20G" $MNT/file3
    
       # Create a snapshot so all the extents become indirectly shared
       # through subtrees, with a generation less than or equals to the
       # generation used to create the snapshot.
       btrfs subvolume snapshot -r $MNT $MNT/snap1
    
       # Unmount and mount again to clear cached metadata.
       umount $MNT
       mount -o compress=lzo $DEV $MNT
    
       start=$(date +%s%N)
       # The filefrag tool  uses the fiemap ioctl.
       filefrag $MNT/foobar
       end=$(date +%s%N)
       dur=$(( (end - start) / 1000000 ))
       echo "fiemap took $dur milliseconds (metadata not cached)"
       echo
    
       start=$(date +%s%N)
       filefrag $MNT/foobar
       end=$(date +%s%N)
       dur=$(( (end - start) / 1000000 ))
       echo "fiemap took $dur milliseconds (metadata cached)"
    
       umount $MNT
    
    The results were the following on a non-debug kernel (Debian's default
    kernel config).
    
    Before this patch:
    
       (...)
       /mnt/sdi/foobar: 327680 extents found
       fiemap took 1821 milliseconds (metadata not cached)
    
       /mnt/sdi/foobar: 327680 extents found
       fiemap took 399 milliseconds (metadata cached)
    
    After this patch:
    
       (...)
       /mnt/sdi/foobar: 327680 extents found
       fiemap took 591 milliseconds (metadata not cached)
    
       /mnt/sdi/foobar: 327680 extents found
       fiemap took 123 milliseconds (metadata cached)
    
    That's a speedup of 3.1x and 3.2x.
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    e2fd8306
backref.c 97.8 KB