我正在使用嵌入式Linux内核进行项目,并且在访问闪存时遇到了线程延迟问题 .
我的应用程序是多线程的,有些线程必须在不到500毫秒的时间内完成给定的任务 . 问题是这些线程有时会在超过1秒的时间内“冻结”,并且我的执行时间超过500毫秒 .
这种行为似乎与闪存写入有关,因为它也发生在我从shell执行“dd”命令以在闪存中连续写入时 .
我尝试了各种配置:
-
增加了我的实时线程的优先级:SCHED_RR,priority = 55
-
更改了IO调度程序:deadline => cfq(更好:15分钟后失败而不是3分钟) .
通过使用ftrace工具,我可以看到,在“冻结”时间内,一些线程和进程仍在运行,其他任务之间有很多“空闲”任务时间(空闲任务时隙持续时间> 20ms):
-
2个网络线程(SCHED_RR,优先级= 50)
-
dd进程
我不明白:
-
为什么所有其他任务在所有这些时间内都是"locked"(有时在请求互斥锁时,有时在计算简单的16位-CRC时) .
-
为什么在此期间使用ftrace(在sched事件之间)可以看到如此多的空闲时间 .
-
为什么更高的应用程序线程优先级无法解决问题 .
我怀疑与内核中的IO管理有关的东西,好像内核抢占了每个非IO线程,以便完成与IO相关的所有工作(网络,文件......) .
有没有人知道可能导致这种延迟的原因?
我的内核设置:
-
Linux内核版本2.6.39
-
启用了Preempt选项
-
无所事事
-
HZ = 1000
-
CFQ调度程序(默认设置)
编辑:
由于我不是专家,我与你分享ftrace capture(与kernelshark一起查看):https://drive.google.com/file/d/0B6pJb20-D0D2NHZBUHJVRlV0aDg/view?usp=sharing
也许它可以帮助你了解我的系统上发生了什么 .
在这个捕获中,我使用外部“dd”命令再现了我在名义条件下应用程序遇到的类似行为 .
在时间戳上,“洞”(“冻结”)是(不再是我的应用程序中的自定义ftrace标记):
-
开始:469.118370
-
结束:469.802940
另一个小“洞”
-
开始:469.807644
-
结束:469.952975
2 回答
我认为这可能是因为内核已经决定它必须刷新一些文件系统元数据,或者做其他文件系统内务处理,并且必须停止你的进程,直到它做得足够 .
我遇到了类似的问题,并使用多线程和用户空间缓冲来吸收停顿 . 见my old question and answer here .
我更新了这个主题的状态:我们认为我们找到了锁定的根本原因 .
我公司聘请了一位Linux专家2天 .
多亏了他,我们发现:
锁是由内核完成数据刷新时阻止所有闪存访问的事实引起的 .
特别是我们的 Logger 模块(用于时间戳...),它调用syslog()函数 .
但是这个syslog()函数也阻塞了进程,即使syslogd守护进程是访问flash的真正进程...(我们怀疑用于syslog通信的unix套接字阻塞,直到资源可用,比如写入时的bash管道'|'很多日志都记录在flash中的文件中 .
解决方案是通过对隔离线程进行日志/闪存访问(使用非阻塞自定义消息Queue作为通信项),在实时线程和另一个线程之间拆分对闪存的所有访问权限
它似乎有效!
我之前没有读过blueshift的答案,但似乎他是对的;-)