In the previous article, we learned that the startup time was caused by the page interruption, so we could arrange according to our.order method when compiling, but if our project was large, it would be difficult to find a way to arrange.

1. Clang pile insertion configuration

LLVM has a simple code coverage built in. It inserts user-defined functions into functions, base blocks, and edge-level calls. Default implementations of these callbacks are provided, and simple coverage reports and visual Clang code coverage are detailed and demonstrated.

1.1 configuration

Add it to Other C Flags in Build Settings if we are an OC project

-fsanitize-coverage=trace-pc-guard
Copy the code

Add a documented method implementation to any controller or file, and compile.

Print out the implementation of the method after running

Let’s look at __sanitizer_cov_trace_pc_guard_init, where start and stop represent the number of methods, start and end, for loop, return when the start address and end address are the same.

Here 0e stands for 14 symbol tables, and we add a method and a block

Represented as 16. If we do the Swift project or the mix,In the Build SettingsIn theOther Swift Flagsadd

-sanitize-coverage=func
-sanitize=undefined
Copy the code

1.2 the principle

Let’s debug it in assemblyAfter the main function is called__sanitizer_cov_trace_pc_guard

[AppDelegate application: didFinishLaunchingWithOptions:] function will be called__sanitizer_cov_trace_pc_guard

The subsequent discovery will be called after implementing our method__sanitizer_cov_trace_pc_guard, which means that the system will add hook to the methods in our project during compilation to mark and locate our methods. We did it throughOther c FlagsTag added, so it must be done at compile timeInsert the codeThe action.

2. Implementation

The function __builtin_return_address(0) returns the address of the previous function, that is, the caller, this PC is the address of the previous function. Represents the __sanitizer_cov_trace_pc_guard inserted at line 0. We take the information for this address, and we store the information for this method through Dl_info.

Dl_info info;
dladdr(PC, &info);
Copy the code

The import#import <dlfcn.h>.Dl_info, including the path, method name, and address.Let’s just print the name of the method

There is no +load method when printing, we found that the break point did enter, but the GUAD is 0, so we remove this judgment when writing.

2.1 Save method name

We add a method to get the method name. When we are storing, multiple threads will call the method. This hook will also be in multiple threads.

2.1 Atomic operation save

We import #import to define atomic queues and symbolic structures

We write methods in the hook

Here to addThe next nodeThe address is also the PC information, convenient for us to take out the time to determine whether the timeThe last oneAnd the last one that has no information about the next node.

We added a for loop in the ‘touchesBegan’

The hook caught our for loop too, causing the table to keep insertingInfinite loop, let’s modify the tag

-fsanitize-coverage=func,trace-pc-guard
Copy the code

It’s in our programswiftCode, or blocks, and so on,

Do add and reverse traversal, and remove the method itself

The final writtenorderfile

Print the results in the order in which they are executed

2.3 link orderFile

We write links in OrderFile, and the compiled methods are executed in the order we started them

3. Summary

Through the official hook of the method, we locate the implemented method, save it into the array, and finally read it by pressing the. Order file, so as to reduce The Times of Page fault and improve the startup speed. Write specific code:

static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;

// Define the symbolic structure

typedef struct {

    void * pc;

    void * next;

} KBNode;

void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {

//  if (!*guard) return;

  void *PC = __builtin_return_address(0);

    

// Dl_info info;

// dladdr(PC, &info);


// NSLog(@"%s\n,\n",info.dli_sname);

    

    KBNode *node = malloc(sizeof(KBNode));

    

    *node = (KBNode){PC,NULL};Next indicates the address of the next node

    

    OSAtomicEnqueue(&symbolList, node, offsetof(KBNode, next));// Write the atomic list method and write the address of the next node.} - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

{

    // Define an array

    NSMutableArray<NSString *> * symbleNames = [NSMutableArray array];

    while (YES) {

        KBNode *node = OSAtomicDequeue(&symbolList, offsetof(KBNode, next));

        if (node == NULL) {

            break;// If no, end

        }

        Dl_info info;

        dladdr(node->pc, &info);

// printf("%s\n",info.dli_sname);

        NSString * name = @(info.dli_sname);// Turn to string

        BOOL isObjc = [name hasPrefix:@"+ ["] || [name hasPrefix:@"-"];

        NSString * symbolName = isObjc ? name : [@"_" stringByAppendingString:name];

        [symbleNames addObject:symbolName];

        

       

    }

    / / add

    NSEnumerator * em = [symbleNames reverseObjectEnumerator];

    NSMutableArray * funcs = [NSMutableArray arrayWithCapacity:symbleNames.count];

    NSString * name;

    while (name = [em nextObject]) {

        if(! [funcs containsObject:name]) {// The array has no name[funcs addObject:name]; }}// Remove yourself!

    [funcs removeObject:[NSString stringWithFormat:@"%s",__func__]];

    

    // Write to the file

    //1. Programming string

    NSString * funcStr = [funcs componentsJoinedByString:@"\n"];

    NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test.order"];

    NSData * file = [funcStr dataUsingEncoding:NSUTF8StringEncoding];

    

    [[NSFileManager defaultManager] createFileAtPath:filePath contents:file attributes:nil];

    

    NSLog(@"% @",funcStr);

}
Copy the code