VFAT performance.
Hi,
For the performance freaks: We're copying some data off a VFAT32 partition. We've opened the drive. (Yes I know, you're not supposed to do that. "Don't do this at home folks!" :-)
When copying /dev/hda, we were able to achieve 11Mbyte per second: Our 100mpbs ethernet throughput.
When copying large files off /mnt, we see a performance of about 7Mb per second. We see the head seek to the FAT about twice per second. This fits in with:
4K bytes of FAT contains 1024 fat entries.
with a 4K clustersize, that would describe about 4Mbytes worth of data. So, at 7Mbytes per second we require a new FAT block twice per second.
I think that we're loosing the 4Mbytes per second of performance due to the 4 seeks per second that the drive has to perform.
The way to fix this would be to be able to assign a higher cache priority (*) to the blocks in the FAT, and to read more than just 4k per seek to the FAT.
Just something to keep in mind when fiddling with the code again....
Roger.
(*) i.e. expire them from the buffer cache less easily than normal blocks.
Signature · 5 lines
** [email protected] ** http://www.BitWizard.nl/ ** +31-15-2600998 ** *-- BitWizard writes Linux device drivers for any device you may have! --* * The Worlds Ecosystem is a stable system. Stable systems may experience * * excursions from the stable situation. We are currently in such an * * excursion: The stable situation does not include humans. ***************
OGAWA Hirofumi
maintainerQuoted 3 lines · Rogier Wolff
The way to fix this would be to be able to assign a higher cache priority (*) to the blocks in the FAT, and to read more than just 4k per seek to the FAT.
I tried it by attached *stupid* patch.
copying 500M data
root@devron (x)[1014]# time dd if=/dev/hda6 bs=1M count=500 > /dev/null 500+0 records in 500+0 records out 524288000 bytes transferred in 44.988916 seconds (11653715 bytes/sec) real 0m45.011s user 0m0.008s sys 0m8.723s
2.5.70-bk9
root@devron (a)[1032]# time dd if=file bs=1M count=500 > /dev/null 500+0 records in 500+0 records out 524288000 bytes transferred in 75.510951 seconds (6943205 bytes/sec) real 1m15.538s user 0m0.015s sys 0m16.493s
2.5.70-bk9+patch
root@devron (a)[1024]# time dd if=file bs=1M count=500 > /dev/null 500+0 records in 500+0 records out 524288000 bytes transferred in 52.034399 seconds (10075796 bytes/sec) real 0m52.041s user 0m0.006s sys 0m17.594s
You're right. It seems that that optimization has sufficient effect to non fragment file. Thanks.
Signature · 1 line
OGAWA Hirofumi <[email protected]>
fs/fat/cache.c | 22 +++++++++++++++++----- fs/fat/inode.c | 4 +++- include/linux/msdos_fs_sb.h | 1 + 3 files changed, 21 insertions(+), 6 deletions(-)
fs/fat/cache.c renamed from fs/fat/cache.c~fat_test +17 -5
@@ -17,7 +17,7 @@ int __fat_access(struct super_block *sb,struct msdos_sb_info *sbi =MSDOS_SB (sb);struct buffer_head *bh, *bh2, *c_bh, *c_bh2;unsigned char *p_first, *p_last; -int copy, first, last, next, b; +int copy, first, last, next, b, i;if (sbi->fat_bits ==32 ) { first = last = nr*4 ;
@@ -28,10 +28,22 @@ int __fat_access(struct super_block *sb, last = first+1 ; } b = sbi->fat_start + (first >> sb->s_blocksize_bits); -if (!(bh =sb_bread (sb, b))) { -printk (KERN_ERR "FAT: bread(block %d) in" -" fat_access failed\n" , b); -return -EIO ; + bh =NULL ; +for (i =0 ; i <16 ; i++) { +if (sbi->fat_bh[i]->b_blocknr == b) { + bh = sbi->fat_bh[i]; +break ; + } + } +if (bh ==NULL ) { +for (i =0 ; i <16 ; i++) { +brelse (sbi->fat_bh[i]); + sbi->fat_bh[i] =sb_bread (sb, b + i); +if (sbi->fat_bh[i] ==NULL ) +return -EIO ; +get_bh (sbi->fat_bh[i]); + } + bh = sbi->fat_bh[0 ]; }if ((first >> sb->s_blocksize_bits) == (last >> sb->s_blocksize_bits)) { bh2 = bh;
fs/fat/inode.c renamed from fs/fat/inode.c~fat_test +3 -1
@@ -158,7 +158,9 @@ void fat_clear_inode(struct inode *inodevoid fat_put_super (struct super_block *sb) {struct msdos_sb_info *sbi =MSDOS_SB (sb); - +int i; +for (i =0 ; i <16 ; i++) +brelse (sbi->fat_bh[i]);fat_clusters_flush (sb);if (sbi->nls_disk) {unload_nls (sbi->nls_disk);
include/linux/msdos_fs_sb.h renamed from include/linux/msdos_fs_sb.h~fat_test +1 -0
@@ -59,6 +59,7 @@ struct msdos_sb_info {spinlock_t cache_lock;struct fat_cache cache_array[FAT_CACHE_NR ], *cache; + struct buffer_head *fat_bh[16]; };#endif
_