I've created a small app that compares the speeds of WebAssembly and Javascript. To my surprise, JavaScript is way faster at calculating factorials of a large number. Or at least it seems like it is. I am pretty sure this is not right and is caused by the await syntax I'm using. (The functions are the same.) Also, what are some really time heavy tasks I can use to compare those two? This doesn't really seem that time consuming, since it takes less than a 0.1 millisecond.
AssemblyScript (this gets compiled into wasm)
// The entry file of your WebAssembly module.
export function fib(num: i32): i32 {
var a: i32 = 1,
b: i32 = 0,
temp: i32;
while (num > 0) {
temp = a;
a = a + b;
b = temp;
num--;
}
return b;
}
App.js
import waApi from "./api";
...
<button
onClick={async () => {
const t0 = performance.now();
(await waApi).fib(200);
const t1 = performance.now();
this.updateGraph(t1 - t0, "wa");
const t2 = performance.now();
this.fib(200);
const t3 = performance.now();
this.updateGraph(t3 - t2, "js");
}}>
Calculate with both
</button>
api.js
import { instantiateStreaming } from "assemblyscript/lib/loader";
export default instantiateStreaming(fetch("./assembly.wasm"));
The problem with micro-benchmarks (i.e. benchmarks that analyse the performance of small, very fast function) is that you almost always end up measuring the wrong thing. Your measurements are going to be heavily skewed by:
The overhead involved in invoking WebAssembly functions from JavaScript
The ability of the AssemblyScript compiler (which is very new) to optimise your function
The accuracy of your timer
The time for your JavaScript engine to reach peak optimisation
Just to name a few!
A more realistic benchmark would perform calculations that execute a far greater range of WebAssembly operations, be more 'realistic' in nature (i.e. measure the types of load you really would offload to WebAssembly), and take longer to execute.
Here's a much better benchmark based on a GameBoy emulator:
https://medium.com/#torch2424/webassembly-is-fast-a-real-world-benchmark-of-webassembly-vs-es6-d85a23f8e193
It should be
import waApi from "./api";
class Test extends React.Component {
async componentDidMount() {
this.wasmModule = await waApi;
}
render() {
return (
<button
onClick={() => {
const module = this.wasmModule;
if (!module) {
console.warn("module not yet loaded. Try later");
return;
}
const t0 = performance.now();
module.fib(200);
const t1 = performance.now();
this.updateGraph(t1 - t0, "wa");
const t2 = performance.now();
this.fib(200);
const t3 = performance.now();
this.updateGraph(t3 - t2, "js");
}}>
);
}
}
Because in your example for wasm part you also measured loading and instantiation of module.
Related
I am trying to create an easing function on scroll but my main function is growing rather large and I want to be able to split it up. I am creating a requestAnimationFrame function that will ease the page scroll. The big issue I am having is that the render function with the animation frame will ease the Y value and then calls the update function to update the elements. But if I split this up and import them individually I am having trouble figuring out how to pass the updated values between functions. Many other functions also rely on these updated values.
I could take an object oriented approach and create a class or a constructor function and bind this to the function but it seems like bad practice to me:
import render from './render'
import update from './update'
const controller = () => {
this.items = [];
this.event = {
delta: 0,
y: 0
}
this.render = render.bind(this)
this.update = update.bind(this)
//ect
}
I could also break it up into classes that extend each other but I would like to take a more functional approach to the situation but I am having trouble figuring out how to achieve this.
Here is a very condensed version of what I am trying to do. Codesandbox.
const controller = (container) => {
const items = [];
let aF = null;
const event = {
delta: 0,
y: 0
};
const render = () => {
const diff = event.delta - event.y;
if (Math.abs(diff) > 0.1) {
event.y = lerp(event.y, event.delta, 0.06);
aF = requestAnimationFrame(render);
} else {
stop();
}
update();
};
const start = () => {
if (!aF) aF = requestAnimationFrame(render);
};
const stop = () => {
event.y = event.delta;
cancelAnimationFrame(aF);
aF = null;
};
const update = () => {
const y = event.y;
container.style.transform = `translateY(-${y}px)`;
items.forEach((item) => {
item.style.transform = `translate(${y}px, ${y}px)`;
});
};
const addItem = (item) => items.push(item);
const removeItem = (item) => {
const idx = items.indexOf(item);
if (idx > -1) items.splice(idx, 1);
};
const onScroll = () => {
event.delta = window.scrollY;
start();
};
// and a bunch more stuff
window.addEventListener("scroll", onScroll);
return {
addItem,
removeItem
};
};
export default controller;
I would like to be able to split this up and create a more functional approach with pure functions where I can import the update and render functions. The problem is that these functions are reliant on the updated global variables. Everywhere I look it says that global variables are a sin but I don't see a way to avoid them here. I have tried to look at the source code for some large frameworks to get some insight on how they structure their projects but it is too much for me to take in at the moment.
Any Help would be appreciated. Thanks.
What you wrote in the first example is completely valid, you basically did what classes are doing under the hood (classes are just syntactic sugar almost), but there are some problems with your code:
You use an arrow function, so this becomes window actually in that context.
You should use function expression instead, and initialize your instance using new, only in this case this will work how you want.
However, there are many solutions for Dependency Injection / Plugin systems which is what you're basically looking for, I'd advise you to look around this area.
In case you want a more functional approach, you need to avoid the this keyword and you need to use pure functions. I'd advice you not to share values in a context, but simply pass the necessary dependencies to your functions.
import render from './render'
const controller = () => {
const items = []
window.addEventListener('scroll', (event) => {
start({ y: event.y })
})
const start = ({ y }) => {
// Pass what render needs
requestAnimationFrame(() => render({ container, items, y }))
}
}
Using the above:
You don't need the update function in this file, render will import it on its own.
Your functions are pure, easily testable on their own.
You don't need to create an instance by using new (it's actually more expensive).
No need for shared state across functions.
No DI/Plugin solution need to implemented/used.
In case you do want to have shared state, you won't do that without classes and/or extra tooling around.
The way I'd do this is by creating a seperate .js file, then send the information you need into that js file right at the start of your main files code. Then just use the seperate file to store all your functions, then just call them with utils.myFunction(). At least that's how I do it in node.
I am completely lost in trying to translate the following Haskell code into Javascript:
instance MonadFix IO where
mfix f = do
var <- newEmptyMVar -- 1
ans <- unsafeInterleaveIO $ takeMVar var -- 2
result <- f ans -- 3
putMVar var result -- 4
return result -- 5
Let’s walk through this line by line in terms of our little time
travel analogy:
Create an empty mutable variable.
Predict the future value that will be contained in that mutable variable.
Call the function f with the predicted future value.
Store the result of f in the variable, thus fulfilling the prophecy as required by line 2.
Return that result.
What I have is a special Lazy type that handles (or rather defers) synchronous IO. However, I'd like to abstract from direct recursion with value recursion:
const record = (type, o) =>
(o[Symbol.toStringTag] = type.name || type, o);
const Lazy = lazy => record(Lazy, {get lazy() {
delete this.lazy
return this.lazy = lazy();
}});
// Monad
const lazyChain = mx => fm =>
Lazy(() => fm(mx.lazy).lazy);
const lazyChain_ = fm => mx =>
Lazy(() => fm(mx.lazy).lazy);
const lazyOf = x => Lazy(() => x);
// mfix = chain_ => fm => chain_(fm) (mfix(chain_) (fm)) ???
// MAIN
const trace = x => (console.log(x), x);
const app_ = x => f => trace(f(x));
const readLine = s => Lazy(() => window.prompt(s));
const fac = x => x === 0 ? 1 : x * fac(x - 1),
tri = x => x === 0 ? 0 : x + tri(x - 1);
const foo = lazyChain(readLine("enter true/false")) (s => {
return lazyOf(s === "true"
? fac : tri);
});
const bar = x => lazyChain(foo) (y => lazyOf(app_(x) (y)));
const main = bar(5);
console.log("effect has not yet been unleashed..");
main.lazy;
How do I implement the Lazy instance of MonadFix in Javascript?
You have a representation of thunks with your Lazy construct, which happens to form a monad (where monadic application is just strict function application, as you’ve written), but you don’t have a representation of IO, so you’re essentially just using unsafePerformIO everywhere.
In your model, each I/O action can only be executed once, so I expect this will not work quite the way you expect unless you add a separate IO wrapper with something like a runIO function (or property, if you like) that does not share Lazy’s behaviour of overwriting itself with the memoised result, or perhaps if you add some way to explicitly duplicate a deferred action. Of course, mfix f only runs the effects of f once anyway—that is, it’s for using effects to produce a lazy/self-referential data structure—so this may be fine for your purposes.
Those caveats aside, it’s perfectly possible to express something resembling an instance of MonadFix for your thunk structure, but it’s just a lazy version of fix:
// cf. Haskell ‘fix f = let ans = f ans in ans’
function lazyFix(f) {
var ans = Lazy(() => f(ans));
return ans;
}
If you have side effects interleaved in these thunks, they’ll happen as you force them.
I think the MVar business in the original Haskell code is mainly just a convenient way to catch a subset of infinite loops, by ensuring that if the action tries to force the thunk before a value is written into it, then the runtime will be able to detect that the thread is “blocked indefinitely in an MVar operation” and raise an error.
And as a side note, you should be able to simplify your lazyChain definition to just fm(mx.lazy), since Lazy(() => fm(mx.lazy).lazy) forces the result and then immediately wraps it in a thunk again, which is both extra work and possibly too eager about your interleaved effects. Your version is effectively let fx = fm mx in mx `seq` fx `seq` fx, which can be simplified (by a `seq` a = a) to mx `seq` fm mx, which is then equivalent to fm $! mx, i.e., strict function application.
I came across this "higher order function". But I can't wrap my head around it.
Here's the snippet:
addUrlProps([options])(WrappedComponent)
Is this addUrlProps a function? What does it accept? It has two () beside it...
In React it's called a higher order function (HOC), but really it's just borrowing an old functional programming concept. What it really is, is an application of currying.
Simple Example
Let's say you want to create an add2 and add3 function. You'd do something like this:
// add2 = a => Number
const add2 = a => a + 2;
const sum2 = add2(5) // => 7
// add3 = a => Number
const add3 = a => a + 3;
const sum3 = add3(5) // => 8
The problem is this isn't really scalable. What if you needed to create add4, add5... add100? This is where currying comes into play;
// add = a => b => Number
const add = a => b => a + b;
// add(2)(5)
const add2 = add(2);
const sum2 = add2(5); // => 7
// add(3)(5)
const add3 = add(3);
const sum3 = add3(5); // => 8
...
// add(100)(5)
const add100 = add(100);
const sum100 = add100(5); // => 105
Theoretically you could create an infinite number of add functions to your taste.
Case Example
In your example addUrlProps([options])(WrappedComponent) is doing the exact same thing.
// addUrlProps([options])(WrappedComponent)
const foo = addUrlProps([options]);
const HOC = foo(WrappedComponent); // => A component
It's taking in [options] to create a function. Then that function takes a second argument called WrappedComponent.
addUrlProps is a function that returns a function. In react terms it is a HOC. HOC documentation The second () is invoking the function that is returned from the first invocation.
It is a shorthand for the following.
const func = addUrlProps();
func(WrappedComponent);
So instead of saving the result of addUrlProps() into a variable, it is invoked immediatley like so
export addUrlProps()(WrappedComponent);
Its returned value is the same component, wrapped in another component that is adding some extra functionality, or props.
It is worth noting that not all HOCs follow this curried pattern. A very popular library that uses this particular pattern is react-redux connect HOC. Don't be afraid to view the source code to figure out what is happening!
Are there any performance(or otherwise) implications in doing this;
// ...
const greeting = `Hello, ${name}!`;
return greeting;
in comparison to doing just this;
// ...
return `Hello, ${name}!`;
Yes, assigning a value to a variable name and then returning that variable takes slightly more effort than simply returning the value. For a mini performance test, see:
(warning: the following will block your browser for a bit, depending on your specs)
// references to "name" removed to provide a more minimal test:
const p0 = performance.now();
for (let i = 0; i < 1e9; i++) {
(() => {
const greeting = `Hello!`;
return greeting;
})();
}
const p1 = performance.now();
for (let i = 0; i < 1e9; i++) {
(() => {
return `Hello!`;
})();
}
const p2 = performance.now();
console.log(p1 - p0);
console.log(p2 - p1);
The difference is quite small, but it's consistently there, at least in V8 - the overhead of the function call mostly overshadows it.
That said, this really sounds like premature optimization - it's probably better to aim for code readability and maintainability, and then fix performance issues if and when they pop up. If declaring a name for the returned value makes the code easier to read, it's probably a good idea to do so, even if it makes the script take a (completely insignificant) longer time to run.
I read in various places that it's advisable to be careful with the arguments object and that this is ok...
var i = arguments.length, args = new Array(i);
while (i--) args[i] = arguments[i];
But, is this ok or not?...
function makeArray (l) {
var i = l.length, array = new Array(i);
while (i--) array[i] = l[i];
return array;
};
//...
//EDIT: put the function on an object to better represent the actual case
var o = {};
o.f = function (callback) {
var args = makeArray (arguments);
callback.apply(args[0] = this, args);
};
What is meant by "leaking arguments" and how does it affect optimisation?
I am focused on V8, but I assume it applies to other compilers as well?
to prove it works...
function makeArray (l) {
var i = l.length, array = new Array(i);
while (i--) array[i] = l[i];
return array;
};
//...
//EDIT: put the function on an object to better represent the actual case
var o = {};
o.f = function (callback) {
var args = makeArray (arguments);
callback.apply(args[0] = this, args);
};
o.m = "Hello, ";
function test(f, n) {
alert(this.m + " " + n)
}
o.f(test, "it works...")
The problem with arguments is same as with local eval and with: they cause aliasing. Aliasing defeats all sorts of optimizations so even if you enabled optimization of these kind of functions you would probably end up just wasting time which is a problem with JITs because the time spent in the compiler is time not spent running code (although some steps in the optimization pipeline can be run in parallel).
Aliasing due to arguments leaking:
function bar(array) {
array[0] = 2;
}
function foo(a) {
a = 1;
bar(arguments);
// logs 2 even though a is local variable assigned to 1
console.log(a);
}
foo(1);
Note that strict mode eliminates this:
function bar(array) {
array[0] = 2;
}
function foo(a) {
"use strict";
a = 1;
bar(arguments);
// logs 1 as it should
console.log(a);
}
foo(1);
Strict mode however isn't optimized either and I don't know any reasonable explanation except that benchmarks don't use strict mode and strict mode is rarely used. That might change since many es6 features require strict mode, otoh arguments is not needed in es6 so...
This is a 2-fold problem:
You lose any and all possible optimizations and branch predictions
The arguments object is unpredictible.
You leak memory. Really bad!
Consider the following code (run it at your own risk!):
function a(){return arguments;}
x=a(document.getElementsByTagName('*'));
window._interval=setInterval(function(){
for(var i=0;i<1e6;i++)
{
x=a(x);
}
},5000);
*{font-family:sans-serif;}
<p>Warning! This may overheat your cpu and crash your browser really badly!</p>
<p>I'm not responsible for any software and hardware damages!</p>
<p><b>Run at your own risk!!!</b></p>
<p>If you ran this code, press F5 to stop or close the browser.</p>
<p>If you want, you can try to <button onclick="window.clearInterval(window._interval);window.x='';">stop it</button>. (the RAM may remain unchanged)</p>
And now watch your RAM go up, when you run that (it goes up at a rate of around 300-500MB every 5 seconds).
A naive implementation that simply passes the arguments around may cause these problems.
Not to mention that your code will (generally) be a tad slower.
Note that this:
function a(){return arguments;}
function b(arg){return arg;}
x=a(document.getElementsByTagName('*'));
window._interval=setInterval(function(){
for(var i=0;i<1e6;i++)
{
x=b(x);
}
},5000);
*{font-family:sans-serif;}
<p>This may be safe, but be careful!</p>
<p>I'm not responsible for any software and hardware damages!</p>
<p><b>Run at your own risk!!!</b></p>
<p>If you ran this code, press F5 to stop or close the browser.</p>
<p>If you want, you can try to <button onclick="window.clearInterval(window._interval);window.x='';">stop it</button>.</p>
Won't have the same effect as the code before.
This is because b() returns the same variable, instead of a new reference to a new arguments object.
This is a very important difference.