Slide 1

Slide 1 text

Vladimir Agafonkin ⚡fast by default: algorithmic optimization in practice

Slide 2

Slide 2 text

rain.in.ua

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

obsessed with performance⚡

Slide 8

Slide 8 text

❤❤❤ open source

Slide 9

Slide 9 text

1.find a narrowly scoped task 2.⚡make the world’s fastest and simplest JavaScript library for it 3. repeat

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

github.com/mapbox/potpack

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

spatial indices

Slide 17

Slide 17 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 18

Slide 18 text

mapbox/pixelmatch (JS) mapbox/pixelmatch-cpp (C++)

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

github.com/d3/d3-delaunay

Slide 21

Slide 21 text

github.com/mapbox/delaunator

Slide 22

Slide 22 text

1.delaunay: 150s 2.delaunay-fast: 117s 3.faster-delaunay: 5s 4.delaunator: 1s⚡ 5.delaunator-cpp: 0.9s 6.delaunator-rs: 0.9s triangulating 1 million points in JS

Slide 23

Slide 23 text

math education? %

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

why learn algorithms?

Slide 26

Slide 26 text

Vladimir Agafonkin a super-silly introduction to algorithms

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

1. find a bottleneck 2. find out why it’s slow 3. make it faster optimization:

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

1. find a bottleneck 2. find out why it’s slow 3. make it faster optimization:

Slide 31

Slide 31 text

slow code: code that does unnecessary work

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

Rollup

Slide 34

Slide 34 text

rollup/rollup#2062 rollup: map = magicString.generateMap() rollup: obj = decode(map) ";;;;EAEEA,EAAE,EAAC,CAAE;ECQY,UACC…"

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

map = encode(obj) obj = decode(map)

Slide 37

Slide 37 text

your code dependencies

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

O(1) O(log n) O(n) O(n log n) O(n2) O(n3)

Slide 40

Slide 40 text

algorithmic complexity: a way to describe how performance scales with input size

Slide 41

Slide 41 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 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 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 45

Slide 45 text

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

Slide 46

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

Slide 47 text

accidentallyquadratic.tumblr.com

Slide 48

Slide 48 text

O(n3) — rewrite from scratch 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 49

Slide 49 text

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

Slide 50

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

Slide 51 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 52

Slide 52 text

No content

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

for (const b of items) { a.slice().concat(b).map(foo) .filter(bar).reduce(bla, 0); }

Slide 56

Slide 56 text

functional programming! immutability! reactivity! damn allocations

Slide 57

Slide 57 text

function foo() { … return [x, y]; } const [x, y] = foo();

Slide 58

Slide 58 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 59

Slide 59 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) { // ";" ... 3 times faster

Slide 60

Slide 60 text

O(log n) logarithmic complexity

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

binary search o(log n)

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

No content

Slide 68

Slide 68 text

No content

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

rollup/rollup#2228 … 40x faster

Slide 71

Slide 71 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 out algorithmic optimization

Slide 72

Slide 72 text

slow slow slow algorithmic optimization

Slide 73

Slide 73 text

organize data algorithmic optimization

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

sorted array o(n log n) ❤ favorite data structure

Slide 77

Slide 77 text

sort so that all items in the left are smaller o(n) github.com/mourner/quickselect 39, 28, 28, 33, 21, 12, 22, 50, 53, 56, 59, 65, 90, 77, 95

Slide 78

Slide 78 text

github.com/mourner/kdbush

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

people take established code for granted

Slide 83

Slide 83 text

established != best there is always room for improvement

Slide 84

Slide 84 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 85

Slide 85 text

Gràcies agafonkin.com