[
https://issues.apache.org/jira/browse/QPIDJMS-505?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17111121#comment-17111121
]
Mario Schlipf edited comment on QPIDJMS-505 at 5/19/20, 12:08 PM:
------------------------------------------------------------------
The {{com.sun.misc.Unsafe.park}} seems to be called very often, so the CPU time
is spent likely spent on context switching. Digging deeper in the code from the
stacktrace I posted above, we can see how QPID uses this:
{code:java}
at sun.misc.Unsafe.park(Native Method)
at
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)
at
org.apache.qpid.jms.provider.ProgressiveProviderFuture.sync(ProgressiveProviderFuture.java:143)
at org.apache.qpid.jms.JmsConnection.pull(JmsConnection.java:910)
at org.apache.qpid.jms.JmsConnection.pull(JmsConnection.java:899)
at
org.apache.qpid.jms.JmsMessageConsumer.performPullIfRequired(JmsMessageConsumer.java:726)
at
org.apache.qpid.jms.JmsMessageConsumer.dequeue(JmsMessageConsumer.java:304)
at
org.apache.qpid.jms.JmsMessageConsumer.receive(JmsMessageConsumer.java:213)
at {code}
The {{ProgressiveProviderFuture}} that is used for polling, has this piece of
code in the {{sync}} function:
{code:java}
if (idleCount < SPIN_COUNT) {
idleCount++;
} else if (idleCount < YIELD_COUNT) {
Thread.yield();
idleCount++;
} else if (idleCount < TINY_PARK_COUNT) {
LockSupport.parkNanos(tinyParkNanos);
idleCount++;
} else if (idleCount < SMALL_PARK_COUNT) {
LockSupport.parkNanos(smallParkNanos);
idleCount++;
} else {
synchronized (this) {
if (isComplete()) {
failOnError();
return true;
} waiting++;
try {
wait(-diff / 1000000, (int) (-diff % 1000000));
} finally {
waiting--;
}
}
}{code}
Relevant fields:
{code:java}
private static final int SPIN_COUNT = 10;
private static final int YIELD_COUNT = 100;
private static final int TINY_PARK_COUNT = 1000;
private static final int TINY_PARK_NANOS = 1;
private static final int SMALL_PARK_COUNT = 101_000;
private static final int SMALL_PARK_NANOS = 10_000;{code}
So it calls the {{LockSupport.parkNanos}} thousands of times within 10
seconds.Also, the strategy which provider future (apart from progressive, there
is conservative and balanced) is not configurable:
{code:java}
if (futureTypeKey == null || futureTypeKey.isEmpty()) {
if (Runtime.getRuntime().availableProcessors() < 4) {
return new ConservativeProviderFutureFactory();
} else if (isWindows()) {
return new BalancedProviderFutureFactory();
} else {
return new ProgressiveProviderFutureFactory();
}
}
{code}
({{futureTypeKey}} is always \{{null }}it seems)
We are not running on Windows and the available processors are >= 4.
was (Author: marioschlipf):
The {{com.sun.misc.Unsafe.park}} seems to be called very often, so the CPU time
is spent likely spent on context switching. Digging deeper in the code from the
stacktrace I posted above, we can see how QPID uses this:
at sun.misc.Unsafe.park(Native Method)
at
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)
at
org.apache.qpid.jms.provider.ProgressiveProviderFuture.sync(ProgressiveProviderFuture.java:143)
at org.apache.qpid.jms.JmsConnection.pull(JmsConnection.java:910)
at org.apache.qpid.jms.JmsConnection.pull(JmsConnection.java:899)
at
org.apache.qpid.jms.JmsMessageConsumer.performPullIfRequired(JmsMessageConsumer.java:726)
at
org.apache.qpid.jms.JmsMessageConsumer.dequeue(JmsMessageConsumer.java:304)
at
org.apache.qpid.jms.JmsMessageConsumer.receive(JmsMessageConsumer.java:213)
at
The {{ProgressiveProviderFuture}} that is used for polling, has this piece of
code in the {{sync}} function:
if (idleCount < SPIN_COUNT) {
idleCount++;
} else if (idleCount < YIELD_COUNT) {
Thread.yield();
idleCount++;
} else if (idleCount < TINY_PARK_COUNT) {
LockSupport.parkNanos(tinyParkNanos);
idleCount++;
} else if (idleCount < SMALL_PARK_COUNT) {
LockSupport.parkNanos(smallParkNanos);
idleCount++;
} else {
synchronized (this) {
if (isComplete()) {
failOnError();
return true;
} waiting++;
try {
wait(-diff / 1000000, (int) (-diff % 1000000));
} finally {
waiting--;
}
}
}
Relevant fields:
private static final int SPIN_COUNT = 10;
private static final int YIELD_COUNT = 100;
private static final int TINY_PARK_COUNT = 1000;
private static final int TINY_PARK_NANOS = 1;
private static final int SMALL_PARK_COUNT = 101_000;
private static final int SMALL_PARK_NANOS = 10_000;
So it calls the {{LockSupport.parkNanos}} thousands of times within 10
seconds.Also, the strategy which provider future (apart from progressive, there
is conservative and balanced) is not configurable:
if (futureTypeKey == null || futureTypeKey.isEmpty()) {
if (Runtime.getRuntime().availableProcessors() < 4) {
return new ConservativeProviderFutureFactory();
} else if (isWindows()) {
return new BalancedProviderFutureFactory();
} else {
return new ProgressiveProviderFutureFactory();
}
}
({{futureTypeKey}} is always {{null }}it seems)
We are not running on Windows and the available processors are >= 4.
> High CPU usage through ProgressiveProviderFuture
> ------------------------------------------------
>
> Key: QPIDJMS-505
> URL: https://issues.apache.org/jira/browse/QPIDJMS-505
> Project: Qpid JMS
> Issue Type: Bug
> Components: qpid-jms-client
> Affects Versions: 0.51.0
> Reporter: Mario Schlipf
> Priority: Major
>
> We are using QPID JMS in combination with Sping Boot to set up JMS listeners
> on queues.
> We are experiencing high CPU loads from the Spring listener threads, about
> 20% CPU usage per thread. We have done some investigations and using a
> profiler, 92% of that CPU time seems to go into `sun.misc.Unsafe.park`, see
> below stacktrace:
> {code:java}
> at sun.misc.Unsafe.park(Native Method)
> at
> java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:338)
> at
> org.apache.qpid.jms.provider.ProgressiveProviderFuture.sync(ProgressiveProviderFuture.java:143)
> at org.apache.qpid.jms.JmsConnection.pull(JmsConnection.java:910)
> at org.apache.qpid.jms.JmsConnection.pull(JmsConnection.java:899)
> at
> org.apache.qpid.jms.JmsMessageConsumer.performPullIfRequired(JmsMessageConsumer.java:726)
> at
> org.apache.qpid.jms.JmsMessageConsumer.dequeue(JmsMessageConsumer.java:304)
> at
> org.apache.qpid.jms.JmsMessageConsumer.receive(JmsMessageConsumer.java:213)
> at
> org.springframework.jms.support.destination.JmsDestinationAccessor.receiveFromConsumer(JmsDestinationAccessor.java:132)
> at
> org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveMessage(AbstractPollingMessageListenerContainer.java:418)
> at
> org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:303)
> at
> org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257)
> at
> org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1190)
> at
> org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1180)
> at
> org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1077)
> at java.lang.Thread.run(Thread.java:747)
> {code}
> We see the high CPU load also reported using a simple `top` command.
> I would expect that the `Unsafe.park` puts the thread into a waiting state,
> i.e. not consuming further resources.
> We have migrated to ActiveMQ JMS for a test and cannot see the same CPU usage.
>
>
>
--
This message was sent by Atlassian Jira
(v8.3.4#803005)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]