Bug #8272
reduce ClassNotFoundException and NoSuchMethodException usage in RuntimeJastInterpreter
0%
Related issues
History
#1 Updated by Constantin Asofiei almost 2 years ago
- Related to Bug #9032: Reduce the number of exceptions that are being thrown added
#2 Updated by Dănuț Filimon over 1 year ago
- Assignee set to Artur Școlnic
Artur, I remember going over this and reducing some of the exceptions thrown in a customer performance scenario. You can check #9032 for the two branches, I used JMC (https://proj.goldencode.com/projects/p2j/wiki/Profiling#JDK-Mission-Control-JMC) to check for all exceptions that are thrown. Check if those changes are relevant for this task and look into when ClassNotFoundException and NoSuchMethodException are being thrown.
#3 Updated by Artur Școlnic over 1 year ago
- Status changed from New to WIP
#4 Updated by Artur Școlnic over 1 year ago
First run:
- baseline: java.lang.NoSuchMethodException 14723
: java.lang.ClassNotFoundException 6903
- 9032a : java.lang.NoSuchMethodException 11833
: java.lang.ClassNotFoundException 5908
- 9032c : java.lang.NoSuchMethodException 14723
: java.lang.ClassNotFoundException 6903
After warmup:
- baseline: java.lang.NoSuchMethodException 52
: java.lang.ClassNotFoundException 471
- 9032a : java.lang.NoSuchMethodException 51
: java.lang.ClassNotFoundException 471
- 9032c : java.lang.NoSuchMethodException 51
: java.lang.ClassNotFoundException 471
9032a brings a slight improvement of 20% less NoSuchMethodException and 14% ClassNotFoundException for the first run of the test.
When it comes to the origins of these exception, this is my analysis:
In callMethod
// attempt to use simple reflection for all super classes
while (itClass != null)
{
try
{
method = itClass.getDeclaredMethod(methodName, parTypes); // the origin of NoSuchMethodException
// if we found the method, exit the while loop
break;
}
catch (NoSuchMethodException e)
{
// do nothing, expected exception if method not defined here
}
itClass = itClass.getSuperclass();
}
Later the method is identified using
RuntimeJastInterpreter.findMatchingMethod.If there won't be a performance hit, I think we could eliminate the reflective find of the method and rely only on the manual one.
In RuntimeJastInterpreter.callCtor:
for (String path : imports)
{
// load class, prepare constructor
String ctorClass = path + ctorNode.getText();
try
{
queryClass = classForName(ctorClass); // // the origin of ClassNotFoundException
break; // found it
}
catch (ClassNotFoundException e)
{
// not the right package this class, try next package
}
}
Looks like we try to instantiate a class by concatenating the class name with each import, this results in a lot of wrong full class names which are responsible for the failed reflections.
I don't see an existing alternative to using reflection for class lookups, maybe we can implement one.
#5 Updated by Artur Școlnic over 1 year ago
Ovidiu, is there a strong reason to use reflections instead of a manual lookup?
#6 Updated by Ovidiu Maxiniuc over 1 year ago
I am not sure what "manual lookup" means?
A you have understood, the problem is that you have:- a set of paths (added by conversion, similar to
importstatements); - a name of a class whose package is unknown, but normally should be one of the paths/packages above.
The solution I quickly implemented is by brute force, I admit. I did not take the time to optimize it, and let the caching (the runtime annotation) to provide a quick lookup on subsequent calls. Taking each of the 'paths' and inspecting whether there is a class there with a specific name (using reflection, as well) does not look like a better/faster approach. You may try implementing this and compare the lookup for 1000 classes to decide the winner.
I welcome any another ideas...
#7 Updated by Artur Școlnic over 1 year ago
Manual lookup is something I saw in the comments, I did not dive too deep.
If the reflection fails, this happens:
if (method == null)
{
// attempt to do it manually (because of null values most likely)
method = findMatchingMethod(aClass, methodName, parTypes, minargs);
}
The java docs states that this method
Looks into the list of methods of a class for the one that matches name and the list of argument types
#8 Updated by Ovidiu Maxiniuc over 1 year ago
If you look at the findMatchingMethod method you'll see that it is a far more CPU intensive routine. It will go up the inheritance tree and try to get a match from all methods based on the (name and) provided signature. Even so, a perfect match is not always available, so a 'compatibility matrix' is used (for example invoking setLong(long) using an int parameter or throwException(Throwable) using an SQLException).
This would actually be a good candidate for performance improvements. Note that the call end up in Function.matchSignatire() and it is used in different other places (for example in TRPL) for method lookup in interpretative execution is required.