Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
2
LATEX editor using TeX Live utilities and GNU Make. Figure 1 requires this setting.
displays a screenshot of the editor. From this point, the build process is mostly unchanged from
a standard compilation. For programs that use the autotools
2.1. LATEX Editor Overview build system, such as GNU Make and TeX Live, instead of
The editor presents a split-screen view to the user, with the doc- running ./configure, the developer invokes emconfigure
uments LATEX source on the left, and generated PDF preview ./configure. This wrapper overrides standard tools like cc
on the right. The editors UI is a standard web application, and ar with em prefixed alternatives that compile the program
and represents the only new code. When the user clicks on the with Emscripten, which produces individual JavaScript files
Build PDF button, the editor uses B ROWSIX to invoke GNU for each program.
Make in a B ROWSIX process, which rebuilds the PDF. Staging the Filesystem: Next, the developer configures
The process for building the PDF is familiar to anyone who B ROWSIXs in-browser filesystem so that it hosts all of the
has used LATEX, except B ROWSIX performs all of the needed files that the programs require. B ROWSIXs file system ex-
steps entirely in the browser instead of server-side. It runs tends Doppios BrowserFS file system with multi-process sup-
GNU Make to read a Makefile from B ROWSIXs file system, port, building on its support for files backed by cloud storage,
which contains rules for rebuilding LATEX projects. Make then browser-local storage, traditional HTTP servers, and more [9].
runs pdflatex and bibtex, depending on whether the user For our LATEX example, both pdflatex and bibtex require
has updated the references file. read access to class, font, and other files from a LATEX distribu-
pdflatex and bibtex read any required LATEX packages, tion to function properly. While a complete TeX Live distribu-
fonts, and other system files from B ROWSIXs file system, tion contains over 60,000 individual files, the average LATEX
which lazily pulls in files as needed from the network. Both of document only references a small subset of these files.
these applications write their output to B ROWSIXs file system. To reduce load times and minimize the amount of stor-
Once all steps have completed (or an error has occurred), the age required on a clients device, the developer can leverage
Make process exits with an exit code indicating whether or not B ROWSIXs filesystem to load only the needed files. In this
PDF generation succeeded. B ROWSIX sends the exit code back case, the developer uploads a full TeX Live distribution to an
to the web application. If GNU Make exits normally, the editor HTTP server and configures B ROWSIXs filesystem to use an
reads the PDF from B ROWSIXs shared filesystem and displays HTTP-backed filesystem backend. The filesystem will then
it to the user. Otherwise, it displays the standard output from load these files on-demand from the network upon first ac-
pdflatex and bibtex to the user, which describes the source cess. The browser caches these files automatically, making
of the error. subsequent access much faster.
2.2. Building with B ROWSIX B ROWSIX Setup Code: Finally, the developer adds code to
the web application to load and initialize B ROWSIX, and to
Building any web application that runs Unix programs in launch make to build the PDF. A script tag in the HTML
B ROWSIX generally consists of the same three step process: loads browsix.js, and a subsequent script tag with inline
(1) compile the programs to JavaScript (using tools with JavaScript calls B ROWSIXs Boot function with the desired
B ROWSIX support), (2) stage files required by the applica- filesystem configuration.
tion for placement in the in-browser filesystem, and (3) add Additional application-specific initialization follows as
setup code to the web application to initiate B ROWSIX and usual. Once the filesystem is ready, the developer adds
launch the programs. code to read the contents of main.tex and main.bib from
Compiling to JavaScript: To run pdflatex, bibtex, and B ROWSIXs filesystem, and display the contents in the editor;
GNU Make in B ROWSIX, the developer compiles each pro- The application then registers a callback function with the
gram to JavaScript using Emscripten, a C/C++ to JavaScript Build PDF button to be run whenever the user clicks the
compiler [12]. We extend Emscriptens runtime library with button.
B ROWSIX support, so standard Unix APIs map to B ROWSIX
2.3. Execution with B ROWSIX
primitives. We discuss this extension in more detail in Sec-
tion 4.3. When the applications callback is executed in response to a
Before compilation, the developer needs to determine if any users Build PDF click, the application invokes the system
of the programs use the fork command. Due to browser limi- method on its kernel instance to start make. Make runs
tations explored in Section 6, B ROWSIX can only implement pdflatex and bibtex as described in Section 1. When the
fork as an asynchronous system call, which requires the use application receives a notification from B ROWSIX that Make
of a variant of Emscriptens compilation procedure that gener- has exited, it inspects Makes exit code. If it is zero, the PDF
ates less efficient code. If this option is configured incorrectly, was generated successfully and is read from the filesystem.
the program will fail at runtime when it attempts to invoke Otherwise, the captured standard output and standard error are
fork. For the LATEX example, only GNU Make uses fork and displayed to the user so they can debug their markup.
3
Component Lines of Code (LoC) Class System calls
Kernel 2,249 Process Management fork, spawn, pipe2,
BrowserFS modifications 1,231 wait4, exit
Shared syscall module 421 Process Metadata chdir, getcwd, getpid
Emscripten integration* 1,557
(C/C++ support) Sockets socket, bind, getsockname,
This overview demonstrates how straightforward B ROWSIX Figure 3: A representative list of the system calls implemented
makes it to run existing components designed to work in a by the B ROWSIX kernel. fork is only supported for C and C++
Unix environment and execute them seamlessly inside a web programs.
browser. The next two sections provide technical details on 3.2. System Calls
how B ROWSIX provides Unix-like abstractions in the browser
environment and integrates with language runtimes. The B ROWSIX kernel supports two types of system calls: asyn-
chronous and synchronous. Asynchronous system calls work
3. B ROWSIX OS Support in all modern browsers, but impose a high performance penalty
on C and C++ programs. Synchronous system calls enable C
The core of B ROWSIXs OS support is a kernel that controls and C++ programs to perform much better, but currently only
access to shared Unix services. Unix services, including the work in Google Chrome via a mechanism we describe below;
shared file system, pipes, sockets, and task structures, live in- this mechanism is already standardized and is on track to be
side the kernel, which runs in the main browser thread. Pro- supported by other mainstream browsers.
cesses run separately and in parallel inside Web Workers, and
Asynchronous System Calls: B ROWSIX implements asyn-
access B ROWSIX kernel services through a system call inter-
chronous system calls in a continuation-passing style (CPS).
face. B ROWSIX and all of its runtime services are implemented
A process initiates a system call by sending a message to the
in JavaScript and TypeScript, a typed variant of JavaScript that
kernel with a process-specific unique ID, the system call num-
compiles to pure JavaScript. Figure 2 provides a breakdown
ber, and arguments. B ROWSIX copies all arguments, such as
of each of B ROWSIXs components.
file descriptor or a buffer to write to a file descriptor, from
the process to the kernel - no memory is shared. When the
3.1. Kernel
kernel sends a response, the Web Worker process executes the
The kernel lives in the main JavaScript context alongside the continuation (or callback) with response values, also copied
web application, and acts as the intermediary between pro- from the kernels heap into the processs heap.
cesses and loosely coupled Unix subsystems. Processes issue Asynchronous system calls work well for Node.js and Go,
system calls to the kernel to access shared resources, and but are a poor match for many C and C++ programs. In Node.js,
the kernel relays these requests to the appropriate subsystem. filesystem and other APIs accept a callback parameter to in-
When the subsystem responds to the system call, it relays the voke when a response is ready, which matches B ROWSIXs
response to the process. The kernel is also responsible for asynchronous system call mechanism. The GopherJS runtime
dispatching signals to processes, which we describe further in provides support for suspending and resuming the call stack in
Section 3.3. Figure 3 presents a partial list of the system calls order to implement goroutines (lightweight thread-like prim-
that the kernel currently supports. itives); this support also meshes with B ROWSIXs approach.
However, when using Emscripten to compile C and C++ pro-
In a departure from modern Unix systems, B ROWSIX does
grams, they must be compiled in an interpreted mode (called
not support multiple users. A traditional kernel would, for
the Emterpreter) in order to use asynchronous system calls.
example, use user identities to check permissions on certain
This mode produces much less efficient code than the standard
system calls or for access to files. Instead, B ROWSIX lever-
compiler, which produces asm.js output by default.
ages and relies on the browsers built-in sandbox and security
features, such as the same origin policy. In other words, a Synchronous System Calls: Synchronous system calls
B ROWSIX application enjoys the same level of protection and work by sharing a view of a processs address space between
security as any other web application. the kernel and the process, similar to a traditional operating
4
system kernel like Linux. At startup, the language runtime in faces (notably excluding the Document Object Model (DOM)),
a process wishing to use synchronous system calls passes to runs in a separate execution context, and can only communi-
the kernel (via an asynchronous system call) a reference to the cate with the main browser context via asynchronous message
heap (a SharedArrayBuffer object), along with two offsets into passing. Web Workers are not aware of one another, cannot
the heap: where to put system call return values, and an offset share memory with one another, and can only exchange mes-
to use to wake the process when the syscall is complete. sages with the main browser context that created them (see
A process invokes a synchronous system call by sending Section 6 for a discussion). Major browsers like Chrome and
a message, as in the asynchronous case, but arguments are Safari do not support spawning sub-workers from workers,
just integers and integer offsets (representing pointers) into so-called nested workers, and have not added support for them
the shared memory array, rather than larger objects (like Ar- since they were first proposed in 2009. Thus, if a Web Worker
rayBuffers) that would need to be copied between heaps. For needs to perform a task in parallel, it must delegate the request
system calls like pread, data is copied directly from the filesys- to the main browser thread, and proxy all messages to that
tem, pipe or socket into the processs heap, avoiding a poten- worker through the main browser thread. Perhaps unsurpris-
tially large allocation and extra copy. ingly, the limitations and complexity of Web Workers have
After sending a message to the kernel, the process per- hindered their adoption in web applications.
forms a blocking wait on the address previously arranged By contrast, B ROWSIX implements Unix processes on top of
with the kernel and is awakened when the system call has Web Workers, giving developers a familiar and full-featured ab-
completed or a signal is received. This wait is provided by the straction for parallel processing in the browser. Each B ROWSIX
JavaScript Atomics.wait function, part of the ECMAScript process has an associated task structure that lives in the kernel
Shared Memory and Atomics specification [4]. A side effect of that contains its process ID, parents process ID, Web Worker
this approach is that fork is not compatible with synchronous object, current working directory, and map of open file descrip-
system calls, as there is no way to re-wind or jump to a partic- tors. Processes have access to the system calls in Figure 3,
ular call stack in the child Web Worker. and invoke them by sending a message with the system call
Synchronous system calls are faster in practice for a number name and arguments to the kernel. As a result, processes can
of reasons. First, they only require one message to be passed share state via the file system, send signals to one another,
between the kernel and process, which is a relatively slow spawn sub-processes to perform tasks in parallel, and con-
operation. Second, system call arguments are numbers, rather nect processes together using pipes. Below, we describe how
than potentially large arrays that need to be copied between B ROWSIX maps familiar OS interfaces onto Web Workers.
JavaScript contexts. Finally, synchronous system calls provide spawn: B ROWSIX supports spawn, which constructs a new
a blocking primitive and do not depend on language runtimes process from a specified executable on the file system. spawn
to unwind and rewind the call stack. As such, they are suitable is the primary process creation primitive exposed in modern
for use with asm.js and WebAssembly functions on the call programming environments such as Go and Node.js, as fork
stack, which are faster and more amenable to optimization by is unsuitable for general use in multithreaded processes. spawn
the JavaScript runtime than Emscriptens interpreter. lets a process specify an executable to run, the arguments to
Synchronous system calls currently require the in- pass to that executable, the new processs working directory,
development browser features SharedArrayBuffers and Atom- and the resources that the subprocess should inherit (such as
ics, and currently only work in Google Chrome when launched file descriptors). In B ROWSIX, executables include JavaScript
with extra flags. SharedArrayBuffers and Atomics are on the files, file beginning with a shebang line, and WebAssembly
standards track, and are expected to be supported un-flagged files. When a process invokes spawn, B ROWSIX creates a
in mainstream browsers in the near future. new task structure with the specified resources and working
3.3. Processes directory, and creates a new Web Worker that runs the target
executable or interpreter.
B ROWSIX relies on Web Workers as the foundation for emulat- There are two technical challenges to implementing spawn.
ing Unix processes. However, Web Workers differ substantially First, the Web Worker constructor takes a URL to a JavaScript
from Unix processes, and B ROWSIX must provide a significant file as its first argument. Files in B ROWSIXs file system
amount of functionality to bridge this gap. may not correspond to files on a web server. For example,
In Unix, processes execute in isolated virtual address spaces, they might be dynamically produced by other B ROWSIX pro-
run in parallel with one another when the system has multiple cesses. To work around this restriction, B ROWSIX generates a
CPU cores, and can interact with system resources and other JavaScript Blob object that contains the data in the file, obtains
processes via system calls. However, the web browser does a dynamically-created URL for the blob from the browsers
not expose a process API to web applications. Instead, web window object, and passes that URL as a parameter to the Web
applications can spawn a Web Worker that runs a JavaScript Worker constructor. All modern web browsers now support
file in parallel with the application. constructing Workers from blob URLs.
A Web Worker has access to only a subset of browser inter- The second challenge is that there is no way to pass data to a
5
Worker on startup apart from sending a message. As processes 3.5. Sockets
synchronously access state like the arguments vector and en-
vironment map, B ROWSIX-enabled runtimes delay execution B ROWSIX implements a subset of the BSD/POSIX socket
of a processs main() function until after the worker has re- API, with support for SOCK_STREAM (TCP) sockets for com-
ceived an init message containing the processs arguments municating between B ROWSIX processes. These sockets en-
and environment. able servers that bind, listen and then accept new connec-
tions on a socket, along with clients that connect to a socket
fork: The fork system call creates a new process contain- server, with both client and server reading and writing from
ing a copy of the current address space and call stack. Fork the connected file descriptor. Sockets are sequenced, reliable,
returns twice first with a value of zero in the new process, and bi-directional streams.
with the PID of the new process in the original. Web Workers
3.6. Shared File System
do not expose a cloning API, and JavaScript lacks the reflec-
tion primitives required to serialize a contexts entire state into B ROWSIX builds on and significantly extends BrowserFSs file
a snapshot. Thus, B ROWSIX only supports fork when a lan- system, part of Doppio [9]. BrowserFS already included sup-
guage runtime is able to completely enumerate and serialize port for multiple mounted filesystems in a single hierarchical
its own state. Section 4 describes how we extend Emscripten directory structure. BrowserFS provides multiple file system
to provide fork support for C/C++ programs compiled to backend implementations, such as in-memory, zip file, XML-
JavaScript. HttpRequest, Dropbox, and an overlay filesystem. BrowserFS
provides a unified, encapsulated interface to all of these back-
wait4: The wait4 system call reaps child processes that ends.
have finished executing. It returns immediately if the specified B ROWSIX extends BrowserFS in two key ways: it adds
child has already exited, or the WNOHANG option is specified. multi-process support and incorporates improved support for
Waiting requires that the kernel not immediately free task struc- loading files over HTTP. To provide multi-process support,
tures, and required us to implement the zombie task state for B ROWSIXs file system adds locking operations to the over-
children that have not yet been waited upon. The C library used lay filesystem to prevent operations from different processes
by Emscripten, musl, uses the wait4 system call to implement from interleaving. In addition, B ROWSIX incorporates domain-
the C library functions wait, wait3, and waitpid. specific optimizations into its file system; for example, it
avoids expensive operations like recording the call stack when
exit: Language runtimes with B ROWSIX-support are re- a path lookup fails (a common event).
quired to explicitly issue an exit system call when they are
B ROWSIX modifies BrowserFSs overlay backend to lazily
done executing, as the containing Web Worker context has
load files from its read-only underlay; the original version
no way to know that the process has finished. This is due to
eagerly read all files from the read-only filesystem upon initial-
the event-based nature of JavaScript environments even if
ization. B ROWSIXs approach drastically improves the startup
there are no pending events in the Workers queue, the main
time of the kernel, minimizes the amount of data transferred
JavaScript context could, from the perspective of the browser,
over the network, and enables applications like the LATEX edi-
send the Worker a message at any time.
tor where only a small subset of files are required for a given
end user.
getpid, getppid, getcwd, chdir: These four system calls
Finally, B ROWSIX implements system calls that operate on
operate on the data in current processs task structure, which
paths, like open and stat, as method calls to the kernels
lives in the B ROWSIX kernel. getpid returns the processs ID,
BrowserFS instance. When a system call takes a file descriptor
getppid returns the parent processs ID, getcwd returns the
as an argument, the kernel looks up the descriptor in the taskss
processs working directory, and chdir changes the processs
file hashmap and invokes the appropriate method on that file
working directory.
object, calling into BrowserFS for regular files and directories.
Child processes inherit file descriptor tables, and B ROWSIX
3.4. Pipes
manages each object (whether it is a file, directory, pipe or
socket) with reference counting.
B ROWSIX pipes are implemented as in-memory buffers with
read-side wait queues. If there is no data to be read when a 4. B ROWSIX Runtime Support
process issues a read system call, B ROWSIX enqueues the
callback encapsulating the system call response which it in- Applications access B ROWSIX system calls indirectly through
vokes when data is written to the pipe. Similarly, if there is their runtime systems. This section describes the runtime sup-
not enough space in a pipes internal buffer, B ROWSIX only port we added to GopherJS, Emscripten, and Node.js along
invokes the callback encapsulating the system call response to with the APIs exposed to web applications so they can execute
the write operation when the pipe is read from. programs in B ROWSIX.
6
kernel.system( function sys_getdents64(cb, trap, fd, dirp, len) {
pdflatex example.tex, var done = function (err, buf) {
function(pid, code) { if (!err)
if (code === 0) { dirp.set(buf);
displayPDF(); cb([err ? -1 : buf.byteLength, 0, err ? err : 0]);
} else { };
displayLatexLog(); syscall_1.syscall.getdents(fd, len, done);
} }
}, logStdout, logStderr);
7
__syscall220: function(which, varargs) { After the kernel launches a new Web Worker, it transfers this
#if EMTERPRETIFY_ASYNC copy of global memory and PC to the new Worker as part of
return EmterpreterAsync.handle(function(resume) {
var fd = SYSCALLS.get(), dirp = SYSCALLS.get(), count = the initialization message. When the Emscripten runtime in
SYSCALLS.get(); the new B ROWSIX process receives the initialization message,
var done = function(err, buf) {
if (err > 0) if a memory array and PC are present the runtime swaps them
HEAPU8.subarray(dirp, dirp+buf.byteLength).set(buf); in and invokes the Emterpreter to continue from where fork
resume(function() {
return err; was invoked.
});
}; Node.js: Node.js (a.k.a. Node) is a platform for building
SYSCALLS.browsix.syscall.async(done, getdents, [fd,
count]);
servers and command line tools with JavaScript, implemented
}); in C, C++ and JavaScript, on top of the v8 JavaScript en-
#else
var fd = SYSCALLS.get(), dirp = SYSCALLS.get(), count =
gine. Node.js APIs are JavaScript modules that can be loaded
SYSCALLS.get(); into the current browser context by invoking the require
return SYSCALLS.browsix.syscall.sync(220, fd, dirp, count);
#endif
built-in function. These high-level APIs are implemented in
}, platform-agnostic JavaScript, and call into lower-level C++
bindings, which in turn invoke operating system interfaces like
Figure 6: Implementing the B ROWSIX getdents64 syscall in filesystem IO, TCP sockets, and child process management.
Emscripten. Node.js embraces the asynchronous, callback-oriented nature
and registering it; an example is shown in Figure 5 of JavaScript most Node APIs that invoke system calls take
a callback parameter that is invoked when results are ready.
B ROWSIX replaces a number of low-level runtime functions;
the most important are syscall.forkAndExecInChild and To run servers and utilities written for Node.js under
net.Listen. The former is overridden to directly invoke
B ROWSIX, we provide a browser-node executable that pack-
B ROWSIXs spawn system call, and the latter to provide access ages Nodes high-level APIs with pure-JavaScript replace-
to B ROWSIX socket services. Additional integration points in- ments for Nodes C++ bindings that invoke B ROWSIX system
clude an explicit call to the exit system call when the main calls as a single file that runs in a B ROWSIX process. B ROWSIX
function exits, and waiting until the processs arguments and also replaces several other native modules, like the module
environment have been received before starting main() (see for parsing and generating HTTP responses and requests, with
3.3). pure JavaScript implementations. Node executables can be in-
voked directly, such as node server.js, or will be invoked
C and C++: We also extend Emscripten, Mozilla Researchs indirectly by the kernel if node is specified as the interpreter
LLVM-based C and C++ compiler that targets JavaScript, with in the shebang line of a text file marked as executable.
support for B ROWSIX. B ROWSIX-enhanced Emscripten sup-
ports two modes - synchronous system calls and asynchronous 5. Evaluation
system calls (described in Section 3.2), one of which is se-
lected at compile time. When asynchronous system calls are Our evaluation answers the following questions: (1) Does
used, it requires use of Emscriptens interpreter mode (named bringing Unix abstractions into the browser enable compelling
the Emterpreter) to save and restore the C stack. B ROWSIXs use cases? (2) Is the performance impact of running programs
asynchronous system calls require all functions that may be on under B ROWSIX acceptable?
the stack under a system call to be interpreted so that the stack 5.1. Case Studies
can be restored when the system call completes. Emscripten
can selectively compile other parts of an application to asm.js, We evaluate the applicability and advantages of bringing Unix
which will be JIT-compiled and run as native JavaScript by the abstractions into the browser with two case studies, in addition
browser. Synchronous system calls do not have this limitation. to the LATEX editor from the overview (2). First, we build a
As with GopherJS, Emscripten provides a clear integration web application for creating memes that can run its unmodi-
point at the level of system calls. Emscripten provides im- fied server in B ROWSIX. The meme generator transparently
plementations for a number of system calls, but is restricted switches between generating memes in-browser or server-side
to performing in-memory operations that do not block. We depending on network and device characteristics. Second, we
replace Emscripten system call implementations with ones build a Unix terminal that lets application developers use dash,
that call into the B ROWSIX kernel, such as in Figure 6. In the a widely-used POSIX shell, to interact with B ROWSIX in a
case of getdents and stat, padding was added to C struc- familiar manner.
ture definitions to match the layout expected by the B ROWSIX 5.1.1. Meme Generator: Our meme generator lets users cre-
kernel. ate memes consisting of images with (nominally) humorous
When a C process invokes fork, the runtime sends a copy of overlaid text. Figure 7 contains a screenshot. Existing ser-
the global memory array, which includes the C stack and heap, vices, such as MemeGenerator.net, perform meme gener-
along with the current program counter (PC) to the kernel. ation server-side. Moving meme creation into the browser
8
5.1.2. The B ROWSIX Terminal: To make it easy for devel-
opers to interact with and test programs in B ROWSIX, we
implement an in-browser Unix terminal that exposes a POSIX
shell. The terminal uses the Debian Almquist shell (dash),
the default shell of Debian and Ubuntu. We compile dash to
JavaScript using B ROWSIX-enhanced Emscripten, and run it
in a B ROWSIX process.
Since the B ROWSIX terminal uses a standard Linux
shell, developers can use it to run arbitrary shell com-
mands in B ROWSIX. Developers can pipe programs together
(e.g. cat file.txt | grep apple > apples.txt), exe-
Figure 7: A meme generator built using B ROWSIX. All server-
cute programs in a subshell in the background with &, run
side functionality was moved into the browser without modify-
shell scripts, and change environment variables. Developers
ing any code.
can also run Go, C/C++, and Node.js programs.
would reduce server load and reduce latency when the net- The terminal includes a variety of Unix utilities on the
work is overloaded or unreliable, but doing so would normally shells PATH that we wrote for Node.js: cat, cp, curl, echo,
present a significant engineering challenge. The meme gen- exec, grep, head, ls, mkdir, rm, rmdir, sh, sha1sum, sort,
eration server uses sockets to communicate with the browser stat, tail, tee, touch, wc, and xargs. These programs run
over HTTP and reads meme templates from the file system. equivalently under Node and B ROWSIX without any modifi-
Before B ROWSIX, the client and server code would need to be cations, and were used heavily during development to debug
re-architected and rewritten to run together in the browser. B ROWSIX functionality.
To demonstrate B ROWSIXs ability to quickly port code Summary: B ROWSIX makes it trivial to execute applica-
from the server to the web, we implement our meme creator as tions designed to run in a Unix environment within the browser,
a traditional client/server web application; Figure 8a contains enabling the rapid development of sophisticated web applica-
a system diagram. The client is implemented in HTML5 and tions. These applications can incorporate server code into the
JavaScript, and the server is written in Go. The server reads browser and harness the functionality of existing applications.
base images and font files from the filesystem, and uses off-
the-shelf third-party Go libraries for image manipulation and 5.2. Performance
font rendering to produce memes [3]. The server also uses We evaluate the performance overhead of B ROWSIX on our
Gos built-in http module to run its web server. Note that case studies. All experiments were performed on a Thinkpad
this server is stateless, following best practices [7]; porting a X1 Carbon with an Intel i7-5600U CPU and 8 GB of RAM,
stateful server would naturally require more care. running Linux 4.7.0.
To port the server to B ROWSIX, we follow the process out-
lined in Section 2. First, we compile the Go server to a single LATEX Editor: Running pdflatex under B ROWSIX im-
JavaScript file using GopherJS, a Go to JavaScript compiler [8]. poses an order of magnitude slowdown. A native build of
Then, we stage the font and images for the BrowserFS filesys- pdflatex under Linux takes around 100 milliseconds on a
tem. Finally, we augment the client application to load the single page document with a bibliography. When using syn-
B ROWSIX JavaScript module, initialize a kernel instance, and chronous calls (as supported by Google Chrome), the same
start the meme-server. document builds in B ROWSIX in just under 3 seconds. While
Next, we augment the web application to dynamically route in relative terms this is a significant slowdown, this time is
meme generation requests to a server running in B ROWSIX fast enough to be acceptable. Using asynchronous system
or to the cloud. We add a function to the application that calls and the Emterpreter, which is only necessary to enable
implements a simple policy: if the network is inaccessible, broader compatibility with todays browsers, increases runtime
or the browser is running on a desktop (which is a proxy for to around 12 seconds.
a powerful device), the application routes meme generation Meme Generator: The meme generator performs two types
requests to the server running in B ROWSIX. Otherwise, it of HTTP requests to the server: requests for a list of available
sends the requests to the remote server. In both cases, the web background images, and requests to generate a meme. We
application uses an XMLHttpRequest-like interface to make benchmark the performance of the meme generator server run-
the request, requiring little change to the existing code. ning natively and running in Browsix in both Google Chrome
Figure 8b displays a system diagram of the modified meme and Firefox.
generator. With this modification, meme generation works On average, a request for a list of background images takes
even when offline. The code required to implement this pol- 1.7 milliseconds natively, 9 ms in Google Chrome, and 6 ms
icy and dynamic behavior amounted to less than 30 lines of in Firefox. While requests to a server running natively on
JavaScript. the same machine as the client are faster than those served
9
(a) Meme creator running without B ROWSIX
Figure 8: System diagram of the meme generator application with and without B ROWSIX, demonstrating how the client and server
interact with one another. With B ROWSIX, the server runs in the browser without code modifications.
by B ROWSIX, B ROWSIX is faster once a network connection Command Native Node.js B ROWSIX
and roundtrip latencies are factored in. When comparing an sha1sum 0.002s 0.067s 0.189s
instance of the meme-server running on an EC2 instance, the ls 0.001s 0.044s 0.108s
in-B ROWSIX request completed three times as fast as the re- Figure 9: Execution time of utilities under B ROWSIX, com-
quest to the remote machine. Times reported are the mean of pared to the same utilities run under Node.js, and the na-
100 runs following a 20-run warmup. tive GNU/Linux utilities. sha1sum is run on usr/bin/node,
The performance of meme generation is degraded by limi- and ls is run on /usr/bin. Running in JavaScript (with
tations in current browsers. The in-B ROWSIX HTTP request Node.js and B ROWSIX) imposes most overhead; running in the
takes approximately two seconds to generate a meme in the B ROWSIX environment adds roughly another 3 overhead.
browser, versus 200 ms when running server-side. This inef-
ficiency is primarily due to missing 64-bit integer primitives Summary: While B ROWSIXs performance is limited by the
when numerical code is compiled to JavaScript with GopherJS, performance of underlying browser primitives (notably, the
rather than overhead introduced by B ROWSIX; we expect this lack of native 64-bit longs), it provides acceptable performance
to improve with both when future browsers support native for a range of applications.
access to 64-bit integers, and with independent improvements
to the GopherJS compiler. 6. Discussion
The process of implementing B ROWSIX has highlighted op-
B ROWSIX Terminal and Utilities: Unix utilities provide
portunities for improvement in the implementation and speci-
a mechanism to compare the performance of real-world pro-
fication of browser APIs, especially Web Workers. We outline
grams under Linux and B ROWSIX. Figure 9 shows the re-
a number of optimizations and natural extensions that are gen-
sults of running the same JavaScript utility under B ROWSIX
erally useful, and would extend B ROWSIXs reach.
and on Linux under Node.js, and compares this to the execu-
tion time of the corresponding GNU Coreutils utility (written Worker Priority Control: The parent of a Web Worker
in C, running on Linux). Most of the overhead can be at- has no way to lower the priority of a created worker. As
tributed to JavaScript (the basis of Node.js and B ROWSIX); workers are implemented on top of OS threads, this con-
subsequently running in the B ROWSIX environment imposes cept maps cleanly onto OS-level priorities/niceness. Providing
roughly a 3 overhead over Node.js on Linux. Nonetheless, this facility would let web applications prevent a low-priority
this performance (completion in under 200 milliseconds) is CPU-intensive worker from interfering with the main browser
low enough that it should be generally acceptable to users. thread.
10
rs
ts
rve
lien
em
s
t se
sse
tc
t
sys
ls
cke
cke
oce
na
es
e
Pip
Sig
Fil
So
So
Pr
E NVIRONMENTS B ROWSIX 3 3 3 3 3 3
D OPPIO [9]
WebAssembly
L ANGUAGE RUNTIMES Emscripten (C/C++)
GopherJS (Go)
B ROWSIX + Emscripten 3 3 3 3 3 3
B ROWSIX + GopherJS 3 3 3 3 3 3
Table 1: Feature comparison of JavaScript execution environments and language runtimes for programs compiled to JavaScript.
indicates that the feature is only accessible by a single running process. B ROWSIX provides multi-process support for all of its
features.
FutureFeatures.md
11
References
[1] A. Baumann, P. Barham, P.-E. Dagand, T. Harris, R. Isaacs, S. Peter,
T. Roscoe, A. Schpbach, and A. Singhania. The multikernel: a new
OS architecture for scalable multicore systems. In Proceedings of the
ACM SIGOPS 22nd symposium on Operating systems principles, pages
2944. ACM, 2009.
[2] S. Doeraene. Scala.js: Type-Directed Interoperability with Dynami-
cally Typed Languages. Technical report, cole polytechnique fdrale
de Lausanne, 2013.
[3] M. Fogleman. fogleman/gg: Go Graphics - 2D rendering in Go with a
simple API, 2016. https://github.com/fogleman/gg.
[4] L. T. Hansen and J. Fairbank. ECMAScript Shared Memory and Atom-
ics, 2016. https://tc39.github.io/ecmascript_sharedmem/
shmem.html.
[5] H. Hrtig, M. Hohmuth, J. Liedtke, J. Wolter, and S. Schnberg. The
performance of -kernel-based systems. In Proceedings of the Six-
teenth ACM Symposium on Operating Systems Principles, SOSP 97,
pages 6677, New York, NY, USA, 1997. ACM.
[6] R. Hickey. Clojurescript. http://clojurescript.org/about/
rationale, 2016.
[7] T. Mauro. Adopting Microservices at Netflix: Lessons for
Architectural Design, 2015. https://www.nginx.com/blog/
microservices-at-netflix-architectural-best-practices/.
[8] R. Musiol. gopherjs/gopherjs: A compiler from Go to JavaScript
for running Go code in a browser, 2016. https://github.com/
gopherjs/gopherjs.
[9] J. Vilk and E. D. Berger. D OPPIO: Breaking the browser language
barrier. In Proceedings of the 2014 ACM SIGPLAN Conference on
Programming Language Design and Implementation (PLDI 2014),
pages 508518. ACM, 2014.
[10] J. Vouillon and V. Balat. From bytecode to JavaScript: the Js_of_ocaml
compiler. Software: Practice and Experience, 44(8):951972, 2014.
[11] D. Yoo and S. Krishnamurthi. Whalesong: running racket in the
browser. In DLS13, Proceedings of the 9th Symposium on Dynamic
Languages, part of SPLASH 2013, Indianapolis, IN, USA, October
26-31, 2013, pages 97108, 2013.
[12] A. Zakai. Emscripten: an LLVM-to-JavaScript compiler. In OOPSLA
Companion, pages 301312, 2011.
12