$30 off During Our Annual Pro Sale. View Details »

Faster than C?

Faster than C?

Presentation given at the Prague JS Usergroup.

Felix Geisendörfer

November 29, 2012
Tweet

More Decks by Felix Geisendörfer

Other Decks in Programming

Transcript

  1. felixge
    Faster than C?
    Parsing binary data in JavaScript
    Felix Geisendörfer

    View Slide

  2. @felixge
    felixge
    Background
    2005 - 2008 2008 - now 2009 - now

    View Slide

  3. @felixge
    felixge
    The NodeCopter
    nodecopter.com

    View Slide

  4. felixge
    This Talk

    View Slide

  5. felixge
    JavaScript vs C

    View Slide

  6. felixge
    Good vs Evil

    View Slide

  7. felixge
    Good Parts vs Evil

    View Slide

  8. felixge
    Bad Parts vs Evil

    View Slide

  9. felixge
    Faster than C?

    View Slide

  10. felixge
    No
    Sorry for the “title bait”

    View Slide

  11. felixge
    As fast as C bindings
    For parsing binary protocols / database drivers

    View Slide

  12. felixge
    The Story

    View Slide

  13. felixge
    early 2010

    View Slide

  14. felixge
    No MySQL module
    for node.js
    early 2010

    View Slide

  15. felixge

    View Slide

  16. felixge
    Pure JS / No C/C++

    View Slide

  17. felixge
    Before Buffers
    became usable

    View Slide

  18. felixge
    The Parser was using
    JavaScript Strings

    View Slide

  19. felixge
    Node.js Trivia

    View Slide

  20. felixge
    “ Buffers” used to be
    called “Blobs”

    View Slide

  21. felixge
    For 3 min and 15 sec

    View Slide

  22. felixge
    RIP Blobs

    View Slide

  23. felixge
    Sun Dec 13 08:39:20 2009
    -
    Sun Dec 13 08:42:45 2009

    View Slide

  24. felixge
    Anyway

    View Slide

  25. felixge
    mysql can be done
    without libmysql

    View Slide

  26. felixge

    View Slide

  27. felixge
    No good deed goes
    unpunished

    View Slide

  28. felixge
    Sir Isaac Newton

    View Slide

  29. felixge
    Third Law of Motion

    View Slide

  30. “When a first body exerts a
    force F1 on a second body, the
    second body simultaneously
    exerts a force F2 = −F1 on the
    first body. This means that F1
    and F2 are equal in magnitude
    and opposite in direction.”

    View Slide

  31. felixge
    Third Law of Github

    View Slide

  32. “When a first person pushes
    a library L1 into a remote
    repository, a second person
    simultaneously starts working
    on a second library L2 which
    will be equally awesome, but
    in a different way.”

    View Slide

  33. felixge
    <3 Github!

    View Slide

  34. felixge

    View Slide

  35. @felixge
    felixge
    Benchmark
    • Parse ~180 MB / 100.000 rows of MySQL result data
    • 5 Columns: id, title, text, created, updated
    • -> create 100k objects with 500k keys + 500k values

    View Slide

  36. felixge
    0
    500
    1,000
    1,500
    mysql−0.9.6 mysql−libmysqlclient−1.5.1
    benchmark
    mbit
    benchmark
    mysql−0.9.6
    mysql−libmysqlclient−1.5.1

    View Slide

  37. felixge
    Of course.

    View Slide

  38. felixge
    libmysql = C

    View Slide

  39. felixge
    my library = JavaScript

    View Slide

  40. felixge
    C > JS, right?

    View Slide

  41. felixge
    But V8!

    View Slide

  42. felixge
    And Crankshaft!!

    View Slide

  43. felixge
    Node.js !!!1!

    View Slide

  44. felixge
    Was I
    living a lie?

    View Slide

  45. felixge
    Kind of

    View Slide

  46. felixge
    V8 / Node
    = Tools

    View Slide

  47. felixge
    Performance
    is not a tool

    View Slide

  48. felixge
    Performance is
    hard work &
    data analysis

    View Slide

  49. felixge
    0
    500
    1,000
    1,500
    mysql−0.9.6 mysql−libmysqlclient−1.5.1mysql−2.0.0−alpha3
    benchmark
    mbit
    benchmark
    mysql−0.9.6
    mysql−libmysqlclient−1.5.1
    mysql−2.0.0−alpha3

    View Slide

  50. felixge
    Third Law of Github

    View Slide

  51. felixge

    View Slide

  52. felixge
    0
    1,000
    2,000
    3,000
    4,000
    mysql−0.9.6
    mysql−libmysqlclient−1.5.1
    mysql−2.0.0−alpha3 mariadb−0.1.7
    benchmark
    mbit
    benchmark
    mysql−0.9.6
    mysql−libmysqlclient−1.5.1
    mysql−2.0.0−alpha3
    mariadb−0.1.7

    View Slide

  53. felixge
    Time to give up?

    View Slide

  54. felixge
    NEVER!

    View Slide

  55. felixge
    New Parser

    View Slide

  56. @felixge
    felixge
    0
    2,000
    4,000
    6,000
    mysql2 new−parser
    benchmark
    mbit
    benchmark
    mysql2
    new−parser

    View Slide

  57. felixge
    Third law of Github?

    View Slide

  58. felixge
    Endgame

    View Slide

  59. felixge
    Last bottleneck:
    V8 / Creating JS Objects

    View Slide

  60. felixge
    Also: MySQL Server saturated

    View Slide

  61. felixge
    Anyway

    View Slide

  62. felixge
    How to write fast JS

    View Slide

  63. felixge
    Does not work

    View Slide

  64. @felixge
    felixge
    Profiling
    • Good at telling you which functions are slow
    • Bad at telling you how to fix it

    View Slide

  65. felixge
    Taking performance advice
    from strangers

    View Slide

  66. @felixge
    felixge
    Taking performance advice
    from strangers
    • Good for ideas & inspiration
    • But useless when applied cargo-cult style

    View Slide

  67. @felixge
    felixge
    for (var i = 0; i < array.length; i++) {
    // do some work with array[i]
    }

    View Slide

  68. @felixge
    felixge
    for (var i = 0, length = array.length; i < length; i++) {
    // do some work with array[i]
    }

    View Slide

  69. felixge
    What Does Work?

    View Slide

  70. felixge
    Benchmark Driven
    Development

    View Slide

  71. @felixge
    felixge
    Benchmark Driven Development
    • Similar to test driven development
    • Use it when performance is an explicit design goal
    • Benchmark first > benchmark after !

    View Slide

  72. felixge
    1 function benchmark() {
    2 // intentionally empty
    3 }

    View Slide

  73. felixge
    1 while (true) {
    2 var start = Date.now();
    3 benchmark();
    4 var duration = Date.now() - start;
    5 console.log(duration);
    6 }

    View Slide

  74. @felixge
    felixge
    Benchmark Driven Development
    • Next step: Implement a tiny part of your function
    • Example: Parse headers of MySQL packets
    • Look at impact, tweak code, repeat

    View Slide

  75. @felixge
    felixge
    Example Results
    • try...catch is ok
    • big switch statement = bad
    • function calls = very cheap
    • buffering is ok

    View Slide

  76. @felixge
    felixge
    Favorite Optimization:
    Loop unrolling with eval()’s
    good twin new Function()

    View Slide

  77. @felixge
    felixge
    1 function parseRow(columns, parser) {
    2 var row = {};
    3 for (var i = 0; i < columns.length; i++) {
    4 row[columns[i].name] = parser.readColumnValue();
    5 }
    6 return row;
    7 }

    View Slide

  78. @felixge
    felixge
    1 function parseRow(columns, parser) {
    2 return {
    3 id : parser.readColumnValue(),
    4 title : parser.readColumnValue(),
    5 body : parser.readColumnValue(),
    6 created : parser.readColumnValue(),
    7 updated : parser.readColumnValue(),
    8 };
    9 }

    View Slide

  79. @felixge
    felixge
    How can we unroll this loop at
    runtime?

    View Slide

  80. @felixge
    felixge
    1 var code = 'return {\n';
    2
    3 columns.forEach(function(column) {
    4 code += '"' + column.name + '":' + 'parser.readColumnValue(),\n';
    5 });
    6
    7 code += '};\n';
    8
    9 var parseRow = new Function('columns', 'parser', code);

    View Slide

  81. PLEASE DO NOT
    REMEMBER THIS
    -
    DO YOUR OWN
    BENCHMARKS!!!

    View Slide

  82. @felixge
    felixge
    Data Analysis

    View Slide

  83. @felixge
    felixge
    Data analysis
    • Produce data points as tab separated values
    • Add as many VM/OS metrics as you can get to every line
    • Do not mix data and analysis !!

    View Slide

  84. @felixge
    felixge
    Recommended Tools
    • node benchmark.js | tee results.tsv
    • R Programming language (with ggplot2) !
    • Makefiles, Image Magick, Skitch

    View Slide

  85. @felixge
    felixge
    Why?

    View Slide

  86. @felixge
    felixge
    0
    2,000
    4,000
    6,000
    mysql2 new−parser
    benchmark
    mbit
    benchmark
    mysql2
    new−parser

    View Slide

  87. @felixge
    felixge

    ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


    ● ●
    ● ● ●●
    ● ● ●
    ● ● ● ●
    ● ●
    ● ●
    ● ●
    ● ●
    ● ●
    ● ●
    ● ●


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


    ● ●
    ● ●
    ● ●
    ● ● ●●
    ● ●

    ● ●
    ● ●
    ● ● ●
    ●● ● ●
    ● ●

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



    ● ●
    3,000
    4,000
    5,000
    6,000
    mysql2 new−parser
    benchmark
    mbit
    benchmark


    mysql2
    new−parser

    View Slide

  88. @felixge
    felixge

    ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


    ● ●
    ● ● ●●
    ● ● ●
    ● ● ● ●
    ● ●
    ● ●
    ● ●
    ● ●
    ● ●
    ● ●
    ● ●


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


    ● ●
    ● ●
    ● ●
    ● ● ●●
    ● ●

    ● ●
    ● ●
    ● ● ●
    ●● ● ●
    ● ●

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



    ● ●
    3,000
    4,000
    5,000
    6,000
    mysql2 new−parser
    benchmark
    mbit
    benchmark


    mysql2
    new−parser
    Dafuq?
    Dafuq?

    View Slide

  89. @felixge
    felixge
    3,000
    4,000
    5,000
    6,000
    0 100 200 300
    number
    mbit
    benchmark
    mysql2
    new−parser

    View Slide

  90. @felixge
    felixge
    10
    20
    30
    0 100 200 300
    number
    Heap Total (MB)
    benchmark
    mysql2
    new−parser

    View Slide

  91. @felixge
    felixge
    5
    10
    15
    0 100 200 300
    number
    Heap Used (MB)
    benchmark
    mysql2
    new−parser

    View Slide

  92. @felixge
    felixge
    tl;dr

    View Slide

  93. @felixge
    felixge
    1. Write a benchmark
    2. Write/change a little code
    3. Collect data
    4. Find problems
    5. Goto 2

    View Slide

  94. @felixge
    felixge
    Thank you
    Felix Geisendörfer

    View Slide

  95. @felixge
    felixge
    github.com/felixge/faster-than-c
    All benchmarks, results and analysis scripts
    Felix Geisendörfer

    View Slide