前言
需要了解的知识
用户态、内核态
系统调用
DMA、CPU拷贝
传统io
传统io:会经过四次内核态和用户态上下文切换,四次数据的拷贝
传统io流程
1、用户程序发起read()系统调用,由用户态切换为内核态(1次状态切换)
2、内核通过DMA把数据读进内核缓冲(1次DMA拷贝),再把数据通过cpu拷贝到用户缓冲(1次cpu拷贝复制),read()系统调用结束返回
内核态切换为用户态(1次状态切换)
3、用户调用write()系统调用,由用户态切换为内核态(1次状态切换),将数据从用户缓冲拷贝进内核缓冲(1次cpu拷贝复制)
4、内核将数据通过DMA拷贝到网卡(1次DMA拷贝),结束read()系统调用返回,由用户态切换为内核态(1次状态切换)
2次DMA拷贝、2次cpu拷贝、4次内核态用户态切换
mmap
使用mmap系统调用:会经过四次内核态和用户态上下文切换,三次数据的拷贝
1、用户程序发起mmap()系统调用,将用户缓冲和内核缓冲做映射,由用户态切换为内核态1次状态切换),
2、内核通过DMA将数据拷贝到内核缓冲(一次DMA拷贝),mmap()调用返回,由内核态切换为用户态(1次状态切换)
3、用户程序发起write()系统调用,由用户态切换为内核态(一次切换),因为做了映射:内核直接通过cpu拷贝数据到
输出的缓冲区(1次cpu拷贝)
4、内核通过DMA把数据拷贝到硬件网卡(一次DMA拷贝),write()系统调用返回,由内核态切换为用户态(1次状态切换)
2次DMA拷贝、1次cpu拷贝、4次内核态用户态切换
sendfile
使用sendfile系统调用:会经过两次内核态和用户态上下文切换,三次数据的拷贝
1、用户程序发起sendfile()系统调用,由用户态切换为内核态1次状态切换),
2、内核通过DMA将数据拷贝到内核缓冲(一次DMA拷贝)
3、内核直接通过cpu拷贝数据到输出的缓冲区(1次cpu拷贝)
4、内核通过DMA把数据拷贝到硬件网卡(一次DMA拷贝),sendfile()系统调用返回,由内核态切换为用户态(1次状态切换)
只需要sendfile一个系统调用
2次DMA拷贝、1次cpu拷贝、2次内核态用户态切换
这其实还是会有一次cpu拷贝,如何实现真正的零拷贝?
sendfile+DMA scatter/gather实现真正的零拷贝
1、用户程序发起sendfile()系统调用,由用户态切换为内核态1次状态切换),
2、内核通过DMA将数据拷贝到内核缓冲(一次DMA拷贝)
3、内核把缓冲区的地址以及偏移量(数据长度)发送到到输出的缓冲区
4、内核通过DMA把数据从内核缓冲直接通过DMA拷贝到硬件网卡(一次DMA拷贝),sendfile()系统调用返回,由内核态切换为用户态(1次状态切换)
2次DMA拷贝、2次内核态用户态切换;没有cpu拷贝:真正的零拷贝