Intro Hi I'm Jimmy, I'm an intern on the desktop firefox e10s team. I enjoy long walks on the beach, and reliable & fast wifi connections. My mentor is Neil Deakin. My manger is Dave Townsend
What is Electrolysis? (“e10s” for short) •Separate chrome code from content code • chrome process [parent process] • content process [child process] • First iteration •all browser tabs run in the same content process • Future iteration •We expect to have more than one content process.
Benefits of e10s Show me the money •Benefits: •UI doesn't hang. •Better performance •2 processes can do more since they're asynchronous and operations don't block. •If a tab crashes it doesn't crash the browser
So why does it break everything? •Existing code behaviour: •Browser UI accessing web page content and using it like it was in the same process. •Some code just doesn't work in the content process. •Ex. setting prefs, downloading files
Migrating to e10s 1. CPOWs (Cross-process object wrappers) •A way to allow code in the parent process to access objects in the child process synchronously. •Created using the message manager. •The parent waits for a response from the child. gWindow = window.opener.gBrowser.selectedBrowser.contentWindowAsCPOW; gDocument = gWindow.document; //also a CPOW. CPOWs can only beget more CPOWs gDocument.title if (gDocument instanceof ImageDocument) imageText = item.title || item.alt; In Chrome process
Migrating to e10s 2. Eventually removing CPOWs and writing content & chrome scripts. And having them communicate via messages. Because every property access sends a message, CPOWs can be slow to use. There is no caching, so 1,000 accesses to the same property will send 1,000 messages. - Bill McCloskey CPOWs are easier than converting existing code to be asynchronous
Talos (Windows) Test Win or Loss Tp5 Responsiveness 90% improvement Tp5 Scroll 13% improvement SVG 22% improvement SVG Transparent 54% improvement Simple Paint (ts_paint) 55% improvement Tpaint, tart, canvasmark, webgl 2-3% improvement A11y 8% regression Tp5 Optimized 9% regression Other tests Within margin of error or no data* SEE META BUG 1144120 FOR CURRENT DATA *kraken, v8_7, dromaeo_css, dromaeo_dom, sessionrestore, sessionrestore_no_auto_restore Credit: Jim Mathies (IRC: jimm)
Culprit browser/base/content/pageinfo/pageInfo.js function onLoadPageInfo() { gWindow = window.opener.gBrowser.selectedBrowser.contentWindowAsCPOW; gDocument = gWindow.document; ... //call other functions. Do stuff } function goThroughFrames(gDocument, gWindow) { gFrameList.push(gDocument); if (gWindow && gWindow.frames.length > 0) { var num = aWindow.frames.length; for (var i = 0; i < num; i++) goThroughFrames(gWindow.frames[i].document, gWindow.frames[i]); } } function processFrames() { if (gFrameList.length) { var doc = gFrameList[0]; onProcessFrame.forEach(function(func) { func(doc); }); var iterator = doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, grabAll); gFrameList.shift(); } }
Culprit browser/base/content/pageinfo/pageInfo.js function onLoadPageInfo() { gWindow = window.opener.gBrowser.selectedBrowser.contentWindowAsCPOW; gDocument = gWindow.document; ... //call other functions. Do stuff } function goThroughFrames(gDocument, gWindow) { gFrameList.push(gDocument); if (gWindow && gWindow.frames.length > 0) { var num = aWindow.frames.length; for (var i = 0; i < num; i++) goThroughFrames(gWindow.frames[i].document, gWindow.frames[i]); } } function processFrames() { if (gFrameList.length) { var doc = gFrameList[0]; onProcessFrame.forEach(function(func) { func(doc); }); var iterator = doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, grabAll); gFrameList.shift(); } }
Culprit It's attempting to walk the DOM tree of the contentDocument CPOW to get information about various scripts, images, etc. unsafe usage of CPOWs. var iterator = doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, grabAll); 190 unsafe CPOW warnings are from this alone!
Why are some CPOW usage unsafe? Why are they slower? Both chrome process get blocked by CPOW usage. Especially noticeable for dom walker var iterator = doc.createTreeWalker(doc, NodeFilter.SHOW_ELEMENT, grabAll); Instead of asking for the whole book, you’re asking for page by page - Mike Conley
How Do We Fix This? Break pageinfo.js into a content process script and chrome process script. •Do the fetching of the web page •metadata, •media elements, •feeds, •info for permissions + security tabs in the content script. Send the info back to the parent process.
Chrome process browser/base/content/pageinfo/pageInfo.js Uses: browser/base/content/pageinfo/feeds.js browser/base/content/pageinfo/security.js browser/base/content/pageinfo/permissions.js Content process browser/base/content/content.js (already loaded on content page whenever a tab is opened)
browser/base/content/content.js let pageInfoListener = { init: function() { addMessageListener("PageInfo:getData", this, false, true); }, receiveMessage: function(message) { let frameOuterWindowID = message.data.frameOuterWindowID; // If inside frame then get the frame's window and document. if (frameOuterWindowID) { this.window = Services.wm.getOuterWindowWithId(frameOuterWindowID); this.document = this.window.document; } else { this.document = content.document; this.window = content.window; } let pageInfoData = {metaViewRows: this.getMetaInfo(), docInfo: this.getDocumentInfo(), feeds: this.getFeedsInfo(), windowInfo: this.getWindowInfo()}; sendAsyncMessage("PageInfo:data", pageInfoData); // Separate step so page info dialog isn't blank while waiting for this to finish. this.getMediaInfo(); // Send the message after all the media elements have been walked through. let pageInfoMediaData = {imageViewRows: this.imageViewRows}; sendAsyncMessage("PageInfo:mediaData", pageInfoMediaData); }, } pageInfoListener.init();
browser/base/content/content.js let pageInfoListener = { init: function() { addMessageListener("PageInfo:getData", this, false, true); }, receiveMessage: function(message) { let frameOuterWindowID = message.data.frameOuterWindowID; // If inside frame then get the frame's window and document. if (frameOuterWindowID) { this.window = Services.wm.getOuterWindowWithId(frameOuterWindowID); this.document = this.window.document; } else { this.document = content.document; this.window = content.window; } let pageInfoData = {metaViewRows: this.getMetaInfo(), docInfo: this.getDocumentInfo(), feeds: this.getFeedsInfo(), windowInfo: this.getWindowInfo()}; sendAsyncMessage("PageInfo:data", pageInfoData); // Separate step so page info dialog isn't blank while waiting for this to finish. this.getMediaInfo(); // Send the message after all the media elements have been walked through. let pageInfoMediaData = {imageViewRows: this.imageViewRows}; sendAsyncMessage("PageInfo:mediaData", pageInfoMediaData); }, } pageInfoListener.init();
•Separate chrome process code from content process code •Build up data and send it to parent in a message. •Retains same functionality. but does it safely now. Takeaway
Why doesn’t it work? Light Weight Web Themes were installed by having our browser listen in the chrome process for these event from the theme web page “InstallBrowserTheme" "PreviewBrowserTheme" "ResetBrowserThemePreview"
How Do We Fix This? The chrome process will not have access to the content process so it can't listen for events. Instead you should: 1. Listen for the event in the content process 2. Send a message to the chrome process letting them know about the type of event
Let’s ship e10s faster Test addons arewee10syet.com (blue untested) Report their status in e10s so we know which ones still don't work with e10s When filing a new bug •please add the flag •tracking-e10s:? •place 'e10s' in the bug title •so that it shows up in the team's weekly triage bug list. Work on e10s Bugs. Frontend bugs: https:/ /bugzilla.mozilla.org/show_bug.cgi?id=core-e10s Backend bugs: https:/ /bugzilla.mozilla.org/show_bug.cgi?id=fxe10s IRC: #e10s on irc.mozilla.org People involved in e10s: https:/ /wiki.mozilla.org/Electrolysis#People