Share
Embed
Devoxx UK 2015 Presentation: Miniboxing - Fast Generics for Primitive Types
Miniboxing presentation at Devoxx UK 2015. Website: http://www.devoxx.co.uk/
The recording is available on parleys: https://www.parleys.com/tutorial/miniboxing-fast-generics-primitive-types
The two demos:
- Streams: not yet online
- Image processing: http://scala-miniboxing.org/example_pureimage.html
Project website: http://scala-miniboxing.org
Vlad Ureche
June 18, 2015
Transcript
161 slides
-
scala-miniboxing.org @miniboxing 18th of June 2015 Devoxx United Kingdom London,
UK scala-miniboxing.org -
scala-miniboxing.org @miniboxing Vlad URECHE PhD student in the Scala Team
@ EPFL Working on program transformations in the Scala programming language, focusing on data representation. Contributions to specialization, backend and Scaladoc. @ @VladUreche @VladUreche [email protected] -
scala-miniboxing.org @miniboxing STOP Please ask if things are not clear!
Really! I mean it! -
scala-miniboxing.org @miniboxing What is miniboxing? Why use it? How does
it... ? Conclusion Generics -
scala-miniboxing.org @miniboxing Compilers Compilers Source code (language 1) compiler C,
C++, Java, Scala, C#, Haskell, Clojure, ... -
scala-miniboxing.org @miniboxing Compilers Compilers Source code (language 1) Source code
(language 2) compiler C, C++, Java, Scala, C#, Haskell, Clojure, ... x86/ARM assembly LLVM bitcode Cuda code JVM bytecode .NET bytecode ... -
scala-miniboxing.org @miniboxing Compilers Compilers Source code (language 1) Source code
(language 2) compiler C, C++, Java, Scala, C#, Haskell, Clojure, ... x86/ARM assembly LLVM bitcode Cuda code JVM bytecode .NET bytecode ... Why so much fuss ? -
scala-miniboxing.org @miniboxing Compilers Compilers Abstraction Imple- mentation compiler Variable Stack
slot or Processor register or Heap location -
scala-miniboxing.org @miniboxing Compilers Compilers Abstraction Imple- mentation compiler Variable Stack
slot or Processor register or Heap location … Implementation details -
scala-miniboxing.org @miniboxing Generics Don't Exist Generics Don't Exist in the
JVM in the JVM Java/ Scala -
scala-miniboxing.org @miniboxing Generics Don't Exist Generics Don't Exist in the
JVM in the JVM Java/ Scala -
scala-miniboxing.org @miniboxing Generics Don't Exist Generics Don't Exist in the
JVM in the JVM Javac Scalac Java/ Scala -
scala-miniboxing.org @miniboxing Generics Don't Exist Generics Don't Exist in the
JVM in the JVM Javac Scalac Generics Java/ Scala -
scala-miniboxing.org @miniboxing Erased Generics Erased Generics def identity[T](t: T): T
= t def identity(t: Object): Object = t scalac / javac -
scala-miniboxing.org @miniboxing Erased Generics Erased Generics java.lang.Integer.valueOf(5) boxing is not
great ... boxing is not great ... inflates heap requirements -
scala-miniboxing.org @miniboxing Erased Generics Erased Generics java.lang.Integer.valueOf(5) boxing is not
great ... boxing is not great ... inflates heap requirements produces garbage -
scala-miniboxing.org @miniboxing Erased Generics Erased Generics java.lang.Integer.valueOf(5) boxing is not
great ... boxing is not great ... inflates heap requirements produces garbage value is accessed indirectly (slow) -
scala-miniboxing.org @miniboxing Erased Generics Erased Generics java.lang.Integer.valueOf(5) boxing is not
great ... boxing is not great ... inflates heap requirements produces garbage value is accessed indirectly (slow) breaks locality guarantees -
scala-miniboxing.org @miniboxing Specialization Specialization def identity[T](t: T): T = t
def identity(t: Object): Object = t specialization -
scala-miniboxing.org @miniboxing Specialization Specialization def identity[T](t: T): T = t
def identity(t: Object): Object = t specialization def identity_Z(t: bool): bool = t -
scala-miniboxing.org @miniboxing Specialization Specialization def identity[T](t: T): T = t
def identity(t: Object): Object = t specialization def identity_Z(t: bool): bool = t def identity_C(t: char): char = t -
scala-miniboxing.org @miniboxing Specialization Specialization def identity[T](t: T): T = t
def identity(t: Object): Object = t specialization def identity_Z(t: bool): bool = t def identity_C(t: char): char = t … (7 other variants) -
scala-miniboxing.org @miniboxing Specialization Specialization identity(5) identity_I(5) specialization No boxing, it
automatically calls the specialized variant for integers -
scala-miniboxing.org @miniboxing Specialization Specialization def tupled[T1, T2](t1: T1, t2: T2)
... // 100 methods (102) specialization -
scala-miniboxing.org @miniboxing Specialization Specialization def tupled[T1, T2](t1: T1, t2: T2)
... // 100 methods (102) specialization -
scala-miniboxing.org @miniboxing Specialization Specialization def tupled[T1, T2](t1: T1, t2: T2)
... // 100 methods (102) specialization Can we do better? -
scala-miniboxing.org @miniboxing What is miniboxing? Why use it? How does
it... ? Conclusion Generics -
scala-miniboxing.org @miniboxing The idea behind The idea behind LONG DOUBLE
miniboxing miniboxing -
scala-miniboxing.org @miniboxing The idea behind The idea behind LONG DOUBLE
INT miniboxing miniboxing -
scala-miniboxing.org @miniboxing The idea behind The idea behind ... LONG
DOUBLE INT FLOAT SHORT miniboxing miniboxing -
scala-miniboxing.org @miniboxing The idea behind The idea behind ... LONG
DOUBLE INT FLOAT SHORT ... LONG DOUBLE INT FLOAT SHORT a long integer miniboxing miniboxing -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing def identity[T](t: T): T = t
def identity(t: Object): Object = t miniboxing -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing def identity[T](t: T): T = t
def identity(t: Object): Object = t miniboxing def identity_M(..., t: long): long = t -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing def identity[T](t: T): T = t
def identity(t: Object): Object = t miniboxing def identity_M(..., t: long): long = t long encodes all primitive types -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing def identity[T](t: T): T = t
def identity(t: Object): Object = t miniboxing def identity_M(..., t: long): long = t Only 2n variants long encodes all primitive types -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing identity(3) identity_M(..., int2minibox(3)) miniboxing The miniboxed
variant of identity Unlike boxing, these conversions do not affect performance -
scala-miniboxing.org @miniboxing What is miniboxing? Why use it? How does
it... ? Conclusion Generics -
scala-miniboxing.org @miniboxing Clash of the Lambdas Clash of the Lambdas
• Paper from 2014 • By Aggelos Biboudis, Uni of Athens -
scala-miniboxing.org @miniboxing Clash of the Lambdas Clash of the Lambdas
• Paper from 2014 • By Aggelos Biboudis, Uni of Athens • Comparing Steaming support in – in Java 8 – in Scala – in .NET -
scala-miniboxing.org @miniboxing Clash of the Lambdas Clash of the Lambdas
• Paper from 2014 • By Aggelos Biboudis, Uni of Athens • Comparing Steaming support in – in Java 8 – in Scala – in .NET • … but Scala did not have streaming support -
scala-miniboxing.org @miniboxing Clash of the Lambdas Clash of the Lambdas
• Paper from 2014 • By Aggelos Biboudis, Uni of Athens • Comparing Steaming support in – in Java 8 – in Scala – in .NET • But Scala lacks an equivalent streaming support – Thus the numbers :) -
scala-miniboxing.org @miniboxing What is miniboxing? Why use it? How does
it... ? Conclusion Generics -
scala-miniboxing.org @miniboxing Warnings Warnings scala> def baz[T](t: T): T =
t baz: [T](t: T)T scala> baz(4) -
scala-miniboxing.org @miniboxing Warnings Warnings scala> def baz[T](t: T): T =
t baz: [T](t: T)T scala> baz[Int](4) -
scala-miniboxing.org @miniboxing Warnings Warnings scala> def baz[T](t: T): T =
t baz: [T](t: T)T scala> baz[Int](4) <console>:9: warning: The method baz would benefit from miniboxing type parameter T, since it is instantiated by a primitive type. ... -
scala-miniboxing.org @miniboxing Call Graph Call Graph def foo[T](t: T): T
= bar(t) def bar[T](t: T): T = baz(t) -
scala-miniboxing.org @miniboxing Call Graph Call Graph def foo[T](t: T): T
= bar(t) def bar[T](t: T): T = baz(t) def baz[T](t: T): T = t -
scala-miniboxing.org @miniboxing Call Graph Call Graph def foo[T](t: T): T
= bar(t) def bar[T](t: T): T = baz(t) def baz[T](t: T): T = t call graph -
scala-miniboxing.org @miniboxing Miniboxed Call Graph Miniboxed Call Graph def foo[@miniboxed
T](t: T): T = bar(t) def bar[@miniboxed T](t: T): T = baz(t) def baz[@miniboxed T](t: T): T = t -
scala-miniboxing.org @miniboxing Miniboxed Call Graph Miniboxed Call Graph def foo[@miniboxed
T](t: T): T = bar(t) def bar[@miniboxed T](t: T): T = baz(t) def baz[@miniboxed T](t: T): T = t miniboxing -
scala-miniboxing.org @miniboxing Miniboxed Call Graph Miniboxed Call Graph def foo(...):
... = bar(t) def foo_M(...): ... = bar_M(t) def bar(...): ... = baz(t) def bar_M(...): ... = baz_M(t) def baz(...): ... = t def baz_M(...): ... = t -
scala-miniboxing.org @miniboxing Miniboxed Call Graph Miniboxed Call Graph foo foo_M
bar bar_M baz baz_M Data is pased in the miniboxed encoding no boxing necessary! -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph def foo[@miniboxed
T](t: T): T = bar(t) def bar[@miniboxed T](t: T): T = baz(t) def baz[@miniboxed T](t: T): T = t -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph def foo[@miniboxed
T](t: T): T = bar(t) def bar[@miniboxed T](t: T): T = baz(t) def baz[@miniboxed T](t: T): T = t -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph def foo[@miniboxed
T](t: T): T = bar(t) def bar[@miniboxed T](t: T): T = baz(t) def baz[@miniboxed T](t: T): T = t miniboxing -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph foo foo_M
bar baz baz_M boxing arguments → warn -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph foo foo_M
bar baz baz_M boxing arguments → warn -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph foo foo_M
bar baz baz_M boxing arguments → warn -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph foo foo_M
bar baz baz_M boxing arguments → warn there is a better version but I can't call it → warn -
scala-miniboxing.org @miniboxing Suboptimal Call Graph Suboptimal Call Graph scala> object
Test { | def foo[@miniboxed T](t: T): T = bar(t) | def bar[ T](t: T): T = baz(t) | def baz[@miniboxed T](t: T): T = t | } <console>:10: warning: The method Test.bar would benefit from miniboxing type parameter T, since it is instantiated by miniboxed type parameter T of method foo: def foo[@miniboxed T](t: T): T = bar(t) ^ <console>:11: warning: The following code could benefit from miniboxing specialization if the type parameter T of method bar would be marked as "@miniboxed T": def bar[T](t: T): T = baz(t) ^ defined object Test -
scala-miniboxing.org @miniboxing Warnings Warnings • Miniboxing tries to avoid boxing
• When it can't avoid it, it warns you – And you can act on it • Many other warnings – To keep you from shooting yourself in the foot -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing • Replaces the library constructs –
Functions – Arrays – Numeric type classes ... library ... library -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing • Replaces the library constructs –
Functions – Arrays – Numeric type classes • Adds – Interfaces to other constructs – Miniboxed state reflection ... library ... library -
scala-miniboxing.org @miniboxing Miniboxing Miniboxing • Replaces the library constructs –
Functions – Arrays – Numeric type classes • Adds – Interfaces to other constructs – Miniboxed state reflection ... library ... library Am I inside a miniboxed class? If so, what is T? -
scala-miniboxing.org @miniboxing What is miniboxing? Why use it? How does
it... ? Conclusion Generics -
scala-miniboxing.org @miniboxing Credits and Thank you-s • Martin Odersky -
without Scala, there would be no miniboxing • Cristian Talau - developed the initial prototype, as a semester project • Milos Stojanovic - work on warnings, tuple accessors and others • Romain Beguet - work on miniboxed arrays • Eugene Burmako - the value class plugin based on the LDL transformation • Aymeric Genet - developing collection-like benchmarks for the miniboxing plugin • Martin Odersky, for his patient guidance • Dmitry Petrashko, for the many cool discussions we had • Ilya Klyuchnikov and Pablo Guerrero - fixes and commits • Iulian Dragos, for his work on specialization and many explanations • Miguel Garcia, for his original insights that spawned the miniboxing idea • Michel Schinz, for his wonderful comments and enlightening ACC course • Andrew Myers and Roland Ducournau for the discussions we had and the feedback provided • Heather Miller for the eye-opening discussions we had • Vojin Jovanovic, Sandro Stucki, Manohar Jonalagedda and the whole LAMP laboratory in EPFL • Adriaan Moors, for the miniboxing name which stuck :)) • Thierry Coppey, Vera Salvisberg and George Nithin, for the feedback -
scala-miniboxing.org @miniboxing Credits and Thank you-s • Grzegorz Kossakowski, for
the many brainstorming sessions on specialization • Erik Osheim, Tom Switzer and Rex Kerr for their guidance on the Scala community side • Sandro, Vojin, Nada, Heather, Manohar - reviews and discussions on the LDL paper • Hubert Plociniczak for the type notation in the LDL paper • Denys Shabalin (@densh), Dmitry Petrashko (@darkdimius) for their patient reviews of the LDL paper • Alexandru Nedelcu (@alex_ndc) - for the functions direction • Stu Hood (@stuhood) - for the initial support, ideas • Julien Truffault (@JulienTruffaut) - for motivating the development of tuple accessors, sticky plugin warnings • Aggelos Biboudis (@biboudis) - for pushing the functions project forward and the stream benchmarks • Tom Switzer (@tixxit) - for pushing the array project forward and the vector benchmarks • Philip Stutz (@PhilipStutz) - for the ideas on warnings • Rex Kerr (@ichoran) - for ideas on reflection • Vlad Patryshev (@vpatryshev) - for organizing the Scala Bay Meetup, wehre I presented once • The Scala Community • The Valhalla Project Architects • The Devoxx, PNWScala and ScalaDays organizers! -
scala-miniboxing.org @miniboxing PureImage PureImage • has very nice abstractions –
generalizes over input, output format – generalizes over pixel format – provides collection-like mapping over images • liked it a lot -
scala-miniboxing.org @miniboxing PureImage PureImage • took the usual path to
using miniboxing – code up a mock-up – become familiar with the problem – try out miniboxing on a small scale -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Image[Repr: Pixel]
{ def width: Int def height: Int def apply(x: Int, y: Int): Repr def map[Repr2: Pixel](f: Image[Repr] => Generator[Repr2]): Image[Repr2] } -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Image[Repr: Pixel]
{ def width: Int def height: Int def apply(x: Int, y: Int): Repr def map[Repr2: Pixel](f: Image[Repr] => Generator[Repr2]): Image[Repr2] } What's a generator? -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Generator[Repr: Pixel]
{ def width: Int def height: Int def generate(x: Int, y: Int): Repr } -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Generator[Repr: Pixel]
{ def width: Int def height: Int def generate(x: Int, y: Int): Repr } Why generic? What is pixel? -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels Transformed image 8-bit RGBA channels ... -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels Image on disk Indexed colors Transformed image 8-bit RGBA channels ... -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels Image on disk Indexed colors Transformed image 8-bit RGBA channels ... discretization after each filter => artifacts -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels Image on disk Indexed colors Transformed image 8-bit RGBA channels ... discretization after each filter => artifacts double precision RGBA double precision RGBA -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels Image on disk Indexed colors Transformed image 8-bit RGBA channels ... discretization after each filter => artifacts double precision RGBA double precision RGBA discretization only when saving the file => better quality -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up Image on disk Indexed
colors Loaded image 8-bit RGBA channels Transformed image 8-bit RGBA channels Image on disk Indexed colors Transformed image 8-bit RGBA channels ... discretization after each filter => artifacts double precision RGBA double precision RGBA discretization only when saving the file => better quality Pixel representation -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Pixel[Repr: Manifest]
{ def r(t: Repr): Double // red def g(t: Repr): Double // green def b(t: Repr): Double // blue def a(t: Repr): Double // alpha def pack(r: Double, g: Double, b: Double, a: Double): Repr ... } -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Pixel[Repr: Manifest]
{ def r(t: Repr): Double // red def g(t: Repr): Double // green def b(t: Repr): Double // blue def a(t: Repr): Double // alpha def pack(r: Double, g: Double, b: Double, a: Double): Repr ... } All transformations occur on doubles -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up abstract class Pixel[Repr: Manifest]
{ def r(t: Repr): Double // red def g(t: Repr): Double // green def b(t: Repr): Double // blue def a(t: Repr): Double // alpha def pack(r: Double, g: Double, b: Double, a: Double): Repr ... } All transformations occur on doubles But the data can be encoded differently -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up object RGBA extends Pixel[Int]
{ ... } object RGBAExtended extends Pixel[Long] { ... } -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up object RGBA extends Pixel[Int]
{ ... } object RGBAExtended extends Pixel[Long] { ... } Encoding all channels -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up object RGBA extends Pixel[Int]
{ ... } object RGBAExtended extends Pixel[Long] { ... } case class DiscreteChannels[T](r: T, g: T, b: T, a: T) object FullPixel extends FourChannelPixel[Double] object HalfPixel extends FourChannelPixel[Float] Encoding all channels -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up object RGBA extends Pixel[Int]
{ ... } object RGBAExtended extends Pixel[Long] { ... } case class DiscreteChannels[T](r: T, g: T, b: T, a: T) object FullPixel extends FourChannelPixel[Double] object HalfPixel extends FourChannelPixel[Float] Storing channels individually Encoding all channels -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up "More London Office Development
at Dusk, London, UK - Diliff" by Diliff - Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:More_London_Office_Development_at_Dusk,_London,_UK_-_Diliff.jpg -
scala-miniboxing.org @miniboxing PureImage Mock-up PureImage Mock-up "More London Office Development
at Dusk, London, UK - Diliff" by Diliff - Own work. Licensed under CC BY-SA 3.0 via Wikimedia Commons - https://commons.wikimedia.org/wiki/File:More_London_Office_Development_at_Dusk,_London,_UK_-_Diliff.jpg