6

I have implemented a very naive quicksort in pure Javascript and in C, the later being exported as a WebAssembly module.

I am sorting the 2 same arrays of 106 integers in the range [0;1000]. The pure javascript implementation takes on average 780ms, while the WebAssembly based takes 935ms (1020ms when no optimization flags set).

Why is the pure javascript implementation the fastest?

Below the 2 implementations in question:

JS:

function swap(array, swapy1, swapy2) {
  let tmp = array[swapy1];
  array[swapy1] = array[swapy2];
  array[swapy2] = tmp;
}


function partition(array, lo, hi) {
  const pivot = array[hi];
  let i = lo - 1;
  for (let j = lo; j < hi; j++) {
    if (array[j] < pivot) {
      if (i !== j) {
        i++;
        swap(array, i, j)
      }
    }
  }
  i++;
  swap(array, i, hi);
  return i;
}

export default function sort(array, lo, hi) {
  if (lo < hi) {
    const p = partition(array, lo, hi);
    sort(array, lo, p - 1);
    sort(array, p + 1, hi);
  }
}

C:

void swap(int *array, int swapy1, int swapy2) {
    int tmp = array[swapy1];
    array[swapy1] = array[swapy2];
    array[swapy2] = tmp;
  }


  int partition(int *array, int lo, int hi) {
    int pivot = array[hi];
    int i = lo - 1;
    for (int j = lo; j < hi; j++) {
      if (array[j] < pivot) {
        if (i != j) {
          i++;
          swap(array, i, j);
        }
      }
    }
    i++;
    swap(array, i, hi);
    return i;
  }

  void sort(int *array, int lo, int hi) {
    if (lo < hi) {
      int p = partition(array, lo, hi);
      sort(array, lo, p - 1);
      sort(array, p + 1, hi);
    }
  }

  void quicksort(int *array, int lo, int hi, char *exp) {
   struct timeval t1, t2;
   double elapsedTime;

    gettimeofday(&t1, NULL);
    sort(array, lo, hi);
    gettimeofday(&t2, NULL);

    // compute and print the elapsed time in millisec
    elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0;      // sec to ms
    elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0;   // us to ms

    printf(" - 10%s entries sorted in %.0f ms\n", exp, elapsedTime);
  }

Caller code (through emscripten Module object):

WasmModule().then(wasm => {
    console.log("Monothreaded Lomuto Quicksort, WebAssembly");
    function callWasm(array, exponant) {
      let heapBuf = wasm._malloc(array.length * Uint32Array.BYTES_PER_ELEMENT);
      wasm.HEAP32.set(array, heapBuf / 4);
      wasm.ccall('quicksort', null, ['number', 'number', 'number', 'string'], [heapBuf, 0, array.length - 1, exponant]);
      wasm._free(heapBuf);
    }
    millionIntCopy = millionInt.slice();
    tenMillionIntCopy = tenMillionIntCopy.slice();
    callWasm(millionIntCopy, "\u2076");
    // callWasm(tenMillionIntCopy, "\u2077"); // stack overflow
    // callWasm(hundredMillionInt, "\u2078"); stackoverflow
  })

Full project may be found here

Eturcim
  • 798
  • 8
  • 26
  • How did you initialize the array in Wasm side? Can you share the full code including your actual caller program. – Bumsik Kim Nov 28 '18 at 04:04
  • Possible duplicate of [Why is webAssembly function almost 300 time slower than same JS function](https://stackoverflow.com/questions/48173979/why-is-webassembly-function-almost-300-time-slower-than-same-js-function) – ColinE Nov 28 '18 at 08:42
  • Thanks @ColinE , I'll have a look to that answer, missed it actually. – Eturcim Nov 28 '18 at 16:45
  • After reading the suggested duplicate and the article mentioned in it, it's not clearer to me why pure js implementation is faster than wasm. I am just understanding that the js runtime is doing some optimization that could be one reason. Does it mean we have to be aware of the runtime engine implementation to know if it worth porting a C/C++ library vs rewriting it in pure JS ? – Eturcim Nov 28 '18 at 23:57
  • 1
    also note that gettimeofday in emscripten is likely implemented with a call into javascript code. I would recommend just calling that twice in a row without doing a quicksort and see how long that takes, and take that number into consideration when comparing js to emscripten compiled code. – prushik Jun 26 '19 at 19:18

0 Answers0