在本节中,我们将说明如何在普通文件I/O上向内核提供建议。Linux为这类建议提供了两个接口:posix_fadvise()和readahead()。
posix_fadvise()系统调用
#include <fcntl.h>
int posix_fadvise(int fd, off_t offset, off_t len, int advice);
对posix_fadvise()的调用为内核提供了文件描述符fd上的对于[offset, offset+len)这一段的建议。如果len为0,则建议将应用于范围[offset,length of file]。
可供选择的advice参数有:
- POSIX_FADV_NORMAL
应用程序没有关于此文件范围的特定通知。它应该被视为正常。
内核像往常一样运行,执行适量的readahead操作。 - POSIX_FADV_RANDOM
应用程序打算访问特定的数据以随机的方式。
内核禁用readahead,只读取每个物理读取操作的最小数据量。 - POSIX_FADV_SEQUENTIAL
应用程序打算顺序地访问指定范围内的数据,从低地址到高地址。
内核执行积极的readahead,使readahead读取窗口的大小加倍。 - POSIX_FADV_WILLNEED
应用程序打算在不久的将来访问指定范围内的数据。
内核启动readahead,开始读取给定页面的内存。 - POSIX_FADV_NOREUSE
应用程序打算在不久的将来访问指定范围内的数据,但只访问 就一次。
-POSIX_FADV_DONTNEED
应用程序不打算在不久的将来访问指定范围内的页面。
当前,该行为与POSIX_FADV_WILLNEED相同;未来的内核可能会执行额外的优化来利用“一次性使用”行为。
内核从页面缓存中删除给定范围内的任何缓存数据。
//example
int ret;
ret = posix_fadvise(fd, 0,0, POSIX_FADV_RANDOM);
if(ret == -1){
perror("posix_fadvise");
}
成功后,返回0。如果失败,则返回−1,并设置errno。
readahead()系统调用
posix_fadvise()系统调用对于2.6Linux内核来说是新的。readahead()系统调用以前就有了,与POSIX_FADV_WILLNEED提示有相同的行为。
与posix_fadvise()不同的是, readahead() 是linux专属接口。
#define _GNU_SOURCE
#include <fcntl.h>
ssize_t readahead(int fd, off64_t offset, size_t count);
对readahead()的调用将从文件描述符fd中的区域[offset,偏offset+count)填充到页面缓存中。
成功后,readahead()返回0。如果失败,则返回−1,并设置errno。
Advice is cheap
一些常见的应用程序工作负载可以很容易地受益于对内核的一些善意的建议。这样的建议可以大大减轻I/O的负担。
在读取文件块之前,进程可以提供POSIX_FADV_WILLNEED提示,指示内核将文件读入页缓存。I/O将在后台异步发生。 当应用程序最终访问文件时,操作可以没有阻塞的完成。
相反,在读取或写入大量数据(例如,将视频连续流写到磁盘时),进程可以提供POSIX_FADV_DONTNEED提示,指示内核排除页缓存中给定的文件块。一个大的流操作可以持续地填充页面缓存.如果应用程序不再打算访问数据,这意味着页面缓存将充满多余的数据。 以牺牲潜在更有用的数据为代价。因此,流视频应用程序定期请求将流数据从缓存中清除是有意义的。
打算读取整个文件的进程可以提供POSIX_FADV_SEQUENTIAL提示,指示内核执行积极的readahead。相反的,一个进程知道自己会随机处理一个文件,寻求来回,可以提供POSIX_FADV_RANDOM提示,指示内核readahead将是毫无价值的开销。