美文网首页
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