今天有用戶(hù)反饋予借,在mac微信不退出的情況下,蓋上電腦,發(fā)熱會(huì)比較厲害灵迫,然后打開(kāi)電腦秦叛,用活動(dòng)監(jiān)視器看到mac微信的能耗和CPU占用率都比較高。很自然的想法就是瀑粥,蓋上電腦期間挣跋,mac微信究竟干了什么事情,這些事情當(dāng)中狞换,又有哪些比較耗CPU避咆?
如果是開(kāi)著電腦,并且可以重現(xiàn)修噪,就可以用instrument來(lái)定位耗CPU的業(yè)務(wù)代碼查库。然而,蓋上電腦沒(méi)法用instrument黄琼,所以只能靠日志了樊销。那么,日志要怎么加适荣,才能讓CPU占用率跟特定的業(yè)務(wù)代碼關(guān)聯(lián)起來(lái)呢现柠?
mach內(nèi)核中有數(shù)據(jù)結(jié)構(gòu)記錄了每個(gè)線(xiàn)程的CPU占用率,而堆棧調(diào)用分析框架(這里選用BSBacktraceLogger)可以打出每個(gè)線(xiàn)程執(zhí)行的現(xiàn)場(chǎng)日志弛矛,兩者結(jié)合够吩,就是我們想要的。下面直接上代碼:
kern_return_t kr;
task_info_data_t tinfo;
mach_msg_type_number_t task_info_count;
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 nil;
}
thread_array_t thread_list; // 線(xiàn)程數(shù)組
mach_msg_type_number_t thread_count; // 線(xiàn)程數(shù)
thread_info_data_t thinfo;
mach_msg_type_number_t thread_info_count;
thread_basic_info_t basic_info_th;
kr = task_threads(mach_task_self(), &thread_list, &thread_count); // 獲取線(xiàn)程列表和線(xiàn)程數(shù)
if (kr != KERN_SUCCESS) {
return nil;
}
NSString* backstraces = nil;// 遍歷每個(gè)線(xiàn)程
for (int j = 0; j < thread_count; j++)
{
thread_info_count = THREAD_INFO_MAX;
kr = thread_info(thread_list[j], THREAD_BASIC_INFO, (thread_info_t)thinfo, &thread_info_count); //獲取線(xiàn)程信息
if (kr != KERN_SUCCESS) {
return nil;
}
basic_info_th = (thread_basic_info_t)thinfo; // 線(xiàn)程基本信息丈氓,包含CPU占用率周循、CPU占用時(shí)間等等
if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
float current_thread_cpu = basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * 100.0; // 當(dāng)前線(xiàn)程的CPU占用率
if(current_thread_cpu >= 自定義單核CPU占用率閾值){
// 記錄CPU占用率超過(guò)閾值的線(xiàn)程的執(zhí)行堆棧
NSString* backstrace = [BSBacktraceLogger bs_backtraceOfMachThread:thread_list[j]];
backstraces = [NSString stringWithFormat:@"%@\n%@", backstraces, backstrace];
}
}
}
kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
return backstraces;
這里只是拋磚引玉,有待后續(xù)深入研究万俗。