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

  1. Startup time is a period of time
  2. 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:

  1. 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
  2. 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 oneCA::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:

  1. 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
  2. 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:

  1. How to obtain the start time and end time of the startup process
  2. 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:

  1. The first frame appears after Launch Image disappears
  2. The first oneCA::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

CFRunLoopPerformBlockinCA::Transaction::commit()Call before execution,kCFRunLoopBeforeTimersinCA::Transaction::commit()Call after execution

  • IOS13 or later is usedrunloopTo register akCFRunLoopBeforeTimersThe 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 usedCFRunLoopPerformBlockMethod 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

  1. mainFunction before the pre-main phase
  2. mainAfter the function
  3. After rendering the first screen

mainFunction 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:

  1. Load executable files (collection of.o files for app)
  2. Load the dynamic connection library
  3. Rebase pointer adjustment and bind symbol binding
  4. Initial handling of OC runtime (REGISTRATION of OC related classes, category registration, selector uniqueness checking, etc.)
  5. 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

mainAfter 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:

  1. Initialize the read and write operations of the configuration file on the first screen
  2. Read big data from the first screen list
  3. A lot of calculations for the first screen rendering
mainTime 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 atself.window.rootViewControllerMeasurement 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 atself.window.rootViewControllerMeasurement after method
  • The end time isdidFinishLaunchingWithOptionsMethods 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.