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

Faster than C? Parsing binary data in JavaScript.

Faster than C? Parsing binary data in JavaScript.

Talk given at JSConf.eu 2012.

Felix Geisendörfer

October 07, 2012
Tweet

More Decks by Felix Geisendörfer

Other Decks in Technology

Transcript

  1. Faster than C?
    Parsing binary data in JavaScript
    Felix Geisendörfer 7. Oct, 2012 - JSConf.eu

    View Slide

  2. @felixge

    View Slide

  3. transloadit.com

    View Slide

  4. Faster than C?

    View Slide

  5. Sorry about the
    “title bait”

    View Slide

  6. High
    performance
    JavaScript

    View Slide

  7. JavaScript vs C

    View Slide

  8. Good vs Evil

    View Slide

  9. Good Parts vs Evil

    View Slide

  10. Bad Parts vs Evil

    View Slide

  11. early 2010

    View Slide

  12. No MySQL module
    for node.js
    early 2010

    View Slide

  13. All we had was
    NoSQL Libraries
    early 2010

    View Slide

  14. View Slide

  15. Pure JS / No C/C++

    View Slide

  16. Before Buffers
    became usable

    View Slide

  17. The Parser was using
    JavaScript Strings

    View Slide

  18. Node.js Trivia

    View Slide

  19. “ Buffers” used to be
    called “Blobs”

    View Slide

  20. For 3 min and 15 sec

    View Slide

  21. RIP Blobs

    View Slide

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

    View Slide

  23. Anyway

    View Slide

  24. mysql can be done
    without libmysql

    View Slide

  25. View Slide

  26. No good deed goes
    unpunished

    View Slide

  27. Sir Isaac Newton

    View Slide

  28. Third Law of Motion

    View Slide

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

  30. Third Law of Github

    View Slide

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

  32. <3 Github!

    View Slide

  33. View Slide

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

  35. Of course.

    View Slide

  36. libmysql = C

    View Slide

  37. my library = JavaScript

    View Slide

  38. C > JS, right?

    View Slide

  39. But V8!

    View Slide

  40. And Crankshaft!!

    View Slide

  41. Node.js !!!1!

    View Slide

  42. Was I
    living a lie?

    View Slide

  43. Kind of

    View Slide

  44. V8 / Node
    = Tools

    View Slide

  45. Performance
    is not a tool

    View Slide

  46. Performance is
    hard work &
    data analysis

    View Slide

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

  48. Third Law of Github

    View Slide

  49. View Slide

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

  51. Time to give up?

    View Slide

  52. NEVER!

    View Slide

  53. New Parser

    View Slide

  54. 0
    2,000
    4,000
    6,000
    mysql2 new−parser
    benchmark
    mbit
    benchmark
    mysql2
    new−parser

    View Slide

  55. Third law of Github?

    View Slide

  56. Endgame

    View Slide

  57. Last bottleneck:
    Creating JS Objects

    View Slide

  58. Also: MySQL Server saturated

    View Slide

  59. Anyway

    View Slide

  60. How to write fast JS

    View Slide

  61. Does not work

    View Slide

  62. Profiling
    • Good for spotting small functions with stupid
    algorithms performing many iterations
    • Bad for complex functions with many
    primitive operations

    View Slide

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

    View Slide

  64. Does Work

    View Slide

  65. BDD

    View Slide

  66. Behavior Driven
    Development

    View Slide

  67. Benchmark Driven
    Development

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

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

    View Slide

  73. Favorite

    View Slide

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

  75. Make it faster!

    View Slide

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

  77. ->

    View Slide

  78. 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. eval = awesome

    View Slide

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

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

    View Slide

  82. Why?

    View Slide

  83. 0
    2,000
    4,000
    6,000
    mysql2 new−parser
    benchmark
    mbit
    benchmark
    mysql2
    new−parser

    View Slide


  84. ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


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


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


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

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

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



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


    mysql2
    new−parser

    View Slide


  85. ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


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


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


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

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

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



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


    mysql2
    new−parser
    Dafuq?
    Dafuq?

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  89. Collect data ->
    Analyze it ->
    Find problems ->
    Tweak the code ->
    Repeat

    View Slide

  90. Thank you

    View Slide

  91. github.com/felixge/faster-than-c
    All benchmarks, results and analysis scripts
    Thank you !

    View Slide