MbArray Tutorial
MbArray
is an indexed sequence container that matches the performance of raw arrays when used in miniboxed contexts. Also, unlike arrays, MbArray creation does not require the presence of a ClassTag, which makes it more versatile. This page will describe the motivation behind MbArray and will show how to use it through examples.
Motivation
Raw arrays offer the best access performance for primitive types, but they can only be instantiated in generic contexts if a ClassTag is present – which is not always possible. Consider typing the following code in the REPL :
Pressing enter will result in the following error :
This could be addressed, at the expense of performance, by letting the scala runtime have access to type informations about T
using a ClassTag
from scala.reflect
:
While this works, it may not be sufficiently fast for algorithms where high performance is expected. Instead, MbArray
combined with the miniboxing transformation offers performances that are similar to those of raw arrays without having to carry around a ClassTag
. The following code will work without requiring any condition on T
. On top of that, any read or write to the array will perform better.
MbArrays are included in the runtime support package for the miniboxing transformation. To see how to add miniboxing to your project, please see this page.
Usage
Let’s take a closer look at how exactly a program can be transformed to take full advantage of the miniboxing transformation and MbArrays. Consider a classic implementation of the merge sort algorithm using a raw Array
with an implicit ClassTag
:
The transformation
Now let’s transform the code above such that it uses miniboxing and MbArrays.
- Let’s first add the line
import MbArray._
. - Then, replace all occurences of the type
Array[T]
byMbArray[T]
, and all the array instantiationsnew Array[T](...)
byMbArray.empty[T](...)
. - Finally, remove the
ClassTag
bound on the type parameterT
.
Compiling at this point will yield the following output :
The miniboxing plugin informs us that code is suboptimal and could get faster if we were to use the @miniboxed
annotation on the type parameter T
. After proceeding and compiling again, we observe that there are no more warnings and our code has been successfully optimized by the miniboxing transformation. The final transformation looks like this :
Benchmarks
We benchmarked the merge sort algorithm implementation above with different sizes of array and ended up with the following numbers (in milliseconds) :
Array Size | Array with ClassTag | MbArray | Improvement |
---|---|---|---|
500’000 | 713 | 528 | 35% |
1’000’000 | 1536 | 1163 | 32% |
3’000’000 | 5311 | 3545 | 50% |
We can observe an average speedup of approximately 40%. Note that the Array with ClassTag version is compiled without the miniboxing plugin. You can try it yourself by downloading the benchmarks here.
Conclusion
- Raw Arrays : Perform well, but cannot be instantiated in generic contexts.
- Raw Arrays with
ClassTag
: Can be instantiated in generic contexts, but introduces performance overhead. - MbArrays with the Miniboxing transformation : Can be instantiated in generic contexts, and will perform well if the generic context is miniboxed.
MbArray is therefore a great choice of the underlying container for any custom collection, as it does not impose additional conditions on the type parameter(s) of the collection, without compromising the performances.
Please keep in mind that the miniboxing plugin is a beta release, and you may encounter occasional hickups as we are working towards a feature-complete and super-stable implementation.
We are doing our best to make miniboxing a stable transformation, with nightly builds and hundreds of test cases running every night. Yet, there are bugs we haven't fixed yet, so don't be surprised if the plugin fails on some programs. But please do file bugs for such failures, so we can fix them asap! (on average, we fixed a bug every 3 days for the last two months!)
The miniboxing release currently supports two specific versions of the Scala compiler:
- 2.11.7, the current release in the 2.11 series and
- 2.10.6, the current release in the 2.10 series
Due to compiler bugs (for the 2.10 series) and binary incompatibility of the compiler API (for the 2.11 series), we do not currently support the other versions. We are planning, however, to fully cross-compile against all 2.10 and 2.11 versions and to provide error messages for the earlier and unsupported versions of the Scala compiler. We're sorry for this, but the engineering effort in supporting even two versions of the compiler is significant!
Comments
Comments are always welcome! But to make the best use of them, please consider this:
- If you have questions or feedback regarding the content of this page, please leave us a comment!
- If you have general questions about the miniboxing plugin, please ask on the mailing List.
- If you found a bug, please let us know on the github issue tracker.
Thanks! Looking forward to your messages!
comments powered by Disqus