C 为什么nanosleep()会增加一个恒定的延迟,我如何避免这种情况?
我想用我的树莓3驱动步进电机。我需要每秒产生大约10000个脉冲,这意味着我需要以大约100us的间隔产生脉冲。我知道Raspberry可以生成PWM,但事实并非如此,因为我需要精确控制脉冲数以及加速/减速,所以我更喜欢显式循环 虽然忙循环提供了非常精确的计时,但它显然消耗了100%的CPU时间。同时,nanosleep()在时间精度和CPU负载之间提供了很好的平衡——我可以用大约10%的CPU负载驱动电机 但是。我写了一小段代码来测量nanosleep()延迟C 为什么nanosleep()会增加一个恒定的延迟,我如何避免这种情况?,c,raspberry-pi,real-time,C,Raspberry Pi,Real Time,我想用我的树莓3驱动步进电机。我需要每秒产生大约10000个脉冲,这意味着我需要以大约100us的间隔产生脉冲。我知道Raspberry可以生成PWM,但事实并非如此,因为我需要精确控制脉冲数以及加速/减速,所以我更喜欢显式循环 虽然忙循环提供了非常精确的计时,但它显然消耗了100%的CPU时间。同时,nanosleep()在时间精度和CPU负载之间提供了很好的平衡——我可以用大约10%的CPU负载驱动电机 但是。我写了一小段代码来测量nanosleep()延迟 无符号长迭代次数=5000; 对
无符号长迭代次数=5000;
对于(int d=10;d
1) 为什么我期望的睡眠时间和实际的睡眠时间有差异
Linux可能会等到所需的时间过去,然后花一定的时间切换回您的任务并从内核返回
3) 如果CPU负载增加,为什么这种差异会变小(我的预期正好相反)
当CPU无事可做(例如,因为你在“纳米延迟”)时,Linux可能会将CPU置于某种睡眠状态以降低功耗;当延迟到期时,需要额外的时间来唤醒CPU。当然,如果CPU还有其他工作要做,它就不会进入睡眠状态(也不会节省电源),也不需要被唤醒
请注意,使用TIMER\u ABSTIME来确保额外的延迟是恒定的(并且不会增加-例如,这次延迟65微秒,下次延迟130微秒,之后延迟196微秒,…)可能会更有趣。您的进程是从用户空间运行的。为了睡眠和获得时间,您需要切换到内核空间。这会产生间接费用。此外,任何睡眠功能都只能保证在睡眠计时器过期后的某个时间唤醒
总之,为了获得所需的精度,您可能需要以设备驱动程序的形式编写代码。这使您可以直接访问所需的高分辨率计时器
1)为什么期望睡眠时间与实际睡眠时间之间存在差异?
:
虽然通常有最短时间段的保证,但没有严格保证线程会立即或很快运行,甚至在指定的时间过去后根本不会运行。这取决于调度程序的判断,并取决于线程优先级和实现细节,如休眠线程再次运行时的计时器分辨率
这也适用于Linux。若您的流程是关键的,您可以使用命令提高其优先级,这将影响流程调度,并可能给您带来更好的结果
2)这种差异非常稳定,不依赖于请求的延迟。有人对此有解释吗?
除了上面提到的,另一个因素是。摘自维基百科:
在计算中,上下文切换是存储进程或线程状态的过程,以便以后可以从同一点恢复进程或线程状态并恢复执行。这允许多个进程共享一个CPU,这是多任务操作系统的一个基本特性
显然,上下文切换需要时间,这是测试中应该考虑的
3)如果CPU负载增加,为什么这种差异会变小(我的预期正好相反)?
有,默认为ondemand
。摘自内核文档:
CPUfreq调控器“ondemand”根据CPU频率设置
当前系统负载
这意味着如果有更大的CPU负载,您的系统可能会响应更快
对于测试,您可能希望将调控器设置为performance
或userspace
,以获得不受CPU速度动态变化影响的结果:
echo performance > /sys/bus/cpu/devices/cpu0/cpufreq/scaling_governor
echo 1000000 > /sys/bus/cpu/devices/cpu0/cpufreq/scaling_max_freq
计时器延迟(即期望睡眠时间和实际睡眠时间之间的差异)似乎是由名为timer_slop的内核参数引起的。它的默认值是50 us,这意味着您的计时器将延迟最多50 us。定时器斜率的设计是为了通过分批处理定时器中断来提高系统性能,从而减少定时器中断的数量
您可以通过文件/proc/[pid]/timerslack\n更改进程的计时器斜率。
例如,命令echo 10000>/proc/[pid]/timerslack\u ns
将计时器斜率更改为10 us。是的,我正在考虑编写内核模块,但这需要一些时间来学习如何做到这一点。谢谢,切换到“性能”模式使延迟更加稳定。它不再依赖于CPU负载,但仍然是大约60us。增加了1和2的答案。
10 80 70
15 85 70
20 89 69
25 95 70
30 99 69
35 105 70
40 110 70
45 114 69
50 123 70
55 124 69
60 129 69
65 134 69
70 130 60 <---- here I run CPU-heavy process
75 135 60
80 140 60
85 145 60
90 150 60
95 158 62
100 161 61
105 166 61
110 172 62
115 177 62
120 181 61
125 186 61
130 191 61
135 205 70 <---- here it finished
140 210 70
145 215 70
150 220 70
155 225 70
160 230 70
165 235 70
echo performance > /sys/bus/cpu/devices/cpu0/cpufreq/scaling_governor
echo 1000000 > /sys/bus/cpu/devices/cpu0/cpufreq/scaling_max_freq