You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by fs...@apache.org on 2017/02/18 14:31:45 UTC
svn commit: r1783558 -
/jmeter/trunk/src/components/org/apache/jmeter/visualizers/StatVisualizer.java
Author: fschumacher
Date: Sat Feb 18 14:31:45 2017
New Revision: 1783558
URL: http://svn.apache.org/viewvc?rev=1783558&view=rev
Log:
Make GUI more responsive when it gets a lot of events.
Convert Aggregate Report to use a queue, when new rows are to be inserted.
Update the model (or at least notify the gui) only periodically.
That way we get the update of the model out of the busy path of the swing
event loop.
Bugzilla Id: 60687
Modified:
jmeter/trunk/src/components/org/apache/jmeter/visualizers/StatVisualizer.java
Modified: jmeter/trunk/src/components/org/apache/jmeter/visualizers/StatVisualizer.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/components/org/apache/jmeter/visualizers/StatVisualizer.java?rev=1783558&r1=1783557&r2=1783558&view=diff
==============================================================================
--- jmeter/trunk/src/components/org/apache/jmeter/visualizers/StatVisualizer.java (original)
+++ jmeter/trunk/src/components/org/apache/jmeter/visualizers/StatVisualizer.java Sat Feb 18 14:31:45 2017
@@ -26,8 +26,10 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
+import java.util.Deque;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedDeque;
import javax.swing.BoxLayout;
import javax.swing.JButton;
@@ -36,6 +38,7 @@ import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
+import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
@@ -92,6 +95,8 @@ public class StatVisualizer extends Abst
private final Map<String, SamplingStatCalculator> tableRows = new ConcurrentHashMap<>();
+ private Deque<SamplingStatCalculator> newRows = new ConcurrentLinkedDeque<>();
+
public StatVisualizer() {
super();
model = StatGraphVisualizer.createObjectTableModel();
@@ -116,32 +121,21 @@ public class StatVisualizer extends Abst
@Override
public void add(final SampleResult res) {
- JMeterUtils.runSafe(false, new Runnable() {
- @Override
- public void run() {
- SamplingStatCalculator row;
- final String sampleLabel = res.getSampleLabel(useGroupName.isSelected());
- synchronized (lock) {
- row = tableRows.get(sampleLabel);
- if (row == null) {
- row = new SamplingStatCalculator(sampleLabel);
- tableRows.put(row.getLabel(), row);
- model.insertRow(row, model.getRowCount() - 1);
- }
- }
- /*
- * Synch is needed because multiple threads can update the counts.
- */
- synchronized(row) {
- row.addSample(res);
- }
- SamplingStatCalculator tot = tableRows.get(TOTAL_ROW_LABEL);
- synchronized(tot) {
- tot.addSample(res);
- }
- model.fireTableDataChanged();
- }
+ SamplingStatCalculator row = tableRows.computeIfAbsent(res.getSampleLabel(useGroupName.isSelected()), label -> {
+ SamplingStatCalculator newRow = new SamplingStatCalculator(label);
+ newRows.add(newRow);
+ return newRow;
});
+ synchronized(row) {
+ /*
+ * Synch is needed because multiple threads can update the counts.
+ */
+ row.addSample(res);
+ }
+ SamplingStatCalculator tot = tableRows.get(TOTAL_ROW_LABEL);
+ synchronized(lock) {
+ tot.addSample(res);
+ }
}
/**
@@ -152,6 +146,7 @@ public class StatVisualizer extends Abst
synchronized (lock) {
model.clearData();
tableRows.clear();
+ newRows.clear();
tableRows.put(TOTAL_ROW_LABEL, new SamplingStatCalculator(TOTAL_ROW_LABEL));
model.addRow(tableRows.get(TOTAL_ROW_LABEL));
}
@@ -187,6 +182,15 @@ public class StatVisualizer extends Abst
opts.add(saveTable, BorderLayout.CENTER);
opts.add(saveHeaders, BorderLayout.EAST);
this.add(opts,BorderLayout.SOUTH);
+
+ new Timer(500, e -> {
+ synchronized (lock) {
+ while (!newRows.isEmpty()) {
+ model.insertRow(newRows.pop(), model.getRowCount() - 1);
+ }
+ }
+ model.fireTableDataChanged();
+ }).start();
}
@Override