What is a start

WWDC defines what a startup is. There are roughly three stages

  • The first is between the first interface the user sees the app
  • The second is the render where the cached data appears after the first frame
  • The third is the real interface where the real network data is loaded.

It takes about 100ms to load the libSystem base libraries in dyld. It takes about 300ms to load the base libraries in dyld. It takes about 300ms to load the base libraries in dyld. In addition to the system’s 100ms, Apple recommends that the first frame of an app be limited to 400ms.

So, if we want to do boot optimization well, we need to know what the system is doing and what we can do in those 400ms.

What did we do before main

To be moreCopy the code

What optimizations we can do

To be moreCopy the code

Binary rearrangement

Core point record, the following is the original, I just do verification and testing.

IOS optimization – start optimization of Clang pile to achieve binary rearrangement

For the three-party POD library shortcut symbol import, you can see this lazy version of binary reorder, where directly after the POD install will run a script, perform the related Settings and operations, will be better.

  • post_installAn error will be reported when finding the script path. Drag the script path directly into the project and change it to an absolute path.

In fact, if we are studying a third party, we can initialize the call in this way and see the symbol direction of the third party, which can help us understand the architecture and the invocation more quickly.

View pageFault times

Practical application

  • Starts when the application is installed for the first time
  • No background program status when the phone is started
  • The application is hot-started in the background
  • After killing the background, open some other applications and start again

Adding environment variables

DYLD_PRINT_STATISTICS = 1

Using Instruments to view virtual memory page shortage exceptions

Select System Trace to view MainThread to view the VM virtual memory

Project Settings

  • build settingSearch for order and find the one under linkOrder FileSet to the current directory${SRCROOT}/xx.order.
  • Search for other C and findOther C FlagsModified to-fsanitize-coverage=func,trace-pc-guard

Note that when creating the order file, use the touch command to create it in the current directory, otherwise it will be impossible to read or open the file.

Other C Flags set to -fsanitize-coverage= trace-pc-Guard will have problems reading loop calls

Want to see the order of your symbols

  • The Link Map is a product of compilation and records the layout of the binaries. By setting theWrite Link Map FileThe default is no.
  • Product-show in Finder: A TXT file will appear in the upper level directory of the real machine or emulator.

Add hook code

I’ll just write it somewhere. I’ll write it in VC. The following is the final solution.

#import <dlfcn.h> #import <libkern/OSAtomic.h> - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ NSMutableArray<NSString *> * symbolNames = [NSMutableArray array]; While (true) {//offsetof is to find the offsetof an attribute relative to a structure. SymbolNode * node = OSAtomicDequeue(&symboList, offsetof(SymbolNode, next)); if (node == NULL) break; Dl_info info; dladdr(node->pc, &info); NSString * name = @(info.dli_sname); / / add _ BOOL isObjc = [name hasPrefix: @ "+ ["] | | [name hasPrefix: @" - ["]; nsstrings * symbolName = isObjc? Name: [@ "_" stringByAppendingString: name]; / / to weigh the if (! [symbolNames containsObject: symbolName]) {[symbolNames AddObject :symbolName];}} NSArray * symbolAry = [[symbolNames reverseObjectEnumerator] allObjects]; NSLog (@ "% @", symbolAry); / / the result written to the file nsstrings * funcString = [symbolAry componentsJoinedByString: @ "\ n"); nsstrings * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"lb.order"]; NSData * fileContents = [funcString dataUsingEncoding:NSUTF8StringEncoding]; BOOL result = [[NSFileManager defaultManager] createFileAtPath:filePath If (result) {NSLog(@"%@",filePath);}else{NSLog(@" file write error ");}} // Atomic queue static OSQueueHead symboList = OS_ATOMIC_QUEUE_INIT; // Struct typedef {void * PC; void * next;}SymbolNode; void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { static uint64_t N; // Counter for the guards. if (start == stop || *start) return; // Initialize only once. printf("INIT: %p %p\n", start, stop); for (uint32_t *x = start; x < stop; x++) *x = ++N; // Guards should start from 1. } void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { //if (!*guard) return; // Duplicate the guard check. void *PC = __builtin_return_address(0); SymbolNode *node = malloc(sizeof(SymbolNode)); *node = (SymbolNode){PC,NULL}; // Join // OSAtomicEnqueue(&symboList, node, offsetof(SymbolNode, next));}Copy the code

The problem

→ : Multi-threaded problem

  • Multithreading calls are very frequent in the code, so atomic queues are chosen here. If a lock is used, spin locks are more appropriate.

→ : Solve the loop

  • In the above code, resolve the loop-fsanitize-coverage=func,trace-pc-guardHook for FUNc.

The guard parameter of __sanitizer_cov_trace_pc_guard is 0 when the → : load method is used.

  • Block out__sanitizer_cov_trace_pc_guardIn theif (! *guard) return;

→ : Details processing

  • The queue is first in, then out, so you need to get data from the queue in reverse order
  • duplicate removal
  • orderFile Format RequirementscFunction, block call before the need to add_The underline.
  • Write to a file and copy it into your own project.

Swift project/mixed engineering problem

The above method is suitable for pure OC project to obtain symbols. Since the swift compiler front end is its own SWIFT compiler front end program, the configuration is slightly different. Search for Other Swift Flags and add two configurations:

  • -sanitize-coverage=func
  • -sanitize=undefined

The Swift class can also get symbols using the above method.

Realization principle, static pile insertion

Static piling actually adds hook code (we added __sanitizer_cov_trace_pc_guard) to the binary source data inside each function at compile time to achieve the effect of global method hooks.

Why use atomicity and not locks

Here is the jump instruction to add a very small section of code is executed, does not need the resulting threads in the highly competitive, because the multithreaded execution and call here is already in the case of has to be handled by inserting a very simple and not time-consuming operation, so using atomic operations will be better here, Atomic properties are inappropriate if threads are competing for long wait times, and if there is little time and contention, atomic properties are better than locks.

  • Locks perform better than atomic variables when threads are highly competitive.
  • Locks that are highly competitive constantly suspend recovery threads to allow CPU usage to the rest of the computing resources
  • Atomic variables are highly competitive and always occupy the CPU so the rest of the computing resources are slow due to lack.

conclusion

Update in the…

The important thing is that Swift is already at the heart of Apple, and now from the compiler to the whole maintenance has been promoted, the official update efficiency, and now the relative documentation of the API, etc. Learning Swift early is a must for iOS programmers.