iOS -如何测量线程唤醒?

6tqwzwtp  于 2022-12-05  发布在  iOS
关注(0)|答案(3)|浏览(162)

我有一个应用程序因为太多“线程唤醒”而崩溃。例如:
过去220秒内有45004次唤醒(平均每秒205次唤醒),超过300秒内每秒150次唤醒的限制
这很难调试,因为我不知道有什么直接的方法来测量线程唤醒。我找到的最接近的方法是一个称为“系统跟踪”的“仪器”模板,它会显示阻塞线程事件的数量。据推测,这是密切相关的,因为阻塞线程意味着该线程将休眠,然后在解除阻塞时唤醒。
奇怪的是,当应用程序正常运行并且没有崩溃时,阻塞线程的数量在每秒10,000个范围内。我的假设是,阻塞的、休眠的线程只在某些情况下计入“唤醒”限制--例如,我认为由于互斥锁而被锁定的线程也会计入。而在正常操作中简单地转换到其他线程的操作系统则不会。
如果Instruments有一个线程唤醒模板,我会很惊讶。我能找到的唯一文档在这里-https://developer.apple.com/library/content/technotes/tn2151/_index.html
异常子类型WAKEUPS表示进程中的线程每秒被唤醒太多次,这迫使CPU非常频繁地被唤醒并消耗电池寿命。
通常,这是由线程到线程的通信(通常使用peformSelector:onThread:dispatch_async)导致的,这种通信在无意中发生的频率远远超过了它应该发生的频率。由于触发此异常的通信类型发生得如此频繁,因此通常会有多个后台线程具有非常相似的回溯跟踪-指示通信的起源。

kwvwclae

kwvwclae1#

下面是一些基于Ivan答案的Objective-C代码,您可以将其复制并粘贴到项目中的某个位置(例如,您的applicationDidFinishLaunching:方法),以记录每秒唤醒的次数(适用于Mac和iOS):

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

...

__block NSUInteger lastWakeups = 0;
[NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
    struct task_power_info info = {0};
    mach_msg_type_number_t count = TASK_POWER_INFO_COUNT;
    kern_return_t ret = task_info(current_task(), TASK_POWER_INFO, (task_info_t)&info, &count);
    if (ret == KERN_SUCCESS) {
        NSUInteger wakeups = info.task_interrupt_wakeups + info.task_timer_wakeups_bin_1 + info.task_timer_wakeups_bin_2;
        NSLog(@"WAKEUPS: %lu per second", (unsigned long)(wakeups - lastWakeups));
        lastWakeups = wakeups;
    } else {
        NSLog(@"Error: unable to get CPU wakeups (%d)", ret);
    }
}];
cwxwcias

cwxwcias2#

请看这里https://developer.apple.com/forums/thread/124180这里有一个在您的应用程序中获取唤醒计数的代码描述,而不仅仅是在仪器中。

#include <mach/task.h>
#include <mach/mach.h>
BOOL GetSystemWakeup(NSInteger *interrupt_wakeup, NSInteger *timer_wakeup) {
  struct task_power_info info = {0};
  mach_msg_type_number_t count = TASK_POWER_INFO_COUNT;
  kern_return_t ret = task_info(current_task(), TASK_POWER_INFO, (task_info_t)&info, &count);
  if (ret == KERN_SUCCESS) {
    if (interrupt_wakeup) {
      *interrupt_wakeup = info.task_interrupt_wakeups;
    }
    if (timer_wakeup) {
      *timer_wakeup = info.task_timer_wakeups_bin_1 + info.task_timer_wakeups_bin_2;
    }
    return true;
  }
  else {
    if (interrupt_wakeup) {
      *interrupt_wakeup = 0;
    }
    if (timer_wakeup) {
      *timer_wakeup = 0;
    }
    return false;
  }
}

此外,您还可以找到唤醒次数过多的一些原因。

sbdsn5lh

sbdsn5lh3#

最后的“Energy Efficiency Guide for Mac Apps“提到了一个名为timerfires的命令行实用程序,可以用来查看是什么导致了唤醒。
然而,该实用程序在macOS 12 Monterey上似乎已经过时了,因为当我第一次尝试运行它时,出现了如下错误:
探测器说明fbt::thread_dispatch:entry与任何探测器都不匹配
我必须复制该实用程序并对其进行编辑,以删除所有不再可用的DTrace方法,从而使该工具正常工作。
完成后,该工具将显示每个计时器调用,这对于跟踪计时器以减少唤醒非常有帮助。

相关问题