如何提升sysfs及虚拟文件系统的文件读取速度?
问题描述
使用sysfs采集CPU信息时,单个pread()调用开销可控,但循环读取多个CPU的sysfs文件(如每个CPU的cpuinfo_cur_freq)时,系统调用的开销会快速累积。示例代码如下:
int cpu0_freq_open() { int fd = open("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq", O_RDONLY | O_NONBLOCK); } int cpu0_freq_read(int fd) { char buffer[64]; if ( pread(fd, &buffer, sizeof(buffer), 0) == -1 ) { printf("Reading failed"); return 1; } int freq = atoi(buffer); // function call to store the event value at this timestamp } int main() { int fd_cpu0 = cpu0_freq_open(); // we open for all cpu#s // do some action here // make a lot of cpu0_freq_read(fd_cpu0) calls for cpu0 and all other cpus cpu0_freq_close(); }
原本考虑的内存映射方案因sysfs虚拟文件系统特性无法适用,需要找到提升sysfs文件读取速度的方法,以及针对虚拟文件系统的整体优化方案。
优化方案
一、针对sysfs CPU信息读取的专项优化
1. 批量读取+结果缓存
避免单次读取单个CPU的单个文件,改为周期性批量读取所有目标CPU的相关文件,将结果缓存到内存中。后续业务逻辑直接从缓存获取数据,大幅减少系统调用次数:
- 预先打开所有CPU的
cpuinfo_cur_freq文件描述符 - 每隔固定时间(如10ms)批量调用
pread()读取所有CPU的频率数据并更新缓存 - 业务代码直接读取缓存值,无需发起新的系统调用
2. 长期复用文件描述符
确保所有需要读取的sysfs文件描述符长期保持打开状态(示例代码已实现此点),避免每次读取时执行open()/close()系统调用——这两个操作的开销远高于pread(),高频场景下会显著拖慢性能。
3. 用汇总接口替代单个文件读取
部分场景下可借助proc或sysfs的汇总接口减少读取次数:
/proc/stat可获取CPU整体运行状态,/proc/cpuinfo能读取静态CPU属性(注意:其中的cpu MHz为初始频率,动态频率仍需依赖sysfs的cpufreq目录)- 若系统支持
cpufreq的policy级目录(如/sys/devices/system/cpu/cpufreq/policy0),可通过该目录下的文件批量获取同policy组内CPU的频率信息
4. 异步IO批量处理请求
使用io_uring机制,将多个sysfs文件的读取请求一次性提交到内核批量处理。io_uring通过减少用户态与内核态的切换次数,能显著降低高频系统调用的总开销,适合大量小文件的读取场景。
二、虚拟文件系统(VFS)整体优化方案
1. 减少路径解析开销
用openat()替代open(),预先打开父目录的文件描述符,后续通过相对路径打开子文件:
- 先打开父目录fd:
int cpu_dir_fd = open("/sys/devices/system/cpu/", O_DIRECTORY | O_RDONLY); - 再通过
openat(cpu_dir_fd, "cpu0/cpufreq/cpuinfo_cur_freq", O_RDONLY | O_NONBLOCK)打开目标文件
这种方式利用内核已缓存的目录项(dentry),避免重复解析完整路径,提升文件打开速度。
2. 提升VFS缓存命中率
- 保持访问路径的一致性,让内核缓存常用的目录项和inode,减少元数据查询开销
- 避免频繁访问大量不同路径的文件,防止缓存被频繁替换导致命中率下降
3. 选择高效的系统调用
- 批量读取目录内容时,使用
getdents()替代多次readdir(),一次性获取多个目录项,减少系统调用次数 - 读取小文件时,优先使用
read()或pread()(无需额外lseek()操作),避免复杂IO接口带来的额外开销
4. 减少不必要的数据拷贝
sysfs文件内容通常很小,内核会通过copy_to_user()将数据拷贝到用户态。若批量读取多个文件,可尝试将结果写入连续的用户态缓冲区,减少多次拷贝的开销——此优化仅在极端高频场景下考虑,需权衡实现复杂度。
内容的提问来源于stack exchange,提问作者Kron
相关产品推荐
相关产品推荐

