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

Faster than C?

Faster than C?

Presentation given at nodedublin.

Felix Geisendörfer

October 18, 2012
Tweet

More Decks by Felix Geisendörfer

Other Decks in Programming

Transcript

  1. Faster than C?
    Parsing binary data in JavaScript
    Felix Geisendörfer 18. Oct, 2012 - NodeDublin

    View full-size slide

  2. @felixge
    transloadit.com nodecopter.com

    View full-size slide

  3. JavaScript vs C

    View full-size slide

  4. Good vs Evil

    View full-size slide

  5. Good Parts vs Evil

    View full-size slide

  6. Bad Parts vs Evil

    View full-size slide

  7. Faster than C?

    View full-size slide

  8. Sorry for the
    “title bait”

    View full-size slide

  9. JavaScript vs C-Addons
    (for parsing binary protocols)

    View full-size slide

  10. No MySQL module
    for node.js
    early 2010

    View full-size slide

  11. All we had was
    NoSQL Libraries
    early 2010

    View full-size slide

  12. Pure JS / No C/C++

    View full-size slide

  13. Before Buffers
    became usable

    View full-size slide

  14. The Parser was using
    JavaScript Strings

    View full-size slide

  15. Node.js Trivia

    View full-size slide

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

    View full-size slide

  17. For 3 min and 15 sec

    View full-size slide

  18. RIP Blobs

    View full-size slide

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

    View full-size slide

  20. mysql can be done
    without libmysql

    View full-size slide

  21. No good deed goes
    unpunished

    View full-size slide

  22. Sir Isaac Newton

    View full-size slide

  23. Third Law of Motion

    View full-size slide

  24. “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 full-size slide

  25. Third Law of Github

    View full-size slide

  26. “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 full-size slide

  27. 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 full-size slide

  28. 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 full-size slide

  29. libmysql = C

    View full-size slide

  30. my library = JavaScript

    View full-size slide

  31. C > JS, right?

    View full-size slide

  32. And Crankshaft!!

    View full-size slide

  33. Node.js !!!1!

    View full-size slide

  34. Was I
    living a lie?

    View full-size slide

  35. V8 / Node
    = Tools

    View full-size slide

  36. Performance
    is not a tool

    View full-size slide

  37. Performance is
    hard work &
    data analysis

    View full-size slide

  38. 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 full-size slide

  39. Third Law of Github

    View full-size slide

  40. 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 full-size slide

  41. Time to give up?

    View full-size slide

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

    View full-size slide

  43. Third law of Github?

    View full-size slide

  44. Last bottleneck:
    Creating JS Objects

    View full-size slide

  45. Also: MySQL Server saturated

    View full-size slide

  46. How to write fast JS

    View full-size slide

  47. Does not work

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  50. Benchmark Driven
    Development

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  54. 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 full-size slide

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

    View full-size slide

  56. 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 full-size slide

  57. Make it faster!

    View full-size slide

  58. 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 full-size slide

  59. 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 full-size slide

  60. eval = awesome

    View full-size slide

  61. eval = awesome

    View full-size slide

  62. new Function = awesome

    View full-size slide

  63. Data Analysis

    View full-size slide

  64. 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 full-size slide

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

    View full-size slide

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

    View full-size slide


  67. ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


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


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


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

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

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



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


    mysql2
    new−parser

    View full-size slide


  68. ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


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


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


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

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

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



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


    mysql2
    new−parser
    Dafuq?
    Dafuq?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  74. nodecopter.com
    Dublin, Oct 20
    (Saturday)
    Brighton, Nov 10
    http://tinyurl.com/brcopter

    View full-size slide