延迟OSX 10.10上的代码执行

时间:2015-02-28 18:28:02

标签: grand-central-dispatch osx-yosemite nsthread mach usleep

我遇到了一个非常奇怪的问题,影响我的代码仅在OSX 10.10系统上运行。我已经看到这种异常发生在运行我的代码的超过25个OSX 10.10系统上,而完全相同的代码在升级之前没有表现出这种行为(10.7)。此外,该问题不是100%可再现的,因为它在0-5%的时间内随机发生。在测试代​​码时,机器上没有其他任何关键或CPU穷举。即使发生了其他事情,我所经历的延误太长得太荒谬,这个结论似乎很可疑。无论如何,不​​用多说,看看下面的NSLog打印:

12:00:05.766 MyApp[59957:6540517] Time_To_Wait: 679000000, Fire_Date: 270946738287700, Cur_Date: 270946059302734
12:00:26.446 MyApp[59957:6540517] Resume...

时间以纳秒为单位。根据NSLog时间戳,我们实际上最终等待了20.68秒,而不是期望的0.679秒。现在,我们来看看代码:

NSLog(@"Time_To_Wait: %lld, Fire_Date: %lld, Cur_Date: %lld", time_to_wait, fire_date, mach_absolute_time());
mach_wait_until(fire_date);
NSLog(@"Resume...");

如果你想知道mach_wait是什么,它是一个默认的高分辨率计时器。只需加入

#include <mach/mach.h>
#include <mach/mach_time.h>

但这并不重要,因为如果我将mach_wait_until替换为:

,我遇到了完全相同的问题
  • sleep()
  • usleep()
  • [NSThread sleepForTimeInterval:]
  • GCD's dispatch_after(,^{});
  • mach_wait_until()

无论我尝试使用何种延迟方法,我使用NSLog将“延迟”值打印到控制台作为完整性检查以确保它是正确的ms,然后触发其中一个以上。它按照规范行事的时间约为95%。但偶尔随机,我会得到一些重击延迟,如10-20秒。是什么赋予了?这是一些优胜美地内核问题吗?再一次,我从来没有经历过在10.7上运行的相同代码。我已经测试了所有上述延迟代码执行的方法。


更新:

根据评论建议,我继续sudo dtruss -f -e sudo -u USER MyApp 2> ~/myapps.log。像往常一样,大多数mach_wait和sleeps都按照预期的方式行事。因此,为了使事情更易于识别,我在检查中添加了实际睡眠持续时间是否>它应该是3倍,打印出DELAY ISSUE。跑我的程序,并搜索延迟问题。下面列出的是紧接在mach_wait语句之前和之后的日志打印之间发生的最频繁的系统调用(dtruss输出):

  • 99613 / 0xcf33b9:30250 __semwait_signal(0xD07,0x0,0x1)= -1 Err#60
  • 99613 / 0xcf33b9:16 workq_kernreturn(0x20,0x0,0x1)= 0 0

上述两个电话约有250+。可能比__semwait更多的工作。无论如何,semwait通常需要大约30000'单位'的时间才能完成。敦诺如何度过难关。这些构成了大部分电话。

  • 752 / 0xcf3320:2787191 kevent64(0x3,0x0,0x0)= 1 0
  • 752 / 0xcf335d:189948 select(0x40,0x7FC080E18220,0x7FC080E13B40,0x0,0x0)= 1 0
  • 752 / 0xcf335d:1648403 select(0x40,0x7FC080E18220,0x7FC080E13B40,0x0,0x0)= 1 0

这三个系统调用占用了最长的单位时间。在我们约20秒的等待间隙期间,它们每个都出现在输出中。

不确定如何处理上述= X

1 个答案:

答案 0 :(得分:3)

见上面的评论

该问题似乎与Apple的计时器合并相关联,这是Mac OS X 10.9 Mavericks中的一项新功能,它可以将计时器的触发时间缩短几毫秒来合并它们,从而允许处理器可以减少电源状态转换并保持空闲时间更长。这样做的好处是大大降低了功耗。

Apple关于短暂提及的主题的白皮书是here

评论中保留的解决方案是禁用TC,如下所示:

sudo sysctl -w kern.timer.coalescing_enabled=0