Sunday, April 23, 2017

WebAssembly - sending a Javascript array to wasm for modification and getting back the modified version.



Alright so WebAssembly has hit the MVP and is enabled by default in more than one browser right now, so starting to use it makes sense.

One of the main functions of WebAssembly is to let it handle the heavy lifting part of the code.

This post is going to take you through sending an array to a 'wasm' function, make some crazy low level stuff on its elements and finally reflecting that change on the web page with Javascript.

Note that this post explains how to send an array that's already filled, which involves copying the elements into the WebAssembly memory space. In a lot of cases, though, you would want to skip the copying part and just build the array incrementally directly into the WebAssembly memory space (see the JS code near the end).

For the sake of simplicity, his post assumes that you are using C/C++ with Emscripten to generate the helper JS file.

C

Let's start at the C level (sorry)

#include <stdint.h>

int addThree(uint8_t *buf, int len) {
  uint8_t *item;
  uint8_t *end = buf + len;

  for (item = buf; item<end; item++) {
    *item += 3;
  }

  return 0;
}

Let's break things down..

On line 1, we include the stdint library which gives consistent operation across different machines.

On line 3, we define our function, it takes two parameters:

  • a pointer to the start address of the array in memory (which is technically the location of index 0). Array pointers have to be one byte in size.
  • and the number of elements in this array (to help us loop through the items).

We then define two pointers to the start and end location of the array in memory (it is safe to add together diffreent integer sizes).

We then loop through the array items and do the crazy stuff (like adding 3 to each element in this case) and just return 0 to say that we are done.

Look out for overflows, like in the above example, we have used the unsigned int8 integer to hold the data, which can store integers from 0 to 255, so adding a 3 to say a 253 will cause an overflow and get you into trouble.

Alright, One thing left, we've got to compile that code and export the addThree function.

assuming that you already have emcc into your PATH, compile the C file with this (I choose the name "freeThree.c", because it rhymes).

 emcc -o three.html freeThree.c -s WASM=1 -s EXPORTED_FUNCTIONS="['_addThree']"

Here we are just telling the compiler to use native WebAssembly (and not asm.js) and we tell it to expose the addThree function.

Notice the "_" before the function name, this is very important.


While we are here and before we go to the Javascript side of things, if you may have to pass large arrays to this function, consider making room for the extra memory.

one technique that I use is to use the ALLOW_MEMORY_GROWTH flag, run the web page, and keep an eye on the console, it's going to give you the a number every time is grows the memory. Note that when your app demands extra memory, the size of memory doubles rather than keping up with the exact demanded size, still you can get a nice approximation about what your maximum memory size should be. Add this to the end of the previous compile command after EXPORTED_FUNCTIONS="['_addThree']".

-s ALLOW_MEMORY_GROWTH=1

ALLOWMEMORYGROWTH prevents some optimizations that the compiler can make, so after you have decided that your app will use a maximum of X memory it's better to use that number for specifying the static memory of your app. So instead of the ALLOW_MEMORY_GROWTH flag, use this

-s TOTAL_MEMORY=X


Javascript

Now let's shift our focus to the Javascript level.

After you've run the above command, emscripten should have outputted a nice bloated three.html file with a .js file with the same name (along with the .wasm file itself), this .js file is gonna make our life a lot easier when dealing with the weird WebAssembly memory model.

We won't change anything in the script file, it's just our interface to the WebAssembly binary (.wasm file), it fetches, compiles and instantiate the wasm file and gives us a nice and clean Module object ready to be used.

Now open the three.html file and inside the first <script> tag, right before the closing </script> tag which is right above the other <script> tag (I hope this has clarified more than confused..), create a function with the following Javascript (you can use it as an event handler, or just shove it into the Mosule's postRun array, which is on around line 1226 in your three.html file, to run it as soon as the Module loads)

const myArray = new Uint8Array([100, 200, 250]);

const buffer = Module._malloc(myArray.length);
Module.HEAPU8.set(myArray, buffer);

Module.ccall('addThree', 'number', ['number', 'number'], [buffer, myArray.length]);

console.log(Module.HEAPU8.subarray(buffer, buffer+myArray.length));

Module._free(buffer);

Here's what's going on..

On line 1, we create our array that we wish to send to the C function for manipulation.

Please note that AFAIK (and according to the emscripten docs), you can only send Uint8Array or or Int8Array. If you have figured out a way to send other typed arrays please share it with us.

Then on line 3, we allocate enough memory (in bytes, it's just the length of the array here because each element is one byte in size) to hold our array elements.

We then actually copy the elements from the array into the buffer we have just created, which means that we are copying the data into the WebAssembly Module's memory space. While the module's memory is represented as a single ArrayBuffer, Module.HEAPU8 is the Uint8 view of that buffer, so it's just a normal Javascript typed array built around that buffer, so in turn, it has the set function.

After that we use the utility function ccall to call the C function, passing in the buffer to act as a pointer to the first element in the array.

ccall docs and other options of calling the C function can be found here.

Line 8 uses the subarray function to peek at the array items while they are sitting happily in their ArrayBuffer, you can use subarray or slice to deal with the modified elements. You can find more details here, but the bottom line is if you just wanna look at the elements or loop over them or the likes and then throw them, use subarray, it's way faster then slice.

Finally we must free up the allocated memory space (a la C malloc/free functions).


The catch

Copying the data (with set) takes time, if you have a huge array this can easily be your app's performance bottleneck.

Imagine you have a canvas that you want to manipulate which is 4000 in width and 3000 in height, this canvas has 4000*3000 pixels, which is 12 million pixels. Now you want to get the ImageData array to be processed by the fast C function, this array gives every pixel 4 entries, which is 4 bytes, now we have 48 million entries/bytes that we have to copy into the memory space of WebAssembly. On a modern machine this takes something close to 2 seconds!

So three's a tradeoff happening here, just be sure that copying the data isn't going to be your bottleneck (like, don't use it for adding 3 to the entries). If so, you better off doing it with Javascript, it would be a lot faster (You can also use workers to get some concurrency).


Hope that helps clear things up. please share your suggestions and questions below.

Thursday, April 13, 2017

Javascript typed arrays - slice vs subarray



What

Both of these TypedArrays' methods appear to do the same thing, except for a cool difference. Let's start with examples..

const a = new Uint8Array([1, 2, 3, 4]);

const b = a.slice(1, 3); // b becomes Uint8Array [ 2, 3 ]
const c = a.subarray(1, 3); // c becomes Uint8Array [ 2, 3 ]

Now let's see what happens when we change the values of these new arrays

b[0] = 5; // b is now Uint8Array [ 5, 3 ]
console.log(a); // Uint8Array [ 1, 2, 3, 4 ]

c[0] = 5; // c is now Uint8Array [ 5, 3 ]
console.log(a); // Uint8Array [ 1, 5, 3, 4 ]

See what happened at line 5? when we changed c, a has changed too, where on the other hand, b doesn't have the same effect, that's the difference.


Why

As you know, subarray exists only for typed arrays, that's the key to understand what's going on.

TypedArrays in javascript are represented in the memory as a single slab of bytes with the size reflecting the number of array items (if every item is one byte and the array has 3 items, then the memory taken is 3 bytes). Let's compare what slice does with what subarray does..

  • slice: Allocate a new space in memory and copy the items from the original array between the start and end indices provided in the arguments into these new memory locations, return the new array.
  • subarray: make a new empty typed array object, which points to a part of the original array between the start and end indices provided in the arguments.

So basically subarray lets a and c see and modify the same memory locations, it provides a smaller "view" (window) over the original array.

That makes subarray very fast compared to slice, because no copying is involved.


When

you can take advantage of this when you have a huge array that you want to convert a range of it into another type. One such situation that comes to mind is when the canvas demands a Uint8ClampedArray to draw its pixels.

const d = new Uint8ClampedArray(c);

the constructor sees c as a Uint8Array, because it really is an independent array which happens to look at the same memory location as a.

This gives you a new array d with the contents of a part of a without having to create an intermediate copy of the range that we want from a.


I hope I have managed to clear up the difference. feel free to ask questions, point out flaws and speak your mind in the comments.

Wednesday, March 15, 2017

Javascript - create fast lookup for string characters with this one-liner



This is another language shortcut, you may use it if you find yourself wanting to check if a string contains some character, and you want to do it fast, because it's inside a loop or something.

const stringy = "strings";

const stringLookup = new Set([...stringy]);

// stringLookup.has('s') === true

This is going to create a set, a hash-table-ish structure with all unique characters in the string.

The spread operator is creating an array from the string, which is essentially equivalent to stringy.split('').

So, stringLookup now has these entries { 's', 't', 'r', 'i', 'n', 'g' }.

View Set as a bag of unique elements, so it's most useful for quick character lookups.


A note about String.prototype.includes

This method uses the same algorithm used for String.prototype.indexOf, which in most implementations has an inside loop, which is not perfect for performance demanding apps.


I'm sure there are a lot of other ways, please share your favorite way of doing it in a comment.

Monday, January 9, 2017

How to use Swift's 'Data' structure to carry different types of data



Introduction


Swift provides the Data structure as an easy way to deal with byte buffers (sometimes called byte arrays). this means it holds raw bytes. This allows for very fast transfer of data (like over bluetooth).

It may be a little tricky to use it with some data types. This post provides ways to use Data to hold some of the most useful data types.

Just keep in mind that there has to be some kind of an "agreement" between your code and the consuming party of this data (it should know what data type and size are being sent).

If you are using a Swift playground, just import CoreData before you begin.

Code


UInt8 (and maybe booleans)

This is the primitive byte type as mentioned in the Swift docs; it is a raw byte after all 😅. It is the most straightforward to use as well.

Data can be used to hold an array of UInt8s directly.

let data = Data([1, 5])

/* or maybe create a flag,
 * change it in different places of the app
 * and send it like so..
 */
var flag: UInt8 = 0
let data = Data([flag])

This can also be used as a boolean flag by using 0 and 1 as values for a single element array (like you've seen in the above example).

String

Strings are also pretty easy to deal with.

let myString = "Cats are awesome"
let data = string.data(using: .utf8)

Just note that depending on your encoding of choice, the size is defferent. For this example with utf8, every character is 1 byte.

Float, Double and other number types

Other number types can take advantage of the flexibility of the UnsafeRawPointer to point directly to the memory location of the variable holding the data you want to send. This pointer is then used to initialize the Data object.

var myDouble = -9.52

let data = withUnsafePointer(to: &myDouble) {
    Data(bytes: $0, count: MemoryLayout.size(ofValue: myDouble))
}

This creates a Data object with the first parameter being a pointer to the myDouble variable.

The $0 is Swift's shorthand name of the UnsafePointer of myDouble. Check this answer if you need more info.

The second argument is the length which the Data initializer needs to walk through the memory to represent your variable, for this we have used the MemoryLayout.size(ofValue:) function to get the size of the myDouble variable automatically (which we know is 8 bytes, or 64 bits).

So this basically says: Starting at the position of myDouble in memory, walk 8 bytes, copy these bytes into a Data object.

Multiple data types with the same Data object


Most of the time, you would be okay with sending one type of data, but you might want to take advantage of the fact that you can send like double the size of the data you are sending at the moment to include other data.

Lets imagine that we want to send the price of a cat, along with a flag indicating if it is a kitten or a grown up cat.

// Like before, define a variable for the price
// and create a Data object with it
var price = 100.99

var data = withUnsafePointer(to: &price) {
    Data(bytes: $0, count: MemoryLayout.size(ofValue: price))
}
// now, define the kitten flag
var kitten: UInt8 = 1

// Make a Data object with it
let kittenFlagData = Data([kitten])

// append the two objects
data.append(kittenFlagData)

data now has 9 bytes, 8 bytes for the price (which, from the prespective of the consuming party, starts at offset 0).

It also has 1 byte for the flag (which, from the prespective of the consuming party, starts at offset 8).


That's it. Feel free to provide any kind of feedback.