Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Supersonic JavaScript

Supersonic JavaScript

Presented at Samsung Web Tech Talk: http://www.meetup.com/Samsung-Web-Tech-Talk/events/171219722/

Writing fast JavaScript code is not only about running loops, measuring the elapsed time, and getting obsessed with microbenchmarks. Understanding the inner workings of the JavaScript engine will reveal the typical code patterns favored for maximum execution speed (short function, fixed object shape, profile-guided, garbage minimization).

Ariya Hidayat

April 07, 2014
Tweet

More Decks by Ariya Hidayat

Other Decks in Programming

Transcript

  1. Supersonic JavaScript
    @ariyahidayat

    View Slide

  2. First Things First, Steven Covey
    “The Big Rock”
    http://calendar.perfplanet.com/2013/javascript-performance-big-picture/

    View Slide

  3. The real problem is that programmers have spent
    far too much time worrying about efficiency in the
    wrong places and at the wrong times;
    premature optimization is the root of all evil
    (or at least most of it) in programming.
    Computer Programming as an Art
    Knuth’s Turing Award lecture (1974)

    View Slide

  4. Performance Analysis
    Timing Prepare the stopwatch
    Mark the start and the end
    Sampling Periodically check which function
    is being executed
    Tracing Track all function calls and exits
    http://ariya.ofilabs.com/2012/12/javascript-performance-analysis-sampling-tracing-and-timing.html

    View Slide

  5. Status Quo?

    View Slide

  6. Short Function

    View Slide

  7. Function = Expensive
    sortDepartment
    totalDepartementExpense
    totalEmployeesSalaries
    getEmployeeData
    OLD Wisdom

    View Slide

  8. NEW movement
    Let the JavaScript engine
    figure out the best way to
    execute the functions.

    View Slide

  9. Automatic Inlining
    function square(p) {
    return p * p;
    }
    function f(x) {
    var sum = 0;
    for (var i = 0; i < x; i++)
    sum += square(i);
    return sum;
    }
    function f(x) {
    var sum = 0;
    for (var i = 0; i < x; i++)
    sum += i * i;
    return sum;
    }
    http://ariya.ofilabs.com/2013/04/automatic-inlining-in-javascript-engines.html

    View Slide

  10. Deferred Parsing
    To further reduce the time to first executed instruction,
    Chakra processes and emits bytecode only for functions
    that are about to be executed using a mechanism called
    deferred parsing.
    http://blogs.msdn.com/b/ie/archive/2012/06/13/advances-in-javascript-performance-in-ie10-and-windows-8.aspx

    View Slide

  11. Lazy Parsing
    http://ariya.ofilabs.com/2012/07/lazy-parsing-in-javascript-engines.html
    function add(x, y) { return x + y; }
    function mul(x, y) { return x * y; }
    alert(add(40, 2));
    Declare a function call add with the function body “{ return x + y; }”.
    Declare a function call mul with the function body “{ return x * y; }”.
    Call alert with the result of function add with 40 and 2 as the arguments.
    1
    2
    Call function add. Hmm, it is not parsed yet.
    Call the real parser for “{ return x + y; }”.
    It accepts x and y as the arguments.
    The return value is a binary operation + of x and y.

    View Slide

  12. Fixed Object Shape

    View Slide

  13. WILD idea
    How to avoid any
    deoptimization in the
    JavaScript engine?

    View Slide

  14. Shape Transition
    function Vehicle() {
    this.color = 'white';
    this.speed = 0;
    }
    var car = new Vehicle();
    car.color = 'black';
    car.maker = 'BMW';
    var motorbike = new Vehicle();
    motorbike.wheels = ['front', 'back'];
    color
    speed
    color
    speed
    maker
    color
    speed
    wheels

    View Slide

  15. (Optimized) Property Access
    console.log(car.color);
    Execute the generic
    property access
    Shape
    check
    Get the value from
    property #1
    color
    speed

    View Slide

  16. “Freeze” the Object Shape
    var universe = {
    answer: 42
    };
    // do something else
    universe.panic = false;
    var universe = {
    answer: 42,
    panic: true
    };
    // do something else
    universe.panic = false;
    http://ariya.ofilabs.com/2012/02/javascript-object-structure-speed-matters.html

    View Slide

  17. Avoid Conditional Transition
    var car = {
    color: 'blue'
    };
    if (currentYear > 2015)
    car.backupCamera = new Camera();
    var car = {
    color: 'blue',
    backupCamera: null
    };
    if (currentYear > 2015)
    car.backupCamera = new Camera();

    View Slide

  18. Profile Guided

    View Slide

  19. View Slide

  20. function isDigit(ch) {
    return (ch !== ' ') && '0123456789'.indexOf(ch) >= 0;
    }
    Fast Lane
    http://ariya.ofilabs.com/2013/07/profile-guided-javascript-optimization.html
    function isDigit(ch) {
    return '0123456789'.indexOf(ch) >= 0;
    }
    Shortcut

    View Slide

  21. Object in a Set
    var valid_words = {
    'foobar': true,
    'bar': true,
    'baz': true,
    'quux': true
    };
    function is_valid(word) {
    return valid_words.hasOwnProperty(word);
    }
    is_valid('fox'); // false
    http://ariya.ofilabs.com/2012/08/determining-objects-in-a-set-examples-in-javascript.html
    Dictionary
    Spell checker

    View Slide

  22. Tiered Conditionals
    http://ariya.ofilabs.com/2012/08/determining-objects-in-a-set-examples-in-javascript.html
    function is_valid(word) {
    switch (word.length) {
    case 3:
    return word === 'bar' || word === 'baz';
    case 4:
    return word === 'quux';
    case 6:
    return word === 'foobar';
    }
    return false;
    }
    Filter #1:
    length

    View Slide

  23. Garbage Handling

    View Slide

  24. Minimize Object Construction
    https://www.youtube.com/watch?v=Vo72W1HWeFI
    var tick = new Date();
    for (var i = 0, j = 0; i < 4e4; ++i){
    var delta = new Date();
    delta = delta - tick;
    tick = new Date();
    j += delta;
    }
    var tick = Date.now();
    for (var i = 0, j = 0; i < 4e4; ++i) {
    var delta = Date.now() - tick;
    tick = Date.now();
    j += delta;
    }

    View Slide

  25. GC Tracing on
    56 ms: Scavenge 1.8 (36.0) -> 0.9 (36.0) MB, 2.8 ms
    73 ms: Scavenge 1.8 (36.0) -> 0.9 (37.0) MB, 2.8 ms
    89 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms
    109 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms
    126 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms
    141 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms
    159 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms
    176 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms
    192 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 0.9 ms
    207 ms: Scavenge 1.9 (37.0) -> 0.9 (37.0) MB, 1.0 ms
    54 ms: Scavenge 1.8 (36.0) -> 0.9 (36.0) MB, 2.9 ms
    67 ms: Scavenge 1.8 (36.0) -> 0.9 (37.0) MB, 2.7 ms
    new Date( ) Date.now()

    View Slide

  26. Final Words

    View Slide

  27. Summary
    Measure twice, cut once
    Under the hood: explore and learn
    Be advised of every best practice

    View Slide

  28. Thank You
    shapesecurity.com
    @ariyahidayat

    View Slide