Faster than C?

Faster than C?

Presentation given at nodeconf.it.

23968f0ca75b13463d2db5343e5c2096?s=128

Felix Geisendörfer

November 10, 2012
Tweet

Transcript

  1. felixge Faster than C? Parsing binary data in JavaScript Felix

    Geisendörfer
  2. @felixge felixge Background 2005 - 2008 2008 - now 2009

    - now
  3. @felixge felixge The NodeCopter nodecopter.com

  4. felixge This Talk

  5. felixge JavaScript vs C

  6. felixge Good vs Evil

  7. felixge Good Parts vs Evil

  8. felixge Bad Parts vs Evil

  9. felixge Faster than C?

  10. felixge No Sorry for the “title bait”

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

  12. felixge The Story

  13. felixge early 2010

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

  15. felixge

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

  17. felixge Before Buffers became usable

  18. felixge The Parser was using JavaScript Strings

  19. felixge Node.js Trivia

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

  21. felixge For 3 min and 15 sec

  22. felixge RIP Blobs ✞

  23. felixge Sun Dec 13 08:39:20 2009 - Sun Dec 13

    08:42:45 2009
  24. felixge Anyway

  25. felixge mysql can be done without libmysql

  26. felixge

  27. felixge No good deed goes unpunished

  28. felixge Sir Isaac Newton

  29. felixge 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. felixge 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. felixge <3 Github!

  34. felixge

  35. @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
  36. 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
  37. felixge Of course.

  38. felixge libmysql = C

  39. felixge my library = JavaScript

  40. felixge C > JS, right?

  41. felixge But V8!

  42. felixge And Crankshaft!!

  43. felixge Node.js !!!1!

  44. felixge Was I living a lie?

  45. felixge Kind of

  46. felixge V8 / Node = Tools

  47. felixge Performance is not a tool

  48. felixge Performance is hard work & data analysis

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

  51. felixge

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

  54. felixge NEVER!

  55. felixge New Parser

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

    benchmark mysql2 new−parser
  57. felixge Third law of Github?

  58. felixge Endgame

  59. felixge Last bottleneck: V8 / Creating JS Objects

  60. felixge Also: MySQL Server saturated

  61. felixge Anyway

  62. felixge How to write fast JS

  63. felixge Does not work

  64. @felixge felixge Profiling • Good for spotting small functions with

    stupid algorithms performing many iterations • Bad for complex functions with many primitive operations
  65. felixge Taking performance advice from strangers

  66. @felixge felixge for (var i = 0; i < array.length;

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

    i < length; i++) { // do some work with array[i] }
  68. @felixge felixge Taking performance advice from strangers • Good for

    ideas & inspiration • But useless when applied cargo-cult style
  69. felixge Does Work

  70. felixge Benchmark Driven Development

  71. @felixge felixge Benchmark Driven Development • Similar to test driven

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

    }
  73. felixge 1 while (true) { 2 var start = Date.now();

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

    switch statement = bad • function calls = very cheap • buffering is ok
  76. @felixge felixge Favorite

  77. @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 }
  78. @felixge felixge Make it faster!

  79. @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);
  80. @felixge felixge ->

  81. @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 }
  82. @felixge felixge eval = awesome

  83. @felixge felixge eval = awesome

  84. @felixge felixge new Function = awesome

  85. @felixge felixge Data Analysis

  86. @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 !!
  87. @felixge felixge Recommended Tools • node benchmark.js | tee results.tsv

    • R Programming language (with ggplot2) ! • Makefiles, Image Magick, Skitch
  88. @felixge felixge Why?

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

    benchmark mysql2 new−parser
  90. @felixge felixge • • • • • • • •

    • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • •• • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • • 3,000 4,000 5,000 6,000 mysql2 new−parser benchmark mbit benchmark • • mysql2 new−parser
  91. @felixge felixge • • • • • • • •

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

    number mbit benchmark mysql2 new−parser
  93. @felixge felixge 10 20 30 0 100 200 300 number

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

    Heap Used (MB) benchmark mysql2 new−parser
  95. @felixge felixge tl;dr

  96. @felixge felixge 1. Write a benchmark 2. Write/change a little

    code 3. Collect data 4. Find problems 5. Goto 2
  97. @felixge felixge Thank you Felix Geisendörfer

  98. @felixge felixge github.com/felixge/faster-than-c All benchmarks, results and analysis scripts Felix

    Geisendörfer