Slide 1

Slide 1 text

⚡fast by default: everyday algorithmic thinking for developers Vladimir Agafonkin

Slide 2

Slide 2 text

obsessed with performance

Slide 3

Slide 3 text

❤❤❤ open source

Slide 4

Slide 4 text

1. Find a narrowly scoped task 2. ⚡ Make the world’s fastest and simplest JavaScript library for it 3. Back to step 1

Slide 5

Slide 5 text

Leaflet, mapbox-gl-js, mapbox-gl-native, earcut, earcut.hpp, rbush, rbush-knn, kdbush, kdbush.hpp, geokdbush, flatbush, geoflatbush, concaveman, supercluster, supercluster.hpp, dobbyscan, delaunator, d3-delaunay, linematch, lineclip, pixelmatch, simplify-js, cheap-ruler, polylabel, tinyqueue, flatqueue, tile-cover, which-polygon, quickselect, simple-statistics, tiny-sdf, geojson-vt, potpack, geojson-vt-cpp, geobuf, pbf, tile-reduce, geojson.hpp, geometry.hpp, tile-decorator, mbtiles- extracts, webgl-wind, suncalc, flamebearer, simpleheat, binary-split, magic-string, polysnap, rollup, sourcemap-codec

Slide 6

Slide 6 text

github.com/mapbox/delaunator

Slide 7

Slide 7 text

github.com/d3/d3-delaunay

Slide 8

Slide 8 text

1.delaunay: 150s 2.delaunay-fast: 117s 3.faster-delaunay: 5s 4.delaunator: 1.3s⚡ triangulating 1 million points in JavaScript

Slide 9

Slide 9 text

mapbox/earcut (JS) mapbox/earcut.hpp (C++)

Slide 10

Slide 10 text

spatial indices

Slide 11

Slide 11 text

github.com/mourner/rbush github.com/mourner/kdbush github.com/mourner/flatbush github.com/mourner/rbush-knn github.com/mourner/geokdbush github.com/mourner/geoflatbush

Slide 12

Slide 12 text

~ mapbox/geojson-vt (JS) mapbox/geojson-vt-cpp (C++)

Slide 13

Slide 13 text

mapbox/supercluster (JS) mapbox/supercluter-hpp (C++)

Slide 14

Slide 14 text

mapbox/supercluster (JS) mapbox/supercluter-hpp (C++)

Slide 15

Slide 15 text

github.com/mapbox/webgl-wind

Slide 16

Slide 16 text

github.com/mapbox/potpack

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

mathematical background? %

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

why understand algorithms?

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

99% of performance bottlenecks are of algorithmic nature

Slide 23

Slide 23 text

slow code: code which does unnecessary work

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

productive laziness: the art of avoiding unnecessary work

Slide 26

Slide 26 text

algorithmic thinking: the art of avoiding unnecessary work by a machine

Slide 27

Slide 27 text

your app frameworks

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

rollup/rollup#2062 rollup: map = magicString.generateMap() rollup: obj = decode(map)

Slide 30

Slide 30 text

rollup/rollup#2062 rollup: map = magicString.generateMap() magic-string: ... map = encode(obj) rollup: obj = decode(map)

Slide 31

Slide 31 text

rollup/rollup#2062 rollup: map = magicString.generateDecodedMap() magic-string: map = encode(obj) rollup: obj = decode(map) 40% faster source maps

Slide 32

Slide 32 text

1. identify a bottleneck 2. find out why it’s a bottleneck 3. optimize the bottleneck performance optimization: requires understanding algorithms

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

algorithmic complexity: and where to look for unnecessary work a way to describe how performance scales with input size

Slide 35

Slide 35 text

O(1) O(log n) O(n) O(n log n) O(n^2) O(n^3)

Slide 36

Slide 36 text

array[0] + array[1]; O(1) — instant

Slide 37

Slide 37 text

O(n) — suspicious for (const item of array) { sum += item; }

Slide 38

Slide 38 text

O(n2) — terribly slow for (let i = 0, n = array.length; i < n; i++) { for (let j = i + 1; j < n; j++) { sum += array[i] + array[j]; } }

Slide 39

Slide 39 text

function foo(array) { for (const item of array) { array[array.indexOf(item)] = item + 10; } } O(n2) — terribly slow

Slide 40

Slide 40 text

function foo(array) { for (const item of array) { bar(array, item); } } function bar(array, item) { array[array.indexOf(item)] = item + 10; } O(n2) — terribly slow

Slide 41

Slide 41 text

accidentallyquadratic.tumblr.com

Slide 42

Slide 42 text

O(n3) — unbearable, throw away for (let i = 0, n = array.length; i < n; i++) { for (let j = i + 1; j < n; j++) { for (let k = j + 1; k < n; k++) { sum += array[i] + array[j]; } } }

Slide 43

Slide 43 text

1. O(1) — instant 2. O(n) — suspicious 3. O(n2) — terribly slow 4. O(n3) — throw away

Slide 44

Slide 44 text

1. O(1) — 1 2. O(n) — 1000 3. O(n2) — 1,000,000 4. O(n3) — 1,000,000,000 (n = 1000)

Slide 45

Slide 45 text

чорти б мене побрали!!! хай йому грець!! дідько! if (j < 0) { if (triangles.length === 0) triangles.push([i]); return; } for (let n = triangles.length, a = 0; a < n; ++a) { let sa = triangles[a]; if (sa[0] === j) { for (let b = a + 1; b < n; ++b) { let sb = triangles[b]; if (sb[sb.length - 1] === i) { triangles.splice(b, 1); triangles[a] = sa = sb.concat(sa); return; } } sa.unshift(i); return; } d3/d3-delaunay#23

Slide 46

Slide 46 text

array.indexOf array.lastIndexOf array.splice array.includes array.reverse array.every Object.values array.find array.some array.findIndex array.reduce array.reduceRight array.some Object.keys O(n) — suspicious

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

array.slice array.concat array.map array.filter str.split suspicious allocations

Slide 49

Slide 49 text

a.slice().concat(b).map(foo) .filter(bar).reduce(bla, 0); allocate memory and throw it away immediately (4 times)

Slide 50

Slide 50 text

for (const b of items) { a.slice().concat(b).map(foo) .filter(bar).reduce(bla, 0); } allocate memory and throw it away immediately (4 times)

Slide 51

Slide 51 text

functional programming! immutability! reactivity! damn allocations

Slide 52

Slide 52 text

foo.forEach(a => { bar.forEach(b => { baz.forEach(c => { ... }); }); });

Slide 53

Slide 53 text

JIT-optimizing JS engines don’t always understand what you want

Slide 54

Slide 54 text

write predictable code so that the engine doesn’t have to guess

Slide 55

Slide 55 text

Rich-Harris/sourcemap-codec#71 const lines = input.split(';'); for (const line of lines) { const segments = line.split(','); for (const segment of segments) { const decoded = decode(segment); for (const i of decoded) { ... } } }

Slide 56

Slide 56 text

Rich-Harris/sourcemap-codec#71 for (let i = 0; i < input.length; i++) { const c = input.charCodeAt(i); if (c === 44) { // "," ... } else if (c === 59) { // ";" ... 2.7x faster decoding

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

O(1) O(n) O(log n) O(log n) — blazing fast

Slide 59

Slide 59 text

1 1,000,000 20 O(log n) — blazing fast

Slide 60

Slide 60 text

binary search o(log n)

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

No content

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

rollup/rollup#2228 … 40x faster

Slide 68

Slide 68 text

1. O(n) → O(log n) 2. O(n log n) → O(n) 3. O(n2) → O(n log n) 4. O(n3) — throw away algorithmic optimization:

Slide 69

Slide 69 text

slow slow slow algorithmic optimization:

Slide 70

Slide 70 text

data processing algorithmic optimization:

Slide 71

Slide 71 text

do more at the beginning to do less every next time algorithmic optimization:

Slide 72

Slide 72 text

data structures: ways to organize data to search and update it efficiently

Slide 73

Slide 73 text

• hash map • hash set • binary search tree • priority heap • linked list data structures: • interval tree • grid • r-tree • quadtree • kd-tree

Slide 74

Slide 74 text

sorting an array: o(n log n)

Slide 75

Slide 75 text

sorting an array so that smallest k items come first: o(n) github.com/mourner/quickselect

Slide 76

Slide 76 text

github.com/mourner/kdbush

Slide 77

Slide 77 text

priority tree: push: o(1) top: o(1) pop: o(log n) github.com/mourner/tinyqueue github.com/mourner/flatqueue

Slide 78

Slide 78 text

• how often do you insert items? • how often do you remove items? • how often do you access items, and how? data structures:

Slide 79

Slide 79 text

{ '1': 10, '2': 20, '3': 30 }; { '0': 10, '1': 20, ‘2': 30 }; HashTable Array [10, 20, 30];

Slide 80

Slide 80 text

istanbuljs/istanbul-lib-instrument#22 { '1': 10, '2': 20, '3': 30 }; { '0': 10, '1': 20, ‘2': 30 }; 15x faster

Slide 81

Slide 81 text

how I read academic papers and reference code

Slide 82

Slide 82 text

1. learn how things work under the hood 2. don’t hesitate to dig inside frameworks 3. contribute to open source 4. don’t be afraid to reinvent the wheel 5. simplify your code constantly 6. practice optimization, and you’ll learn how to write fast code from the start

Slide 83

Slide 83 text

thank you