blob: e0f00e260e7507a010460ecc986cbf1064a7fbbd [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#import "WXTracingManager.h"
#import "WXComponentFactory.h"
#import "WXModuleFactory.h"
#import "WXSDKManager.h"
#import "WXComponentFactory.h"
#import "WXModuleFactory.h"
#import "WXHandlerFactory.h"
#import "WXUtility.h"
#import "WXComponentManager.h"
#import "WXTracingProtocol.h"
#import "WXSDKEngine.h"
@implementation WXTracing
-(NSDictionary *)dictionary {
return [NSDictionary dictionaryWithObjectsAndKeys:self.ref?:@"",@"ref",self.parentRef?:@"",@"parentRef",self.className?:@"",@"className",self.name?:@"",@"name",self.ph?:@"",@"ph",@(self.ts),@"ts",@(self.traceId),@"traceId",@(self.duration),@"duration",self.fName?:@"",@"fName",self.iid?:@"",@"iid",@(self.parentId)?:0,@"parentId",self.threadName?:@"",@"tName", nil];
}
@end
@implementation WXTracingTask
@end
@interface WXTracingManager()
@property (nonatomic) BOOL isTracing;
@property (nonatomic, strong) NSMutableDictionary *tracingTasks; // every instance have a task
@property (nonatomic, copy) NSString *currentInstanceId; // every instance have a task
@end
@implementation WXTracingManager
+ (instancetype) sharedInstance{
static WXTracingManager *instance = nil;
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [[WXTracingManager alloc] initPrivate];
});
return instance;
}
- (instancetype) initPrivate{
self = [super init];
if(self){
self.isTracing = NO;
}
return self;
}
+(void)switchTracing:(BOOL )isTracing
{
[WXTracingManager sharedInstance].isTracing = isTracing;
}
+(BOOL)isTracing
{
return [WXTracingManager sharedInstance].isTracing;
}
+(void)startTracing:(WXTracing *)tracing
{
if([self isTracing]){
if(![WXTracingManager sharedInstance].tracingTasks){
[WXTracingManager sharedInstance].tracingTasks = [NSMutableDictionary new];
}
if(![[WXTracingManager sharedInstance].tracingTasks objectForKey:tracing.iid]){
WXTracingTask *task = [WXTracingTask new];
task.iid = tracing.iid;
if (tracing.iid) {
[[WXTracingManager sharedInstance].tracingTasks setObject:task forKey:tracing.iid];
}
}
WXTracingTask *task = [[WXTracingManager sharedInstance].tracingTasks objectForKey:tracing.iid];
if(task.bundleUrl.length == 0){
if(tracing.bundleUrl.length>0){
task.bundleUrl = tracing.bundleUrl;
}
}
if(!task.tracings){
task.tracings = [NSMutableArray new];
}
if(WXFloatEqual(tracing.ts,0)){
NSTimeInterval time=[[NSDate date] timeIntervalSince1970]*1000;
tracing.ts = time;
}
if(WXFloatEqual(tracing.duration,0)){
tracing.duration = WXTracingDurationDefault;
}
if(![WXTracingEnd isEqualToString:tracing.ph]){ // end is should not update
tracing.traceId = task.counter++;
}
if([WXTNetworkHanding isEqualToString:tracing.name] && [WXTracingBegin isEqualToString:tracing.ph]){
task.tag = WXTNetworkHanding;
}
NSTimeInterval ts = [[NSDate date] timeIntervalSince1970]*1000;
tracing.ts = ts ;
dispatch_async(dispatch_get_main_queue(), ^{
[self updateTracings:task tracing:tracing];
});
}
}
+(void)setBundleJSType:(NSString *)jsBundleString instanceId:(NSString *)iid
{
if([self isTracing] && iid.length >0){
WXTracingTask *task = [[WXTracingManager sharedInstance].tracingTasks objectForKey:iid];
if(jsBundleString.length >0){
NSRange range = [jsBundleString rangeOfString:@"}"];
if (range.location != NSNotFound) {
NSString *searchStr = [jsBundleString substringToIndex:range.location+range.length];
if ([searchStr rangeOfString:@"Vue"].location != NSNotFound){
task.bundleJSType = @"Vue";
}else if([searchStr rangeOfString:@"Rax"].location != NSNotFound){
task.bundleJSType = @"Rax";
}else{
task.bundleJSType = @"Weex";
}
}
}
}
}
+(void)clearTracingData
{
[WXTracingManager sharedInstance].tracingTasks = nil;
}
+(NSTimeInterval)getCurrentTime
{
if([self isTracing]){
return [[NSDate date] timeIntervalSince1970]*1000;
}
return 0;
}
+(void)startTracingWithInstanceId:(NSString *)iid ref:(NSString*)ref className:(NSString *)className name:(NSString *)name phase:(NSString *)phase functionName:(NSString *)functionName options:(NSDictionary *)options
{
if([self isTracing]){
WXTracing *tracing = [WXTracing new];
tracing.parentId = -1;
if(ref.length>0){
tracing.ref = ref;
}else {
tracing.ref = @"";
}
if(className.length>0){
tracing.className = className;
}else {
tracing.className = @"";
}
if(name.length>0){
tracing.name = name;
}
if(functionName.length>0){
tracing.fName = functionName;
}
if(phase.length>0){
tracing.ph = phase;
}
if(iid.length>0){
tracing.iid = iid;
}
if(options && options[@"ts"]){
tracing.ts = [options[@"ts"] floatValue];
}
if(options && options[@"duration"]){
tracing.duration = [options[@"duration"] floatValue];
}
if(options && options[@"parentRef"]){
tracing.parentRef = options[@"parentRef"];
}
if(options && options[@"bundleUrl"]){
tracing.bundleUrl = options[@"bundleUrl"];
}
if(options && options[@"threadName"]){
tracing.threadName = options[@"threadName"];
}
if(options && options[@"componentData"]){
tracing.childrenRefs = [self getChildrenRefs:options[@"componentData"]];
}
[self startTracing:tracing];
}
}
+ (NSMutableArray *)getChildrenRefs:(NSDictionary *)componentData
{
NSMutableArray *mArray = [NSMutableArray new];
[self recursively:mArray componentData:componentData];
return mArray;
}
+(void)recursively:(NSMutableArray *)mArray componentData:(NSDictionary *)componentData
{
if([componentData valueForKey:@"children"]){
NSArray *children = [componentData valueForKey:@"children"];
for(NSDictionary *subcomponentData in children){
NSString *ref = [subcomponentData objectForKey:@"ref"];
if(ref){
[mArray addObject:ref];
}
[self recursively:mArray componentData:subcomponentData];
}
}
}
+(WXTracing *)copyTracing:(WXTracing *)tracing
{
WXTracing *newTracing = [WXTracing new];
if(tracing.ref.length>0){
newTracing.ref = tracing.ref;
}
if(tracing.parentRef.length>0){
newTracing.parentRef = tracing.parentRef;
}
if(tracing.className.length>0){
newTracing.className = tracing.className;
}
if(tracing.name.length>0){
newTracing.name = tracing.name;
}
if(tracing.fName.length>0){
newTracing.fName = tracing.fName;
}
if(tracing.ph.length>0){
newTracing.ph = tracing.ph;
}
if(tracing.iid.length>0){
newTracing.iid = tracing.iid;
}
if(tracing.parentId>0){
newTracing.parentId = tracing.parentId;
}
if(tracing.traceId>0){
newTracing.traceId = tracing.traceId;
}
if(tracing.ts>0){
newTracing.ts = tracing.ts;
}
if(tracing.threadName.length>0){
newTracing.threadName = tracing.threadName;
}
return newTracing;
}
+(NSString *)getclassName:(WXTracing *)tracing
{
NSString *className = @"";
if(tracing.ref.length>0 && tracing.name.length >0){
Class cls = [WXComponentFactory classWithComponentName:tracing.name];
className = NSStringFromClass(cls);
}else if(tracing.name.length > 0){
Class cls = [WXModuleFactory classWithModuleName:tracing.name];
if(cls){
className = NSStringFromClass(cls);
}
}
return className;
}
+(NSInteger )getParentId:(WXTracingTask *)task tracing:(WXTracing *)tracing
{
NSMutableArray *tracings = task.tracings;
if([tracing.threadName isEqualToString:WXTJSBridgeThread]) {
return -1;
}
if(tracings && [tracings count]>0){
for (NSInteger i = [tracings count] - 1; i >= 0; i--) {
WXTracing *t = tracings[i];
// if([t.threadName isEqualToString:WXTJSBridgeThread]&& [self compareRef:tracing.ref withTracing:t] && ([t.name isEqualToString:tracing.name] || [t.name isEqualToString:WXTJSCall])){
if([t.threadName isEqualToString:WXTJSBridgeThread]&& [self compareRef:tracing.ref withTracing:t]){
if([t.fName isEqualToString:tracing.fName]){
return (NSInteger)t.traceId;
}
}
}
}
return -1;
}
+(BOOL)compareRef:(NSString *)ref withTracing:(WXTracing *)tracing
{
if([tracing.ref isEqualToString:ref]){
return YES;
}
if(tracing.childrenRefs && [tracing.childrenRefs count] > 0){
for (NSString *childRef in tracing.childrenRefs) {
if([childRef isEqualToString:ref]){
return YES;
}
}
}
return NO;
}
+(void)updateTracings:(WXTracingTask *)task tracing:(WXTracing *)tracing
{
if([WXTNetworkHanding isEqualToString:task.tag]){
if([WXTExecJS isEqualToString:tracing.name]){
NSMutableArray *tracings = task.tracings;
[tracings enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(WXTracing *bTracing, NSUInteger idx, BOOL *stop) {
if(([WXTNetworkHanding isEqualToString:bTracing.name] || [bTracing.ref isEqualToString:tracing.ref])&&[WXTracingBegin isEqualToString:bTracing.ph]){
WXTracing *newTracing = [self copyTracing:bTracing];
newTracing.iid = tracing.iid;
newTracing.ph = WXTracingEnd;
newTracing.ts = tracing.ts ;
newTracing.duration = newTracing.ts - bTracing.ts ;
bTracing.duration = newTracing.duration;
[task.tracings addObject:newTracing];
*stop = YES;
}
}];
task.tag = WXTExecJS;
}
}
if([WXTracingBegin isEqualToString:tracing.ph]){
if(tracing.ref.length>0){
WXPerformBlockOnComponentThread(^{
WXSDKInstance *instance = [WXSDKManager instanceForID:task.iid];
WXComponent *com = [instance componentForRef:tracing.ref];
if(task.bundleUrl.length == 0){
task.bundleUrl = [instance.scriptURL absoluteString];
}
if(com.supercomponent){
tracing.parentRef = com.supercomponent.ref;
}
tracing.name = com.type;
if(tracing.className.length == 0){
tracing.className = [self getclassName:tracing];
}
});
if(tracing.parentId == -1){
tracing.parentId = [self getParentId:task tracing:tracing];
}
} else {
if(tracing.parentId == -1){
tracing.parentId = [self getParentId:task tracing:tracing];
}
}
}
if([WXTracingEnd isEqualToString:tracing.ph]){ // deal end
NSMutableArray *tracings = task.tracings;
[tracings enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(WXTracing *bTracing, NSUInteger idx, BOOL *stop) {
if(tracing.ref.length > 0 && bTracing.ref.length>0){
if(![tracing.ref isEqualToString:bTracing.ref]){
return ;
}
}
if([bTracing.fName isEqualToString:tracing.fName] &&[WXTracingBegin isEqualToString:bTracing.ph] ){
tracing.iid = bTracing.iid;
if(bTracing.ref.length > 0){
tracing.ref = bTracing.ref;
}
if(bTracing.parentRef.length > 0){
tracing.parentRef = bTracing.parentRef;
}
tracing.parentId = bTracing.parentId;
tracing.duration = tracing.ts - bTracing.ts ;
tracing.traceId = bTracing.traceId;
tracing.threadName = bTracing.threadName;
bTracing.duration = tracing.duration;
tracing.name = bTracing.name;
*stop = YES;
}
}];
}
[task.tracings addObject:tracing];
if([@"renderFinish" isEqualToString:tracing.fName] && [WXTracingInstant isEqualToString:tracing.ph] && [WXTUIThread isEqualToString:tracing.threadName]) {
[WXTracingManager commitTracing:task.iid];
}
}
+(NSMutableDictionary *)getTracingData
{
if(![self isTracing]){
return nil;
}
return [WXTracingManager sharedInstance].tracingTasks;
}
+(NSDictionary *)getTacingApi
{
if(![self isTracing]){
return @{};
}
NSMutableDictionary *dict = [NSMutableDictionary new];
NSMutableArray *componetArray = [NSMutableArray new];
NSMutableArray *moduleArray = [NSMutableArray new];
NSMutableArray *handleArray = [NSMutableArray new];
NSDictionary *componentConfigs = [WXComponentFactory componentConfigs];
void (^componentBlock)(id, id, BOOL *) = ^(id mKey, id mObj, BOOL * mStop) {
NSMutableDictionary *componentConfig = [mObj mutableCopy];
NSDictionary *cDict = [WXComponentFactory componentSelectorMapsWithName:componentConfig[@"name"]];
if(cDict && [cDict count]>0 && [cDict[@"methods"] count]>0){
[componentConfig setObject:cDict[@"methods"] forKey:@"methods"];
}
[componetArray addObject:componentConfig];
};
[componentConfigs enumerateKeysAndObjectsUsingBlock:componentBlock];
if(componetArray && [componetArray count]>0){
[dict setObject:componetArray forKey:@"componet"];
}
NSDictionary *moduleConfigs = [WXModuleFactory moduleConfigs];
void (^moduleBlock)(id, id, BOOL *) = ^(id mKey, id mObj, BOOL * mStop) {
NSDictionary *mDict = [WXModuleFactory moduleSelectorMapsWithName:mKey];
NSMutableDictionary *subDict = [NSMutableDictionary new];
[subDict setObject:mKey forKey:@"name"];
[subDict setObject:mObj forKey:@"class"];
if([mDict objectForKey:mKey]){
[subDict setObject:[mDict objectForKey:mKey] forKey:@"methods"];
}
[moduleArray addObject:subDict];
};
[moduleConfigs enumerateKeysAndObjectsUsingBlock:moduleBlock];
if(moduleArray && [moduleArray count]>0){
[dict setObject:moduleArray forKey:@"module"];
}
NSDictionary *handleConfigs = [[WXHandlerFactory handlerConfigs] mutableCopy];
void (^handleBlock)(id, id, BOOL *) = ^(id mKey, id mObj, BOOL * mStop) {
NSMutableDictionary *subDict = [NSMutableDictionary new];
[subDict setObject:mKey forKey:@"class"];
[subDict setObject:NSStringFromClass([mObj class]) forKey:@"name"];
[handleArray addObject:subDict];
};
[handleConfigs enumerateKeysAndObjectsUsingBlock:handleBlock];
if(handleArray && [handleArray count]>0){
[dict setObject:handleArray forKey:@"handle"];
}
return dict;
}
+ (void)commitTracing:(NSString *)instanceId
{
if(![self isTracing]){
return ;
}
id tracingHandle = [WXSDKEngine handlerForProtocol:@protocol(WXTracingProtocol)];
if ([tracingHandle respondsToSelector:@selector(commitTracingInfo:)]){
WXTracingTask *task = [[WXTracingManager sharedInstance].tracingTasks objectForKey:instanceId];
if(task) {
[tracingHandle commitTracingInfo:task];
}
}
}
+ (void)commitTracingSummaryInfo:(NSDictionary *)info withInstanceId:(NSString *)instanceId
{
if(![self isTracing]){
return ;
}
id tracingHandle = [WXSDKEngine handlerForProtocol:@protocol(WXTracingProtocol)];
if ([tracingHandle respondsToSelector:@selector(commitTracingSummaryInfo:)]){
if(info) {
NSMutableDictionary *newInfo = [info mutableCopy];
if(instanceId.length > 0){
[newInfo setObject:instanceId forKey:@"instanceId"];
[newInfo setObject:[[WXUtility getEnvironment] objectForKey:@"platform"] forKey:@"platform"];
}
[tracingHandle commitTracingSummaryInfo:newInfo];
}
}
}
+(void)destroyTraincgTaskWithInstance:(NSString *)instanceId
{
if(![self isTracing]){
return ;
}
WXTracingTask *task = [[WXTracingManager sharedInstance].tracingTasks objectForKey:instanceId];
if(task){
[[WXTracingManager sharedInstance].tracingTasks removeObjectForKey:instanceId];
}
}
@end