Am 03.02.2017 08:21, schrieb Felix Schumacher:
Am 2. Februar 2017 21:44:43 MEZ schrieb Vladimir Sitnikov
<sitnikov.vladi...@gmail.com>:
Can you clarify your question if it's a real one.
Well, that's a real question.
It is a long time since I launched a load test, and I can't remember
if
faced "UI stuck" error ever.
I would admit I've never used non-GUI mode, and GUI was just fine for
me
(of course I had to disable things like "view results").
Philippe>Did you see the last thread "High CPU utilization in
JMeter 3.x with HttpClient 4 leads to freeze" ?
I think I missed that.
A quick glance (e.g.
https://drive.google.com/drive/folders/0B1uBdVuLED5NejZaanZ2UHNlblk )
shows
that we have a logging problem.
That is org.apache.jmeter.gui.LoggerPanel.processEvent might fill UI
event
queue, thus rendering UI unresponsive.
We might want to have some throttling there, or circular buffering, or
lazy-loading (e.g. logging to a file and refreshing it to the UI from
time
to time).
In any way, the number of threads itself has nothing to do with UI
responsiveness provided there is enough Xmx (remember we did discuss
"please specify new Xmx value and click restart" dialog?) and there is
enough CPU power (in case of CPU starvation the load test makes no
sense at
all).
Philippe>blocks Load test mode
You are right. It is much better to have application level error that
explains what goes wrong rather than fail with some obscure error at
runtime.
However I would like to explore if we can have a way out without
stopping
the show.
When captain opens the thread dump above, he would find some obvious
things:
1) Logging fills the UI queue. The simplest workaround would be to
disable
log panel updates after N messages.
2) Statistics posts UI events as well (SummaryReport.add). Can we have
some
debounce there, so the UI gets refreshed once a second at most?
Well, the above do not look like a quick win, however I think those
can
be
fixed without complicating the codebase too much.
Does it make sense to spawn a couple of new mail threads regarding
those
issues?
I think those are valid things to try out.
I tried it out and the resuls are promising.
Usage (%) in AWT Dispatcher
old code: 88
new (100ms): 44
new (500ms): 14
Usage (%) in Thread (mostly the JSR223-Sampler)
old code: 11
new (100ms): 55
new (500ms): 84
The test case I used was one Thread Group with 100 Threads and a single
JSR223-Sampler with "log.info("Blubb");"
Memory Usage (speak GC) went down to.
Felix
Felix
Vladimir
diff --git a/extras/proxycert.sh b/extras/proxycert.sh
old mode 100644
new mode 100755
diff --git a/src/core/org/apache/jmeter/gui/LoggerPanel.java
b/src/core/org/apache/jmeter/gui/LoggerPanel.java
index 2bf84da..a80b9dc 100644
--- a/src/core/org/apache/jmeter/gui/LoggerPanel.java
+++ b/src/core/org/apache/jmeter/gui/LoggerPanel.java
@@ -20,13 +20,16 @@ package org.apache.jmeter.gui;
import java.awt.BorderLayout;
import java.awt.Insets;
+import java.util.Iterator;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
+import javax.swing.Timer;
+import org.apache.commons.collections.buffer.BoundedFifoBuffer;
import org.apache.jmeter.gui.util.JSyntaxTextArea;
import org.apache.jmeter.gui.util.JTextScrollPane;
import org.apache.jmeter.util.JMeterUtils;
@@ -45,12 +48,19 @@ public class LoggerPanel extends JPanel implements
LogTarget {
private final JTextArea textArea;
+ private final BoundedFifoBuffer events =
+ new
BoundedFifoBuffer(JMeterUtils.getPropDefault("jmeter.loggerpanel.maxlength",
1000)); // $NON-NLS-1$
+
+ private Timer timer;
+
+ private volatile boolean logChanged = false;
+
private final PatternFormatter format;
// Limit length of log content
private static final int LOGGER_PANEL_MAX_LENGTH =
JMeterUtils.getPropDefault("jmeter.loggerpanel.maxlength", 80000);
// $NON-NLS-1$
-
+
// Make panel handle event even if closed
private static final boolean LOGGER_PANEL_RECEIVE_WHEN_CLOSED =
JMeterUtils.getPropDefault("jmeter.loggerpanel.enable_when_closed", true); //
$NON-NLS-1$
@@ -89,6 +99,9 @@ public class LoggerPanel extends JPanel implements LogTarget {
areaScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
areaScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
this.add(areaScrollPane, BorderLayout.CENTER);
+
+ initWorker();
+
return jTextArea;
}
@@ -100,22 +113,40 @@ public class LoggerPanel extends JPanel implements
LogTarget {
if(!LOGGER_PANEL_RECEIVE_WHEN_CLOSED &&
!GuiPackage.getInstance().getMenuItemLoggerPanel().getModel().isSelected()) {
return;
}
-
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- synchronized (textArea) {
- textArea.append(format.format(logEvent));
- int currentLength = textArea.getText().length();
- // If LOGGER_PANEL_MAX_LENGTH is 0, it means all log
events are kept
- if(LOGGER_PANEL_MAX_LENGTH != 0 && currentLength>
LOGGER_PANEL_MAX_LENGTH) {
-
textArea.setText(textArea.getText().substring(Math.max(0,
currentLength-LOGGER_PANEL_MAX_LENGTH),
- currentLength));
+
+ synchronized (events) {
+ if (events.isFull()) {
+ events.remove();
+ }
+ events.add(format.format(logEvent));
+ }
+
+ logChanged = true;
+ }
+
+ private void initWorker() {
+ timer = new Timer(
+ 100,
+ e -> {
+ if (logChanged) {
+ logChanged = false;
+ StringBuilder builder = new StringBuilder();
+ synchronized (events) {
+ Iterator<String> lines = events.iterator();
+ while (lines.hasNext()) {
+ builder.append(lines.next());
+ }
+ }
+ String logText = builder.toString();
+ synchronized (textArea) {
+ textArea.setText(logText);
+ int currentLength = logText.length();
+ textArea.setCaretPosition(logText.length());
}
- textArea.setCaretPosition(textArea.getText().length());
}
}
- });
+ );
+ timer.start();
}
/**
@@ -123,5 +154,7 @@ public class LoggerPanel extends JPanel implements
LogTarget {
*/
public void clear() {
this.textArea.setText(""); // $NON-NLS-1$
+ events.clear();
+ timer.stop();
}
}