QDAS-APM: 360’s iOS Mobile Performance Monitoring Solution
This article introduces 360’s iOS mobile performance monitoring solution, QDAS‑APM, detailing its background, monitored metrics such as page rendering time, main‑thread stalls, network errors, FPS, CPU, memory, crash and startup duration, and explains implementation techniques using KVO, runtime class traversal, and code snippets.
This article introduces 360’s iOS performance monitoring solution, QDAS‑APM, which aims to detect and locate performance problems such as crashes, network errors, UI lag, main‑thread blockage, high CPU/memory usage, and excessive power consumption.
Background : Performance issues greatly affect user experience. 360 has summarized five key performance concerns—resource control, version quality, online issue tracing, development‑stage degradation prevention, and realistic monitoring—and built a monitoring system based on these insights.
Monitored Features :
Page rendering duration
Main‑thread stalls
Network errors
FPS
Large file storage
CPU usage
Memory usage
Crash reports
App startup time
1. Page Rendering Duration
Page rendering time is measured from view controller initialization to the moment the user sees the rendered UI. Important sub‑metrics include lifecycle method execution time, page class name, launch type, execution cost, and plugin name. Directly hooking UIViewController methods is insufficient because most apps subclass UIViewController.
Two feasible approaches are proposed:
Using KVO: the system creates a dynamic subclass for any observed object, allowing interception of property changes.
Runtime traversal: enumerate all UIViewController subclasses and replace their implementations.
The preferred method is KVO due to better compatibility and performance. Implementation steps:
Create a UIViewController category and add KVO for the target instance.
In the KVO‑generated subclass, add swizzled methods to capture the original SEL and IMP.
Remove KVO observers in dealloc to avoid crashes.
Example code for measuring viewDidLoad execution time:
static void qh_viewDidLoad(UIViewController *kvo_self, SEL _sel)
{
Class kvo_cls = object_getClass(kvo_self);
Class origin_cls = class_getSuperclass(kvo_cls);
// Get original implementation
IMP origin_imp = method_getImplementation(class_getInstanceMethod(origin_cls, _sel));
void(*func)(UIViewController *, SEL) = (void(*)(UIViewController *, SEL))origin_imp;
CFAbsoluteTime startTime = CACurrentMediaTime();
func(kvo_self, _sel);
CFAbsoluteTime endTime = CACurrentMediaTime();
NSTimeInterval duration = (endTime - startTime) * 1000;
NSLog(@"Class %@ cost %g in viewDidLoad", [kvo_self class], duration);
}Simply summing the durations of init , loadView , viewDidLoad , viewWillAppear , and viewDidAppear does not accurately represent rendering time, especially with asynchronous rendering. Instead, the layout completion callback viewDidLayoutSubviews can be used as an indirect indicator of rendering completion.
2. Main‑Thread Stall Analysis
Stalls affect UI smoothness and are measured by FPS (Frames Per Second). A healthy app maintains 50–60 FPS. Stalls occur when CPU/GPU processing exceeds the 16.67 ms window before the next V‑Sync signal, causing the display to show the previous frame. The article explains the iPhone’s double‑buffering, V‑Sync mechanism, and how missed V‑Sync leads to visible lag.
3. Network Monitoring
Two approaches are discussed:
NSURLProtocol : convenient for HTTP/HTTPS but limited to supported schemes and cannot handle custom protocols or certificate verification.
Hooking (NSProxy) : uses an abstract NSProxy subclass to forward messages, allowing interception of NSURLConnection , NSURLSession , and CFNetwork methods.
Excerpt from Apple’s documentation on NSProxy :
NSProxy is an abstract superclass defining an API for objects that act as stand‑ins for other objects or for objects that don’t exist yet. Typically, a message to a proxy is forwarded to the real object or causes the proxy to load (or transform itself into) the real object.By hooking key methods in the three network classes, QDAS‑APM collects request/response metrics, formats them, and reports them to the backend for aggregation and reporting.
4. Integration and Usage
QDAS‑APM is a passive‑collection SDK that requires no additional system libraries. Integration consists of three simple steps:
Import the SDK library.
Include the SDK header files.
Initialize the SDK in application:didFinishLaunchingWithOptions: with the provided app key.
References :
Meituan Hertz: https://tech.meituan.com/2016/12/19/hertz.htmlg
iOS Performance Monitoring: http://www.cocoachina.com/articles/19680
360 Tech Engineering
Official tech channel of 360, building the most professional technology aggregation platform for the brand.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.