Slide 1

Slide 1 text

Vladimir Agafonkin ⚡fast by default: algorithmic optimization in practice

Slide 2

Slide 2 text

No content

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

⚡fast or GTFO

Slide 7

Slide 7 text

Leaflet earcut pixelmatch delaunator rbush flatbush kdbush geokdbush geoflatbush geojson-vt potpack supercluster martini delatin cheap-ruler polylabel icomesh concaveman dobbyscan linematch lineclip simplify-js robust-predicates tinyqueue flatqueue which-polygon quickselect webgl-wind suncalc flamebearer tiny-sdf simpleheat … github.com/mourner/projects

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

github.com/mapbox/potpack

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

github.com/mapbox/delatin

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

delaunay: 150s delaunay-fast: 117s faster-delaunay: 5s delaunator: 1s delaunator-cpp: 0.9s delaunator-rs: 0.9s Delaunay triangulation of 1 million points in JavaScript:

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

slow code: code that does unnecessary work

Slide 20

Slide 20 text

Rollup

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

algorithmic complexity: a measure of how performance scales with input size

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

O(n2) — ridiculously 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 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

accidentallyquadratic.tumblr.com

Slide 33

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

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

Slide 35 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 36

Slide 36 text

No content

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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) { ... } } } Rich-Harris/sourcemap-codec#71

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

O(log n) logarithmic complexity

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

binary search o(log n)

Slide 46

Slide 46 text

No content

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

No content

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

rollup/rollup#2228 … 40x faster

Slide 53

Slide 53 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 54

Slide 54 text

slow slow slow algorithmic optimization

Slide 55

Slide 55 text

organize data algorithmic optimization

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

github.com/mourner/kdbush

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

people take established code for granted

Slide 63

Slide 63 text

established !== best there is always room for improvement

Slide 64

Slide 64 text

1. learn how things work under the hood 2. don’t be afraid to reinvent the wheel 3. simplify your code constantly 4. practice optimization, and you’ll learn how to write fast code by default

Slide 65

Slide 65 text

agafonkin.com thank you