Mobile Development 6 min read

iOS CPU Power Consumption Monitoring with QiCPUMonitor

This article explains how to monitor iOS CPU power consumption using the QiCPUMonitor tool, covering CPU architecture basics, the implementation of QiCPUMonitor, relevant data structures, code snippets for thread inspection, and a periodic timer to capture high‑usage threads without impacting app performance.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
iOS CPU Power Consumption Monitoring with QiCPUMonitor

After reviewing a performance monitoring talk, the author summarizes iOS CPU power‑consumption monitoring techniques and introduces a series of articles on the topic.

The CPU (Central Processing Unit) consists of an arithmetic unit, a control unit, and registers; common architectures for iPhone are ARM64, which offers low power consumption compared to Intel.

QiCPUMonitor monitors CPU usage by obtaining the current task, retrieving all live thread information, setting a CPU‑usage threshold, and storing the stack trace of any thread whose usage exceeds the threshold.

The core data structure used is struct thread_basic_info { time_value_t user_time; time_value_t system_time; integer_t cpu_usage; policy_t policy; integer_t run_state; integer_t flags; integer_t suspend_count; integer_t sleep_time; }; which describes per‑thread metrics such as user/system time and CPU usage (max 1000).

Three variables are declared to hold the thread list, thread count, and the current task:

thread_act_array_t threads;               //! array of threads
mach_msg_type_number_t threadCount = 0;   //! number of threads
const task_t thisTask = mach_task_self(); //! current task

The task's threads are fetched with kern_return_t kr = task_threads(thisTask, &threads, &threadCount); and success is verified against KERN_SUCCESS .

A loop iterates over each thread, obtains thread_basic_info via thread_info , skips idle threads, calculates cpuUsage = threadBaseInfo->cpu_usage / 10 , and if cpuUsage > CPUMONITORRATE records the stack trace, stores it in the database, and logs the event.

for (int i = 0; i < threadCount; i++) {
    thread_info_data_t threadInfo;
    thread_basic_info_t threadBaseInfo;
    mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX;
    if (thread_info((thread_act_t)threads[i], THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount) == KERN_SUCCESS) {
        threadBaseInfo = (thread_basic_info_t)threadInfo;
        if (!(threadBaseInfo->flags & TH_FLAGS_IDLE)) {
            integer_t cpuUsage = threadBaseInfo->cpu_usage / 10;
            if (cpuUsage > CPUMONITORRATE) {
                NSString *reStr = qiStackOfThread(threads[i]);
                QiCallStackModel *model = [[QiCallStackModel alloc] init];
                model.stackStr = reStr;
                [[[QiLagDB shareInstance] increaseWithStackModel:model] subscribeNext:^(id x) {}];
                NSLog(@"CPU useage overload thread stack:\n%@", reStr);
            }
        }
    }
}

A timer refreshes the monitoring every three seconds to minimize performance impact:

self.cpuMonitorTimer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(updateCPUInfo) userInfo:nil repeats:YES];
mobile developmentperformanceiosCPU monitoringQiCPUMonitorthread inspection
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.