Slide 1

Slide 1 text

Faster than C? Parsing binary data in JavaScript Felix Geisendörfer 7. Oct, 2012 - JSConf.eu

Slide 2

Slide 2 text

@felixge

Slide 3

Slide 3 text

transloadit.com

Slide 4

Slide 4 text

Faster than C?

Slide 5

Slide 5 text

Sorry about the “title bait”

Slide 6

Slide 6 text

High performance JavaScript

Slide 7

Slide 7 text

JavaScript vs C

Slide 8

Slide 8 text

Good vs Evil

Slide 9

Slide 9 text

Good Parts vs Evil

Slide 10

Slide 10 text

Bad Parts vs Evil

Slide 11

Slide 11 text

early 2010

Slide 12

Slide 12 text

No MySQL module for node.js early 2010

Slide 13

Slide 13 text

All we had was NoSQL Libraries early 2010

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Pure JS / No C/C++

Slide 16

Slide 16 text

Before Buffers became usable

Slide 17

Slide 17 text

The Parser was using JavaScript Strings

Slide 18

Slide 18 text

Node.js Trivia

Slide 19

Slide 19 text

“ Buffers” used to be called “Blobs”

Slide 20

Slide 20 text

For 3 min and 15 sec

Slide 21

Slide 21 text

RIP Blobs ✞

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

Anyway

Slide 24

Slide 24 text

mysql can be done without libmysql

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No good deed goes unpunished

Slide 27

Slide 27 text

Sir Isaac Newton

Slide 28

Slide 28 text

Third Law of Motion

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

Third Law of Github

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

<3 Github!

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

Of course.

Slide 36

Slide 36 text

libmysql = C

Slide 37

Slide 37 text

my library = JavaScript

Slide 38

Slide 38 text

C > JS, right?

Slide 39

Slide 39 text

But V8!

Slide 40

Slide 40 text

And Crankshaft!!

Slide 41

Slide 41 text

Node.js !!!1!

Slide 42

Slide 42 text

Was I living a lie?

Slide 43

Slide 43 text

Kind of

Slide 44

Slide 44 text

V8 / Node = Tools

Slide 45

Slide 45 text

Performance is not a tool

Slide 46

Slide 46 text

Performance is hard work & data analysis

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Third Law of Github

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

Time to give up?

Slide 52

Slide 52 text

NEVER!

Slide 53

Slide 53 text

New Parser

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

Third law of Github?

Slide 56

Slide 56 text

Endgame

Slide 57

Slide 57 text

Last bottleneck: Creating JS Objects

Slide 58

Slide 58 text

Also: MySQL Server saturated

Slide 59

Slide 59 text

Anyway

Slide 60

Slide 60 text

How to write fast JS

Slide 61

Slide 61 text

Does not work

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

Does Work

Slide 65

Slide 65 text

BDD

Slide 66

Slide 66 text

Behavior Driven Development

Slide 67

Slide 67 text

Benchmark Driven Development

Slide 68

Slide 68 text

Benchmark Driven Development • Similar to test driven development • Use it when performance is an explicit design goal • Benchmark first > benchmark after !

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

1 while (true) { 2 var start = Date.now(); 3 benchmark(); 4 var duration = Date.now() - start; 5 console.log(duration); 6 }

Slide 71

Slide 71 text

Benchmark Driven Development • Next step: Implement a tiny part of your function • Example: Parse headers of MySQL packets • Look at impact, tweak code, repeat

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Favorite

Slide 74

Slide 74 text

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 }

Slide 75

Slide 75 text

Make it faster!

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

->

Slide 78

Slide 78 text

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 }

Slide 79

Slide 79 text

eval = awesome

Slide 80

Slide 80 text

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 !!

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

Why?

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

Collect data -> Analyze it -> Find problems -> Tweak the code -> Repeat

Slide 90

Slide 90 text

Thank you

Slide 91

Slide 91 text

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