0

Unfortunately calling redefine / retransform on a big number of classes is kind of slow and can easily take multiple minutes. There was even a bug raised some time ago which was closed as "won't fix": JDK-6173565 : RedefineClasses must be fast even when hundreds or thousands of classes are redefined (Note: I know it's an old bug, but even using JDK8 it is sill very slow; ~2min for ~4500 classes)

I'm having a use case where I ideally need to be able to switch quickly between the original version of some classes and the instrumented ones.

One "solution" I was thinking of is to simply weave an if-else statement to the methods and pretty much duplicate the method body; with the if block containing the original version and the else the modified version. But that would impact every method of the application code, so I expect some overhead even for always running through the ifs. Not sure yet how the jit will be able to optimize that. According to quick JMH test the overhead of calling a simple getter method with an "if" inside is roughly 4-5%. Of course in a real application that should be a little less as there are more instructions to be executed than in my stupid test case, but nevertheless not sure if that is a good way to approach the problem.

Any other idea how I could prevent having to wait multiple minutes when the fuctionality is enabled and disabled?

Haasip Satang
  • 457
  • 3
  • 17
  • the bug seems to be "won't fix" only for one version of JVM, and has been taken up to higher version. Also, that was more than 10 years ago, and all related bugs appear to have been fixed. You may be facing a different problem than what you've linked. – M. Prokhorov Dec 20 '17 at 15:27
  • What about a custom class loader? When the switch is flipped all target classes are dumped. The next class reference loads the relevant version of the class. [This](https://stackoverflow.com/questions/20091075/reload-used-classes-at-runtime-java) looked interesting. – Andrew S Dec 20 '17 at 15:34
  • @M.Prokhorov Yes, the but report is old. But based on my latest version of JDK8 it is still taking about ~2min for ~4500 classes. – Haasip Satang Dec 20 '17 at 16:36
  • @AndrewS Thanks, but I don't see how a custom classloader would help. This would only work for newly created objects and not for already existing ones, wouldn't it? Unless you come up with some fancy JRebel like classloading tricks, not sure about the performance impact of such an approach though. – Haasip Satang Dec 20 '17 at 16:43
  • What’s the problem with 4-5% overhead that is expected to be even less in a real application? – Holger Dec 20 '17 at 17:56
  • @Holger well... if I would retransform the classes the overhead would obviously be 0% as long as the feature is not enabled (at the cost of the long running retransformation). Therefore I'm trying to see if there is a solution to improve that. So let me counter you question with: "What's the problem with trying to see if things can be improved / made even better"? Also I honestly do not know how the jit would behave for methods that would pass the threshold as the number for byte code instructions more than double. Would you expect any impact by that? – Haasip Satang Dec 20 '17 at 18:01
  • Retransforming classes does not come for free. Changing the code obviously implies dropping any optimized generated native code and start at square one with interpreted execution again. Depending on how long it takes until reaching the maximum optimized state and when the next retransformation will happen, the net overhead might be on par with the overhead of the conditional. On the other hand, the speed of the conditional may also depend on the JVM’s prediction of the condition, so changing the flag might cause deoptimization as well. It’s not an easy math. Why not try and measure… – Holger Dec 20 '17 at 18:08
  • Yes, agree. Will need to measure for sure, no doubt about that. Might even offer two types of transformers in the end to have it configurable; one that does it upfront by using a condition and another that would retransform. So that the user can decide which hit he wants to take. But coming back to the theoretical part of my question: Do you see any way to do redefinitions faster (really anything, no matter how "hacky") Or only via patching the JDK (like dcevm for example does some enhancements)? – Haasip Satang Dec 20 '17 at 18:19
  • 1
    I see an alternative, not claiming to be faster. You could try to use `invokedynamic` being linked to a `MutableCallSite` instead of the conditional. The advantage is that this clearly bears the “now it’s unconditionally linked to A” and “now I’m switching to unconditionally using B” semantic, without needing redefiniton when switching. However, that’s the theory. I have no idea how it compares *practically* with the other alternatives. – Holger Dec 20 '17 at 18:27
  • @HaasipSatang I just wonder of the correctness of the test here... since it is an if/else you could have easily hit a branch prediction and always go a "happy path" – Eugene Dec 20 '17 at 19:43
  • @Holger Now that's the sort of idea I was looking for :) Thanks! I'm not that familar with the details of invokedynamic yet I have to admit. Only read Rafael's post [Dismantling invokedynamic](http://mydailyjava.blogspot.se/2015/03/dismantling-invokedynamic.html) but haven't experimented a lot with it yet. While I expect it to be slower I'll give it a try though. The use case is actually that I need method entry and exit events. Since the JVMTI ones are to slow I will need to weave in code before and after `invoke` instructions. – Haasip Satang Dec 20 '17 at 23:33
  • @Eugene Yep, was also thinking about that. But unfortunately here I'm also missing the necessary background in oder to be able to judge that. What would be you take for coming up with the most correct test? I guess it's kinda hard as in a static test scenario so many things can easily be optimized. – Haasip Satang Dec 20 '17 at 23:39

0 Answers0