linux write函数耗时分析

本文深入探讨Linux内核中write函数的调用过程,涉及页高速缓存、内核回写线程的工作原理。分析了write函数可能导致的卡顿原因,以及如何通过调整内核参数优化IO性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、背景:

嵌入式设备写SD卡的时候,偶尔会出现调用write卡顿,内核linux-3.4.y

二、linux内核io流程

1. 应用程序调用write,陷入内核执行vfs_write函数,将数据写入页高速缓存(每个缓存页包含若干个缓冲区)。而在写入之前需要(1)检查页是否在回写,如果正在回写则挂起进程,等待回写标志清空时唤醒进程;(2)检查页buffer是否locked,如果locked则挂起进程等待唤醒

2. 内核有一个常驻线程,为每个bdi创建一个线程,定时检查是否需要回写,需要则提交bio,让驱动写入sd卡

3. bio结束时执行回调,将页回写标志清除三、相关函数分析(记录主要函数,方便跟踪源码)

三、内核代码分析

1. 写页高速缓存

(1)重要结构: 


const struct file_operations fat_file_operations = {
    .llseek        = generic_file_llseek,
    .read        = do_sync_read,
    .write        = do_sync_write,
    .aio_read    = generic_file_aio_read,
    .aio_write    = generic_file_aio_write,
    .mmap        = generic_file_mmap,
    .release    = fat_file_release,
    .unlocked_ioctl    = fat_generic_ioctl,
#ifdef CONFIG_COMPAT
    .compat_ioctl    = fat_generic_compat_ioctl,
#endif
    .fsync        = fat_file_fsync,
    .splice_read    = generic_file_splice_read,
};

struct address_space_operations {
    int (*writepage)(struct page *page, struct writeback_control *wbc);
    int (*readpage)(struct file *, struct page *);
    int (*sync_page)(struct page *);
    int (*writepages)(struct address_space *, struct writeback_control *);
    int (*set_page_dirty)(struct page *page);
    int (*readpages)(struct file *filp, struct address_space *mapping,
                    struct list_head *pages, unsigned nr_pages);
 
### 文操作与性能分析 `fopen` 函数用于打开文并创建一个 `FILE *` 类型的文流指针,该函数内部会初始化一系列结构体以及设置缓冲区等资源。由于涉及到了用户空间缓冲区(即 stdio 缓冲区),其执行过程中可能存在一些潜在的性能瓶颈。 #### 用户空间缓冲的影响 当调用 `fopen` 执行文读写时,默认情况下会启用全缓冲模式,在这种模式下,程序不会每次请求都直接访问磁盘而是先将数据存储到内存中的缓存区域里再批量处理。虽然这种方式减少了实际 I/O 次数从而提高了效率,但如果应用程序频繁地进行少量数据的操作,则可能会因为等待填满整个缓冲区而增加延迟时间[^1]。 ```c // 设置无缓冲模式可以减少因缓冲带来的额外开销 setvbuf(fp, NULL, _IONBF, 0); ``` #### 使用低级接口绕过标准库层 为了获得更好的控制力和更优的性能表现,可以直接利用底层操作系统所提供的 API 来代替高级别的 C 库函数。例如 Linux 下可以通过 `open()` 创建新的文描述符,并配合其他系统调用来完成相应的功能而不必经过复杂的封装逻辑。不过需要注意的是这样做会使代码失去跨平台特性并且增加了复杂度[^2]。 ```c #include <fcntl.h> #include <unistd.h> int fd = open("example.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd != -1) { // 对应于 fopen 的后续操作... } ``` #### 利用内存映射提高大文处理速度 针对非常庞大的文或者需要随机访问其中部分内容的情况,采用内存映射技术能够显著提升工作效率。这种方法允许进程把部分或全部文的内容映射至自己的地址空间内当作常规变量一样对待,既简化了编程模型又加快了读取/修改的速度[^4]。 ```java import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; try (FileChannel channel = new RandomAccessFile("largeData.bin", "rw").getChannel()) { MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, channel.size()); // 处理已映射的数据 } catch (Exception e) { System.out.println(e.getMessage()); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值