Shutting down things asynchronously

February 14, 2014 § Leave a comment

This blog entry is part of the Making Firefox Feel As Fast As Its Benchmarks series. The fourth entry of the series was growing much too long for a single blog post, so I have decided to cut it into bite-size entries.

A long time ago, Firefox was completely synchronous. One operation started, then finished, and then we proceeded to the next operation. However, this model didn’t scale up to today’s needs in terms of performance and performance perception, so we set out to rewrite the code and make it asynchronous wherever it matters. These days, many things in Firefox are asynchronous. Many services get started concurrently during startup or afterwards. Most disk writes are entrusted to an IO thread that performs and finishes them in the background, without having to stop the rest of Firefox.

Needless to say, this raises all sorts of interesting issues. For instance: « how do I make sure that Firefox will not quit before it has finished writing my files? » In this blog entry, I will discuss this issue and, more generally, the AsyncShutdown mechanism, designed to implement shutdown dependencies for asynchronous services.

« Read the rest of this entry »

Trapping uncaught asynchronous errors

October 14, 2013 § 2 Comments

While the official specifications of DOM Promise is still being worked on, Mozilla has been using Promise internally for several years already. This API is available to the platform front-end and to add-ons. In the past few weeks, Promise.jsm (our implementation of Promise) and Task.jsm (our implementation of Beautiful Concurrency in JavaScript, built on top of Promise) have been updated with a few new features that should make everybody’s life much easier.

Reporting errors

The #1 issue developers encounter with the use of Promise and Task is error-handling. In non-Promise code, if a piece of code throws an error, by default, that error will eventually be reported by window.onerror or any of the other error-handling mechanisms.

function fail() {
  let x;
  return x.toString();
}

fail(); // Displays somewhere: "TypeError: x is undefined"

By opposition, with Promise and/or Task, if a piece of code throws an error or rejects, by default, this error will be completely ignored:

Task.spawn(function*() {
  fail(); // Error is ignored
});

 

Task.spawn(function*() {
  yield fail(); // Error is ignored
});

 

somePromise.then(function onSuccess() {
  fail(); // Error is ignored
});

 

somePromise.then(function onSuccess() {
  return fail(); // Error is ignored
});

Debugging the error requires careful instrumentation of the code, which is error-prone, time-consuming, often not compositional and generally ugly to maintain:

Task.spawn(function*() {
  try {
    fail();
  } catch (ex) {
    Components.utils.reportError(ex);
    throw ex;
    // The error report is incomplete, re-throwing loses stack information
    // and can cause double-reporting
  }
});

The main reason we errors end up dropped silently is that it is difficult to find out whether an error is eventually caught by an error-handler – recall that, with Promise and Task, error handlers can be registered long after the error has been triggered.

Well, after long debates, we eventually found solutions to fix the issue :)

Simple case: Reporting programming errors

Our first heuristic is that programming errors are, well, programming errors, and that programmers are bound to be looking for them.

So,

Task.spawn(function*() {
  fail(); // Error is not invisible anymore
});

will now cause the following error message

*************************
A coding exception was thrown and uncaught in a Task.

Full message: TypeError: x is undefined
Full stack: fail@Scratchpad/2:23
@Scratchpad/2:27
TaskImpl_run@resource://gre/modules/Task.jsm:217
TaskImpl@resource://gre/modules/Task.jsm:182
Task_spawn@resource://gre/modules/Task.jsm:152
@Scratchpad/2:26
*************************

The message appears on stderr (if you have launched Firefox from the command-line) and in the system logs, so it won’t disrupt your daily routine, but if you are running tests or debugging your code, you should see it.

A similar error message will be printed out if the error is thrown from a raw Promise, without use of Task.

These error messages are limited to programming errors and appear only if the errors are thrown, not passed as rejections.

General case: Reporting uncaught errors

Now, we have just landed a more general support for displaying uncaught errors.

Uncaught thrown error

Task.spawn(function* () {
  throw new Error("BOOM!"); // This will be displayed
});

Uncaught rejection

Task.spawn(function* () {
  yield Promise.reject("BOOM!"); // This will also be displayed
});

Uncaught and clearly incorrect rejection

Task.spawn(function* () {
  Promise.reject("BOOM!");
  // Oops, forgot to yield.
  // Nevermind, this will be displayed, too
});

These will be displayed in the browser console as follows:

A promise chain failed to handle a rejection: on Mon Oct 14 2013 16:50:15 GMT+0200 (CEST), Error: BOOM! at
@Scratchpad/2:27
TaskImpl_run@resource://gre/modules/Task.jsm:217
TaskImpl@resource://gre/modules/Task.jsm:182
Task_spawn@resource://gre/modules/Task.jsm:152
@Scratchpad/2:26

These error messages appear for every uncaught error or rejection, once it is certain that the error/rejection cannot be caught anymore. If you are curious about the implementation, just know that it hooks into the garbage-collector to be informed once the error/promise cannot be caught anymore.

This should prove very helpful when debugging Promise- or Task-related errors. Have fun :)

Support for ES6 generators

You may have noticed that the above examples use function*() instead of function(). Be sure to thank Brandon Benvie who has recently updated Task.jsm to be compatible with ES6 generators :)

Project Async & Responsive, issue 1

April 26, 2013 § 3 Comments

In the previous episodes

Our intrepid heroes, a splinter cell from Snappy, have set out on a quest to offer alternatives to all JavaScript-accessible APIs that blocks the main thread of Firefox & Mozilla Apps.

Recently completed

Various cleanups on Session Restore (Bug 863227, 862442, 861409)

Summary Currently, we regularly (~every 15 seconds) save the state of every single window, tab, iframe, form being displayed, so as to be able to restore the session quickly in case of crash, power failure, etc. As this can be done only on the main thread, just the jank of data collection is often noticeable (i.e. > 50 ms). We are in the process of refactoring Session Restore to make it both faster and more responsive. These bugs are steps towards optimizations.

Status Landed. More cleanups in progress.

Telemetry for Number of Threads (Bug 724368)

Summary As we make Gecko and add-ons more and more concurrent, we need to measure whether this concurrency can cause accidental internal Denial of Service. The objective of this bug is to measure.

Status Landed. You can follow progression in histograms BACKGROUNDFILESAVER_THREAD_COUNT and SIMPLEMEASURES_MAXIMALNUMBEROFCONCURRENTTHREADS.

Reduce number of fsync() in Firefox Health Report (Bug 830492)

Summary Firefox Health Report stores its data using mozStorage. The objective of this bug is to reduce the number of expensive disk synchronizations performed by FHR.

Status Landed.

Ongoing bugs

Out Of Process Thumbnailing (Bug 841495)

Summary Currently, we capture thumbnails of all pages, e.g. for display in about:newtab, in Panorama or in add-ons. This blocks the main thread temporarily. This bug is about using another process to capture thumbnails of pages currently being visited. This can be useful for both security/privacy reasons (i.e. to ensure that bank account numbers do not show up in thumbnails) and responsiveness (i.e. to ensure that we never block browsing).

Status In progress.

Cutting Session Restore data collection into chunks (Bug 838577)

Summary Currently, we regularly (~every 15 seconds) save the state of every single window, tab, iframe, form being displayed, so as to be able to restore the session quickly in case of crash, power failure, etc. As this can be done only on the main thread, just the jank of data collection is often noticeable (i.e. > 50 ms). This bug is about cutting data collection in smaller chunks, to remove that jank.

Status Working prototype.

Off Main Thread database storage (Bug 702559)

Summary We are in the process of moving as many uses of mozStorage out of the main thread. While mozStorage already supports doing much I/O off the main thread, there is no clear way for developers to enforce this. This bug is about providing a subset of mozStorage that performs all I/O off the main thread and that will serve as target for both ongoing refactorings and future uses of mozStorage, in particular by add-ons.

Status Working prototype.

Improvements transaction management by JavaScript API for Off Main Thread database storage (Bug 856925)

Summary Sqlite.jsm is our JavaScript library for convenient Off Main Thread database storage. This bug is about improving how implicit transactions are handled by the library, hence improving performance.

Status In progress.

Refactor how Places data is backed up (Bugs 852040, 852041, 852034, 852032, 855638, 865643, 846636, 846635, 860625, 854927, 855190)

Summary Places is the database containing bookmarks, history, etc. Historically, Places was implemented purely on the main thread, which is something we very much want to remove, as any main thread I/O can block the user interface for arbitrarily lengthy durations. This set of bugs is part of the larger effort to get rid of Places main thread I/O. The objective here is to isolate and cleanup Places backup, to later allow removing it entirely from the main thread.

Status Working prototype.

APIs for updating/reading Places Off Main Thread (Bugs 834539, 834545)

Summary These bugs are part of the effort to provide a clean API, usable by platform and add-ons, to access/modify Places information off the main thread.

Status In progress.

Move Form History to use Off Main Thread storage (Bug 566746)

Summary This bug is part of the larger effort to get rid of Places main thread I/O. The objective here is to move Form History I/O off the main thread.

Status In progress.

Make about:home use IndexedDB instead of LocalStorage (Bug 789348)

Summary Currently, page about:home uses localStorage to store some data. This is not good, as localStorage does blocking main thread I/O. This bug is about porting about:home to use indexedDB instead.

Status In progress.

Download Architecture Improvements (Bug 825588 and sub-bugs)

Summary Our Architecture for Downloads has grown organically for about 15 years. Part of it is executed on the main thread and synchronously. The objective of this meta-bug is to re-implement Downloads with a modern architecture, asynchronous, off the main thread, and accessible from JavaScript.

Status In progress.

Constant stack space Promise (Bug 810490)

Summary Much of our main thread asynchronous work uses Promises. The current implementation of Promise is very recursive and eats considerable amounts of stack. The objective here is to replace it with a new implementation of Promise that works in (almost) constant stack space.

Status Working partial prototype.

Reduce amount of I/O in session restore (Bug 833286)

Summary The algorithm used by Session Restore to back up its state is needlessly expensive. The objective of this bug is to replace it by an alternative implementation that requires much less I/O.

Status Working prototype.

Planning stage

Move session recording and activity monitoring to Gecko (Bug 841561)

Summary Firefox Health Report implements a sophisticated mechanism for determining whether a user is actively using the browser. This mechanism could be reimplemented in a more efficient and straightforward manner by moving it to Gecko itself. This is the objective of this bug.

Status Looking for developer.

Non-blocking Thumbnailing (Bug 744100)

Summary Currently, we capture thumbnails of all pages, e.g. for display in about:newtab, in Panorama or in add-ons. This blocks the main thread temporarily, as capturing a page requires repainting it into memory from the main thread. This bug is about removing completely the “repaint into memory” step and rather collaborate with the renderer to obtain a copy of the latest image rendered.

Status Design in progress.

Evaluate dropping “www.” from rev_host column (Bug 843357)

Summary The objective of this bug is to simplify parts of the Places database and its users by removing some data that appears unnecessary.

Status Evaluation in progress.

Optimize worker communication for large messages (Bug 852187)

Summary We sometimes need to communicate very large messages between the main thread and workers. For large enough messages, the communication itself ends up being very expensive for the main thread. This bug is about optimizing such communications.

Status Design in progress.

Why Firefox OS matters to me

March 16, 2013 § 5 Comments

These days, everybody seems to be talking about Firefox OS. About how removing the barrier of the marketplace will make the world a better place, or about how HTML5 is so darn great, or about the fact that a gazillion constructors and operators are supporting Firefox OS. And that’s great, because Firefox OS is an impressively good product and deserves this attention.

However, all this craze is missing one feature that makes Firefox OS my choice of mobile operating system: I can write a playable prototype for a simple game, from scratch, in two hours.

Of course, this was a prototype, and completing the game took me a few more days of adding 8 bit graphics, optimizing, toying with the rules, adding difficulty levels, high scores, etc. But after just two hours, I could play the game on computer, tablet and cellphone, and decide where to proceed from here. This was both my first HTML5 game and my first mobile game, by the way. It is by no means an AAA game, but it is fun enough that I sometimes play it in the subway. By the way, did I mention that, once I was satisfied with this game, I could publish it in just a few seconds, simply by hosting it anywhere on the web?

Oh, and another feature: I wrote a quite usable comic book reader in the subway, while commuting from/to work. It took me a few days of commuting (three days, I seem to remember) to obtain a tool that works quite nicely. Due to screen size, I prefer using it on my Android tablet than on a cellphone, but that’s the wonders of HTML5 and Open Web Applications: I developed for one, and it worked for both. Did I mention that this was my first attempt at writing a web application that does file I/O or that uses the touch screen intelligently? I will try and finalize and release this application one of these days.

Now, other developers or users might not share this feeling, but this simplicity to start coding and publish and evolve a game or application is of tremendous importance to me. Because one day, I will have a child in age of playing video games. And for his birthday, I will have a chance to download a 5€ game from the Firefox Marketplace (or anywhere else), but more importantly, I will be able to build a game with his favorite characters as support cast and him as a hero. I hope he will love it. And I will not need to ask for permission.

If there is some application you want to develop, neither will you.

Mozilla Student Projects update

February 27, 2013 § 3 Comments

It has been quite some time since the last update. Since then, many things have happened, both with the Student Projects and with the world of Mozilla. We have had the exciting FirefoxOS AppDays, many alpha, beta and near-final versions of FirefoxOS, and the MWC launch of FirefoxOS.

Well, without further ado, let us see how the student projects have progressed.

« Read the rest of this entry »

Asynchronous file I/O for the Mozilla Platform

October 3, 2012 § 18 Comments

The Mozilla platform has recently been extended with a new JavaScript library for asynchronous, efficient, file I/O. With this library, developers of Firefox, Firefox OS and add-ons can easily write code that behave nicely with respect to the process and the operating system. Please use it, report bugs and contribute.

Off-main thread file I/O

Almost one year ago, Mozilla started Project Snappy. The objective of Project Snappy is to improve, wherever possible, the responsiveness of Firefox, the Mozilla Platform, and now, Firefox OS, based on performance data collected from volunteer users. Thanks to this real-world performance data, we have been able to identify a number of bottlenecks at all levels of Firefox. As it turns out, one of the main bottlenecks is main thread file I/O, i.e. reading from a file or writing to a file from the thread that also runs most of the code of Firefox and its add-ons.

« Read the rest of this entry »

Appel à enseignants/intervenants

September 26, 2012 § 2 Comments

Pour Mozilla, l’année universitaire 2012-2013 est l’année de Firefox OS, l’année des Open Web Applications et l’année à laquelle la communauté Mozilla lance sa campagne de libération des téléphones et applications portables !

Nous avons besoin de vous pour enseigner les technologies des Open Web Applications aux communautés francophones.
L’objectif des cours est de former des étudiants ingénieurs ou équivalents aux technologies nécessaires pour le développement ouvert d’applications web ouvertes. Nous cherchons notamment des enseignements sur les sujets suivants :
  • JavaScript avancé (clôtures, événements, prototypes, itérateurs/générateurs, timeouts)

Déroulement des cours

Autant que possible, les cours seront donnés en français face à une classe de MIAGE de  l’Université d’Évry, où ils seront aussi enregistrés. Les cours seront mis à disposition de toute la communauté Mozilla francophone dans le cadre de Mozilla Education. Les documents correspondants seront eux-mêmes mis à  disposition sous licence libre sur github.
Si  vous ne pouvez pas vous rendre à Évry, mais si vous pouvez enregistrer des cours par vous-mêmes, n’hésitez pas à nous contacter. Nous mettrons vos cours à disposition du public francophone.
Si vous avez d’autres idées, n’hésitez pas à nous les proposer. En ce moment, nos capacités d’enregistrement sont limitées mais nous ferons notre possible pour enregistrer et mettre votre cours à disposition.

Pour participer

  • Si vous pouvez assurer ces cours (entièrement ou en partie), suivez les liens ci-dessus
  • Pour proposer d’autres cours que vous pouvez vous-même assurer, ajoutez la description de vos cours sur https://github.com/Yoric/Mozilla-Courses/issues (cliquez sur “New issue”). Précisez si vous avez des contraintes géographiques ou besoin de matériel spécifique.

Et après ?

Notre objectif est d’étendre cette initiative hors de la région parisienne et surtout hors de France. Nous espérons notamment pouvoir organiser des cours en Afrique Francophone. La suite au prochain épisode !

 

 

 

Fun with Windows paths.

June 19, 2012 § 3 Comments

I am currently attempting to implement a JavaScript library to handle file system paths in a portable manner.

Right now, I am having lots of fun with Windows paths and I wanted to share a few tidbits.

Under Windows, a path name can look like:

  1. “\\?\drivename:” followed by backslash-separated components.
    Such paths can be either relative or absolute.
    In such paths, “.”, “..” and “/” are regular file names.
  2. “\\.\drivename:” followed by backslash-separated components.
    Such paths can be either relative or absolute.
    In such paths, “.”, “..” and “/” are special names.
  3. “\\?\UNC\servername” followed by backslash-separated components.
    Such paths can only be absolute.
    In such paths, “.”, “..” and “/” are regular file names.
  4. “\\servername” followed by slash- or backslash- components.
    Such paths can only be absolute.
    In such paths, “.”, “..” and “/” are special names.
  5. “drivename:” followed by slash- or backslash- components.
    Such paths can be either relative or absolute.
    In such paths, “.”, “..” and “/” are special names.
  6. Just a series of slash- or backslash- components.
    Such paths can be either relative or absolute.
    In such paths, “.”, “..” and “/” are special names.

To simplify things further, depending on the version of Windows, a drive name can be:

  • only one letter between A and Z;
  • any sequence of letters between A an Z;
  • something that looks like Volume{41AF5D4F-04CC-4D15-9389-734BD6F52A7E}.

Also

  • if a path starts with “\\?\”, its length is limited to 32,767 chars;
  • otherwise, its length is limited to 260 chars.

Also

  • some names such as “LPT”, “COM”, etc. are reserved and cannot be used as file names;
  • … unless your path starts with “\\”.

Also

  • paths are case-insensitive;
  • … except when they are case-sensitive because of the disk format;
  • … except when they are case-sensitive because of something else.

Fortunately, the Windows APIs provides the following functions to simplify matters:

  • PathCanonicalize (completely broken);
  • GetFullPathName (broken);
  • GetLongPathName (requires access permissions just to tell you if a path is well-formatted);
  • UriCanonicalize (not sure what it does exactly, I haven’t tested it yet).

Of course, not all Windows API functions accept all schemes.

As you can imagine, I am having lots of fun.

Quick exercise given two paths A and B (either absolute or relative), how do you determine the path obtained by concatenating A and B?

If you are interested in following my progress, details are on bugzilla.

Call For Classrooms

January 17, 2012 § 1 Comment

(and Researchers, Professors, Teachers, Students …)

Mozilla is working with numerous educators, professors and researchers across the world, both to bring open-source, the open web and web technologies into the classroom, and to bring the contributions of students and their mentors to the world. You can be a part of this, and your field does not have to be Computer Science.

« Read the rest of this entry »

Introducing JavaScript native file management

December 6, 2011 § 28 Comments

Summary

The Mozilla Platform keeps improving: JavaScript native file management is an undergoing work to provide a high-performance JavaScript-friendly API to manipulate the file system.

The Mozilla Platform, JavaScript and Files

The Mozilla Platform is the application development framework behind Firefox, Thunderbird, Instantbird, Camino, Songbird and a number of other applications.

While the performance-critical components of the Mozilla Platform are developed in C/C++, an increasing number of components and add-ons are implemented in pure JavaScript. While JavaScript cannot hope to match the speed or robustness of C++ yet (edit: at least not on all aspects), the richness and dynamism of the language permit the creation of extremely flexible and developer-friendly APIs, as well as quick prototyping and concise implementation of complex algorithms without the fear of memory errors and with features such as higher-level programming, asynchronous programming and now clean and efficient multi-threading. If you combine this with the impressive speed-ups experienced by JavaScript in the recent years, it is easy to understand why the language has become a key element in the current effort to make the Mozilla Platform and its add-ons faster and more responsive at all levels.

« Read the rest of this entry »

Where Am I?

You are currently browsing entries tagged with programming at Il y a du thé renversé au bord de la table.

Follow

Get every new post delivered to your Inbox.

Join 25 other followers