Skip to content

Commit ee35b36

Browse files
authored
Merge pull request #3544 from ControlSystemStudio/CSSTUDIO-3420
CSSTUDIO-3420 Performance improvements to the Waterfall Plot widget
2 parents b32391b + 4d604e6 commit ee35b36

File tree

3 files changed

+83
-98
lines changed

3 files changed

+83
-98
lines changed

app/display/waterfallplot/src/main/java/org/phoebus/applications/waterfallplotwidget/WaterfallPlotController.java

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,12 @@
1717

1818
import java.time.Duration;
1919
import java.time.Instant;
20+
import java.util.ArrayList;
2021
import java.util.LinkedList;
2122
import java.util.List;
2223
import java.util.Optional;
23-
import java.util.SortedMap;
24-
import java.util.TreeMap;
24+
import java.util.concurrent.ConcurrentSkipListMap;
2525
import java.util.concurrent.atomic.AtomicBoolean;
26-
import java.util.concurrent.atomic.AtomicReference;
2726

2827
public class WaterfallPlotController {
2928

@@ -309,7 +308,7 @@ public synchronized void redraw(WaterfallPlotRuntime.PVData pvData) {
309308
previousT2[0] = Optional.of(t2);
310309

311310
LinkedList<Double> timeValuesLinkedList = new LinkedList<>();
312-
LinkedList<LinkedList<Double>> zValuesLinkedList = new LinkedList<>();
311+
LinkedList<ArrayList<Double>> zValuesLinkedList = new LinkedList<>();
313312
int waveformLength = 1;
314313

315314
double minFromPV = Double.NaN;
@@ -320,21 +319,24 @@ public synchronized void redraw(WaterfallPlotRuntime.PVData pvData) {
320319
minFromPV = waveformPVData.minFromPV().get();
321320
maxFromPV = waveformPVData.maxFromPV().get();
322321

323-
TreeMap<Instant, LinkedList<Double>> instantToWaveform = waveformPVData.instantToValue().get();
322+
ConcurrentSkipListMap<Instant, ArrayList<Double>> instantToWaveform = waveformPVData.instantToValue();
323+
Instant startKey = instantToWaveform.ceilingKey(Instant.MIN);
324324
for (Instant t = t1.plus(stepsize); t.compareTo(t2) <= 0; t = t.plus(stepsize)) {
325325
timeValuesLinkedList.add(((double) t.toEpochMilli()) / 1000.0);
326326

327-
var instant = instantToWaveform.floorKey(t);
328-
if (instant != null) {
329-
LinkedList<Double> waveform = instantToWaveform.get(instant);
327+
if (startKey == null || t.isBefore(startKey)) {
328+
zValuesLinkedList.add(null); // null means absence of data for this point in time
329+
}
330+
else {
331+
var instant = instantToWaveform.floorKey(t);
332+
333+
ArrayList<Double> waveform = instantToWaveform.get(instant);
330334
waveformLength = Math.max(waveformLength, waveform.size());
331335
zValuesLinkedList.add(waveform);
332-
} else {
333-
zValuesLinkedList.add(null); // null means absence of data for this point in time
334336
}
335337
}
336338
} else if (pvData instanceof WaterfallPlotRuntime.ScalarPVsData scalarPVsData) {
337-
LinkedList<Pair<String, AtomicReference<TreeMap<Instant, Double>>>> pvNameToInstantToValue = scalarPVsData.pvNameToInstantToValue();
339+
ArrayList<Pair<String, ConcurrentSkipListMap<Instant, Double>>> pvNameToInstantToValue = scalarPVsData.pvNameToInstantToValue();
338340
pvNameToInstantToValue.forEach(pvNameAndInstantToValueAtomicReference -> garbageCollectInstantToValue(pvNameAndInstantToValueAtomicReference.getValue(), t1));
339341

340342
minFromPV = scalarPVsData.minFromPV().get();
@@ -344,12 +346,12 @@ public synchronized void redraw(WaterfallPlotRuntime.PVData pvData) {
344346

345347
for (Instant t = t1.plus(stepsize); t.compareTo(t2) <= 0; t = t.plus(stepsize)) {
346348
timeValuesLinkedList.add(((double) t.toEpochMilli()) / 1000.0);
347-
LinkedList<Double> zValues = new LinkedList<>();
349+
ArrayList<Double> zValues = new ArrayList<>();
348350

349351
for (var pvNameAndInstantToValue : pvNameToInstantToValue) {
350352
String pvName = pvNameAndInstantToValue.getKey();
351353

352-
TreeMap<Instant, Double> instantToValue = pvNameAndInstantToValue.getValue().get();
354+
ConcurrentSkipListMap<Instant, Double> instantToValue = pvNameAndInstantToValue.getValue();
353355

354356
var instant = instantToValue.floorKey(t);
355357
if (instant == null) {
@@ -363,7 +365,7 @@ public synchronized void redraw(WaterfallPlotRuntime.PVData pvData) {
363365

364366
// Append the last value one more time in order to
365367
// fix the plotting when there is only 1 scalar PV:
366-
var lastValue = zValues.getLast();
368+
var lastValue = zValues.get(zValues.size()-1);
367369
zValues.add(lastValue);
368370

369371
zValuesLinkedList.add(zValues);
@@ -392,7 +394,7 @@ public synchronized void redraw(WaterfallPlotRuntime.PVData pvData) {
392394
}
393395

394396
for (int n = 0; n < zValuesLinkedList.size(); n++) {
395-
LinkedList<Double> waveformValues = zValuesLinkedList.get(n);
397+
ArrayList<Double> waveformValues = zValuesLinkedList.get(n);
396398

397399
for (int m = 0; m < waveformLength; m++) {
398400
double value;
@@ -431,7 +433,7 @@ public synchronized void redraw(WaterfallPlotRuntime.PVData pvData) {
431433
}
432434

433435
for (int n = 0; n < zValuesLinkedList.size(); n++) {
434-
LinkedList<Double> waveformValues = zValuesLinkedList.get(n);
436+
ArrayList<Double> waveformValues = zValuesLinkedList.get(n);
435437

436438
for (int m = 0; m < waveformLength; m++) {
437439
double value;
@@ -479,14 +481,13 @@ else if (zAxisMinMax.equals(WaterfallPlotWidget.ZAxisMinMax.FromPVLimits)) {
479481
}
480482
}
481483

482-
private synchronized static <T> void garbageCollectInstantToValue(AtomicReference<TreeMap<Instant, T>> instantToValueAtomicReference, Instant t1) {
484+
private synchronized static <T> void garbageCollectInstantToValue(ConcurrentSkipListMap<Instant, T> instantToWaveform, Instant t1) {
483485
// Garbage collect old values that are no longer needed:
484-
TreeMap<Instant, T> instantToWaveform = instantToValueAtomicReference.get();
485486
Instant instantOfOldestRelevantKey = instantToWaveform.floorKey(t1);
486487
if (instantOfOldestRelevantKey != null) {
487-
SortedMap<Instant, T> instantToWaveformGarbageCollectedSortedMap = instantToWaveform.subMap(instantOfOldestRelevantKey, Instant.MAX);
488-
TreeMap<Instant, T> instantToWaveformGarbageCollected = new TreeMap<>(instantToWaveformGarbageCollectedSortedMap);
489-
instantToValueAtomicReference.set(instantToWaveformGarbageCollected);
488+
for (var key : instantToWaveform.subMap(Instant.MIN, instantOfOldestRelevantKey).keySet()) {
489+
instantToWaveform.remove(key);
490+
}
490491
}
491492
}
492493

0 commit comments

Comments
 (0)