Skip to main content

WebAssembly experiment: C++ vs JS

Introduction

WebAssembly brings the webapp executes as fast as running machine code. It is now supported in all major browsers (Chrome, Firefox, Edge, Safari). I’m very excited about the potential so I started to evaluate it.

This is an experimental webapp to demonstrate how to call the external C++ module from Javascript. In addition, here also compares the performance for manipulating a list of products in C++ (with STL) versus Javascript (with Lodash).

Contents of this Blog:
  1. Development environment setup
  2. Develop C++ module
  3. Develop the web interface
  4. Develop Javascript module
  5. Performance comparison result

1. Development Environment Setup

In my development environment, I’m using MacOSX 10.11 EI Capitan. The programming language versions I installed as below:
$ node -v
# v8.9.1
$ python -V
# Python 2.7.13
$ java -version
# java version "1.8.0_171"
$ clang++ -v
# clang version 6.0.1  (emscripten 1.38.6 : 1.38.6)
$ cmake -version
# cmake version 3.11.4

Install Visual Studio Code

Visual Studio Code (VSCode) is a light-weight and cross-platform editor. You can download it free from here.

After the VSCode installed, you’ll need to install C/C++ language extension like this screenshot:

Install Emscripten

Emscripten is a source-to-source compiler to compile C++ into WebAssembly.

Follow these instructions to install the Emscripten and its prerequisites.

When I installed the Emscripten. I need to run below commands before using it:
# Make sure at Emscripten installation directory
$ source ./emsdk_env.sh
Below command is to verify the installation:
$ emcc -v
# emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.38.6

2. Develop C++ Module

Create the project

Before creating the project, make sure you have run the source ./emsdk_env.sh in Emscripten directory. Then type this commands:
$ cd ~/code # suppose your codebase in ~/Code
$ mkdir wasm_exp && cd wasm_exp
Create the module files as below:
  1. main.cpp
    • This is the main program file.
    • Create a product array.
    • Operate the product array (two filterings and one sorting).
    • Perform one million times of operations on the product array.
  2. headers.h
    • Include all STL headers. The product array operations are using STL vector.
  3. product.h
    • Declares a product object
  4. product.cpp
    • Operator overloaded function for dumping the product to ostream such as cout.
  5. Makefile

VSCode settings for building and debugging

Now you can run the C++ module inside the VSCode. To do that, create two files: tasks.json & launch.json. VSCode can help you to create the tasks.json. In VScode editor, click menu “Tasks”->”Configure Default Build Task…”->”Create tasks.json file from template”->”Others”. Like the screenshot below:

Replace the tasks.json with below contents:
{
"version": "2.0.0",
  "tasks": [
    {
      "label": "build",
      "type": "shell",
      "command": "make",
      "args": [ "debug" ],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "problemMatcher": {
        "owner": "cpp",
        "fileLocation": ["relative", "${workspaceFolder}"],
        "pattern": {
          "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
          "file": 1,
          "line": 2,
          "column": 3,
          "severity": 4,
          "message": 5
        }
      }
    }
  ]
}
The next one is to create launch.json for debugging. In VSCode, click “Debug” tab, then select ‘Configure or fix launch.json’ as below screenshot:

Modify the two settings in launch.json:

...
      "preLaunchTask": "build",
      "program": "${workspaceFolder}/app",
...

Now you can set a breakpoint in VSCode and start the debugger (press F5). See below screenshot:

Compile the C++ into WASM

Emscripten can compile the C++ module into a single Javascript file which is WASM format. I’ve already created the build script in the Makefile. To build it, type:
$ make wasm
Note: If the build failed, you may forget to run source ./emsdk_env.sh inside the emsdk directory.

If the build is successful, it generates an app.js and app.wasm files respectively. Actually, we’ll need only the app.js file in the next section.

3. Develop Web Interface

In this section, we’ll develop a simple website to incorporate the app.js which generated by Emscripten. I’m a fan of Semantic UI, so I build the frontend in Semantic UI. All the external dependencies (include frameworks, libraries) retrieve from the CDN.

Click here to view the contents of index.html. Notice that it loads the app.js using async syntax as below:
...
</body>
<script async type="text/javascript" src="app.js"></script>
...

4. Develop Javascript Module

To make the comparison between WebAssembly and Javascript. I developed a Javascript module that performs the same operations as what the C++ module does. I used Lodash to process the product array. You can view the contents of product.js file. Below is the main operations:
...
function ProcessProducts() {
  let products = CreateProducts();
  let products1 = _.filter(products, (product) => {
    return product._price >= 20.0 && product._price <= 200.0;
  });
  let products2 = _.filter(products1, (product) => {
    return product._description.includes('pretium');
  });
  let products3 = _.sortBy(products2, '_price');
  return products3;
}
...

5. Performance Comparison Result

At this time, we can run a webserver to browse the website to start the comparison. At the project root directory, start the http-server as below commands (if you haven’t installed the http-server, you can install it via npm install -g http-server):
$ http-server
# Starting up http-server, serving ./
# Available on:
#   http://127.0.0.1:8080
Open the Chrome browser (version 57 or above) and browses http://localhost:8080. Below is the website screenshot:

The Results from my PC

You can click C++ and JS execute buttons one by one. Below is the result of my Macbook (2016):

6. Conclusion

As you can see, in this experiment, Javascript out-performs C++ nearly 3 times. This surprised me. It represents Google’s V8 engine is really very fast even faster than C++ STL. But it is just a case of the smaller array sizes. In the results of another experiment, C++ WebAssembly performs faster than Javascript on larger array sizes.

The Source Codes

The source codes are hosting in this Github repo


Comments

Popular posts from this blog

Create An Online Store Theme Used By MyCMS

MyCMS is an open-source Content Management System to generate static online shop website. You can use my hosting to input your products, or you can download the source codes and host it in your own server (running NodeJS). Please refer to my Github repo for the detailed installation instructions. This blog is a step-by-step tutorial that shows you how to create an online-shop theme. In this tutorial, it’s using my hosting to input the shop details and products. If you’re hosting the MyCMS by yourself, just change the domain name to yours will do. Introducing MyCMS Before making the theme, you’ll need to use MyCMS to configure the demo shop and input two demo products. MyCMS generates a static website via a theme. The generated static website is NO server program required. You can put the website files (HTML/CSS/JS) to any CDN, hosting. Shop Configuration You must prepare below settings Before using MyCMS: Setting Description Example Store name Your store name will be displayed in t...

How I make a web-components based dynamic Javascript page at the top of Google Search

Introduction Everybody wants their website shown at the first position of Google search. SEO (Search Engine Optimization) is a big topic. I just helped my client's website shows the database records at the top search rankings (at least several Chinese generic keywords). See the three example questions all are listed at top ranking: Website background: My client's website  popa.qa  is a traditional Chinese Q&A site that lets members ask and answer questions. All answers and questions are storing in the database server. Step 1: Create The Project This blog illustrates the problems and the steps to fix that with project source codes. Below is the description of the basic project: NodeJS backend (server.js) Develop an API ( /get-database-records ) to simulate getting database records Web-components frontend (index.html) An example component IndexPage  make use of  LitElement to render database records To start the server type: npm start Then I check the webpag...

Build A Simple Sales System using Google Drive

Google Drive is a free-to-use cloud service with a 15 GB limit storage. 15 GB is large enough to store documents, and "program" too. Yes, it's correct. We can program Google Drive. This blog is a step-by-step tutorial to show you how to build a simple P.O.S. system on Google Drive. Create a Google Sheets to define the products 1. Login to Google Drive using your Gmail account and create a Google Sheets: 2. Input the products in the Google Sheets Create a Google Forms for sale input 1. Create a new Google Form 2. Edit the form and the first field Note that leave the option field unchanged. We'll assign it programmatically in below 3. Add a quantity field 4.  Add a last field for the price input How to copy data from Google Sheets to Google Forms? We need to add a script to do that. Google developed Google App Script (GAS) for us to achieve that. Now go back to the Google Sheet we just created above. Then enter to the script editor You'll see the below screen. Then ...