Slow class loading when running JVM in debug mode

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Slow class loading when running JVM in debug mode

Egor Ushakov
Hi everyone!

we have detected that a process started with the debug agent (even when
debugger is not actually attached) may run significantly slower than
without the agent, see:
https://youtrack.jetbrains.com/issue/JBR-1611
We all thought that without the debugger attached there should not be a
difference.
Is that something well known? Should we file a bug?

Thanks,
Egor

--
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop

Reply | Threaded
Open this post in threaded view
|

Re: Slow class loading when running JVM in debug mode

Volker Simonis
Hi Egor,

yes, I‘d say this is something well known. The reason for this is that a debugging agent will request some JVMTI capabilities like "can_access_local_variables" which can only be requested at JVM startup. However, once these capabilities have been taken, certain kinds of optimizations like for example Escape Analysis, can’t be done anymore which results in a performance degradation even if you don’t ever attach a debugger.

We‘ve always enabled debugging in our commercial SAP JVM and called it „Debugging on Demand“ but usually didn’t observed any performance slowdown of more than 3-5% at most. We’ve started contributing some of the improvements we’ve done to make this possible to the OpenJDK.

I’ve not looked into your concrete class loading use case. Maybe it’s possible to improve that. First you have to check by which JVMTI capability it is triggered and if that capability is really necessary for debugging and can only be requested at startup. If the answer is yes, you can still check if it’s not possible to improve the implementation of that capability in order to get a better runtime behavior.

Regards,
Volker


Egor Ushakov <[hidden email]> schrieb am Do. 20. Juni 2019 um 11:36:
Hi everyone!

we have detected that a process started with the debug agent (even when
debugger is not actually attached) may run significantly slower than
without the agent, see:
https://youtrack.jetbrains.com/issue/JBR-1611
We all thought that without the debugger attached there should not be a
difference.
Is that something well known? Should we file a bug?

Thanks,
Egor

--
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop

Reply | Threaded
Open this post in threaded view
|

Re: Slow class loading when running JVM in debug mode

Chris Plummer
With respect to the specific issue brought up in https://youtrack.jetbrains.com/issue/JBR-1611:

"If we look into the code, we'll see that whenever a new class is loaded and an event about it is delivered, when a garbage collection has occurred, classTrack_processUnloads iterates over all loaded classes to see if any of them have been unloaded. This leads to O(classCount * gcCount) performance, which in case of frequent GCs (and they are frequent, especially the minor ones) is close to O(classCount^2). In IDEA, we have quite a lot of classes, especially counting all lambdas, so this results in quite significant overhead."

The debug agent calls JVMTI GetLoadedClasses() during initialization to get a cache of all prepared classes. It keeps that cache up-to-date by getting JVMTI CLASS_PREPARE events. When there is a gc, the debug agent basically throws away the cache and creates a new one by calling GetLoadedClasses() again. It also compares the old and new caches to determine which classes where unloaded, and generates JDWP CLASS_UNLOAD events for them (if there is a debugger attached that wants them).

It might be possible to defer initialization of the loaded classes cache (and any maintenance of it) until there is a debugger attached. I'm not sure if the only reason for the cache is for delivery of CLASS_UNLOAD events, but at first glance that appears to be the case.

Chris

On 6/20/19 1:31 PM, Volker Simonis wrote:
Hi Egor,

yes, I‘d say this is something well known. The reason for this is that a debugging agent will request some JVMTI capabilities like "can_access_local_variables" which can only be requested at JVM startup. However, once these capabilities have been taken, certain kinds of optimizations like for example Escape Analysis, can’t be done anymore which results in a performance degradation even if you don’t ever attach a debugger.

We‘ve always enabled debugging in our commercial SAP JVM and called it „Debugging on Demand“ but usually didn’t observed any performance slowdown of more than 3-5% at most. We’ve started contributing some of the improvements we’ve done to make this possible to the OpenJDK.

I’ve not looked into your concrete class loading use case. Maybe it’s possible to improve that. First you have to check by which JVMTI capability it is triggered and if that capability is really necessary for debugging and can only be requested at startup. If the answer is yes, you can still check if it’s not possible to improve the implementation of that capability in order to get a better runtime behavior.

Regards,
Volker


Egor Ushakov <[hidden email]> schrieb am Do. 20. Juni 2019 um 11:36:
Hi everyone!

we have detected that a process started with the debug agent (even when
debugger is not actually attached) may run significantly slower than
without the agent, see:
https://youtrack.jetbrains.com/issue/JBR-1611
We all thought that without the debugger attached there should not be a
difference.
Is that something well known? Should we file a bug?

Thanks,
Egor

--
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop


Reply | Threaded
Open this post in threaded view
|

Re: Slow class loading when running JVM in debug mode

Egor Ushakov
Will have a look, thanks for advices!

On 21-Jun-19 00:42, Chris Plummer wrote:
With respect to the specific issue brought up in https://youtrack.jetbrains.com/issue/JBR-1611:

"If we look into the code, we'll see that whenever a new class is loaded and an event about it is delivered, when a garbage collection has occurred, classTrack_processUnloads iterates over all loaded classes to see if any of them have been unloaded. This leads to O(classCount * gcCount) performance, which in case of frequent GCs (and they are frequent, especially the minor ones) is close to O(classCount^2). In IDEA, we have quite a lot of classes, especially counting all lambdas, so this results in quite significant overhead."

The debug agent calls JVMTI GetLoadedClasses() during initialization to get a cache of all prepared classes. It keeps that cache up-to-date by getting JVMTI CLASS_PREPARE events. When there is a gc, the debug agent basically throws away the cache and creates a new one by calling GetLoadedClasses() again. It also compares the old and new caches to determine which classes where unloaded, and generates JDWP CLASS_UNLOAD events for them (if there is a debugger attached that wants them).

It might be possible to defer initialization of the loaded classes cache (and any maintenance of it) until there is a debugger attached. I'm not sure if the only reason for the cache is for delivery of CLASS_UNLOAD events, but at first glance that appears to be the case.

Chris

On 6/20/19 1:31 PM, Volker Simonis wrote:
Hi Egor,

yes, I‘d say this is something well known. The reason for this is that a debugging agent will request some JVMTI capabilities like "can_access_local_variables" which can only be requested at JVM startup. However, once these capabilities have been taken, certain kinds of optimizations like for example Escape Analysis, can’t be done anymore which results in a performance degradation even if you don’t ever attach a debugger.

We‘ve always enabled debugging in our commercial SAP JVM and called it „Debugging on Demand“ but usually didn’t observed any performance slowdown of more than 3-5% at most. We’ve started contributing some of the improvements we’ve done to make this possible to the OpenJDK.

I’ve not looked into your concrete class loading use case. Maybe it’s possible to improve that. First you have to check by which JVMTI capability it is triggered and if that capability is really necessary for debugging and can only be requested at startup. If the answer is yes, you can still check if it’s not possible to improve the implementation of that capability in order to get a better runtime behavior.

Regards,
Volker


Egor Ushakov <[hidden email]> schrieb am Do. 20. Juni 2019 um 11:36:
Hi everyone!

we have detected that a process started with the debug agent (even when
debugger is not actually attached) may run significantly slower than
without the agent, see:
https://youtrack.jetbrains.com/issue/JBR-1611
We all thought that without the debugger attached there should not be a
difference.
Is that something well known? Should we file a bug?

Thanks,
Egor

--
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop



-- 
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop
Reply | Threaded
Open this post in threaded view
|

Re: Slow class loading when running JVM in debug mode

Chris Plummer
You might also want to have a look at:

JDK:8214892: Delayed starting of debugging via jcmd

This should allow you to defer initialization of the debug agent (and the creation of the loaded classes cache) until you turn on debugging using the jcmd (and the presumably follow that with an attach from a debugger).

Note there is also an after-the-fact CSR in progress for this which might result in an eventual name change for debug agent option and jcmd command.

Chris


On 6/21/19 3:06 AM, Egor Ushakov wrote:
Will have a look, thanks for advices!

On 21-Jun-19 00:42, Chris Plummer wrote:
With respect to the specific issue brought up in https://youtrack.jetbrains.com/issue/JBR-1611:

"If we look into the code, we'll see that whenever a new class is loaded and an event about it is delivered, when a garbage collection has occurred, classTrack_processUnloads iterates over all loaded classes to see if any of them have been unloaded. This leads to O(classCount * gcCount) performance, which in case of frequent GCs (and they are frequent, especially the minor ones) is close to O(classCount^2). In IDEA, we have quite a lot of classes, especially counting all lambdas, so this results in quite significant overhead."

The debug agent calls JVMTI GetLoadedClasses() during initialization to get a cache of all prepared classes. It keeps that cache up-to-date by getting JVMTI CLASS_PREPARE events. When there is a gc, the debug agent basically throws away the cache and creates a new one by calling GetLoadedClasses() again. It also compares the old and new caches to determine which classes where unloaded, and generates JDWP CLASS_UNLOAD events for them (if there is a debugger attached that wants them).

It might be possible to defer initialization of the loaded classes cache (and any maintenance of it) until there is a debugger attached. I'm not sure if the only reason for the cache is for delivery of CLASS_UNLOAD events, but at first glance that appears to be the case.

Chris

On 6/20/19 1:31 PM, Volker Simonis wrote:
Hi Egor,

yes, I‘d say this is something well known. The reason for this is that a debugging agent will request some JVMTI capabilities like "can_access_local_variables" which can only be requested at JVM startup. However, once these capabilities have been taken, certain kinds of optimizations like for example Escape Analysis, can’t be done anymore which results in a performance degradation even if you don’t ever attach a debugger.

We‘ve always enabled debugging in our commercial SAP JVM and called it „Debugging on Demand“ but usually didn’t observed any performance slowdown of more than 3-5% at most. We’ve started contributing some of the improvements we’ve done to make this possible to the OpenJDK.

I’ve not looked into your concrete class loading use case. Maybe it’s possible to improve that. First you have to check by which JVMTI capability it is triggered and if that capability is really necessary for debugging and can only be requested at startup. If the answer is yes, you can still check if it’s not possible to improve the implementation of that capability in order to get a better runtime behavior.

Regards,
Volker


Egor Ushakov <[hidden email]> schrieb am Do. 20. Juni 2019 um 11:36:
Hi everyone!

we have detected that a process started with the debug agent (even when
debugger is not actually attached) may run significantly slower than
without the agent, see:
https://youtrack.jetbrains.com/issue/JBR-1611
We all thought that without the debugger attached there should not be a
difference.
Is that something well known? Should we file a bug?

Thanks,
Egor

--
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop



-- 
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop


Reply | Threaded
Open this post in threaded view
|

Re: Slow class loading when running JVM in debug mode

Egor Ushakov
I filed https://bugs.openjdk.java.net/browse/JDK-8227269.
Not sure that we could fix that ourselves.

Egor

On 21-Jun-19 21:50, Chris Plummer wrote:
You might also want to have a look at:

JDK:8214892: Delayed starting of debugging via jcmd

This should allow you to defer initialization of the debug agent (and the creation of the loaded classes cache) until you turn on debugging using the jcmd (and the presumably follow that with an attach from a debugger).

Note there is also an after-the-fact CSR in progress for this which might result in an eventual name change for debug agent option and jcmd command.

Chris


On 6/21/19 3:06 AM, Egor Ushakov wrote:
Will have a look, thanks for advices!

On 21-Jun-19 00:42, Chris Plummer wrote:
With respect to the specific issue brought up in https://youtrack.jetbrains.com/issue/JBR-1611:

"If we look into the code, we'll see that whenever a new class is loaded and an event about it is delivered, when a garbage collection has occurred, classTrack_processUnloads iterates over all loaded classes to see if any of them have been unloaded. This leads to O(classCount * gcCount) performance, which in case of frequent GCs (and they are frequent, especially the minor ones) is close to O(classCount^2). In IDEA, we have quite a lot of classes, especially counting all lambdas, so this results in quite significant overhead."

The debug agent calls JVMTI GetLoadedClasses() during initialization to get a cache of all prepared classes. It keeps that cache up-to-date by getting JVMTI CLASS_PREPARE events. When there is a gc, the debug agent basically throws away the cache and creates a new one by calling GetLoadedClasses() again. It also compares the old and new caches to determine which classes where unloaded, and generates JDWP CLASS_UNLOAD events for them (if there is a debugger attached that wants them).

It might be possible to defer initialization of the loaded classes cache (and any maintenance of it) until there is a debugger attached. I'm not sure if the only reason for the cache is for delivery of CLASS_UNLOAD events, but at first glance that appears to be the case.

Chris

On 6/20/19 1:31 PM, Volker Simonis wrote:
Hi Egor,

yes, I‘d say this is something well known. The reason for this is that a debugging agent will request some JVMTI capabilities like "can_access_local_variables" which can only be requested at JVM startup. However, once these capabilities have been taken, certain kinds of optimizations like for example Escape Analysis, can’t be done anymore which results in a performance degradation even if you don’t ever attach a debugger.

We‘ve always enabled debugging in our commercial SAP JVM and called it „Debugging on Demand“ but usually didn’t observed any performance slowdown of more than 3-5% at most. We’ve started contributing some of the improvements we’ve done to make this possible to the OpenJDK.

I’ve not looked into your concrete class loading use case. Maybe it’s possible to improve that. First you have to check by which JVMTI capability it is triggered and if that capability is really necessary for debugging and can only be requested at startup. If the answer is yes, you can still check if it’s not possible to improve the implementation of that capability in order to get a better runtime behavior.

Regards,
Volker


Egor Ushakov <[hidden email]> schrieb am Do. 20. Juni 2019 um 11:36:
Hi everyone!

we have detected that a process started with the debug agent (even when
debugger is not actually attached) may run significantly slower than
without the agent, see:
https://youtrack.jetbrains.com/issue/JBR-1611
We all thought that without the debugger attached there should not be a
difference.
Is that something well known? Should we file a bug?

Thanks,
Egor

--
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop



-- 
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop



-- 
Egor Ushakov
Software Developer
JetBrains
http://www.jetbrains.com
The Drive to Develop