cxfeng1 closed pull request #1412: [WEEX-552][iOS] apm for ios
URL: https://github.com/apache/incubator-weex/pull/1412
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/ios/playground/WeexDemo.xcodeproj/project.pbxproj 
b/ios/playground/WeexDemo.xcodeproj/project.pbxproj
index 9721ca7c98..e3c9b31450 100644
--- a/ios/playground/WeexDemo.xcodeproj/project.pbxproj
+++ b/ios/playground/WeexDemo.xcodeproj/project.pbxproj
@@ -7,6 +7,8 @@
        objects = {
 
 /* Begin PBXBuildFile section */
+               17036A5720FDF9AA0029AE3D /* WXApmGeneratorImpl.m in Sources */ 
= {isa = PBXBuildFile; fileRef = 17036A5620FDF9AA0029AE3D /* 
WXApmGeneratorImpl.m */; };
+               17036A5A20FDF9DF0029AE3D /* WXApmImpl.m in Sources */ = {isa = 
PBXBuildFile; fileRef = 17036A5920FDF9DF0029AE3D /* WXApmImpl.m */; };
                17C1DB57206B675D000E0CEB /* DebugAnzlyzer.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 17C1DB56206B675D000E0CEB /* DebugAnzlyzer.m */; 
};
                2AE88A2C1C8544E6003329DE /* WXScannerVC.m in Sources */ = {isa 
= PBXBuildFile; fileRef = 2AE88A2B1C8544E6003329DE /* WXScannerVC.m */; };
                564B94671DD9C65000441C8D /* WeexUITestDemo-Info.plist in 
Resources */ = {isa = PBXBuildFile; fileRef = 564B94661DD9C65000441C8D /* 
WeexUITestDemo-Info.plist */; };
@@ -67,6 +69,10 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+               17036A5520FDF9AA0029AE3D /* WXApmGeneratorImpl.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; name = 
WXApmGeneratorImpl.h; path = extend/handler/WXApmGeneratorImpl.h; sourceTree = 
"<group>"; };
+               17036A5620FDF9AA0029AE3D /* WXApmGeneratorImpl.m */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = 
WXApmGeneratorImpl.m; path = extend/handler/WXApmGeneratorImpl.m; sourceTree = 
"<group>"; };
+               17036A5820FDF9DF0029AE3D /* WXApmImpl.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WXApmImpl.h; path 
= extend/handler/WXApmImpl.h; sourceTree = "<group>"; };
+               17036A5920FDF9DF0029AE3D /* WXApmImpl.m */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = WXApmImpl.m; 
path = extend/handler/WXApmImpl.m; sourceTree = "<group>"; };
                17C1DB55206B6729000E0CEB /* DebugAnalyzer.h */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.h; name = DebugAnalyzer.h; 
path = debug/DebugAnalyzer.h; sourceTree = "<group>"; };
                17C1DB56206B675D000E0CEB /* DebugAnzlyzer.m */ = {isa = 
PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = 
DebugAnzlyzer.m; path = debug/DebugAnzlyzer.m; sourceTree = "<group>"; };
                1888E2C5769382461DEDC97D /* 
Pods-WeexUITestDemo.release.xcconfig */ = {isa = PBXFileReference; 
includeInIndex = 1; lastKnownFileType = text.xcconfig; name = 
"Pods-WeexUITestDemo.release.xcconfig"; path = "Pods/Target Support 
Files/Pods-WeexUITestDemo/Pods-WeexUITestDemo.release.xcconfig"; sourceTree = 
"<group>"; };
@@ -336,6 +342,10 @@
                                DC20B8E51ECADA2500845F39 /* 
WXConfigCenterDefaultImpl.m */,
                                DCABAFFC1D029753001C8592 /* 
WXImgLoaderDefaultImpl.h */,
                                DCABAFFD1D029753001C8592 /* 
WXImgLoaderDefaultImpl.m */,
+                               17036A5520FDF9AA0029AE3D /* 
WXApmGeneratorImpl.h */,
+                               17036A5620FDF9AA0029AE3D /* 
WXApmGeneratorImpl.m */,
+                               17036A5820FDF9DF0029AE3D /* WXApmImpl.h */,
+                               17036A5920FDF9DF0029AE3D /* WXApmImpl.m */,
                        );
                        name = handler;
                        sourceTree = "<group>";
@@ -625,6 +635,7 @@
                                DCABAFF31D029685001C8592 /* WXATLoggerPlugin.m 
in Sources */,
                                DC15A3D0200E30FC009C8977 /* 
WXNavigationHandlerImpl.m in Sources */,
                                2AE88A2C1C8544E6003329DE /* WXScannerVC.m in 
Sources */,
+                               17036A5720FDF9AA0029AE3D /* 
WXApmGeneratorImpl.m in Sources */,
                                775BEE861C1E8ECC008D1629 /* 
WXDemoViewController.m in Sources */,
                                DC5B53691E8CED9400E02125 /* 
WXScannerHistoryVC.m in Sources */,
                                74CC79EB1C2B9E4700829368 /* 
UIViewController+WXDemoNaviBar.m in Sources */,
@@ -633,6 +644,7 @@
                                775BEE831C1E8ECC008D1629 /* AppDelegate.m in 
Sources */,
                                847CAF311F39E3F100551725 /* WXExtModule.m in 
Sources */,
                                DC15A3C7200C505C009C8977 /* WXTitleBarModule.m 
in Sources */,
+                               17036A5A20FDF9DF0029AE3D /* WXApmImpl.m in 
Sources */,
                                DC20B8E61ECADA2500845F39 /* 
WXConfigCenterDefaultImpl.m in Sources */,
                                DCABAFF41D029685001C8592 /* 
WXATViewHierarchyPlugin.m in Sources */,
                                775BEE801C1E8ECC008D1629 /* main.m in Sources 
*/,
diff --git a/ios/playground/WeexDemo/AppDelegate.m 
b/ios/playground/WeexDemo/AppDelegate.m
index 7687f47a65..683d3b3e61 100644
--- a/ios/playground/WeexDemo/AppDelegate.m
+++ b/ios/playground/WeexDemo/AppDelegate.m
@@ -37,6 +37,7 @@
 #import "WXConfigCenterDefaultImpl.h"
 #import "WXNavigationHandlerImpl.h"
 //#import "WXAnalyzerCenter.h"
+#import "WXApmGeneratorImpl.h"
 
 
 #ifdef DEBUG
@@ -123,6 +124,7 @@ - (void)initWeexSDK
     [WXSDKEngine registerHandler:[WXEventModule new] 
withProtocol:@protocol(WXEventModuleProtocol)];
     [WXSDKEngine registerHandler:[WXConfigCenterDefaultImpl new] 
withProtocol:@protocol(WXConfigCenterProtocol)];
     [WXSDKEngine registerHandler:[WXNavigationHandlerImpl new] 
withProtocol:@protocol(WXNavigationProtocol)];
+    [WXSDKEngine registerHandler:[WXApmGeneratorImpl new] 
withProtocol:@protocol(WXApmGeneratorProtocol)];
     
     [WXSDKEngine registerComponent:@"select" 
withClass:NSClassFromString(@"WXSelectComponent")];
     [WXSDKEngine registerModule:@"event" withClass:[WXEventModule class]];
diff --git a/ios/playground/WeexDemo/extend/handler/WXApmGeneratorImpl.h 
b/ios/playground/WeexDemo/extend/handler/WXApmGeneratorImpl.h
new file mode 100644
index 0000000000..f18c4c3814
--- /dev/null
+++ b/ios/playground/WeexDemo/extend/handler/WXApmGeneratorImpl.h
@@ -0,0 +1,6 @@
+#import <Foundation/Foundation.h>
+#import "WXApmProtocol.h"
+
+@interface WXApmGeneratorImpl : NSObject <WXApmGeneratorProtocol>
+
+@end
diff --git a/ios/playground/WeexDemo/extend/handler/WXApmGeneratorImpl.m 
b/ios/playground/WeexDemo/extend/handler/WXApmGeneratorImpl.m
new file mode 100644
index 0000000000..fffd213310
--- /dev/null
+++ b/ios/playground/WeexDemo/extend/handler/WXApmGeneratorImpl.m
@@ -0,0 +1,12 @@
+#import "WXApmGeneratorImpl.h"
+#import "WXApmImpl.h"
+
+@implementation WXApmGeneratorImpl
+
+- (id<WXApmProtocol>)gengratorApmInstance:(NSString *) type
+{
+    id<WXApmProtocol> instance = [[WXApmImpl alloc] init];
+    return instance;
+}
+
+@end
diff --git a/ios/playground/WeexDemo/extend/handler/WXApmImpl.h 
b/ios/playground/WeexDemo/extend/handler/WXApmImpl.h
new file mode 100644
index 0000000000..85003e6d6f
--- /dev/null
+++ b/ios/playground/WeexDemo/extend/handler/WXApmImpl.h
@@ -0,0 +1,6 @@
+#import <Foundation/Foundation.h>
+#import "WXApmProtocol.h"
+
+@interface WXApmImpl : NSObject <WXApmProtocol>
+
+@end
diff --git a/ios/playground/WeexDemo/extend/handler/WXApmImpl.m 
b/ios/playground/WeexDemo/extend/handler/WXApmImpl.m
new file mode 100644
index 0000000000..4bb195d436
--- /dev/null
+++ b/ios/playground/WeexDemo/extend/handler/WXApmImpl.m
@@ -0,0 +1,110 @@
+
+#import "WXApmImpl.h"
+#import "WXUtility.h"
+
+@interface WXApmImpl()
+@property(nonatomic,strong) NSMutableDictionary<NSString*,NSNumber*>* stageMap;
+@property(nonatomic,strong) NSMutableDictionary<NSString*,id>* propertyMap;
+@property(nonatomic,strong) NSMutableDictionary<NSString*,NSNumber*>* 
statisticMap;
+@property(nonatomic,strong) NSMutableDictionary<NSString*,id>* eventMap;
+
+@end
+
+@implementation WXApmImpl
+
+- (instancetype)init
+{
+    self = [super init];
+    if (self) {
+        _stageMap = [[NSMutableDictionary alloc] init];
+        _propertyMap = [[NSMutableDictionary alloc] init];
+        _statisticMap = [[NSMutableDictionary alloc] init];
+        _eventMap = [[NSMutableDictionary alloc] init];
+    }
+    return self;
+}
+
+
+- (void) onStart:(NSString *)instanceId topic:(NSString *)topic
+{
+    
+}
+
+- (void) onEnd
+{
+    [self _printApmInfo];
+}
+
+- (void) onEvent:(NSString *)name withValue:(id)value
+{
+    [self.eventMap setObject:value forKey:name];
+}
+
+- (void) onStage:(NSString *)name withValue:(long)timestamp
+{
+    [self.stageMap setObject:[NSNumber numberWithLong:timestamp] forKey:name];
+}
+
+- (void) addProperty:(NSString *)name withValue:(id)value
+{
+    [self.propertyMap setObject:value forKey:name];
+}
+
+- (void) addStatistic:(NSString *)name withValue:(double)value
+{
+     [self.statisticMap setObject:[NSNumber numberWithDouble:value] 
forKey:name];
+}
+
+- (void) addBiz:(NSString *)bizID withValue:(NSDictionary *)properties
+{
+    
+}
+
+- (void) addBizAbTest:(NSString *)bizID withValue:(NSDictionary *)abTest
+{
+    
+}
+
+- (void) addBizStage:(NSString *)bizID withValue:(NSDictionary *)stage
+{
+    
+}
+
+- (void) onSubProcedureBegin:(NSString *)subProcedureName
+{
+    
+}
+
+- (void) onSubProcedureEndFailed:(NSString *)subProcedureName
+{
+    
+}
+
+- (void) onSubProcedureEndSucceed:(NSString *)subProcedureName
+{
+    
+}
+
+- (void)pauseApmRecord {
+    
+}
+
+
+- (void)resumeApmRecord {
+    
+}
+
+
+- (void) _printApmInfo
+{
+    NSDictionary* InfoMap = @{
+                              @"stage":self.stageMap,
+                              @"property":self.propertyMap,
+                              @"statistic":self.statisticMap,
+                              @"event":self.eventMap
+                              };
+    NSString* jsonStr = [WXUtility JSONString:InfoMap];
+    NSLog(@"wxApmForInstance :%@",jsonStr);
+}
+
+@end
diff --git a/ios/playground/WeexDemo/extend/handler/WXImgLoaderDefaultImpl.m 
b/ios/playground/WeexDemo/extend/handler/WXImgLoaderDefaultImpl.m
index a085ddbfa9..b957cd74a7 100644
--- a/ios/playground/WeexDemo/extend/handler/WXImgLoaderDefaultImpl.m
+++ b/ios/playground/WeexDemo/extend/handler/WXImgLoaderDefaultImpl.m
@@ -19,6 +19,8 @@
 
 #import "WXImgLoaderDefaultImpl.h"
 #import <SDWebImage/UIImageView+WebCache.h>
+#import "WXLog.h"
+#import "WXSDKManager.h"
 
 #define MIN_IMAGE_WIDTH 36
 #define MIN_IMAGE_HEIGHT 36
@@ -48,6 +50,7 @@ @implementation WXImgLoaderDefaultImpl
 
 - (id<WXImageOperationProtocol>)downloadImageWithURL:(NSString *)url 
imageFrame:(CGRect)imageFrame userInfo:(NSDictionary *)userInfo 
completed:(void(^)(UIImage *image,  NSError *error, BOOL 
finished))completedBlock
 {
+    [self _recoredImgLoad:url options:userInfo];
     if ([url hasPrefix:@"//"]) {
         url = [@"http:" stringByAppendingString:url];
     }
@@ -57,11 +60,13 @@ @implementation WXImgLoaderDefaultImpl
         if (completedBlock) {
             completedBlock(image, error, finished);
         }
+        [self _recoredFinish:imageURL error:error loadOptions:userInfo];
     }];
 }
 
 - (void)setImageViewWithURL:(UIImageView *)imageView url:(NSURL *)url 
placeholderImage:(UIImage *)placeholder options:(NSDictionary *)options 
progress:(void (^)(NSInteger, NSInteger))progressBlock completed:(void 
(^)(UIImage *, NSError *, WXImageLoaderCacheType, NSURL *))completedBlock
 {
+    [self _recoredImgLoad:url.absoluteString options:options];
     SDWebImageOptions sdWebimageOption = SDWebImageRetryFailed;
     if (options && options[@"sdWebimageOption"]) {
         [options[@"sdWebimageOption"] intValue];
@@ -75,7 +80,40 @@ - (void)setImageViewWithURL:(UIImageView *)imageView 
url:(NSURL *)url placeholde
         if (completedBlock) {
             completedBlock(image, error, (WXImageLoaderCacheType)cacheType, 
imageURL);
         }
+        [self _recoredFinish:imageURL error:error loadOptions:options];
     }];
 }
 
+- (void) _recoredImgLoad:(NSString *)url options:(NSDictionary *)options
+{
+    if (nil == url) {
+        return;
+    }
+    NSString* instanceId = [options objectForKey:@"instanceId"];
+    if (nil == instanceId) {
+        WXLogWarning(@"please set instanceId in userInfo,for url %@:",url);
+        return;
+    }
+    WXSDKInstance* instance =[WXSDKManager instanceForID:instanceId];
+    if (nil == instance) {
+        return;
+    }
+    [instance.apmInstance updateDiffStats:KEY_PAGE_STATS_IMG_LOAD_NUM 
withDiffValue:1];
+}
+
+- (void) _recoredFinish:(NSURL*)imgUrl error:(NSError*)error 
loadOptions:(NSDictionary*)options
+{
+    NSString* instanceId = [options objectForKey:@"instanceId"];
+    if (nil == instanceId) {
+        WXLogWarning(@"please set instanceId in userInfo,for url 
%@:",imgUrl.absoluteString);
+        return;
+    }
+    WXSDKInstance* instance =[WXSDKManager instanceForID:instanceId];
+    if (nil == instance) {
+        return;
+    }
+    bool loadSucceed = error == nil;
+    [instance.apmInstance actionImgLoadResult:loadSucceed withErrorCode:nil];
+}
+
 @end
diff --git a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj 
b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
index 92753ed8f9..8a8ed3ba29 100644
--- a/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
+++ b/ios/sdk/WeexSDK.xcodeproj/project.pbxproj
@@ -8,6 +8,12 @@
 
 /* Begin PBXBuildFile section */
                042013AD1E66CD6A001FC79C /* WXValidateProtocol.h in Headers */ 
= {isa = PBXBuildFile; fileRef = 042013AC1E66CD6A001FC79C /* 
WXValidateProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               17036A4E20FDE72F0029AE3D /* WXApmForInstance.h in Headers */ = 
{isa = PBXBuildFile; fileRef = 17036A4C20FDE72F0029AE3D /* WXApmForInstance.h 
*/; settings = {ATTRIBUTES = (Public, ); }; };
+               17036A4F20FDE72F0029AE3D /* WXApmForInstance.h in Headers */ = 
{isa = PBXBuildFile; fileRef = 17036A4C20FDE72F0029AE3D /* WXApmForInstance.h 
*/; settings = {ATTRIBUTES = (Public, ); }; };
+               17036A5020FDE72F0029AE3D /* WXInstanceApm.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 17036A4D20FDE72F0029AE3D /* WXInstanceApm.m */; 
};
+               17036A5120FDE72F0029AE3D /* WXInstanceApm.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 17036A4D20FDE72F0029AE3D /* WXInstanceApm.m */; 
};
+               17036A5320FDE7490029AE3D /* WXApmProtocol.h in Headers */ = 
{isa = PBXBuildFile; fileRef = 17036A5220FDE7490029AE3D /* WXApmProtocol.h */; 
settings = {ATTRIBUTES = (Public, ); }; };
+               17036A5420FDE7490029AE3D /* WXApmProtocol.h in Headers */ = 
{isa = PBXBuildFile; fileRef = 17036A5220FDE7490029AE3D /* WXApmProtocol.h */; 
settings = {ATTRIBUTES = (Public, ); }; };
                170B4664208733AF00562666 /* WXAnalyzerCenter.h in Headers */ = 
{isa = PBXBuildFile; fileRef = 17C74F092072145000AB4CAB /* WXAnalyzerCenter.h 
*/; settings = {ATTRIBUTES = (Public, ); }; };
                170B4665208733BF00562666 /* WXAnalyzerCenter+Transfer.h in 
Headers */ = {isa = PBXBuildFile; fileRef = 17C74F082072145000AB4CAB /* 
WXAnalyzerCenter+Transfer.h */; };
                170B4668208733E500562666 /* WXAnalyzerCenter.m in Sources */ = 
{isa = PBXBuildFile; fileRef = 17C74F0A2072145100AB4CAB /* WXAnalyzerCenter.m 
*/; };
@@ -647,6 +653,9 @@
 /* Begin PBXFileReference section */
                042013AC1E66CD6A001FC79C /* WXValidateProtocol.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WXValidateProtocol.h; sourceTree = "<group>"; };
                1746EA7220E9D253007E55BD /* WXComponent_performance.h */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path 
= WXComponent_performance.h; sourceTree = "<group>"; };
+               17036A4C20FDE72F0029AE3D /* WXApmForInstance.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WXApmForInstance.h; sourceTree = "<group>"; };
+               17036A4D20FDE72F0029AE3D /* WXInstanceApm.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= WXInstanceApm.m; sourceTree = "<group>"; };
+               17036A5220FDE7490029AE3D /* WXApmProtocol.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
WXApmProtocol.h; sourceTree = "<group>"; };
                176BE43B209172330086B6AF /* WXComponent+Layout.mm */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; 
name = "WXComponent+Layout.mm"; path = "Layout/WXComponent+Layout.mm"; 
sourceTree = "<group>"; };
                17B1221F2090AA9300387E33 /* WXSDKInstance_performance.m */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = 
sourcecode.c.objc; path = WXSDKInstance_performance.m; sourceTree = "<group>"; 
};
                17B122202090AA9300387E33 /* WXSDKInstance_performance.h */ = 
{isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; 
path = WXSDKInstance_performance.h; sourceTree = "<group>"; };
@@ -1022,6 +1031,25 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+               17036A4B20FDE7090029AE3D /* Performance */ = {
+                       isa = PBXGroup;
+                       children = (
+                               17036A4C20FDE72F0029AE3D /* WXApmForInstance.h 
*/,
+                               17036A4D20FDE72F0029AE3D /* WXInstanceApm.m */,
+                       );
+                       path = Performance;
+                       sourceTree = "<group>";
+               };
+               17B12228209170CF00387E33 /* Recovered References */ = {
+                       isa = PBXGroup;
+                       children = (
+                               8431F8DD1F9EFCC100C76E1E /* 
WXScrollerComponent+Layout.mm */,
+                               59D3CA461CFC3CC0008835DC /* 
WXSliderComponent.mm */,
+                               847E1DE01F9A1BCF00A48124 /* WXCoreStyle.h */,
+                       );
+                       name = "Recovered References";
+                       sourceTree = "<group>";
+               };
                2A42AF861C23B33E00818EA6 /* WeexSDK_MTL */ = {
                        isa = PBXGroup;
                        children = (
@@ -1303,6 +1331,7 @@
                77D161181C02DCB90010B15B /* Sources */ = {
                        isa = PBXGroup;
                        children = (
+                               17036A4B20FDE7090029AE3D /* Performance */,
                                DCA446261EFA5DAF00D0CFA8 /* WeexSDK.h */,
                                C4F012711E1502A6003378D0 /* WebSocket */,
                                2AF626C61C191E2200E71A38 /* Layout */,
@@ -1405,6 +1434,7 @@
                77D1611C1C02DD3C0010B15B /* Protocol */ = {
                        isa = PBXGroup;
                        children = (
+                               17036A5220FDE7490029AE3D /* WXApmProtocol.h */,
                                17C74F0E2072147A00AB4CAB /* 
WXAnalyzerProtocol.h */,
                                59A596171CB630E50012CD52 /* 
WXNavigationProtocol.h */,
                                DCDFED001E68238F00C228D7 /* 
WXJSExceptionProtocol.h */,
@@ -1637,6 +1667,7 @@
                                775BEE711C1BD977008D1629 /* WXModuleProtocol.h 
in Headers */,
                                7469869F1C4E2C000054A57E /* NSArray+Weex.h in 
Headers */,
                                74CC7A201C2BF9DC00829368 /* WXListComponent.h 
in Headers */,
+                               17036A5320FDE7490029AE3D /* WXApmProtocol.h in 
Headers */,
                                7423EB511F4ADE30001662D1 /* 
WXComponent+DataBinding.h in Headers */,
                                74FD6E041C7C0E9600DBEB6D /* 
WXScrollerProtocol.h in Headers */,
                                74CFDD3D1F459400007A1A66 /* 
WXRecycleListDataManager.h in Headers */,
@@ -1764,6 +1795,7 @@
                                74A4BA851CAD453400195969 /* WXNetworkProtocol.h 
in Headers */,
                                7461F8A81CFC33A800F62D44 /* 
WXThreadSafeMutableArray.h in Headers */,
                                D33451081D3E19480083598A /* WXCanvasComponent.h 
in Headers */,
+                               17036A4E20FDE72F0029AE3D /* WXApmForInstance.h 
in Headers */,
                                74B8BEFE1DC47B72004A6027 /* WXRootView.h in 
Headers */,
                                77E65A111C155EA8008B8775 /* WXImageComponent.h 
in Headers */,
                                745B2D6C1E5A8E1E0092D38A /* 
WXRecyclerDataController.h in Headers */,
@@ -1844,6 +1876,7 @@
                                DCA445B11EFA576800D0CFA8 /* WXLog.h in Headers 
*/,
                                DCA4459D1EFA56DB00D0CFA8 /* 
WXValidateProtocol.h in Headers */,
                                DCA445B81EFA579800D0CFA8 /* 
WXEventModuleProtocol.h in Headers */,
+                               17036A5420FDE7490029AE3D /* WXApmProtocol.h in 
Headers */,
                                DCA445AE1EFA575700D0CFA8 /* WXMonitor.h in 
Headers */,
                                DCA445BD1EFA57B500D0CFA8 /* 
WXConfigCenterProtocol.h in Headers */,
                                DCA445A11EFA56FA00D0CFA8 /* 
WXScrollerProtocol.h in Headers */,
@@ -1907,6 +1940,7 @@
                                74B81AE31F73C3E300D3A61D /* 
WXRecycleListComponent.h in Headers */,
                                DCA445DA1EFA59A600D0CFA8 /* 
WXMultiColumnLayout.h in Headers */,
                                DCA445E01EFA59CD00D0CFA8 /* 
WXLoadingIndicator.h in Headers */,
+                               17036A4F20FDE72F0029AE3D /* WXApmForInstance.h 
in Headers */,
                                DCA445E61EFA59E500D0CFA8 /* WXImageComponent.h 
in Headers */,
                                DCA4461B1EFA5AA200D0CFA8 /* 
WXDatePickerManager.h in Headers */,
                                DCA445D71EFA598D00D0CFA8 /* 
WXComponent+ViewManagement.h in Headers */,
@@ -2290,6 +2324,7 @@
                                74862F821E03A24500B7A041 /* WXComponentMethod.m 
in Sources */,
                                77E65A121C155EA8008B8775 /* WXImageComponent.m 
in Sources */,
                                74CFDD3E1F459400007A1A66 /* 
WXRecycleListDataManager.m in Sources */,
+                               17036A5020FDE72F0029AE3D /* WXInstanceApm.m in 
Sources */,
                                2A837AB31CD9DE9200AEDF03 /* 
WXLoadingComponent.mm in Sources */,
                                2AE5B7531CAB7DBD0082FDDB /* WXAComponent.m in 
Sources */,
                                176BE43C209172330086B6AF /* 
WXComponent+Layout.mm in Sources */,
@@ -2380,6 +2415,7 @@
                                DCA445511EFA55B300D0CFA8 /* 
WXCycleSliderComponent.mm in Sources */,
                                DCE2CF9D1F46D4370021BDC4 /* WXVoiceOverModule.m 
in Sources */,
                                DCA445531EFA55B300D0CFA8 /* WXCellComponent.mm 
in Sources */,
+                               17036A5120FDE72F0029AE3D /* WXInstanceApm.m in 
Sources */,
                                DCA445541EFA55B300D0CFA8 /* WXListComponent.mm 
in Sources */,
                                DCA445551EFA55B300D0CFA8 /* 
WXIndicatorComponent.m in Sources */,
                                17E5ACDB2091F05700EE81F1 /* 
WXComponent+Layout.mm in Sources */,
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m 
b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index cb4903ace0..f19632288c 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -484,6 +484,11 @@ - (NSInteger)invokeNative:(NSString *)instanceId 
tasks:(NSArray *)tasks callback
         instance.performance.fsCallNativeNum++;
         instance.performance.fsCallNativeTime =  
instance.performance.fsCallNativeTime + diff;
     }
+    if (instance && !instance.apmInstance.isFSEnd) {
+        NSTimeInterval diff = CACurrentMediaTime()*1000 - startTime;
+        [instance.apmInstance 
updateFSDiffStats:KEY_PAGE_STATS_FS_CALL_NATIVE_NUM withDiffValue:1];
+        [instance.apmInstance 
updateFSDiffStats:KEY_PAGE_STATS_FS_CALL_NATIVE_TIME withDiffValue:diff];
+    }
     return 1;
 }
 
@@ -504,6 +509,8 @@ - (void)createInstance:(NSString *)instanceIdString
                        }
                }
        }
+    WXSDKInstance *sdkInstance = [WXSDKManager instanceForID:instanceIdString];
+    [sdkInstance.apmInstance onStage:KEY_PAGE_STAGES_LOAD_BUNDLE_START];
     
     //create a sendQueue bind to the current instance
     NSMutableArray *sendQueue = [NSMutableArray array];
@@ -519,6 +526,8 @@ - (void)createInstance:(NSString *)instanceIdString
         bundleType = [self _pareJSBundleType:instanceIdString 
jsBundleString:jsBundleString]; // bundleType can be Vue, Rax and the new 
framework.
     }
     if (bundleType&&shoudMultiContext) {
+        [sdkInstance.apmInstance 
setProperty:KEY_PAGE_PROPERTIES_USE_MULTI_CONTEXT withValue:[NSNumber 
numberWithBool:true]];
+        [sdkInstance.apmInstance setProperty:KEY_PAGE_PROPERTIES_BUNDLE_TYPE 
withValue:bundleType];
         NSMutableDictionary *newOptions = [options mutableCopy];
         if (!options) {
             newOptions = [NSMutableDictionary new];
@@ -527,7 +536,6 @@ - (void)createInstance:(NSString *)instanceIdString
         newOptions[@"bundleType"] = bundleType;
         NSString *raxAPIScript = nil;
         NSString *raxAPIScriptPath = nil;
-        WXSDKInstance *sdkInstance = [WXSDKManager 
instanceForID:instanceIdString];
         sdkInstance.bundleType = bundleType;
         if ([bundleType.lowercaseString isEqualToString:@"rax"]) {
              raxAPIScriptPath = [[NSBundle bundleForClass:[weakSelf class]] 
pathForResource:@"weex-rax-api" ofType:@"js"];
@@ -597,6 +605,8 @@ - (void)createInstance:(NSString *)instanceIdString
         }
         
     } else {
+        [sdkInstance.apmInstance 
setProperty:KEY_PAGE_PROPERTIES_USE_MULTI_CONTEXT withValue:[NSNumber 
numberWithBool:false]];
+        [sdkInstance.apmInstance setProperty:KEY_PAGE_PROPERTIES_BUNDLE_TYPE 
withValue:@"singleContextUnkonwType"];
         if (data){
             args = @[instanceIdString, jsBundleString, options ?: @{}, data];
         } else {
@@ -605,6 +615,7 @@ - (void)createInstance:(NSString *)instanceIdString
         [self callJSMethod:@"createInstance" args:args];
     }
     WX_MONITOR_INSTANCE_PERF_END(WXPTJSCreateInstance, [WXSDKManager 
instanceForID:instanceIdString]);
+    [sdkInstance.apmInstance onStage:KEY_PAGE_STAGES_LOAD_BUNDLE_END];
 }
 
 - (NSString *)_pareJSBundleType:(NSString*)instanceIdString 
jsBundleString:(NSString*)jsBundleString
@@ -950,10 +961,8 @@ - (void)_sendQueueLoop
     
     if ([tasks count] > 0 && execIns) {
         WXSDKInstance * execInstance = [WXSDKManager instanceForID:execIns];
-        NSTimeInterval start = -1;
-        if (execInstance && !(execInstance.isJSCreateFinish)) {
-            start = CACurrentMediaTime()*1000;
-        }
+        NSTimeInterval start = CACurrentMediaTime()*1000;
+        
         if (execInstance.instanceJavaScriptContext && execInstance.bundleType) 
{
             [self callJSMethod:@"__WEEX_CALL_JAVASCRIPT__" args:@[execIns, 
tasks] onContext:execInstance.instanceJavaScriptContext completion:nil];
         } else {
@@ -964,6 +973,11 @@ - (void)_sendQueueLoop
             execInstance.performance.fsCallJsNum++;
             execInstance.performance.fsCallJsTime =  
execInstance.performance.fsCallJsTime+ diff;
          }
+        if (execInstance && !execInstance.apmInstance.isFSEnd) {
+             NSTimeInterval diff = CACurrentMediaTime()*1000 - start;
+            [execInstance.apmInstance 
updateFSDiffStats:KEY_PAGE_STATS_FS_CALL_JS_NUM withDiffValue:1];
+            [execInstance.apmInstance 
updateFSDiffStats:KEY_PAGE_STATS_FS_CALL_JS_TIME withDiffValue:diff];
+        }
     }
     
     if (hasTask) {
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm 
b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm
index 36b82b3c0f..e6b6f725a5 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCellComponent.mm
@@ -54,6 +54,13 @@ - (instancetype)initWithRef:(NSString *)ref type:(NSString 
*)type styles:(NSDict
         if (attributes[@"zIndex"]) {
             _zIndex = [WXConvert NSString:attributes[@"zIndex"]];
         }
+        if (!_isRecycle) {
+            [weexInstance.apmInstance 
updateDiffStats:KEY_PAGE_STATS_CELL_UN_RE_USE_NUM withDiffValue:1];
+            //for protocol
+            //in iOS impl,cellReuse equal cellDataRecycle
+            //in Android, cellReuse is not equal cellDataRecycle
+            [weexInstance.apmInstance 
updateDiffStats:KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM withDiffValue:1];
+        }
     }
     
     return self;
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m 
b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
index 7f177f3050..ef28440a45 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXImageComponent.m
@@ -373,11 +373,12 @@ - (void)updateImage
         if (self.placeholdSrc) {
             newURL = [self.placeholdSrc copy];
             WX_REWRITE_URL([self placeholdSrc], WXResourceTypeImage, 
self.weexInstance)
-            [[self imageLoader] setImageViewWithURL:(UIImageView*)self.view 
url:[NSURL URLWithString:newURL] placeholderImage:nil options:nil progress:nil 
completed:nil];
+            NSDictionary* extInfo = 
@{@"instanceId":self.weexInstance.instanceId};
+            [[self imageLoader] setImageViewWithURL:(UIImageView*)self.view 
url:[NSURL URLWithString:newURL] placeholderImage:nil options:extInfo 
progress:nil completed:nil];
         }
         newURL = [[self imageSrc] copy];
         WX_REWRITE_URL([self imageSrc], WXResourceTypeImage, self.weexInstance)
-        NSDictionary *userInfo = @{@"imageQuality":@(self.imageQuality), 
@"imageSharp":@(self.imageSharp), @"blurRadius":@(self.blurRadius)};
+        NSDictionary *userInfo = @{@"imageQuality":@(self.imageQuality), 
@"imageSharp":@(self.imageSharp), 
@"blurRadius":@(self.blurRadius),@"instanceId":self.weexInstance.instanceId};
         [[self imageLoader] setImageViewWithURL:(UIImageView*)self.view 
url:[NSURL URLWithString:newURL] placeholderImage:nil options:userInfo 
progress:^(NSInteger receivedSize, NSInteger expectedSize) {
             // progress when loading image
         } completed:^(UIImage *image, NSError *error, WXImageLoaderCacheType 
cacheType, NSURL *imageURL) {
@@ -395,7 +396,7 @@ - (void)updateImage
                 if (strongSelf.placeholdSrc) {
                     NSString *newURL = [strongSelf.placeholdSrc copy];
                     WX_REWRITE_URL([strongSelf placeholdSrc], 
WXResourceTypeImage, strongSelf.weexInstance)
-                    [[strongSelf imageLoader] 
setImageViewWithURL:(UIImageView*)strongSelf.view url:[NSURL 
URLWithString:newURL] placeholderImage:nil options:nil progress:nil 
completed:nil];
+                    [[strongSelf imageLoader] 
setImageViewWithURL:(UIImageView*)strongSelf.view url:[NSURL 
URLWithString:newURL] placeholderImage:nil 
options:@{@"instanceId":strongSelf.weexInstance.instanceId} progress:nil 
completed:nil];
                     return;
                 }
             }
@@ -419,8 +420,9 @@ - (void)updateImage
             if (!error && image && strongSelf.view) {
                 double imageSize = image.size.width * image.scale * 
image.size.height * image.scale;
                 double viewSize = strongSelf.view.frame.size.height *  
strongSelf.view.frame.size.width;
-                if (imageSize > viewSize) {
+                if (imageSize > viewSize+1) {
                     self.weexInstance.performance.imgWrongSizeNum++;
+                    [self.weexInstance.apmInstance 
updateDiffStats:KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT withDiffValue:1];
                 }
             }
         }];
@@ -465,7 +467,10 @@ - (void)updatePlaceHolderWithFailedBlock:(void(^)(NSString 
*, NSError *))downloa
     WX_REWRITE_URL(self.placeholdSrc, WXResourceTypeImage, self.weexInstance)
     
     __weak typeof(self) weakSelf = self;
-    self.placeholderOperation = [[self imageLoader] 
downloadImageWithURL:newURL imageFrame:self.calculatedFrame userInfo:nil 
completed:^(UIImage *image, NSError *error, BOOL finished) {
+    self.placeholderOperation = [[self imageLoader] 
downloadImageWithURL:newURL imageFrame:self.calculatedFrame
+                                        
userInfo:@{@"instanceId":self.weexInstance.instanceId}
+                                        completed:^(UIImage *image, NSError 
*error, BOOL finished)
+    {
         dispatch_async(dispatch_get_main_queue(), ^{
             __strong typeof(self) strongSelf = weakSelf;
             UIImage *viewImage = ((UIImageView *)strongSelf.view).image;
@@ -502,7 +507,7 @@ - (void)updateContentImageWithFailedBlock:(void(^)(NSString 
*, NSError *))downlo
     }
     
     WXLogDebug(@"Updating image:%@, component:%@", self.imageSrc, self.ref);
-    NSDictionary *userInfo = @{@"imageQuality":@(self.imageQuality), 
@"imageSharp":@(self.imageSharp), @"blurRadius":@(self.blurRadius)};
+    NSDictionary *userInfo = @{@"imageQuality":@(self.imageQuality), 
@"imageSharp":@(self.imageSharp), 
@"blurRadius":@(self.blurRadius),@"instanceId":self.weexInstance.instanceId};
     NSString * newURL = [imageSrc copy];
     WX_REWRITE_URL(imageSrc, WXResourceTypeImage, self.weexInstance)
     __weak typeof(self) weakSelf = self;
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm 
b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
index 056ca4ed16..4a876db8fc 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
@@ -173,6 +173,10 @@ -(instancetype)initWithRef:(NSString *)ref type:(NSString 
*)type styles:(NSDicti
             _shouldRemoveScrollerListener = shouldRemoveScrollerListener;
             
         }
+        //may be list
+        if ([@"scroller" isEqualToString:type]) {
+            [weexInstance.apmInstance 
updateDiffStats:KEY_PAGE_STATS_SCROLLER_NUM withDiffValue:1];
+        }
     }
     
     return self;
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.m 
b/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.m
index 82b2be5d9b..cf3a5fc681 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXVideoComponent.m
@@ -199,7 +199,10 @@ - (void)setPosterURL:(NSURL *)posterURL {
     
     [self cancelImage];
     __weak typeof(self) weakSelf = self;
-    weakSelf.imageOperation = [[self imageLoader] 
downloadImageWithURL:posterURL.absoluteString 
imageFrame:self.posterImageView.frame userInfo:nil completed:^(UIImage *image, 
NSError *error, BOOL finished) {
+    weakSelf.imageOperation = [[self imageLoader] 
downloadImageWithURL:posterURL.absoluteString 
imageFrame:self.posterImageView.frame
+                                                              
userInfo:@{@"instanceId":self.weexSDKInstance.instanceId}
+                                                             
completed:^(UIImage *image, NSError *error, BOOL finished)
+    {
         dispatch_async(dispatch_get_main_queue(), ^{
             __strong typeof(self) strongSelf = weakSelf;
             if (!error) {
diff --git a/ios/sdk/WeexSDK/Sources/Handler/WXNavigationDefaultImpl.m 
b/ios/sdk/WeexSDK/Sources/Handler/WXNavigationDefaultImpl.m
index d57bf8bb9b..5f3383510b 100644
--- a/ios/sdk/WeexSDK/Sources/Handler/WXNavigationDefaultImpl.m
+++ b/ios/sdk/WeexSDK/Sources/Handler/WXNavigationDefaultImpl.m
@@ -284,7 +284,7 @@ - (UIView *)barButton:(NSDictionary *)param 
position:(WXNavigationItemPosition)p
             button.position = position;
             [button addTarget:self action:@selector(onClickBarButton:) 
forControlEvents:UIControlEventTouchUpInside];
             
-            [[self imageLoader] downloadImageWithURL:icon 
imageFrame:CGRectMake(0, 0, 25, 25) userInfo:nil completed:^(UIImage *image, 
NSError *error, BOOL finished) {
+            [[self imageLoader] downloadImageWithURL:icon 
imageFrame:CGRectMake(0, 0, 25, 25) 
userInfo:@{@"instanceId":self.weexInstance.instanceId} completed:^(UIImage 
*image, NSError *error, BOOL finished) {
                 dispatch_async(dispatch_get_main_queue(), ^{
                     [button setBackgroundImage:image 
forState:UIControlStateNormal];
                     [button setBackgroundImage:image 
forState:UIControlStateHighlighted];
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm 
b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
index 1e4be38240..83c7986134 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
@@ -130,6 +130,7 @@ - (void)_frameDidCalculated:(BOOL)isChanged
         CGFloat mainScreenHeight = [[UIScreen mainScreen] bounds].size.height;
         if (mainScreenHeight/2 < _calculatedFrame.size.height && 
mainScreenWidth/2 < _calculatedFrame.size.width) {
             [self weexInstance].performance.cellExceedNum++;
+            [self.weexInstance.apmInstance 
updateFSDiffStats:KEY_PAGE_STATS_CELL_EXCEED_NUM withDiffValue:1];
         }
     }
     
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m 
b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
index 3a9e27e020..ebbc95c39b 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXBridgeManager.m
@@ -351,6 +351,10 @@ - (void)fireEvent:(NSString *)instanceId ref:(NSString 
*)ref type:(NSString *)ty
     {
         instance.performance.fsCallEventNum++;
     }
+    if (instance && !instance.apmInstance.isFSEnd) {
+        [instance.apmInstance 
updateFSDiffStats:KEY_PAGE_STATS_FS_CALL_EVENT_NUM withDiffValue:1];
+    }
+    
     WXCallJSMethod *method = [[WXCallJSMethod alloc] initWithModuleName:nil 
methodName:@"fireEvent" arguments:args instance:instance];
     [self callJsMethod:method];
 }
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm 
b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
index a3510a697b..43622dca68 100644
--- a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
+++ b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.mm
@@ -296,6 +296,7 @@ - (void)_recursivelyAddComponent:(NSDictionary 
*)componentData toSupercomponent:
 
     
     [supercomponent _insertSubcomponent:component atIndex:index];
+    [supercomponent.weexInstance.apmInstance 
updateMaxStats:KEY_PAGE_STATS_MAX_COMPONENT_NUM 
curMaxValue:[supercomponent.weexInstance numberOfComponents]];
     // use _lazyCreateView to forbid component like cell's view creating
     if(supercomponent && component && supercomponent->_lazyCreateView) {
         component->_lazyCreateView = YES;
@@ -396,6 +397,7 @@ - (void)recordMaximumVirtualDom:(WXComponent*) component
         maxDeep++;
         component = component.supercomponent;
     }
+    [self.weexInstance.apmInstance updateMaxStats:KEY_PAGE_STATS_MAX_DEEP_DOM 
curMaxValue:maxDeep];
     if(maxDeep > [self weexInstance].performance.maxVdomDeep)
     {
         [self weexInstance].performance.maxVdomDeep = maxDeep;
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h 
b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
index f987d89376..1e333c796b 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.h
@@ -23,6 +23,7 @@
 #import "WXResourceResponse.h"
 #import "WXResourceRequest.h"
 #import "WXBridgeProtocol.h"
+#import "WXApmForInstance.h"
 
 extern NSString *const bundleUrlOptionKey;
 
@@ -187,6 +188,7 @@ typedef NS_ENUM(NSInteger, WXErrorCode) {//error.code
  */
 @property (nonatomic, copy) BOOL 
(^onRenderTerminateWhenJSDownloadedFinish)(WXResourceResponse 
*response,WXResourceRequest *request,NSData *data, NSError* error);
 
+@property(nonatomic,strong) NSDictionary* continerInfo;
 
 /**
  *  the frame of current instance.
@@ -285,7 +287,6 @@ typedef NS_ENUM(NSInteger, WXErrorCode) {//error.code
  */
 - (NSUInteger)numberOfComponents;
 
-
 /**
  * check whether the module eventName is registered
  */
@@ -315,12 +316,18 @@ typedef NS_ENUM(NSInteger, WXErrorCode) {//error.code
 @property (nonatomic, strong) NSString *bizType;
 @property (nonatomic, strong) NSString *pageName;
 @property (nonatomic, weak) id pageObject;
+//Deprecated, use @WXApmForInstance
 @property (nonatomic, strong) NSMutableDictionary *performanceDict;
 
+@property (nonatomic ,strong) WXApmForInstance* apmInstance;
+
+
 
 /** 
  * Deprecated 
  */
+
+
 @property (nonatomic, strong) NSDictionary *properties 
DEPRECATED_MSG_ATTRIBUTE();
 @property (nonatomic, assign) NSTimeInterval networkTime 
DEPRECATED_MSG_ATTRIBUTE();
 @property (nonatomic, copy) void (^updateFinish)(UIView *);
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m 
b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
index db08941d67..7855f50acb 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
@@ -120,6 +120,7 @@ - (instancetype)init
         _performanceCommit = NO;
         
         _performance = [[WXPerformance alloc] init];
+        _apmInstance = [[WXApmForInstance alloc] init];
         
         id configCenter = [WXSDKEngine 
handlerForProtocol:@protocol(WXConfigCenterProtocol)];
         if ([configCenter 
respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) {
@@ -216,9 +217,9 @@ - (void)renderWithURL:(NSURL *)url options:(NSDictionary 
*)options data:(id)data
         WXLogError(@"Url must be passed if you use renderWithURL");
         return;
     }
+    [self.apmInstance startRecord:self.instanceId];
     
     self.needValidate = [[WXHandlerFactory 
handlerForProtocol:@protocol(WXValidateProtocol)] needValidate:url];
-    
     WXResourceRequest *request = [WXResourceRequest requestWithURL:url 
resourceType:WXResourceTypeMainBundle referrer:@"" 
cachePolicy:NSURLRequestUseProtocolCachePolicy];
     [self _renderWithRequest:request options:options data:data];
     [WXTracingManager startTracingWithInstanceId:self.instanceId ref:nil 
className:nil name:WXTNetworkHanding phase:WXTracingBegin 
functionName:@"renderWithURL" options:@{@"bundleUrl":url?[url 
absoluteString]:@"",@"threadName":WXTMainThread}];
@@ -245,6 +246,7 @@ - (void)_renderWithMainBundleString:(NSString 
*)mainBundleString
         return;
     }
     self.performance.renderTimeOrigin = CACurrentMediaTime()*1000;
+    [self.apmInstance onStage:KEY_PAGE_STAGES_RENDER_ORGIGIN];
     
     if (![WXUtility isBlankString:self.pageName]) {
         WXLog(@"Start rendering page:%@", self.pageName);
@@ -299,10 +301,12 @@ - (void)_renderWithMainBundleString:(NSString 
*)mainBundleString
     _needDestroy = YES;
     _mainBundleString = mainBundleString;
     if ([self _handleConfigCenter]) {
-        NSError * error = [NSError errorWithDomain:WX_ERROR_DOMAIN code:9999 
userInfo:nil];
+        int wxErrorCode = 9999;
+        NSError * error = [NSError errorWithDomain:WX_ERROR_DOMAIN 
code:wxErrorCode userInfo:nil];
         if (self.onFailed) {
             self.onFailed(error);
         }
+        [self.apmInstance setProperty:KEY_PROPERTIES_ERROR_CODE 
withValue:[@(wxErrorCode) stringValue]];
         return;
     }
     
@@ -380,8 +384,10 @@ - (void)_renderWithRequest:(WXResourceRequest *)request 
options:(NSDictionary *)
     WX_MONITOR_INSTANCE_PERF_START(WXPTJSDownload, self);
     __weak typeof(self) weakSelf = self;
     _mainBundleLoader = [[WXResourceLoader alloc] initWithRequest:request];;
+     [self.apmInstance onStage:KEY_PAGE_STAGES_DOWN_BUNDLE_START];
     _mainBundleLoader.onFinished = ^(WXResourceResponse *response, NSData 
*data) {
         __strong typeof(weakSelf) strongSelf = weakSelf;
+        [strongSelf.apmInstance onStage:KEY_PAGE_STAGES_DOWN_BUNDLE_END];
         NSError *error = nil;
         if ([response isKindOfClass:[NSHTTPURLResponse class]] && 
((NSHTTPURLResponse *)response).statusCode != 200) {
             error = [NSError errorWithDomain:WX_ERROR_DOMAIN
@@ -399,6 +405,7 @@ - (void)_renderWithRequest:(WXResourceRequest *)request 
options:(NSDictionary *)
         if (error) {
             WXJSExceptionInfo * jsExceptionInfo = [[WXJSExceptionInfo alloc] 
initWithInstanceId:@"" bundleUrl:[request.URL absoluteString] 
errorCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_JS_DOWNLOAD] 
functionName:@"_renderWithRequest:options:data:" exception:[error 
localizedDescription]  userInfo:nil];
             [WXExceptionUtils commitCriticalExceptionRT:jsExceptionInfo];
+            [strongSelf.apmInstance setProperty:KEY_PROPERTIES_ERROR_CODE 
withValue:[@(WX_KEY_EXCEPTION_JS_DOWNLOAD) stringValue]];
             return;
         }
 
@@ -412,18 +419,24 @@ - (void)_renderWithRequest:(WXResourceRequest *)request 
options:(NSDictionary *)
             if (strongSelf.onFailed) {
                 strongSelf.onFailed(error);
             }
+            [strongSelf.apmInstance setProperty:KEY_PROPERTIES_ERROR_CODE 
withValue:[@(WX_KEY_EXCEPTION_JS_DOWNLOAD) stringValue]];
             return;
         }
         
         NSString *jsBundleString = [[NSString alloc] initWithData:data 
encoding:NSUTF8StringEncoding];
         if (!jsBundleString) {
             WX_MONITOR_FAIL_ON_PAGE(WXMTJSDownload, 
WX_ERR_JSBUNDLE_STRING_CONVERT, @"data converting to string failed.", 
strongSelf.pageName)
+            [strongSelf.apmInstance setProperty:KEY_PROPERTIES_ERROR_CODE 
withValue:[@(WX_ERR_JSBUNDLE_STRING_CONVERT) stringValue]];
             return;
         }
         if (!strongSelf.userInfo) {
             strongSelf.userInfo = [NSMutableDictionary new];
         }
-        strongSelf.userInfo[@"jsMainBundleStringContentLength"] = 
@([jsBundleString length]);
+        
+        NSUInteger bundleSize = [jsBundleString length];
+        [strongSelf.apmInstance updateDiffStats:KEY_PAGE_STATS_BUNDLE_SIZE 
withDiffValue:bundleSize];
+        
+        strongSelf.userInfo[@"jsMainBundleStringContentLength"] = 
@(bundleSize);
         strongSelf.userInfo[@"jsMainBundleStringContentMd5"] = [WXUtility 
md5:jsBundleString];
 
         WX_MONITOR_SUCCESS_ON_PAGE(WXMTJSDownload, strongSelf.pageName);
@@ -442,13 +455,16 @@ - (void)_renderWithRequest:(WXResourceRequest *)request 
options:(NSDictionary *)
     };
     
     _mainBundleLoader.onFailed = ^(NSError *loadError) {
+        [weakSelf.apmInstance onStage:KEY_PAGE_STAGES_DOWN_BUNDLE_END];
         NSString *errorMessage = [NSString stringWithFormat:@"Request to %@ 
occurs an error:%@", request.URL, loadError.localizedDescription];
-        
-        WX_MONITOR_FAIL_ON_PAGE(WXMTJSDownload, [loadError.domain 
isEqualToString:NSURLErrorDomain] && loadError.code == 
NSURLErrorNotConnectedToInternet ? WX_ERR_NOT_CONNECTED_TO_INTERNET : 
WX_ERR_JSBUNDLE_DOWNLOAD, errorMessage, weakSelf.pageName);
+        long wxErrorCode = [loadError.domain isEqualToString:NSURLErrorDomain] 
&& loadError.code == NSURLErrorNotConnectedToInternet ? 
WX_ERR_NOT_CONNECTED_TO_INTERNET : WX_ERR_JSBUNDLE_DOWNLOAD;
+
+        WX_MONITOR_FAIL_ON_PAGE(WXMTJSDownload, wxErrorCode, errorMessage, 
weakSelf.pageName);
         
         if (weakSelf.onFailed) {
             weakSelf.onFailed(error);
         }
+        [weakSelf.apmInstance setProperty:KEY_PROPERTIES_ERROR_CODE 
withValue:[@(wxErrorCode) stringValue]];
     };
     
     [_mainBundleLoader start];
@@ -481,6 +497,7 @@ - (void)refreshInstance:(id)data
 
 - (void)destroyInstance
 {
+    [self.apmInstance endRecord];
     NSString *url = @"";
     if([WXPrerenderManager isTaskExist:[self.scriptURL absoluteString]]) {
         url = [self.scriptURL absoluteString];
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_performance.h 
b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_performance.h
index 855997b958..c696fe7d8d 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_performance.h
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance_performance.h
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+//Deprecated, use @WXApmForInstance
+
 #import "WXSDKInstance.h"
 #import "WXImageComponent.h"
 
@@ -71,6 +73,7 @@
 @interface WXSDKInstance ()
 
 @property (nonatomic, assign) BOOL isJSCreateFinish;
+//Deprecated, use @WXApmForInstance
 @property (nonatomic,strong) WXPerformance* performance;
 
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m 
b/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m
index 0827b63bfc..be156baf3c 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXTimerModule.m
@@ -57,6 +57,19 @@ - (void)trigger
     [[WXSDKManager bridgeMgr] callBack:_weexInstance.instanceId 
funcId:_callbackID params:nil keepAlive:_shouldRepeat];
 }
 
++ (void) checkExcuteInBack:(NSString*) instanceId
+{
+    //todo,if instance is nil or instance has detroy ,can't record timer in 
back.....
+    WXSDKInstance* instance = [WXSDKManager instanceForID:instanceId];
+    if (nil == instance) {
+        return;
+    }
+    if (instance.state == WeexInstanceBackground || instance.state == 
WeexInstanceDisappear
+        || instance.state == WeexInstanceDestroy) {
+        [instance.apmInstance updateDiffStats:KEY_PAGE_TIMER_BACK_NUM 
withDiffValue:1];
+    }
+}
+
 @end
 
 @implementation WXTimerModule
diff --git a/ios/sdk/WeexSDK/Sources/Monitor/WXMonitor.h 
b/ios/sdk/WeexSDK/Sources/Monitor/WXMonitor.h
index c50d40d92f..395535d513 100644
--- a/ios/sdk/WeexSDK/Sources/Monitor/WXMonitor.h
+++ b/ios/sdk/WeexSDK/Sources/Monitor/WXMonitor.h
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+
 #import <Foundation/Foundation.h>
 #import "WXDefine.h"
 #import "WXSDKError.h"
@@ -95,6 +96,7 @@ NSError *error = [NSError errorWithDomain:WX_ERROR_DOMAIN \
 #define WX_MONITOR_INSTANCE_PERF_IS_RECORDED(tag, instance) [WXMonitor 
performancePoint:tag isRecordedWithInstance:instance]
 #define WX_MONITOR_INSTANCE_PERF_COMMIT(instance) [WXMonitor 
performanceFinish:instance]
 
+//DEPRECATED_ATTRIBUTE
 @interface WXMonitor : NSObject
 
 + (void)performancePoint:(WXPerformanceTag)tag 
willStartWithInstance:(WXSDKInstance *)instance;
diff --git a/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h 
b/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h
new file mode 100644
index 0000000000..466079be22
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Performance/WXApmForInstance.h
@@ -0,0 +1,103 @@
+#import <Foundation/Foundation.h>
+
+#pragma mark - const static string
+
+extern NSString* const WEEX_PAGE_TOPIC;
+
+/************** properties *****************/
+extern NSString* const KEY_PROPERTIES_ERROR_CODE;
+extern NSString* const KEY_PAGE_PROPERTIES_LAUNCH_ID;
+extern NSString* const KEY_PAGE_PROPERTIES_BIZ_ID;
+extern NSString* const KEY_PAGE_PROPERTIES_JSLIB_VERSION;
+extern NSString* const KEY_PAGE_PROPERTIES_WEEX_VERSION;
+extern NSString* const KEY_PAGE_PROPERTIES_REQUEST_TYPE;
+extern NSString* const KEY_PAGE_PROPERTIES_REQUEST_TYPE;
+extern NSString* const KEY_PAGE_PROPERTIES_NET_TYPE;
+extern NSString* const KEY_PAGE_PROPERTIES_CACHE_TYPE;
+extern NSString* const KEY_PAGE_PROPERTIES_USE_MULTI_CONTEXT;
+extern NSString* const KEY_PAGE_PROPERTIES_BUNDLE_TYPE;
+
+///************** stages *****************/
+extern NSString* const KEY_PAGE_STAGES_START;
+extern NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_START;
+extern NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_END;
+extern NSString* const KEY_PAGE_STAGES_RENDER_ORGIGIN;
+extern NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_START;
+extern NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_END;
+extern NSString* const KEY_PAGE_STAGES_FSRENDER;
+extern NSString* const KEY_PAGE_STAGES_INTERACTION;
+extern NSString* const KEY_PAGE_STAGES_DESTROY;
+
+///************** stats *****************/
+extern NSString* const KEY_PAGE_STATS_BUNDLE_SIZE;
+extern NSString* const KEY_PAGE_STATS_FS_CALL_JS_TIME;
+extern NSString* const KEY_PAGE_STATS_FS_CALL_JS_NUM;
+extern NSString* const KEY_PAGE_STATS_FS_TIMER_NUM;
+extern NSString* const KEY_PAGE_STATS_FS_CALL_NATIVE_TIME;
+extern NSString* const KEY_PAGE_STATS_FS_CALL_NATIVE_NUM;
+extern NSString* const KEY_PAGE_STATS_FS_CALL_EVENT_NUM;
+extern NSString* const KEY_PAGE_STATS_FS_REQUEST_NUM;
+
+extern NSString* const KEY_PAGE_STATS_SCROLLER_NUM;
+extern NSString* const KEY_PAGE_STATS_CELL_EXCEED_NUM;
+extern NSString* const KEY_PAGE_STATS_CELL_UN_RE_USE_NUM;
+extern NSString* const KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM;
+
+extern NSString* const KEY_PAGE_STATS_MAX_DEEP_VIEW;
+extern NSString* const KEY_PAGE_STATS_MAX_DEEP_DOM;
+extern NSString* const KEY_PAGE_STATS_MAX_COMPONENT_NUM;
+extern NSString* const KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT;
+extern NSString* const KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM;
+
+extern NSString* const KEY_PAGE_STATS_I_SCREEN_VIEW_COUNT;
+extern NSString* const KEY_PAGE_STATS_I_ALL_VIEW_COUNT;
+
+extern NSString* const KEY_PAGE_STATS_I_COMPONENT_CREATE_COUNT;
+extern NSString* const KEY_PAGE_ANIM_BACK_NUM;
+extern NSString* const KEY_PAGE_TIMER_BACK_NUM;
+extern NSString* const KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME;
+
+extern NSString* const KEY_PAGE_STATS_IMG_LOAD_NUM;
+extern NSString* const KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM;
+extern NSString* const KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM;
+extern NSString* const KEY_PAGE_STATS_NET_NUM;
+extern NSString* const KEY_PAGE_STATS_NET_SUCCESS_NUM;
+extern NSString* const KEY_PAGE_STATS_NET_FAIL_NUM;
+
+///************** value *****************/
+extern NSString* const VALUE_ERROR_CODE_DEFAULT;
+
+
+
+@interface WXApmForInstance : NSObject
+
+@property (nonatomic, assign) bool isFSEnd;
+
+#pragma mark - basic method
+
+- (void) onEvent:(NSString *)name withValue:(id)value;
+- (void) onStage:(NSString *)name;
+- (void) setProperty:(NSString *)name withValue:(id)value;
+- (void) setStatistic:(NSString *)name withValue:(double)value;
+
+#pragma mark - instance record 
+
+- (void) startRecord:(NSString*) instanceId;
+- (void) endRecord;
+- (void) arriveFSRenderTime;
+- (void) updateFSDiffStats:(NSString *)name withDiffValue:(double)diff;
+- (void) updateDiffStats:(NSString *)name withDiffValue:(double)diff;
+- (void) updateMaxStats:(NSString *)name curMaxValue:(double)maxValue;
+- (void) updateExtInfo:(NSDictionary*) extInfo;
+
+
+#pragma mark - called by IWXHttpAdapter implementer
+
+- (void) actionNetRequest;
+- (void) actionNetRequestResult:(bool)succeed 
withErrorCode:(NSString*)errorCode;
+
+#pragma mark - called by IWXImgLoaderAdapter implementer
+- (void) actionImgLoad;
+- (void) actionImgLoadResult:(bool)succeed withErrorCode:(NSString*)errorCode;
+
+@end
diff --git a/ios/sdk/WeexSDK/Sources/Performance/WXInstanceApm.m 
b/ios/sdk/WeexSDK/Sources/Performance/WXInstanceApm.m
new file mode 100644
index 0000000000..ab3e914e03
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Performance/WXInstanceApm.m
@@ -0,0 +1,289 @@
+#import "WXApmForInstance.h"
+#import "WXApmProtocol.h"
+#import "WXHandlerFactory.h"
+#import "WXSDKManager.h"
+#import "WXAppConfiguration.h"
+#import "WXUtility.h"
+
+
+#pragma mark - const static string
+
+NSString* const WEEX_PAGE_TOPIC = @"weex_page";
+
+/************** properties *****************/
+NSString* const KEY_PROPERTIES_ERROR_CODE = @"wxErrorCode";
+NSString* const KEY_PAGE_PROPERTIES_LAUNCH_ID = @"wxLaunchId";
+NSString* const KEY_PAGE_PROPERTIES_BIZ_ID = @"wxBizID";
+NSString* const KEY_PAGE_PROPERTIES_JSLIB_VERSION  = @"wxJSLibVersion";
+NSString* const KEY_PAGE_PROPERTIES_WEEX_VERSION  = @"wxSDKVersion";
+NSString* const KEY_PAGE_PROPERTIES_REQUEST_TYPE  = @"wxRequestType";
+NSString* const KEY_PAGE_PROPERTIES_NET_TYPE  = @"wxNetType";
+NSString* const KEY_PAGE_PROPERTIES_CACHE_TYPE  = @"wxCacheType";
+NSString* const KEY_PAGE_PROPERTIES_USE_MULTI_CONTEXT  = @"wxUseMultiContext";
+NSString* const KEY_PAGE_PROPERTIES_BUNDLE_TYPE = @"wxBundleType";
+
+///************** stages *****************/
+NSString* const KEY_PAGE_STAGES_START = @"wxRecordStart";
+NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_START  = @"wxStartDownLoadBundle";
+NSString* const KEY_PAGE_STAGES_DOWN_BUNDLE_END  = @"wxEndDownLoadBundle";
+NSString* const KEY_PAGE_STAGES_RENDER_ORGIGIN  = @"wxRenderTimeOrigin";
+NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_START  = @"wxStartLoadBundle";
+NSString* const KEY_PAGE_STAGES_LOAD_BUNDLE_END  = @"wxEndLoadBundle";
+NSString* const KEY_PAGE_STAGES_FSRENDER  = @"wxFsRender";
+NSString* const KEY_PAGE_STAGES_INTERACTION  = @"wxInteraction";
+NSString* const KEY_PAGE_STAGES_DESTROY  = @"wxDestroy";
+
+///************** stats *****************/
+NSString* const KEY_PAGE_STATS_BUNDLE_SIZE  = @"wxBundleSize";
+NSString* const KEY_PAGE_STATS_FS_CALL_JS_TIME  = @"wxFSCallJsTotalTime";
+NSString* const KEY_PAGE_STATS_FS_CALL_JS_NUM  = @"wxFSCallJsTotalNum";
+NSString* const KEY_PAGE_STATS_FS_TIMER_NUM = @"wxFSTimerCount";
+NSString* const KEY_PAGE_STATS_FS_CALL_NATIVE_TIME = 
@"wxFSCallNativeTotalTime";
+NSString* const KEY_PAGE_STATS_FS_CALL_NATIVE_NUM = @"wxFSCallNativeTotalNum";
+NSString* const KEY_PAGE_STATS_FS_CALL_EVENT_NUM = @"wxFSCallEventTotalNum";
+NSString* const KEY_PAGE_STATS_FS_REQUEST_NUM = @"wxFSRequestNum";
+
+NSString* const KEY_PAGE_STATS_SCROLLER_NUM = @"wxScrollerCount";
+NSString* const KEY_PAGE_STATS_CELL_EXCEED_NUM = @"wxCellExceedNum";
+NSString* const KEY_PAGE_STATS_CELL_UN_RE_USE_NUM = @"wxCellUnReUseCount";
+NSString* const KEY_PAGE_STATS_CELL_DATA_UN_RECYCLE_NUM = 
@"wxCellDataUnRecycleCount";
+
+NSString* const KEY_PAGE_STATS_MAX_DEEP_VIEW = @"wxMaxDeepViewLayer";
+NSString* const KEY_PAGE_STATS_MAX_DEEP_DOM = @"wxMaxDeepVDomLayer";
+NSString* const KEY_PAGE_STATS_MAX_COMPONENT_NUM = @"wxMaxComponentCount";
+NSString* const KEY_PAGE_STATS_WRONG_IMG_SIZE_COUNT = @"wxWrongImgSizeCount";
+NSString* const KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM = @"wxImgUnRecycleCount";
+
+NSString* const KEY_PAGE_STATS_I_SCREEN_VIEW_COUNT = 
@"wxInteractionScreenViewCount";
+NSString* const KEY_PAGE_STATS_I_ALL_VIEW_COUNT = @"wxInteractionAllViewCount";
+
+NSString* const KEY_PAGE_STATS_I_COMPONENT_CREATE_COUNT = 
@"wxInteractionComponentCreateCount";
+NSString* const KEY_PAGE_ANIM_BACK_NUM = @"wxAnimationInBackCount";
+NSString* const KEY_PAGE_TIMER_BACK_NUM = @"wxTimerInBackCount";
+NSString* const KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME = @"wxActualNetworkTime";
+
+NSString* const KEY_PAGE_STATS_IMG_LOAD_NUM = @"wxImgLoadCount";
+NSString* const KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM = @"wxImgLoadSuccessCount";
+NSString* const KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM = @"wxImgLoadFailCount";
+NSString* const KEY_PAGE_STATS_NET_NUM  = @"wxNetworkRequestCount";
+NSString* const KEY_PAGE_STATS_NET_SUCCESS_NUM = 
@"wxNetworkRequestSuccessCount";
+NSString* const KEY_PAGE_STATS_NET_FAIL_NUM = @"wxNetworkRequestFailCount";
+
+///************** value *****************/
+NSString* const VALUE_ERROR_CODE_DEFAULT = @"0";
+
+@interface WXApmForInstance ()
+@property (nonatomic,strong) id<WXApmProtocol> apmProtocolInstance;
+@property (nonatomic,strong) NSString* instanceId;
+@property (nonatomic,strong) NSMutableDictionary<NSString*,NSNumber*>* 
recordStatsMap;
+@end
+
+@implementation WXApmForInstance
+
+
+- (instancetype) init
+{
+    self = [super init];
+    if (self) {
+        id<WXApmGeneratorProtocol> generater = [WXHandlerFactory 
handlerForProtocol:@protocol(WXApmGeneratorProtocol)];
+        _apmProtocolInstance = [generater 
gengratorApmInstance:WEEX_PAGE_TOPIC];
+        _recordStatsMap = [[NSMutableDictionary alloc] init];
+    }
+    return self;
+}
+
+- (void) onEvent:(NSString *)name withValue:(id)value
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    [self.apmProtocolInstance onEvent:name withValue:value];
+}
+
+- (void) onStage:(NSString *)name
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    [self.apmProtocolInstance onStage:name withValue:[WXUtility 
getUnixCurrentTimeMillis]];
+}
+
+- (void) setProperty:(NSString *)name withValue:(id)value
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    [self.apmProtocolInstance addProperty:name withValue:value];
+}
+
+- (void) setStatistic:(NSString *)name withValue:(double)value
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    [self.apmProtocolInstance addStatistic:name withValue:value];
+}
+
+#pragma mark - instance record
+
+- (void) startRecord:(NSString*) instanceId
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    _instanceId = instanceId;
+    
+    [self.apmProtocolInstance onStart:instanceId topic:WEEX_PAGE_TOPIC];
+    [self onStage:KEY_PAGE_STAGES_START];
+    WXSDKInstance* instance = [WXSDKManager instanceForID:instanceId];
+    if (nil != instance) {
+        for (NSString* key in instance.continerInfo) {
+            id value = [instance.continerInfo objectForKey:key];
+            [self setProperty:key withValue:value];
+        }
+    }
+    NSString* pageUrl = instance.scriptURL.absoluteString;
+    pageUrl = nil == pageUrl || [@"" 
isEqualToString:pageUrl]?@"unKnowUrl":pageUrl;
+    
+    [self setProperty:KEY_PAGE_PROPERTIES_BIZ_ID withValue:pageUrl];
+    [self setProperty:KEY_PROPERTIES_ERROR_CODE 
withValue:VALUE_ERROR_CODE_DEFAULT];
+    [self setProperty:KEY_PAGE_PROPERTIES_JSLIB_VERSION 
withValue:[WXAppConfiguration JSFrameworkVersion]];
+    [self setProperty:KEY_PAGE_PROPERTIES_WEEX_VERSION 
withValue:WX_SDK_VERSION];
+    
+    //for apm protocl
+    //iOS/Android we default recycle img when imgView disapper form screen
+    //but in Android ,js can switch recycle or not
+    [self updateDiffStats:KEY_PAGE_STATS_IMG_UN_RECYCLE_NUM withDiffValue:0];
+}
+
+- (void) endRecord;
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    
+    [self onStage:KEY_PAGE_STAGES_DESTROY];
+    [self.apmProtocolInstance onEnd];
+}
+
+- (void) arriveFSRenderTime
+{
+    if (nil == _apmProtocolInstance || self.isFSEnd) {
+        return;
+    }
+    self.isFSEnd = true;
+    [self onStage:KEY_PAGE_STAGES_FSRENDER];
+}
+
+- (void) updateFSDiffStats:(NSString *)name withDiffValue:(double)diff
+{
+    if (nil == _apmProtocolInstance || self.isFSEnd) {
+        return;
+    }
+    [self updateDiffStats:name withDiffValue:diff];
+}
+
+- (void) updateDiffStats:(NSString *)name withDiffValue:(double)diff
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    NSNumber* preNumber = [self.recordStatsMap objectForKey:name];
+    double preVal = nil == preNumber?0:preNumber.doubleValue;
+    double currentVal = preVal + diff;
+    [self.recordStatsMap setObject:@(currentVal) forKey:name];
+    [self setStatistic:name withValue:currentVal];
+}
+
+- (void) updateMaxStats:(NSString *)name curMaxValue:(double)currentValue
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    NSNumber* maxNumber = [self.recordStatsMap objectForKey:name];
+    double maxVal = nil == maxNumber?0:maxNumber.doubleValue;
+    
+    if (maxVal < currentValue) {
+        maxVal = currentValue;
+        [self.recordStatsMap setObject:@(maxVal) forKey:name];
+        [self setStatistic:name withValue:maxVal];
+    }
+}
+
+- (void) updateExtInfo:(NSDictionary*) extInfo
+{
+    if (nil == _apmProtocolInstance || nil == extInfo) {
+        return;
+    }
+    
+    id wxRequestType = [extInfo objectForKey:KEY_PAGE_PROPERTIES_REQUEST_TYPE];
+    if (nil != wxRequestType && [wxRequestType isKindOfClass: NSString.class]) 
{
+        [self setProperty:KEY_PAGE_PROPERTIES_REQUEST_TYPE 
withValue:wxRequestType];
+    }
+    
+    id wxNetType = [extInfo objectForKey:KEY_PAGE_PROPERTIES_NET_TYPE];
+    if (nil != wxRequestType && [wxNetType isKindOfClass: NSString.class]) {
+        [self setProperty:KEY_PAGE_PROPERTIES_NET_TYPE 
withValue:wxRequestType];
+    }
+    
+    id wxCacheType = [extInfo objectForKey:KEY_PAGE_PROPERTIES_CACHE_TYPE];
+    if (nil != wxCacheType && [wxCacheType isKindOfClass: NSString.class]) {
+        [self setProperty:KEY_PAGE_PROPERTIES_CACHE_TYPE 
withValue:wxCacheType];
+    }
+
+    id wxNetLibDownBundleTime = [extInfo 
objectForKey:KEY_PAGE_STATS_ACTUAL_DOWNLOAD_TIME];
+    if (nil != wxNetLibDownBundleTime && [wxNetLibDownBundleTime 
isKindOfClass: NSNumber.class]) {
+        double value = ((NSNumber *)wxNetLibDownBundleTime).doubleValue;
+        [self  setStatistic:KEY_PAGE_PROPERTIES_CACHE_TYPE withValue:value];
+    }
+}
+
+#pragma mark - called by IWXHttpAdapter implementer
+
+- (void) actionNetRequest
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    if (!self.isFSEnd) {
+        [self updateFSDiffStats:KEY_PAGE_STATS_FS_REQUEST_NUM withDiffValue:1];
+    }
+    [self updateDiffStats:KEY_PAGE_STATS_NET_NUM withDiffValue:1];
+}
+
+- (void) actionNetRequestResult:(bool)succeed 
withErrorCode:(NSString*)errorCode
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    if (succeed) {
+        [self updateDiffStats:KEY_PAGE_STATS_NET_SUCCESS_NUM withDiffValue:1];
+    } else {
+        [self updateDiffStats:KEY_PAGE_STATS_NET_FAIL_NUM withDiffValue:1];
+    }
+}
+
+#pragma mark - called by IWXImgLoaderAdapter implementer
+
+- (void) actionImgLoad
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    [self updateDiffStats:KEY_PAGE_STATS_IMG_LOAD_NUM withDiffValue:1];
+}
+
+- (void) actionImgLoadResult:(bool)succeed withErrorCode:(NSString*)errorCode
+{
+    if (nil == _apmProtocolInstance) {
+        return;
+    }
+    if (succeed) {
+        [self updateDiffStats:KEY_PAGE_STATS_IMG_LOAD_SUCCESS_NUM 
withDiffValue:1];
+    } else {
+        [self updateDiffStats:KEY_PAGE_STATS_IMG_LOAD_FAIL_NUM 
withDiffValue:1];
+    }
+}
+
+@end
+
diff --git a/ios/sdk/WeexSDK/Sources/Protocol/WXApmProtocol.h 
b/ios/sdk/WeexSDK/Sources/Protocol/WXApmProtocol.h
new file mode 100644
index 0000000000..a461edbc9f
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Protocol/WXApmProtocol.h
@@ -0,0 +1,85 @@
+
+#import <Foundation/Foundation.h>
+#import "WXAppMonitorProtocol.h"
+
+
+@protocol WXApmProtocol <NSObject>
+
+/**
+ * start record
+ *
+ * @param instanceId instanceId
+ */
+@required
+- (void) onStart:(NSString*)instanceId topic:(NSString*)topic;
+
+/**
+ * pause apm record (apm ext mem / fps)
+ */
+@required
+- (void) pauseApmRecord;
+
+/**
+ * resume apm record (apm ext mem / fps)
+ */
+@required
+- (void) resumeApmRecord;
+
+/**
+ * end record
+ */
+@required
+- (void) onEnd;
+
+/**
+ * record event
+ */
+@required
+- (void) onEvent:(NSString *)name withValue:(id)value;   
+
+/**
+ * record stage
+ */
+@required
+- (void) onStage:(NSString *)name withValue:(long)timestamp;
+
+/**
+ * record property
+ */
+@required
+- (void) addProperty:(NSString *)name withValue:(id)value;
+
+/**
+ * record statistic
+ */
+@required
+- (void) addStatistic:(NSString *)name withValue:(double)value;
+
+@required
+- (void) onSubProcedureBegin:(NSString*)subProcedureName;
+
+@required
+- (void) onSubProcedureEndSucceed:(NSString*)subProcedureName;
+
+@required
+- (void) onSubProcedureEndFailed:(NSString*)subProcedureName;
+
+/**
+ * record biz properties
+ */
+@required
+- (void) addBiz:(NSString *)bizID withValue:(NSDictionary *)properties;
+
+/**
+ * record biz stage
+ */
+@required
+- (void) addBizStage:(NSString *)bizID withValue:(NSDictionary *)stage;
+
+@end
+
+@protocol WXApmGeneratorProtocol <NSObject>
+
+@required
+- (id<WXApmProtocol>)gengratorApmInstance:(NSString *) type;
+@end
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h 
b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
index 9babd18338..a7a7abf5dd 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
@@ -493,4 +493,6 @@ BOOL WXFloatGreaterThanWithPrecision(CGFloat a,CGFloat 
b,double precision);
 
 + (BOOL)listSectionRowThreadSafe;
 
++ (long) getUnixCurrentTimeMillis;
+
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m 
b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
index d9f543384b..e063395844 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
@@ -969,6 +969,12 @@ + (NSData *_Nonnull)base64DictToData:(NSDictionary 
*_Nullable)base64Dict
     }
     return nil;
 }
+
++ (long) getUnixCurrentTimeMillis
+{
+    return [[NSDate date] timeIntervalSince1970] * 1000;
+}
+
 @end
 
 
diff --git a/ios/sdk/WeexSDK/Sources/WeexSDK.h 
b/ios/sdk/WeexSDK/Sources/WeexSDK.h
index 5c03635a1f..fa1648b6ca 100644
--- a/ios/sdk/WeexSDK/Sources/WeexSDK.h
+++ b/ios/sdk/WeexSDK/Sources/WeexSDK.h
@@ -72,6 +72,8 @@
 #import "WXBaseViewController.h"
 #import "WXAppMonitorProtocol.h"
 #import "WXAppConfiguration.h"
+#import "WXApmProtocol.h"
+#import "WXApmForInstance.h"
 #import "WXAnalyzerProtocol.h"
 #import "WXAnalyzerCenter.h"
 #import "WXAComponent.h"


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to