Learn all about miniboxing in a 5 minute demo.


Image Processing Example - PNWScala

The following example is based on the miniboxing presentation at PNWScala. A huge thanks to Thomas Lockney and the PNWScala organizers for the wonderful conference and the confreaks guys who recorded the presentation!


This page will guide you through the steps necessary to run the example in the presentation. The pureimage library is located at github.com/stephenjudkins/pureimage. The mock-up used for the presentation is located at github.com/VladUreche/image-example.

To start, clone the pureimage mock-up:

$ git clone https://github.com/VladUreche/image-example.git
Cloning into 'image-example'...
...

$ cd image-example

Let’s generate the Eclipse project files to load the project in the IDE:

$ sbt eclipse
[info] Loading global plugins from /home/sun/.sbt/0.13/plugins
...
[info] Done updating.
[info] Successfully created Eclipse project files for project(s):
[info] image-example

Cool. Now, all you need is the latest Scala IDE for Eclipse to load the project. Please use a version for Scala 2.11, in order to stay compatible with the rest of the project. Now, to load the project:

You should see the project in Eclipse:


Open Test.scala from package image.example, located in src/main/scala, and run it:


On my laptop, I got the following times:

Operation took 4192 milliseconds.
Operation took 4957 milliseconds.
Operation took 4755 milliseconds.
Operation took 3969 milliseconds.
Operation took 4073 milliseconds.

The miniboxing plugin generated a couple of warnings during compilation:


One such warning is:

The class image.example.Pixel would benefit from miniboxing type parameter Repr, since it is 
instantiated by a primitive type.

So let’s go in and fix that. Open Pixel.scala and mark the type parameter Repr of class Pixel by @miniboxed:

abstract class Pixel[@miniboxed 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
  // to allow Image to build an array:
  implicit def manifest = implicitly[Manifest[Repr]]
}


We can fix the other 8 warnings that appear and recompile. Surprisingly, after compiling again, we get an error:

The method map in class ImageImpl overrides method map in class Image therefore needs to 
have the follwing type parameters marked with @miniboxed: type Repr2.


This is because we added the @miniboxed annotation to method map in Image:

abstract class Image[Repr: Pixel] {
  def width: Int
  def height: Int
  def apply(x: Int, y: Int): Repr
  def map[@miniboxed Repr2: Pixel](f: Image[Repr] => Generator[Repr2]): Image[Repr2]
}

but did not add the annotation to method map in ImageImpl, which extends Image:

private class ImageImpl[Repr: Pixel](val width: Int, val height: Int) extends Image[Repr] {
  ...
  def map[Repr2: Pixel](f: Image[Repr] => Generator[Repr2]): Image[Repr2] = {
    ...
  }
}

Let’s fix that:

private class ImageImpl[Repr: Pixel](val width: Int, val height: Int) extends Image[Repr] {
  ...
  def map[@miniboxed Repr2: Pixel](f: Image[Repr] => Generator[Repr2]): Image[Repr2] = {
    ...
  }
}

If we recompile, the error is gone, but we get another batch of 26 warnings:


Let’s try to run the program now, despite the warnings:


So by adding a couple of annotations, we just shaved off one quarter of the running time:

Operation took 3082 milliseconds.
Operation took 2998 milliseconds.
Operation took 3017 milliseconds.
Operation took 2535 milliseconds.
Operation took 2615 milliseconds.

Maybe this miniboxing thing is actually worth it…

Let’s now address all the warnings. But let’s be smart about it:

As explained in the command line options, the -P:minibox:mark-all flag will mark all type parameters with @miniboxed automatically.



Recompile and you should not see any more warnings. Now let’s run again:


Operation took 1346 milliseconds.
Operation took 1187 milliseconds.
Operation took 1178 milliseconds.
Operation took 1094 milliseconds.
Operation took 1163 milliseconds.

Wow, that’s four times faster than our initial running time. That’s what miniboxing can do for numeric-intensive applications!

Comments

Comments are always welcome! But to make the best use of them, please consider this:

Thanks! Looking forward to your messages!


comments powered by Disqus