Start-up performance on mobile

144 views
Skip to first unread message

Mihai Sardarescu

unread,
Feb 26, 2013, 8:09:42 AM2/26/13
to chromi...@chromium.org, William Chan, Jeremy Moskovich, Susanna Leng, Stuart Morgan
I am working on improving the start-up performance for Chrome on iOS.

We have done a lot of testing around start-up and it looks like starting the application with a larger profile is slower than starting it with a rather empty one. In our case, having a large profile adds up to 1 second to the start-up time. We have profiled the application and it seems that creating the profile is rather cheap (around 20 ms), however creating its services leads to lots of work being done at start-up on background threads. This is expensive during start-up especially when running on a mobile device with low resources (the main thread is interrupted by the background ones).

For example, when we create the first tab, we create the FaviconService (via FaviconServiceFactory), which instantiates HistoryService (via HistoryServiceFactory), which instantiates the BookmarkModel (via BookmarkModelFactory). The BookmarkModelFactory triggers the load of the bookmarks on a background thread. The HistoryService does something similar. These dependency links are hard to follow and it's going to be very hard to remove the expensive services from start-up on iOS.

It would be great to only start loading all these data once the application is ready - the UI would be available faster for the user. The same could be said for other moments during the application's lifecycle - for example during a low memory warning, it would be wiser to avoid loading data from disk.

We would have the following 2 proposals on how to improve this:

1. Have a general flag that tells the services whether or not they should start loading data from disk when they are created. This flag could be added to g_browser_test. When the application is ready (start-up is done etc.), it could post a notification that informs the profile services they can start loading their data from disk.

2. Expensive services should load their data using blocking pools. On mobile we would create these blocking pools at start-up, but only start them after start-up has finished. On desktop we would create and start these blocking pools at start-up.

What is the right way of addressing this? Do you have a better solution?

Anton Vayvod

unread,
Feb 26, 2013, 8:27:40 AM2/26/13
to msa...@chromium.org, chromium-dev, William Chan, Jeremy Moskovich, Susanna Leng, Stuart Morgan, Anthony Berent
+Anthony, if he has any insights from Chrome on Android point of view.


--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
 
 
 

Jeremy Moskovich

unread,
Feb 26, 2013, 8:50:03 AM2/26/13
to Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
Just to note that for the desktop case, when we measured this a few months back - profile size did not appear to affect startup time*.  It's quite possible however that this was due to the profiles we picked (large profile built up over time by QA vs a fresh profile in our case).

Best regards,
Jeremy
* Measured on an old Mac laptop with a slow HD and disk caches purged.

Scott Violet

unread,
Feb 26, 2013, 11:04:41 AM2/26/13
to msa...@chromium.org, chromi...@chromium.org, William Chan, Jeremy Moskovich, Susanna Leng, Stuart Morgan
A magical flag that indicates when services should load their data
seems too error prone. I prefer figuring out what is triggering the
creation of the services in the first place and attempting to break
those.

-Scott

Drew Wilson

unread,
Feb 26, 2013, 11:17:56 AM2/26/13
to Scott Violet, msa...@chromium.org, Chromium-dev, William Chan, Jeremy Moskovich, Susanna Leng, Stuart Morgan
I don't know that Mihai's specific suggestion is a good one, but "when should my service initialize itself" is one of the great unsolved problems in Chrome.

For example, both Sync and CloudPolicy have some locally cached state that they want to update from the cloud when a profile is loaded. They probably don't want to do it immediately on profile startup, because in general the cached data is sufficient and we want to decrease contention during startup. But we don't really want to sit around with data that's potentially out-of-date, so we want to initialize the service and perform an update "soon".

The canonical solution seems to be to set a timer to some random value (30 seconds!) and then kick off your delayed initialization, but that's totally hacky. Ideally we'd have a better solution that a) ensured that services can do their background initialization in a timely manner and b) avoids contention between service initialization and user activity/other services also trying to initialize themselves.

-atw

Marcus Bulach

unread,
Feb 26, 2013, 11:45:50 AM2/26/13
to atwi...@chromium.org, Scott Violet, msa...@chromium.org, Chromium-dev, William Chan, Jeremy Moskovich, Susanna Leng, Stuart Morgan
In chrome for android, we tried to split the initialization of our UI (which happens before the native c/c++ gets started) in different "continuations", to try to mimic some different levels of "criticality":

We first kick off loading the .so in a separate thread, then we start initializing visible UI elements, then we bind the native side, and so on and so forth..

Of course, we don't have truly well defined boundaries for this various levels of critical path, but at least we try not to add anything else to the "level 0", sort of speaking.

I fully agree with drew that this is one of the "great unsolved problems" in chrome :) and I'd be very happy to try to help!

Perhaps we could define such levels more explicitly and consistently across platforms, would that make any sense? 
In Android, we have essentially "critical 0", then "critical with native", then "deferred with native" then finally "background tasks", but surely we could do something for fine grained..

Thanks,
Marcus

Jeremy Moskovich

unread,
Feb 28, 2013, 7:31:03 AM2/28/13
to Drew Wilson, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
"service initialization" and "perform IO that isn't strictly needed at early startup" are two phases that seem to exist in several of our services.  Might be good to explicitly separate them.

Drew: Might be preferable to wait for NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME rather than using a timer, since then you won't be contending with first page load.

Drew Wilson

unread,
Feb 28, 2013, 9:02:52 AM2/28/13
to Jeremy Moskovich, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
How does NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME work in the case that you are launched in background mode (no open windows)?

Jeremy Moskovich

unread,
Feb 28, 2013, 9:29:26 AM2/28/13
to Drew Wilson, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
I confess to not knowing anything about background mode, but if there's a background page then it should fire for that page, right?

Drew Wilson

unread,
Feb 28, 2013, 9:42:05 AM2/28/13
to Jeremy Moskovich, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
I don't know under what circumstances LOAD_COMPLETED_MAIN_FRAME is fired. Are you saying this is fired for things like extension background pages?

Also, background mode doesn't mean there are background pages. Heck, on Mac a user can just set the "Launch at Login" flag on Chrome and it'll launch with no open windows and no background pages at all (assuming there aren't any extensions/apps installed).

Jeremy Moskovich

unread,
Mar 3, 2013, 7:50:33 AM3/3/13
to Drew Wilson, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
You're right of course, the notification doesn't fire for a windowless launch.

WDYT of adding a new notification specifically for when it's safe to do init work that we don't want to block first page load?

Jonathan Dixon

unread,
Mar 3, 2013, 6:58:56 PM3/3/13
to Jeremy Moskovich, Drew Wilson, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
On 3 March 2013 04:50, Jeremy Moskovich <jer...@chromium.org> wrote:
You're right of course, the notification doesn't fire for a windowless launch.

WDYT of adding a new notification specifically for when it's safe to do init work that we don't want to block first page load?


That would work well for Android too. Right now it's hanging lazy background startup off of the first 'on page finished' event (plus 0.5 second, plus the next message loop idle event, IIRC), but having a common signal to trigger this would be more robust. e.g. hypothetically  if the NTP were re-implemented as native controls, the current design would break

Jeremy Moskovich

unread,
Mar 4, 2013, 3:09:34 AM3/4/13
to jo...@chromium.org, Drew Wilson, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
Tracking at crbug.com/179779

Drew Wilson

unread,
Mar 4, 2013, 3:14:47 AM3/4/13
to Jeremy Moskovich, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
I'd be fine with such a notification as a start. My main concern is that contention that starts *just after* the first browser loads is no better than contention that prevents the first browser window from opening - in either case, the user is going to notice slowness when trying to use Chrome.

I don't know what the right solution is, but I figure having several services suddenly dump network requests onto the I/O thread at the same time will cause noticeable jank for the user, so it'd be good if we could smooth out this background initialization somehow. But definitely this notification is a good start.

Jeffrey Yasskin

unread,
Mar 4, 2013, 1:16:51 PM3/4/13
to atwi...@chromium.org, Jeremy Moskovich, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
What about a TaskRunner instead? A component that needs initialization
would add a task, and the browser could start tasks gradually as it
wasn't too loaded. Any single event that starts all of the "soon after
start" services is going to cause galloping-herd problems.

Drew Wilson

unread,
Mar 5, 2013, 3:54:16 AM3/5/13
to Jeffrey Yasskin, Jeremy Moskovich, Scott Violet, Mihai Sardarescu, Chromium-dev, William Chan, Susanna Leng, Stuart Morgan
I like this solution. If we fire off the tasks in the order in which they are added, then the task ordering will match the order in which ProfileKeyedServices are initialized, which means we inherit their dependency ordering for free.

The only downside of a TaskRunner-based solution is that a component has no way of signaling when its background initialization is done, so I guess the way this would work is we'd just blindly fire off the next task in the queue every XXX milliseconds. This means we don't have perfect serializing of requests (resulting in idle time during which no tasks are being executed, or overlapping task execution which means a service you depend on may not be fully initialized when your task is executed).

I think in practice this would be fine, though, and would be pretty easy to maintain.

Mihai Sardarescu

unread,
Mar 13, 2013, 1:26:24 PM3/13/13
to chromi...@chromium.org, Jeffrey Yasskin, Jeremy Moskovich, Scott Violet, Mihai Sardarescu, William Chan, Susanna Leng, Stuart Morgan
I have tried to implement the solution with the TaskRunner for the load of the bookmarks. Here are the issues I've encountered so far:
1. The bookmark model uses the profile's IOTaskRunner which starts its threads as soon as the first task is posted. There is no API to start the threads of a TaskRunner later or to add a delay between the task execution.
2. All bookmarks are loaded in a single task, so using a delay between tasks does not change anything for the bookmarks. I need to be able to delay the execution after the start-up is done.
3. I've noticed that the bookmarks are the only service that use a Task Runner - I think the other just create their own threads (i.e. the history service).

I guess my questions are:
1. Should I add support for the Task Runners to start the threads later than when the first task is posted?
2. Should I use a different SequencedTaskRunner for the bookmarks instead of using the profile's IOTaskRunner?
3. Should different services have independent TaskRunners, or should they share them?

PS: For the bookmarks I can use a hack: post a 2 second delay task on the profile's IOTaskRunner before any work is done. This will delay all tasks on the IOTaskRunner as it is a SequencedTaskRunner.

Jeffrey Yasskin

unread,
Mar 13, 2013, 2:54:11 PM3/13/13
to Mihai Sardarescu, chromium-dev, Jeremy Moskovich, Scott Violet, William Chan, Susanna Leng, Stuart Morgan
If I were doing this, I'd write a new TaskRunner implementation just
for this purpose. Instantiate it once (per profile?), add one task for
each service, and have that task bounce over to the appropriate
TaskRunner for the service.

We're likely to want to play with different strategies for kicking off
tasks. Maybe we'll want a single method that's called N seconds after
startup, which then runs tasks every M seconds. Maybe we'll want a
method that's called when other TaskRunners are idle, and then waits N
seconds after all of them are idle before running the next task. Maybe
we'll want to give service loaders a completion callback, which tells
the "startup" TaskRunner that it can move on to the next service.
Maybe we'll want a way to eagerly start a service when, for example,
the user tries to open the bookmarks manager before it's loaded.
I'd do the simplest thing for now, but leave room for that kind of
experimentation.
Reply all
Reply to author
Forward
0 new messages