Faster than C? Parsing binary data in JavaScript.

Faster than C? Parsing binary data in JavaScript.

Talk given at JSConf.eu 2012.

23968f0ca75b13463d2db5343e5c2096?s=128

Felix Geisendörfer

October 07, 2012
Tweet

Transcript

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

    7. Oct, 2012 - JSConf.eu
  2. @felixge

  3. transloadit.com

  4. Faster than C?

  5. Sorry about the “title bait”

  6. High performance JavaScript

  7. JavaScript vs C

  8. Good vs Evil

  9. Good Parts vs Evil

  10. Bad Parts vs Evil

  11. early 2010

  12. No MySQL module for node.js early 2010

  13. All we had was NoSQL Libraries early 2010

  14. None
  15. Pure JS / No C/C++

  16. Before Buffers became usable

  17. The Parser was using JavaScript Strings

  18. Node.js Trivia

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

  20. For 3 min and 15 sec

  21. RIP Blobs ✞

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

    2009
  23. Anyway

  24. mysql can be done without libmysql

  25. None
  26. No good deed goes unpunished

  27. Sir Isaac Newton

  28. Third Law of Motion

  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.”
  30. Third Law of Github

  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.”
  32. <3 Github!

  33. None
  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
  35. Of course.

  36. libmysql = C

  37. my library = JavaScript

  38. C > JS, right?

  39. But V8!

  40. And Crankshaft!!

  41. Node.js !!!1!

  42. Was I living a lie?

  43. Kind of

  44. V8 / Node = Tools

  45. Performance is not a tool

  46. Performance is hard work & data analysis

  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
  48. Third Law of Github

  49. None
  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
  51. Time to give up?

  52. NEVER!

  53. New Parser

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

    new−parser
  55. Third law of Github?

  56. Endgame

  57. Last bottleneck: Creating JS Objects

  58. Also: MySQL Server saturated

  59. Anyway

  60. How to write fast JS

  61. Does not work

  62. Profiling • Good for spotting small functions with stupid algorithms

    performing many iterations • Bad for complex functions with many primitive operations
  63. Taking performance advice from strangers • Good for ideas &

    inspiration • But useless when applied cargo-cult style
  64. Does Work

  65. BDD

  66. Behavior Driven Development

  67. Benchmark Driven Development

  68. Benchmark Driven Development • Similar to test driven development •

    Use it when performance is an explicit design goal • Benchmark first > benchmark after !
  69. 1 function benchmark() { 2 // intentionally empty 3 }

  70. 1 while (true) { 2 var start = Date.now(); 3

    benchmark(); 4 var duration = Date.now() - start; 5 console.log(duration); 6 }
  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
  72. Example Results • try...catch is ok • big switch statement

    = bad • function calls = very cheap • buffering is ok
  73. Favorite

  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 }
  75. Make it faster!

  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);
  77. ->

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

  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 !!
  81. Recommended Tools • node benchmark.js | tee results.tsv • R

    Programming language (with ggplot2) ! • Makefiles, Image Magick, Skitch
  82. Why?

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

    new−parser
  84. • • • • • • • • • •

    • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • •• • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • 3,000 4,000 5,000 6,000 mysql2 new−parser benchmark mbit benchmark • • mysql2 new−parser
  85. • • • • • • • • • •

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

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

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

    (MB) benchmark mysql2 new−parser
  89. Collect data -> Analyze it -> Find problems -> Tweak

    the code -> Repeat
  90. Thank you

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