Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
271 views
in Technique[技术] by (71.8m points)

javascript - Why is webAssembly function almost 300 time slower than same JS function

Find length of line 300* slower

First of I have read the answer to Why is my WebAssembly function slower than the JavaScript equivalent?

But it has shed little light on the problem, and I have invested a lot of time that may well be that yellow stuff against the wall.

I do not use globals, I do not use any memory. I have two simple functions that find the length of a line segment and compare them to the same thing in plain old Javascript. I have 4 params 3 more locals and returns a float or double.

On Chrome the Javascript is 40 times faster than the webAssembly and on firefox the wasm is almost 300 times slower than the Javascript.

jsPref test case.

I have added a test case to jsPref WebAssembly V Javascript math

What am I doing wrong?

Either

  1. I have missed an obvious bug, bad practice, or I am suffering coder stupidity.
  2. WebAssembly is not for 32bit OS (win 10 laptop i7CPU)
  3. WebAssembly is far from a ready technology.

Please please be option 1.

I have read the webAssembly use case

Re-use existing code by targeting WebAssembly, embedded in a larger JavaScript / HTML application. This could be anything from simple helper libraries, to compute-oriented task offload.

I was hoping I could replace some geometry libs with webAssembly to get some extra performance. I was hoping that it would be awesome, like 10 or more times faster. BUT 300 times slower WTF.


UPDATE

This is not a JS optimisation issues.

To ensure that optimisation has as little as possible effect I have tested using the following methods to reduce or eliminate any optimisation bias..

  • counter c += length(... to ensure all code is executed.
  • bigCount += c to ensure whole function is executed. Not needed
  • 4 lines for each function to reduce a inlining skew. Not Needed
  • all values are randomly generated doubles
  • each function call returns a different result.
  • add slower length calculation in JS using Math.hypot to prove code is being run.
  • added empty call that return first param JS to see overhead

// setup and associated functions
    const setOf = (count, callback) => {var a = [],i = 0; while (i < count) { a.push(callback(i ++)) } return a };
    const rand  = (min = 1, max = min + (min = 0)) => Math.random() * (max - min) + min;
    const a = setOf(100009,i=>rand(-100000,100000));
    var bigCount = 0;




    function len(x,y,x1,y1){
        var nx = x1 - x;
        var ny = y1 - y;
        return Math.sqrt(nx * nx + ny * ny);
    }
    function lenSlow(x,y,x1,y1){
        var nx = x1 - x;
        var ny = y1 - y;
        return Math.hypot(nx,ny);
    }
    function lenEmpty(x,y,x1,y1){
        return x;
    }


// Test functions in same scope as above. None is in global scope
// Each function is copied 4 time and tests are performed randomly.
// c += length(...  to ensure all code is executed. 
// bigCount += c to ensure whole function is executed.
// 4 lines for each function to reduce a inlining skew
// all values are randomly generated doubles 
// each function call returns a different result.

tests : [{
        func : function (){
            var i,c=0,a1,a2,a3,a4;
            for (i = 0; i < 10000; i += 1) {
                a1 = a[i];
                a2 = a[i+1];
                a3 = a[i+2];
                a4 = a[i+3];
                c += length(a1,a2,a3,a4);
                c += length(a2,a3,a4,a1);
                c += length(a3,a4,a1,a2);
                c += length(a4,a1,a2,a3);
            }
            bigCount = (bigCount + c) % 1000;
        },
        name : "length64",
    },{
        func : function (){
            var i,c=0,a1,a2,a3,a4;
            for (i = 0; i < 10000; i += 1) {
                a1 = a[i];
                a2 = a[i+1];
                a3 = a[i+2];
                a4 = a[i+3];
                c += lengthF(a1,a2,a3,a4);
                c += lengthF(a2,a3,a4,a1);
                c += lengthF(a3,a4,a1,a2);
                c += lengthF(a4,a1,a2,a3);
            }
            bigCount = (bigCount + c) % 1000;
        },
        name : "length32",
    },{
        func : function (){
            var i,c=0,a1,a2,a3,a4;
            for (i = 0; i < 10000; i += 1) {
                a1 = a[i];
                a2 = a[i+1];
                a3 = a[i+2];
                a4 = a[i+3];                    
                c += len(a1,a2,a3,a4);
                c += len(a2,a3,a4,a1);
                c += len(a3,a4,a1,a2);
                c += len(a4,a1,a2,a3);
            }
            bigCount = (bigCount + c) % 1000;
        },
        name : "length JS",
    },{
        func : function (){
            var i,c=0,a1,a2,a3,a4;
            for (i = 0; i < 10000; i += 1) {
                a1 = a[i];
                a2 = a[i+1];
                a3 = a[i+2];
                a4 = a[i+3];                    
                c += lenSlow(a1,a2,a3,a4);
                c += lenSlow(a2,a3,a4,a1);
                c += lenSlow(a3,a4,a1,a2);
                c += lenSlow(a4,a1,a2,a3);
            }
            bigCount = (bigCount + c) % 1000;
        },
        name : "Length JS Slow",
    },{
        func : function (){
            var i,c=0,a1,a2,a3,a4;
            for (i = 0; i < 10000; i += 1) {
                a1 = a[i];
                a2 = a[i+1];
                a3 = a[i+2];
                a4 = a[i+3];                    
                c += lenEmpty(a1,a2,a3,a4);
                c += lenEmpty(a2,a3,a4,a1);
                c += lenEmpty(a3,a4,a1,a2);
                c += lenEmpty(a4,a1,a2,a3);
            }
            bigCount = (bigCount + c) % 1000;
        },
        name : "Empty",
    }
],
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Andreas describes a number of good reasons why the JavaScript implementation was initially observed to be x300 faster. However, there are a number of other issues with your code.

  1. This is a classic 'micro benchmark', i.e. the code that you are testing is so small, that the other overheads within your test loop are a significant factor. For example, there is an overhead in calling WebAssembly from JavaScript, which will factor in your results. What are you trying to measure? raw processing speed? or the overhead of the language boundary?
  2. Your results vary wildly, from x300 to x2, due to small changes in your test code. Again, this is a micro benchmark issue. Others have seen the same when using this approach to measure performance, for example this post claims wasm is x84 faster, which is clearly wrong!
  3. The current WebAssembly VM is very new, and an MVP. It will get faster. Your JavaScript VM has had 20 years to reach its current speed. The performance of the JS <=> wasm boundary is being worked on and optimised right now.

For a more definitive answer, see the joint paper from the WebAssembly team, which outlines an expected runtime performance gain of around 30%

Finally, to answer your point:

Whats the point of WebAssembly if it does not optimise

I think you have misconceptions around what WebAssembly will do for you. Based on the paper above, the runtime performance optimisations are quite modest. However, there are still a number of performance advantages:

  1. Its compact binary format mean and low level nature means the browser can load, parse and compile the code much faster than JavaScript. It is anticipated that WebAssembly can be compiled faster than your browser can download it.
  2. WebAssembly has a predictable runtime performance. With JavaScript the performance generally increases with each iteration as it is further optimised. It can also decrease due to se-optimisation.

There are also a number of non-performance related advantages too.

For a more realistic performance measurement, take a look at:

Both are practical, production codebases.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...