Faster than C?

Faster than C?

Presentation given at nodedublin.

23968f0ca75b13463d2db5343e5c2096?s=128

Felix Geisendörfer

October 18, 2012
Tweet

Transcript

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

    18. Oct, 2012 - NodeDublin
  2. @felixge transloadit.com nodecopter.com

  3. My Battle

  4. JavaScript vs C

  5. Good vs Evil

  6. Good Parts vs Evil

  7. Bad Parts vs Evil

  8. Faster than C?

  9. Sorry for the “title bait”

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

  11. The Story

  12. early 2010

  13. No MySQL module for node.js early 2010

  14. All we had was NoSQL Libraries early 2010

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

  17. Before Buffers became usable

  18. The Parser was using JavaScript Strings

  19. Node.js Trivia

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

  21. For 3 min and 15 sec

  22. RIP Blobs ✞

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

    2009
  24. Anyway

  25. mysql can be done without libmysql

  26. None
  27. No good deed goes unpunished

  28. Sir Isaac Newton

  29. Third Law of Motion

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

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

  34. None
  35. 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
  36. 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
  37. Of course.

  38. libmysql = C

  39. my library = JavaScript

  40. C > JS, right?

  41. But V8!

  42. And Crankshaft!!

  43. Node.js !!!1!

  44. Was I living a lie?

  45. Kind of

  46. V8 / Node = Tools

  47. Performance is not a tool

  48. Performance is hard work & data analysis

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

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

  54. NEVER!

  55. New Parser

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

    new−parser
  57. Third law of Github?

  58. Endgame

  59. Last bottleneck: Creating JS Objects

  60. Also: MySQL Server saturated

  61. Anyway

  62. How to write fast JS

  63. Does not work

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

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

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

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

  81. new Function = awesome

  82. Data Analysis

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

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

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

    new−parser
  87. • • • • • • • • • •

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

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

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

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

    (MB) benchmark mysql2 new−parser
  92. tl;dr

  93. 1. Write a benchmark 2. Write/change a little code 3.

    Collect data 4. Find problems 5. Goto 2
  94. Thank you

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

  96. None
  97. None
  98. nodecopter.com Dublin, Oct 20 (Saturday) Brighton, Nov 10 http://tinyurl.com/brcopter