Skip to content

Commit

Permalink
更改样式,提高准确度
Browse files Browse the repository at this point in the history
  • Loading branch information
ming1016 committed Aug 19, 2017
1 parent 3775d9b commit 627cf38
Show file tree
Hide file tree
Showing 17 changed files with 179 additions and 71 deletions.
6 changes: 6 additions & 0 deletions GCDFetchFeed/GCDFetchFeed.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
0A12F26F1DE96864002ED910 /* STMURLCacheMk.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A12F2691DE96864002ED910 /* STMURLCacheMk.m */; };
0A12F2701DE96864002ED910 /* STMURLCacheModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A12F26B1DE96864002ED910 /* STMURLCacheModel.m */; };
0A12F2711DE96864002ED910 /* STMURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A12F26D1DE96864002ED910 /* STMURLProtocol.m */; };
0A333DED1F46946900EAD6E8 /* SMCallStackModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A333DEC1F46946900EAD6E8 /* SMCallStackModel.m */; };
0A35AD451F45B31600780172 /* SMCPUMonitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A35AD441F45B31600780172 /* SMCPUMonitor.m */; };
0A35AD4A1F45B32600780172 /* SMStackViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A35AD471F45B32600780172 /* SMStackViewController.m */; };
0A35AD4B1F45B32600780172 /* SMStackCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A35AD491F45B32600780172 /* SMStackCell.m */; };
Expand Down Expand Up @@ -92,6 +93,8 @@
0A12F26B1DE96864002ED910 /* STMURLCacheModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STMURLCacheModel.m; sourceTree = "<group>"; };
0A12F26C1DE96864002ED910 /* STMURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STMURLProtocol.h; sourceTree = "<group>"; };
0A12F26D1DE96864002ED910 /* STMURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STMURLProtocol.m; sourceTree = "<group>"; };
0A333DEB1F46946900EAD6E8 /* SMCallStackModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMCallStackModel.h; sourceTree = "<group>"; };
0A333DEC1F46946900EAD6E8 /* SMCallStackModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMCallStackModel.m; sourceTree = "<group>"; };
0A35AD431F45B31600780172 /* SMCPUMonitor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMCPUMonitor.h; sourceTree = "<group>"; };
0A35AD441F45B31600780172 /* SMCPUMonitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMCPUMonitor.m; sourceTree = "<group>"; };
0A35AD461F45B32600780172 /* SMStackViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMStackViewController.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -284,6 +287,8 @@
0A35AD5F1F45B34C00780172 /* SMCallTraceTimeCostModel.m */,
0A35AD601F45B34C00780172 /* SMCallStack.h */,
0A35AD611F45B34C00780172 /* SMCallStack.m */,
0A333DEB1F46946900EAD6E8 /* SMCallStackModel.h */,
0A333DEC1F46946900EAD6E8 /* SMCallStackModel.m */,
0A35AD671F45B35500780172 /* SMLagMonitor.h */,
0A35AD681F45B35500780172 /* SMLagMonitor.m */,
);
Expand Down Expand Up @@ -800,6 +805,7 @@
3E58A86E1C50BDCE0026A610 /* SMHighlightLabel.m in Sources */,
3E58A86B1C50BA870026A610 /* SMSubContentLabel.m in Sources */,
3EE311701C4E212700103FA3 /* SMRootViewController.m in Sources */,
0A333DED1F46946900EAD6E8 /* SMCallStackModel.m in Sources */,
3EE311751C4E303600103FA3 /* SMFeedModel.m in Sources */,
3E8341F21C525ABD002C3EAA /* SMFeedListCell.m in Sources */,
0A35AD6D1F45B41E00780172 /* DCHook.m in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions GCDFetchFeed/GCDFetchFeed/AppDelegate.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@





//
// AppDelegate.h
// GCDFetchFeed
Expand Down
11 changes: 7 additions & 4 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMCPUMonitor.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "SMCPUMonitor.h"
#import "SMCallStack.h"
#import "SMCallStackModel.h"
#import "SMLagDB.h"

@implementation SMCPUMonitor
Expand All @@ -28,12 +29,14 @@ + (void)updateCPU {
threadBaseInfo = (thread_basic_info_t)threadInfo;
if (!(threadBaseInfo->flags & TH_FLAGS_IDLE)) {
integer_t cpuUsage = threadBaseInfo->cpu_usage / 10;
if (cpuUsage > 75) {
//cup 消耗大于 75 时打印和记录堆栈
if (cpuUsage > CPUMONITORRATE) {
//cup 消耗大于设置值时打印和记录堆栈
NSString *reStr = smStackOfThread(threads[i]);
SMCallStackModel *model = [[SMCallStackModel alloc] init];
model.stackStr = reStr;
//记录数据库中
[[[SMLagDB shareInstance] increaseWithStackString:reStr] subscribeNext:^(id x) {}];
NSLog(@"CPU useage overload thread stack:\n%@",reStr);
[[[SMLagDB shareInstance] increaseWithStackModel:model] subscribeNext:^(id x) {}];
// NSLog(@"CPU useage overload thread stack:\n%@",reStr);
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMCallStack.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#import "SMCallStack.h"


//为通用回溯设计结构支持栈地址由小到大,地址里存储上个栈指针的地址
typedef struct SMStackFrame {
const struct SMStackFrame *const previous;
Expand Down Expand Up @@ -117,7 +116,7 @@ + (NSString *)callStackWithType:(SMCallStackType)type {

uintptr_t buffer[100];
int i = 0;
NSMutableString *reStr = [NSMutableString stringWithFormat:@"Stack of thread: %u:\n CPU used: %.1f percent\n user time: %d second\n", thread, threadInfoSt.cpuUsage, threadInfoSt.userTime];
NSMutableString *reStr = [NSMutableString stringWithFormat:@"Stack of thread: %u:\nCPU used: %.1f percent\nuser time: %d second\n", thread, threadInfoSt.cpuUsage, threadInfoSt.userTime];

//回溯栈的算法
/*
Expand Down
17 changes: 17 additions & 0 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMCallStackModel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// SMCallStackModel.h
// GCDFetchFeed
//
// Created by DaiMing on 2017/8/18.
// Copyright © 2017年 Starming. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface SMCallStackModel : NSObject

@property (nonatomic, copy) NSString *stackStr; //完整堆栈信息
@property (nonatomic) BOOL isStuck; //是否被卡住
@property (nonatomic, assign) NSTimeInterval dateString; //可展示信息

@end
13 changes: 13 additions & 0 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMCallStackModel.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// SMCallStackModel.m
// GCDFetchFeed
//
// Created by DaiMing on 2017/8/18.
// Copyright © 2017年 Starming. All rights reserved.
//

#import "SMCallStackModel.h"

@implementation SMCallStackModel

@end
22 changes: 13 additions & 9 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMCallTrace.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,30 @@ + (void)save {
model.path = [NSString stringWithFormat:@"[%@ %@]",model.className,model.methodName];
[self appendRecord:model to:mStr];
}
NSLog(@"%@",mStr);
// NSLog(@"%@",mStr);
}
+ (void)stopSaveAndClean {
[SMCallTrace stop];
[SMCallTrace save];
smClearCallRecords();
}
+ (void)appendRecord:(SMCallTraceTimeCostModel *)cost to:(NSMutableString *)mStr {
[mStr appendFormat:@"%@\n path%@\n",[cost des],cost.path];
// [mStr appendFormat:@"%@\n path%@\n",[cost des],cost.path];
if (cost.subCosts.count < 1) {
cost.lastCall = YES;
//记录到数据库中
[[SMLagDB shareInstance] addWithClsCallModel:cost];
} else {
for (SMCallTraceTimeCostModel *model in cost.subCosts) {
if ([model.className isEqualToString:@"SMCallTrace"]) {
break;
}
//记录方法的子方法的路径
model.path = [NSString stringWithFormat:@"%@ - [%@ %@]",cost.path,model.className,model.methodName];
[self appendRecord:model to:mStr];
}
}
//记录到数据库中
[[[SMLagDB shareInstance] increaseWithClsCallModel:cost] subscribeNext:^(id x) {}];

for (SMCallTraceTimeCostModel *model in cost.subCosts) {
//记录方法的子方法的路径
model.path = [NSString stringWithFormat:@"%@ - [%@ %@]",cost.path,model.className,model.methodName];
[self appendRecord:model to:mStr];
}
}
+ (NSArray<SMCallTraceTimeCostModel *>*)loadRecords {
NSMutableArray<SMCallTraceTimeCostModel *> *arr = [NSMutableArray new];
Expand Down
7 changes: 4 additions & 3 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMClsCallCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ - (void)buildUI {
[self addSubview:self.pathLb];
[self.nameLb mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self).offset(10);
make.right.equalTo(self).offset(-10);
}];
[self.desLb mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.nameLb.mas_bottom).offset(10);
Expand All @@ -46,7 +47,7 @@ - (void)buildUI {

- (void)updateWithModel:(SMCallTraceTimeCostModel *)model {
self.nameLb.text = [NSString stringWithFormat:@"[%@ %@]",model.className,model.methodName];
self.desLb.text = [NSString stringWithFormat:@"频次:%lu 深度:%lu 耗时:%f",(unsigned long)model.frequency,(unsigned long)model.callDepth, model.timeCost * 1000];
self.desLb.text = [NSString stringWithFormat:@"频次:%lu 耗时:%f",(unsigned long)model.frequency, model.timeCost * 1000];
self.pathLb.text = model.path;
}

Expand All @@ -58,7 +59,7 @@ - (void)layoutSubviews {
- (UILabel *)nameLb {
if (!_nameLb) {
_nameLb = [[UILabel alloc] init];
_nameLb.font = [UIFont systemFontOfSize:14];
_nameLb.font = [UIFont boldSystemFontOfSize:16];
_nameLb.textColor = [UIColor grayColor];
}
return _nameLb;
Expand All @@ -67,7 +68,7 @@ - (UILabel *)desLb {
if (!_desLb) {
_desLb = [[UILabel alloc] init];
_desLb.font = [UIFont systemFontOfSize:12];
_desLb.textColor = [UIColor lightGrayColor];
_desLb.textColor = [UIColor grayColor];
}
return _desLb;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ - (UITableView *)tbView {
}
- (SMLagButton *)closeView {
if (!_closeView) {
_closeView = [[SMLagButton alloc] initWithStr:@"X" size:24 backgroundColor:[UIColor blackColor]];
_closeView = [[SMLagButton alloc] initWithStr:@"退出" size:16 backgroundColor:[UIColor blackColor]];
@weakify(self);
[[_closeView click] subscribeNext:^(id x) {
@strongify(self);
Expand All @@ -167,7 +167,7 @@ - (SMLagButton *)closeView {
}
- (SMLagButton *)clearAndCloseView {
if (!_clearAndCloseView) {
_clearAndCloseView = [[SMLagButton alloc] initWithStr:@"CX" size:20 backgroundColor:[UIColor redColor]];
_clearAndCloseView = [[SMLagButton alloc] initWithStr:@"清理" size:16 backgroundColor:[UIColor redColor]];
@weakify(self);
[[_clearAndCloseView click] subscribeNext:^(id x) {
@strongify(self);
Expand Down
10 changes: 7 additions & 3 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMLagDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,25 @@
#import <ReactiveCocoa/RACEXTScope.h>
//#import "SMClsCallModel.h"
#import "SMCallTraceTimeCostModel.h"
#import "SMCallStackModel.h"

#define PATH_OF_APP_HOME NSHomeDirectory()
#define PATH_OF_TEMP NSTemporaryDirectory()
#define PATH_OF_DOCUMENT [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]

#define CPUMONITORRATE 80
#define STUCKMONITORRATE 88

@interface SMLagDB : NSObject

+ (SMLagDB *)shareInstance;
/*------------卡顿和CPU超标堆栈---------------*/
- (RACSignal *)increaseWithStackString:(NSString *)str;
- (RACSignal *)increaseWithStackModel:(SMCallStackModel *)model;
- (RACSignal *)selectStackWithPage:(NSUInteger)page;
- (void)clearStackData;
/*------------ClsCall方法调用频次-------------*/
//添加记录
- (RACSignal *)increaseWithClsCallModel:(SMCallTraceTimeCostModel *)model;
//添加记录s
- (void)addWithClsCallModel:(SMCallTraceTimeCostModel *)model;
//分页查询
- (RACSignal *)selectClsCallWithPage:(NSUInteger)page;
//清除数据
Expand Down
67 changes: 37 additions & 30 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMLagDB.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ + (SMLagDB *)shareInstance {
- (instancetype)init {
if (self = [super init]) {
_clsCallDBPath = [PATH_OF_DOCUMENT stringByAppendingPathComponent:@"clsCall.sqlite"];
_dbQueue = [FMDatabaseQueue databaseQueueWithPath:_clsCallDBPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:_clsCallDBPath] == NO) {
FMDatabase *db = [FMDatabase databaseWithPath:_clsCallDBPath];
if ([db open]) {
Expand All @@ -53,23 +52,31 @@ - (instancetype)init {
stackcontent: 堆栈内容
insertdate: 日期
*/
NSString *createStackSql = @"create table stack (sid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, stackcontent text, insertdate double)";
NSString *createStackSql = @"create table stack (sid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, stackcontent text,isstuck integer, insertdate double)";
[db executeUpdate:createStackSql];
}
}
_dbQueue = [FMDatabaseQueue databaseQueueWithPath:_clsCallDBPath];
}
return self;
}

#pragma mark - 卡顿和CPU超标堆栈
//添加 stack 表数据
- (RACSignal *)increaseWithStackString:(NSString *)str {
- (RACSignal *)increaseWithStackModel:(SMCallStackModel *)model {
@weakify(self);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if ([model.stackStr containsString:@"+[SMCallStack callStackWithType:]"]) {
return nil;
}
@strongify(self);
[self.dbQueue inDatabase:^(FMDatabase *db){
if ([db open]) {
[db executeUpdate:@"insert into stack (stackcontent, insertdate) values (?, ?)",str, [NSDate date]];
NSNumber *stuck = @0;
if (model.isStuck) {
stuck = @1;
}
[db executeUpdate:@"insert into stack (stackcontent, isstuck, insertdate) values (?, ?, ?)",model.stackStr, stuck, [NSDate date]];
[db close];
[subscriber sendCompleted];
}
Expand All @@ -89,7 +96,11 @@ - (RACSignal *)selectStackWithPage:(NSUInteger)page {
NSUInteger count = 0;
NSMutableArray *arr = [NSMutableArray array];
while ([rs next]) {
[arr addObject:[rs stringForColumn:@"stackcontent"]];
SMCallStackModel *model = [[SMCallStackModel alloc] init];
model.stackStr = [rs stringForColumn:@"stackcontent"];
model.isStuck = [rs boolForColumn:@"isstuck"];
model.dateString = [rs doubleForColumn:@"insertdate"];
[arr addObject:model];
count++;
}
if (count > 0) {
Expand All @@ -114,32 +125,29 @@ - (void)clearStackData {

#pragma mark - ClsCall方法调用频次
//添加记录
- (RACSignal *)increaseWithClsCallModel:(SMCallTraceTimeCostModel *)model {
@weakify(self);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
@strongify(self);
[self.dbQueue inDatabase:^(FMDatabase *db){
if ([db open]) {
FMResultSet *rsl = [db executeQuery:@"select cid,frequency from clscall where path = ?", model.path];
if ([rsl next]) {
//有相同路径就更新路径访问频率
int fq = [rsl intForColumn:@"frequency"] + 1;
int cid = [rsl intForColumn:@"cid"];
[db executeUpdate:@"update clscall set frequency = ? where cid = ?", @(fq), @(cid)];
} else {
//没有就添加一条记录
NSNumber *lastCall = @0;
if (model.lastCall) {
lastCall = @1;
}
[db executeUpdate:@"insert into clscall (cls, mtd, path, timecost, calldepth, frequency, lastcall) values (?, ?, ?, ?, ?, ?, ?)", model.className, model.methodName, model.path, @(model.timeCost), @(model.callDepth), @1, lastCall];
- (void)addWithClsCallModel:(SMCallTraceTimeCostModel *)model {
if ([model.methodName isEqualToString:@"clsCallInsertToViewWillAppear"] || [model.methodName isEqualToString:@"clsCallInsertToViewWillDisappear"]) {
return;
}
[self.dbQueue inDatabase:^(FMDatabase *db){
if ([db open]) {
//添加白名单
FMResultSet *rsl = [db executeQuery:@"select cid,frequency from clscall where path = ?", model.path];
if ([rsl next]) {
//有相同路径就更新路径访问频率
int fq = [rsl intForColumn:@"frequency"] + 1;
int cid = [rsl intForColumn:@"cid"];
[db executeUpdate:@"update clscall set frequency = ? where cid = ?", @(fq), @(cid)];
} else {
//没有就添加一条记录
NSNumber *lastCall = @0;
if (model.lastCall) {
lastCall = @1;
}
[db close];
[subscriber sendCompleted];
[db executeUpdate:@"insert into clscall (cls, mtd, path, timecost, calldepth, frequency, lastcall) values (?, ?, ?, ?, ?, ?, ?)", model.className, model.methodName, model.path, @(model.timeCost), @(model.callDepth), @1, lastCall];
}
}];

return nil;
[db close];
}
}];
}

Expand All @@ -163,7 +171,6 @@ - (RACSignal *)selectClsCallWithPage:(NSUInteger)page {
} else {
[subscriber sendError:nil];
}
[subscriber sendCompleted];
[db close];
}
return nil;
Expand Down
18 changes: 12 additions & 6 deletions GCDFetchFeed/GCDFetchFeed/Lib/SMLagMonitor/SMLagMonitor.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

#import "SMLagMonitor.h"
#import "SMCallStack.h"
#import "SMCallStackModel.h"
#import "SMCPUMonitor.h"
#import "SMLagDB.h"

@interface SMLagMonitor() {
int timeoutCount;
Expand Down Expand Up @@ -57,7 +59,7 @@ - (void)beginMonitor {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//子线程开启一个持续的loop用来进行监控
while (YES) {
long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, 20*NSEC_PER_MSEC));
long semaphoreWait = dispatch_semaphore_wait(dispatchSemaphore, dispatch_time(DISPATCH_TIME_NOW, STUCKMONITORRATE * NSEC_PER_MSEC));
if (semaphoreWait != 0) {
if (!runLoopObserver) {
timeoutCount = 0;
Expand All @@ -68,12 +70,16 @@ - (void)beginMonitor {
//两个runloop的状态,BeforeSources和AfterWaiting这两个状态区间时间能够检测到是否卡顿
if (runLoopActivity == kCFRunLoopBeforeSources || runLoopActivity == kCFRunLoopAfterWaiting) {
//出现三次出结果
// if (++timeoutCount < 3) {
// continue;
// }
NSLog(@"monitor trigger");
if (++timeoutCount < 3) {
continue;
}
// NSLog(@"monitor trigger");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
// [SMCallStack callStackWithType:SMCallStackTypeAll];
NSString *stackStr = [SMCallStack callStackWithType:SMCallStackTypeCurrent];
SMCallStackModel *model = [[SMCallStackModel alloc] init];
model.stackStr = stackStr;
model.isStuck = YES;
[[[SMLagDB shareInstance] increaseWithStackModel:model] subscribeNext:^(id x) {}];
});
} //end activity
}// end semaphore wait
Expand Down
Loading

0 comments on commit 627cf38

Please sign in to comment.