direct-io-zonian-ChinaUnix博客
2013-03-29 13:34
246 查看
direct-io-zonian-ChinaUnix博客
direct-io 2011-10-19 14:20:37分类: LINUX
这两天抽时间把以前的一个遗留的direct-io问题跟踪了下。
Direct-io的目的在于绕过fs的cache,直接对block设备上的文件进行读写,其目的在于提高读写性能(以读为例,毕竟少了一次从fs cache 到用户态buffer的拷贝过程),这在文件仅读/写一次的情况下应该是比较比默认的读/写方式效率高(理论上)。
首先,direct-io是以block设备的block块大小为单位进行读写,因此,用户态分配的buffer的length至少要为block块的整数倍。之所以为一个遗留问题,是因为用户态的所使用的buffer是由一块自己管理的IO内存来分的(以页为分配的基本单位,而vaddr则是由mmap默认去选择的,这里mmap会去调用find_vma从而随机的得到一个vaddr),由于脑袋中想的一直是物理页是以页为单位分配的,页就当然是block块的整数倍,因此在地址上没有多加考虑。问题就出在这里,direct-io要的虚拟内存连续,与你paddr没关系!-_-!(当然有关系,普通的内存管理中,虚拟地址到物理地址的转换是通过查询页表来实现的,页表记录着 paddr >> PAGE_SHIFT, 即页帧号,虚拟地址的在虚拟页帧内的偏移与物理地址页偏移是相同的,在IOMEM用mmap来实物理地址到虚拟地址的转换,而这个地址我们又是让kernel来选择,当然就无法保证页对其,所以fs就认为其物理地址也是非页对其,从而出现了这个现象),因此当初在使用iomem的时候就一直出 INVALID的错误,确还怀疑iomem的页表管理与普通mem页表管理不同(实际没差别)?这里贴出kernel中对vaddr检查的代码:
if (offset & blocksize_mask) {
if (bdev)
blkbits = bdev_blkbits;
blocksize_mask = (1 << blkbits) - 1;
if (offset & blocksize_mask)
goto out;
}
for (seg = 0; seg < nr_segs; seg++) {
addr = (unsigned long)iov[seg].iov_base;
size = iov[seg].iov_len;
end += size;
if ((addr & blocksize_mask) || (size & blocksize_mask)) {
if (bdev)
blkbits = bdev_blkbits;
blocksize_mask = (1 << blkbits) - 1;
if ((addr & blocksize_mask) || (size & blocksize_mask))
goto out;
}
}
//注:iov:管理用户态buffer, offset为读写的起始地址(当然也该block块大小对齐)
问题找到了,接下来就应该测试下这个direct-io到底有多好的性能(在x86下用系统内存进行测试)
测试代码如下:
#define TESTFILE "test"
#define BUFFSIZE (4096)
int
main(void)
{
int fd, ret, i;
void *buff, *align;
buff = valloc(BUFFSIZE);
if ( !buff ) {
perror("alloc failed");
return -1;
}
fd = open(TESTFILE, O_RDONLY | O_DIRECT, 0666); //在这里区别是否用direct-io
if ( fd <= 0 ) {
perror("open file directly failed");
return -1;
}
for ( i = 0; i < 10240; i++) {
ret = read( fd, buff, BUFFSIZE);
if ( ret < 0 ) {
perror("read failed");
}
}
free(buff);
return 0;
}
这里循环读写 4k*10240 = 40M的数据,可测试结果确出乎人意外。这里做了direct 和non-direct的测试,在测试前均刷了系统的页高速缓存和目录项缓存(echo 3 > /proc/sys/vm/drop_caches ),这样,读test文件都应该从block设备读,应该满足测试要求。
direct-io测试结果:
real 0m1.216s
user 0m0.008s
sys 0m0.568s
non-direct-io测试结果:
real 0m0.639s
user 0m0.000s
sys 0m0.048s
这样不管是指令的执行时间还是在内核态的是时间,非direct-io都要少于direct-io,世界怎么反过来了?Why?接下去要好好查查原因
![](http://blog.chinaunix.net/blog/image/editor/pb/2.gif)
原因: 在进行DirectIO读写时,fs会根据用户态请求 iovec,将请求封为一个bio,将这个bio交给block层去填数据。由于bio是根据iovec来的,因此,fs就不可能实现文件的预读,而非directIO系统会根据当前的操作调整文件的预读窗口,将后续内容读到页高速缓存,这样后续的读操作就完全是mem copy了,速度当然是directIO不可比的。我们可以在非directIO时关掉系统预读来测测其性能。代码如下:
#define TESTFILE "test"
#define BUFFSIZE (4096)
int
main(void)
{
int fd;
int ret;
void *buff, *align;
int i = 0;
buff = valloc(BUFFSIZE);
if ( !buff ) {
perror("alloc failed");
return -1;
}
fd = open(TESTFILE, O_RDONLY , 0666);
if ( fd <= 0 ) {
perror("open file directly failed");
return -1;
}
#if 1
ret = posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); //这里将文件的访问方式改为随机读,这样系统就会关闭其
if ( ret ) { //预读窗口
printf("disable readahead disabled failed\n");
}
#endif
for ( i = 0; i < 10240; i++ ) {
ret = read( fd, buff, BUFFSIZE);
if ( ret < 0 ) {
perror("read failed");
}
}
free(buff);
return 0;
}
测试结果如下:
real 0m1.259s
user 0m0.000s
sys 0m0.608s
这样是不是就是我们想看到的结果了,无论是real、sys directIO都少于non-directIO。
看来direct-IO并不是我们想象中的利器,并不能有效的提高我们的性能。但既然存在,应该有它存在的意义吧。从实验可以猜出一二:首先,数据访问方式为随机访问,但只访问一次(怎么可能呢, 开玩笑了)。使用directIO就意味着不会消耗系统的缓冲,也就是说减轻了内存回收的压力,因此,它可能存在的意义在于,存在自己管理文件cache的情况(例如数据库)。
Ok,后面有时间会给出directIO的具体流程。
这两天抽时间把以前的一个遗留的direct-io问题跟踪了下。
Direct-io的目的在于绕过fs的cache,直接对block设备上的文件进行读写,其目的在于提高读写性能(以读为例,毕竟少了一次从fs cache 到用户态buffer的拷贝过程),这在文件仅读/写一次的情况下应该是比较比默认的读/写方式效率高(理论上)。
首先,direct-io是以block设备的block块大小为单位进行读写,因此,用户态分配的buffer的length至少要为block块的整数倍。之所以为一个遗留问题,是因为用户态的所使用的buffer是由一块自己管理的IO内存来分的(以页为分配的基本单位,而vaddr则是由mmap默认去选择的,这里mmap会去调用find_vma从而随机的得到一个vaddr),由于脑袋中想的一直是物理页是以页为单位分配的,页就当然是block块的整数倍,因此在地址上没有多加考虑。问题就出在这里,direct-io要的虚拟内存连续,与你paddr没关系!-_-!(当然有关系,普通的内存管理中,虚拟地址到物理地址的转换是通过查询页表来实现的,页表记录着 paddr >> PAGE_SHIFT, 即页帧号,虚拟地址的在虚拟页帧内的偏移与物理地址页偏移是相同的,在IOMEM用mmap来实物理地址到虚拟地址的转换,而这个地址我们又是让kernel来选择,当然就无法保证页对其,所以fs就认为其物理地址也是非页对其,从而出现了这个现象),因此当初在使用iomem的时候就一直出 INVALID的错误,确还怀疑iomem的页表管理与普通mem页表管理不同(实际没差别)?这里贴出kernel中对vaddr检查的代码:
if (offset & blocksize_mask) {
if (bdev)
blkbits = bdev_blkbits;
blocksize_mask = (1 << blkbits) - 1;
if (offset & blocksize_mask)
goto out;
}
for (seg = 0; seg < nr_segs; seg++) {
addr = (unsigned long)iov[seg].iov_base;
size = iov[seg].iov_len;
end += size;
if ((addr & blocksize_mask) || (size & blocksize_mask)) {
if (bdev)
blkbits = bdev_blkbits;
blocksize_mask = (1 << blkbits) - 1;
if ((addr & blocksize_mask) || (size & blocksize_mask))
goto out;
}
}
//注:iov:管理用户态buffer, offset为读写的起始地址(当然也该block块大小对齐)
问题找到了,接下来就应该测试下这个direct-io到底有多好的性能(在x86下用系统内存进行测试)
测试代码如下:
#define TESTFILE "test"
#define BUFFSIZE (4096)
int
main(void)
{
int fd, ret, i;
void *buff, *align;
buff = valloc(BUFFSIZE);
if ( !buff ) {
perror("alloc failed");
return -1;
}
fd = open(TESTFILE, O_RDONLY | O_DIRECT, 0666); //在这里区别是否用direct-io
if ( fd <= 0 ) {
perror("open file directly failed");
return -1;
}
for ( i = 0; i < 10240; i++) {
ret = read( fd, buff, BUFFSIZE);
if ( ret < 0 ) {
perror("read failed");
}
}
free(buff);
return 0;
}
这里循环读写 4k*10240 = 40M的数据,可测试结果确出乎人意外。这里做了direct 和non-direct的测试,在测试前均刷了系统的页高速缓存和目录项缓存(echo 3 > /proc/sys/vm/drop_caches ),这样,读test文件都应该从block设备读,应该满足测试要求。
direct-io测试结果:
real 0m1.216s
user 0m0.008s
sys 0m0.568s
non-direct-io测试结果:
real 0m0.639s
user 0m0.000s
sys 0m0.048s
这样不管是指令的执行时间还是在内核态的是时间,非direct-io都要少于direct-io,世界怎么反过来了?Why?接下去要好好查查原因
![](http://blog.chinaunix.net/blog/image/editor/pb/2.gif)
原因: 在进行DirectIO读写时,fs会根据用户态请求 iovec,将请求封为一个bio,将这个bio交给block层去填数据。由于bio是根据iovec来的,因此,fs就不可能实现文件的预读,而非directIO系统会根据当前的操作调整文件的预读窗口,将后续内容读到页高速缓存,这样后续的读操作就完全是mem copy了,速度当然是directIO不可比的。我们可以在非directIO时关掉系统预读来测测其性能。代码如下:
#define TESTFILE "test"
#define BUFFSIZE (4096)
int
main(void)
{
int fd;
int ret;
void *buff, *align;
int i = 0;
buff = valloc(BUFFSIZE);
if ( !buff ) {
perror("alloc failed");
return -1;
}
fd = open(TESTFILE, O_RDONLY , 0666);
if ( fd <= 0 ) {
perror("open file directly failed");
return -1;
}
#if 1
ret = posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM); //这里将文件的访问方式改为随机读,这样系统就会关闭其
if ( ret ) { //预读窗口
printf("disable readahead disabled failed\n");
}
#endif
for ( i = 0; i < 10240; i++ ) {
ret = read( fd, buff, BUFFSIZE);
if ( ret < 0 ) {
perror("read failed");
}
}
free(buff);
return 0;
}
测试结果如下:
real 0m1.259s
user 0m0.000s
sys 0m0.608s
这样是不是就是我们想看到的结果了,无论是real、sys directIO都少于non-directIO。
看来direct-IO并不是我们想象中的利器,并不能有效的提高我们的性能。但既然存在,应该有它存在的意义吧。从实验可以猜出一二:首先,数据访问方式为随机访问,但只访问一次(怎么可能呢, 开玩笑了)。使用directIO就意味着不会消耗系统的缓冲,也就是说减轻了内存回收的压力,因此,它可能存在的意义在于,存在自己管理文件cache的情况(例如数据库)。
Ok,后面有时间会给出directIO的具体流程。
相关文章推荐
- OpenCV-2.1 + IPP + TBB在Moblin上的安装-y307921462-ChinaUnix博客
- 10.VbScript循环语句For...Next_chicol-ChinaUnix博客
- 博客转移 favoorr.github.io
- Oracle误删数据文件灾难恢复-Linux_ghan-ChinaUnix博客
- 数据库和mysql字段定义罗列_云中的二舅-ChinaUnix博客
- YII中的CComponent,CEvent与Behavior示例_nuoyazhou110-ChinaUnix博客
- Apache编译与安装 RedHat enterprises 6.2_SONY619-ChinaUnix博客
- 我的新博客地址http://xxxbw.github.io/
- Python操作MySQL以及中文乱码的问题_mengl_2011-ChinaUnix博客
- linux mmap使用例子_wallwind-ChinaUnix博客
- 个人博客koalahl.github.io
- autotools 使用实例-ckelsel-ChinaUnix博客
- 我在chinaunix上的博客
- [Java][IO]JAVA NIO之浅谈内存映射文件原理与DirectMemory
- boost高并发网络框架+线程池-ehyyngp-ChinaUnix博客
- [置顶] ieayoio的个人博客
- 最新的QT git代码到code.qt.io/cgit,还有planet.qt.io有许多博客
- 时间分割线:2016年1月的文章都是以前chinaunix的博客文章
- cdn流量调度系统-oxwangfeng-ChinaUnix博客
- Fiddler的一些坑: !SecureClientPipeDirect failed: System.IO.IOException