美文网首页
Advanced File I/O 同步、异步、 I/O调度器与

Advanced File I/O 同步、异步、 I/O调度器与

作者: 无无吴 | 来源:发表于2019-08-15 10:17 被阅读0次

    在写入的数据至少存储在内核的缓冲区缓存中之后,synchronize write入操作才会返回。
    在读取数据存储在应用程序提供的用户空间缓冲器中之前,synchronize read操作不会返回。
    另一方面, asynchronous write操作可以在数据甚至离开用户空间之前返回; asynchronous read操作可以在读取数据可用之前返回。也就是说,操作可能不会在请求时实际发生,而只是在往后排队。当然,在这种情况下,必须存在某种机制来确定操作何时实际完成。 以及成功的程度。
    与单纯的synchronize操作相比,synchronized操作更具限制性和安全性。synchronized write操作将数据刷新到磁盘,确保磁盘上的数据始终是同步的。 相对于相应的内核缓冲区。synchronized read操作总是从磁盘返回最新的数据副本。

    写入操作的同步性
    读取操作总是同步的,因为读取陈旧的数据没有什么意义。
    读操作的同步性 。
    通过O_SYNC标志使write synchronized,,通过fsync()确保所有I/O在是synchronized。

    Asynchronous I/O

    #include <aio.h>
    /* asynchronous I/O control block */
    struct aiocb {
        int aio_fildes; /* file descriptor */
        int aio_lio_opcode; /* operation to perform */
        int aio_reqprio; /* request priority offset */
        volatile void *aio_buf; /* pointer to buffer */
        size_t aio_nbytes; /* length of operation */
        struct sigevent aio_sigevent; /* signal number and value */
        /* internal, private members follow... */
    };
    int aio_read (struct aiocb *aiocbp);
    int aio_write (struct aiocb *aiocbp);
    int aio_error (const struct aiocb *aiocbp);
    int aio_return (struct aiocb *aiocbp);
    int aio_cancel (int fd, struct aiocb *aiocbp);
    int aio_fsync (int op, struct aiocb *aiocbp);
    int aio_suspend (const struct aiocb * const cblist[],
                                int n,
                                const struct timespec *timeout);
    

    I/O Scheduler and I/O Performance

    在现代系统中,磁盘与系统其余部分之间的相对性能差距相当大,而且还在不断扩大。
    磁盘性能的最糟糕组件是将读/写头从磁盘的一部分移动到另一个部分的过程,这是一种称为seek的操作。
    鉴于磁盘驱动器与系统其他部分在性能上的差异,按照发出I/O请求的顺序向磁盘发送I/O请求将是极其粗糙和低效的。 因此,现代操作系统内核实现I/O调度器,它通过操作I/O请求的服务顺序和时间来最小化磁盘的数量和大小。I/O调度程序努力减少与磁盘访问相关的性能损失。

    The Life of an I/O Scheduler

    I/O调度程序执行两个基本操作:合并和排序。
    合并·:
    考虑两个请求,一个从磁盘块5读取,另一个从磁盘块6到7读取,这些请求可以合并为一个从磁盘块5到7读取的请求。 I/O的其他数量可能相同,但I/O操作的数量减少了一半。
    排序:
    例如,给定对块52、109和7的I/O操作,I/O调度程序将这些请求排序为顺序7、52和109。如果向第81项发出请求,则将插入 在对块52和109的请求之间。然后,I/O计划程序将按它们在队列中的顺序将请求分派到磁盘:7、然后52、81和109。

    Helping Out Reads

    每个读取请求必须返回最新的数据。因此,如果请求的数据不在页缓存中,则读取过程必须阻塞,直到数据可以从磁盘读取-这可能是一种冗长的操作。 我们称这种性能影响为read latency。

    Optimzing I/O Performance

    Sechedling I/O in user space

    sort based on:

    • The full path
    • The inode number
    • The physical disk block of the file
    Sorting by path

    通过路径名进行排序是最简单、最有效的逼近块排序的方式。
    文件系统越支离破碎,按路径排序的用处就越小。

    Sorting by inode

    每个文件都有一个与其相关联的inode,并且为inode分配了唯一的编号。

    //怎么获取inode
    int get_inode(int fd)
    {
        struct stat buf;
        int ret;
        ret = fstat(fd, &buf);
        if(ret < 0){
            perror("fstat");
            return -1;
        }
        return buf.st_ino;
    }
    
    
    int Print_inode_Number(int argc, char* argv[]) {
        int fd, inode;
        if(argc<2){
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            return 1;
        }
        fd = open(argv[1], O_RDONLY);
        if(fd<0){
            perror("open");
            return 1;
        }
    
        inode = get_inode(fd);
        printf("%s - inode: %d\n", argv[1], inode);
        if(close(fd)<0){
            perror("close");
        }
        return 0;
    }
    
    int main(int argc, char*argv[])
    {
        Print_inode_Number(argc, argv);
        return 0;
    }
    
    测试结果
    这是在用户空间中调度I/O请求的最常用方法。
    Sorting by physical block

    当然,设计您自己的电梯算法的最佳方法是按物理磁盘块进行排序。
    内核提供了从文件的逻辑块号获取物理磁盘块的方法。

    ret = ioctl(fd, FIBMAP, &block);
    if(ret < 0)
        perror("ioctl");
    

    在这里,fd是所讨论文件的文件描述符,block是我们想要确定的物理块的逻辑块。
    在成功返回时,block将被替换为物理块编号。
    传入的逻辑块是零索引和文件有关的。也就是说,如果一个文件由八个逻辑块组成,那么有效值是0到7。
    因此,寻找逻辑到物理块映射是一个两步的过程。
    首先,我们必须确定给定文件中的块数。这是通过stat()系统调用完成的。
    第二,对于每个逻辑块,我们必须发出一个ioctl()请求,以查找对应的物理块。

    int get_block(int fd, int logical_block)
    {
        int ret;
        ret = ioctl(fd, FIBMAP, &logical_block);
        if(ret < 0) {
            perror("ioctl");
            return -1;
        }
        return logical_block;
    }
    
    int get_nr_blocks(int fd)
    {
        struct stat buf;
        int ret;
        ret = fstat(fd, &buf);
        if(ret < 0){
            perror("fstat");
            return -1;
        }
        return buf.st_blocks;
    }
    
    void print_blocks(int fd)
    {
        int nr_blocks, i;
        nr_blocks = get_nr_blocks(fd);
        if(nr_blocks < 0){
            fprintf(stderr, "get_nr_blocks failed!\n");
            return;
        }
        if(nr_blocks == 0){
            printf("no allocared blocks\n");
            return;
        }
        else if(nr_blocks == 1){
            printf("1 block\n\n");
        }
        else{
            printf("%d blocks\n\n", nr_blocks);
        }
    
        for(i = 0; i < nr_blocks; ++i){
            int phys_block = get_block(fd, i);
            if(phys_block < 0){
                fprintf(stderr, "get_block failed!\n");
                return;
            }
            if(!phys_block){
                continue;
            }
            printf("(%u, %u)", i, phys_block);
        }
        putchar('\n');
    }
    
    
    
    int logical_to_physical(int argc, char **argv) {
    
        int fd;
    
        if(argc < 2){
            fprintf(stderr, "usage: %s <file>\n", argv[0]);
            return 1;
        }
        fd = open(argv[1], O_RDONLY);
        if(fd < 0){
            perror("open");
            return 1;
        }
        print_blocks(fd);
        if(close(fd) < 0){
            perror("close");
        }
        return 0;
    }
    
    int main(int argc, char*argv[])
    {
        logical_to_physical(argc, argv);
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:Advanced File I/O 同步、异步、 I/O调度器与

          本文链接:https://www.haomeiwen.com/subject/lkcajctx.html