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

Faster than C?

Faster than C?

Presentation given at nodeconf.it.

Felix Geisendörfer

November 10, 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 full-size slide

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

    View full-size slide

  3. @felixge
    felixge
    The NodeCopter
    nodecopter.com

    View full-size slide

  4. felixge
    This Talk

    View full-size slide

  5. felixge
    JavaScript vs C

    View full-size slide

  6. felixge
    Good vs Evil

    View full-size slide

  7. felixge
    Good Parts vs Evil

    View full-size slide

  8. felixge
    Bad Parts vs Evil

    View full-size slide

  9. felixge
    Faster than C?

    View full-size slide

  10. felixge
    No
    Sorry for the “title bait”

    View full-size slide

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

    View full-size slide

  12. felixge
    The Story

    View full-size slide

  13. felixge
    early 2010

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. felixge
    Before Buffers
    became usable

    View full-size slide

  17. felixge
    The Parser was using
    JavaScript Strings

    View full-size slide

  18. felixge
    Node.js Trivia

    View full-size slide

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

    View full-size slide

  20. felixge
    For 3 min and 15 sec

    View full-size slide

  21. felixge
    RIP Blobs

    View full-size slide

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

    View full-size slide

  23. felixge
    Anyway

    View full-size slide

  24. felixge
    mysql can be done
    without libmysql

    View full-size slide

  25. felixge
    No good deed goes
    unpunished

    View full-size slide

  26. felixge
    Sir Isaac Newton

    View full-size slide

  27. felixge
    Third Law of Motion

    View full-size slide

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

  29. felixge
    Third Law of Github

    View full-size slide

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

  31. felixge
    <3 Github!

    View full-size slide

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

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

  34. felixge
    Of course.

    View full-size slide

  35. felixge
    libmysql = C

    View full-size slide

  36. felixge
    my library = JavaScript

    View full-size slide

  37. felixge
    C > JS, right?

    View full-size slide

  38. felixge
    But V8!

    View full-size slide

  39. felixge
    And Crankshaft!!

    View full-size slide

  40. felixge
    Node.js !!!1!

    View full-size slide

  41. felixge
    Was I
    living a lie?

    View full-size slide

  42. felixge
    Kind of

    View full-size slide

  43. felixge
    V8 / Node
    = Tools

    View full-size slide

  44. felixge
    Performance
    is not a tool

    View full-size slide

  45. felixge
    Performance is
    hard work &
    data analysis

    View full-size slide

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

  47. felixge
    Third Law of Github

    View full-size slide

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

  49. felixge
    Time to give up?

    View full-size slide

  50. felixge
    NEVER!

    View full-size slide

  51. felixge
    New Parser

    View full-size slide

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

    View full-size slide

  53. felixge
    Third law of Github?

    View full-size slide

  54. felixge
    Endgame

    View full-size slide

  55. felixge
    Last bottleneck:
    V8 / Creating JS Objects

    View full-size slide

  56. felixge
    Also: MySQL Server saturated

    View full-size slide

  57. felixge
    Anyway

    View full-size slide

  58. felixge
    How to write fast JS

    View full-size slide

  59. felixge
    Does not work

    View full-size slide

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

    View full-size slide

  61. felixge
    Taking performance advice
    from strangers

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  65. felixge
    Does Work

    View full-size slide

  66. felixge
    Benchmark Driven
    Development

    View full-size slide

  67. @felixge
    felixge
    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

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

    View full-size slide

  69. felixge
    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

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

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

    View full-size slide

  72. @felixge
    felixge
    Favorite

    View full-size slide

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

  74. @felixge
    felixge
    Make it faster!

    View full-size slide

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

  76. @felixge
    felixge
    ->

    View full-size slide

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

  78. @felixge
    felixge
    eval = awesome

    View full-size slide

  79. @felixge
    felixge
    eval = awesome

    View full-size slide

  80. @felixge
    felixge
    new Function = awesome

    View full-size slide

  81. @felixge
    felixge
    Data Analysis

    View full-size slide

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

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

    View full-size slide

  84. @felixge
    felixge
    Why?

    View full-size slide

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

    View full-size slide

  86. @felixge
    felixge

    ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


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


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


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

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

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



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


    mysql2
    new−parser

    View full-size slide

  87. @felixge
    felixge

    ● ●

    ● ●

    ● ●
    ● ●

    ● ● ●
    ● ● ●
    ● ●
    ● ● ●


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


    ● ● ●
    ● ●
    ● ● ● ●

    ● ●
    ● ● ●
    ● ● ●
    ● ●

    ● ●
    ● ● ●
    ● ●



    ● ●


    ● ●
    ● ●

    ● ● ●
    ● ●





    ● ●
    ● ●
    ● ●
    ● ● ●

    ● ● ●

    ● ●

    ● ● ● ●

    ● ●

    ● ●

    ● ● ●

    ● ●
    ● ● ●


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

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

    ● ●

    ● ●

    ● ●
    ●● ● ●

    ● ● ●
    ● ●




    ● ● ● ●






    ● ●
    ● ●
    ● ● ●

    ● ● ●
    ● ●
    ● ●



    ● ●


    ● ● ●
    ● ●






    ● ●
    ● ●

    ● ●
    ● ●



    ● ● ● ●



    ● ●

    ● ●

    ● ●

    ● ●

    ● ● ●



    ● ●



    ● ●




    ● ●



    ●●



    ● ●

    ● ●

    ● ● ●
    ● ● ●
    ● ●



    ● ● ●
    ● ●●


    ● ●

    ● ●

    ● ●

    ● ●





    ● ●●



    ● ●
    ● ●

    ● ●




    ● ●
    ● ●

    ● ●



    ● ●


    ● ● ●





    ● ●
    ● ● ●






    ● ●

    ● ●



    ● ● ● ●

    ● ●

    ● ●
    ● ● ● ●
    ● ●

    ● ●

    ● ●

    ● ●


    ● ●




    ● ● ●





    ● ●
    ● ●

    ● ●

    ● ●



    ● ●




    ● ● ●
    ● ● ●

    ● ●
    ● ●
    ● ● ●


    ● ●

    ● ●

    ● ●
    ● ●









    ● ●






    ● ● ●




    ● ● ● ●

    ● ●


    ● ●

    ● ●●
    ● ● ●
    ● ●
    ● ●

    ● ●

    ● ●


    ● ● ● ●

    ● ●
    ● ●


    ● ●
    ● ●
    ● ●
    ● ●

    ● ● ●









    ● ●



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


    mysql2
    new−parser
    Dafuq?
    Dafuq?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  91. @felixge
    felixge
    tl;dr

    View full-size slide

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

    View full-size slide

  93. @felixge
    felixge
    Thank you
    Felix Geisendörfer

    View full-size slide

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

    View full-size slide