Tuesday, 19 December 2017

WebAssembly at a Glance


Evolution:



Figure 1.0 WebAssembly Evolution



asm.js which first appeared in 2013 and was developed by Mozilla as a sub-set of JavaScript. It is meant to be a compile target for languages like C/C++. This allows porting of existing applications written in C/C++ to run in the browser without the need for any additional third party library.  Using asm.js significantly increases performance when compared to same code written in JavaScript. Although asm.js runs on all browsers(https://caniuse.com/#feat=asmjs) it has highest performance on Firefox. 

Web assembly is a new compile target being standardized by W3C along with companies such as Google, Microsoft, Apple and Mozilla. Although asm.js performed close to native speed it was not consistent across all browsers but WebAssembly promises to perform consistently. Web assembly is influenced by asm.js and it can be thought of as an optimized version of asm.js for faster performance. 


Compared to asm.js WebAssembly provides the following advantages to developers:

  • Reduced load time.
  • Reduced run-time memory consumption for code.
  • Smooth performance.
  • Full set of capabilities for C/C++ applications with almost native performance.

Current Spec:
Figure 2.0 WebAssembly Pipeline (Stable)



Figure 3.0 WebAssembly Pipeline (Unstable)

WebAssembly is essentially efficient low level byte code which is fast to load and execute. It is stack machine language that loads values on to the stack to use them for computation later. 

It supports the following value types:



  • i32: 32-bit integer
  • i64: 64-bit integer
  • f32: 32-bit floating point
  • f64: 64-bit floating point
Currently Emscripten can be used to convert existing C/C++ code to '.wasm' files. The conversion pipeline from C/C++ to wasm is visible in figure 2.0 which is the stable pipeline. And figure 3.0 show shows the unstable pipeline as of 12/16/2017. Browser compatibility for WebAssembly can be found at https://caniuse.com/#feat=wasm .

Example: Adding two integers


emcc add.c -O3 -s WASM=1 -s SIDE_MODULE=1 -o add.wasm

The above script builds the C file to wasm. It is built as a stand alone module using 'SIDE_MODULE=1' option. And the optimization level is O3.

C:

//File: add.c
int add(int a, int b) {
  return a + b;
}

WASM(WAST representation):

//File: add.wasm
(module
  (type $type0 (func (param i32 i32) (result i32)))
  (type $type1 (func))
  (import "env" "memoryBase" (global $global0 i32))
  (import "env" "memory" (memory (;0;) 256))
  (import "env" "table" (table $table0 0 anyfunc))
  (import "env" "tableBase" (global $global1 i32))
  (global $global2 (mut i32) (i32.const 0))
  (global $global3 (mut i32) (i32.const 0))
  (export "_add" (func $func0))
  (export "__post_instantiate" (func $func2))
  (export "runPostSets" (func $func1))
  (func $func0 (param $var0 i32) (param $var1 i32) (result i32)
    get_local $var1
    get_local $var0
    i32.add
  )
  (func $func1
    nop
  )
  (func $func2
    get_global $global0
    set_global $global2
    get_global $global2
    i32.const 5242880
    i32.add
    set_global $global3
  )
)

HMTL/JS:


<!doctype html><!-- index.html -->
<html>
  <head>
    <meta charset="utf-8">
    <title>WASM add example</title>
  </head>
  <body>
    <script>
        function loadModule(filename) {
          return fetch(filename)
              .then(response => response.arrayBuffer())
              .then(buffer => WebAssembly.compile(buffer))
              .then(module => {
                  const imports = {
                      env: {
                          memoryBase: 0,
                          tableBase: 0,
                          memory: new WebAssembly.Memory({
                              initial: 256
                          }),
                          table: new WebAssembly.Table({
                              initial: 0,
                              element: 'anyfunc'
                          })
                      }
                  };

                  return new WebAssembly.Instance(module, imports);
              });
      }

      loadModule('add.wasm').then(instance => {
          const add = instance.exports._add;

          console.log(add(1, 6));//7
      });
    </script>
  </body>
</html>

In the example above a function adding two integers in C is complied to wasm. Here '.wasm' binary file contains complied code but here the intermediary textual representation (s-expression) is shown. The '.wasm' file will be loaded into the browser using the provided JavaScript code. Finally the function 'add' can be called by passing in two arguments 1 and 6 which leads to 7. 

Performance:


    JSperf link: https://jsperf.com/fibonacci-wasm



Fig 4.0 Performance Measurement Fibonacci Sequence

This performance setup implements two versions of Fibonacci sequence generator methods. One is slow(recursive version) and the other one is fast(iterative version). Both JS and wasm implementation are compared and it is evident that wasm is the fastest.

Learning/Exploration Tools:


WebAssembly Explorer(https://mbebenita.github.io/WasmExplorer/):



Fig 5.0 WebAssembly Explorer

This is a great tool for exploring and understanding WebAssembly. Developers can input their C/C++ code in the first pane and this tool automatically compiles that code to appropriate 'wast' format visible in the second pane. It then converts 'wast' to 'x86' assembly format on the right most pane. 

Alternatively users can input 'wast' directly and it will be converted to 'x86' assembly.

Developers can toggle 'LLVM x86 Assembly'  to allow LLVM compiler to do the conversion to 'x86' assembly rather than Firefox's compiler. 


There are also built-in examples and other features that developers can choose from the options pane.


WebAssembly Fiddle(https://wasdk.github.io/WasmFiddle/):


Fig 6.0 WebAssembly Fiddle

This is tool can be used to share WebAssembly snippets with others using unique URL. It has 4 panes on each corner.


Top-left pane: The top-left pane is where developers can write C/C++ code.

Top-right pane:This is where the JavaScript resides for utilizing the wasm module.


Bottom-left: This is where the compiled 'wast' can be seen. There is also an options drop down to show other representations of the compiled C/C++ code.


Bottom-Right: This is where the output of the compiled program can be seen for debugging purposes. 

WebAssembly Binaries(https://wasdk.github.io/wasmcodeexplorer/):

Fig 7.0 WebAssembly Binary Explorer

This tool is good for understanding the binary representation of WebAssembly. On the left pane there is binary representation and on the right pane developers can open a 'wasm' or 'wast' file. 

Future:


The development team is trying to improve on the following aspects:

  • Improve the WebAssembly LLVM backend from experimental to stable implementation in Emscripten.
  • Add support for more languages to be source for wasm compile target.
  • Backward compatibility of new WebAssembly features.
  • Developer tools integration for WebAssembly in the browsers.
  • Add support for multi-threading.
  • Efficiently allocate and manipulate GC objects directly from WebAssembly code.

Saturday, 21 October 2017

WebSocket Server with JavaScript

Server:

Handshake Client/Server:

Fig 1.0 HTTP Handshake

Before the connection is established the client sends a handshake request to the server via GET method. It passes 'Set-WebSocket-Version' header to let server know if a specific  version of WebSocket is required for communication. It also passes 'Set-WebSocket-Key' which is then used by the server to generate a new key which it sends via the 'Set-WebSocket-Accept' header. The key that server sends back to the client is generated from concatenating '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' with the  key set from the client and taking SHA-1 hash of the resulting string. Then the server sends back base64 encoded version of the hash. 

Ping/Pong:

To ensure the connection is alive the client or server may send a ping with opcode 0x9 to each other after the initial HTTP handshake. The client or server need to send a pong with opcode 0xA right after they receive a ping. The pong should have the same payload as it was received in the ping. A pong received without sending a ping should be ignored.

Client Tracking:

To prevent multiple handshakes for the same client each client needs to be tracked by the server. Tracking clients will also help recognize DOS attacks. This is where Socket.io comes into picture as a server side framework that makes creating a websocket server less cumbersome.  

Socket.io:

installation:
Socket.io can be easily installed from the npm repository.

npm install socket.io --save

server setup: 
The server can be setup using either http module in nodejs or using express. In this case http module is used. 

let app = require('http').createServer(handler)
let io = require('socket.io')(app);
let fs = require('fs');

app.listen(80);

function handler(req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

io.on('connection', function (socket) {
  //handle communication here
});

In the sample code above the 'handler' functions serves the static content like index.html file. This is where the UI for the application may reside. The 'server' object is passed to the 'socket.io' object so it may also start listening. The 'connection' event is fired as soon as the connection with the client is established.

It should be noted that the port where the app listens should either be 80 or 443 for best results. Other ports may cause issues due to firewalls and proxies.

receiving:
Information can be received from the 'socket' event. 

io.on('connection', function (socket) {
    socket.on('message', function(data){
        console.log(data);
    });
});

In the above code the 'message' event is used to receive data. But in practice the client can send data via any event ('abc', 'new york', 'hello').

message single client:
Socket.io allows developers to send message to a single client. This can be done two ways: 

1. Sending message back to the sender-client. 

io.on('connection', function (socket) {
    socket.on('message', function(data) {        socket.emit('message', 'testing');
    });
});

2. Sending message to a specific client using socketId. In the sample code below developers can replace '<socketid>' with specific id.  

io.on('connection', function (socket) {
    socket.on('message', function(data){
         socket.broadcast.to(<socketid>).emit('message', 'message to specific client');
    });
});

broadcasting:
While broadcasting the message is sent to all other clients except the one which has sent the message to be broadcast. 

io.on('connection', function (socket) {
  socket.on('message', function(data){ 
      socket.broadcast.emit('message', "this is a test");
  });
});

client tracking:
Clients can be tracked using their specific socket ids. When the client makes a connection the socket object contains the id associated with that particular client. 

io.on('connection', function (socket) {
    let socketId= socket.id;
    //do something with socket id.
});



Fig 2.0 Namespaces and Room Tree


Namespace:

In Socket.io 'Namespace' is a specific endpoint on the same TCP/IP connection. This is helpful if a single connection is to be used for different use cases. By default the clients can connect to '/' endpoint but custom endpoints like '/gaming' and '/messaging' can be specified for the same connection. 


let app = require('http').createServer(handler)
let io = require('socket.io')(app);
let chatNameSpace = io.of('/chat');
let gamingNameSpace = io.of('/gaming');
let fs = require('fs');

app.listen(80);

function handler(req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }

    res.writeHead(200);
    res.end(data);
  });
}

chatNameSpace.on('connection', function (socket) {
  //handle chat communication here
});

gamingNameSpace.on('connection', function (socket) {
  //handle gaming communication here
});

In the sample code above custom 'Namespaces' have been defined using 'io.of' method. So '/chat' and '/gaming' name  spaces can have separate communication endpoints where the clients connect.

Rooms:

Within each 'Namespace' the communication channels can be further separated into 'rooms'. Clients can join or leave the 'room' which makes the application more dynamic and flexible. 

io.on('connection', function(socket){
  socket.join('myroom');
  //send message
  io.to('myroom').emit('message', 'mymessage');
  socket.leave('myroom');
});

The above code snippet shows how socket can join a room using '.join' method. It can then send message message to 'myroom' and the leave the room using '.leave()' method.

'io' vs 'socket' object:

The 'socket' variable represents a single connection. Each time a new client connects a new 'socket' object is created and passed in the callback and it can only be used to communicate on that connection. The 'io' variable on the other hand represents a group of 'socket' objects for all connections. 

Saturday, 7 October 2017

WebSocket Client with JavaScript


Fig 1.0 Components of WebSocket


Client:

'WebSocket' Object:  

The 'WebSocket' object enables developers to establish a connection with the server. The URL for the server endpoint along with specification for sub-protocols can be passed to the  WebSocket  constructor. In this case the client is a web browser.

let socketInstance = new WebSocket("ws://www.myservice.com/endpoint", ["protocolA", "protocolB"]);

The first argument passed to the constructor is the URL representing the server endpoint and the second argument can be a single argument or an array representing sub protocols for WebSocket which are optional.

Events:

onopen:
When the connection between the client and the server is created the 'open' event fires. So any communication with server can be performed in the event callback.

socketInstance.onopen = (event) => {
  //start communicating with the server
};

onmessage:
The 'onmessage' event is fired when the client receives information from the server. And the information can be accessed through the event callback.

socketInstance.onmessage = (event)=> {
  //do something with the data
  console.log(event.data);
}

onerror:
This event gets fired when there is an error in communication between the client and the server. Developers can use this event to warn users that the web application will close.

socketInstance.onerror = (event) => {
    //do something with the event data
    console.log(event.data);
};

onclose:
The 'onclose' event is fired right after the 'onerror' event or when calling the 'close' method. Developers can use this event to close the application and perform any final operations before the user is redirected.

socketInstance.onclose = (event) => {
   //check event code for cause 
   if (event.code != 1000) {
      // if 1000 it means that the connection was closed normally.
      // inform user if not online
      if (!navigator.onLine) {
         console.log("You are offline. Please connect to the Internet and try again.");
      }
   }
}

Methods:

Once an instance of 'WebSocket' is created then it can be used to start communicating with the server.

send:
The send method can be used to send information to the server in the form of string or JSON string. But the client can only communicate with the server after 'open' event is fired so the communication logic can be placed inside an event callback. 

socketInstance.onopen = (event)=> {
   
  let message = {
    userId: 'asdfow9238x',
    score: 140,
    time: 4500,
    turn: 5
  }

  socketInstance.send(JSON.stringify(message); 
};

close:

socketInstance.close();

The connection can be simply closed via the 'close' method. After the connection is closed the 'onclose' event gets fired.

Sunday, 10 September 2017

Using Math.js Library



When building compute heavy applications the need for custom math functions will put significant load on developers. But math.js library promises to ease development by providing essential math operations from everyday uses cases to focused scientific domains. 


Basic Operations:


Math.js supports the following basic types:

  • Boolean
  • Number
  • BigNumber
  • Complex
  • Fraction
  • Array
  • Matrix
  • Unit
  • String
math.round(math.e, 3);            // 2.718
math.atan2(3, -3) / math.pi;      // 0.75
math.log(1000, 10);              // 3
math.sqrt(-4);                    // 2i
math.pow([[-1, 2], [3, 1]], 2);
     // [[7, 0], [0, 7]]

Math.js has all the usual functions that any programming language provides by default. In this case basic operations like square root, log, power, number rounding and trigonometric functions

Custom Functions:


The real advantage of using math.js is that it allows developers to write custom functions. So the functions are not limited to certain level of complexity. 


math.eval('(2+3)/4');                // 1.25
math.eval('sqrt(3^2 + 4^2)');        // 5
math.eval('sqrt(-4)');               // 2i
math.eval(['a=3', 'b=4', 'a*b']);,   // [3, 4, 12]

let scope = {a:3, b:4};
math.eval('a^2 + (2*a*b)+ b^2', scope); // 49

The 'eval' method parses the string to perform computation. The 'scope' variable can be passed to allow value referencing. The ability to reference values allows developers to build modular functions that can be used with different arguments.

Matrix Operations:

Math.js is very good for matrix manipulation tasks. Implementing explicit functions to do matrix operations would take significant development time. So Math.js eases the development process quite a bit.

//General matrix
math.matrix();                          // Matrix, size [0]
math.matrix([0, 1, 2]);                 // Matrix, size [3]
math.matrix([[0, 1, 2], [0, 1, 2]]);    // Matrix, size [2,3]

//Matrix with zeros
math.zeros(3, 2);   // Matrix, size [3, 2], [[0, 0], [0, 0], [0, 0]]

//Matrix with ones
math.ones(2, 3);    // Matrix, size [2, 3],    [[1, 1, 1], [1, 1, 1]]

//Diagonal Matrix
math.eye(2, 3);  // Matrix, size [2, 3], [[1, 0, 0], [0, 1, 0]]

//Matrix values within range
math.range('2:1:6');     //generate matrix from 2 to 6 and increment by 1 [2, 3, 4, 5]

//Random valued matrix
math.random([2, 3]); // returns a 2x3 matrix with random numbers between 0 and 1

The 'matrix' method is useful to generate a new matrix object. Math.js provides various ways to generate a matrix like random valued matrix, diagonal matrix and range matrix. 

Element Wise Operation:

let a = [[9, 5], [6, 1]];
let b = [[3, 2], [5, 2]];

math.dotMultiply(a, b); // returns [[27, 10], [30, 2]]

The 'dotMultiply(<matrix1>, <matrix2>)' method allows developers to multiply matrices element wise. Similar to 'multiply' other element wise operations can also be done via 'eval' method.


Dot Product/Cross Product:


//dot product
math.dot([2, 4, 1], [2, 2, 3]);       // returns number 15

//cross product
math.cross([[1, 2, 3]], [[4], [5], [6]]); // returns [[-3, 6, -3]]

The 'dot' and 'cross' methods allow developers to easily compute dot and cross products of  matrices.

Add/Subtract:

let  matrix1 = math.matrix([[2, 0], [-1, 3]]);               
let  matrix2 = math.matrix([[7, 1], [-2, 3]]);  

// perform addition
math.add(matrix1 , matrix2);                      // Matrix, [[9, 1], [-3, 6]]

// perform subtraction
math.subtract(matrix1 , matrix2);                      // Matrix, [[-5, -1], [1, 0]]

The 'add' and 'subtract' methods make it easy to subtract high dimensional matrices.


Transpose:

let A = [[1, 2, 3], [4, 5, 6]];
math.transpose(A); // returns [[1, 4], [2, 5], [3, 6]]

The transpose of a matrix can be achieved through the 'transpose(<matrix>)' method where any matrix object can be passed as an argument.