Adding Community-Driven Wayland Support to Servo

It’s been some time since the last Servo article on the OSG blog, but this has no relation to the speed at which the browser engine’s development has been progressing.

In the last post, the Offscreen Rendering (OSR) integration status was explored, culminating in both some code snippets as well as videos of an embedded browser application. That post can be considered the foundation for the recently-tweeted screenshot of Servo running with Wayland support.

The Technical Hurdle

Before delving into the technical details of Wayland integration, it’s important to know the background of Servo’s rendering stack. In order to provide support for a broad range of platforms, Servo uses the rust-layers library to create hardware-accelerated drawing abstractions for Android, Linux, MacOS, and Windows; this enables the browser engine to use a unified API for all its internal compositor painting.

Under Linux, rust-layers uses GLX, the OpenGL extension for X11, to perform hardware accelerated drawing in the commonly-used Xorg display server. This is the go-to method for using the GPU when running Xorg on desktop Linux.

GLX is problematic in some cases, however. First, GLX is X-specific, meaning that it cannot run under other display servers such as Wayland, or directly in the framebuffer, such as on Raspberry Pi devices. Requiring GLX in this case becomes an issue for anyone who wants to use Servo on embedded devices that run non-Android Linux variants. Additionally, continuous integration tests involving GLX have been prone to intermittent failures for some time, so replacing it with something else could yield benefits in this area. Finally, GLX code is also very driver-specific, and special cases are often needed for different platforms, hardware, and even driver versions.

Based on this information, using Servo on Wayland seems to be quite impossible. There have been tickets open for some time on GitHub related to converting Servo’s graphics stack over from GLX to EGL, a newer OpenGL variant which is usable outside of X, but no progress had been made on this transition over a long period of time.

Solving the Problem Through Education

Enter Dr. Gehringer’s Object Oriented Design class at NC State University. For the past few terms (link, link, link), this professor has been requiring students to contribute to open source projects as a practical application of their learning over the course of the term. This term, one of the open source project choices available was to refactor the OpenGL usage in Servo’s graphics stack, effectively adding support for EGL to all Linux-based systems.

The task was quite difficult for the students; “it took some time trying to figure some things out, as the Servo and Rust layer code-bases are really huge, but after some time, most of us could figure out where things were.” wrote Prashant Gupta, a student involved in the project. Considering that Servo consists of over 800k lines of Rust code and nearly 1.2 million lines of C/C++, that’s quite a feat!

While the rust-layers library may seem small by comparison to the main repository at around 3,000 lines of code, it’s important to consider that it’s written in a language that university students are unlikely to be familiar with, and the code exclusively deals with complex graphics APIs. “The redesign ended up being fairly daunting for newbies, because it required a lot of carefully interconnected code to be changed […]”, commented Neal O’Hara, another student from the team.

This isn’t to say that the project was set adrift with no guidance or assistance, however. Prashant was quick to note that “we were helped a lot […] through the IRC channel of the Mozilla group, and they were extremely prompt in helping us out in any way they could”, and Neal confirmed that “for the actual coding process, we had a lot of help […] which allowed us to quickly find the code to change, and work through cascaded errors.” With the final resulting pull request weighing in at 30 commits made over the course of a week; it’s no small feat that they managed this much – less than two months after having chosen to undertake this project – especially considering that none of the students had ever worked with the Rust language before.

The Key to It All: Community-Supported Learning

Mozilla, in particular the Servo project, is no stranger to student contributors, so it’s no surprise that help was readily available; Servo has been receiving student contributions for some time, and from a number of institutions with differing backgrounds. For example, Servo’s WebGL implementation was largely created by a student from the University of Salamanca for a GSoC-like project that’s associated with academic institutions.

On the topic of getting students involved with Servo and Open Source, Josh Matthews was quoted as saying: “I think all parties get a lot out of the projects – we regularly get to interact with newcomers who expose ways we can improve our onboarding experience, and we receive significant contributions that improve Servo. The students get a real-world experience contributing to a huge codebase in a cutting-edge language and have something to put on their resumes. It can certainly be a lot of work, but both the process and the results are valuable every term, so I feel that it’s well worth it. One of the students this term described it as ‘the most challenging and most rewarding project’ that she had ever been part of.”

As for applying the students’ work in order to run Servo within Wayland, this was a fairly trivial task by comparison. After the previously-described work running Servo embedded within an application using the OSR API for rendering, the same application more-or-less worked out of the box for the purpose of taking Wayland screenshots such as this:

Adding Community-Driven Wayland Support to Servo - WaylandScreenshot

This endeavor has been an immense success and we look forward to future involvement from academia.

Footnote: the first question that was asked after the story hit the twittersphere and news sites was whether the application was using Glutin to create the window for drawing in Wayland. To be short: no. After trying to run the Glutin port, the only output was an error about DISPLAY not being set; given that EFL is easier to work with than Glutin – based on available time and expertise – and that the reference embedding application uses EFL, it was an easy choice to not dig further into this issue and instead use something which has been known to work well in Wayland since 2012.It’s worth noting, however, that there is ongoing work to improve Wayland support in Glutin, so Servo and other Rust applications may be able to run using this port in the near future.

Anshita Sayal, another student from the team involved with the EGL refactoring project in Servo, was unable to be reached for comments.

Guest Author: Josh Matthews

Josh Matthews, Senior Platform Engineer at Mozilla, is the coordinator of Servo’s DOM implementation and is constantly on the lookout for ways to engage with students and volunteers more effectively.

Guest Author: Lars Bergstrom

Lars Bergstrom is a researcher at Mozilla, currently working on the servo parallel web browser project.He received his Ph.D. from the University of Chicago‘s Computer Science department, studying under Dr. John Reppy. His Master’s paper was on the implementation of analysis and optimization passes in our parallel compiler, Manticore. His Ph.D. research was on how to add mutation safely and efficiently into a functional parallel programming language. He has also been doing work on a runtime, garbage collector, and most recently some extensions to control-flow analysis. Before that, he was a manager and a developer at Microsoft in the Visual Studio organization, working on next-generation software development tools technology out at the Redmond, WA offices.

Servo: The Countdown To Your Next Browser Continues

Huge progress is being made on the Servo browser engine, and development continues moving forward at full speed. Now, it’s even possible to write applications that embed Servo to display web content, and these applications can drop Chromium in at any point, with very few changes, in order to have a more functional product while Servo continues its heavy development. This article will take a look at the new code that provides this detection ability to toggle functionality based on the running engine, in addition to the new improvements that have been introduced to Servo’s rendering and embedding capabilities.

Detecting Servo to Work in Harmony With Chromium

Detection of the engine is made possible by a symbol added into Servo’s embedding library, which can be detected in C with a bit of code like this:

servo = !!dlsym(NULL, "servo_test");

This returns the address of the symbol and sets a boolean variable “servo” based on the symbol’s presence. When using Chromium, it will return NULL, and this can allow different steps to be taken in the application. For example, in one of our demo browsers the following code snippet can be found:

Evas_Object *ic;
ic = elm_image_add(win);
if (servo)
 elm_image_file_set(ic, "doge.png", NULL);
else
 elm_image_file_set(ic, "chromium.png", NULL);
elm_win_icon_object_set(win, elm_image_object_get(ic));

This will produce a different icon for the window based on the running engine, and provides a visual hint to the user or developer.

Framework Under Construction

As discussed in a previous post, Servo has chosen to use the API from Chromium Embedded Framework (CEF) for embedding. There have been some challenges in adopting this, the first is that Servo has a different rendering mechanism than Chromium.
Let’s examine the rendering interface provided by CEF:

 void (CEF_CALLBACK *on_paint)(struct _cef_render_handler_t* self,
   struct _cef_browser_t* browser, cef_paint_element_type_t type,
   size_t dirtyRectsCount, cef_rect_t const* dirtyRects, const void* buffer,
   int width, int height);

This is called when an element should be painted. Pixel values passed to this function are scaled relative to view coordinates based on the value of CefScreenInfo.device_scale_factor returned from GetScreenInfo.

  • |type| indicates whether the element is the view or the popup widget.
  • |buffer| contains the pixel data for the whole image.
  • |dirtyRects| contains the set of rectangles in pixel coordinates that need to be repainted.
  • |buffer| will be |width|*|height|*4 bytes in size and represents a BGRA image with an upper-left origin.

This callback is triggered any time Chromium wants to draw or update its displayed content, and it’s the only available mechanism for integrating the application canvas with the web canvas. The only alternative to it is to allow CEF to create its own window and re-parent it to the application’s own window: a poor choice since it then becomes impossible to render any application content in the space occupied by the browser content.

When using this callback, the user is provided with a pixel buffer that has no lifetime guarantees and must be rendered “now.” The onus is on the application to perform the actual blitting to the screen. Even though time was already spent in the engine creating this pixel buffer, no drawing to the output occurred. The application is either left with a texture upload or a full software render for the region, and neither of these were possible in Servo.

The problem here is in the architecture: Servo does all its rendering in parallel using output tiles, so there is no pixel buffer to provide. A decision was made that Servo should not just be a passive user of CEF, but should also engage in driving its API development. The result is that Servo now has extra methods in the rendering interface which are being tested and iterated upon. Once they are deemed ‘good,’ the plan is to try merging the methods into upstream CEF. However, at present they are simply added onto the ends of the interface structs in order to preserve binary compatibility with CEF.

The following video displays this ABI compatibility:

Composite Smarter, Not Harder

Servo’s CEF render interface now contains a few additional methods:

void (CEF_CALLBACK *composite)(struct _cef_browser_host_t* self);

This instructs the browser to perform an accelerated composite. The appropriate Direct3D or OpenGL state must have been set up before calling this function.

void (CEF_CALLBACK *initialize_compositing)(struct _cef_browser_host_t* self);

This instructs the browser to initialize accelerated compositing. The appropriate Direct3D or OpenGL state must have been set up before calling this function.

int (CEF_CALLBACK *get_backing_rect)(struct _cef_render_handler_t* self,
 struct _cef_browser_t* browser, cef_rect_t* rect);

This is called to retrieve the backing size of the view rectangle which is relative to screen coordinates. On HiDPI displays, the backing size can differ from the view size as returned by |GetViewRect|. Return true (1) if the rectangle was provided. Only used on Mac OS.

void (CEF_CALLBACK *on_present)(struct _cef_render_handler_t* self,
 struct _cef_browser_t* browser);

This is called when an element should be presented (e.g. double buffers should page flip). This is called only during accelerated compositing.

These provide a number of advantages and improvements to the hardware-accelerated rendering pipeline, effectively allowing the application to set up its render surface for the browser to draw directly onto. The application can then execute a swap to display the newly-rendered content with no extra steps. This ends up being simpler in many cases for applications.

The biggest benefit, however, is that it provides compatibility with different types of rendering mechanisms, such as deferred renderers. CEF provides no lifetime guarantees for the buffers provided in its paint callback, meaning that any developer wanting to safely render the buffer asynchronously should copy it first to ensure that it is not deleted without warning.

Using the new methods added in Servo’s branch of CEF, an application can prepare its render surfaces before calling initialize_compositing() to enable rendering. A paint callback occurs as in upstream CEF, but there is no pixel buffer provided; the application simply executes the composite() method at any convenient time to trigger the render and then performs the swap when the engine sends the present() callback.

Bringing it All Together

One feature that landed recently is the ability to force an early initial layout of the page, even if the rest of the content has not yet loaded. With this feature, Servo, like Firefox, will ensure that 200ms after the `<body>` tag is parsed the rendering engine will attempt to display whatever has been parsed so far. Any further resources loaded, modifications from JavaScript, or user actions that occur and change the DOM tree will cause subsequent reflows to take the new information into account.

A short video was recently recorded which features a development browser chrome that includes all of the functionality described in this post. It’s worth noting that, at the time of writing, the biggest speed bottleneck in Servo’s page load is the network resource fetching code. Servo does not yet implement connection pooling or resource prefetching, which causes many sequential resource loads and creates the long delays seen in the video.

Guest Author: Lars Bergstrom

Lars Bergstrom is a researcher at Mozilla, currently working on the servo parallel web browser project.He received his Ph.D. from the University of Chicago‘s Computer Science department, studying under Dr. John Reppy. His Master’s paper was on the implementation of analysis and optimization passes in our parallel compiler, Manticore. His Ph.D. research was on how to add mutation safely and efficiently into a functional parallel programming language. He has also been doing work on a runtime, garbage collector, and most recently some extensions to control-flow analysis. Before that, he was a manager and a developer at Microsoft in the Visual Studio organization, working on next-generation software development tools technology out at the Redmond, WA offices.

Servo: The Embeddable Browser Engine

Embedding, in the context of this article, is the process of hosting a web rendering engine inside another application. This engine displays content exactly as a regular web browser would, but allows the application author to customize the user’s experience further than what is possible in the typical display of a normal website. Development time can be reduced by keeping part of the content of an application in web-related languages due to the relative ease of writing web content and the widespread knowledge of HTML5.

The technique of embedding web content is used in many places by many companies, including:

  • Popular Linux applications such as Rhythmbox, Kate, Eclipse, and Evolution have support for embedding web content.
  • Microsoft Entourage and Apple Mail for Mac OS both utilize embedding for displaying web content and parts of the UI.
  • Adobe products, including their constantly-running updater, embed full web runtimes.
  • Valve’s Steam client also depends heavily on embedding web content, as they reuse the content from their online store to display in their native application.
  • Many applications in mobile app stores are simply a native wrapper around a web browser control and HTML5 resources.

HTML5 has been gaining significant traction in the mobile and embedded world. According to a recent survey HTML5 is a leading platform for application development in all markets, and this figure is likely to increase as the number of mobile platforms grows in the future. Finally, HTML5 is a widely known cross-platform solution which guarantees portability.

The Need for A Common, Embeddable API

There are very few common APIs for embedding content into applications, and until a couple years ago, the most prevalent API was WebKit. This was problematic because WebKit’s API is not considered stable, forcing developers to rewrite parts of their application in order to keep up with changes in the underlying browser engine. In recent years, Blink was forked from WebKit, creating yet another embeddable API. Unfortunately, in addition to being confined to C++, Blink’s embedding API is also not stable, perpetuating the increased workload for application developers.

One solution for these problems is to use the Chromium Embedded Framework. Launched in 2008, the project is based on the Blink browser engine but aims to completely insulate its users from underlying engine changes. It provides a base C API with C++ extensions; allowing support at the lowest levels of software development. Currently, this API is used extensively by Valve for their Steam client, and by Adobe, for various products.

The Servo Solution

The Servo browser engine aims to be embeddable in order to provide maximum flexibility to developers. To this end, it must provide a stable API and ABI for developers to rely on. It is written in Rust because it provides an API usable from C. Designing yet another embeddable web API is an extremely complex task which requires a tremendous amount of consideration and review. It also requires extensive documentation to be written, frameworks to be tested, and the resulting product to be promoted and accepted into general usage. Based on this, we decided to take a different approach.

Servo implements the Chromium Embedded Framework API: if it’s good enough for Valve, it’s good enough for us. This means developers who currently use CEF will not need to make any application changes to compare performance between the Blink and Servo engines, and prospective developers will not have yet another browser API to review and consider. Hopefully, this also means Servo will reach an embeddable state much more quickly.

The methodology for this implementation is twofold: ensure full symbol coverage, and attempt to mimic the exact functionality of each method call as closely as possible. Since this is not a common practice, let’s break it down a little further. Symbol coverage refers to the externally visible symbols provided by a library. Rust, using the extern “C” keywords, allows any function written in Rust to be directly accessible from C with no extra work needed. So in this regard, full symbol coverage would mean that every CEF function call is able to be hooked by Servo’s embedding library. It also requires that any time an externally-used struct is allocated, it must match the size and member positioning as a similar struct allocated by the real CEF.

pub struct cef_string_utf8 {
   pub str: *mut u8,
   pub length: size_t,
   pub dtor: extern "C" fn(str: *mut u8),
}

Mimicking functionality is a bit trickier. This requires full understanding of each CEF function and how it ties into the browser engine. Then, the same order of operations must be replicated using the underlying Servo browser engine. This can be quite a complex process, as CEF makes internal function calls back and forth between itself and Blink, sometimes requiring functions to operate recursively.

The method for implementing and testing the success of this endeavor has been a bit complex. First, a symbol list was needed. Using standard utilities, specifically the nm tool on Linux, we copied the undefined symbols from some of the example CEF applications. This provided an easy starting point to begin implementing functions and functionality. With the list of target symbols, it became much easier to track the execution of the application through the CEF library and determine what was happening in each function call. From here it became a case of using Rust/Servo to replicate the expected and observed behavior.

A Few Hitches Along The Way

The process of writing this implementation for embedding has not come very far because it was only recently begun; at present, there is only a very small team focusing on it. However, there have been some difficulties that may be interesting to other developers. One such difficulty that was immediately apparent was tracking the C API’s execution through the C++ extensions provided by CEF. The example applications all use the C++ extensions which required a bit of legwork to understand how they utilize and wrap the C API and what was going on internally. The solution here was extremely rudimentary, just read a whole bunch of source code. Eventually, even the most high-level wrapper would come down to one or two function calls which could then be written and tested more thoroughly.

Another difficulty that took quite a while to track down is a byproduct of the testing environment. In order to run the CEF examples with the Servo backend, we needed to use some library preloading hacks (LD_PRELOAD and friends on Linux) so the running environment would inject the Servo embedding symbols for use in the application, effectively overriding the CEF-provided functions. However, as long as the CEF library is used in any function call it will invoke the underlying Blink runtime, which uses the tcmalloc allocator. The reason this is problematic is because tcmalloc uses different function calls for allocating memory between C and C++ than what is expected, and it complains quite loudly when it detects any deviation from this behavior. As a result, the Servo embedding library needed to provide wrappers to allow calling these functions directly for memory allocation, but only when using the preload hack:

pub fn new(size: size_t) -> *mut c_void {
   unsafe {
      tc_new(size)
   }
}

The embedding support is now sufficient to run Servo within the cefsimple application, and a number of tasks are currently open to improve support in other directions. For more information check out the GitHub page.

Guest Author: Lars Bergstrom

Lars Bergstrom is a researcher at Mozilla, currently working on the servo parallel web browser project.He received his Ph.D. from the University of Chicago‘s Computer Science department, studying under Dr. John Reppy. His Master’s paper was on the implementation of analysis and optimization passes in our parallel compiler, Manticore. His Ph.D. research was on how to add mutation safely and efficiently into a functional parallel programming language. He has also been doing work on a runtime, garbage collector, and most recently some extensions to control-flow analysis. Before that, he was a manager and a developer at Microsoft in the Visual Studio organization, working on next-generation software development tools technology out at the Redmond, WA offices.

Servo Continues Pushing Forward

Servo is a new prototype web browser layout engine written in Rust that was launched by Mozilla in 2012 with a new architecture to achieve high parallelism on components like layout and painting.

It has been progressing at an amazing pace, with over 120 CSS properties currently supported, and work is ongoing to implement the remaining properties. For a full list of the current set of CSS properties with initial support in Servo, check out the Google Docs spreadsheet servo team is using to track development.

The current supported properties allow Servo to be mostly operational on static sites like Wikipedia and GitHub, with a surprisingly small code footprint. It has only about 126K lines of Rust code, and the Rust compiler and libraries are about 360K lines. For comparison, in 2014 Blink had about 700K lines of C++ code, and WebKit had around 1.3M lines, including platform specific code.

Another exciting development is servo-shell, which allows the implementation and customization of a WebBrowser using only Javascript and CSS. It’s essentially a browser chrome that uses mozbrowser APIs (i.e.  iFrame extensions) running on top of Servo and provides the ability to separate the browser content from loaded pages, which has led to fairly good performance so far.

Finally, Rust (the programming language used to implement Servo) is approaching the 1.0 launch and a big group of people are ready to celebrate the occasion in San Francisco.

Improving Debugging and Testing

One of the most challenging parts of developing a browser engine from scratch is re-implementing all of the CSS features, because they often have complicated interactions. For a developer to solve any layout rendering bugs they run into, they must first inspect the graphical representation of the DOM tree to see if it is correct. In case of Servo, the DOM tree will generate a FlowTree and DisplayLists while performing layout and rendering, compared to WebKit and Blink, which uses a RenderTree as graphical representation (and features DumpRenderTree tool for accessing the RenderTree). Debugging support was improved remarkably with addition of the ability to dump Optimized display lists, Flow tree, and Display List, as well as the implementation of reflow events debugging, which can be used to inform developers when and why a layout was recalculated.

Integration of the Firefox timeline has recently been started on Servo. This is a tool that allows tracking of operations performed by the web engine and is useful for debugging and profiling a site. Additionally, W3C organization has created a test suite to help in verifying CSS features across browsers, which enhances interoperability.  Servo now has support for running these W3C CSS tests.

Additional Servo Highlights

General Developments

  • Servo has being ported to Gonk (the low level layer of Firefox OS) last February.
  • Servo has some state of the art components (e.g. HTML5 parser, CSS parser) implemented in Rust as independent libraries, which may be beneficial to integrate with Firefox. Work has started on this integration, but whether the image decoder or the URL parser will be integrated first is undefined at this time.
  • WebGL implementation has begun.
  • Another cool feature is the visualization of parallel painting, where Servo executes in a mode in which tiles rendered by each distinct thread will have an overlay rendered on top of it. This makes it possible to visualize Servo’s parallel painting.
  • Support for displaying a placeholder when an image link is broken.
  • Cookies are now supported as well as SSL certification verification. These allow users to login to most websites that have user accounts.
  • Providing the ability to embed Servo on applications in the future is important, and work on this subject is progressing. Instead of creating a new API for developers, the community decided to use the Chromium Embedded Framework (CEF): an API that is quite successful and stable. Servo has a CEF-like API that provides the ability to embed a Servo-powered webview on native apps, as demonstrated by Miniservo on Mac and Linux. Work on supporting the API has been progressing well.

Improved HTML/CSS Support

The Road Ahead

As you can see, Servo has advanced remarkably in the last few months by implementing many new features that benefit both Servo developers as well as future users. It is moving at a fast pace, implementing support for several of the web features needed by any modern browser engine while proving that Rust, as a systems-level programing language, is up to the task of writing a web engine from scratch.

Are you interested in contributing to Servo or just curious to give it a try? Visit the project site, or feel free to chat with the developers on #servo on the mozilla IRC server.

 

Guest Author: Lars Bergstrom

Lars Bergstrom is a researcher at Mozilla, currently working on the servo parallel web browser project.He received his Ph.D. from the University of Chicago‘s Computer Science department, studying under Dr. John Reppy. His Master’s paper was on the implementation of analysis and optimization passes in our parallel compiler, Manticore. His Ph.D. research was on how to add mutation safely and efficiently into a functional parallel programming language. He has also been doing work on a runtime, garbage collector, and most recently some extensions to control-flow analysis. Before that, he was a manager and a developer at Microsoft in the Visual Studio organization, working on next-generation software development tools technology out at the Redmond, WA offices.

Servo: Building a High-Performance, Safe Web Browser

Servo is a new web rendering engine that was launched by Mozilla in 2012 and is now receiving significant contributions from both Samsung and independent community members. Our goal is to produce an embeddable engine that can be used in both browsers and applications to make the web platform faster and safer, and bring it to more devices.

We started this project to address fundamental limitations of current browser engines. First, the C family of programming languages doesn’t ensure safe use of memory, which leads to the majority of all zero-day browser security bugs. Second, current engines were originally designed for use on a PC, and are challenging to scale down to low memory and low power devices. Finally, as the web platform has evolved, the tightly-coupled design of current browser engines has made it difficult to provide performance guarantees, such as 60 fps screen updates.

Memory Safety

Investigations have shown that most high priority, security critical bugs in the browser engine are related to use-after-free or buffer overruns. In Servo, we are using the Rust programming language to prevent many of these issues statically, at compile-time. In Rust, all allocated memory is owned by a single variable, and the compiler ensures that the memory cannot be referenced by multiple owners.

For example:

fn foo() {
let x = create_thing();
store_thing(x);
use_thing(x); // Error - the value in 'x' has been moved!
}

This ownership model ensures that pointers to allocated memory do not outlive the release of that memory and that concurrent threads cannot access the same piece of memory simultaneously.The Rust compiler automatically inserts all calls to allocate and free data, and because these ownership properties are statically checked, at runtime this data may freely be accessed without any extra overhead, unlike traditional approaches such as garbage collection or reference counting.

Low Memory and Power Devices

Modern browsers have achieved incredible levels of performance, even running full video games in JavaScript. While Firefox runs well on devices with only 256 MB of RAM , with Servo we are working to make it possible to bring the web platform to wearables and appliances with less than a quarter of that amount.

Parallelism has been exploited primarily to provide speedups by using a machine with four cores in the hopes that the program would run four times as fast as the program on a single core. However, in Servo we are using parallelism to provide better power usage and are experimenting with running four cores clocked to a more power-efficient clock speed, resulting in the same execution time but significantly lower power usage. For example, the following charts show that when running Servo on large benchmark page at a lower clock frequency, the four cores have the same speed as a single core at the higher frequency, but use 40% less power.

Servo Building a High-Performance Safe Web Browser - servo-perf
Running 4 threads at a lower frequency is as fast as a single core running at a higher frequency.

Servo Building a High-Performance Safe Web Browser - servo-power

Performance

Concurrency is the ability to perform multiple tasks in an interleaved fashion. As web sites have become more complex, the lack of concurrency in modern browsers has resulted in ‘jank’, or cases where the page fails to update because a non-graphics task is being performed on the same thread where the graphics are being rendered. In Servo, our graphics task is completely decoupled from JavaScript evaluation and webpage layout, allowing the graphics to be updated at a consistent 60fps.

Additionally, we have added concurrency within web pages. If a page has multiple iframe elements, each of which is running JavaScript, in today’s web browsers all of the iframes will pause when any one of them is executing that script. Some modern browsers plan to solve this by spawning a process per iframe, but it is unclear how that will work for sites with tens to hundreds of iframes. Such sites already exist, and will only become more prevalent as ad platforms shift from Flash to HTML5.

In Servo, we avoid this problem by using Rust’s lightweight task spawning mechanism. For each iframe in a page, each of the layout, graphics rendering, and script processing tasks run concurrently. And that is also true between each iframe. So, without consuming a huge number of native OS threads or processes, we can already provide concurrency.

This design also has the advantage of forcing a clean architectural separation between the various pieces of our engine, which makes the addition of new web platform features both easier to write and less likely to affect unrelated pieces of the browser engine.

Current Status

Servo is intended to support the full web platform eventually, and it passes the ACID1 and ACID2 tests. Rather than focus on benchmark suites and further classic web conformance tests, we are now working towards full specification compliance through the Web Platform Tests initiative.

We are currently expanding on Servo’s functionality and are targeting an alpha-quality browser in 2015. We are always looking for new contributors, and actively mentor newcomers by curating bugs appropriate for them! Because Servo is so new, it is easy to make a very large contribution with a small amount of effort.

Please come join us!

Guest Author: Lars Bergstrom

Lars Bergstrom is a researcher at Mozilla, currently working on the servo parallel web browser project.He received his Ph.D. from the University of Chicago‘s Computer Science department, studying under Dr. John Reppy. His Master’s paper was on the implementation of analysis and optimization passes in our parallel compiler, Manticore. His Ph.D. research was on how to add mutation safely and efficiently into a functional parallel programming language. He has also been doing work on a runtime, garbage collector, and most recently some extensions to control-flow analysis. Before that, he was a manager and a developer at Microsoft in the Visual Studio organization, working on next-generation software development tools technology out at the Redmond, WA offices.