在 OSX 10.10 上延迟代码执行
Delaying Code Execution on OSX 10.10
我遇到了一个非常奇怪的问题,它仅在 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
将我的 'delay' 值打印到控制台作为完整性检查,以确保它是正确的毫秒数,然后解雇上述之一。 ~95% 的时间它的行为符合规范。但偶尔随机地,我会得到一些 10-20 秒的重击延迟。是什么赋予了?这是一些 Yosemite 内核问题吗?同样,我从未在 10.7 上遇到过使用相同代码 运行 的情况。并且我已经测试了以上所有延迟代码执行的方法。
更新:
根据评论建议,我继续 sudo dtruss -f -e sudo -u USER MyApp 2> ~/myapps.log
。和往常一样,大多数 mach_wait 和睡眠都按照预期的方式行事。因此,为了让事情更容易识别,我添加了一个检查,如果实际睡眠持续时间 > 3 倍,它会打印出延迟问题。 运行 我的程序并搜索了延迟问题。下面列出的是在 mach_wait 语句之前和之后的日志打印之间发生的最频繁的系统调用(dtruss 输出):
- 99613/0xcf33b9: 30250 __semwait_signal(0xD07, 0x0, 0x1) = -1 错误#60
- 99613/0xcf33b9: 16 workq_kernreturn(0x20, 0x0, 0x1) = 0 0
以上两个调用大约有 ~250+ 个。可能比 __semwait 多一些。 semwait 通常需要大约 30000 'units' 的时间才能完成,不管是什么。不知道 dtruss 时代如何。这些构成了大部分电话。
- 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
见上面评论
该问题似乎与 Apple 的 Timer Coalescing 有关,这是 Mac OS X 10.9 Mavericks 中的一项新功能,可重新调整计时器的触发时间最多几毫秒以合并它们,从而允许处理器进行更少的电源状态转换并保持空闲更长时间。好处是功耗大大降低。
Apple 的一份白皮书简要提到了它的主题是 here。
评论中保留的解决方案是禁用TC,如下:
sudo sysctl -w kern.timer.coalescing_enabled=0
我遇到了一个非常奇怪的问题,它仅在 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
将我的 'delay' 值打印到控制台作为完整性检查,以确保它是正确的毫秒数,然后解雇上述之一。 ~95% 的时间它的行为符合规范。但偶尔随机地,我会得到一些 10-20 秒的重击延迟。是什么赋予了?这是一些 Yosemite 内核问题吗?同样,我从未在 10.7 上遇到过使用相同代码 运行 的情况。并且我已经测试了以上所有延迟代码执行的方法。
更新:
根据评论建议,我继续 sudo dtruss -f -e sudo -u USER MyApp 2> ~/myapps.log
。和往常一样,大多数 mach_wait 和睡眠都按照预期的方式行事。因此,为了让事情更容易识别,我添加了一个检查,如果实际睡眠持续时间 > 3 倍,它会打印出延迟问题。 运行 我的程序并搜索了延迟问题。下面列出的是在 mach_wait 语句之前和之后的日志打印之间发生的最频繁的系统调用(dtruss 输出):
- 99613/0xcf33b9: 30250 __semwait_signal(0xD07, 0x0, 0x1) = -1 错误#60
- 99613/0xcf33b9: 16 workq_kernreturn(0x20, 0x0, 0x1) = 0 0
以上两个调用大约有 ~250+ 个。可能比 __semwait 多一些。 semwait 通常需要大约 30000 'units' 的时间才能完成,不管是什么。不知道 dtruss 时代如何。这些构成了大部分电话。
- 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
见上面评论
该问题似乎与 Apple 的 Timer Coalescing 有关,这是 Mac OS X 10.9 Mavericks 中的一项新功能,可重新调整计时器的触发时间最多几毫秒以合并它们,从而允许处理器进行更少的电源状态转换并保持空闲更长时间。好处是功耗大大降低。
Apple 的一份白皮书简要提到了它的主题是 here。
评论中保留的解决方案是禁用TC,如下:
sudo sysctl -w kern.timer.coalescing_enabled=0