Other C Flags
-fsanitize-coverage=func,trace-pc-guard
如果项目中有Swift
的话。
在Other Swift Flags
新增2行代码。
-sanitize-coverage=func
-sanitize=undefined
用到的头文件
#import <dlfcn.h>
#import <libkern/OSAtomic.h>
// 执行每个函数、block 都会将此函数插入到汇编中,上线打包需要将此桩去掉
// 即取出前面的2个配置文件,新增 orderfile 文件。
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.
}
//原子队列
static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;
//定义符号结构体
typedef struct {
void *pc;
void *next;
}SYNode;
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
// if (!*guard) return; // Duplicate the guard check.
/* 精确定位 哪里开始 到哪里结束! 在这里面做判断写条件!*/
// 取出pc,pc是当前函数、文件地址、等参数结构体的指针。
// 可以使用dladdr取出来
void *PC = __builtin_return_address(0);
SYNode *node = malloc(sizeof(SYNode));
*node = (SYNode){PC,NULL};
//进入
OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));
// printf("fname:%s \nfbase:%p \nsname:%s \nsaddr:%p\n",
// info.dli_fname,
// info.dli_fbase,
// info.dli_sname,
// info.dli_saddr);
//
}
/// 这是将记录的函数写入到文件
NSMutableArray <NSString *> * symbolNames = [NSMutableArray array];
while (YES) {
SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode, next));
if (node == NULL) {
break;
}
Dl_info info;
dladdr(node->pc, &info);
NSString * name = @(info.dli_sname);
BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["];
NSString * symbolName = isObjc ? name: [@"_" stringByAppendingString:name];
[symbolNames addObject:symbolName];
}
//取反
NSEnumerator * emt = [symbolNames reverseObjectEnumerator];
//去重
NSMutableArray<NSString *> *funcs = [NSMutableArray arrayWithCapacity:symbolNames.count];
NSString * name;
while (name = [emt nextObject]) {
if (![funcs containsObject:name]) {
[funcs addObject:name];
}
}
//干掉自己!
[funcs removeObject:[NSString stringWithFormat:@"%s",__FUNCTION__]];
//将数组变成字符串
NSString * funcStr = [funcs componentsJoinedByString:@"\n"];
NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"setup.order"];
NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];
[[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];
NSLog(@"%@",funcStr);
将静态插装生成的order文件复制到工程文件根目录,然后配置下。
让编译函数的顺序按照该文件的先后顺序进行编译,Build Settings->Order File
。否则按照Build Phases->Compile Sources
的先后顺序进行编译。
./setup.order
在Instruments->system Trace
中测试启动page falut
,次数和耗时。
二进制重排,在启动的路径触发的
page in
次数的数量,会影响启动时间,如果page in
次数不上万,则此操作可以忽略,如果达到了10万次级别,则可以尝试。我们APP 次数平均在2000多次,平均每次
page in
0.1ms,一共0.2s,完全在测试不出来。