怎样才能地址苹果手机CPU使用率呢?
CPU 是移动设备最重要的组成部分,如果开发者写的代码有问题导致CPU负载过高,会导致app使用过程中发生卡顿,同时也可能导致手机发热发烫,耗电过快,严重影响用户体验。
如果想避免CPU负载过高可以通过检测app的CPU使用率,然后可以发现导致CPU过高的代码,并根据具体情况优化。那该如何检测CPU使用率呢?大学期间学过计算机的应该都上过操作系统这门课,学过的都知道线程CPU是调度和分配的基本单位,而应用作为进程运行时,包含了多个不同的线程,这样如果我们能知道app里所有线程占用 CPU 的情况,也就能知道整个app的 CPU 占用率。幸运的是我们在Mach 层中 thread_basic_info 结构体发现了我们想要的东西,thread_basic_info 结构体定义如下:
struct thread_basic_info {
time_value_t user_time; /* user run time */
time_value_t system_time; /* system run time */
integer_t cpu_usage; /* scaled cpu usage percentage */
policy_t policy; /* scheduling policy in effect */
integer_t run_state; /* run state (see below) */
integer_t flags; /* various flags (see below) */
integer_t suspend_count; /* suspend count for thread */
integer_t sleep_time; /* number of seconds that thread
has been sleeping */
};
其中cpu_usage即为该线程的CPU使用率,接下来我们需要获取app的所有线程,iOS内核提供了 thread_info API 调用获取指定 task 的线程列表,然后可以通过 thread_info API 调用来查询指定线程的信息,thread_info API 在 thread_act.h 中定义。
kern_return_t task_threads
(
task_t target_task,
thread_act_array_t *act_list,
mach_msg_type_number_t *act_listCnt
);
task_threads 将 target_task 任务中的所有线程保存在 act_list 数组中。
现在我们能够取得app的所有线程,并且能够取得每个线程的CPU使用率,这样获取app的CPU使用率的代码就呼之欲出,直接上代码:
- (CGFloat)usedCpu {
kern_return_t kr = { 0 };
task_info_data_t tinfo = { 0 };
mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
kr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
if (kr != KERN_SUCCESS) {
return 0.0f;
}
task_basic_info_t basic_info = { 0 };
thread_array_t thread_list = { 0 };
mach_msg_type_number_t thread_count = { 0 };
thread_info_data_t thinfo = { 0 };
thread_basic_info_t basic_info_th = { 0 };
basic_info = (task_basic_info_t)tinfo;
// get threads in the task
kr = task_threads(mach_task_self(), &thread_list, &thread_count);
if (kr != KERN_SUCCESS) {
return 0.0f;
}
long tot_sec = 0;
long tot_usec = 0;
float tot_cpu = 0;
for (int i = 0; i < thread_count; i++) {
mach_msg_type_number_t thread_info_count = THREAD_INFO_MAX;
kr = thread_info(thread_list[i], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count);
if (kr != KERN_SUCCESS) {
return 0.0f;
}
basic_info_th = (thread_basic_info_t)thinfo;
if ((basic_info_th->flags & TH_FLAGS_IDLE) == 0) {
tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
tot_usec = tot_usec + basic_info_th->system_time.microseconds + basic_info_th->system_time.microseconds;
tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE;
}
}
kr = vm_deallocate( mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t) );
if (kr != KERN_SUCCESS) {
return 0.0f;
}
return (CGFloat)tot_cpu * 100;
}
有了获取CPU使用率的方法后我们只要再加个定时器去实时查询,并将得到的结果显示在界面上即可:
- (void)startMonitoringWithNoticeBlock:(void(^)(CGFloat value))noticeBlock {
self.noticeBlock = noticeBlock;
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(noticeCPUValue) userInfo:nil repeats:YES];
}
- (void)noticeCPUValue {
if (self.noticeBlock) {
self.noticeBlock([self usedCpu]);
}
}
网友评论