Faster than C?

Faster than C?

Presentation given at the Prague JS Usergroup.

23968f0ca75b13463d2db5343e5c2096?s=128

Felix Geisendörfer

November 29, 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 As fast as C bindings For parsing binary protocols

    / database drivers
  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 at telling you which functions

    are slow • Bad at telling you how to fix it
  65. felixge Taking performance advice from strangers

  66. @felixge felixge Taking performance advice from strangers • Good for

    ideas & inspiration • But useless when applied cargo-cult style
  67. @felixge felixge for (var i = 0; i < array.length;

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

    i < length; i++) { // do some work with array[i] }
  69. felixge What 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 Optimization: Loop unrolling with eval()’s good twin

    new Function()
  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 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. @felixge felixge How can we unroll this loop at runtime?

  80. @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);
  81. PLEASE DO NOT REMEMBER THIS - DO YOUR OWN BENCHMARKS!!!

  82. @felixge felixge Data Analysis

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

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

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

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

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

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

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

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

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

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

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

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

    Geisendörfer