二进制重排的方案参考链接
原理,代码执行是pagefault会消耗性能,将order file提供给编译器,让它按给到的顺序来链接.o,从而减少pagefault次数
https://mp.weixin.qq.com/s/Drmmx5JtjG3UtTFksL6Q8Q
https://www.jianshu.com/p/024b3d847fe0
https://www.lizenghai.com/archives/41858.html
如何获取启动时调用的那些方法(
sanitizerCoverage
)
https://blog.csdn.net/zhang14916/article/details/100924489
https://blog.csdn.net/chouju2014/article/details/100657380
出处:
配置:other c flag -fsanitize_coverage=func,trace_pc_guard
https://github.com/yulingtianxia/AppOrderFiles
//调用,直接停止统计并且写入到一个文件
extern void AppOrderFiles(void(^completion)(NSString *orderFilePath)); // // AppOrderFiles.m // AppOrderFiles // // Created by 杨萧玉 on 2019/8/31. // Copyright © 2019 杨萧玉. All rights reserved. // #import "AppOrderFiles.h" #import <dlfcn.h> #import <libkern/OSAtomicQueue.h> #import <pthread.h> static OSQueueHead queue = OS_ATOMIC_QUEUE_INIT; static BOOL collectFinished = NO; typedef struct { void *pc; void *next; } PCNode; // The guards are [start, stop). // This function will be called at least once per DSO and may be called // more than once with the same values of start/stop. void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { static uint32_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. } // This callback is inserted by the compiler on every edge in the // control flow (some optimizations apply). // Typically, the compiler will emit the code like this: // if(*guard) // __sanitizer_cov_trace_pc_guard(guard); // But for large functions it will emit a simple call: // __sanitizer_cov_trace_pc_guard(guard); void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { if (!*guard) return; // Duplicate the guard check. if (collectFinished) { return; } // If you set *guard to 0 this code will not be called again for this edge. // Now you can get the PC and do whatever you want: // store it somewhere or symbolize it and print right away. // The values of `*guard` are as you set them in // __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive // and use them to dereference an array or a bit vector. *guard = 0; void *PC = __builtin_return_address(0); PCNode *node = malloc(sizeof(PCNode)); *node = (PCNode){PC, NULL}; OSAtomicEnqueue(&queue, node, offsetof(PCNode, next)); } extern void AppOrderFiles(void(^completion)(NSString *orderFilePath)) { collectFinished = YES; __sync_synchronize(); NSString *functionExclude = [NSString stringWithFormat:@"_%s", __FUNCTION__]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSMutableArray <NSString *> *functions = [NSMutableArray array]; while (YES) { PCNode *node = OSAtomicDequeue(&queue, offsetof(PCNode, next)); if (node == NULL) { break; } Dl_info info = {0}; dladdr(node->pc, &info); NSString *name = @(info.dli_sname); BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["]; NSString *symbolName = isObjc ? name : [@"_" stringByAppendingString:name]; [functions addObject:symbolName]; } if (functions.count == 0) { if (completion) { completion(nil); } return; } NSMutableArray<NSString *> *calls = [NSMutableArray arrayWithCapacity:functions.count]; NSEnumerator *enumerator = [functions reverseObjectEnumerator]; NSString *obj; while (obj = [enumerator nextObject]) { if (![calls containsObject:obj]) { [calls addObject:obj]; } } [calls removeObject:functionExclude]; NSString *result = [calls componentsJoinedByString:@"\n"]; NSLog(@"Order:\n%@", result); NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"app.order"]; NSData *fileContents = [result dataUsingEncoding:NSUTF8StringEncoding]; BOOL success = [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil]; if (completion) { completion(success ? filePath : nil); } }); }