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

Supersonic JS

Supersonic JS

Presented at O'Reilly Velocity 2015 in Santa Clara: http://velocityconf.com/devops-web-performance-2015/public/schedule/detail/42098

Analyzing the performance of large-scale JavaScript applications requires a distinct set of tools. It is no longer enough to run various benchmarks by creating loops and measuring the elapsed time. The amazing progress of modern JavaScript engines means that developers should not stress about outdated considerations such as cache array length, avoiding ‘switch’ statements, and using ‘while’ instead of ‘for.’ Understanding the inner workings of the engine itself will reveal the typical code patterns favored for maximum execution speed (short function, fixed object shape, profile-guided, garbage minimization). We will also cover the use of strategies like sampling and tracing, in order to spot performance issues while simultaneously avoiding being trapped in a local maxima.

Ariya Hidayat

May 29, 2015
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. Beyond checklists Global maximum

    View Slide

  5. Short Function

    View Slide

  6. Function = Expensive
    sortDepartment
    totalDepartementExpense
    totalEmployeesSalaries
    getEmployeeData
    OLD Wisdom

    View Slide

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

    View Slide

  8. 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

  9. 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

  10. 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

  11. Fixed Object Shape

    View Slide

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

    View Slide

  13. 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

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

    View Slide

  15. “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

  16. 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

  17. Garbage Handling

    View Slide

  18. 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

  19. 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

  20. Memory Profiling
    https://developer.chrome.com/devtools/docs/javascript-memory-profiling

    View Slide

  21. Performance Analysis

    View Slide

  22. 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

  23. Profile Guided

    View Slide

  24. View Slide

  25. 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

  26. 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

  27. 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

  28. Algorithmic Complexity

    View Slide

  29. Fast = Enough?
    Alice
    Bob
    Chuck
    Dan
    ...
    Bob
    Alice
    Dan
    Chuck
    ...
    Sort
    How’s the
    speed?
    2 ms to sort 10
    contacts

    View Slide

  30. Array.prototype.swap = function (i, j) {
    var k = this[i]; this[i] = this[j]; this[j] = k;
    }
    function sort(list) {
    var items = list.slice(0), swapped = false, p, q;
    for (p = 1; p < items.length; ++p) {
    for (q = 0; q < items.length - p; ++q) {
    if (items[q + 1] < items[q]) {
    items.swap(q, q + 1);
    swapped =true;
    }
    }
    if (!swapped) break;
    }
    return items;
    }
    Bubble Sort
    ???

    View Slide

  31. Run-time Complexity
    http://ariya.ofilabs.com/2012/01/scalable-web-apps-the-complexity-issue.html
    Array.prototype.swap = function (i, j) {
    var k = this[i]; this[i] = this[j]; this[j] = k;
    }
    Array.prototype.swap = function (i, j) {
    Log({ name: 'Array.prototype.swap', lineNumber: 1, range: [23, 94] });
    var k = this[i]; this[i] = this[j]; this[j] = k;
    }

    View Slide

  32. View Slide

  33. Final Words

    View Slide

  34. tools and knowledge
    not rules and checklists

    View Slide

  35. contextual profiling
    not microbenchmarks

    View Slide

  36. T D D B D D

    View Slide

  37. Thank You!
    shapesecurity.com
    @ariyahidayat
    And don’t forget
    to rate the talk

    View Slide