Bursty写入SD / USB使我的时间紧迫的应用程序停滞在嵌入式Linux上
我正在从事一个嵌入式Linux项目,该项目将ARM9连接到硬件视频编码器芯片,并将视频写到SD卡或者USB记忆棒中。该软件体系结构包括将数据读入缓冲区池的内核驱动程序,以及将数据写入已安装的可移动设备上的文件的userland应用程序。
我发现在一定的数据速率(大约750kbyte / sec)以上时,我开始看到userland视频编写应用程序停顿了大约半秒钟,大约每5秒。这足以导致内核驱动程序用尽缓冲区,即使我可以增加缓冲区的数量,视频数据也必须与实时进行的其他事情同步(理想情况下是在40毫秒之内)。在这5秒的"滞后尖峰"之间,写入在40ms内完成得很好(就应用程序而言,我很欣赏它们被操作系统缓冲了)
我认为这种延迟高峰与Linux将数据刷新到磁盘的方式有关。我注意到pdflush旨在每5s唤醒一次,我的理解是这将是写作的目的。一旦失速结束,userland应用程序便可以快速服务并编写缓冲区的积压(未溢出)。
我认为我正在写入的设备具有合理的最终吞吐量:从内存fs复制15MB文件并等待同步完成(并且USB记忆棒的光停止闪烁)使我的写入速度约为2.7MBytes / sec。
我正在寻找两种线索:
- 如何阻止突发写入停止我的应用程序-可能是处理优先级,实时补丁或者调整文件系统代码以连续写入而不是突发写入?
- 如何在写入积压和卡/棒的吞吐量方面使我的应用程序了解文件系统的状况?我能够即时更改硬件编解码器中的视频比特率,这比丢弃帧或者对最大允许比特率强加人工上限要好得多。
更多信息:这是一个200MHz的ARM9,当前运行基于Montavista 2.6.10的内核。
回答
这是一些有关为大量写操作调整pdflush的信息。
回答
有调试帮助,我们可以使用strace来查看花费时间的操作。
FAT / FAT32可能有些令人惊讶的事情。
我们要写入单个文件还是多个文件?
我们可以创建一个读取线程,该线程将维护准备写入队列的视频缓冲池。
接收到帧后,将其添加到队列中,并向写线程发出信号
共享资料
SYNC(2) Linux Programmer’s Manual SYNC(2) NAME sync - commit buffer cache to disk SYNOPSIS #include <unistd.h> void sync(void); Feature Test Macro Requirements for glibc (see feature_test_macros(7)): sync(): _BSD_SOURCE || _XOPEN_SOURCE >= 500 DESCRIPTION sync() first commits inodes to buffers, and then buffers to disk. ERRORS This function is always successful.
阅读线程:
empty_buffer_queue ready_buffer_queue video_data_ready_semaphore
编写线程
buf=get_buffer() bufer_to_write = buf_dequeue(empty_buffer_queue) memcpy(bufer_to_write, buf) buf_enqueue(bufer_to_write, ready_buffer_queue) sem_post(video_data_ready_semaphore)
如果写线程在等待内核时被阻止,则可能有效。
但是,如果我们被限制在内核空间之内,那么除了寻找比2.6.10更新的内核外,我们无能为力。
回答
想要自己控制自己,执行flush()听起来很对我,而不是让通用缓冲层变幻莫测。
这可能很明显,但是请确保我们不会经常调用write(),以确保每个write()都有足够的数据要写入,以使syscall开销值得。另外,从另一个方向讲,也不要称它太少,否则它会阻塞足够长的时间而导致出现问题。
在更难以实现的轨道上,我们是否尝试过切换到异步I / O?使用aio,我们可以在将视频数据吸入另一组缓冲区时触发写操作并将其交给一组缓冲区,而在写操作完成后,我们可以切换一组缓冲区。
回答
一个有用的Linux函数以及sync或者fsync的替代方法是sync_file_range。这样,我们就可以调度要写入的数据,而不必等待内核缓冲系统熟悉它。
为避免长时间停顿,请确保IO队列(例如:/ sys / block / hda / queue / nr_requests)足够大。该队列是从内存中刷新数据到磁盘之间进入数据的地方。
请注意,sync_file_range不可移植,并且仅在内核2.6.17及更高版本中可用。
回答
记录下来,除了最极端的情况外,似乎有两个主要方面消除了这个问题。该系统仍在开发中,尚未经过严格的折磨测试,但运行良好(触摸木头)。
最大的胜利来自使userland writer应用程序成为多线程。有时会阻塞对write()的调用:其他进程和线程仍在运行。只要我有一个线程为设备驱动程序提供服务,并更新帧计数和其他数据以与正在运行的其他应用程序同步,就可以在几秒钟后对数据进行缓冲和写出,而不会超出任何期限。我首先尝试了一个简单的乒乓双缓冲,但这还不够。小缓冲区将不堪重负,而大缓冲区只会在文件系统消化写入操作时造成较大的暂停。在线程之间排队的10个1MB缓冲区池现在运行良好。
另一个方面是关注物理介质的最终写入吞吐量。为此,我一直关注stat脏:/ proc / meminfo报告。如果"脏",我有一些粗糙的现成代码可以限制编码器:爬到某个阈值之上,似乎可以正常工作。以后需要更多测试和调整。幸运的是,我有很多RAM(128M)可以玩,给了我几秒钟的时间来查看积压的积压和平稳地减少油压。
如果我发现需要采取其他措施来解决此问题,我会尽量记住弹出并更新此答案。多亏了其他回答者。
回答
有人告诉我主机发送命令后,MMC和SD卡"必须在0到8个字节内响应"。
但是,规范允许这些卡在完成操作之前以"忙"响应,并且显然对卡可以声称处于忙状态的时间没有限制(请告诉我是否有这样的限制)。
我看到一些低成本的闪存芯片(例如M25P80)的"最大单扇区擦除时间"保证为3秒,尽管通常"仅"需要0.6秒。
可疑的0.6秒听起来与我们"待约半秒钟"相似。
我怀疑廉价,慢速闪存芯片与昂贵,快速闪存芯片之间的权衡与USB闪存驱动器结果的巨大差异有关:
- 在打开文件时通过
O_SYNC
标志,这将导致每个写操作都被阻塞,直到被写入磁盘为止,这将消除我们写操作的突发行为...代价是每次写操作都变慢。 - 如果我们正在从设备进行读取/操作以获取视频数据块,则可能需要考虑在应用程序和内核之间分配一个共享内存区域,否则在传输视频时会遇到一堆" copy_to_user"调用从内核空间到用户空间的数据缓冲区。
我听说有传言说,每次擦除闪存扇区然后对其进行重新编程时,都会比上次花费更长的时间。
因此,如果我们有时间紧迫的应用程序,则可能需要(a)测试SD卡和USB记忆棒,以确保它们满足应用程序所需的最小延迟,带宽等,并且(b)定期重新测试或者抢先更换这些存储设备。
列表数量不匹配
列表数量不匹配
列表数量不匹配
代码数量不匹配