Confirmed users
130
edits
Wmccloskey (talk | contribs) (add examples) |
Wmccloskey (talk | contribs) m (minor fixes) |
||
Line 2: | Line 2: | ||
The goal of the Quantum DOM project is to eliminate jank from background tabs. One of the main ways we intend to do this is to run each tab in its own cooperatively scheduled thread. If a runnable on a background thread takes too long to run, then we will pause its execution and switch to a different thread. To do this correctly, we need to guarantee that web pages never observe a change in behavior. For example, it would be bad if we paused a runnable R1 and then allowed another runnable R2 from the same page to see that R1 had started but not yet finished. | The goal of the Quantum DOM project is to eliminate jank from background tabs. One of the main ways we intend to do this is to run each tab in its own cooperatively scheduled thread. If a runnable on a background thread takes too long to run, then we will pause its execution and switch to a different thread. To do this correctly, we need to guarantee that web pages never observe a change in behavior. For example, it would be bad if we paused a runnable R1 and then allowed another runnable R2 from the same page to see that R1 had started but not yet finished. | ||
One of the biggest pieces of the project is to "label" runnables with the page that they're operating on. This page describes how to label runnables. | |||
= Concepts = | = Concepts = | ||
Line 11: | Line 13: | ||
A DocGroup is the collection of documents from a given TabGroup that share the same eTLD+1 part of their origins. So if a TabGroup contains tabs with documents {x.a.com, y.a.com, x.b.com, y.b.com}, then these documents will belong to two DocGroups: {x.a.com, y.a.com}, {x.b.com, y.b.com}. DocGroups are essentially a refinement of TabGroups to account for the fact that only same-origin documents can synchronously communicate. (The eTLD+1 part is to account for pages changing their origin by modifying document.domain.) So a runnable from one DocGroup can run while a runnable from a different DocGroup is paused. | A DocGroup is the collection of documents from a given TabGroup that share the same eTLD+1 part of their origins. So if a TabGroup contains tabs with documents {x.a.com, y.a.com, x.b.com, y.b.com}, then these documents will belong to two DocGroups: {x.a.com, y.a.com}, {x.b.com, y.b.com}. DocGroups are essentially a refinement of TabGroups to account for the fact that only same-origin documents can synchronously communicate. (The eTLD+1 part is to account for pages changing their origin by modifying document.domain.) So a runnable from one DocGroup can run while a runnable from a different DocGroup is paused. | ||
A major task for the Quantum DOM project is to | Given a document, you can find its DocGroup via nsIDocument::GetDocGroup. Given an inner or outer window, you can find its TabGroup and DocGroup via nsPIDOMWindow::{TabGroup,GetDocGroup}. These methods should only be called on the main thread. | ||
A major task for the Quantum DOM project is to label runnables with DocGroups or TabGroups. Ideally we would assign all runnables a DocGroup. But in some cases the best we can do is to give it a TabGroup. | |||
= | = Labeling = | ||
Based on how it is dispatched, there are multiple ways to label a runnable. The simplest way is to provide the DocGroup or TabGroup when dispatching the runnable. | |||
== Dispatching == | == Dispatching == | ||
Both the TabGroup and DocGroup classes have Dispatch methods to dispatch runnables. Runnables dispatched in this way will always run on the main thread. You can call Dispatch from any thread. Both TabGroup and DocGroup are threadsafe refcounted. The Dispatch method requires you to name the runnable and provide a category. For now, these are for debugging purposes, but the category may be used for scheduling purposes later on. | Both the TabGroup and DocGroup classes have Dispatch methods to dispatch runnables. Runnables dispatched in this way will always run on the main thread. You can call Dispatch from any thread. Both TabGroup and DocGroup are threadsafe refcounted. The Dispatch method requires you to name the runnable and provide a "task category". For now, these are for debugging purposes, but the category may be used for scheduling purposes later on. | ||
As a convenience, nsIDocument and nsIGlobalObject have a Dispatch method that will dispatch to their DocGroup. The nsIDocument::Dispatch method can be used on any thread (although you must be careful because nsIDocument is not threadsafe refcounted). The nsIGlobalObject::Dispatch method is main thread only. | As a convenience, nsIDocument and nsIGlobalObject have a Dispatch method that will dispatch to their DocGroup. The nsIDocument::Dispatch method can be used on any thread (although you must be careful because nsIDocument is not threadsafe refcounted). The nsIGlobalObject::Dispatch method is main thread only. | ||
Line 25: | Line 29: | ||
=== Example === | === Example === | ||
Suppose you have a runnable that is dispatched to the main thread. | Suppose you have a runnable that is dispatched to the main thread. To convert this code, we simply call Dispatch on the document. Her is a diff showing the changes: | ||
/* virtual */ void | |||
nsDocument::PostVisibilityUpdateEvent() | |||
{ | |||
nsCOMPtr<nsIRunnable> event = | |||
NewRunnableMethod(this, &nsDocument::UpdateVisibilityState); | |||
- NS_DispatchToMainThread(event); | |||
+ Dispatch("UpdateVisibility", TaskCategory::Other, event.forget()); | |||
} | |||
As a more complex example, consider off-thread script parsing. When parsing is done, a NotifyOffThreadScriptLoadCompletedRunnable runnable is posted to the main thread. We can modify this code by | As a more complex example, consider off-thread script parsing. When parsing is done, a NotifyOffThreadScriptLoadCompletedRunnable runnable is posted to the main thread. We can modify this code by finding the DocGroup while still on the main thread, storing it in the runnable, and then dispatching to that DocGroup off the main thread: | ||
class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable | class NotifyOffThreadScriptLoadCompletedRunnable : public Runnable | ||
Line 60: | Line 55: | ||
, mLoader(aLoader) | , mLoader(aLoader) | ||
+ , mDocGroup(aLoader->GetDocGroup()) | + , mDocGroup(aLoader->GetDocGroup()) | ||
{} | { MOZ_ASSERT(NS_IsMainThread(); } | ||
... | |||
} | |||
For this to work, we need to instrument the nsScriptLoader with a DocGroup method. That's very easy though: | For this to work, we need to instrument the nsScriptLoader with a DocGroup method. That's very easy though: | ||
Line 95: | Line 92: | ||
} | } | ||
When using EventTargetFor, please try to set the name of the runnable as well. For timers, the name of the timer runnable is derived from the name of the nsITimerCallback (via a GetName method). XMLHttpRequestMainThread implements nsITimerCallback, so we just need to add a GetName method: | When using EventTargetFor, please try to set the name of the runnable as well. For timers, the name of the timer runnable is derived from the name of the nsITimerCallback (via a GetName method on nsITimerCallback). XMLHttpRequestMainThread implements nsITimerCallback, so we just need to add a GetName method: | ||
nsresult | nsresult | ||
Line 110: | Line 107: | ||
=== Example === | === Example === | ||
Most networking data comes in via the HttpChannelChild actor. We first create a method that finds the correct event target via the LoadInfo | Most networking data comes in via the HttpChannelChild actor. We first create a method that finds the correct event target via the LoadInfo. | ||
void | void |