Hi Akka Team,
I was recently doing performance optimization for our project which is using Akka Http and was looking into ByteString.compact method for specifically ByteStrings
class:
final class ByteStrings private (private[akka] val bytestrings: Vector[ByteString1], val length: Int)
extends ByteString {
....
def compact: CompactByteString = {
if (isCompact) bytestrings.head.compact
else {
val ar = new Array[Byte](length)
var pos = 0
bytestrings.foreach { b =>
b.copyToArray(ar, pos, b.length)
pos += b.length
}
ByteString1C(ar)
}
}
uses copyToArray
which delegates to IterableOnce
which is coyping byte by byte in the loop.
I`m wondering have you considered using ByteBuffer instead of Array like this:
def compact: CompactByteString = {
if (isCompact) bytestrings.head.compact
else {
val bb = ByteBuffer.alocate(length)
bytestrings.foreach { b =>
bb.put(b.asByteBuffer)
}
ByteString1C(bb.array())
}
}
which would be using ByteBuffer.put()
which is optimised if both ByteBuffers (source and destination) are instance of HeapByteBuffer to use bulk copy?
public ByteBuffer put(ByteBuffer src) {
if (src instanceof HeapByteBuffer) {
if (src == this)
throw createSameBufferException();
HeapByteBuffer sb = (HeapByteBuffer)src;
int n = sb.remaining();
if (n > remaining())
throw new BufferOverflowException();
System.arraycopy(sb.hb, sb.ix(sb.position()),
hb, ix(position()), n);
sb.position(sb.position() + n);
position(position() + n);
} else if (src.isDirect()) {
int n = src.remaining();
if (n > remaining())
throw new BufferOverflowException();
src.get(hb, ix(position()), n);
position(position() + n);
} else {
super.put(src);
}
return this;
}
In Akka HTTP I think it would give a lot of improvements when parsing incoming http message (as those bytestring already backed with HeapByteBuffer) when dealing with TLS and in Framing where ByteString.compact
is used a lot.
Regards,
Kyrylo