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 transloadit.com nodecopter.com

Slide 3

Slide 3 text

Faster than C?

Slide 4

Slide 4 text

Sorry about the “title bait”

Slide 5

Slide 5 text

High performance JavaScript

Slide 6

Slide 6 text

JavaScript vs C

Slide 7

Slide 7 text

Good vs Evil

Slide 8

Slide 8 text

Good Parts vs Evil

Slide 9

Slide 9 text

Bad Parts vs Evil

Slide 10

Slide 10 text

early 2010

Slide 11

Slide 11 text

No MySQL module for node.js early 2010

Slide 12

Slide 12 text

All we had was NoSQL Libraries early 2010

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

Pure JS / No C/C++

Slide 15

Slide 15 text

Before Buffers became usable

Slide 16

Slide 16 text

The Parser was using JavaScript Strings

Slide 17

Slide 17 text

Node.js Trivia

Slide 18

Slide 18 text

“ Buffers” used to be called “Blobs”

Slide 19

Slide 19 text

For 3 min and 15 sec

Slide 20

Slide 20 text

RIP Blobs ✞

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Anyway

Slide 23

Slide 23 text

mysql can be done without libmysql

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No good deed goes unpunished

Slide 26

Slide 26 text

Sir Isaac Newton

Slide 27

Slide 27 text

Third Law of Motion

Slide 28

Slide 28 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 29

Slide 29 text

Third Law of Github

Slide 30

Slide 30 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 31

Slide 31 text

<3 Github!

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 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 34

Slide 34 text

Of course.

Slide 35

Slide 35 text

libmysql = C

Slide 36

Slide 36 text

my library = JavaScript

Slide 37

Slide 37 text

C > JS, right?

Slide 38

Slide 38 text

But V8!

Slide 39

Slide 39 text

And Crankshaft!!

Slide 40

Slide 40 text

Node.js !!!1!

Slide 41

Slide 41 text

Was I living a lie?

Slide 42

Slide 42 text

Kind of

Slide 43

Slide 43 text

V8 / Node = Tools

Slide 44

Slide 44 text

Performance is not a tool

Slide 45

Slide 45 text

Performance is hard work & data analysis

Slide 46

Slide 46 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 47

Slide 47 text

Third Law of Github

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 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 50

Slide 50 text

Time to give up?

Slide 51

Slide 51 text

NEVER!

Slide 52

Slide 52 text

New Parser

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

Third law of Github?

Slide 55

Slide 55 text

Endgame

Slide 56

Slide 56 text

Last bottleneck: Creating JS Objects

Slide 57

Slide 57 text

Also: MySQL Server saturated

Slide 58

Slide 58 text

Anyway

Slide 59

Slide 59 text

How to write fast JS

Slide 60

Slide 60 text

Does not work

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

Does Work

Slide 64

Slide 64 text

BDD

Slide 65

Slide 65 text

Behavior Driven Development

Slide 66

Slide 66 text

Benchmark Driven Development

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 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 71

Slide 71 text

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

Slide 72

Slide 72 text

Favorite

Slide 73

Slide 73 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 74

Slide 74 text

Make it faster!

Slide 75

Slide 75 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 76

Slide 76 text

->

Slide 77

Slide 77 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 78

Slide 78 text

eval = awesome

Slide 79

Slide 79 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 80

Slide 80 text

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

Slide 81

Slide 81 text

Why?

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ●● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● 3,000 4,000 5,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 Dafuq? Dafuq?

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

tl;dr

Slide 89

Slide 89 text

1. Write a benchmark 2. Write/change a little code 3. Collect data 4. Find problems 5. Goto 2

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 !

Slide 92

Slide 92 text

No content

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

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