Created
December 7, 2018 15:30
-
-
Save lrytz/900dcc6aba5479ae615098bb0d74b1ee to your computer and use it in GitHub Desktop.
Ensure stepper / stream / accumulator / array conversions don't box
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.google.monitoring.runtime.instrumentation.AllocationRecorder | |
import com.google.monitoring.runtime.instrumentation.Sampler | |
import scala.collection.convert._ | |
import scala.collection.JavaConverters._ | |
// download java-allocation-instrumenter-3.2.0.jar from here: | |
// http://repo1.maven.org/maven2/com/google/code/java-allocation-instrumenter/java-allocation-instrumenter/3.2.0/ | |
// compile and run with | |
// build/quick/bin/scalac -cp java-allocation-instrumenter-3.2.0.jar Test.scala | |
// build/quick/bin/scala -J-javaagent:java-allocation-instrumenter-3.2.0.jar -cp .:java-allocation-instrumenter-3.2.0.jar Test | |
object IntegerSampler extends Sampler { | |
val exclude = List( | |
"com.google.monitoring" | |
) | |
def trace: String = (new Exception).getStackTrace.drop(3).take(15).map(e => " " + e.toString).mkString("\n") | |
def sampleAllocation(count: Int, desc: String, newObj: Object, size: Long): Unit = { | |
if (newObj.isInstanceOf[java.lang.Integer]) { | |
val t = trace | |
if (!exclude.exists(trace.contains)) { | |
println(s"$desc : $newObj") | |
println(t) | |
} | |
} | |
} | |
} | |
object Test { | |
def show(i: Int) = { | |
AllocationRecorder.removeSampler(IntegerSampler) | |
println(i) | |
AllocationRecorder.addSampler(IntegerSampler) | |
} | |
def show(a: AnyRef) = { | |
AllocationRecorder.removeSampler(IntegerSampler) | |
println(a) | |
AllocationRecorder.addSampler(IntegerSampler) | |
} | |
def main(args: Array[String]): Unit = { | |
val ia = Array(10001,10002,10003) // small Integers are cached | |
val ba = ia.map(_.toShort) | |
val bset = collection.immutable.BitSet(10001,10002,10003) | |
val iasq = collection.immutable.ArraySeq.unsafeWrapArray(Array(10001,10002,10003)) | |
AllocationRecorder.addSampler(IntegerSampler) | |
println("start testing") | |
val iast = ia.stepper | |
var i = 0 | |
while (iast.hasStep) if (i == 0) i += iast.nextStep() else i += iast.nextInt() | |
show(i) | |
i = 0 | |
val bast = ba.stepper | |
while (bast.hasStep) if (i == 0) i += bast.nextStep() else i += bast.nextInt() | |
show(i) | |
show(ia.seqStream.sum()) // result is boxed and unboxed, that's ok | |
show(ia.parStream.toScala(Accumulator)) | |
show(ba.stepper.seqStream.toScala(IntAccumulator)) | |
// show(ba.stepper.parStream.toScala(Array)) // boxes and unboxes, but that's also for BitSet(1).to(Array) | |
show(ba.stepper.parStream.toArray) | |
show(ia.seqStream.toScala(Accumulator).toArray) | |
show(ia.seqStream.spliterator.stepper.to(Accumulator)) | |
// boxes and unboxes. could add a special case in IntAccumulator.fromSpecific, but there's no | |
// simple way to iterate over all Ints of a BitSet without boxing them. | |
// show(bset.to(IntAccumulator).seqStream.toArray) | |
show(ia.to(Accumulator).toArray: Array[Int]) | |
// TODO | |
// boxes because the IntIndexedSeqStepper calls underlying.apply, which boxes | |
// will be solved by having specific steppers for ArraySeq (which can use the array steppers) | |
// show(iasq.stepper.seqStream.spliterator.stepper.to(Accumulator)) | |
// also boxes, same reason as above | |
// show(iasq.seqStream.toScala(Accumulator)) | |
show(iasq.to(Accumulator)) | |
// boxes: stepper.to has special cases for primitive accumulators, but not for other target | |
// collections. so it goes to ArraySeq.from | |
// show(ia.stepper.to(collection.immutable.ArraySeq)) | |
// similar to above, the toScala extension method has special cases for accumulators to avoid | |
// boxing, but not for other target collections. | |
// show(ia.seqStream.toScala(collection.immutable.ArraySeq)) | |
// IntAccumulator.to calls ArraySeq.fromw, which boxes. maybe could add special cases to | |
// IntAccumulator.to, currently there aren't any. but that method doesn't take an | |
// `AccumulatorFactoryInfo` implicit that would allow knowing the factory. the method is an | |
// override, so adding a parameter would make an overload, not sure if it would be picked. | |
// show(ia.to(Accumulator).to(collection.immutable.ArraySeq)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment