[
https://issues.apache.org/jira/browse/KAFKA-4424?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15691817#comment-15691817
]
Michael Andre Pearce (IG) edited comment on KAFKA-4424 at 11/24/16 12:57 AM:
-----------------------------------------------------------------------------
The link you reference re virtual calls.
This is much more about monomorphic call or polymorphic calls. Making a class
that implements an interface final, where the method invocation is by interface
methods, does not change this.
This is more to do with the number of class's loaded/invoked that implement the
interface.
So in case of single implementation being used and loaded your jvm you have a
monomorphic case for the interface, the JVM will inline this (final or not).
If you happen to have two implementations being used and loaded the jvm will
still be able to inline but will create a branch case, the second loaded
implementation will be slower if invoked due to the branch.
If you have more than two implementations loaded the JVM will on loading these
do on stack replacement of the previously loaded inlined, and move to using
virtual tables.
You'll see this occur if you turn on -XX:+PrintCompilation
A classical implementation and write up showing this is:
http://mechanical-sympathy.blogspot.co.uk/2012/04/invoke-interface-optimisations.html
You'll note taking the code, and running it with or without final
implementations makes no difference.
Also i've taken this classical test, for your final and non final cases
(attached to this jira), if you note I've loaded two versions, one with the
final being declared and loaded by the JVM first and vice versa. As you note in
both the implementation loaded first due to the inlined branch will be more
performant.
On checking your original test case we noted that the FinalByteArraySerializer
version runs first (due to alphabetic ordering that test are run in) , as such
it would be always the first in the inline branch benefitting from this, this
would explain why it seems always final was negligible faster when running your
benchmark test case.
was (Author: michael.andre.pearce):
The link you reference re virtual calls.
This is much more about monomorphic call or polymorphic calls. Making a class
that implements an interface final, where the method invocation is by interface
methods, does not change this.
This is more to do with the number of class's loaded that implement the
interface.
So in case of single implementation being used and loaded your jvm you have a
monomorphic case for the interface, the JVM will inline this (final or not).
If you happen to have two implementations being used and loaded the jvm will
still be able to inline but will create a branch case, the second loaded
implementation will be slower if invoked due to the branch.
If you have more than two implementations loaded the JVM will on loading these
do on stack replacement of the previously loaded inlined, and move to using
virtual tables.
You'll see this occur if you turn on -XX:+PrintCompilation
A classical implementation and write up showing this is:
http://mechanical-sympathy.blogspot.co.uk/2012/04/invoke-interface-optimisations.html
You'll note taking the code, and running it with or without final
implementations makes no difference.
Also i've taken this classical test, for your final and non final cases
(attached to this jira), if you note I've loaded two versions, one with the
final being declared and loaded by the JVM first and vice versa. As you note in
both the implementation loaded first due to the inlined branch will be more
performant.
On checking your original test case we noted that the FinalByteArraySerializer
version runs first (due to alphabetic ordering that test are run in) , as such
it would be always the first in the inline branch benefitting from this, this
would explain why it seems always final was negligible faster when running your
benchmark test case.
> Make serializer classes final
> -----------------------------
>
> Key: KAFKA-4424
> URL: https://issues.apache.org/jira/browse/KAFKA-4424
> Project: Kafka
> Issue Type: Improvement
> Components: clients
> Reporter: Matthias Bechtold
> Priority: Minor
> Attachments: FinalTest.java, FinalTestReversed.java
>
>
> Implementations of simple serializers / deserializers should be final to
> prevent JVM method call overhead.
> See also:
> https://wiki.openjdk.java.net/display/HotSpot/VirtualCalls
> This breaks the API slightly, inheritors must change to generic interfaces
> Serializer / Deserializer. But architecture-wise final serialization classes
> make the most sense to me.
> So what do you think?
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)