linux 磁盘io技术3------libaio使用介绍
2013-11-29 17:28
531 查看
前一篇文章介绍了一下libaio与block io性能比较:/article/9319028.html。
今天来仔细聊聊libaio的使用。
一、O_DIRECT
研究libaio之前,必须怎明白O_DIRECT标志是干嘛的。
Buffered I/O:
user space buffer----> kernel space buffer---->disk,这就需要用户空间数据拷贝到内核缓冲区,这就浪费了CPU和内存资源了。
DIRECT I/O:
不通过kernel内存缓存,直接将用户空间数据拷贝到磁盘。
那么使用O_DIRECT,则使用DIRECT I/O,这样会减少内存拷贝次数,cpu使用率也会减少。但是这样做就需要由用户层来做内存block对齐,并且其内存大小也必须是block整数倍。如果不这样做,用write是写不进数据的,直接报错。
通过命令dumpe2fs可以查看系统文件系统的block大小。我的系统block是1024。
但是这个地方我做过实验,不需要是block对齐,或block整数倍,只需要512对齐,512整数倍就可以。512是正好一个扇区的大小。这个地方很奇怪,不知道哪位高手能帮忙解惑下,不胜感激。
保证512对齐可以采用如下方法:
方法1:
方法2:
<注> 最后说明一下,在使用libaio,是必须将O_DIRECT标识置上的,如果不置,可能会报错,也可能会直接采用同步block读写的方式,其行为不确定。
可以参照说明:http://lse.sourceforge.net/io/aio.html。
二、libaio接口说明
接口文件为/usr/include/libaio.h,可以直接打开看,这里捡些主要的来说明一下。
接口结构体:
这里面buf和nbytes没啥好说的,buf和buf size,offset是相对于文件的偏移量。但有一点必须强调下,buf、buf size、offset必须都是512的整数倍。否则读或写都会失败的。
data:可以自定义类型,通常在这里定义call back ptr和call back ptr data,在io_getevents返回之后,通过此回调函数,完成读写完成之后的后续处理
aio_fildes:file fd
aio_lio_opcode:io_iocb_cmd下的命令,常用的就是读写。
union联合中,常用的是io_iocb_common。
这个结构是不是很复杂,其实是不用我们挨个赋值的,libaio提供了一些内联函数,来帮我们做这些事情,内联函数在头文件libaio.h中有定义,这里不赘述了。
data:没太搞懂,没怎么明白有啥用?
obj: iocb
res:为完成的读、写字节数
res2:读写成功状态,0表示成功
接口函数:
io_setup:maxevents表示能处理的最大时间数,同时初始化结构io_context_t,调用之前ctxp必须。
io_destroy:和io_setup对应
io_submint:该函数把nr个iocb放到ctx对应的执行队列中之后返回
io_cancel:该函数尝试取消之前通过io_submit传入的iocb。
io_getevents:该函数尝试从完成队列中去的至少min_nr个,至多nr个的消息。我们通过检查io_event的信息可以做我们想做的事情。
简单示例:
写到这里,libaio基本知识也都说的差不多了,但是现在有个问题,如果当前进程是基于epoll的,那么是否可以将libaio当成普通fd,加入到epoll当中来,和网络io结合到一起呢,这样对于一些网络服务,是不是特别方便,特别帅呢。答案是ok的。网上有一个epoll和libaio结合的例子供大家参考,作者偷个懒,这里不做单独讨论,例子如下:
http://blog.chinaunix.net/uid-16979052-id-3840266.html
今天来仔细聊聊libaio的使用。
一、O_DIRECT
研究libaio之前,必须怎明白O_DIRECT标志是干嘛的。
Buffered I/O:
user space buffer----> kernel space buffer---->disk,这就需要用户空间数据拷贝到内核缓冲区,这就浪费了CPU和内存资源了。
DIRECT I/O:
不通过kernel内存缓存,直接将用户空间数据拷贝到磁盘。
那么使用O_DIRECT,则使用DIRECT I/O,这样会减少内存拷贝次数,cpu使用率也会减少。但是这样做就需要由用户层来做内存block对齐,并且其内存大小也必须是block整数倍。如果不这样做,用write是写不进数据的,直接报错。
通过命令dumpe2fs可以查看系统文件系统的block大小。我的系统block是1024。
但是这个地方我做过实验,不需要是block对齐,或block整数倍,只需要512对齐,512整数倍就可以。512是正好一个扇区的大小。这个地方很奇怪,不知道哪位高手能帮忙解惑下,不胜感激。
保证512对齐可以采用如下方法:
方法1:
void * buf = NULL; posix_memalign(&buf, 512, BUF_SIZE);
方法2:
#include <stdint.h> #define CHUNK_ALIGNMENT 512 // align to 512-byte boundary #define CHUNK_ALIGNMENT_MASK (~(CHUNK_ALIGNMENT - 1)) static inline size_t align_size (size_t unaligned) { return((unaligned + CHUNK_ALIGNMENT - 1 ) & CHUNK_ALIGNMENT_MASK); } static inline void * align_buf (void *unaligned) { return((void *)((intptr_t)(unaligned + CHUNK_ALIGNMENT - 1) & CHUNK_ALIGNMENT_MASK)); } static inline bool buf_aligned (void *ptr) { return(((intptr_t)(ptr) & (~CHUNK_ALIGNMENT_MASK)) == 0); }
<注> 最后说明一下,在使用libaio,是必须将O_DIRECT标识置上的,如果不置,可能会报错,也可能会直接采用同步block读写的方式,其行为不确定。
可以参照说明:http://lse.sourceforge.net/io/aio.html。
二、libaio接口说明
接口文件为/usr/include/libaio.h,可以直接打开看,这里捡些主要的来说明一下。
接口结构体:
struct io_iocb_common { PADDEDptr(void *buf, __pad1); //buf start ptr PADDEDul(nbytes, __pad2); //buf size long long offset; //file offset long long __pad3, __pad4; };
这里面buf和nbytes没啥好说的,buf和buf size,offset是相对于文件的偏移量。但有一点必须强调下,buf、buf size、offset必须都是512的整数倍。否则读或写都会失败的。
typedef enum io_iocb_cmd { IO_CMD_PREAD = 0, IO_CMD_PWRITE = 1, IO_CMD_FSYNC = 2, IO_CMD_FDSYNC = 3, IO_CMD_POLL = 5, IO_CMD_NOOP = 6, } io_iocb_cmd_t;
struct iocb { PADDEDptr(void *data, __pad1); /* Return in the io completion event */ PADDED(unsigned key, __pad2); /* For use in identifying io requests */ short aio_lio_opcode; short aio_reqprio; int aio_fildes; union { struct io_iocb_common c; struct io_iocb_vector v; struct io_iocb_poll poll; struct io_iocb_sockaddr saddr; } u; };
data:可以自定义类型,通常在这里定义call back ptr和call back ptr data,在io_getevents返回之后,通过此回调函数,完成读写完成之后的后续处理
aio_fildes:file fd
aio_lio_opcode:io_iocb_cmd下的命令,常用的就是读写。
union联合中,常用的是io_iocb_common。
这个结构是不是很复杂,其实是不用我们挨个赋值的,libaio提供了一些内联函数,来帮我们做这些事情,内联函数在头文件libaio.h中有定义,这里不赘述了。
struct io_event { PADDEDptr(void *data, __pad1); PADDEDptr(struct iocb *obj, __pad2); PADDEDul(res, __pad3); PADDEDul(res2, __pad4); };
data:没太搞懂,没怎么明白有啥用?
obj: iocb
res:为完成的读、写字节数
res2:读写成功状态,0表示成功
接口函数:
extern int io_setup(int maxevents, io_context_t *ctxp); extern int io_destroy(io_context_t ctx); extern int io_submit(io_context_t ctx, long nr, struct iocb *ios[]); extern int io_cancel(io_context_t ctx, struct iocb *iocb, struct io_event *evt); extern int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout);
io_setup:maxevents表示能处理的最大时间数,同时初始化结构io_context_t,调用之前ctxp必须。
io_destroy:和io_setup对应
io_submint:该函数把nr个iocb放到ctx对应的执行队列中之后返回
io_cancel:该函数尝试取消之前通过io_submit传入的iocb。
io_getevents:该函数尝试从完成队列中去的至少min_nr个,至多nr个的消息。我们通过检查io_event的信息可以做我们想做的事情。
简单示例:
<span style="font-size:14px;">#include <stdio.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <libaio.h> #include <errno.h> #include <unistd.h> #include <unistd.h> #define MAX_COUNT 10 * 1024 #define BUF_SIZE 1 * 1024 * 1024 #ifndef O_DIRECT #define O_DIRECT 040000 /* direct disk access hint */ #endif int main(int args, void *argv[]){ int fd; void * buf = NULL; int pagesize = sysconf(_SC_PAGESIZE); posix_memalign(&buf, pagesize, BUF_SIZE); io_context_t ctx; struct iocb io,*p=&io; struct io_event e[10]; struct timespec timeout; memset(&ctx,0,sizeof(ctx)); if(io_setup(10,&ctx)!=0){ printf("io_setup error\n"); return -1; } if((fd = open("/home/aio.d", O_WRONLY | O_CREAT | O_APPEND | O_DIRECT, 0644))<0) { perror("open error"); io_destroy(ctx); return -1; } int n = MAX_COUNT; while(n > 0) { io_prep_pwrite(&io, fd, buf, BUF_SIZE, 0); if(io_submit(ctx, 1, &p)!=1) { io_destroy(ctx); printf("io_submit error\n"); return -1; } int ret = io_getevents(ctx, 1, 10, e, NULL); if (ret != 1) { perror("ret != 1"); break; } n--; } close(fd); io_destroy(ctx); return 0; } </span>
写到这里,libaio基本知识也都说的差不多了,但是现在有个问题,如果当前进程是基于epoll的,那么是否可以将libaio当成普通fd,加入到epoll当中来,和网络io结合到一起呢,这样对于一些网络服务,是不是特别方便,特别帅呢。答案是ok的。网上有一个epoll和libaio结合的例子供大家参考,作者偷个懒,这里不做单独讨论,例子如下:
http://blog.chinaunix.net/uid-16979052-id-3840266.html
相关文章推荐
- Linux中使用cgroups管理进程磁盘io介绍
- linux 磁盘io技术2------libaio与block io性能比较
- linux的IO复用技术:select、poll、epoll的区别以及epoll的原理和使用
- Linux下使用iotop检测磁盘io使用情况
- Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍
- Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍
- 在Linux下创建一个大文件,即制造磁盘IO异常,使用dd命令
- Linux下磁盘IO性能测试工具介绍
- Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍
- Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍 by 北南南北
- Linux 查看磁盘读写速度IO使用情况
- linux 磁盘io技术1------概述
- linux下磁盘管理之利器 lvm使用介绍
- Linux 查看磁盘分区、文件系统、磁盘的使用情况相关的命令和工具介绍
- linux 使用 ionice 限制 Xen 虚拟机磁盘 IO
- linux下磁盘管理之利器 lvm使用介绍
- Linux下磁盘IO性能测试工具介绍
- linux下磁盘管理之利器 lvm使用介绍
- Linux 服务器 Shell 命令 查找大文件 磁盘占用情况 内存使用情况
- linux磁盘IO