Pro Yearly is on sale from $80 to $50! »

Fast by Default: Algorithmic Optimization in Practice (JSCamp 2019)

Fast by Default: Algorithmic Optimization in Practice (JSCamp 2019)

6d07e6d95a43357254698ce9723350e6?s=128

Vladimir Agafonkin

July 19, 2019
Tweet

Transcript

  1. Vladimir Agafonkin ⚡fast by default: algorithmic optimization in practice

  2. rain.in.ua

  3. None
  4. None
  5. None
  6. None
  7. obsessed with performance⚡

  8. ❤❤❤ open source

  9. 1.find a narrowly scoped task 2.⚡make the world’s fastest and

    simplest JavaScript library for it 3. repeat
  10. 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
  11. mapbox/earcut (JS) mapbox/earcut.hpp (C++)

  12. github.com/mapbox/potpack

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

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

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

  16. spatial indices

  17. 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

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

  19. None
  20. github.com/d3/d3-delaunay

  21. github.com/mapbox/delaunator

  22. 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
  23. math education? %

  24. None
  25. why learn algorithms?

  26. Vladimir Agafonkin a super-silly introduction to algorithms

  27. None
  28. 1. find a bottleneck 2. find out why it’s slow

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

    3. make it faster optimization:
  31. slow code: code that does unnecessary work

  32. None
  33. Rollup

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

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

    rollup: obj = decode(map)
  36. map = encode(obj) obj = decode(map)

  37. your code dependencies

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

    obj = decode(map) source maps got 40% faster
  39. O(1) O(log n) O(n) O(n log n) O(n2) O(n3)

  40. algorithmic complexity: a way to describe how performance scales with

    input size
  41. 1. O(1) — 1 2. O(n) — 1000 3. O(n2)

    — 1,000,000 4. O(n3) — 1,000,000,000 (n = 1000)
  42. array[0] + array[1]; O(1) — instant

  43. O(n) — suspicious for (const item of array) { sum

    += item; }
  44. 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]; } }
  45. function foo(array) { for (const item of array) { array[array.indexOf(item)]

    = item + 10; } } O(n2) — terribly slow
  46. 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
  47. accidentallyquadratic.tumblr.com

  48. 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]; } } }
  49. 1. O(1) — instant 2. O(n) — suspicious 3. O(n2)

    — terribly slow 4. O(n3) — throw out
  50. 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
  51. 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
  52. None
  53. array.slice array.concat array.map array.filter str.split suspicious allocations

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

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

  56. functional programming! immutability! reactivity! damn allocations

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

    y] = foo();
  58. 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) { ... } } }
  59. 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
  60. O(log n) logarithmic complexity

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

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

  63. binary search o(log n)

  64. None
  65. None
  66. None
  67. None
  68. None
  69. None
  70. rollup/rollup#2228 … 40x faster

  71. 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
  72. slow slow slow algorithmic optimization

  73. organize data algorithmic optimization

  74. algorithmic optimization: do more at the beginning to do less

    every next time
  75. • hash map • hash set • binary search tree

    • priority heap • linked list • interval tree • grid • r-tree • quadtree • kd-tree data structures
  76. sorted array o(n log n) ❤ favorite data structure

  77. 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
  78. github.com/mourner/kdbush

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

    github.com/mourner/flatqueue
  80. { '1': 10, '2': 20, '3': 30 }; { '0':

    10, '1': 20, ‘2': 30 }; HashTable Array [10, 20, 30];
  81. istanbuljs/istanbul-lib-instrument#22 { '1': 10, '2': 20, '3': 30 }; {

    '0': 10, '1': 20, ‘2': 30 }; 15 times faster
  82. people take established code for granted

  83. established != best there is always room for improvement

  84. 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
  85. Gràcies agafonkin.com