This is the first day of my participation in the Gwen Challenge in November. Check out the details: the last Gwen Challenge in 2021
Start time monitoring
There are only two things you need to understand about boot time monitoring
- Startup time is a period of time
- How is this time monitored
What is the startup time period
View startup time from the user’s perspective
From a user perspective, startup time is measured in two ways:
- Click the icon to the home page data loading completed
- For example, if the home page is loaded with a web image, the startup time is the time from when you click on the app icon to when the home page image appears
- From clicking the icon to the first frame after Launch Image disappears
- For example, if a web image is loaded on the home page, the startup time is from clicking the app icon to seeing the home page (the image is not loaded at that moment, only a home title can be seen).
The first point is hard to align because different applications load different amounts of data on their front pages, so it’s best to stick to the second point
Look at startup time at the code level
From the point of view of the code, the official gives a calculation method
- Start time Indicates the time when the process is created
- The end time is the first one
CA::Transaction::commit()
CA::Transaction::commit()
It is a transaction mechanism provided by Core Animation that packages a set of UI changes and sends them to the Render Server. What does that mean, that you submit a set of UIs to the GPU for drawing
Two boot modes
There are two ways to launch an app:
-
Cold start
- A cold start is a startup when there is no process cache information in the system. For example, the first startup after the mobile phone is restarted or the process cache has been cleared after the application is killed for a long time. The first startup after the process cache has been cleared is also a cold start
-
Warm start
- Hot boot is when the process cache is still in the system, for example, the application is killed and then immediately hit the application to enter
Hot starts are faster because process caching is used, so subsequent starts generally refer to cold starts
How is the startup time monitored
There are two parts:
- How to obtain the start time and end time of the startup process
- How to obtain the time of each phase in the startup process
Overall startup time monitoring
How to obtain the start time and end time of the startup process
The start time
You can obtain the process creation time by using the current processIdentifier (NSProcessInfo\processIdentifier). The process creation time (__p_starttime) in the process information is the starttime
#import <sys/sysctl.h> #import < Mach /mach.h> + (NSTimeInterval)processStartTime {// struct kinfo_proc kProcInfo; if ([self processInfoForPID:[[NSProcessInfo processInfo] processIdentifier] procInfo:&kProcInfo]) { return Kpprocinfo.kp_proc.p_un.__p_starttime.tv_sec + kprocinfo.kp_proc.p_un.__p_starttime.tv_usec / 1000000.0; } else {NSAssert(NO, @" can't get process information "); return 0; } } + (BOOL)processInfoForPID:(int)pid procInfo:(struct kinfo_proc*)procInfo { int cmd[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; size_t size = sizeof(*procInfo); return sysctl(cmd, sizeof(cmd)/sizeof(*cmd), procInfo, &size, NULL, 0) == 0; }Copy the code
The end of time
We have also analyzed the end time with two algorithms:
- The first frame appears after Launch Image disappears
- The first one
CA::Transaction::commit()
perform
The first frame appears after Launch Image disappears
- IOS 12 and below: Root viewDidAppear for viewController
- IOS 13 + : applicationDidBecomeActive
The first oneCA::Transaction::commit()
perform
In this method, we can’t get the time of the first execution directly, but we can get the time close to this point through other events
CFRunLoopPerformBlock
inCA::Transaction::commit()
Call before execution,kCFRunLoopBeforeTimers
inCA::Transaction::commit()
Call after execution
- IOS13 or later is used
runloop
To register akCFRunLoopBeforeTimers
The callback gets a more accurate time when the App’s first screen rendering is completed.
// Register kCfrunloop-beforetimers callback CFRunLoopRef mainRunloop = [[NSRunLoop mainRunloop] getCFRunLoop]; CFRunLoopActivity activities = kCFRunLoopAllActivities; CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, activities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { if (activity == kCFRunLoopBeforeTimers) { NSTimeInterval stamp = [[NSDate date] timeIntervalSince1970]; NSLog(@"runloop beforetimers launch end:%f",stamp); CFRunLoopRemoveObserver(mainRunloop, observer, kCFRunLoopCommonModes); }}); CFRunLoopAddObserver(mainRunloop, observer, kCFRunLoopCommonModes);Copy the code
- Oss later than iOS13 are used
CFRunLoopPerformBlock
Method injection block to obtain the App first screen rendering completion time is more accurate.
// register block CFRunLoopRef mainRunloop = [[NSRunLoop mainRunloop] getCFRunLoop]; CFRunLoopPerformBlock(mainRunloop,NSDefaultRunLoopMode,^(){ NSTimeInterval stamp = [[NSDate date] timeIntervalSince1970]; NSLog(@"runloop block launch end:%f",stamp); });Copy the code
How to obtain the time of each phase
The total startup time, the next is to calculate the startup time of each stage, first of all, we should know what stages are in the startup process, the application startup process is usually divided into three stages
main
Function before the pre-main phasemain
After the function- After rendering the first screen
main
Function before
The stage before main refers to the period from clicking on the icon to executing main. We call it the pre-main stage. This stage mainly does the following things:
- Load executable files (collection of.o files for app)
- Load the dynamic connection library
- Rebase pointer adjustment and bind symbol binding
- Initial handling of OC runtime (REGISTRATION of OC related classes, category registration, selector uniqueness checking, etc.)
- Initialize the(to perform
+load()
Method,The attribute (constructor)
Modify function calls, create C++ static global variables)
Here’s an overview of what was done, and I’ll cover each in more detail later
Time monitoring in the pre-main phase
Apple provides a measure by setting the environment variable DYLD_PRINT_STATISTICS to 1 in Xcode, Edit scheme -> Run -> Uments. The console will then output something similar, which we can see clearly
The entire pre-main is 1.3 seconds, with details for each section below
main
After the function
Refers to the starting from the main function to perform at this stage to appDelegate didFinishLaunchingWithOptions method first screen rendering method completes, i.e., From the main function to set the self. The window. The rootViewController execution stage. The main function does the following:
- Initialize the read and write operations of the configuration file on the first screen
- Read big data from the first screen list
- A lot of calculations for the first screen rendering
main
Time monitoring after the function
According to the execution process at this stage, it can be concluded that:
- The start time can be measured at the beginning of main
- The end time can be at
self.window.rootViewController
Measurement after method
After rendering the first screen
After completion of this stage is to point to in the first screen rendering to didFinishLaunchingWithOptions end the segment method is carried out
- The start time is at
self.window.rootViewController
Measurement after method - The end time is
didFinishLaunchingWithOptions
Methods the end
The above is to measure startup time by code, but you can also measure startup time by tools
1. Use time profiler monitoring
2. Use app Launch to measure
I won’t introduce it here. Above, welcome to comment and exchange.