Bug 708812 - Add telemetry probes for Android startup. r=blassey
authorGian-Carlo Pascutto <gpascutto@mozilla.com>
Mon, 01 Oct 2012 22:57:00 +0200
changeset 108781 b2fa7360a9e3378de3cd0aef42f302bb618e18c0
parent 108780 b198e36a7d73dff78f0b57e8796ef28481c6c286
child 108782 ece3e81be2b68213e716f2e96edaf48a926d19d0
push id15690
push usergpascutto@mozilla.com
push dateMon, 01 Oct 2012 21:32:30 +0000
treeherdermozilla-inbound@ece3e81be2b6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey
bugs708812
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 708812 - Add telemetry probes for Android startup. r=blassey
mobile/android/base/AboutHomeContent.java.in
mobile/android/base/BrowserApp.java
mobile/android/base/GeckoApp.java
mobile/android/base/Telemetry.java
toolkit/components/telemetry/Histograms.json
--- a/mobile/android/base/AboutHomeContent.java.in
+++ b/mobile/android/base/AboutHomeContent.java.in
@@ -73,16 +73,17 @@ public class AboutHomeContent extends Sc
 
         public static final EnumSet<UpdateFlags> ALL = EnumSet.allOf(UpdateFlags.class);
     }
 
     private Context mContext;
     private BrowserApp mActivity;
     private Cursor mCursor;
     UriLoadCallback mUriLoadCallback = null;
+    VoidCallback mLoadCompleteCallback = null;
     private LayoutInflater mInflater;
 
     private AccountManager mAccountManager;
     private OnAccountsUpdateListener mAccountListener = null;
 
     protected SimpleCursorAdapter mTopSitesAdapter;
     protected GridView mTopSitesGrid;
 
@@ -94,16 +95,20 @@ public class AboutHomeContent extends Sc
 
     private View.OnClickListener mRemoteTabClickListener;
     private OnInterceptTouchListener mOnInterceptTouchListener;
 
     public interface UriLoadCallback {
         public void callback(String uriSpec);
     }
 
+    public interface VoidCallback {
+        public void callback();
+    }
+
     public AboutHomeContent(Context context) {
         super(context);
         mContext = context;
     }
 
     public AboutHomeContent(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
@@ -279,16 +284,22 @@ public class AboutHomeContent extends Sc
                     mTopSitesAdapter.changeCursor(mCursor);
                 }
 
                 updateLayout(syncIsSetup);
 
                 // Free the old Cursor in the right thread now.
                 if (oldCursor != null && !oldCursor.isClosed())
                     oldCursor.close();
+
+                // Even if AboutHome isn't necessarily entirely loaded if we
+                // get here, for phones this is the part the user initially sees,
+                // so it's the one we will care about for now.
+                if (mLoadCompleteCallback != null)
+                    mLoadCompleteCallback.callback();
             }
         });
     }
 
     void update(final EnumSet<UpdateFlags> flags) {
         GeckoAppShell.getHandler().post(new Runnable() {
             public void run() {
                 if (flags.contains(UpdateFlags.TOP_SITES))
@@ -305,16 +316,20 @@ public class AboutHomeContent extends Sc
             }
         });
     }
 
     public void setUriLoadCallback(UriLoadCallback uriLoadCallback) {
         mUriLoadCallback = uriLoadCallback;
     }
 
+    public void setLoadCompleteCallback(VoidCallback callback) {
+        mLoadCompleteCallback = callback;
+    }
+
     public void onActivityContentChanged() {
         update(EnumSet.of(UpdateFlags.TOP_SITES));
     }
 
     private void setTopSitesConstants() {
         mNumberOfTopSites = getResources().getInteger(R.integer.number_of_top_sites);
         mNumberOfCols = getResources().getInteger(R.integer.number_of_top_sites_cols);
     }
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -634,22 +634,26 @@ abstract public class BrowserApp extends
                     mAboutHomeContent.init();
                     mAboutHomeContent.update(AboutHomeContent.UpdateFlags.ALL);
                     mAboutHomeContent.setUriLoadCallback(new AboutHomeContent.UriLoadCallback() {
                         public void callback(String url) {
                             mBrowserToolbar.setProgressVisibility(true);
                             loadUrl(url, AwesomeBar.Target.CURRENT_TAB);
                         }
                     });
+                    mAboutHomeContent.setLoadCompleteCallback(new AboutHomeContent.VoidCallback() {
+                         public void callback() {
+                             mAboutHomeStartupTimer.stop();
+                         }
+                    });
                     mAboutHomeContent.setOnInterceptTouchListener(new ContentTouchListener());
                 } else {
                     mAboutHomeContent.update(EnumSet.of(AboutHomeContent.UpdateFlags.TOP_SITES,
                                                         AboutHomeContent.UpdateFlags.REMOTE_TABS));
                 }
-            
                 mAboutHomeContent.setVisibility(View.VISIBLE);
             } else {
                 findViewById(R.id.abouthome_content).setVisibility(View.GONE);
             }
         } 
     }
 
     private void addAddonMenuItem(final int id, final String label, final String icon) {
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -171,16 +171,19 @@ abstract public class GeckoApp
 
     private FullScreenHolder mFullScreenPluginContainer;
     private View mFullScreenPluginView;
 
     private HashMap<String, PowerManager.WakeLock> mWakeLocks = new HashMap<String, PowerManager.WakeLock>();
 
     protected int mRestoreMode = GeckoAppShell.RESTORE_NONE;
     protected boolean mInitialized = false;
+    protected Telemetry.Timer mAboutHomeStartupTimer;
+    private Telemetry.Timer mJavaUiStartupTimer;
+    private Telemetry.Timer mGeckoReadyStartupTimer;
 
     public enum LaunchState {Launching, WaitForDebugger,
                              Launched, GeckoRunning, GeckoExiting};
     private static LaunchState sLaunchState = LaunchState.Launching;
 
     abstract public int getLayout();
     abstract public boolean hasTabsSideBar();
     abstract protected String getDefaultProfileName();
@@ -965,16 +968,17 @@ abstract public class GeckoApp
                 final int tabId = message.getInt("tabID");
                 final String uri = message.getString("uri");
                 final String title = message.getString("title");
                 handleLoadError(tabId, uri, title);
             } else if (event.equals("Content:PageShow")) {
                 final int tabId = message.getInt("tabID");
                 handlePageShow(tabId);
             } else if (event.equals("Gecko:Ready")) {
+                mGeckoReadyStartupTimer.stop();
                 sIsGeckoReady = true;
                 setLaunchState(GeckoApp.LaunchState.GeckoRunning);
                 GeckoAppShell.sendPendingEventsToGecko();
                 connectGeckoLayerClient();
             } else if (event.equals("ToggleChrome:Hide")) {
                 toggleChrome(false);
             } else if (event.equals("ToggleChrome:Show")) {
                 toggleChrome(true);
@@ -1434,18 +1438,24 @@ abstract public class GeckoApp
                 (((screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_LARGE) || 
                  ((screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE)));
     }
 
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
+        GeckoAppShell.registerGlobalExceptionHandler();
+
+        // The clock starts...now. Better hurry!
+        mJavaUiStartupTimer = new Telemetry.Timer("FENNEC_STARTUP_TIME_JAVAUI");
+        mAboutHomeStartupTimer = new Telemetry.Timer("FENNEC_STARTUP_TIME_ABOUTHOME");
+        mGeckoReadyStartupTimer = new Telemetry.Timer("FENNEC_STARTUP_TIME_GECKOREADY");
+
         ((GeckoApplication)getApplication()).initialize();
-        GeckoAppShell.registerGlobalExceptionHandler();
 
         mAppContext = this;
         Tabs.getInstance().attachToActivity(this);
 
         // Check to see if the activity is restarted after configuration change.
         if (getLastNonConfigurationInstance() != null) {
             // Restart the application as a safe way to handle the configuration change.
             doRestart();
@@ -1685,16 +1695,19 @@ abstract public class GeckoApp
                                            (TextSelectionHandle) findViewById(R.id.middle_handle),
                                            (TextSelectionHandle) findViewById(R.id.end_handle),
                                            GeckoAppShell.getEventDispatcher());
 
         UpdateServiceHelper.registerForUpdates(this);
 
         final GeckoApp self = this;
 
+        // End of the startup of our Java App
+        mJavaUiStartupTimer.stop();
+
         GeckoAppShell.getHandler().postDelayed(new Runnable() {
             public void run() {
                 Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - pre checkLaunchState");
                 // Sync settings need Gecko to be loaded, so
                 // no hurry in starting this.
                 checkMigrateSync();
 
                 /*
--- a/mobile/android/base/Telemetry.java
+++ b/mobile/android/base/Telemetry.java
@@ -32,23 +32,32 @@ public class Telemetry {
         } catch (JSONException e) {
             Log.e(LOGTAG, "JSON exception: ", e);
         }
     }
 
     public static class Timer {
         private long mStartTime;
         private String mName;
+        private boolean mHasFinished;
 
         public Timer(String name) {
             mName = name;
             mStartTime = SystemClock.uptimeMillis();
+            mHasFinished = false;
         }
 
         public void stop() {
+            // Only the first stop counts.
+            if (mHasFinished) {
+                return;
+            } else {
+                mHasFinished = true;
+            }
+
             long elapsed = SystemClock.uptimeMillis() - mStartTime;
             if (elapsed < Integer.MAX_VALUE) {
                 HistogramAdd(mName, (int)(elapsed));
             } else {
                 Log.e(LOGTAG, "Duration of " + elapsed + " ms is too long.");
             }
         }
     }
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -21,24 +21,16 @@
     "description": "has XForms accessibility been instantiated"
   },
   "A11Y_UPDATE_TIME": {
     "kind": "exponential",
     "high": "10000",
     "n_buckets": 50,
     "description": "time spent updating accessibility (ms)"
   },
-  "FENNEC_AWESOMEBAR_ALLPAGES_EMPTY_TIME": {
-    "kind": "exponential",
-    "low": 10,
-    "high": "20000",
-    "n_buckets": 20,
-    "description": "Fennec: Time for the Awesomebar Top Sites query to return with no filter set (ms)",
-    "cpp_guard": "ANDROID"
-  },
   "CYCLE_COLLECTOR": {
     "kind": "exponential",
     "high": "10000",
     "n_buckets": 50,
     "description": "Time spent on one cycle collection (ms)"
   },
   "CYCLE_COLLECTOR_VISITED_REF_COUNTED": {
     "kind": "exponential",
@@ -2238,16 +2230,48 @@
   },
   "BROWSERPROVIDER_XUL_IMPORT_HISTORY": {
     "kind": "exponential",
     "high": "1000000",
     "n_buckets": 20,
     "description": "Number of history entries in the original XUL places database",
     "cpp_guard": "ANDROID"
   },
+  "FENNEC_AWESOMEBAR_ALLPAGES_EMPTY_TIME": {
+    "kind": "exponential",
+    "low": 10,
+    "high": "20000",
+    "n_buckets": 20,
+    "description": "Fennec: Time for the Awesomebar Top Sites query to return with no filter set (ms)",
+    "cpp_guard": "ANDROID"
+  },
+  "FENNEC_STARTUP_TIME_JAVAUI": {
+    "kind": "exponential",
+    "low": 100,
+    "high": "5000",
+    "n_buckets": 20,
+    "description": "Time for the Java UI to load (ms)",
+    "cpp_guard": "ANDROID"
+  },
+  "FENNEC_STARTUP_TIME_ABOUTHOME": {
+    "kind": "exponential",
+    "low": 100,
+    "high": "10000",
+    "n_buckets": 20,
+    "description": "Time for the about:home page to be displayed (ms)",
+    "cpp_guard": "ANDROID"
+  },
+  "FENNEC_STARTUP_TIME_GECKOREADY": {
+    "kind": "exponential",
+    "low": 500,
+    "high": "20000",
+    "n_buckets": 20,
+    "description": "Time for the Gecko:Ready message to arrive (ms)",
+    "cpp_guard": "ANDROID"
+  },
   "OUT_OF_MEMORY_KILLED": {
     "kind": "flag",
     "description": "Killed due to an OOM condition",
     "cpp_guard": "ANDROID"
   },
   "SECURITY_UI": {
     "kind": "enumerated",
     "n_values": 100,