Blogs

We are using Web Assembly to build Lekh Board

Last Updated On: Oct 10, 2021

WebAssembly (or wasm) is a portable binary format for executable programs, and a corresponding textual assembly language. The main goal of WebAssembly is to enable high-performance applications on web pages. Languages such as C, C++, Rust etc can be compiled into web assembly and can be executed in a browser environment.

We are compiling our Lekh Board C++ code into wasm and running in the browser. Lekh Board is an intelligent collaborative whiteboard app. We released the Lekh Board a while ago and in this blog post I am sharing the experience of using the web assembly in Lekh Board.

I am going to explain our use case first then will explain why we use the web assembly. Then performance comparison of native code to web assembly running on Firefox and Google Chrome.

 

Intro to Lekh Board and high level architecture

Lekh Board is a whiteboard app with the intelligence of recognizing user’s rough drawings and converting them into shapes and connection lines. It recognizes all basic shapes which you typically draw in a typical whiteboard discussion. Here is a domo of the shape recognition capability of Lekh Board.

Shape Recognition

 

Lekh Board is built with the Lekh Diagram code base. I was doing the Lekh Diagram (iOS and Android) as a hobby app for quite some time and sometime ago I decided to build a collaborative version of it called Lekh Board. The core logic of Lekh Diagram is written in C++ with only dependency on the standard C++ library.

The iOS app UI is written in Object C and consumes the C++ code directly in Object C project. The Android UI is written in Java and consumes the C++ code via JNI.

This can be explained with the following diagram:

Architecture

The Lekh Core does not have any platform specific code. It only uses the standard C++ library. This makes it a perfect candidate for getting converted in web assembly without any issues.

 

Using web assembly to build Lekh Board

To run the Lekh Core logic in browsers we had these choices:

  • Rewrite the Lekh Core in Javascript
  • Use web assembly or asm.js to make use of the C++ code into browser

We did not want to rewrite so the only option we had was to use web assembly (or asm.js). But then we had these concerns:

  • What is the binary size that users have to download for loading the app in browsers?
  • Will the performance be acceptable?
  • Browser support

Our initial exercise was to address these concerns before taking the decision to use the web assembly. In our initial experiment, we got around 5M of the wasm file and performance was all good. Also we could run the web assembly in Firefox, Chrome and Safari. After these observations, we were pretty sure that we could use the web assembly.

 

Now our architecture becomes like this

Architecture

 

The Lekh Board uses HTML canvas for drawings. The glue code has logic to call the HTML canvas API. The glue code also exposes some of the C++ code into javascript using embind.

 

Debugging

The Google Chrome team put out a blog post describing how to debug the web assembly in Google Chrome. Unfortunately, I was not able to get it working. The example there is for a very simple C++ code. In our case, we have a mix of C++ and C Code. Actually, we have written our code only in C++ but we also embed Lua which is written in C. We compile separately and produce bit code and then use emcc again to link them together. I followed the instructions given by the Chrome team, but that did not work.

So for the debugging the only thing that we could do was to use console.log() from the glue code.

 

Performance:

Here is a simple shape recognition benchmark. In this benchmark, I am calling shape recognizer 1000 times for same set of points which are recognized as a circle.

Here is pseudo code for the benchmark

void benchmark() {
  auto rawPoints = getPointsForCircle();
  auto t1 = get_cur_time();
  for (int i = 0; i < 1000; i++) {
    Recognizer recognizer;
    recognizer.recognize(&rawPoints);
  }
 auto t2 = get_cur_time();
 cout << t2 - t1;
}

 

The shape recognition algorithm is single threaded only. Also there is no IO or any syscall so it is purely CPU intensive task.

The benchmark code was run on OS X as native binary (compiled with clang) and then as web assembly in Firefox and Google chrome.

 

Configuration

  Version/ Detail
OS macOS Big Sur 11.3.1
Hardware MacBook Pro (15-inch, 2018) 2.9 GHz 6-Core Intel Core i9
Clang Apple clang version 12.0.5 (clang-1205.0.22.9)
Emcc emcc (Emscripten gcc/clang-like replacement) 1.38.30
Firefox 92.0.1 (64-bit)
Chrome Version 94.0.4606.71 (Official Build) (x86_64)

 

Native run

The native binary was compiled with -O2 optimization flag. The benchmark code was run 5 times and and it took average of 2955 milliseconds. So every shape recognition call took around 2.9 ms

 

Web Assembly run

Here is the result of the web assembly run. The time below is the time taken to execute the above benchmark code while running as web assembly. The percent number is the execution speed relative to the native speed.

Optimization Flag No Flag -O2 -Oz
Firefox 6302 ms (46.88%) 19231 ms (15.36%) 3771 ms (78.36%)
Google Chrome 28190 ms (10.48%) 4619 ms (63.97%) 6746 ms (43.80%)
Binary Size 5.44M 1.48M 1.04M

 

The fastest speed we could achieve was 78.36% of the native speed while running in Firefox. I guess the Firefox could do even better with the -O2 flag but in this case the Firefox is behaving strangely. I repeated the run many times (with -O2) assuming I made some mistake, but got the same result every time. Probably some temporary issues with Firefox which I think should be fixed in future releases.

But in general, the Firefox seems to be much more performant than Google chrome in executing the web assembly.

 

We are using the -Oz optimization flag in our build process. With this we get our wasm file of ~1MB. Network transfer (with gzip encoding) is even lesser ~340 KB. This is amazing!!

 

Conclusion

Web assembly is quite ready for the production use cases. We tested the Lekh Board on browsers in Android, iOS, Windows, Mac and Linux and it seems all the major browsers on these platforms support web assembly.

Firfox performs much better than Chrome in executing the same web assembly.

 

Please send an email to rajeevk@lekhapp.com if you want to contact the author