Skip to content

Tutorial Hello Wasm

Carlo Piovesan edited this page Jul 30, 2019 · 2 revisions

This tutorial will cover the basics of using Cheerp to compiling a generic C++ source file to Javascript and Javascript+WebAssembly.

We will show what Wasm is expecially good at: doing the computational heavy lifting.

We haven't covered yet any input methods (that's for the next tutorial), and we will keep using the most basic output method (writing to the console).

I picked a computational heavy task: "Counting how many primes are smaller than X", I choosed a general and clear implementation written in modern C++ of the segmented version of the sieve of Eratosthenes by Kim Walisch. There are a bunch of standard C++ library features used, std::cout output, std::chrono, std::vector, and we will see what happens while compiling it.

Native compiling

First, save segmented_sieve.cpp on your computer and try to compile it natively:

g++ segmented_sieve.cpp -o segmented_sieve -O3 (or clang++ or equivalent command line C++ compiler)

and then we run it: ./segmented_sieve

the output to the console will be something like:

1.6547e-05s	to sieve in the interval (1, 10)	4 primes found
2.13e-05s	to sieve in the interval (1, 100)	25 primes found
7.999e-06s	to sieve in the interval (1, 1000)	168 primes found
1.0718e-05s	to sieve in the interval (1, 10000)	1229 primes found
5.3065e-05s	to sieve in the interval (1, 100000)	9592 primes found
0.000476074s	to sieve in the interval (1, 1e+06)	78498 primes found
0.00526432s	to sieve in the interval (1, 1e+07)	664579 primes found
0.0631561s	to sieve in the interval (1, 1e+08)	5761455 primes found
0.776708s	to sieve in the interval (1, 1e+09)	50847534 primes found
11.7862s	to sieve in the interval (1, 1e+10)	455052511 primes found

Nice, the program works, we can give it a go with Cheerp.

Cheerp Javascript compiling

/opt/cheerp/bin/clang++ -target cheerp segmented_sieve.cpp -o segmented_sieve.js -O3

and then we run it: nodejs segmented_sieve.js

the output to the console will be something like:

0.004s	to sieve in the interval (1, 10)	4 primes found
0.007s	to sieve in the interval (1, 100)	25 primes found
0.014s	to sieve in the interval (1, 1000)	168 primes found
0.013s	to sieve in the interval (1, 10000)	1229 primes found
0.048s	to sieve in the interval (1, 100000)	9592 primes found
0.126s	to sieve in the interval (1, 1e+06)	78498 primes found
1.094s	to sieve in the interval (1, 1e+07)	664579 primes found

It works, internally it does equivalents calculations. There is a significant performance slowdown (numbers up to 10^9 are not treatable), but actually the relevant and non obvious thing is that automatically, without having to touch/understand the code, a C++ program has been compiled to be executable inside a browser or a JavaScript engine.

Want to see it inside a browser?

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Cheerp example 1: hello Wasm</title>
    <script defer src="segmented_sieve.js"></script>
  </head>
  <body>
  <h1 id="pagetitle">Open the console log
	(Ctrl + Shift + J or Ctrl + Option + J)
	to read the output</h1>
  </body>
</html>

Save this html file in the same folder as segmented_sieve.js, and open it in your browser of choice and check the console log.

Enter WebAssembly / Wasm

Now we will get to the serious stuff, compiling to a mix of Javascript (that will take care of managing/allocating memory and forwarding input and output) and Wasm.

The command line is way more verbose, but it's trasparent what will happens:

/opt/cheerp/bin/clang++ -target cheerp segmented_sieve.cpp -o segmented_sieve.wasm -O3
-cheerp-mode=wasm -cheerp-wasm-loader=segmented_sieve_loader.js

Here you are introduced to the -cheerp-mode flag, that defaults to genericjs (or standard JavaScript), but it could also be set to wasm or asmjs (more on this later).

Something else that have to be specified is what file will act as a loader through the -cheerp-wasm-loader paramether.

Now we just have to run it: nodejs segmented_sieve_loader.js

Why aren't we calling the wasm directly? The Wasm file is "hidden" by his loader, that will take care of loading, compiling and interfacing with the wasm compiled code.

Now the result, on my machine is something like this:

0.001s	to sieve in the interval (1, 10)	4 primes found
0s	to sieve in the interval (1, 100)	25 primes found
0s	to sieve in the interval (1, 1000)	168 primes found
0s	to sieve in the interval (1, 10000)	1229 primes found
0.001s	to sieve in the interval (1, 100000)	9592 primes found
0.005s	to sieve in the interval (1, 1e+06)	78498 primes found
0.057s	to sieve in the interval (1, 1e+07)	664579 primes found
0.571s	to sieve in the interval (1, 1e+08)	5761455 primes found
6.248s	to sieve in the interval (1, 1e+09)	50847534 primes found

Things of note:

  • the nodejs clock lacks precision under the 1/1000th of a second
  • there is a 20x speedup between the Javascript version and the Javascript + Wasm
  • Javascript + Wasm trails natively compiled C++ by 8x here. What that means? Shouldn't be surprising that C++ compiled in his native environment can be fast

Is 8x good, bad, or what? Here is not very relevant, I would say, since the main point of this page is showing that it should be possible to compile (most) C++ code to be run sandboxed in the browser.

Http-server for exectuting on the browser

Want to see it in your browser?

Take the previous html file, and change segmented_sieve.js to segmented_sieve_loader.js. You can not open it directly on your browser, since the JavaScript loader will need a way for loading the wasm file, and allowing arbitrary loading of a file is an unsafe operation that most browsers will not allow.

What then? In the getting ready section we covered how to install a web server, now we will need to run it like:

http-server -o

This will open a new tab on your favorite browser with a list of the files in the current folder. Choose segmented_sieve.html (or whatever name you gave to the file), way few second for the execution and open the console. You should be able to see similar results to the one computed via nodejs.

Conclusions

We compiled a C++ file to pure JavaScript and to Wasm loaded by a JavaScript. Great.

I suggest trying compiling your own pet projects, playing modifying the source code or going forwards with the tutorials. Up next: DOM manipulation.

Clone this wiki locally
You can’t perform that action at this time.