Using WebAssembly and Threads (Chrome Dev Summit 2018)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[MUSIC PLAYING] THOMAS NATTESTAD: My name is Thomas, and I'm the product manager for WebAssembly. ALEX DANILO: My name is Alex, and I'm a software engineer on Chrome OS. THOMAS NATTESTAD: And today we're going to talk to you about WebAssembly. We're going to start off by briefly describing what WebAssembly is and what you can use it for. Then I want to show off some of the amazing new features that the WebAssembly team has been working on to deliver to you in this last year. Then I'll showcase some of the amazing applications that have managed to build with WebAssembly, and our shipping and production. All right. So first off, what is WebAssembly, actually? WebAssembly is a new language for the web, and offers an alternative to JavaScript for expressing logic on the web platform. It's important to note, though, that WebAssembly is in no way a replacement for JavaScript. Rather, it's designed to fill the gaps that exist in JavaScript today. Specifically, WebAssembly is designed as a compilation target, meaning that you write in higher level languages, such as C++, and then compile into WebAssembly. WebAssembly is also designed to deliver reliable and maximized performance, which is something that can be difficult to get out of JavaScript. Most exciting, though, is the fact that WebAssembly is now shipping in all four major browsers, making it the first new language to be fully supported in every major browser since JavaScript was created more than 20 years ago. All right. So what can you actually do with this? Well, as I already mentioned, because WebAssembly offers maximized and reliable performance, you can now expand the set of things that you can feasibly do in the browser. Things like video editing, complex application, codecs, digital signal processing, and many, many more performance-demanding use cases can now be supported on the web. Secondly, WebAssembly offers amazing portability. Because you can compile from other languages, you can port not only your own applications and libraries but also the wealth of open-source C++ libraries and applications that have been written. Lastly, and potentially most exciting to many of you, is the promise for more flexibility when writing for the web. Since the web's inception, JavaScript has been the only fully supported way to execute code on the web, and now with WebAssembly you have more choice. All right, so now that we all know what WebAssembly is, I want to jump in and show off some of the new features that we've been adding in just the last year. First off is source maps. You likely all know how important source maps are when you're working with something like TypeScript or Babel, but it's even more important when you're trying to debug your WebAssembly code. Source maps let you turn something that looks like this into something just slightly more friendly, like this. With source maps you can see the specific line of code where an error has occurred and you can also set breakpoints and have the program actually pause at the appropriate moment. One of the big feature requests that we've heard from users is for better performance when you're starting up your application so that your module can actually get going faster. And for that we've created streaming compilation. In the past, when you wanted to compile a module you had to wait for the entire module to be loaded off of the network, and only then could you move on and actually compile it. Now with streaming compilation, you can start compiling each piece of your module immediately, even before the other parts have finished downloading. To show you what that actually looks like, here's a simple example where we called a fetch function-- or fetch for a WebAssembly Fibonacci module, and then we just passed that fetch promise directly into WebAssembly.inst antiateStreaming, and it takes care of all of this underlying bits and pieces for you to deliver this experience. We did some profiling at different network speeds to see the impact of this. We found that all the way up until 50 megabits per second network speed, the network was actually the primary bottleneck, and that the compilation was done as soon as the module was loaded. It wasn't until you hit the 100 megabits per second speeds that you actually needed additional time past the time it took to download the module in order to fully compile and get it going. To make startup time even faster, the team built and launched an entire new compiler that we called the Liftoff compiler. This Liftoff compiler takes the WebAssembly byte code that comes down off of the wire and then starts executing it immediately. The WebAssembly module is then taken off the main thread and optimized further by the TurboFan optimizing compiler. When TurboFan is done optimizing the WebAssembly code, it's then hot swapped in directly without any need for explicit developer action. Unity did some benchmarking on the effects that Liftoff had. On a benchmark where they tried to load a very large game, they found that it went from taking seven seconds to load the game to less than one second, which makes all of the difference when you're waiting to get into a game experience. Probably the biggest feature that the team's been working on this year is WebAssembly threads. WebAssembly threads lets you run fast, highly paralyzed code for the first time across multiple browsers. It also lets you bring existing libraries and applications that use threaded code such as Pthreads to the web. This is such a big feature that I'm actually going to leave most of the explanation to Alex later on. But before I get into that, I want to show off some of the cool new applications that have already been building and launching with WebAssembly this last year. First off is SketchUp. SketchUp is a 3D modeling software that you can learn and start using really quickly. Unlike traditional computer-aided design, most people can learn SketchUp almost right away. SketchUp lets people draw in perspective and then push-pull things into 3D. In no time, people can draw and redesign a living room, plan out a do-it-yourself project, or create and export a model for 3D printing. This app is a lot of fun and you should all check it out, which you can do right now instantly, just by going to app.sketchup.com. SketchUp has been around for a desktop application, but the team's strategy has always been to expand and broaden the market of people who can use 3D modeling, and by making it simple and easy to use and accessible to everyone. Delivering the app over the web was a critical step in that strategy, and the team knew that they wanted to use the same code base as their desktop applications, because rewriting their entire application in JavaScript was just simply not an option. The team's approach was to use the WebAssembly and Emscripten compiler to compile their core 3D modeler and bring it to the web. The initial port took two engineers only three months to bring to the web, which is pretty phenomenal when you realize just how drastically it expanded the reach of their application. The early focus for SketchUp has always been on the next generation of 3D modelers, and today SketchUp is already one of the most popular apps on the G Suite for education marketplace. At the same time, the app has opened up a subscription model for SketchUp, and in just over six months, the team has increased its paying customer base by 10%. SketchUp has also seen consistent growth in session time, returning visitor percentage, and active users. Moving on, the next application that I want to mention is Google Earth. I'm happy to say that Google Earth has successfully gotten their application ported to WebAssembly, including the newly added support for WebAssembly threads. The best part is that they actually got this threaded build working in both Chrome and Firefox, making Google Earth the first WebAssembly multi-threaded application to be running in multiple browsers. Google Earth did some benchmarking, comparing their single threaded version to their multi-threaded version. They found that the frame rate almost doubled when they went to their threaded version, and the amount of jank/dropped also reduced by more than half. All right, so the last big company and launch that I want to mention is Soundation. Soundation is a web-based music studio that enables anyone to make music online with a wide selection of instruments, loops, samples, and effects. No additional hardware or installation or storage is required. Everything is accessible instantly and everywhere. Soundation's mission is to facilitate musical creativity in the world, and they do this by offering a powerful, accessible, and affordable service to the growing demographic of casual producers. As an online web app, Soundation streamlines the ability for producers to connect with peers, get feedback, enter competitions, and even get record deals. Soundation is using a wide variety of advanced web features to deliver this smooth experience. And the first of these is audio worklets. Launched in Chrome 66, the audio worklet brings fast performance and extensible audio processing to the web platform. It could be used in conjunction with other cutting edge web technologies such as WebAssembly and SharedArrayBuffer. Soundation is also one of the world's first adopters of WebAssembly threads, and they use these threads to achieve fast parellelized processing to seamlessly mix songs. So let's have a look at their architecture and see if we can learn anything. On the JavaScript side of the world, they have their application UI. That application UI then talks to an audio mixing engine. This audio mixing engine then spawns off multiple different worker threads in WebAssembly, and each of these worker threads can talk to the same piece of SharedArrayBuffer memory. This SharedArrayBuffer memory is then passed on to the mixing threads, which further passes it to the audio worklet, which produces the final result. Here's a visualization showing the performance improvements on rendering a song as they added multiple threads. Adding just a single additional thread doubled their performance, and by the time they've added five threads, they had more than tripled the performance of their application. So that's a great visualization showing the performance improvements that thread can bring, but since this is Soundation, I thought we would instead try and listen to it. So here is us trying to render a song in Soundation in the single threaded version of WebAssembly. And fair warning, this is not going to be an entirely pleasant experience. [STATICY MUSIC] So as you can imagine, this is not the experience that you want when you're trying to create beautiful music. But luckily Soundation succeeded in launching with WebAssembly threads, and now they're able to deliver an experience that sounds just a little bit better. [SMOOTH MUSIC] So as you can see, not only is this a much more pleasant experience, but the CPU also has additional cycle for other work. All right, so I want to close off my segment by just talking about some of the amazing community projects that we've seen people working on out there. And the first of these that I want to mention is the awesome work that's been done by the Mozilla team and the Rust community to bring Rust to the web through WebAssembly. They have an awesome set of tools and materials to help you get started, and you can check those out at rustwasm.github.io. Speaking of languages, we've also seen more than 30 different projects trying to bring other languages to the web through WebAssembly. These languages include ones like Perl, Python, Ruby, Kotlin, OCaml, Go, PHP, and the .NET framework. Many of these languages require garbage collection, which isn't currently something that's supported in WebAssembly, though we are working on it. These languages come to the web by actually taking their garbage collection system and other runtime bits and compiling that itself down to WebAssembly, and then shipping everything down to the application page. This is a great strategy for getting started and experimenting with some of these languages on the web, but because of some of their performance and memory characteristics, these aren't currently suited for production applications. The fully supported languages today are C, C++, and Rust, but everything else should still be considered experimental. And there are so many more amazing community projects that I don't have time to do justice. We've seen people porting Gameboy emulators, GNU libraries, digital signal processing, and even entire operating system like Microsoft Windows 2000 now available in a browser tab, which is, if not a exactly pleasant experience, definitely interesting. You can check out all of these demos and much more at the forum where we have multiple demos set up for you to check out. And with that, I want to hand it back off to Alex to talk to you more about WebAssembly threads and how to use some of these features. [APPLAUSE] ALEX DANILO: Thank you, Thomas. One of the kind of big things at the conference here, when we talk about the browser, we talk about using the platform. And quite often people think of the platform as the software stack that's inside the browser, but I like to think of it a little bit different. I like to think about the hardware, the platform that's actually in your machine. So here is an artist's rendition of the inside of a desktop microprocessor. This is what you see today if you take the plastic off the top. So at the top, we have the green bit, which interfaces to the PCI bus, used to be called the northbridge. The left and right, you have memory interfaces. These little yellow boxes are integrated memory controllers. And you see all these blue tiles here. And what they are is cores. So each of those is a CPU core in its own right. So this may be a desktop microprocessor, but even in your pocket, if you have an iPhone or an advanced Android phone, you'll have something like six to eight cores in there, ready to be used to do good computing work. So when you write a normal web application, you're looking at something like this. You have one core running and so you have all this silicon doing nothing. So you're not really using the platform. Now we've seen people come along and do something like spawn a web worker to do the hard work, and have the main thread for UI. In that case, you're running a double threaded application. And so you're using the platform a bit better, but you're not really doing everything you could. Now since we have introduced WebAssembly threads, you can do stuff like this. You could actually use many cores for your application. And as we saw with the Soundation demo, there's visible improvement in the user experience. So I'd really like you to start thinking about how you can adapt your application to use all these cores. Now when you create a web worker, you have to understand that that is a threading primitive and they run concurrently. So you can do compute in parallel. And this is a primitive that we all know pretty well. But one of the things about when we do something like this, if we have an app, on the left, we have what we call the main thread-- we're all familiar with the main thread-- that interacts and talks to the DOM. The worker that we generate is what we call the background thread. So it's running in parallel but it doesn't actually have the ability to call web APIs and interact with the DOM and stuff like that. But when you create workers, and you create them normally with a JavaScript thing, it creates an instance. So these instances kind of sit on their own on the side, they're running parallel, they don't get to do anything with the DOM. So they kind of run on the side. So if you create one, you get V8 hanging off the top of your main thread, and you get an instance hanging off your worker. So then if you go and create a bunch of workers, you get a bunch more V8 instances. Now each of these instances consumes memory. So that means that if you start spawning lots of JavaScript workers to make your application do stuff more complex, it will actually consume more and more memory and you might run out on a phone, or something like that. But I'll let you in on a little secret. They don't talk to each other. So you've got separate bits of JavaScript running in all these parallel threads, but they don't communicate. They don't have any shared state. They're literally another copy of V8 sitting in memory. The way these things can talk to each other, though, is with postMessage. And postMessage is kind of like sending a paper plane over. I'll send it from this worker to that one, I'll sit around and wait for it to arrive, and there's no predictability about when that will be delivered. So it's not a great experience for a true multi-threaded application. Now, when the team built WebAssembly threads, they implemented something that looks a lot more like this. So what happens is, this is an example of, say, having three threads. So under the hood, we actually spin up the three web workers but the difference here is that the WebAssembly module is shared between the workers. So there is one copy of the code, so you're not consuming nearly as much memory. But more importantly, they share state, and the way they share state is through a thing called SharedArrayBuffer. So if you're a JavaScript engineer, you probably know what a typed array is, because you use them day to day. So SharedArrayBuffer is basically the exact same thing, except that it can be shared across workers. And so what that means is the state of the execution of the application is visible to any of the workers in parallel. Now if you farm off something into a pool of workers and you have it hanging off your main app, it will look something like this. You'll have your main thread for your main application that can talk to the DOM, it can use all the web APIs, and it can see the SharedArrayBuffer, and that SharedArrayBuffer is being manipulated by all the parallel threads in the WebAssembly module. OK, but by now you're probably thinking, this is all well and good, but how do I use this stuff in my actual application? So I'll start with a very simple example. We'll do an example which is just a little Fibonacci program that runs in two threads. So it will look a bit like this. There'll be the main thread, the background thread, the WebAssembly module, all talking to the SharedArrayBuffer. So we just take some source code, which will be something like this, which is just a bit of C code. And what we want to do is we want to compile that into a form that we can use in parallel threads. And the way we do that is with the Emscripten tool chain. So it has a compiler called EMCC, and there are a couple of flags here, though, I want to point out. The first one is -s USE_PTHREADS=1. What that does is turn on the multi-threading support when you're compiling your WebAssembly module. The second flag that's interesting is -s PTHREAD_POOL_SIZE=2. What this does is tells the compiler that I want to pre-allocate two threads for my application. So when I actually start the WebAssembly module it will pre-create two threads and get going with that. Now this is kind of visualization what would happen. If you set PTHREAD pool size to two, you get the picture on the left, you get two workers, and if you set it to eight you get eight workers. And that happens at startup time of your web app. Now you may be wondering why you care about the number. Well, the thing is that you should really try and set it to the maximum number of threads. If you say I only want two threads, and then suddenly your application needs three or four, it's a bit of a problem. So what happens is that the WebAssembly module has to yield to the main thread before it can create that worker. So if you're relying on all the threads being there at the startup, you need to set the number high enough. But of course, if you set that number too high, you're wasting memory. So this is something to tune. So in Soundation's case they used five threads and it works really well for them. So when you're tuning your apps you need to think about it. OK, so if you want to get out there and actually try this stuff, which I'm sure you're all dying to, if you fire up Chrome 70 and navigate to Chrome flags and search for WebAssembly thread support, change the setting here from default to enabled, and at that point, you'll have to restart your browser. And then you can start building stuff and testing it locally. Now once you've built a working WebAssembly thread app, you probably want to deploy it out to the public. And the way you do that is by getting an origin trial token. So an origin trial token is tied to your domain and you get it from us. And you basically-- it's just a meta tag that you put on the page. And that tells the browser, hey, these people are trying WebAssembly threads and let's use it. So if you want to go ahead and do that, and I encourage you all to do so, just go to this short link, and there's a form you can fill in, put in your URL, the reason you want to use this stuff, and go start building something really cool. Now of course, as developers, we spend most of our times in DevTools trying to debug things, which is how it is. So in Chrome 70 at the moment, which is released to stable, you can single step instructions. And that is a WebAssembly instructions. So it looks a little bit like this, like not friendly, as Thomas pointed out. So you can see this little box up here, which is showing you the threads. So this is a two thread application running. And this box is the actual WebAssembly disassembled code. So it's not the binary, it's a text form of the instructions that are in the module. And you can single step those and it's all very well and good, but realistically, we don't really like that debugging experience. So Chrome 71 brings source map support, as Thomas mentioned earlier. So source maps lets you change what you saw before into something-- oop, next slide-- something that looks like this. So this is the source code of the Fibonacci function sitting in Dev Tools, and you can single step over instructions, you can set breakpoints, you can do all stuff like that. Now, if you want to actually do this yourself and you want to generate the source map, you just need to set two flags on the EMCC compiler command line. The first is -g, which says generate debug symbols, and the second is --source-map-base, and that points to a URL where it will actually find the source map file. In this case, I'm using local host, so I'll be using it on my own workstation. OK, so I'll just recap on what we've talked about today, just so you can remember what we talked about. The first thing is it's streaming compilation, which lets the browser compile the WebAssembly module as it comes over the wire, which is launched now. It's in Chrome 70, which speeds things up. The second is Liftoff, which is the tiered compiler, so you get the first compile really fast so your app starts, and then hot swaps in the better code a bit later on. Then we have, of course, WebAssembly threads shipping now in Chrome 70, and you can use it with an origin trial, so you can ship it to your customers and they can use it and play with it. And of course, Chrome 71, which will be out really soon, contains source maps, which means that it's a lot easier to debug your code. And so I'd encourage all of you people out there to start writing using WebAssembly threads, because it unlocks the power of the supercomputer that's sitting in your pocket right now. Thank you. [MUSIC PLAYING]
Info
Channel: Google Chrome Developers
Views: 21,987
Rating: undefined out of 5
Keywords: type: Conference Talk (Full production);, pr_pr: Chrome, purpose: Educate
Id: zgOGZgAPUjQ
Channel Id: undefined
Length: 22min 12sec (1332 seconds)
Published: Tue Nov 13 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.