You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by mi...@apache.org on 2017/08/15 09:51:31 UTC

[06/16] incubator-weex git commit: + [android] batch modification for tracing @notdanger

+ [android] batch modification for tracing @notdanger


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/102f2ed0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/102f2ed0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/102f2ed0

Branch: refs/heads/0.16-dev
Commit: 102f2ed0db66226aff309215acbd94472b77390b
Parents: e2d8a7b
Author: misakuo <mi...@apache.org>
Authored: Thu Aug 10 14:35:54 2017 +0800
Committer: misakuo <mi...@apache.org>
Committed: Thu Aug 10 14:35:54 2017 +0800

----------------------------------------------------------------------
 .../com/alibaba/weex/PerformanceActivity.java   | 121 --------------
 .../java/com/taobao/weex/WXSDKInstance.java     |  37 ++++-
 .../main/java/com/taobao/weex/WXSDKManager.java |   9 ++
 .../taobao/weex/adapter/ITracingAdapter.java    |  31 ++++
 .../com/taobao/weex/bridge/WXBridgeManager.java |  66 +++++++-
 .../java/com/taobao/weex/common/WXTracing.java  |  76 ---------
 .../taobao/weex/dom/DOMActionContextImpl.java   |  23 +--
 .../com/taobao/weex/dom/RenderActionTask.java   |  26 +++-
 .../java/com/taobao/weex/dom/WXDomHandler.java  |  15 +-
 .../java/com/taobao/weex/dom/WXDomManager.java  |  16 +-
 .../java/com/taobao/weex/dom/WXDomModule.java   |  37 ++++-
 .../java/com/taobao/weex/dom/WXDomObject.java   |   9 ++
 .../dom/action/AbstractAddElementAction.java    |  28 +++-
 .../dom/action/AbstractLayoutFinishAction.java  |   3 +-
 .../weex/dom/action/AddElementAction.java       |  30 +++-
 .../taobao/weex/dom/action/AddEventAction.java  |  27 +++-
 .../weex/dom/action/CreateBodyAction.java       |  19 +++
 .../weex/dom/action/CreateFinishAction.java     |   6 +
 .../weex/dom/action/RefreshFinishAction.java    |   4 +
 .../taobao/weex/dom/action/TraceableAction.java |  82 ++++++++++
 .../weex/dom/action/UpdateAttributeAction.java  |   2 +-
 .../weex/dom/action/UpdateStyleAction.java      |   2 +-
 .../java/com/taobao/weex/tracing/Stopwatch.java | 132 ++++++++++++++++
 .../java/com/taobao/weex/tracing/WXTracing.java | 156 +++++++++++++++++++
 .../com/taobao/weex/ui/WXRenderManager.java     |  32 +++-
 .../taobao/weex/ui/component/WXComponent.java   |  58 +++++--
 .../taobao/weex/ui/component/WXVContainer.java  |  18 +++
 .../ui/component/list/BasicListComponent.java   |   2 +-
 .../java/com/taobao/weex/utils/WXLogUtils.java  |  45 +++---
 .../com/taobao/weex/utils/WXLogUtilsTest.java   |   1 -
 30 files changed, 826 insertions(+), 287 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/playground/app/src/main/java/com/alibaba/weex/PerformanceActivity.java
----------------------------------------------------------------------
diff --git a/android/playground/app/src/main/java/com/alibaba/weex/PerformanceActivity.java b/android/playground/app/src/main/java/com/alibaba/weex/PerformanceActivity.java
deleted file mode 100644
index ad88546..0000000
--- a/android/playground/app/src/main/java/com/alibaba/weex/PerformanceActivity.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.alibaba.weex;
-
-
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.alibaba.weex.performance.EnvironmentFragment;
-import com.alibaba.weex.performance.EventOverviewFragment;
-
-public class PerformanceActivity extends WXBaseActivity {
-
-  private LinearLayout segmentHost;
-
-  public static void start(Context context, int instanceId) {
-    Intent intent = new Intent(context, PerformanceActivity.class);
-    intent.putExtra("instanceId", instanceId);
-    context.startActivity(intent);
-  }
-
-  @Override
-  protected void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    setContentView(R.layout.activity_performance);
-    segmentHost = (LinearLayout) findViewById(R.id.segment_control);
-    addTab("页面性能", true, new View.OnClickListener() {
-      @Override
-      public void onClick(View v) {
-        switchFragment(EventOverviewFragment.getInstance(getIntent().getIntExtra("instanceId", -1)));
-      }
-    });
-
-    addTab("DOM树", false, new View.OnClickListener() {
-      @Override
-      public void onClick(View v) {
-
-      }
-    });
-
-    addTab("JS LOG", false, new View.OnClickListener() {
-      @Override
-      public void onClick(View v) {
-
-      }
-    });
-
-    addTab("环境变量", false, new View.OnClickListener() {
-      @Override
-      public void onClick(View v) {
-        switchFragment(new EnvironmentFragment());
-      }
-    });
-  }
-
-  private void switchFragment(Fragment fragment) {
-    getSupportFragmentManager()
-        .beginTransaction()
-        .replace(R.id.fragment_container, fragment)
-        .commitAllowingStateLoss();
-  }
-
-  @Override
-  protected void onResumeFragments() {
-    super.onResumeFragments();
-    FragmentManager fragmentManager = getSupportFragmentManager();
-
-    Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);
-    if (fragment == null) {
-      fragmentManager
-          .beginTransaction()
-          .add(R.id.fragment_container, EventOverviewFragment.getInstance(getIntent().getIntExtra("instanceId", -1)))
-          .commitAllowingStateLoss();
-    }
-  }
-
-  private void addTab(String title, final boolean selected, final View.OnClickListener listener) {
-    final TextView textView = new TextView(this);
-    textView.setText(title);
-    LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-    lp.weight = 1;
-    lp.setMargins(1, 1, 1, 1);
-    if (selected) {
-      textView.setBackgroundColor(Color.TRANSPARENT);
-    } else {
-      textView.setBackgroundColor(Color.WHITE);
-    }
-    textView.setGravity(Gravity.CENTER);
-    textView.setLayoutParams(lp);
-    textView.setOnClickListener(new View.OnClickListener() {
-      @Override
-      public void onClick(View v) {
-        if (!v.isSelected() && v instanceof TextView) {
-          listener.onClick(v);
-          for (int i = 0; i < segmentHost.getChildCount(); i++) {
-            segmentHost.getChildAt(i).setSelected(false);
-            segmentHost.getChildAt(i).setBackgroundColor(Color.WHITE);
-            ((TextView) segmentHost.getChildAt(i)).setTextColor(Color.parseColor("#1E90FF"));
-          }
-          v.setSelected(true);
-          v.setBackgroundColor(Color.TRANSPARENT);
-          ((TextView) v).setTextColor(Color.WHITE);
-        }
-      }
-    });
-    textView.setSelected(selected);
-    if (selected) {
-      textView.setTextColor(Color.WHITE);
-    } else {
-      textView.setTextColor(Color.parseColor("#1E90FF"));
-    }
-    segmentHost.addView(textView);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
index a8d8a60..d806148 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
@@ -61,6 +61,7 @@ import com.taobao.weex.dom.WXDomObject;
 import com.taobao.weex.dom.WXDomTask;
 import com.taobao.weex.dom.WXEvent;
 import com.taobao.weex.http.WXHttpUtil;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.component.NestedContainer;
 import com.taobao.weex.ui.component.WXBasicComponentType;
 import com.taobao.weex.ui.component.WXComponent;
@@ -116,6 +117,9 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
   private static volatile int mViewPortWidth = 750;
   private int mInstanceViewPortWidth = 750;
 
+  public long mRenderStartNanos;
+  public int mExecJSTraceId = WXTracing.nextId();
+
   /**
    * Render strategy.
    */
@@ -415,6 +419,16 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
       return;
     }
 
+    if (WXTracing.isAvailable()) {
+      WXTracing.TraceEvent traceEvent = WXTracing.newEvent("executeBundleJS", mInstanceId, -1);
+      traceEvent.traceId = mExecJSTraceId;
+      traceEvent.iid = mInstanceId;
+      traceEvent.tname = "JSThread";
+      traceEvent.ph = "B";
+      traceEvent.submit();
+      mRenderStartNanos = System.nanoTime();
+    }
+
     ensureRenderArchor();
 
     Map<String, Object> renderOptions = options;
@@ -429,7 +443,7 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
     }
 
     mWXPerformance.pageName = pageName;
-    mWXPerformance.JSTemplateSize = template.length() / 1024;
+    mWXPerformance.JSTemplateSize = template.length() / 1024f;
 
     mRenderStartTime = System.currentTimeMillis();
     mRenderStrategy = flag;
@@ -1480,6 +1494,7 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
     private WXRenderStrategy flag;
     private WXSDKInstance instance;
     private long startRequestTime;
+    private int traceId;
 
     private WXHttpListener(String pageName, Map<String, Object> options, String jsonInitData, WXRenderStrategy flag, long startRequestTime) {
       this.pageName = pageName;
@@ -1487,6 +1502,16 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
       this.jsonInitData = jsonInitData;
       this.flag = flag;
       this.startRequestTime = startRequestTime;
+      this.traceId = WXTracing.nextId();
+
+      if (WXTracing.isAvailable()) {
+        WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", mInstanceId, -1);
+        event.iid = mInstanceId;
+        event.tname = "Network";
+        event.ph = "B";
+        event.traceId = traceId;
+        event.submit();
+      }
     }
     
     public void setSDKInstance(WXSDKInstance instance) {
@@ -1526,6 +1551,16 @@ public class WXSDKInstance implements IWXActivityStateListener,DomContext, View.
         this.instance.getWXStatisticsListener().onHttpFinish();
       }
 
+      if (WXTracing.isAvailable()) {
+        WXTracing.TraceEvent event = WXTracing.newEvent("downloadBundleJS", mInstanceId, -1);
+        event.traceId = traceId;
+        event.tname = "Network";
+        event.ph = "E";
+        event.extParams = new HashMap<>();
+        event.extParams.put("BundleSize", response.originalData.length);
+        event.submit();
+      }
+
       mWXPerformance.networkTime = System.currentTimeMillis() - startRequestTime;
       if(response.extendParams!=null){
         Object actualNetworkTime=response.extendParams.get("actualNetworkTime");

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
index 0b43fa6..84e5fa8 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKManager.java
@@ -27,6 +27,7 @@ import com.taobao.weex.adapter.DefaultUriAdapter;
 import com.taobao.weex.adapter.DefaultWXHttpAdapter;
 import com.taobao.weex.adapter.ICrashInfoReporter;
 import com.taobao.weex.adapter.IDrawableLoader;
+import com.taobao.weex.adapter.ITracingAdapter;
 import com.taobao.weex.adapter.IWXDebugAdapter;
 import com.taobao.weex.adapter.IWXHttpAdapter;
 import com.taobao.weex.adapter.IWXImgLoaderAdapter;
@@ -83,6 +84,7 @@ public class WXSDKManager {
   private IWXStatisticsListener mStatisticsListener;
   private URIAdapter mURIAdapter;
   private IWebSocketAdapterFactory mIWebSocketAdapterFactory;
+  private ITracingAdapter mTracingAdapter;
   private WXValidateProcessor mWXValidateProcessor;
   // Tell weexv8 to initialize v8, default is true.
   private boolean mNeedInitV8 = true;
@@ -410,4 +412,11 @@ public class WXSDKManager {
     }
   }
 
+  public void setTracingAdapter(ITracingAdapter adapter) {
+    this.mTracingAdapter = adapter;
+  }
+
+  public ITracingAdapter getTracingAdapter() {
+    return mTracingAdapter;
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java b/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java
new file mode 100644
index 0000000..4acb23d
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/adapter/ITracingAdapter.java
@@ -0,0 +1,31 @@
+/**
+ * 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.
+ */
+package com.taobao.weex.adapter;
+
+import com.taobao.weex.tracing.WXTracing;
+
+/**
+ * Created by moxun on 2017/7/6.
+ */
+
+public interface ITracingAdapter {
+  void enable();
+  void disable();
+  void submitTracingEvent(WXTracing.TraceEvent event);
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
index 2e8e928..2d533ea 100644
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
@@ -51,6 +51,8 @@ import com.taobao.weex.dom.DOMAction;
 import com.taobao.weex.dom.WXDomModule;
 import com.taobao.weex.dom.action.Action;
 import com.taobao.weex.dom.action.Actions;
+import com.taobao.weex.dom.action.TraceableAction;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.utils.WXFileUtils;
 import com.taobao.weex.utils.WXJsonUtils;
 import com.taobao.weex.utils.WXLogUtils;
@@ -157,6 +159,8 @@ public class WXBridgeManager implements Callback,BactchExecutor {
 
   private Interceptor mInterceptor;
 
+  private WXParams mInitParams;
+
   private WXBridgeManager() {
     initWXBridge(WXEnvironment.sRemoteDebugMode);
     mJSThread = new WXThread("WeexJSBridgeThread", this);
@@ -394,7 +398,9 @@ public class WXBridgeManager implements Callback,BactchExecutor {
 
 
     long start = System.currentTimeMillis();
+    long parseNanos = System.nanoTime();
     JSONArray array = JSON.parseArray(tasks);
+    parseNanos = System.nanoTime() - parseNanos;
 
     if(WXSDKManager.getInstance().getSDKInstance(instanceId)!=null) {
       WXSDKManager.getInstance().getSDKInstance(instanceId).jsonParseTime(System.currentTimeMillis() - start);
@@ -411,7 +417,7 @@ public class WXBridgeManager implements Callback,BactchExecutor {
             if(target != null){
               if(WXDomModule.WXDOM.equals(target)){
                 WXDomModule dom = getDomModule(instanceId);
-                dom.callDomMethod(task);
+                dom.callDomMethod(task,parseNanos);
               }else {
                 callModuleMethod(instanceId, (String) target,
                     (String) task.get(METHOD), (JSONArray) task.get(ARGS));
@@ -463,10 +469,20 @@ public class WXBridgeManager implements Callback,BactchExecutor {
 
     try {
       if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
+        long start = System.currentTimeMillis();
+        long nanosTemp = System.nanoTime();
         JSONObject domObject = JSON.parseObject(tasks);
+        nanosTemp = System.nanoTime() - nanosTemp;
+
         WXDomModule domModule = getDomModule(instanceId);
         Action action = Actions.getCreateBody(domObject);
         domModule.postAction((DOMAction)action, true);
+
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).mParseJsonNanos = nanosTemp;
+          ((TraceableAction) action).mStartMillis = start;
+          ((TraceableAction) action).onStartDomExecute(instanceId, "createBody", "_root", domObject.getString("type"), tasks);
+        }
       }
     } catch (Exception e) {
         WXLogUtils.e("[WXBridgeManager] callCreateBody exception: ", e);
@@ -605,9 +621,19 @@ public class WXBridgeManager implements Callback,BactchExecutor {
     try {
       if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
         WXDomModule domModule = getDomModule(instanceId);
+        long start = System.currentTimeMillis();
+        long parseNanos = System.nanoTime();
         JSONObject domObject = JSON.parseObject(task);
+        parseNanos = System.nanoTime() - parseNanos;
+
         Action action = Actions.getUpdateAttrs(ref, domObject);
         domModule.postAction((DOMAction)action, false);
+
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).mStartMillis = start;
+          ((TraceableAction) action).mParseJsonNanos = parseNanos;
+          ((TraceableAction) action).onStartDomExecute(instanceId, "updateAttrs", domObject.getString("ref"), domObject.getString("type"), task);
+        }
       }
     } catch (Exception e) {
       WXLogUtils.e("[WXBridgeManager] callUpdateAttrs exception: ", e);
@@ -648,9 +674,19 @@ public class WXBridgeManager implements Callback,BactchExecutor {
     try {
       if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
         WXDomModule domModule = getDomModule(instanceId);
+        long start = System.currentTimeMillis();
+        long nanosTemp = System.nanoTime();
         JSONObject domObject = JSON.parseObject(task);
+        nanosTemp = System.nanoTime() - nanosTemp;
+
         Action action = Actions.getUpdateStyle(ref, domObject, false);
         domModule.postAction((DOMAction)action, false);
+
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).mParseJsonNanos = nanosTemp;
+          ((TraceableAction) action).mStartMillis = start;
+          ((TraceableAction) action).onStartDomExecute(instanceId, "updateStyle", ref, domObject.getString("type"), domObject.toJSONString());
+        }
       }
     } catch (Exception e) {
       WXLogUtils.e("[WXBridgeManager] callUpdateStyle exception: ", e);
@@ -684,6 +720,10 @@ public class WXBridgeManager implements Callback,BactchExecutor {
         WXDomModule domModule = getDomModule(instanceId);
         Action action = Actions.getRemoveElement(ref);
         domModule.postAction((DOMAction)action, false);
+
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).onStartDomExecute(instanceId, "removeElement", ref, null, ref);
+        }
       }
     } catch (Exception e) {
       WXLogUtils.e("[WXBridgeManager] callRemoveElement exception: ", e);
@@ -752,6 +792,10 @@ public class WXBridgeManager implements Callback,BactchExecutor {
         WXDomModule domModule = getDomModule(instanceId);
         Action action = Actions.getAddEvent(ref, event);
         domModule.postAction((DOMAction)action, false);
+
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).onStartDomExecute(instanceId, "addEvent", ref, null, event);
+        }
       }
     } catch (Exception e) {
       WXLogUtils.e("[WXBridgeManager] callAddEvent exception: ", e);
@@ -785,6 +829,10 @@ public class WXBridgeManager implements Callback,BactchExecutor {
         WXDomModule domModule = getDomModule(instanceId);
         Action action = Actions.getRemoveEvent(ref, event);
         domModule.postAction((DOMAction)action, false);
+
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).onStartDomExecute(instanceId, "removeEvent", ref, null, event);
+        }
       }
     } catch (Exception e) {
       WXLogUtils.e("[WXBridgeManager] callRemoveEvent exception: ", e);
@@ -815,13 +863,22 @@ public class WXBridgeManager implements Callback,BactchExecutor {
 
     if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
       long start = System.currentTimeMillis();
+      long nanosTemp = System.nanoTime();
       JSONObject domObject = JSON.parseObject(dom);
+      nanosTemp = System.nanoTime() - nanosTemp;
 
       if (WXSDKManager.getInstance().getSDKInstance(instanceId) != null) {
         WXSDKManager.getInstance().getSDKInstance(instanceId).jsonParseTime(System.currentTimeMillis() - start);
       }
       WXDomModule domModule = getDomModule(instanceId);
-      domModule.postAction(Actions.getAddElement(domObject, ref,Integer.parseInt(index)),false);
+      DOMAction addElementAction = Actions.getAddElement(domObject, ref,Integer.parseInt(index));
+      domModule.postAction(addElementAction, false);
+
+      if (WXTracing.isAvailable() && addElementAction instanceof TraceableAction) {
+        ((TraceableAction) addElementAction).mParseJsonNanos = nanosTemp;
+        ((TraceableAction) addElementAction).mStartMillis = start;
+        ((TraceableAction) addElementAction).onStartDomExecute(instanceId, "addElement", domObject.getString("ref"), domObject.getString("type"), dom);
+      }
     }
 
     if (UNDEFINED.equals(callback) || NON_CALLBACK.equals(callback)) {
@@ -1368,9 +1425,14 @@ public class WXBridgeManager implements Callback,BactchExecutor {
     wxParams.setDeviceHeight(TextUtils.isEmpty(config.get("deviceHeight")) ? String.valueOf(WXViewUtils.getScreenHeight(WXEnvironment.sApplication)) : config.get("deviceHeight"));
     wxParams.setOptions(WXEnvironment.getCustomOptions());
     wxParams.setNeedInitV8(WXSDKManager.getInstance().needInitV8());
+    mInitParams = wxParams;
     return wxParams;
   }
 
+  public WXParams getInitParams() {
+    return mInitParams;
+  }
+
   private void execRegisterFailTask() {
 
     if (mRegisterModuleFailList.size() > 0) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/common/WXTracing.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXTracing.java b/android/sdk/src/main/java/com/taobao/weex/common/WXTracing.java
deleted file mode 100644
index bc37386..0000000
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXTracing.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.taobao.weex.common;
-
-import android.os.Message;
-
-import com.taobao.weex.dom.WXDomHandler;
-import com.taobao.weex.dom.WXDomTask;
-import com.taobao.weex.dom.action.Action;
-import com.taobao.weex.utils.WXLogUtils;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Created by moxun on 2017/6/6.
- */
-
-public class WXTracing {
-    private static final AtomicInteger sIdGenerator = new AtomicInteger(0);
-
-    public static int nextId() {
-        return sIdGenerator.getAndIncrement();
-    }
-
-    public static void submit(TraceEvent event) {
-        WXLogUtils.d("WXTracing", event.toString());
-    }
-
-    public static class TraceEvent {
-        public String name;
-        public String phase;
-        public String threadName;
-        public long timestamp;
-        public long nanoTime;
-        public long duration;
-
-        @Override
-        public String toString() {
-            final StringBuffer sb = new StringBuffer("TraceEvent{");
-            sb.append("name='").append(name).append('\'');
-            sb.append(", threadName='").append(threadName).append('\'');
-            sb.append(", phase='").append(phase).append('\'');
-            sb.append(", timestamp=").append(timestamp);
-            sb.append(", nanoTime=").append(nanoTime);
-            sb.append(", duration=").append(duration);
-            sb.append('}');
-            return sb.toString();
-        }
-    }
-
-    public static String getFunctionName(Message msg) {
-        Object obj = msg.obj;
-        if (obj != null && obj instanceof WXDomTask) {
-            Object action = ((WXDomTask) obj).args.get(0);
-            if (action instanceof Action) {
-                return getFunctionName(action.getClass());
-            }
-        }
-
-        String actionName = "unknown";
-        int what = msg.what;
-        if (what == WXDomHandler.MsgType.WX_DOM_BATCH) {
-            actionName = "domBatch";
-        } else if (what == WXDomHandler.MsgType.WX_DOM_UPDATE_STYLE) {
-            actionName = "updateStyle";
-        } else if (what == WXDomHandler.MsgType.WX_CONSUME_RENDER_TASKS) {
-            actionName = "consumeRenderTasks";
-        }
-        return actionName;
-    }
-
-    public static String getFunctionName(Class clazz) {
-        String simpleName = clazz.getSimpleName();
-        char[] chars = simpleName.replace("Action", "").toCharArray();
-        chars[0] = Character.toLowerCase(chars[0]);
-        return new String(chars);
-    }
-}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/DOMActionContextImpl.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/DOMActionContextImpl.java b/android/sdk/src/main/java/com/taobao/weex/dom/DOMActionContextImpl.java
index 6e1e385..d18cea8 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/DOMActionContextImpl.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/DOMActionContextImpl.java
@@ -26,12 +26,13 @@ import com.taobao.weex.WXSDKInstance;
 import com.taobao.weex.WXSDKManager;
 import com.taobao.weex.dom.action.Actions;
 import com.taobao.weex.dom.flex.CSSLayoutContext;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.IWXRenderTask;
 import com.taobao.weex.ui.WXRenderManager;
 import com.taobao.weex.ui.animation.WXAnimationBean;
 import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.Stopwatch;
 import com.taobao.weex.utils.WXLogUtils;
 
 import java.util.ArrayList;
@@ -172,9 +173,18 @@ class DOMActionContextImpl implements DOMActionContext {
     if (!mDirty || mDestroy) {
       return;
     }
-
+    long start = System.currentTimeMillis();
+    long startNanos = System.nanoTime();
     WXDomObject rootDom = mRegistry.get(WXDomObject.ROOT);
     layout(rootDom);
+
+    if (WXTracing.isAvailable()) {
+      WXTracing.TraceEvent batchEvent = WXTracing.newEvent("domBatch", mInstanceId, -1);
+      batchEvent.duration = Stopwatch.nanosToMillis(System.nanoTime() - startNanos);
+      batchEvent.ts = start;
+      batchEvent.ph = "X";
+      WXTracing.submit(batchEvent);
+    }
   }
 
   void layout(WXDomObject rootDom) {
@@ -182,9 +192,7 @@ class DOMActionContextImpl implements DOMActionContext {
       return;
     }
     long start0 = System.currentTimeMillis();
-    Stopwatch.tick();
     rebuildingFixedDomTree(rootDom);
-    WXLogUtils.e("Tracing", "rebuildingFixedDomTree " + Stopwatch.tackAndTick() + " ms");
 
     rootDom.traverseTree( new WXDomObject.Consumer() {
       @Override
@@ -195,13 +203,9 @@ class DOMActionContextImpl implements DOMActionContext {
         dom.layoutBefore();
       }
     });
-    WXLogUtils.e("Tracing", "layoutBefore " + Stopwatch.tackAndTick() + " ms");
     long start = System.currentTimeMillis();
 
-
-    long s = System.nanoTime();
     rootDom.calculateLayout(mLayoutContext);
-    WXLogUtils.e("Tracing", "layout " + Stopwatch.tackAndTick() + " ms");
 
     WXSDKInstance instance = WXSDKManager.getInstance().getSDKInstance(mInstanceId);
     if (instance != null) {
@@ -217,11 +221,9 @@ class DOMActionContextImpl implements DOMActionContext {
         dom.layoutAfter();
       }
     });
-    WXLogUtils.e("Tracing", "layoutAfter " + Stopwatch.tackAndTick() + " ms");
 
     start = System.currentTimeMillis();
     rootDom.traverseTree(new ApplyUpdateConsumer());
-    WXLogUtils.e("Tracing", "applyUpdateConsumer " + Stopwatch.tackAndTick() + " ms");
 
     if (instance != null) {
       instance.applyUpdateTime(System.currentTimeMillis() - start);
@@ -232,7 +234,6 @@ class DOMActionContextImpl implements DOMActionContext {
     if (instance != null) {
       instance.updateDomObjTime(System.currentTimeMillis() - start);
     }
-    WXLogUtils.e("Tracing", "updateDomObj " + Stopwatch.tack() + " ms");
     parseAnimation();
 
     boolean isPreRenderMode = instance != null && instance.isPreRenderMode();

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/RenderActionTask.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/RenderActionTask.java b/android/sdk/src/main/java/com/taobao/weex/dom/RenderActionTask.java
index 28b487f..bac1574 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/RenderActionTask.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/RenderActionTask.java
@@ -18,6 +18,12 @@
  */
 package com.taobao.weex.dom;
 
+import android.os.SystemClock;
+
+import com.taobao.weex.dom.action.AbstractAddElementAction;
+import com.taobao.weex.dom.action.TraceableAction;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.IWXRenderTask;
 
 /**
@@ -27,15 +33,33 @@ import com.taobao.weex.ui.IWXRenderTask;
 class RenderActionTask implements IWXRenderTask {
   private final RenderAction mRenderTask;
   private final RenderActionContext mContext;
+  private final long mStartMillis = SystemClock.uptimeMillis();
 
   public RenderActionTask(RenderAction action, RenderActionContext context){
     mRenderTask = action;
     mContext = context;
   }
 
-
   @Override
   public void execute() {
+    if (WXTracing.isAvailable() && mRenderTask instanceof TraceableAction) {
+      ((TraceableAction) mRenderTask).mUIQueueTime = SystemClock.uptimeMillis() - mStartMillis;
+    }
+    long start = System.currentTimeMillis();
+    long uiNanos = System.nanoTime();
     mRenderTask.executeRender(mContext);
+
+    if (WXTracing.isAvailable()) {
+      uiNanos = System.nanoTime() - uiNanos;
+      if (mRenderTask instanceof TraceableAction) {
+        if (!(mRenderTask instanceof AbstractAddElementAction)) {
+          WXTracing.TraceEvent uiExecuteEvent = WXTracing.newEvent("UIExecute", mContext.getInstance().getInstanceId(), ((TraceableAction) mRenderTask).mTracingEventId);
+          uiExecuteEvent.duration = Stopwatch.nanosToMillis(uiNanos);
+          uiExecuteEvent.ts = start;
+          uiExecuteEvent.submit();
+        }
+        ((TraceableAction) mRenderTask).onFinishUIExecute();
+      }
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/WXDomHandler.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomHandler.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomHandler.java
index 03f6940..ca79066 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomHandler.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomHandler.java
@@ -23,9 +23,8 @@ import android.os.Message;
 import android.os.SystemClock;
 
 import com.alibaba.fastjson.JSONObject;
-import com.taobao.weex.common.WXTracing;
 import com.taobao.weex.dom.action.Actions;
-import com.taobao.weex.utils.WXLogUtils;
+import com.taobao.weex.dom.action.TraceableAction;
 
 /**
  * Handler for dom operations.
@@ -45,8 +44,6 @@ public class WXDomHandler implements Handler.Callback {
 
   @Override
   public boolean handleMessage(Message msg) {
-    long s = System.nanoTime();
-    String actionName = WXTracing.getFunctionName(msg);
     if (msg == null) {
       return false;
     }
@@ -54,11 +51,12 @@ public class WXDomHandler implements Handler.Callback {
     Object obj = msg.obj;
     WXDomTask task = null;
 
-    if (obj instanceof WXDomTask) {
+    if (obj != null && obj instanceof WXDomTask) {
       task = (WXDomTask) obj;
-      WXLogUtils.e("Tracing", "Method " + actionName + ", Queue time " + ((s - task.startTime) / 1000000.0) + " ms");
-    } else {
-      WXLogUtils.e("Tracing", "Method " + actionName + ", Queue time " + (SystemClock.uptimeMillis() - msg.getWhen()) + " ms");
+      Object action = ((WXDomTask) obj).args.get(0);
+      if (action != null && action instanceof TraceableAction) {
+        ((TraceableAction) action).mDomQueueTime = SystemClock.uptimeMillis() - msg.getWhen();
+      }
     }
 
     if (!mHasBatch) {
@@ -86,7 +84,6 @@ public class WXDomHandler implements Handler.Callback {
       default:
         break;
     }
-    WXLogUtils.e("Tracing", "Method " + actionName + ", Dom execute time " + ((System.nanoTime() - s) / 1000000.0) + " ms");
     return true;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java
index fe8866b..66fd56e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomManager.java
@@ -26,6 +26,10 @@ import com.taobao.weex.WXEnvironment;
 import com.taobao.weex.WXSDKManager;
 import com.taobao.weex.common.WXRuntimeException;
 import com.taobao.weex.common.WXThread;
+import com.taobao.weex.dom.action.AbstractAddElementAction;
+import com.taobao.weex.dom.action.TraceableAction;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.WXRenderManager;
 import com.taobao.weex.utils.WXUtils;
 
@@ -160,8 +164,18 @@ public final class WXDomManager {
         return;
       }
     }
+    long domStart = System.currentTimeMillis();
+    long domNanos = System.nanoTime();
     action.executeDom(context);
-
+    if (WXTracing.isAvailable()) {
+      domNanos = System.nanoTime() - domNanos;
+      if (!(action instanceof AbstractAddElementAction) && action instanceof TraceableAction) {
+        WXTracing.TraceEvent domExecuteEvent = WXTracing.newEvent("DomExecute", context.getInstanceId(), ((TraceableAction) action).mTracingEventId);
+        domExecuteEvent.duration = Stopwatch.nanosToMillis(domNanos);
+        domExecuteEvent.ts = domStart;
+        domExecuteEvent.submit();
+      }
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
index 2d44561..399ab3a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomModule.java
@@ -26,6 +26,9 @@ import com.taobao.weex.bridge.WXBridgeManager;
 import com.taobao.weex.common.WXModule;
 import com.taobao.weex.dom.action.Action;
 import com.taobao.weex.dom.action.Actions;
+import com.taobao.weex.dom.action.TraceableAction;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.utils.WXLogUtils;
 
 
@@ -76,16 +79,16 @@ public final class WXDomModule extends WXModule {
     mWXSDKInstance = instance;
   }
 
-  public void callDomMethod(JSONObject task) {
+  public void callDomMethod(JSONObject task, long... parseNanos) {
     if (task == null) {
       return;
     }
     String method = (String) task.get(WXBridgeManager.METHOD);
     JSONArray args = (JSONArray) task.get(WXBridgeManager.ARGS);
-    callDomMethod(method,args);
+    callDomMethod(method,args,parseNanos);
   }
   
-  public Object callDomMethod(String method, JSONArray args) {
+  public Object callDomMethod(String method, JSONArray args, long... parseNanos) {
 
     if (method == null) {
       return null;
@@ -102,6 +105,34 @@ public final class WXDomModule extends WXModule {
       }else {
         postAction((RenderAction)action);
       }
+
+      if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+        //TODO: CHECK AGAIN
+        String ref = null;
+        String type = null;
+        if (args.size() > 0) {
+          if (args.size() >= 1) {
+            if (args.get(0) instanceof String) {
+              ref = args.getString(0);
+            } else if (args.get(0) instanceof JSONObject) {
+              ref = ((JSONObject) args.get(0)).getString("ref");
+              type = ((JSONObject) args.get(0)).getString("type");
+            }
+          }
+
+          if (args.size() >= 2) {
+            if (args.get(1) instanceof JSONObject) {
+              ref = ((JSONObject) args.get(1)).getString("ref");
+              type = ((JSONObject) args.get(1)).getString("type");
+            }
+          }
+        }
+        if (parseNanos != null && parseNanos.length == 1) {
+          ((TraceableAction) action).mParseJsonNanos = parseNanos[0];
+          ((TraceableAction) action).mStartMillis -= Stopwatch.nanosToMillis(parseNanos[0]);
+        }
+        ((TraceableAction) action).onStartDomExecute(mWXSDKInstance.getInstanceId(), method, ref, type, args.toJSONString());
+      }
     } catch (IndexOutOfBoundsException e) {
       // no enougn args
       e.printStackTrace();

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
index 641c95a..258df2b 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXDomObject.java
@@ -86,7 +86,11 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject
 
   private boolean mYoung = false;
 
+  public long mDomThreadNanos;
+  public long mDomThreadTimestamp;
+
   public void traverseTree(Consumer...consumers){
+    long startNanos = System.nanoTime();
     if (consumers == null) {
       return;
     }
@@ -101,6 +105,7 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject
       child = getChild(i);
       child.traverseTree(consumers);
     }
+    mDomThreadNanos += (System.nanoTime() - startNanos);
   }
 
 
@@ -628,6 +633,8 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject
    * @return Dom Object corresponding to the JSONObject.
    */
   public static  @Nullable WXDomObject parse(JSONObject json, WXSDKInstance wxsdkInstance){
+      long startNanos = System.nanoTime();
+      long timestamp = System.currentTimeMillis();
       if (json == null || json.size() <= 0) {
         return null;
       }
@@ -671,6 +678,8 @@ public class WXDomObject extends CSSNode implements Cloneable,ImmutableDomObject
         }
       }
 
+      domObject.mDomThreadNanos = System.nanoTime() - startNanos;
+      domObject.mDomThreadTimestamp = timestamp;
       return domObject;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
index b3b27a6..3b2d964 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractAddElementAction.java
@@ -28,24 +28,30 @@ import com.taobao.weex.dom.DOMAction;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderAction;
 import com.taobao.weex.dom.WXDomObject;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXComponentFactory;
 import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.Stopwatch;
 import com.taobao.weex.utils.WXLogUtils;
 
+import java.util.List;
+
 /**
  * Created by sospartan on 22/02/2017.
  */
 
-abstract class AbstractAddElementAction implements DOMAction, RenderAction {
-
+public abstract class AbstractAddElementAction extends TraceableAction implements DOMAction, RenderAction {
 
   protected WXComponent generateComponentTree(DOMActionContext context, WXDomObject dom, WXVContainer parent) {
     if (dom == null) {
       return null;
     }
+    long startNanos = System.nanoTime();
     WXComponent component = WXComponentFactory.newInstance(context.getInstance(), dom, parent);
+    component.mTraceInfo.domThreadStart = dom.mDomThreadTimestamp;
+    component.mTraceInfo.rootEventId = mTracingEventId;
+    component.mTraceInfo.domQueueTime = mDomQueueTime;
 
     context.registerComponent(dom.getRef(), component);
     if (component instanceof WXVContainer) {
@@ -59,7 +65,7 @@ abstract class AbstractAddElementAction implements DOMAction, RenderAction {
         }
       }
     }
-
+    component.mTraceInfo.domThreadNanos = System.nanoTime() - startNanos;
     return component;
   }
 
@@ -83,7 +89,7 @@ abstract class AbstractAddElementAction implements DOMAction, RenderAction {
     //only non-root has parent.
     Stopwatch.tick();
     WXDomObject domObject = WXDomObject.parse(dom, instance);
-    WXLogUtils.e("Tracing", "Component " + domObject.getRef() + " parseDomObject " + Stopwatch.tackAndTick() + " ms");
+    Stopwatch.split("parseDomObject");
 
     if (domObject == null || context.getDomByRef(domObject.getRef()) != null) {
       if (WXEnvironment.isApkDebugable()) {
@@ -93,13 +99,13 @@ abstract class AbstractAddElementAction implements DOMAction, RenderAction {
       return;
     }
     appendDomToTree(context, domObject);
-    WXLogUtils.e("Tracing", "Component " + domObject.getRef() + " appendDomToTree " + Stopwatch.tackAndTick() + " ms");
+    Stopwatch.split("appendDomToTree");
 
     domObject.traverseTree(
         context.getAddDOMConsumer(),
         context.getApplyStyleConsumer()
     );
-    WXLogUtils.e("Tracing", "Component " + domObject.getRef() + " traverseTree " + Stopwatch.tackAndTick() + " ms");
+    Stopwatch.split("traverseTree");
 
 
     //Create component in dom thread
@@ -109,13 +115,19 @@ abstract class AbstractAddElementAction implements DOMAction, RenderAction {
       //stop redner, some fatal happened.
       return;
     }
-    WXLogUtils.e("Tracing", "Component " + domObject.getRef() + " createComponent " + Stopwatch.tackAndTick() + " ms");
+    Stopwatch.split("createComponent");
 
     context.addDomInfo(domObject.getRef(), component);
     context.postRenderTask(this);
     addAnimationForDomTree(context, domObject);
 
     instance.commitUTStab(IWXUserTrackAdapter.DOM_MODULE, WXErrorCode.WX_SUCCESS);
+    if (WXTracing.isAvailable()) {
+      List<Stopwatch.ProcessEvent> events = Stopwatch.getProcessEvents();
+      for (Stopwatch.ProcessEvent event : events) {
+        submitPerformance(event.fname, "X", context.getInstanceId(), event.duration, event.startMillis, true);
+      }
+    }
   }
 
   public void addAnimationForDomTree(DOMActionContext context, WXDomObject domObject) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractLayoutFinishAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractLayoutFinishAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractLayoutFinishAction.java
index 120e56c..a16f27a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractLayoutFinishAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/AbstractLayoutFinishAction.java
@@ -21,7 +21,6 @@ package com.taobao.weex.dom.action;
 import com.taobao.weex.WXSDKInstance;
 import com.taobao.weex.adapter.IWXUserTrackAdapter;
 import com.taobao.weex.common.WXErrorCode;
-import com.taobao.weex.common.WXRenderStrategy;
 import com.taobao.weex.dom.DOMAction;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderAction;
@@ -30,7 +29,7 @@ import com.taobao.weex.dom.WXDomObject;
 /**
  * Created by sospartan on 02/03/2017.
  */
-abstract class AbstractLayoutFinishAction implements DOMAction, RenderAction {
+abstract class AbstractLayoutFinishAction extends TraceableAction implements DOMAction, RenderAction {
 
   protected int mLayoutWidth;
   protected int mLayoutHeight;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
index a4b3adf..e8b3721 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/AddElementAction.java
@@ -25,11 +25,14 @@ import com.taobao.weex.common.WXErrorCode;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderActionContext;
 import com.taobao.weex.dom.WXDomObject;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXVContainer;
-import com.taobao.weex.utils.Stopwatch;
 import com.taobao.weex.utils.WXLogUtils;
 
+import java.util.List;
+
 /**
  * Created by sospartan on 22/02/2017.
  */
@@ -59,6 +62,7 @@ final class AddElementAction extends AbstractAddElementAction {
 
   @Override
   protected void appendDomToTree(DOMActionContext context, WXDomObject domObject) {
+    long startNanos = System.nanoTime();
     WXDomObject parent;
     mRef = domObject.getRef();
     if ((parent = context.getDomByRef(mParentRef)) == null) {
@@ -68,6 +72,7 @@ final class AddElementAction extends AbstractAddElementAction {
       //non-root and parent exist
       parent.add(domObject, mAddIndex);
     }
+    domObject.mDomThreadNanos += (System.nanoTime() - startNanos);
   }
 
   @Override
@@ -98,14 +103,31 @@ final class AddElementAction extends AbstractAddElementAction {
       if (parent == null || component == null) {
         return;
       }
+
       Stopwatch.tick();
       parent.addChild(component, mAddIndex);
       parent.createChildViewAt(mAddIndex);
-      WXLogUtils.e("Tracing", "Component " + mRef + " createViewTree " + Stopwatch.tackAndTick() + " ms");
+      Stopwatch.split("createViewTree");
+
       component.applyLayoutAndEvent(component);
-      WXLogUtils.e("Tracing", "Component " + mRef + " applyLayoutAndEvent " + Stopwatch.tackAndTick() + " ms");
+      Stopwatch.split("applyLayoutAndEvent");
+
       component.bindData(component);
-      WXLogUtils.e("Tracing", "Component " + mRef + " bindData " + Stopwatch.tackAndTick() + " ms");
+      Stopwatch.split("bindData");
+
+      if (WXTracing.isAvailable()) {
+        String instanceId = context.getInstance().getInstanceId();
+        List<Stopwatch.ProcessEvent> splits = Stopwatch.getProcessEvents();
+        for (Stopwatch.ProcessEvent event : splits) {
+          submitPerformance(event.fname, "X", instanceId, event.duration, event.startMillis, true);
+        }
+      }
+      component.mTraceInfo.uiQueueTime = mUIQueueTime;
+      if (component.isLazy()) {
+        component.onRenderFinish(WXComponent.STATE_DOM_FINISH);
+      } else {
+        component.onRenderFinish(WXComponent.STATE_ALL_FINISH);
+      }
     } catch (Exception e) {
       WXLogUtils.e("add component failed.", e);
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/AddEventAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddEventAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/AddEventAction.java
index e051917..e0ee886 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/AddEventAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/AddEventAction.java
@@ -26,14 +26,16 @@ import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderAction;
 import com.taobao.weex.dom.RenderActionContext;
 import com.taobao.weex.dom.WXDomObject;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.Stopwatch;
-import com.taobao.weex.utils.WXLogUtils;
+
+import java.util.List;
 
 /**
  * Created by sospartan on 01/03/2017.
  */
-class AddEventAction implements DOMAction, RenderAction {
+class AddEventAction extends TraceableAction implements DOMAction, RenderAction {
   private final String mRef;
   private final String mEvent;
 
@@ -49,6 +51,8 @@ class AddEventAction implements DOMAction, RenderAction {
     if (context.isDestory()) {
       return;
     }
+
+    Stopwatch.tick();
     WXSDKInstance instance = context.getInstance();
     WXDomObject domObject = context.getDomByRef(mRef);
     if (domObject == null) {
@@ -59,6 +63,11 @@ class AddEventAction implements DOMAction, RenderAction {
     }
     domObject.addEvent(mEvent);
     mUpdatedDom = domObject;
+
+    if (WXTracing.isAvailable() && mBeginEvent != null) {
+      submitPerformance("addEventToDom", "X", instance.getInstanceId(), Stopwatch.tack(), Stopwatch.lastTickStamp(), true);
+    }
+
     context.postRenderTask(this);
 
     if (instance != null) {
@@ -73,9 +82,17 @@ class AddEventAction implements DOMAction, RenderAction {
       //sync dom change to component
       Stopwatch.tick();
       comp.updateDom(mUpdatedDom);
-      WXLogUtils.e("Tracing", "updateDom " + Stopwatch.tackAndTick() + " ms");
+      Stopwatch.split("updateDom");
+
       comp.addEvent(mEvent);
-      WXLogUtils.e("Tracing", "addEvent " + Stopwatch.tackAndTick() + " ms");
+      Stopwatch.split("addEventToComponent");
+
+      if (WXTracing.isAvailable() && mBeginEvent != null) {
+        List<Stopwatch.ProcessEvent> events = Stopwatch.getProcessEvents();
+        for (Stopwatch.ProcessEvent event : events) {
+          submitPerformance(event.fname, "X", comp.getInstanceId(), event.duration, event.startMillis, true);
+        }
+      }
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateBodyAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateBodyAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateBodyAction.java
index c7ac391..8c4df7d 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateBodyAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateBodyAction.java
@@ -30,6 +30,8 @@ import com.taobao.weex.common.WXRenderStrategy;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderActionContext;
 import com.taobao.weex.dom.WXDomObject;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.component.WXComponent;
 import com.taobao.weex.ui.component.WXScroller;
 import com.taobao.weex.utils.WXLogUtils;
@@ -48,6 +50,12 @@ class CreateBodyAction extends AbstractAddElementAction {
 
   @Override
   public void executeDom(DOMActionContext context) {
+    if (WXEnvironment.isApkDebugable()) {
+      WXTracing.TraceEvent execJsEndEvent = WXTracing.newEvent("executeBundleJS", context.getInstanceId(), -1);
+      execJsEndEvent.traceId = context.getInstance().mExecJSTraceId;
+      execJsEndEvent.ph = "E";
+      execJsEndEvent.submit();
+    }
     addDomInternal(context, mData);
   }
 
@@ -58,10 +66,12 @@ class CreateBodyAction extends AbstractAddElementAction {
 
   @Override
   protected void appendDomToTree(DOMActionContext context, WXDomObject domObject) {
+    long startNanos = System.nanoTime();
     String instanceId = context.getInstanceId();
     WXDomObject.prepareRoot(domObject,
         WXViewUtils.getWebPxByWidth(WXViewUtils.getWeexHeight(instanceId), WXSDKManager.getInstanceViewPortWidth(instanceId)),
         WXViewUtils.getWebPxByWidth(WXViewUtils.getWeexWidth(instanceId), WXSDKManager.getInstanceViewPortWidth(instanceId)));
+    domObject.mDomThreadNanos += (System.nanoTime() - startNanos);
   }
 
   @Override
@@ -84,17 +94,24 @@ class CreateBodyAction extends AbstractAddElementAction {
       return;
     }
     try {
+      Stopwatch.tick();
       long start = System.currentTimeMillis();
       component.createView();
       if (WXEnvironment.isApkDebugable()) {
         WXLogUtils.renderPerformanceLog("createView", (System.currentTimeMillis() - start));
+        submitPerformance("createView", "X", instance.getInstanceId(), Stopwatch.tackAndTick(), start, true);
       }
       start = System.currentTimeMillis();
       component.applyLayoutAndEvent(component);
+      if (WXTracing.isAvailable()) {
+        submitPerformance("applyLayoutAndEvent", "X", instance.getInstanceId(), Stopwatch.tackAndTick(), start, true);
+      }
+      start = System.currentTimeMillis();
       component.bindData(component);
 
       if (WXEnvironment.isApkDebugable()) {
         WXLogUtils.renderPerformanceLog("bind", (System.currentTimeMillis() - start));
+        submitPerformance("bindData", "X", instance.getInstanceId(), Stopwatch.tack(), start, true);
       }
 
       if (component instanceof WXScroller) {
@@ -108,6 +125,8 @@ class CreateBodyAction extends AbstractAddElementAction {
         instance.onCreateFinish();
       }
       instance.commitUTStab(IWXUserTrackAdapter.DOM_MODULE, WXErrorCode.WX_SUCCESS);
+      component.mTraceInfo.uiQueueTime = mUIQueueTime;
+      component.onRenderFinish(WXComponent.STATE_ALL_FINISH);
     } catch (Exception e) {
       WXLogUtils.e("create body failed.", e);
     }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateFinishAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateFinishAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateFinishAction.java
index c92cf11..e581c4e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateFinishAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/CreateFinishAction.java
@@ -25,6 +25,8 @@ import com.taobao.weex.common.WXRenderStrategy;
 import com.taobao.weex.common.WXThread;
 import com.taobao.weex.dom.DOMActionContext;
 import com.taobao.weex.dom.RenderActionContext;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 
 /**
  * Created by sospartan on 02/03/2017.
@@ -54,5 +56,9 @@ final class CreateFinishAction extends AbstractLayoutFinishAction {
       instance.onCreateFinish();
     }
     instance.onRenderSuccess(mLayoutWidth, mLayoutHeight);
+    if (WXTracing.isAvailable()) {
+      double renderTime = Stopwatch.millisUntilNow(context.getInstance().mRenderStartNanos);
+      submitPerformance("renderFinish", "X", instance.getInstanceId(), renderTime, System.currentTimeMillis());
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/RefreshFinishAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/RefreshFinishAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/RefreshFinishAction.java
index c46b8d9..2d87d11 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/RefreshFinishAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/RefreshFinishAction.java
@@ -20,6 +20,7 @@ package com.taobao.weex.dom.action;
 
 import com.taobao.weex.WXSDKInstance;
 import com.taobao.weex.dom.RenderActionContext;
+import com.taobao.weex.tracing.WXTracing;
 
 /**
  * Created by sospartan on 02/03/2017.
@@ -31,5 +32,8 @@ class RefreshFinishAction extends AbstractLayoutFinishAction {
   public void executeRender(RenderActionContext context) {
     WXSDKInstance instance = context.getInstance();
     instance.onRefreshSuccess(mLayoutWidth, mLayoutHeight);
+    if (WXTracing.isAvailable()) {
+      submitPerformance("refreshFinish", "I", context.getInstance().getInstanceId(), 0, 0);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/TraceableAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/TraceableAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/TraceableAction.java
new file mode 100644
index 0000000..5bd2689
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/TraceableAction.java
@@ -0,0 +1,82 @@
+/**
+ * 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.
+ */
+package com.taobao.weex.dom.action;
+
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
+
+/**
+ * Created by moxun on 2017/6/30.
+ */
+
+public class TraceableAction {
+  public int mTracingEventId;
+  public long mStartMillis;
+  public long mDomQueueTime;
+  public long mUIQueueTime;
+  public long mParseJsonNanos = -1;
+  protected WXTracing.TraceEvent mBeginEvent;
+
+  {
+    if (WXTracing.isAvailable()) {
+      mTracingEventId = WXTracing.nextId();
+      mStartMillis = System.currentTimeMillis();
+    }
+  }
+
+  protected WXTracing.TraceEvent submitPerformance(String fname, String ph, String instanceId, double duration, long ts, boolean... isSegment) {
+    if (WXTracing.isAvailable()) {
+      WXTracing.TraceEvent event = WXTracing.newEvent(fname, instanceId, mTracingEventId);
+      event.ts = ts;
+      event.ph = ph;
+      event.duration = duration;
+
+      if (isSegment != null && isSegment.length == 1) {
+        event.isSegment = isSegment[0];
+      }
+
+      event.submit();
+      return event;
+    }
+    return new WXTracing.TraceEvent();
+  }
+
+  public void onStartDomExecute(String instanceId, String fname, String ref, String type, String payload) {
+    if (WXTracing.isAvailable()) {
+      mBeginEvent = WXTracing.newEvent(fname, instanceId, -1);
+      mBeginEvent.traceId = mTracingEventId;
+      mBeginEvent.ts = mStartMillis;
+      mBeginEvent.ph = "B";
+      mBeginEvent.ref = ref;
+      mBeginEvent.name = type;
+      mBeginEvent.payload = payload;
+      mBeginEvent.parseJsonTime = Stopwatch.nanosToMillis(mParseJsonNanos);
+      mBeginEvent.submit();
+    }
+  }
+
+  public void onFinishUIExecute() {
+    if (WXTracing.isAvailable() && mBeginEvent != null) {
+      WXTracing.TraceEvent endEvent = WXTracing.newEvent(getClass().getSimpleName(), mBeginEvent.iid, -1);
+      endEvent.traceId = mBeginEvent.traceId;
+      endEvent.ph = "E";
+      endEvent.submit();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
index 3db776e..017bb53 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateAttributeAction.java
@@ -33,7 +33,7 @@ import com.taobao.weex.ui.component.WXComponent;
  * Created by sospartan on 28/02/2017.
  */
 
-class UpdateAttributeAction implements DOMAction, RenderAction {
+class UpdateAttributeAction extends TraceableAction implements DOMAction, RenderAction {
   private final String mRef;
   private final JSONObject mData;
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateStyleAction.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateStyleAction.java b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateStyleAction.java
index aa56e70..a4dc8e9 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateStyleAction.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/action/UpdateStyleAction.java
@@ -39,7 +39,7 @@ import java.util.Map;
  * Created by sospartan on 28/02/2017.
  */
 
-class UpdateStyleAction implements DOMAction, RenderAction {
+class UpdateStyleAction extends TraceableAction implements DOMAction, RenderAction {
   private final String mRef;
   private final JSONObject mData;
   private final boolean mIsCausedByPesudo;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java b/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java
new file mode 100644
index 0000000..10b8be2
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/tracing/Stopwatch.java
@@ -0,0 +1,132 @@
+/**
+ * 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.
+ */
+package com.taobao.weex.tracing;
+
+import com.taobao.weex.utils.WXLogUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Created by moxun on 2017/6/2.
+ */
+
+public class Stopwatch {
+  private static final ThreadLocal<Stopwatch> sThreadLocal = new ThreadLocal<>();
+  private long startNanos;
+  private List<ProcessEvent> splits = new ArrayList<>();
+  private long startMillis;
+
+  private static void prepare() {
+    if (sThreadLocal.get() == null) {
+      sThreadLocal.set(new Stopwatch());
+    }
+  }
+
+  public static void tick() {
+    if (WXTracing.isAvailable()) {
+      try {
+        prepare();
+        if (sThreadLocal.get().startNanos != 0L) {
+          WXLogUtils.w("Stopwatch", "Stopwatch is not reset");
+        }
+        sThreadLocal.get().startNanos = System.nanoTime();
+        sThreadLocal.get().startMillis = System.currentTimeMillis();
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+  }
+
+  public static void split(String fname) {
+    if (WXTracing.isAvailable()) {
+      try {
+        ProcessEvent event = new ProcessEvent();
+        long start = sThreadLocal.get().startMillis;
+        double millis = tackAndTick();
+        event.fname = fname;
+        event.duration = millis;
+        event.startMillis = start;
+        sThreadLocal.get().splits.add(event);
+      } catch (Throwable throwable) {
+        throwable.printStackTrace();
+      }
+    }
+  }
+
+  public static List<ProcessEvent> getProcessEvents() {
+    if (WXTracing.isAvailable()) {
+      tack();
+      List<ProcessEvent> existedEvents = sThreadLocal.get().splits;
+      sThreadLocal.get().splits = new ArrayList<>();
+      return existedEvents;
+    } else {
+      return Collections.emptyList();
+    }
+  }
+
+  public static double tack() {
+    if (WXTracing.isAvailable()) {
+      try {
+        long startNanos = sThreadLocal.get().startNanos;
+        if (startNanos == 0L) {
+          WXLogUtils.w("Stopwatch", "Should call Stopwatch.tick() before Stopwatch.tack() called");
+        }
+        long nanos = System.nanoTime() - startNanos;
+        sThreadLocal.get().startNanos = 0L;
+        return nanosToMillis(nanos);
+      } catch (Throwable throwable) {
+        throwable.printStackTrace();
+      }
+    }
+    return -1;
+  }
+
+  public static long lastTickStamp() {
+    if (WXTracing.isAvailable()) {
+      try {
+        return sThreadLocal.get().startMillis;
+      } catch (Throwable t) {
+        t.printStackTrace();
+      }
+    }
+    return -1;
+  }
+
+  public static double tackAndTick() {
+    double ms = tack();
+    tick();
+    return ms;
+  }
+
+  public static double nanosToMillis(long nanos) {
+    return nanos / 1000000.0;
+  }
+
+  public static double millisUntilNow(long startNanos) {
+    return nanosToMillis(System.nanoTime() - startNanos);
+  }
+
+  public static class ProcessEvent {
+    public String fname;
+    public double duration;
+    public long startMillis;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java b/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java
new file mode 100644
index 0000000..7530322
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/tracing/WXTracing.java
@@ -0,0 +1,156 @@
+/**
+ * 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.
+ */
+package com.taobao.weex.tracing;
+
+import android.os.Looper;
+import android.util.SparseArray;
+
+import com.taobao.weex.WXEnvironment;
+import com.taobao.weex.WXSDKManager;
+import com.taobao.weex.adapter.ITracingAdapter;
+import com.taobao.weex.utils.WXLogUtils;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Created by moxun on 2017/6/6.
+ */
+
+public class WXTracing {
+  private static final AtomicInteger sIdGenerator = new AtomicInteger(0);
+
+  public static int nextId() {
+    return sIdGenerator.getAndIncrement();
+  }
+  
+  public static boolean isAvailable() {
+    return WXEnvironment.isApkDebugable();
+  }
+
+  public static synchronized void submit(TraceEvent event) {
+    ITracingAdapter tracingAdapter = WXSDKManager.getInstance().getTracingAdapter();
+    if (tracingAdapter != null) {
+      if (event.iid == null) {
+        WXLogUtils.w("WXTracing", "Event " + event.fname + " missing instance id");
+      }
+      tracingAdapter.submitTracingEvent(event);
+    }
+  }
+
+  public static class TraceEvent {
+    public String fname;
+    public String tname;
+    public String ph;
+    public int traceId;
+    public long ts;
+    public String iid;
+    public String ref;
+    public String parentRef;
+    public String name;
+    public String classname;
+    public int parentId = -1;
+    public double duration;
+
+    /**
+     * Internal use
+     */
+    public SparseArray<TraceEvent> subEvents;
+    public String payload;
+    public double parseJsonTime;
+    public boolean isSegment;
+    public Map<String, Object> extParams;
+    public boolean firstScreenFinish;
+
+    private boolean submitted;
+
+    public TraceEvent() {
+      ts = System.currentTimeMillis();
+      traceId = nextId();
+      tname = currentThreadName();
+    }
+
+    public JSONObject toJSONObject() {
+      JSONObject object = new JSONObject();
+      try {
+        object.put("parentId", parentId);
+        object.put("ref", ref);
+        object.put("parentRef", parentRef);
+        object.put("className", classname);
+        object.put("ts", ts);
+        object.put("traceId", traceId);
+        object.put("iid", iid);
+        object.put("duration", duration);
+        object.put("fName", fname);
+        object.put("ph", ph);
+        object.put("name", name);
+        object.put("tName", tname);
+      } catch (JSONException e) {
+        e.printStackTrace();
+      }
+      return object;
+    }
+
+    public void submit() {
+      if (!submitted) {
+        submitted = true;
+        WXTracing.submit(this);
+      } else {
+        WXLogUtils.w("WXTracing", "Event " + traceId + " has been submitted.");
+      }
+    }
+  }
+
+  public static String currentThreadName() {
+    Thread thread = Thread.currentThread();
+    String name = thread.getName();
+
+    if ("WeexJSBridgeThread".equals(name)) {
+      return "JSThread";
+    } else if ("WeeXDomThread".equals(name)) {
+      return "DOMThread";
+    } else if (Looper.getMainLooper() == Looper.myLooper()) {
+      return "UIThread";
+    }
+
+    return name;
+  }
+
+  public static TraceEvent newEvent(String fname, String instanceId, int parentId) {
+    WXTracing.TraceEvent traceEvent = new TraceEvent();
+    traceEvent.fname = fname;
+    traceEvent.iid = instanceId;
+    traceEvent.traceId = WXTracing.nextId();
+    traceEvent.parentId = parentId;
+    return traceEvent;
+  }
+
+  public static class TraceInfo {
+    public int rootEventId;
+    public long domQueueTime;
+    public long uiQueueTime;
+    public long domThreadStart = -1;
+    public long domThreadNanos;
+    public long uiThreadStart = -1;
+    public long uiThreadNanos;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java b/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java
index 77e1b1b..edcc560 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/WXRenderManager.java
@@ -18,18 +18,21 @@
  */
 package com.taobao.weex.ui;
 
+import android.os.SystemClock;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
 import com.taobao.weex.WXSDKInstance;
 import com.taobao.weex.common.WXRuntimeException;
 import com.taobao.weex.common.WXThread;
-import com.taobao.weex.common.WXTracing;
 import com.taobao.weex.dom.RenderAction;
 import com.taobao.weex.dom.RenderActionContext;
 import com.taobao.weex.dom.WXDomObject;
+import com.taobao.weex.dom.action.AbstractAddElementAction;
+import com.taobao.weex.dom.action.TraceableAction;
+import com.taobao.weex.tracing.Stopwatch;
+import com.taobao.weex.tracing.WXTracing;
 import com.taobao.weex.ui.component.WXComponent;
-import com.taobao.weex.utils.WXLogUtils;
 import com.taobao.weex.utils.WXUtils;
 
 import java.util.ArrayList;
@@ -104,18 +107,33 @@ public class WXRenderManager {
   }
 
   public void runOnThread(final String instanceId, final RenderAction action) {
-    final long start = System.nanoTime();
-    final String actionName = WXTracing.getFunctionName(action.getClass());
+    final long start = SystemClock.uptimeMillis();
     mWXRenderHandler.post(WXThread.secure(new Runnable() {
       @Override
       public void run() {
-        long s = System.nanoTime();
-        WXLogUtils.e("Tracing", "Method " + actionName + ", Queue time " + (s - start) + " ns");
         if (mRegistries.get(instanceId) == null) {
           return;
         }
+        if (WXTracing.isAvailable() && action instanceof TraceableAction) {
+          ((TraceableAction) action).mUIQueueTime = SystemClock.uptimeMillis() - start;
+        }
+
+        long start = System.currentTimeMillis();
+        long uiNanos = System.nanoTime();
         action.executeRender(getRenderContext(instanceId));
-        WXLogUtils.e("Tracing", "Method " + actionName + ", Render time " + (System.nanoTime() - s) + " ns");
+
+        if (WXTracing.isAvailable()) {
+          uiNanos = System.nanoTime() - uiNanos;
+          if (action instanceof TraceableAction) {
+            if (!(action instanceof AbstractAddElementAction)) {
+              WXTracing.TraceEvent uiExecuteEvent = WXTracing.newEvent("UIExecute", instanceId, ((TraceableAction) action).mTracingEventId);
+              uiExecuteEvent.duration = Stopwatch.nanosToMillis(uiNanos);
+              uiExecuteEvent.ts = start;
+              uiExecuteEvent.submit();
+            }
+            ((TraceableAction) action).onFinishUIExecute();
+          }
+        }
       }
     }));
   }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
index cc44e79..9864b1e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
@@ -31,6 +31,7 @@ import android.os.Build;
 import android.os.Message;
 import android.support.annotation.CallSuper;
 import android.support.annotation.CheckResult;
+import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
@@ -76,6 +77,10 @@ import com.taobao.weex.utils.WXResourceUtils;
 import com.taobao.weex.utils.WXUtils;
 import com.taobao.weex.utils.WXViewUtils;
 
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -1556,16 +1561,49 @@ public abstract class  WXComponent<T extends View> implements IWXObject, IWXActi
     WXSDKManager.getInstance().getWXDomManager().sendMessage(message);
   }
 
-  public void onRenderFinish() {
-    if (isLazy()) {
-      return;
+  public static final int STATE_DOM_FINISH = 0;
+  public static final int STATE_UI_FINISH = 1;
+  public static final int STATE_ALL_FINISH = 2;
+  @IntDef({STATE_DOM_FINISH, STATE_UI_FINISH, STATE_ALL_FINISH})
+  @Retention(RetentionPolicy.SOURCE)
+  @Target(ElementType.PARAMETER)
+  public @interface RenderState {}
+
+  @CallSuper
+  public void onRenderFinish(@RenderState int state) {
+    if (WXTracing.isAvailable()) {
+      double domTime = Stopwatch.nanosToMillis(((WXDomObject) mDomObj).mDomThreadNanos + mTraceInfo.domThreadNanos);
+      double uiTime = Stopwatch.nanosToMillis(mTraceInfo.uiThreadNanos);
+      if (state == STATE_ALL_FINISH || state == STATE_DOM_FINISH) {
+        WXTracing.TraceEvent domEvent = WXTracing.newEvent("DomExecute", getInstanceId(), mTraceInfo.rootEventId);
+        domEvent.ph = "X";
+        domEvent.duration = domTime;
+        domEvent.ts = mTraceInfo.domThreadStart;
+        domEvent.tname = "DOMThread";
+        domEvent.name = getDomObject().getType();
+        domEvent.classname = getClass().getSimpleName();
+        if (getParent() != null) {
+          domEvent.parentRef = getParent().getRef();
+        }
+        domEvent.submit();
+      }
+
+      if (state == STATE_ALL_FINISH || state == STATE_UI_FINISH) {
+        if (mTraceInfo.uiThreadStart != -1) {
+          WXTracing.TraceEvent uiEvent = WXTracing.newEvent("UIExecute", getInstanceId(), mTraceInfo.rootEventId);
+          uiEvent.ph = "X";
+          uiEvent.duration = uiTime;
+          uiEvent.ts = mTraceInfo.uiThreadStart;
+          uiEvent.name = getDomObject().getType();
+          uiEvent.classname = getClass().getSimpleName();
+          if (getParent() != null) {
+            uiEvent.parentRef = getParent().getRef();
+          }
+          uiEvent.submit();
+        } else {
+          WXLogUtils.w("onRenderFinish", "createView() not called");
+        }
+      }
     }
-    double domTime = Stopwatch.nanosToMillis(((WXDomObject) mDomObj).mDomThreadNanos + mTraceInfo.domThreadNanos);
-    double uiTime = Stopwatch.nanosToMillis(mTraceInfo.uiThreadNanos);
-    WXLogUtils.e("RenderFinish", "Ref: " + getRef() + ", type: " + mDomObj.getType() + ", dom: " + mTraceInfo.domQueueTime + "/" + domTime + ", ui: " + mTraceInfo.uiQueueTime + "/" + uiTime);
-    WXTracing.TraceEvent domEvent = WXTracing.measureAndSubmit("dom " + mDomObj.getType() + "@" + getRef(), "X", mTraceInfo.rootEventId, getInstanceId(), domTime);
-    domEvent.ts = mTraceInfo.domThreadStart;
-    domEvent.tname = "DOMThread";
-    WXTracing.measureAndSubmit("ui " + mDomObj.getType() + "@" + getRef(), "X", mTraceInfo.rootEventId, getInstanceId(), uiTime).ts = mTraceInfo.uiThreadStart;
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
index afdad86..871b18a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
@@ -93,6 +93,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
 
   @Override
   public void applyLayoutAndEvent(WXComponent component) {
+    long startNanos = System.nanoTime();
     if(!isLazy()) {
       if (component == null) {
         component = this;
@@ -105,6 +106,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
       }
 
     }
+    mTraceInfo.uiThreadNanos += (System.nanoTime() - startNanos);
   }
 
   /**
@@ -141,6 +143,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
   }
   @Override
   public void bindData(WXComponent component) {
+    long startNanos = System.nanoTime();
     if(!isLazy()) {
       if (component == null) {
         component = this;
@@ -151,6 +154,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
         getChild(i).bindData(((WXVContainer)component).getChild(i));
       }
     }
+    mTraceInfo.uiThreadNanos += (System.nanoTime() - startNanos);
   }
 
   @Override
@@ -240,6 +244,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
   }
 
   public void addChild(WXComponent child, int index) {
+    long startNanos = System.nanoTime();
     if (child == null || index < -1) {
       return;
     }
@@ -250,6 +255,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
     } else {
       mChildren.add(index, child);
     }
+    mTraceInfo.uiThreadNanos += (System.nanoTime() - startNanos);
   }
 
   public final int indexOf(WXComponent comp){
@@ -257,6 +263,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
   }
 
   public void createChildViewAt(int index){
+    long startNanos = System.nanoTime();
     int indexToCreate = index;
     if(indexToCreate < 0){
       indexToCreate = childCount()-1;
@@ -269,6 +276,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
     if(!child.isVirtualComponent()){
       addSubView(child.getHostView(),indexToCreate);
     }
+    mTraceInfo.uiThreadNanos += (System.nanoTime() - startNanos);
   }
 
   protected void addSubView(View child, int index) {
@@ -429,6 +437,16 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
     }
   }
 
+  @Override
+  public void onRenderFinish(@RenderState int state) {
+    for (int i = 0; i < getChildCount(); i++) {
+      WXComponent child = getChild(i);
+      child.mTraceInfo.uiQueueTime = mTraceInfo.uiQueueTime;
+      child.onRenderFinish(state);
+    }
+    super.onRenderFinish(state);
+  }
+
   /********************************
    *  end hook Activity life cycle callback
    ********************************************************/

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
index 9418a1f..08c6c8e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
@@ -850,7 +850,7 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
     if (holder.getComponent() != null && holder.getComponent() instanceof WXCell) {
       if(holder.isRecycled()) {
         holder.bindData(component);
-        component.onRenderFinish();
+        component.onRenderFinish(STATE_UI_FINISH);
       }
       if (mDragHelper == null || !mDragHelper.isDraggable()) {
         return;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java b/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
index 1107003..43246ea 100644
--- a/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
+++ b/android/sdk/src/main/java/com/taobao/weex/utils/WXLogUtils.java
@@ -35,13 +35,12 @@ public class WXLogUtils {
   public static final String WEEX_TAG = "weex";
   public static final String WEEX_PERF_TAG = "weex_perf";
 
-  public static boolean isShowLineNumber = false;
-
   private static final String CLAZZ_NAME_DEBUG_TOOL = "com.taobao.weex.WXDebugTool";
   private static final String CLAZZ_NAME_LOG_UTIL = "com.taobao.weex.devtools.common.LogUtil";
 
   private static StringBuilder builder = new StringBuilder(50);
   private static HashMap<String, Class> clazzMaps = new HashMap<>(2);
+  private static JsLogWatcher jsLogWatcher;
 
   static {
     clazzMaps.put(CLAZZ_NAME_DEBUG_TOOL, loadClass(CLAZZ_NAME_DEBUG_TOOL));
@@ -65,14 +64,13 @@ public class WXLogUtils {
     if (WXEnvironment.isApkDebugable() || WXEnvironment.isPerf()) {
       builder.setLength(0);
       builder.append("[render time]").append(type).append(":").append(time);
-      Log.d(WEEX_PERF_TAG, getLineNumber() + builder.substring(0));
+      Log.d(WEEX_PERF_TAG, builder.substring(0));
       writeConsoleLog("debug", builder.substring(0));
     }
   }
 
   private static void log(String tag, String msg, LogLevel level){
     if (WXEnvironment.isApkDebugable() && msg != null && WXEnvironment.sLogLevel.compare(level) >= 0) {
-      msg = getLineNumber() + msg;
       Log.println(level.getPriority(),tag, msg);
       writeConsoleLog(level.getName(), msg);
       sendLog(level, msg);
@@ -109,8 +107,22 @@ public class WXLogUtils {
 
   public static void d(String tag, String msg) {
     if (WXEnvironment.isApkDebugable() && !TextUtils.isEmpty(msg) && WXEnvironment.sLogLevel.compare(LogLevel.DEBUG) >= 0) {
-      msg = getLineNumber() + msg;
       Log.d(tag, msg);
+
+      if ("jsLog".equals(tag) && jsLogWatcher != null) {
+        if (msg.endsWith("__DEBUG")) {
+          jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__DEBUG", ""));
+        } else if (msg.endsWith("__INFO")) {
+          jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__INFO", ""));
+        } else if (msg.endsWith("__WARN")) {
+          jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__WARN", ""));
+        } else if (msg.endsWith("__ERROR")) {
+          jsLogWatcher.onJsLog(Log.DEBUG, msg.replace("__ERROR", ""));
+        } else {
+          jsLogWatcher.onJsLog(Log.DEBUG, msg);
+        }
+      }
+
       /** This log method will be invoked from jni code, so try to extract loglevel from message. **/
       writeConsoleLog("debug", tag + ":" + msg);
       if(msg.contains(" | __")){
@@ -268,22 +280,11 @@ public class WXLogUtils {
     }
   }
 
-  /**
-   * Why the index is 2 ?
-   * StackTrace:
-   * 0 = com.taobao.weex.utils.WXLogUtils.getLineNumber
-   * 1 = com.taobao.weex.utils.WXLogUtils#x
-   * 2 = the actual caller
-   * …… more stack trace element
-   * */
-  private static String getLineNumber() {
-    if (!isShowLineNumber) {
-      return "";
-    }
-    StackTraceElement[] stackTrace = new Throwable().getStackTrace();
-    final int index = 2;
-    String className = stackTrace[index].getFileName();
-    int lineNum = stackTrace[index].getLineNumber();
-    return "(" + className + ":" + lineNum + ") ";
+  public static void setJsLogWatcher(JsLogWatcher watcher) {
+    jsLogWatcher = watcher;
+  }
+
+  public interface JsLogWatcher {
+    void onJsLog(int level, String log);
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/102f2ed0/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
----------------------------------------------------------------------
diff --git a/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java b/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
index ece6e0e..3fde10a 100644
--- a/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
+++ b/android/sdk/src/test/java/com/taobao/weex/utils/WXLogUtilsTest.java
@@ -46,7 +46,6 @@ public class WXLogUtilsTest {
 
   @Before
   public void setUp() throws Exception {
-    WXLogUtils.isShowLineNumber = true;
     PowerMockito.mockStatic(WXEnvironment.class);
     PowerMockito.when(WXEnvironment.isApkDebugable()).thenReturn(true);
   }