[MDSAL-388] Cache successful augmentation substitutions Created: 13/Nov/18  Updated: 26/Feb/20  Resolved: 19/Nov/18

Status: Resolved
Project: mdsal
Component/s: None
Affects Version/s: None
Fix Version/s: Fluorine SR2, Oxygen SR4, 3.0.2

Type: Improvement Priority: Medium
Reporter: Michael Vorburger Assignee: Robert Varga
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
is duplicated by MDSAL-59 Binding Data Codec: Equivalent augmen... Resolved
Relates
relates to OPNFLWPLUG-1050 Make Grouping{Loose}Resolver immutatable Resolved

 Description   

One of the very top "TLAB allocation" (cumulative nearing 100 GiB - that's a hell of a lot, no?) observed in a JFR from internal scale testing based on Oxygen SR3 code, which seems to contributed to excessive GC, is the code path below.

I'm seeing this with slight variations, curiously always from openflowplugin (is it doing anything obviously wrong here, which could be improved?). Just wondering if there is any way that this could be optimized to cause less object allocation? Could that reflection stuff it seems to be doing here perhaps be cached?

void java.lang.Class$MethodArray.<init>(int)	34969
Method java.lang.Class.getMethod0(String, Class[], boolean)	34969
Method java.lang.Class.privateGetMethodRecursive(String, Class[], boolean, Class$MethodArray)	34237
Method java.lang.Class.getMethod0(String, Class[], boolean)	34237
Method java.lang.Class.privateGetMethodRecursive(String, Class[], boolean, Class$MethodArray)	31798
Method java.lang.Class.getMethod0(String, Class[], boolean)	31798
Method java.lang.Class.privateGetMethodRecursive(String, Class[], boolean, Class$MethodArray)	20695
Method java.lang.Class.getMethod0(String, Class[], boolean)	20695
Method java.lang.Class.getMethod(String, Class[])	11300
boolean org.opendaylight.yangtools.yang.binding.util.BindingReflections.isSubstitutionFor(Class, Class)	11300
DataContainerCodecPrototype org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectCodecContext.augmentationByClassOrEquivalentClass(Class)	11300
DataContainerCodecPrototype org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectCodecContext.augmentationByClass(Class)	11300
DataContainerCodecPrototype org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectCodecContext.streamChildPrototype(Class)	11300
Optional org.opendaylight.mdsal.binding.dom.codec.impl.DataObjectCodecContext.possibleStreamChild(Class)	11300
Object org.opendaylight.mdsal.binding.dom.codec.impl.LazyDataObject.getAugmentationImpl(Class)	11300
Object org.opendaylight.mdsal.binding.dom.codec.impl.LazyDataObject.invoke(Object, Method, Object[])	11300
Augmentation com.sun.proxy.$Proxy503.getAugmentation(Class)	11071
Optional org.opendaylight.openflowplugin.extension.api.GroupingResolver.getExtension(Augmentable)	11071
MatchEntry org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.RegConvertor.convert(Extension)	11071
DataContainer org.opendaylight.openflowplugin.extension.vendor.nicira.convertor.match.RegConvertor.convert(Extension)	11071
MatchEntry org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.lambda$null$4(ExtensionList, ByteBuf, ConvertorToOFJava)	11071
Object org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer$$Lambda$2185.946006913.apply(Object)	11071
Optional java.util.Optional.map(Function)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.lambda$serializeExtensionList$6(ByteBuf, ExtensionList)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer$$Lambda$2182.730382268.accept(Object)	11071
void java.util.ArrayList.forEach(Consumer)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.serializeExtensionList(List, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.lambda$serializeHeader$2(ByteBuf, List)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer$$Lambda$2069.1596170542.accept(Object)	11071
void java.util.Optional.ifPresent(Consumer)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.serializeHeader(Match, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.serialize(Match, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.match.MatchSerializer.serialize(DataContainer, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.messages.FlowMessageSerializer.writeMatch(FlowMessage, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.messages.FlowMessageSerializer.writeFlow(FlowMessage, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.messages.FlowMessageSerializer.serialize(FlowMessage, ByteBuf)	11071
void org.opendaylight.openflowplugin.impl.protocol.serialization.messages.FlowMessageSerializer.serialize(DataContainer, ByteBuf)	11071
void org.opendaylight.openflowjava.protocol.impl.serialization.SerializationFactory.messageToBuffer(short, ByteBuf, DataObject)	11071
void org.opendaylight.openflowjava.protocol.impl.core.OFEncoder.encode(ChannelHandlerContext, MessageListenerWrapper, ByteBuf)	11071
void org.opendaylight.openflowjava.protocol.impl.core.OFEncoder.encode(ChannelHandlerContext, Object, ByteBuf)	11071
void io.netty.handler.codec.MessageToByteEncoder.write(ChannelHandlerContext, Object, ChannelPromise)	11071
void io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(Object, ChannelPromise)	11071
void io.netty.channel.AbstractChannelHandlerContext.invokeWrite(Object, ChannelPromise)	11071
void io.netty.channel.AbstractChannelHandlerContext.write(Object, boolean, ChannelPromise)	11071
ChannelFuture io.netty.channel.AbstractChannelHandlerContext.write(Object, ChannelPromise)	11071
ChannelFuture io.netty.channel.AbstractChannelHandlerContext.write(Object)	11071
ChannelFuture io.netty.channel.DefaultChannelPipeline.write(Object)	11071
ChannelFuture io.netty.channel.AbstractChannel.write(Object)	11071
void org.opendaylight.openflowjava.protocol.impl.core.connection.AbstractOutboundQueueManager.writeMessage(OfHeader, long)	11071
void org.opendaylight.openflowjava.protocol.impl.core.connection.OutboundQueueManager.writeMessage(OfHeader, long)	11071
int org.opendaylight.openflowjava.protocol.impl.core.connection.AbstractStackedOutboundQueue.writeEntries(Channel, long)	11071
void org.opendaylight.openflowjava.protocol.impl.core.connection.AbstractOutboundQueueManager.writeAndFlush()	11071
void org.opendaylight.openflowjava.protocol.impl.core.connection.AbstractOutboundQueueManager.flush()	10043
void org.opendaylight.openflowjava.protocol.impl.core.connection.AbstractOutboundQueueManager.lambda$new$0()	10043
void org.opendaylight.openflowjava.protocol.impl.core.connection.AbstractOutboundQueueManager$$Lambda$1465.2105557852.run()	10043
void io.netty.util.concurrent.AbstractEventExecutor.safeExecute(Runnable)	10043
boolean io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasksFrom(Queue)	10043
boolean io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks()	10043
void io.netty.channel.nio.NioEventLoop.run()	10043
void io.netty.util.concurrent.SingleThreadEventExecutor$5.run()	10043
void io.netty.util.concurrent.FastThreadLocalRunnable.run()	10043
void java.lang.Thread.run()	10043


 Comments   
Comment by Robert Varga [ 13/Nov/18 ]

GroupingResolver is doing something funky, I am not quite sure what and why – that is leading DataObjectCodecContext off of the fast path.

Comment by Michael Vorburger [ 16/Nov/18 ]

Reminder: Need to double check how OPNFLWPLUG-1050 related to this ...

Comment by Robert Varga [ 16/Nov/18 ]

Aside from me looking at GroupingResolver and screaming in anguish over public mutable collections.

 

vorburger if you are looking to improve things further, I would suggest looking at the reported stack trace and cleaning up OFP's use of capturing lambdas (like MatchSerializer.serializeHeader()'s use of Map.forEach()) and this wonderful pattern:

 

Foo nullableFoo;
// I can haz two new objucts? coz is l33ter than 'if (nullableFoo != null)'!
Optional.ofNullable(nullableFoo).ifPresent(nonnullFoo -> {
    // Moar codez goes here...
})

 

Comment by Michael Vorburger [ 16/Nov/18 ]

OMG

Generated at Wed Feb 07 20:09:41 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.