SERVO TRAINING Lars Bergstrom, Simon Sapin, Patrick Walton, and the Servo team
Before we start… • Untar • tar
and start building Servo (in release mode)
zxf servo-{platform}.tgz
• ./mach • May
build -r
need additional platform dependencies, listed at:
http://www.github.com/servo/servo
Why a new browser engine? • Parallelize
compute-intensive web platform features to take advantage of parallel hardware • Layout,
• Design
selector matching, painting, etc.
for concurrency up-front
• Especially
script and layout, including layoutrequiring transitions
• Use
a memory-safe language to reduce the safetyrelated issues
Implementation strategy • Rewrite
layout, rendering, HTML/CSS parsing, networking, core engine glue
• Reuse
JavaScript engine, media codecs, graphics library, fonts, WebRTC
• Bootstrap
with OpenSSL, image libraries, etc.
Servo high-level architecture HTML CSS JS
Parsing
Flow Tree
Script
Script
Final Output
DOM
Styling
Compositing
Layers
Layout
Rendering
Display Lists
More details at: http://arxiv.org/abs/1505.07383
Component Architecture (detailed)
• As
far from a monorepo as you can imagine
• >130
crates, >40 repositories
Component Architecture (simplified) Clients Net
Chrome
Embedding
Script
Devtools
Profiling
Layout
gfx
Compositing
Core Hyper
html5ever
url
Selectors
Style
Canvas
layers
openssl
SM
libpng
Encoding
CSS Parser
Azure
Glutin
harfbuzz
Skia
freetype
Libraries Grey = Rust Component; Blue= C++ Component
This talk • Walk
through each major area, with exercises
• Script • Layout • Graphics • Time
permitting
• Testing,
debugging, performance
Exercise 1: Run Servo! • Just
view a site, play with resize, etc.
• e.g.,
./mach run -r http://www.reddit.com/
• Check
out parallel layout output
• ./mach
run -r http://www.reddit.com/ -Z showparallel-layout
• Note:
this is a release build, kick off debug for future exercises • ./mach
build -d
Script • The
script task starts the parsing of resources, runs the JavaScript, handles events, and triggers layout.
• We
use SpiderMonkey (version 39) in Servo as our JavaScript engine • No
immediate plans to rewrite in Rust
• Maybe
an interpreter-only Rust JS engine…
Loading a page • Create
a new Page entry in the frame tree
• Create
the Window and Document objects
• Hand
off the resource request to the HTML parser (html5ever) and return that parser object to the Script task
• As
the load and parse completes, these will inform the layout task as appropriate
DOM implementation • Use
CodegenRust.py - a variant of Codegen.py from Gecko - to turn WebIDL into interface definitions in Rust
• This
generated code handles the type conversions and required infrastructure between SpiderMonkey and the Rust bindings
• The
Rust bindings interface with the rest of the browser and the OS to implement the features
Avoiding cycle collection •A
JavaScript engine can collect the things it owns
• Complication:
when there are pointers to and from DOM nodes implemented in Rust
• Current
browsers either rely on annotations to inform JS of these pointers or just leak
• In
Servo, we use Rust to ensure all Rust fields are marked and reported to the JS engine if they can hold pointers to JS values
Exercise 2: Script • Goal:
add support for firing the
mouseover event • See
instructions at:
http://bit.ly/1HfmEgn
Layout • Style
system
• Implements
CSS parsing and selector matching
• Layout • Positions • Display
elements
list creation
CSS Parser • Implemented
module
in rust-cssparser standalone
• Tokenizes
and parses into component values and declarations
• Implemented
via a series of macro invocations to handle parsing, fallback, etc.
Selector matching • Implemented
in the rust-selectors library
• Uses
the output of the CSS parser library to create Selectors and perform matching
• Implements
the “usual” Bloom filter for matching
Layout • Assigns
sizes and positions to elements based on their styles
• Most
browsers compute final element positions via virtual function calls • Inefficient • Challenging
• Servo
to parallelize
uses a three-pass system
Layout - bubble widths • Bottom-up
parallel traversal of the tree to compute the intrinsic inline sizes (aka width)
• Also
set some flags for floats, CSS counters, etc.
Layout - assign widths • Top-down
parallel traversal to determine the computed inline sizes (aka widths)
• Minimum
and preferred widths from the previous pass to compute these
• Also
incorporates parent’s width and CSS style
Layout - assign heights • Bottom-up
parallel traversal where it’s possible to compute the block sizes (aka heights)
• Also
handles line breaking and margin collapse
• In-order
for subtrees with floats, text runs, etc. that have to be handled in-order
What about parallelism hazards? • CSS
Counters are an example
• Counter
require a sequential pass to determine the values
• We
mark the regions with Counters and handle them sequentially
• Does
not significantly reduce parallelism on real pages (so far)
• Neither
do floats or other hazards
Compute display lists • Produces •-
a list of lists of simple display commands
Borders, gradients, lines, text, etc.
• Top-down
these lists
traversal of the flow tree to generate
• Generated • Avoids • Stacking
out-of-order and then shuffled
multiple traversals
contexts produce nested lists and can get a hardware layer
Exercise 3: Layout • Goal:
run one of the CSS WG reftests and analyze the failure against the spec.
• Link:
http://bit.ly/1digTQU
Graphics • Servo’s
graphics stack handles turning the display list into composited graphics on-screen
• We
have Rust wrappers around Azure/Moz2D for 2D painting code and Skia for buffer management and actual painting
Layers • The
Rust layers repository provides access to native (platform-specific) graphics contexts
• Really • Also
simple OpenGL compositor
has our few shaders
Glutin • Rust
toolkit library (replaces glut and glfw for us)
• Handles • Also
window creation, event routing, etc.
takes care of headless offscreen with Mesa for testing
Compositing • Currently
on the main UI thread
• One
of the only things other than event routing that we do there!
• Simply
buffers
composites; does not block waiting for
Build system • Mach
handles driving build, updating required tools, etc. • Servo
uses a fixed version of the Rust compiler
• Cargo
(Rust build system) drives the submodule fetching and build • Cargo.lock • One
files pin to specific versions
build system for all platforms (desktop, Android, gonk, ARM linux, etc.)
Developer happiness
• Autolanding
only - buildbot & travis for testing
Testing Web Platform features • We •
use the Web Platform Tests
./mach test-wpt
• Warning!
Will peg all your CPU cores and
run for 20-30 minutes. • pass
—include=/area to reduce
Time profiling
• ./mach
run -r https://www.reddit.com/ -p 2
Memory profiling | 2.89 MiB -- pages | 2.57 MiB -- url(https://www.reddit.com/) | 2.34 MiB -- paint-task | 2.34 MiB -- buffer-map | 0.22 MiB -- layout-task | 0.22 MiB -- display-list | 0.00 MiB -- local-context | 0.00 MiB -- layout-worker-0-local-context | 0.00 MiB -- layout-worker-1-local-context | 0.32 MiB -- url(https://static.adzerk.net/reddit/ads.html?…) | 0.32 MiB -- paint-task | 0.32 MiB -- buffer-map | 0.00 MiB -- layout-task | 0.00 MiB -- display-list | 0.00 MiB -- local-context | 0.00 MiB -- layout-worker-0-local-context | 0.00 MiB -- layout-worker-1-local-context | | 30.91 MiB -- jemalloc-heap-active | 25.38 MiB -- jemalloc-heap-allocated | 140.00 MiB -- jemalloc-heap-mapped | 150.64 MiB -- resident | 3027.35 MiB -- vsize
• ./mach
run -r https://www.reddit.com/ -m 2
Debugging • gdb •b
/ lldb
rust_panic
• RUST_LOG • RUST_BACKTRACE=1
Exercise 4: Debugging • Learn
to debug Servo code!
http://bit.ly/1RBxdKc
From engine to browser • Servo
just renders pages
• Designed
to work in many contexts
• Standalone
browser with HTML UI on desktop
• Embeddable
Framework
• Android,
via Chromium Embedding
application and as a WebView control
• FirefoxOS
Servo roadmap •
https://github.com/servo/servo/wiki/Roadmap
• Q3
2015
• Mobile
/ embedded stability and performance
• Further • CSS
improved graphics performance
& DOM features
• 2015 • Full
Alpha-quality release
Questions? • Thanks
for your time!