CppCon 2019: Ben Smith “Applied WebAssembly: Compiling and Running C++ in Your Web Browser”

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

If only the toolchain and integration would be more userfriendly . I had hard times with that :/

👍︎︎ 12 👤︎︎ u/kiffernase 📅︎︎ Sep 19 2019 🗫︎ replies

I think Ben Smith just made C++ 1000x cooler. Great job! I'm imagining this will be how programming will be taught in the future. Thank you for sharing.

👍︎︎ 6 👤︎︎ u/jjdltorre 📅︎︎ Sep 20 2019 🗫︎ replies

Very cool talk. Compiling, linking, and executing C++ in the browser, all client-side!

👍︎︎ 9 👤︎︎ u/amaiorano 📅︎︎ Sep 19 2019 🗫︎ replies

I would really like to see wasm have direct access to browser apis instead of needing js glue. Wasi seems like a step in the right direction but there's so much more work ahead like ben mentioned, such as support for: threads, atomics, exceptions, 64 bit model.

Ben used memfs for the fake fs used by clang but with a little more work, he could haved used indexeddb for a real client side persistent fs that doesn't touch the user's native fs.

👍︎︎ 3 👤︎︎ u/OrangeGirl_ 📅︎︎ Sep 21 2019 🗫︎ replies

How called book with flame effect?

👍︎︎ 1 👤︎︎ u/d_e_n_o_m 📅︎︎ Oct 07 2019 🗫︎ replies
Captions
who here uses a web browser sometimes yeah so our next speaker works on a web browser called chrome he works for Google and I assume most of you know of JavaScript its programming language so javascript around 2008-2009 started getting much faster through compiler technology and our next speaker works sometimes on JavaScript and sometimes on something called web assembly the point of web assembly is to allow you to run native code inside your browser and many other things as he'll tell you now he joined chrome in 2011 right so the browser's got way faster around 2009 and then they kind of hit a ceiling with JavaScript so what browser vendors started doing is looking at how we could bring more speed and more capabilities to the web through sandboxing technologies and other stuff that's what Ben has done since 2011 after a few years of doing this the browser vendors got together all four of them for the stent form the Standards Committee for web assembly and Ben is the chair of that standards committee so not only is he the implementer of a large part of the tool chain you use when you target web assembly he's also the implementer of what's in your browser and helps guide the technology forward through the standards committee just like the C++ Times Committee guides the implementation of suppose bus so there's no better person to tell you about what assembly then Ben Smith Ben thanks John Wow this is amazing welcome everyone hold on let me unlock my computer yeah great okay welcome yeah well first of all I want to thank you all for coming this is such an honor to be here to be able to speak to all of you and I also want to thank jf for that great introduction jf and I worked together for a long time since 2012 we were at Google together work together for four years and jf has actually been encouraging me to do all sorts of things like this give talks but it didn't start with this talk actually happened a long time ago so back in 2016 jf asked me would you like to give a presentation for the chrome all-hands that's where all of us on the chrome team get together and talk about new technologies things that were working on so I said sure why not it was a great experience it was nerve-wracking to be talking to my boss's boss's boss but I did it then later that year jf signed up for a talk full-stack fest but then decided he didn't want to do and he said no Ben do you do you want to do it instead and I said okay why not I need up giving the talk in Barcelona it was amazing it was a really great place to be and I was excellent to be able to meet so many people and tell him about webassembly so I've been talking about this for a long time as jf mentioned I'm the chair of the webassembly community group and even he was the chair before I was and so when he came to me and said actually I don't know if I want to be cheering more I want to focus on C++ do you want to be chair and I said okay sure so obviously when jf said do you want to speak Etsy if you pecan 2019 I said absolutely not okay so don't get me wrong actually this is amazing I love C++ I've been programming in it for something like 25 years but I actually had previous responsibilities that I had to take care of in particular I'm currently in a program called Google and residents this is a program where we take software engineers from Google and we send them around the United States and to historically black colleges and universities or Hispanic serving institutions and the idea of the program is to try and have better connections between industry like Google and education what we found is that our diversity numbers are not great we have diversity report and what we've found from this diversity report is that we need to do a lot better and this is one way that we we are trying to do that and so what happens is software engineer is like me is embedded into this university and I teach intro to programming so this program actually works with 13 schools around the United States Cal State for Ovaltine University of Texas El Paso even in Puerto Rico and so a bunch of my colleagues are currently teaching classes in in these locations so when I applied to the program back in January I knew that I was going to be accepted I was pretty sure I was going to be accepted and so when J have contacted me I naturally told him I can't do it I'm gonna be too focused on on this this work and so when I was accepted I ended up at Morehouse College which is this school here so Morehouse is a school that probably is most famous for being this school that Martin Luther King jr. attended he entered at the age of 15 actually and in 1944 and he graduated the bachelors of Art in sociology school was founded in 1867 and it's actually one of the only remaining men's colleges in the United States it's located an area called the Atlanta University Center where there's a couple of other HBCUs nearby Spelman which is a women's college and then Clark Atlanta University as well so as I said I knew that I was going to be incredibly busy I'm sure some of you are teachers there's a lot of work that goes into teaching I've only been teaching for four weeks now and I am already incredibly overloaded with things like preparing lectures grading homework teaching labs mock interviews because a lot of these students want to be able to be prepared for coming in and doing interview at Google so naturally I told GFI I just can't do it but if you know j.f you know that he's a very persistent person and so when he said he asked me again I actually thought oops hmm let's see maybe I should try this running me while I take a sip of water so it turns out that the languages that are taught by the Gir instructors the my fellow colleagues is primarily Python maybe not super surprising Morehouse actually is one of the schools that teaches C++ I know it's hard to imagine but yeah just one of the two schools uses soup O's Plus and so when I told my colleagues about this they kind of said this to me really C++ are you gonna teach under behind undefined behavior are you gonna are you gonna teach some pointers are you gonna teach them lambdas are you gonna teach them all this stuff and I said no no I'm not gonna teach them all that stuff we're gonna teach intro intro and so this is one reason why I was a little bit concerned about teaching C++ if y'all have ever tried to use C++ there's a lot of stuff that you need to learn you have to maybe you learn the command line you maybe have to learn tools like vim you might have to learn tools like git you might have to try and remember how to quit out of them right so then you have to remember how to compile your code oh wait note you have to remember to run clang plus plus of course sure then of course you want to commit your code oh no you can't just run commit that doesn't work you have to add no you can't do add right Oh get add okay nope well I added the executable that's wrong okay so you have to remove that right so I didn't want it I didn't want to have to teach the students this so it turns out that there's actually a really great tool that a lot of schools are using and it's called repple it and so this is an example of what it kind of looks like essentially on the left-hand side of the screen you have the code that you can type in on the right hand side of the screen it has a sort of a terminal view and you can hit the big green button at the top play and it'll compile your code and it'll run it and then it'll print your output so you can see here I have a very very simple program this is something that my students could write and and then you can run it and you can see the the output on on the right so I imagine I don't know exactly how repli'd works but I imagine it works something like this you say something like compile and run my code and it sends from the client to the server and then the server says okay I compiled it and I linked it and now it's running and then it comes back to the client and and meanwhile it also says something like oh by the way what's your name because the program is now running and then you send your output across and then the sir meanwhile the server's wait for your response right it's just sitting there running your program and then it returns with the actual result so this is something like I mean if y'all have used compiler Explorer this is very very similar sort of behavior right client-server architecture but one of the problems is of course with client-server programs is like you know sometimes the internet doesn't work very well and it actually turns out that at the University this is a real problem like we've been sitting in labs before where you know the students will raise their hand and say I don't come over OQ having problems a program and they're like no I don't I can't run the code it's just sitting there loading and so a lot of the students actually have their own personal hot spots on their phone and so whenever it goes down they just sort of pull up their hotspot and they start working but if they don't have their hotspot they can't do it at all so the reason we use repple it I mean part of the reason was because of you know not having to learn the terminal and stuff but part of it is also because these students you know they have a wide variety of computers some of them work on iPads some of them work on Chromebooks some of them work on Macs and all sorts of different computers so we need to do something better I think maybe and so I had this thought what if we take our client code and we say okay give me the full tool chain and then the server says okay here you go and it says all right here's all your data and then you can just do everything client-side yeah why not and then the server can just sit there in I don't know calculate digits of pi or whatever servers do when they have nothing better to do right so I wasn't the first person to think of this idea there's actually a really great project that top plumbing worked on before it called clang and browser and does something very similar to this I have a little bit of a different implementation but I wanted to talk about some some prior work here there's also I can't pronounce his name focus Bernard J s Linux which actually solves this problem by filing an entire x86 machine inside of the browser and of course you can do this you can run GCC here I think it takes 15 seconds to compile this something like that because you know of course it's emulating the entire x86 machine to do it but it does work so this is a possibility as well very very cool demo by the way if you want to check out some stuff you can do in the browser so the thing that's the common thread about both of these is that they use web assembly as Jeff said whoever sembly was designed to do this it was designed to run this type of code in the browser things that JavaScript could do but maybe wasn't well suited to do right so when Jeff asked me he said yes please please come to CPP con I finally said all right let's do it honestly how hard could it be right you know I'm just teaching classes and then also coming up with an awesome demo of a thing that I haven't written yet and producing a 90 minute keynote so you know not so hard so here's the plan for the talk first I'm going to talk about web assembly and Razzie I'll tell you what Ghazi is then I'm gonna show you how I made the demo and then finally I'm gonna have a demo time with some live coding and we'll see how that works out in the end all right so first what is web assembly you probably have seen if you've heard anything about webOS only many many articles and talks and podcasts about that actually asked this exact question so rather than reiterate I actually took a quick search of the top hits for what is web assembly and made a little nice dot graph of all the different words here so you could probably I don't know it's a little bit hard to read but if you follow through you can probably find what I think is probably the best definition which is web assembly is an efficient safe low-level bytecode for the web standard binary instruction format for the web so clearly that is what web assembly is okay not really whoever simply is really kind of all of these things it's about being low level it's about being a VM it's about being binary format but it's a lot more than that previously webassembly was actually at CPP con so Dan Goleman who works still works on web assembly at Mozilla gave a talk at 2016 web assembly was still pretty new then it wasn't wasn't yet officially released I think you could you could play around with it and actually even just last year damien boule gave a talk about web assembly and some of the cool things you can do there so it's this isn't the the first time we've heard about web somebody and probably not the last I like to I'd like to think anyway both of those talks do a lot of talking about what web assembly is and so you know rather than repeat what they've said I'm actually going to try and take a little bit of a different tack so what I want to do is talk about how web assembly is different than the things that you know right since everybody here uses compiler Explorer now you're all experts at assembly language I'm sure and so let's talk about how web assembly which we like to think of it as being an ice ax is is similar and yet different for some of the examples that you can see here okay so the first thing is that web assembly is a typed stack machine so that means that at every point in time in the program the type of a stack slot is known but it's not a pure stack machine we actually have unlimited virtual registers so what that means is that you can use locals to access values that you don't want to necessarily store on the stack so sometimes people say web assembly is not a stack machine but it is it's just we've got sort of an escape hatch as well so this just gives you a little bit of an example of the stack machine if you did something like one plus two you would say a 32 Const one-eye 32 constitu and then I 32 add so the first instruction pushes the one second in structured pushes the two and then the third instruction pops those two values and then adds and pushes that result onto the stack so we could take a C++ program like this and we could translate it into web assembly something like this perhaps so you can see the bottom it looks kind of wispy that's just sort of a syntax thing internally it's it's really just storing numbers values here so you can see the basic behavior here one thing to point out is that you don't actually need to return values and webassembly the last value on the stack is the implicit return value and you can also see an example here of using locals so local dot get is an example of being able to pull that parameter in from the function and then return it rustling alright so another thing about web assembly is that web assembly is validated before execution a lot of CPUs maybe don't do this right but because it's statically typed we can actually validate the entire binary and this is necessary right one of the things that we reasons that we created web assembly is because we need to be able to take code untrusted code from the web and then run it in the browser right so we need to be able to rely on the fact that that code isn't going to be able to do anything nasty so obviously we can take that code and we can validate it some of the other things we do is that we bounce checks all memory accesses so just to make sure that we we don't allow you to read outside of the bounds so just an example of that if we have our function like this and then we try and call it with a float value that's what that F 32 Const is there then we actually get a validation error and what that means is that when you actually try and run the code it won't it won't actually even run you won't get to that point it's basically like you you had a compile failure but it's actually running on the clients side when that happens another thing about webassembly is that it has a machine verified formal specification and this is very important actually because like c++ we need to make sure that a lot of different people can use web assembly and can implement it right so for example chrome has an implementation of web assembly and so does Firefox and so does Safari WebKit and so does edge and so does a lot of other implementations that are not even browser-based so having a formal specification actually means that everybody can be fairly certain that their code will run the same in all those different environments so here's some papers there are actually some really great stuff in here the first one is the sort of original web assembly paper bringing the web up to speed with web assembly there are a number of authors here and it's a actually a really great read it's like 15 pages and you can I think it's 15 pages something like that and it and it goes through a lot of the important details of web assembly the second paper here is mechanizing verifying the web assembly specification so this is where researcher conrad watt actually did a machine verified verified the implementation using isabel and then the last one here is actually the core specification we're a w3 standard and so it's currently a candidate recommendation actually I think it's currently a proposed recommendation I think it just happened a week ago and you can read through the spec here it's I've heard people say that it's difficult to read but if you can read the C++ spec I think you can probably read this and it goes into actually a lot of really great detail about how everything works even a floating-point so like if you've tried to read the I Triple E 754 spec you might find that it doesn't go into a lot of mathematical detail but this spec actually does about all the operations that we do so it's pretty cool another very very cool thing about that first paper at least I think it's cool is that these two I guess ages here have the entire typing semantics and the entire execution semantics on one page so you can just sort of look through and I mean it's hard to see here I guess I should have had a higher resolution but very cool to be able to just sort of like scan through and see the entire behavior of webassembly on on two pages okay so another thing about webassembly is that it's a Harvard architecture so this means that the program State is actually separate from its code right so it's not very common in most systems but it actually does provide some benefits it actually means that it's impossible for a program to read or write it's anything in its instructions it's not possible to modify the call stack and so that might look something like this so the top part would be say your trusted code you might have things like your the binary format of your wasn't webassembly blob you might have some internal data structures you'll probably have your compiled x86 code and then the actual call stack and then at the bottom you'll see something which is our untrusted memory and that's the only memory that webassembly can actually access it can't access any of this stuff on the top and this does prevent a certain class of exploits so for example like return oriented programming isn't possible with code like this because you can't modify the stack so another example and this is probably the most controversial thing is that webassembly has structured control flow what that means is that we don't have a go-to statement we don't have a go-to instruction in webassembly instead what we have is very much like you might expect in a very low-level programming language so we have a thing like a block and when a block means is that when you branch to a block it branches out to the bottom of it we have a loop which means when you branch to it it branches to the top of it and you can also have structures like if which allow you to branch outside of it so if it's sort of a syntactic sugar you don't need it but but it does make the code a little bit smaller which is important when you want to send it over the web so here's an example the obligatory compiler Explorer example one cool thing about this is that you can actually produce web assembly code in compiler Explorer by passing - - target Eagles wasm 32 I think there was actually a drop down for it for Reb assembly that my colleague at it and then maybe it was removed I don't know yeah not on purpose not on purpose okay yeah so it was there before and maybe it is there now again I'm not certain but so this is an example of some code here and so I'm gonna try and recreate it here so we can look at something a little bit more interesting so this is what clang did with an example where we're basically just doing a search through a linked list so you can first see that clang already did a nice unrolling of our recursive function and I'm gonna try and get into some of the detail here so the first thing you can see is we actually turn that recursive call into a loop back to the top so you can see that BRF at the bottom there BRF is a conditional branch instruction and allows you to decide whether or not it takes the value on the top of the stack compares that to zero if it's nonzero then it branches to the top then you can see this BRF at the top that BRF is essentially doing the equivalent of this if not root then return root and you can see actually something cool here we branch to the bottom and we just return zero and we know of course that root must be null in this case if and so we don't actually have to read it again we can just return I thirty-two concierge is our null pointer yeah okay so here's the next section here where we actually do a comparison let's let's drill into that a little bit so the first part here is where we actually say take the roots ex-member and then compare it to X so you can see here we do local get zero and then we do an i-32 load that actually reads from that value then we do local get 1 again that's the value we're looking for and then we do I 32 + e that means compare the two values are not equal and then we follow that up with a PRF that allows us to check whether or not those are true if so and actually yes so it actually flipped the check right it was an equality check but the compiler decided it was better to do it as a not equal check and then it can branch out from there and then finally like I said yeah we we have this recursive call here local dot get and then I 32 load 4 is actually reading the next pointer you can see because in soar or 4 bytes that's because webassembly is a 32-bit machine and then we have something a little bit weird here that's the local dot e local that T is an instruction that allows you to set a value in a local and then also leave it on the stack so it's just a nice way to be able to use the stack more efficiently but also set a local value okay so this is a question that I often hear from people when they first hear about web assembly people say stuff like kimbab assembly render graphics can well assembly access the Dom things like that can have assembly tuck me in at night and these are understandable questions because for JavaScript the answer to a lot of these things is true maybe not tucking you in but a lot of the other things right and so the way that I have actually started to answer this question is this whoever simply can't do anything you can quote me on this okay so this is this is kind of a joke but it but like what some of the best jokes it's actually also kind of true the thing is what was simply can't do anything unless you allow it to and so the way that works is that you have a web assembly module and a web assembly module has a collection of imports and a collection of exports and so the imports are what your web assembly program is allowed to do and the exports is basically what you are the web assembly module is allowing you to do to it that's maybe a way to think of it so for example if you have a web assembly module that is has maybe a carnivorous plant living outside of it you don't actually have to worry about that carnivorous plant being fed unless you provide a feed pant plants blood import if all you have is water plant then you're safe so you can actually rely on this by the way yes don't feed the plants Adri to anyone okay so this actually presents a strength and a weakness of web assembly right because what we've ended up with is that whoever simply can't really do anything by default and what that means is that you can craft a web assembly module to do exactly what you want right you can provide exactly the imports you want in exactly the exports that you want but that also means that if you have a web module and a non web module you might actually need to provide different implementations so for example here we have a console log which is how you might do it if you are using a web module and you might have a function like right if you're using a non web module right and so theoretically these these modules should be able to run identically right there there's no reason that we need to actually have a difference here but there's just no standard one way you could work around this is by by providing a shim you have a function that say implements these equivalently but what's better it is to have some kind of standard and that's actually what Y Z is so Y Z is also being developed as a standard in the w3 as a sub subgroup of the webassembly group I was originally proposed by Dan Goleman but it's it's there's a large group of people working on this and the way to think of it is is that it's got a kind of a similar functionality to a stripped-down POSIX the difference is that it's actually been developed as a capability system so unlike POSIX you know that it's and similar to webassembly you only have the behavior that you allow right so you can't access any files in the file system that aren't actually given to the to the huazi interface so currently huazi is actually very small there's only 45 functions if you know POSIX I think there's something like 300 or 400 maybe sis calls you can think of it as being very similar as this calls and so you can see some of the the common functionality that you'd expect right so we have things like being able to read arguments get clocks we can read from the environment we can read a lot of things from files and write to files we can look up things in a path we can you know exit that's always important to do we can get random numbers and then there's some scheduling as well so the way to think of this is that y'see actually is also comes with Lib C so when you use it you can actually write code like F open and that will be translated into the Y Z function path open similarly something like printf will be turned into FD write re F read will be turned into F D read and so on and since this is of course a C++ talk you could do the same thing with the C++ improvements I assume people use f string so there is additionally a tool called wasm time and one of the things that's very cool about once we have Y Z is we can take our environments web and non web and we can run them identically right and so has some time is a tool that allows you to run web assembly code natively in a non-web environment using a different web assembly JIT it's actually called the crane lift jet also being worked on by a number of people that moves along so I just want to give a warning wozy is still very very early I'm gonna be talking about huasi for the rest of the talk but if you try and use this I just want you to know that there's a good chance that you might have to spend a long time fixing issues maybe even up to 250,000 minutes ok just kidding if you want something more mature there is a much more mature tool chain called Emscripten it's been around for a very long time since 2010 I think originally developed by alone Sakai but now there's a large community of people working on it it provides a lot of the functionality that you might want a POSIX environment but it also has a graphics and it has audio and has built-in sdl and it has it has a lot of features so if you want a more mature environment this is what you should use but this is not what I'm going to talk about today just one more thing about M scripting this was actually presented at CPP con as well so Alonso Chi talked about it back in 2014 and actually chat Austin did as well back in 2014 presented on it back then they were using it to produce as MJ s which is kind of like a precursor to web assembly but a lot of the things from this talk from these talks is still true and you can still use it so you should go back and watch those talks if you're curious about this and of course there's there's many many resources on line to find a lot more about how in script in words okay so the to-do list for now this is what I basically came to when I wanted to to make my demo I said okay well the first thing I got to do is get an SDK and then I'm gonna compile clang and then I'm gonna compile lld the linker and then I'm gonna be done right okay simple this is of course after I did nothing so the plan here is to take the SDK tools which by the way run on x86 but then target wasm 32 and then take the LVM source and then compile those and then i will get something which is clang running on webassembly the wisdom plasm 32 host and awasum 32 target so clang already is a cross compiler but now I'm going to have essentially a cross compiler based on the well I guess I'll have a native Tyre a compiler for the web web assembly target so the first thing I did was I downloaded that SDK from this website here and the next thing I did was I cloned LVM from this here I think it's actually pretty recent that you can actually get LVM via get I think before you had to get it on SVN so this is very cool and then I perused these docs here how to cross compile LVM very very useful for this sort of thing so the first step that you find if you look at those docs is it you actually need the system clang and the system LD to produce a couple of these files in particular there's a executable called table gen which is used to to actually be able to do the compilation normally when you're doing a compilation of of LVM it'll do this for you automatically but when you're cross compiling what'll happen is it'll compile for the wrong target right and so if you're compiling for a 32 and then you're trying to run it then your compiler can't do it so you do this as a pre step you compile it and then you produce these outputs which run on x86 so now that I have the tools and I have table Jen and I have the LVM source now I can take these files and I compile them and I can do my cross compile so when I did that I got this issue atomic is not supported on this single threaded system now this is a reasonable thing for the web assembly SDK to do because actually threads are currently being developed as a proposal but they're not ready yet in all environments and so to be conservative it makes sense to disable it I want to say though that this is not the long-term goal we definitely are working on thread support it's just not there yet but I knew for example that LVM didn't need threats clang and an LOD don't need threads so I was able to just disable the code so the way that I did that was it's actually very cool if you have Lib C++ they allow you to provide your own threading library and so I did a very very nasty thing which is have them all do exactly nothing and you will be surprised but this actually does work I'm I see some shocked faces in the audience ok so then I started running into some of the issues that you might expect to see when you're compiling code for a different environment so rasli doesn't have signals webassembly doesn't either I knew that I didn't really need any of these so I basically commented out any of the code that used this again I'm scripting I think does have implementations of a lot of these but again from my case I knew that I didn't need to to handle any of these similarly webassembly doesn't have a map and mom on map and M protect we definitely want to support these but you know webassembly is still very early it turns out that in my case I actually knew that I didn't really need the sort of advanced features of M map so I could turn this into a malloc and free and that was basically enough to do what I I needed to do l LD actually does have an optimization where they M map files and then they can just write directly into it for to make it run very fast it's very cool though actually they have a they have a fallback where if M map isn't supported it'll just you know write into a buffer and then write it out as a file so turns out that they kind of already solved the problem for me so there's some issues with things like I mean by the way I just want to say these names are horrible right anyway so yeah so these are like things about users and passwords and such I knew that I didn't need any of this stuff so again I just sort of put in dummy values I forget what I actually put in for these but I'm sure it was something fun these ones are a little bit more surprising to me actually I think huazi is actually kind of conservative in in the features that it provides and so in particular gets get CVWD and real path really should be provided and maybe trigger as well and so I I basically just wrote sort of simple implementations of those stab BFS and F stat VFS those are like basically looking at information inside the file system I I heard dummy values as well and then up to I think that's actually a capability restriction so but again I don't think that that one was actually required so I commented that out and of course I octal is the the grab bag of the POSIX functions I think in this case it was just used to maybe it was to change the mmm I actually can't remember I think it might have had something to do with like changing the the width of the terminal in any case it wasn't necessary okay so these ones are people's favorites as well said jump long jump those ones actually are supported in M scripting in a very very nasty way what actually happens is when you call set jump what actually happens is it calls out to JavaScript creates a try block calls back into your web assembly calls your functions and then when you do a long jump it actually calls up to javascript throws and then it catches in the JavaScript block and then goes back and it turns out that that actually does work but it's not preferred and so I will also like to say that there is a proposal an ongoing proposal to add real zero or low cost exceptions to to webassembly that's actually pretty far along it has some of the limitation in in some browsers it's just it's a little too early for huazi and so again because of being conservative it's not it's not here so yes and then get host name again that can just be stubbed out and then finally everyone's favorite the the lovely process functions so things like POSIX spawn and get paid and gets it and we pit all that stuff yeah that's more stuff that only is necessary if you run the compiler as a driver so it turns out because the compiler actually has the compiler and the driver in the same executable we can just sort of skip all of the process stuff there are ways we can make this sort of thing work using the hostess kind of an environment maybe running JavaScript as a as a pseudo kernel I know that sounds horrible but you could do it but for now I know we don't need these and so I skip these as well okay so 28 functions later I finally had enough to make this work and actually in the case of LVM I only had to touch 12 files because they they actually condensed all the code that I need to change down to about yeah 12 files it's all in this support library so it was very convenient to do so at this point I started getting some weird linkers stuff like this which I mean I don't know if you can read this but I certainly couldn't I asked my colleague Sam about it and he told me that the problem was actually probably that the libraries that were being generated weren't being indexed I don't know if anyone's run into this problem before it turns out that bran Lib normally does this basically takes your your library file and then it it puts a little index in there so it can find the symbols more quickly the problem was is that I was using the system's brand Lib to try and work on a web assembly library and so as a result it wouldn't work so of course now I have to add another step I have to compile a LLVM AR and LLVM ran Lib for for x86 and then use those as well along with my hacked LVM source and actually it doesn't say it here but my hacked huazi sdk tools and then finally finally finally finally I got this all to work I got a clang and I got an LD so this is what I ended up with a clang binary that was about 50 megabytes I think that could actually be shrunk down currently the one I have is about 35 megabytes after I did some I ran an optimizer on it I think that could probably be smaller than that though and then LD is also 28 megabytes and so you can see because we're using Waze II it's not even using actually all of those 45 functions it's only using about 25 of them and then it only actually exports one function start and the start function is basically the intro and then we'll call your main function and then run and do and then do everything it also exports us a couple of other useful things you can see that I exports a heap base and data end and then an object called memory and I'll talk about those now so the way that web assembly memory is laid out in LVM at least LVM produce web assembly is something like this we have a giant block of memory the part at the bottom is unused it turns out that webassembly a null pointer is completely fine to read and write because it's just reading index 0 of your memory so it's maybe a good idea to leave a little bit of space there in case people start scribbling over the null pointer you don't actually write over any of your static data so then we start writing your static data at about 1k we have data end which represents the this sort of the end of the stack and then we have heap base which represents the the start of your heap and you can see the stack grows downward like all proper stacks do and the heap grows upward and the nice part here is that memory can actually grow so we can grow the size of the webassembly memory and then the heap will i'll be allowed to expand out in that direction as well so you might have remembered that I said that web assembly doesn't allow you to access the stack and it turns out that it doesn't but because we can do things like take address taken local variables or have dynamically sized local variables we do actually need to have a shadow stack as what we call it and this does live in memory this lives in webassembly memory and you're allowed to access it so these are a couple of cases where we actually do have a stack pointer that does move inside the webassembly memory and we store it for these values but only for the values that that the compiler knows it needs to actually allocate space on the untrusted stack for so as I said before clang actually is a driver and a compiler so when you run clang normally what happens is it runs both of these pieces for you so for example if you do food at C - au feu it will compile to a few executable by running the compiler and the linker for you and if you run a - hash hash hash I think that's how you might say that it will tell you what it's actually running under the hood this is sort of stripped-down version of it but it gives you the right idea it runs a number of different arguments here passing the the triple that's required you can see it does emit AUB's that's what the dot - Oh turns out actually yeah that that's how that would be the equivalent of like - see yeah right thank you and then it also passed it it passes in things like this this route and so on so one cool thing that we can do now that we have these wasm binaries in huazi is we can take wesam time our non-web tool and we can run our compiler using wasm but but in the just like from the command line and the way you do that is you run wasm time and then as I said it's a capability system so you actually have to provide you have to tell it what it's allowed to access and so in this case we say you're allowed to access the current working directory I'm calling PWD here and it's called source inside the inside the system and then similarly we can access a directory called sis root and that's called sis inside the system so you can see the sort of colors match map up here and so we can run this and test this and it works and that's very cool because now I don't even have to like there's no JavaScript yet this is all just running on the command line and so one cool thing about this capability system is that actually you are prevented I guess you might say from from accessing outside of there so in this case I'm trying to access outside of the source directory but in as far as wasm time is concerned as far as he is concerned that's not a real thing there's nothing outside of that it's kind of like you're in a showroom yeah exactly thank you for help anyone who's helping me out when I'm trying to remember words by the way so yeah this actually uses lib pre-open to handle this behavior I think it's all ready to borrow some of the code from that so this is very very cool for being able to do sandboxing okay so what we have now is we have wasm time which has the Razzie imports already implemented and then we can use those to run clang but if we want to run this in the browser we actually need to provide our own Wasley implementation because that's not currently provided in the yet it might be in the future but for now it isn't but fortunately we can write some amount of web assembly and JavaScript to be able to implement those imports and then run clang so it turns out that Wesley actually already has a polyfill for this but you know because my job was not hard enough as it is I decided to write my own in-memory file system to be able to implement huazi here so that I could run clang in the browser so this is how I did that I have my JavaScript code here and then I have a mem FS web assembly module that I compiled using C++ and using huazi which implements the imports that are required for clang including things like FD read FD seek and so on as you can see here and then I have other implementations that are not related to the file system that are implemented in JavaScript so things like being able to get the arguments from the from the color also being able to read the environment and things like doing a process exit something like that so to make this work we actually need to add a little bit of functionality that in JavaScript what happens is we have an in-memory file system that has its own memory and then we have clang which has its own memory and we want to be able to copy data back and forth between the two right because what will happen is clang will say something like read this file and it has some buffer that it wants to get filled in and the Memphis has that data available and it wants to be able to take the data from the memory FS and then copy it into claim and now currently web assembly does not allow multiple accesses to memory so a particular web assembly module can only access its own memory but JavaScript has access to both memories so what you can do is import a copy in and copy out function from JavaScript which knows how to do the behavior and and call that from inside mem if s to be able to say copy my data in or copy my data out to the to the running executable so the other thing that you need for a compiler I did not have in my to-do list is you need includes you need libraries and things like that but one of the very very cool things about what we just did is that we already have this stuff available in the web assembly the huazi sdk it needs that to be able to run Rasim 32 in the first place so we can actually take the exact same sis route from the huazi sdk and we can tar it up together and include that instead and write that directly into our memory in memory file system so what I did was I well I got ahead of myself here a little bit I up this data and I produced a sister oogtar and then I wrote a little function in JavaScript that allows you to enter it and it turns out that actually tar is an incredibly simple format so I think this function is something like 15 lines or something to be able to read it out into the in-memory file system it's very cool and so this actually allows us to do pretty much everything we need the only other thing I had to add here is that it would it's nice to be able to rather than using the low-level interface for reading and writing files to the memory filesystem I I have a little sort of cheap function that allows me to just write whole files indirectly just a nice little convenience there okay so taking a step back this is how our system is set up we have JavaScript and we have our memory FS so the very first thing we do is we take our sister me on Tarth at into the memory FS then the next thing we do is we take our CC file that's in JavaScript somewhere and then we write that across into our memory FS as well so it's available to be accessed by claim then we take that file and we write it into clang using our copy in when we get a compile call from JavaScript what clang will do then is we'll use that memory FS and then write it back out as a an object file into the same in-memory filesystem then as you might expect when you do your link call it'll take that object file link it and then it will produce a web assembly file again in the mem memory filesystem and then finally what we can do is we can pull that web assembly file out and then we can compile that using the normal web assembly compilation tools which will produce a new foo module here which we can then run and hook up to the same in-memory file system and then it can actually do any of the access that we need to do here so that gives you may be sort of a lay of the land here but I actually was being a little bit I didn't go into all the details that are required here so there there are a couple of steps that are necessary to produce a web assembly module the module isn't actually the thing that you run the module is more sort of like the compiled code you might say the instance is more like the running process so the the module is sort of like the static data and the instance is sort of the dynamic data it actually has the memory objects and so on and one of the cool things here is that you can actually take a single module and you can produce multiple instances in exactly the same way that you have one executable and you have multiple running processes of that and so what this means is that we can actually compile our code once for clang and instantiate it which is to say sort of run that process many many times and so the compilation is is relatively slow three seconds or so depends on the implementation but instantiation is much much faster because all that work is pretty much done you just sort of have to fill in the holes there's there certain stubs that are not completely filled in and so instantiation sort of fills in those pockets some final things about the implementation here so there are a couple things that you need to do when you're running on the web there is a kind of issue which is that pretty much everything runs on the main thread including the UI and JavaScript so if you run code in JavaScript and it blocks the UI that means your your web page won't be able to be interacted with anymore and of course the one solution to that is to create a worker so what I do is I actually create a worker and that's where all of that behavior that I talked about before actually happens so when you click a button to run it says run on the worker and then it actually runs all of that code inside the worker and then it sends the results back to the main thread to for display and similarly I have a service worker that I run a service worker is kind of like a programmable Network proxy and the idea there is that now when we do a fetch for the clang module and for the LD module which are they're both pretty large we can actually cache those on your system and so the demo that I'll show you very soon actually does that and it means that once you download it you don't really have to download it again so that's pretty cool too there are a couple of other things that I use mostly because I saw that compiler Explorer use them I don't think compiler Explorer uses ace maybe Monaco Monaco yeah ok so I ended up using ace I also use golden layout which is an amazing tool very very cool highly recommend and then I also use x-term j/s that's basically a terminal that allows you to display all the nice output I think it's very commonly used so yeah these are all really excellent tools and made my job a lot easier for making this stuff look good all right and with that who's ready for some super live demos okay ah nervousness okay can we see this can I see this all right so this is currently what I have so this is the the first tool that I sort of played around with this is basically doing what compiler Explorer does so I have my terminal over here let's see if I can this is much harder to do than I thought it was going to be okay so you can see the assembly code on the right I actually cross-compiled the tool so the I I sort of lied when I said that the web assembly tool was was compiling to webassembly it because clang is a cross compiler you can just add another target in so I added in x86 as well so you can see that here so if I do something like changes to a two you can see that it changes that to there on the movie ax 2 or so on right so let's see if I can do the thing that I was practicing we can do like and and do that and then say this and it's compiling stuff and I can say if let's see n is less than to return B that's right right then I can do something like this and there should be B and a plus B right ok right is that correct all right I don't know if it's correct but we can do is we can do a test function here I actually don't need that and then oops we can say return fit up to ok and we can just increase this song right okay I mean I think that's right okay so this is this is sort of like the in-browser equivalent of compiler Explorer and yeah so this is all there's there's no server's involved here I actually slowed down the the compiling but previously I was testing it with compiling like every hundred milliseconds or something I bounced it and it was still fine it's pretty fast in fact I have a little show timing here I think that'll work we'll see yeah this is way harder to see than I thought it would be all right I'm not gonna mess with that I can't I can't find the scrollbar okay so let's look at some other demos so the cool thing about that previous demo is that it's a it's compiling and it's just producing assembly output right but we can also run remember that was what that foo has and was doing so we can take our code and we can compile so you can see this is actually compiling clang and then it's compiling LD and that it runs right so of course we can you know whoops oh yeah this is I really need a and so you can see the second time it's a little bit faster okay so clearly my scroll bar is not moving with me but you can see there okay I'm gonna actually close this and reopen it okay I actually also added some local storage here so you can see that it keeps that this again just sort of a nice compiler Explorer feature so you can see this stuff there okay so let's see oh my goodness okay so there's an example I dropped in the compile time regular expression header so I just sort of put it in include so yeah I'm sure it's fine and so you can see here if I compile it should all compile and work okay so this doesn't actually do anything because all it's doing is the static assert down here but you can see that it actually does work so if I change this to like you know 2017 yeah so it gives me an error here static assert failed and you can see it's actually pretty fast right I mean I don't know this isn't doing a whole lot of work but I think it's pretty cool that it's like you know pretty zippy okay so that's compile time regular expressions okay so here's some silly stuff that I was playing around with so you can see some some lambdas here and things like that okay that's too too big actually I can just change it let's change that to be a little smaller so I added some stuff where you can like you know draw tree and draw diamond and yeah ASCII art right it's cool kids are into it actually the kids are into it I I asked them to do an assignment where they drew stuff with asking art and they were like they had a lot of fun doing that yeah so anyway just a silly little thing that I that I wrote up okay so that's shapes let's see alright of course we need to do our Mandelbrot Mandal bro fractals okay so that's let's see if I can make that a little smaller there you go yeah so there's an ASCII art so that's pretty cool you can you know zoom in and stuff that's probably not a great place to zoom in but you can see so it's not super fast but it's I think it's fast enough okay but of course ASCII art is like not the only thing you can do so I took a small PT which is a small path tracer by Kevin Beeson and I made some tweaks to it and of course added a canvas and let's see so actually I'll leave it here for now so we can see it running so it's it's running you can see it's it like you know wait for it okay so says it's done let's see what we got yeah so that's pretty cool so what's cool about this actually is that it's using the browsers canvas to do this I basically just wired up imports so that you get all the features of the JavaScript canvas but you can access it via C++ so you can take a look at the code down here I made this like little canvas class and then an image data and then you can write in the data and then do commit commit basically takes that data and then copies it out into JavaScript and then you can do put image data which is exactly the same name as it is in JavaScript and and draw it alright so that's an example oh yeah so then here's an example of something that I actually ported I originally wrote this in in raw web assembly but then I decided well why not port this to C++ for the talk so this is a meta ball so let's see if this works yeah there we go so this actually does something a little bit sneaky I guess I'll say is that there's actually a set up function and a loop function the set up function is called from main and then main exits and then loop is called intermittently to update the frame and the way that works is actually I I actually throw an exception so that it doesn't clean up any of the data so that I can still access everything after so that's a that's a super nasty hack and there will be a better solution this for this in the future but for now I realized this in my hotel like yesterday that I was like wait this doesn't actually work so I had to I had to like fix that but anyway so that's a that's a fun little demo old-school metaball demo okay and then here's everyone's favorite the doom fire effect I basically got the code from a fabian Sinclair's book excellent book by the way and you can actually see that the code it creates such a good effect and the the code is really simple you can see it's just like this is the entire loop that that does it and you know because this is CPP con I'm using the seatpost bus random functions I copied those from CPP reference because I do not know how to write it otherwise okay last one that I wanted to try and do I wanted to try and work with you all okay so this is this is my little starter code that I wanted to start with it's just doing something simple right now it takes the image data it draws a little pattern here it puts it out and then you can see that the code here or at least I hope you can see it you can change the fill style and you can change the font and you can change the text here and then it's actually centering the text okay so if I get rid of this I really should have practiced this okay I can change this to CPP con and I should see that and I can do something like how does this work set fill style to black and I can do fill wrecked mmm with height I think okay that works and then I can make a little function like draw and I can take that here I don't want to Center it anymore so let's do that and I think I can do this this is great like I'm sure that all of you are like looking like you forgot a semicolon okay so I think this is looking okay yeah let's make that a little bit smaller cool and now we can do other nasty things like this global variables and we'll just do something like that and we'll start this off here this is way harder than I thought it was gonna be okay so that's not doing anything yet but of course I can do actually let's make these doubles I still have time is that a plus oh my gosh okay so we should be able to run that and see okay it's starting to move okay and of course we want to multiply this by our elapsed I think that might be too slow yeah so let's do that it's a little faster okay that's better we can say if X is greater than with - I mean I don't know or X is less than zero then we'll just turn it around why did I decide to do this I hope y'all are still enjoying this cuz right at this point I'm just coding I don't know okay it's got to be faster than this we can't wait yeah so the problem is I don't know if this is actually gonna be able to hit a corner which is I know what we all want anyway okay yeah so so then that was fun okay did I have anything else that I was gonna do I don't think so okay back to the slides back to the sides thank you thank you for thank you for indulging me okay yes almost out of time okay does my clicker still work no that's fine does anything still work yes okay so technical limitations of of this prototype first off reading input blocking calls co-routines okay so one of the problems with running on the web is that the web doesn't want a block right everything is asynchronous and so if you try and do something like C in or reading from from the network or anything like that where you need to block it's just not going to work there is a way to do this by transforming your code so Alonza kai the author of whom scripting actually added a feature called async of phi i think it's called and he gave a talk about it I think two days ago actually where he goes into details about how you can convert a code that does do blocking into sort of like maintaining and sort of unwinding and rewinding the stack so that's a good tool based solution but there's also in the future we're going to have solutions for this using the exception handing proposal to provide something like delimited continuations so watch this space for the future exceptions as I mentioned before exceptions are not currently supported I think if you tried to throw an exception it just abort but this is again a proposal for webassembly we were actively working on it we're gonna add this feature I hope very very soon threads and Atomics I mentioned this before but it's just not currently in the in the in the tool we're working on it there's a proposal I'm actually the champion of the the proposal and I'd really like to see it move forward we have an implementation in Chrome but the the spec is a little bit further behind so just some quick links if you're interested in web assembly you want to come to the meetings they are open it's a web assembly community group you can go to meetings and you can see all the notes from our previous meetings if you're curious about the future proposals go to web assembly proposals there's a huge list of them the champions and their current stages if you want to read the spec there's this link here if you're interested in y'see go to huazi dev of course I'm scripting now org and then this demo that I just showed you is right there at Benjie github iOS and clang yeah it's very alpha so you know do it with what you will and that's it thank you I have 11 minutes so if people have questions I have answers or I have dodges hi thanks for the talk thank you at the very end emotion that exceptions are not supported and by that amended exceptions in in webassembly are not supported their exception in the compiler which targets the C++ compiler which targets webassembly all supported or both yes so the question is I I said that exceptions are not supported what did I mean and the answer is yes so obviously exceptions are supported in clang you can use them they will be compiled but they will could be compiled into an abort currently in my implementation of this in the future we there's active work adding exception support to LVM I think it's pretty much there but don't quote me on that and at that point you should be able to use it to compile to web assembly using the new exceptions proposal and then then be able to run that in web assembly as well it does that answer your question so if I compute exceptions called the Teelin success yes will with the board it'll it'll run but it old board if you throw currently yes but in the future it and if you use them script in it actually like I says turns exceptions into a thunk out and a thunk back and so those that actually will work but that's sort of a stopgap until we actually have the full support okay thanks thank you alright Ben you mentioned this workaround I guess for the fact that in webassembly you can't share memory between different modules yeah and I go back to JavaScript inheritance so are there plans to loosen that limitation so it doesn't feel so happy yeah there are plans to reduce that it's actually the the binary format is extensible to this point where you we could actually add support for multiple memories we currently just have a limitation there's no proposal about adding multiple memories but it's we've talked about it a lot for exactly this reason yeah so in this slide of yours with the memory map I don't see a code section so how do function corners work yes member functions member function partners with yes so the question is how do functional Earth yeah I kind of glossed over that entirely they do work there's a separate structure called a table that does that the idea of the table is that it stores anything that's a reference that is not like raw date raw date I like raw bytes and so currently that's only used for functions you can basically there's an instruction called call indirect that will take an index and then index into that table and then call that function and it's in its type safe so you have to provide the type signature as well in the future actually very very soon we're going to have features where you can take any number of tables and you can store other data in them as well as opaque handles that's so that way you could actually take a JavaScript object store it in a table and then reference it from from web assembly so so tables are sort of the our mechanism for dealing with objects like data object meaning like JavaScript objects are like host object yeah thank you a question hi so it was a little bit painful watching your talk not because of your talk but because you went through a lot of the things that we went through so we have this project called browse --ax yes basically everything that you your thing does but it also has more yeah you can do synchronous i/o you can do synchronous i/o from a file system that's mounted over HTTP right it's it's quite general we just ported it forwards to to wowza recently so if people are interested in using something that may make this job a little easier it supports almost all of POSIX and it actually supports multiple processes IPC all kinds of stuff yeah yeah so basically just saying browse like is something that does something very similar I'm sorry I didn't mention actually knew about browse X it's very very cool too to to do that sort of stuff again yeah running that all on the web yeah thank you does your project run on Firefox it does run on Firefox I test it on on firefox there was one issue that I ran into which is that the the canvas feature that I use actually relies on off-screen canvas which is supported in Firefox but it's behind a flag currently so if you try and load that up in Firefox it currently I think will print an error message but if as soon as poss screen canvas is supported then it should work all that stuff I tried it thank you yeah hello I actually have two questions if that's okay the first one is why is webassembly advertised as 32 bits targets and are there plans in creating a 64-bit version of the same way uh-huh yeah so the question is why is webassembly 32 bit yeah it's a good question I think originally it was because we figured that was all we would need for to get a lot of a lot of the at work that we needed to get done done we always had plans for Assam 64 but as of now that's currently vaporware I think if you look at LVM there is wasm 64 target that could work maybe I don't think there are any implementations the way that you could extend wasman 32 to Assam 64 like in our heads we've sort of gone like well it should just work right but yeah it's it's not it's not clear it would be a different binary format as well so there definitely some issues there yes okay thank you and the second question is how this actually was different from the aim scooter because on your slides you'll have shown how you implemented most of the POSIX functions which are already implemented in X scripted so I'm curious to know why you didn't use that and what's actually the benefits of using the way was it directly uh yeah okay so the question is why didn't I use the Emscripten versions I mean part of it was just because I wanted to talk about you know how this is implemented if I just using scripting I'd have to sort of say well I'm scripting does this and I don't really understand that code but also because yeah I don't know yeah mostly that's the reason okay thank you very much yeah thank you you mentioned that the web assembly is typed so yeah you have you push an int 32 to the stack and everything does when you compile C++ code do the types on C++ get translated into a type from web assembly or are those just the native types yeah so the question is web assembly is typed does do C++ types get converted into web assembly types is that right yes yeah so the answer is that it does in a sense it's very similar the way that LVM will lower to lv miR except for it's even lower than that because I think L V Mir has pointer types and things like that and in webassembly pointers are just 32-bit integers so it really is just an index into into linear memory into the untrusted memory space so the types are all basically lost at that point by the time you compile to webassembly the high higher types of c++ are lost and they're converted into the lower types of web assembly which currently just is in 32 in 64 float32 float 64 and that's it okay yeah thank you since web assembly has some protection against array out of bounds accesses and things like that what happens if you do that in your C++ code yeah okay so the question is what happens if you try and access out of bounds in C++ code so the first thing I should mention is accessing out of bounds if you have an array and you access that out of bounds that probably will work right because we just have a big bag of bytes right and if you have an array that starts here and ends here and you access outside you're just gonna access some other data just like you couldn't see you pose plus now if you access something that's completely outside of memory what happen as a trap and trap is sort of like the equivalent of yeah like a a segfault or something except for you can catch it in JavaScript and then do something with it so there are a number of different traps dividing by zero if you try and do a call indirect and the type signature doesn't match that's actually a runtime check so that's a trap as well there's other other traps as well so thank you the question is can can do have any way to debug code suppose code compile to but by simply in the classic way yeah so the question is how do you do bug the code and the answer is right now very carefully and in the future actually I think very soon there is a debugging subgroup of the web assembly group that is focused on this topic I think the idea will be that you you will have a separate module that has a everything went off okay you'll have a separate module that basically is intermediary between the web assembly environment and your executable and that will be able to handle the bugging for you so it will do something very similar to like I think in the browser if you're running like on what's that tool that the JetBrains browse debugger anyway when you're using that it communicates with the chrome dev tools to be able to do debugging it'll be something very similar to that but it'll be its own executable that it's running and doing the communication that's the current plan but as of now I don't think there's much there yet so yeah right now it's a lot of printf debugging but we do actually I should take a step back from that we do have some support inside dev tools in chrome and in Firefox that's limited but but not bad it'll give you stack traces with with actual C++ names and it but it will show you and it'll show you source lines but you can't actually inspect values as if you were C++ values so yeah thank you it looks like one more question and that's probably it so adding to that question you mentioned that you cannot alter the the exact table code yeah usually that's how the debugger servers work by putting a trap on that is there kind of a hardware way of doing that saying I want you two to trap when you get to this point the question is is is will you be able to modify the executable code to insert a like a breakpoint or something yeah yeah I I don't think that's gonna be the way it works I think it's probably gonna be something more like there's a communication protocol and so the web assembly engine already knows how to do all that stuff itself so you don't actually need to modify the executable code to do it that way we'll probably end up using the internal breakpoint structures that are already there for JavaScript so that's that's my guess yeah I was thinking more like if you could have a ported version of a gdb server or so you could do remote debugging well I'd like to talk to you more about this but the session is over so thank you everyone thank you [Applause]
Info
Channel: CppCon
Views: 36,109
Rating: 4.4870467 out of 5
Keywords: Ben Smith, CppCon 2019, Computer Science (Field), + C (Programming Language), Bash Films, conference video recording services, conference recording services, nationwide conference recording services, conference videography services, conference video recording, conference filming services, conference services, conference recording, event videographers, capture presentation slides, record presentation slides, event video recording, video services
Id: 5N4b-rU-OAA
Channel Id: undefined
Length: 90min 8sec (5408 seconds)
Published: Thu Sep 19 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.