APP 的 CPU 占用率
如何获取CPU的占用率: 应用作为进程运行时,包含了多个不同的线程,如果我们能获取应用的所有线程占用 CPU 的情况,也就能知道应用的 CPU 占用率
iOS 是基于 Apple Darwin 内核,由 kernel、XNU 和 Runtime 组成,而 XNU 是 Darwin 的内核,它是“X is not UNIX”的缩写,是一个混合内核,由 Mach 微内核和 BSD 组成。Mach 内核是轻量级的平台,只能完成操作系统最基本的职责,比如:进程和线程、虚拟内存管理、任务调度、进程通信和消息传递机制。其他的工作,例如文件操作和设备访问,都由 BSD 层实现
与 Mac OS X 类似,iOS 的线程技术也是基于 Mach 线程技术实现的,在 Mach 层中 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 */
};
Mach task 可以看作一个机器无关的 thread 执行环境的抽象 一个 task 包含它的线程列表。内核提供了 task_threads
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
数组中,数组中包含 act_listCnt
个条目。
kern_return_t thread_info
(
thread_act_t target_act,
thread_flavor_t flavor,
thread_info_t thread_info_out,
mach_msg_type_number_t *thread_info_outCnt
);
thread_info
查询 flavor
指定的 thread
信息,将信息返回到长度为 thread_info_outCnt
字节的 thread_info_out
缓存区中
获取当前应用的 CPU 占用率的实现如下:
#import <mach/mach.h>
#import <assert.h>
+ (CGFloat)appCpuUsage {
task_info_data_t tinfo;
mach_msg_type_number_t task_info_count = TASK_INFO_MAX;
/// THREAD_BASIC_INFO ,使用这个类型会返回线程的基本信息,定义在 thread_basic_info_t 结构体,包含了用户和系统的运行时间,运行状态和调度优先级
kern_return_t kr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)tinfo, &task_info_count);
if (kr != KERN_SUCCESS) {
return -1;
}
thread_array_t thread_list;
mach_msg_type_number_t thread_count;
thread_info_data_t thinfo;
mach_msg_type_number_t thread_info_count;
thread_basic_info_t basic_info_th;
// mach_task_self(),表示获取当前的 Mach task
kr = task_threads(mach_task_self(), &thread_list, &thread_count);
if (kr != KERN_SUCCESS) {
return -1;
}
long total_time = 0;
long total_userTime = 0;
CGFloat total_cpu = 0;
int j;
// for each thread
for (j = 0; j < (int)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);
if (kr != KERN_SUCCESS) {
return -1;
}
basic_info_th = (thread_basic_info_t)thinfo;
if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
total_time = total_time + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
total_userTime = total_userTime + basic_info_th->user_time.microseconds + basic_info_th->system_time.microseconds;
total_cpu = total_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * kMaxPercent;
}
}
/// 防止出现内存泄漏必须调用它
kr = vm_deallocate(mach_task_self(), (vm_offset_t)thread_list, thread_count * sizeof(thread_t));
assert(kr == KERN_SUCCESS);
return total_cpu;
}
CPU 核数
+ (NSUInteger)cpuNumber {
return [NSProcessInfo processInfo].activeProcessorCount;
}
CPU 频率
CPU 频率,就是 CPU 的时钟频率, 是 CPU 运算时的工作的频率(1秒内发生的同步脉冲数)的简称。单位是 Hz,它决定移动设备的运行速度。 在 iOS 中与 CPU 频率相关的性能指标有三个:CPU 频率,CPU 最大频率 和 CPU 最小频率。
+ (NSUInteger)getSysInfo:(uint)typeSpecifier {
size_t size = sizeof(int);
int results;
int mib[2] = {CTL_HW, typeSpecifier};
sysctl(mib, 2, &results, &size, NULL, 0);
return (NSUInteger)results;
}
+ (NSUInteger)getCpuFrequency {
return [self getSysInfo:HW_CPU_FREQ];
}
RAM(Random Access Memory)
物理内存(RAM)与 CPU 一样都是系统中最稀少的资源,也是最有可能产生竞争的资源,应用内存与性能直接相关 - 通常是以牺牲别的应用为代价。 不像 PC 端,iOS 没有交换空间作为备选资源,这就使得内存资源尤为重要。事实上,在 iOS 中就有 Jetsam 机制负责处理系统低 RAM 事件,Jetsam 是一种类似 Linux 的 Out-Of-Memory(Killer) 的机制。
App使用的内存
mach_task_basic_info
结构体存储了 Mach task 的内存使用信息,其中 resident_size
就是应用使用的物理内存大小,virtual_size
是虚拟内存大小。
#define MACH_TASK_BASIC_INFO 20 /* always 64-bit basic info */
struct mach_task_basic_info {
mach_vm_size_t virtual_size; /* virtual memory size (bytes) */
mach_vm_size_t resident_size; /* resident memory size (bytes) */
mach_vm_size_t resident_size_max; /* maximum resident memory size (bytes) */
time_value_t user_time; /* total user run time for
terminated threads */
time_value_t system_time; /* total system run time for
terminated threads */
policy_t policy; /* default policy for new threads */
integer_t suspend_count; /* suspend count for task */
};
task_info
API 根据指定的 flavor
类型返回 target_task
的信息。
kern_return_t task_info
(
task_name_t target_task,
task_flavor_t flavor,
task_info_t task_info_out,
mach_msg_type_number_t *task_info_outCnt
);
获取APP内存使用量
/**
获取APP内存使用量
@return byte
*/
+ (unsigned long long)getAppRAMUsage {
struct mach_task_basic_info info;
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
kern_return_t kr = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count);
if (kr != KERN_SUCCESS) {
return 0;
}
return info.resident_size;
}
获取系统内存总量
/**
获取系统内存总量
@return byte
*/
+ (unsigned long long)getSystemRAMTotal {
return [NSProcessInfo processInfo].physicalMemory;
}
获取当前设备的内存使用情况
+ (CGFloat)getUsedMemory {
size_t length = 0;
int mib[6] = {0};
int pagesize = 0;
mib[0] = CTL_HW;
mib[1] = HW_PAGESIZE;
length = sizeof(pagesize);
if (sysctl(mib, 2, &pagesize, &length, NULL, 0) < 0) {
return 0;
}
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
vm_statistics_data_t vmstat;
if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vmstat, &count) != KERN_SUCCESS) {
return 0;
}
int wireMem = vmstat.wire_count * pagesize;
int activeMem = vmstat.active_count * pagesize;
return wireMem + activeMem;
}