Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With...
Transcript of Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With...
![Page 1: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/1.jpg)
Lightning-Fast Standard Collections
With ScalaBlitz
Dmitry Petrashko (@dark_dimius)
École Polytechnique Fédérale de Lausanne
17 June 2014
![Page 2: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/2.jpg)
Outline
● Example: Scala collections vs Java collections● What stops Scala collections from being fast on an example● Observations:
– Macro-based operations: huge bytecode?
– Interop with specialization
● How to use optimize{}● Supported collections & speedups● Future work
![Page 3: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/3.jpg)
Scala Collections:
![Page 4: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/4.jpg)
Scala Collections:Variety of flavors
![Page 5: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/5.jpg)
Scala Collections:Variety of flavors
![Page 6: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/6.jpg)
Scala Collections:API
![Page 7: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/7.jpg)
Scala Collections:Performance
Java Scala
public double average(int[] data) { int sum = 0; for(int i = 0; i < data.length; i++) { sum += data[i]; } return sum * 1.0d / data.length}
def average(x: Array[Int]) = x.reduce(_ + _) * 1.0 /x.size
![Page 8: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/8.jpg)
Scala Collections:Performance
20 msec 650 msec
Java Scala
public double average(int[] data) { int sum = 0; for(int i = 0; i < data.length; i++) { sum += data[i]; } return sum * 1.0d / data.length}
def average(x: Array[Int]) = x.reduce(_ + _) * 1.0 /x.size
![Page 9: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/9.jpg)
But why?
![Page 10: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/10.jpg)
But why?
Cycle body:● Range check● addition● increment
Java
public double average(int[] data) { int sum = 0; for(int i = 0; i < data.length; i++) { sum += data[i]; } return sum * 1.0d / data.length}
![Page 11: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/11.jpg)
But why?
20 msec 650 msec
Java Scala
public double average(int[] data) { int sum = 0; for(int i = 0; i < data.length; i++) { sum += data[i]; } return sum * 1.0d / data.length}
def average(x: Array[Int]) = { x.reduce(_ + _) * 1.0 /x.size }
![Page 12: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/12.jpg)
But why?
99% of time is spent in `reduce`
def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala
def average(x: Array[Int]) = x.reduce(_ + _) * 1.0 /x.size
![Page 13: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/13.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 14: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/14.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 15: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/15.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 16: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/16.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 17: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/17.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 18: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/18.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 19: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/19.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)● addition
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 20: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/20.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)● addition● boxing of result
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 21: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/21.jpg)
But why?def reduce(op: Function2[Obj, Obj, Obj]): Obj = { var first = true var acc: B = 0.asInstanceOf[B]
this.foreach{ e => if (first) { acc = e first = false } else acc = op.apply(acc, e) } acc }
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)● addition● boxing of result● increment
def foreach(f: Funtion1[Obj, Obj]) { var i = 0 val len = length while (i < len) { f.apply(this(i)); i += 1 } }
![Page 22: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/22.jpg)
But why?Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)● addition● boxing of result● Increment
Java cycle body:● range check● addition● increment
Have ~same cost:● single boxing(allocation) ● 4 dynamic dispatches● 15 additions
![Page 23: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/23.jpg)
Scala Collections:Performance
Can we fix it?
![Page 24: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/24.jpg)
Java Scala
public double average(int[] data) { int sum = 0; for(int i = 0; i < data.length; i++) { sum += data[i]; } return sum * 1.0d / data.length}
import scala.collection.optimizer._
def average(x: Array[Int]) = optimize{ x.reduce(_ + _) * 1.0 /x.size }
20 msec 650 msec 20 msec.
![Page 25: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/25.jpg)
Is it that bad?
![Page 26: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/26.jpg)
Practical example: PageRank
![Page 27: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/27.jpg)
Practical example: PageRank40% speedup(2539 vs 1488 msec)
![Page 28: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/28.jpg)
Operation overhead
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)● addition● boxing of result● increment
The faster is the operation you perform on elements, the more prone you are to this slowdown
![Page 29: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/29.jpg)
Operation overhead*Operations time
Invocation overhead
Iterationtime
range.reduce(_ + _) 4.5 50 2
array.reduce(_ + _) 4.5 50 4
array.map(_ + 1) 60 50 4
array.map(math.sqrt(_)) 95 50 4
*Those values are very hard to measure and are approximate
![Page 30: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/30.jpg)
Operation overhead
0% 10% 20% 30% 40% 50% 60% 70% 80% 90% 100%
IterationInvocation overheadOperation
![Page 31: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/31.jpg)
Operation overhead
Scala cycle body:● range check● boxing of element● dynamic dispatch(foreach arg)● predicate check(first?)● dynamic dispatch(reduce arg)● addition● boxing of result● increment
The faster is the operation you perform on elements, the more prone you are to this slowdown
![Page 32: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/32.jpg)
ScalaBlitz history
ScalaBlitz 1 year ago:● GSOC project developed in cooperation and under supervision of
Alex Prokopec● Aimed on shipping better parallel collections for Scala
● Better API● Best performance
![Page 33: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/33.jpg)
ScalaBlitz historyScala parallel collections API: what's wrong with it?
list.par.scanLeft(0)(_ + _).foldRight(0)(_ + _)
![Page 34: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/34.jpg)
list.par
List(1, 2, 3, 4, 5) => ParVector(1, 2, 3, 4, 5)
ScalaBlitz historyScala parallel collections API: what's wrong with it?
![Page 35: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/35.jpg)
list.par.scanLeft(0)(_ + _)
ParVector(1, 2, 3, 4, 5) => ParVector(0, 1, 3, 6, 10, 15)
ScalaBlitz historyScala parallel collections API: what's wrong with it?
![Page 36: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/36.jpg)
list.par.scanLeft(0)(_ + _).foldRight(0)(_ + _)
ParVector(0, 1, 3, 6, 10, 15) => 0 + 15 + 10 + 6 + 3 + 1 + 0 = 35
ScalaBlitz historyScala parallel collections API: what's wrong with it?
![Page 37: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/37.jpg)
ScalaBlitz history
Scala parallel collections performance?range.reduce(_ + _)
Range ParRange(4 cores)
ScalaBlitz(1 core)
ScalaBlitz(2 cores)
ScalaBlitz(4 cores)
415 msec 8174 msec 20.4 msec 10.2 msec 5.3 msec
![Page 38: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/38.jpg)
How?
Macro: ● Uses quasiquotes to analyze and generate code
![Page 39: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/39.jpg)
Macro-based operations: huge bytecode?
optimize{ (1 to 10).reduce(_ + _)}
![Page 40: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/40.jpg)
Observations: bytecode size
In practice size is almost same or even decreased due to inlining of closures.
Original ScalaBlitz
1964+1693= 3657 bytes
2488 bytes
![Page 41: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/41.jpg)
Observations: collection specializations
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 42: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/42.jpg)
Observations: collection specializations
def count(p: Funtion1[Object, Object]): Int = { var cnt = 0 this.foreach{ x => if (p(x)) cnt += 1 } cnt }
def foreach[U](f: A => U) { var these = this while (!these.isEmpty) { f(these.head) these = these.tail }
Original cycle body:
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 43: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/43.jpg)
Observations: collection specializations
def count(p: Funtion1[Object, Object]): Int = { var cnt = 0 this.foreach{ x => if (p(x)) cnt += 1 } cnt }
def foreach[U](f: A => U) { var these = this while (!these.isEmpty) { f(these.head) these = these.tail }
Original cycle body:● range check
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 44: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/44.jpg)
Observations: collection specializations
def count(p: Funtion1[Object, Object]): Int = { var cnt = 0 this.foreach{ x => if (p(x)) cnt += 1 } cnt }
def foreach[U](f: A => U) { var these = this while (!these.isEmpty) { f(these.head) these = these.tail }
Original cycle body:● range check● dynamic dispatch
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 45: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/45.jpg)
Observations: collection specializations
def count(p: Funtion1[Object, Object]): Int = { var cnt = 0 this.foreach{ x => if (p(x)) cnt += 1 } cnt }
def foreach[U](f: A => U) { var these = this while (!these.isEmpty) { f(these.head) these = these.tail }
Original cycle body:● range check● dynamic dispatch● unboxing of element
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 46: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/46.jpg)
Observations: collection specializations
def count(p: Funtion1[Object, Object]): Int = { var cnt = 0 this.foreach{ x => if (p(x)) cnt += 1 } cnt }
def foreach[U](f: A => U) { var these = this while (!these.isEmpty) { f(these.head) these = these.tail }
Original cycle body:● range check● dynamic dispatch● unboxing of element● predicate check
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 47: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/47.jpg)
Observations: collection specializations
def count(p: Funtion1[Object, Object]): Int = { var cnt = 0 this.foreach{ x => if (p(x)) cnt += 1 } cnt }
def foreach[U](f: A => U) { var these = this while (!these.isEmpty) { f(these.head) these = these.tail }
Original cycle body:● range check● dynamic dispatch● unboxing of element● predicate check● increment
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 48: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/48.jpg)
Observations: collection specializations
ScalaBlitz cycle body:def countSB(x: List[Int]) = { var head = x var count = 0 while (!head.isEmpty) { if (x.head > 0) count += 1 head = head.tail } count}
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 49: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/49.jpg)
Observations: collection specializations
ScalaBlitz cycle body:● range check
def countSB(x: List[Int]) = { var head = x var count = 0 while (!head.isEmpty) { if (x.head > 0) count += 1 head = head.tail } count}
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 50: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/50.jpg)
Observations: collection specializations
ScalaBlitz cycle body:● range check● unboxing of element
def countSB(x: List[Int]) = { var head = x var count = 0 while (!head.isEmpty) { if (x.head > 0) count += 1 head = head.tail } count}
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 51: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/51.jpg)
Observations: collection specializations
ScalaBlitz cycle body:● range check● unboxing of element● predicate check
def countSB(x: List[Int]) = { var head = x var count = 0 while (!head.isEmpty) { if (x.head > 0) count += 1 head = head.tail } count}
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 52: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/52.jpg)
Observations: collection specializations
ScalaBlitz cycle body:● range check● unboxing of element● predicate check● count increment
def countSB(x: List[Int]) = { var head = x var count = 0 while (!head.isEmpty) { if (x.head > 0) count += 1 head = head.tail } count}
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
![Page 53: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/53.jpg)
Observations: collection specializations
Some operations cannot be optimized further without specializing the collection: Eg, count, filter, find
ScalaBlitz cycle body:● range check● unboxing of element● predicate check● increment
Potential gain of combining with http://scala-miniboxing.org/see “Miniboxing: Specialization on a Diet” talk by Vlad Ureche tomorrow.
Original cycle body:● range check● dynamic dispatch● unboxing of element● predicate check● increment
![Page 54: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/54.jpg)
CaveatsGenerated code is harder to debug. Looking forward to “Easy Metaprogramming For Everyone!” by Eugene Burmako and Denys Shabalin
That isn't a big problem if we maintain same guarantees as Scala Collections
Hard to understand stack-traces and runtime profiles.
A bit slower for tiny collections(several elements)
No custom CanBuildFrom support(yet)
![Page 55: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/55.jpg)
Supported collections&Speedups
Range Array HashMap&HashSet
Immutable Map&Set
List
reduce(_ +_) 44x 33x 5.1x 1.1x 4.3x
sum 38x 29x 1.7x 1.1x 2.8x
product 27x 19x 1.6x 1.1x 1.6x
min & max both constant
25x 1.7x same 1.2x
map(_ + 1) 10x 10x 1.3x 1.5x unsupported
flatmap(x => List(x, x))
1.1x 1.3x 1.3x 1.3x unsupported
find(_ < 0)&friends
12x 10x 2.4x same unsupported
count(_ > 0) 3.8x 3.3x 1.3x same unsupported
![Page 56: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/56.jpg)
What does unsupported collection mean?
![Page 57: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/57.jpg)
What does unsupported collection mean?
Nothing bad,operation will simply be performed
by Scala collections
![Page 58: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/58.jpg)
Future work: operation fusion
def minAvgMax(xs: List[Int]) = { val avg = xs.sum * 1.0 / xs.size (xs.min, avg, xs.max) }
Current status: 4 independent operations over collection:● sum● size (also linear time!)● min● max
Idea: interleave operations,use single iteration over collection to perform all 4.
![Page 59: Lightning-Fast Standard Collections With ScalaBlitz · Lightning-Fast Standard Collections With ScalaBlitz Dmitry Petrashko (@dark_dimius) École Polytechnique Fédérale de Lausanne](https://reader030.fdocuments.net/reader030/viewer/2022040314/5e0fb810f0ec366bc11fdf92/html5/thumbnails/59.jpg)
Future work: deforestation
val minMaleAge = people.filter(_.isMale).map(_.age).min
Current status: 2 intermediate collections● filter● map
Idea: use stream-like pipelining