Skip to content

Commit

Permalink
minor fixes (#620)
Browse files Browse the repository at this point in the history
* changed state listeners to be a thread-safe list
* limited BenchPlugin to one open window
* removed single draw calls from info level
* hid renderer->drawOne measure
* changed dirty bits check to work with recent openjfx versions
  • Loading branch information
ennerf authored Sep 26, 2023
1 parent 08a8be4 commit e841751
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 59 deletions.
2 changes: 1 addition & 1 deletion chartfx-chart/src/main/java/io/fair_acc/chartfx/Chart.java
Original file line number Diff line number Diff line change
Expand Up @@ -947,7 +947,7 @@ public void setRecorder(MeasurementRecorder recorder) {
benchLockDataSets = recorder.newDebugDuration("chart-lockDataSets");
benchUpdateAxisRange = recorder.newDuration("chart-updateAxisRange");
benchDrawAxes = recorder.newDuration("chart-drawAxes");
benchDrawCanvas = recorder.newDuration("chart-drawCanvas");
benchDrawCanvas = recorder.newDebugDuration("chart-drawCanvas");
}

private DurationMeasure benchPreLayout = DurationMeasure.DISABLED;
Expand Down
7 changes: 4 additions & 3 deletions chartfx-chart/src/main/java/io/fair_acc/chartfx/XYChart.java
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,9 @@ public void setGlobalRecorder(MeasurementRecorder recorder) {
} else if (axis == getYAxis()) {
axis.setRecorder(recorder.addPrefix("y"));
} else {
axis.setRecorder(recorder.addPrefix("axis" + i++));
axis.setRecorder(recorder.addPrefix("axis" + i));
}
i++;
}
i = 0;
gridRenderer.setRecorder(recorder);
Expand All @@ -323,8 +324,8 @@ public void setGlobalRecorder(MeasurementRecorder recorder) {
@Override
public void setRecorder(MeasurementRecorder recorder) {
super.setRecorder(recorder);
benchDrawGrid = recorder.newDebugDuration("xychart-drawGrid");
benchDrawData = recorder.newDebugDuration("xychart-drawData");
benchDrawGrid = recorder.newDuration("xychart-drawGrid");
benchDrawData = recorder.newDuration("xychart-drawData");
}

private DurationMeasure benchDrawGrid = DurationMeasure.DISABLED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,23 @@ public class BenchPlugin extends ChartPlugin {
private final BooleanProperty enabled = new SimpleBooleanProperty(false);
private final HBox buttons = createButtonBar();
private UnaryOperator<MeasurementRecorder> measurementFilter = rec -> rec.atLevel(BenchLevel.Info).contains("draw");
private final Stage stage = new Stage();

public HBox createButtonBar() {
final Button enableBench = new Button(null, new FontIcon(ICON_ENABLE_BENCH));
enableBench.setPadding(new Insets(3, 3, 3, 3));
enableBench.setTooltip(new Tooltip("displays live benchmark chart"));
final Button disableBench = new Button(null, new FontIcon(ICON_DISABLE_BENCH));
disableBench.setPadding(new Insets(3, 3, 3, 3));
disableBench.setTooltip(new Tooltip("stops live benchmarks"));
final Button enableBtn = new Button(null, new FontIcon(ICON_ENABLE_BENCH));
enableBtn.setPadding(new Insets(3, 3, 3, 3));
enableBtn.setTooltip(new Tooltip("starts displaying live benchmark stats"));
enableBtn.disableProperty().bind(chartProperty().isNull());
final Button disableBtn = new Button(null, new FontIcon(ICON_DISABLE_BENCH));
disableBtn.setPadding(new Insets(3, 3, 3, 3));
disableBtn.setTooltip(new Tooltip("stops displaying live benchmark stats"));

FXUtils.bindManagedToVisible(enableBench).bind(enabled.not());
enableBench.setOnAction(this::enable);
FXUtils.bindManagedToVisible(disableBench).bind(enabled);
disableBench.setOnAction(this::disable);
FXUtils.bindManagedToVisible(enableBtn).bind(enabled.not());
enableBtn.setOnAction(this::enable);
FXUtils.bindManagedToVisible(disableBtn).bind(enabled);
disableBtn.setOnAction(evt -> disable());

final HBox buttonBar = new HBox(enableBench, disableBench);
final HBox buttonBar = new HBox(enableBtn, disableBtn);
buttonBar.setPadding(new Insets(1, 1, 1, 1));
return buttonBar;
}
Expand All @@ -67,6 +69,11 @@ public BenchPlugin() {
n.getToolBar().getChildren().add(buttons);
}
});
stage.showingProperty().addListener((observable, oldValue, showing) -> {
if (!showing) {
disable();
}
});
}

public BenchPlugin setFilter(UnaryOperator<MeasurementRecorder> measurementFilter) {
Expand All @@ -83,28 +90,24 @@ private void enable(ActionEvent event) {
LiveDisplayRecorder recorder = LiveDisplayRecorder.createChart(title, pane -> {
Scene scene = new Scene(pane);
scene.getStylesheets().addAll(chart.getScene().getStylesheets());

Stage stage = new Stage();
stage.initOwner(chart.getScene().getWindow());
stage.setScene(scene);
stage.showingProperty().addListener((observable, oldValue, showing) -> {
if (!showing) {
chart.setGlobalRecorder(MeasurementRecorder.DISABLED);
disable(event);
}
});
resetRecorder = () -> chart.setGlobalRecorder(MeasurementRecorder.DISABLED);
stage.show();
});
chart.setGlobalRecorder(measurementFilter.apply(recorder));
enabled.set(true);
}
}

private void disable(ActionEvent event) {
if (enabled.get() && getChart() != null && getChart() instanceof XYChart) {
XYChart chart = (XYChart) getChart();
chart.setGlobalRecorder(MeasurementRecorder.DISABLED);
private void disable() {
if (enabled.get()) {
enabled.set(false);
resetRecorder.run();
resetRecorder = NO_OP;
stage.hide();
}
}

private static final Runnable NO_OP = () -> {};
private Runnable resetRecorder = NO_OP;
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ public void render() {
for (int i = getDatasetNodes().size() - 1; i >= 0; i--) {
var dataSetNode = getDatasetNodes().get(i);
if (dataSetNode.isVisible()) {
benchDrawSingle.start();
benchDrawOne.start();
render(getChart().getCanvas().getGraphicsContext2D(), dataSetNode.getDataSet(), dataSetNode);
benchDrawSingle.stop();
benchDrawOne.stop();
}
}

Expand Down Expand Up @@ -131,10 +131,10 @@ protected void updateCachedVariables() {

@Override
public void setRecorder(MeasurementRecorder recorder) {
benchDrawAll = recorder.newDuration("xy-draw-all");
benchDrawSingle = recorder.newDuration("xy-draw-single");
benchDrawAll = recorder.newDuration("xy-drawAll");
benchDrawOne = recorder.newTraceDuration("xy-drawOne");
}

private DurationMeasure benchDrawAll = DurationMeasure.DISABLED;
private DurationMeasure benchDrawSingle = DurationMeasure.DISABLED;
private DurationMeasure benchDrawOne = DurationMeasure.DISABLED;
}
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ private static double snap(final double value) {

@Override
public void setRecorder(MeasurementRecorder recorder) {
benchDrawGrid = recorder.newDuration("grid-drawGrid");
benchDrawGrid = recorder.newDebugDuration("grid-drawGrid");
}

private DurationMeasure benchDrawGrid = DurationMeasure.DISABLED;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.lang.management.ManagementFactory;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
Expand All @@ -25,7 +27,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.javafx.scene.NodeHelper;
// import com.sun.javafx.perf.PerformanceTracker; // keep for the future in case this becomes public API
import com.sun.management.OperatingSystemMXBean;

Expand Down Expand Up @@ -54,7 +55,7 @@ public class SimplePerformanceMeter extends Region {
private double cpuLoadProcessAvgInternal;
private double cpuLoadSystemInternal;
private double cpuLoadSystemAvgInternal = -1;
private final Field dirtyRootBits;
private final Method isCleanMethod;
private final Field dirtyNodesSize;
private final long updateDuration;
// private final PerformanceTracker fxPerformanceTracker; // keep for the future in case this becomes public
Expand All @@ -81,17 +82,19 @@ public void handle(long now) {
}
};

Field field1 = null;
Method isDirtyEmpty = null;
Field field2 = null;
try {
field1 = Node.class.getDeclaredField("dirtyBits");
field1.setAccessible(true);
isDirtyEmpty = Node.class.getDeclaredMethod("isDirtyEmpty");
isDirtyEmpty.setAccessible(true);
field2 = Scene.class.getDeclaredField("dirtyNodesSize");
field2.setAccessible(true);
} catch (SecurityException | NoSuchFieldException e) {
} catch (SecurityException | NoSuchFieldException | NoSuchMethodException e) {
// alternate implementation (potential issues with Java Jigsaw (com.sun... dependency):
// return !com.sun.javafx.scene.NodeHelper.isDirtyEmpty(this.getScene().getRoot());
LOGGER.atError().setCause(e).log("cannot access scene root's dirtyBits field");
}
dirtyRootBits = field1;
isCleanMethod = isDirtyEmpty;
dirtyNodesSize = field2;

this.setManaged(false);
Expand Down Expand Up @@ -253,19 +256,21 @@ public boolean isSceneDirty() {
return false;
}
try {
// implementation based on reflection
return dirtyNodesSize.getInt(this.getScene()) != 0 || dirtyRootBits.getInt(this.getScene().getRoot()) != 0;
} catch (IllegalAccessException | IllegalArgumentException exception) {
try {
// alternate implementation (potential issues with Java Jigsaw (com.sun... dependency):
return !NodeHelper.isDirtyEmpty(this.getScene().getRoot());
} catch (Throwable t) {
LOGGER.atError().setCause(exception).log("cannot access scene root's dirtyBits field");
return true;
}
return isDirty(getScene()) || isDirty(getScene().getRoot());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) {
LOGGER.atError().setCause(exception).log("cannot access scene root's dirtyBits field");
return true;
}
}

private boolean isDirty(Scene scene) throws IllegalAccessException {
return dirtyNodesSize.getInt(scene) != 0;
}

private boolean isDirty(Node node) throws InvocationTargetException, IllegalAccessException {
return !((Boolean) isCleanMethod.invoke(node));
}

protected static double computeAverage(final double newValue, final double oldValue, final double alpha) {
if (oldValue < 0) {
return newValue;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.fair_acc.dataset.events;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.IntSupplier;
Expand Down Expand Up @@ -167,15 +167,15 @@ public BitState addInvalidateListener(int filter, StateListener listener) {

public BitState addChangeListener(StateListener listener) {
if (changeListeners == null) {
changeListeners = new ArrayList<>();
changeListeners = new CopyOnWriteArrayList<>();
}
changeListeners.add(listener);
return this;
}

public BitState addInvalidateListener(StateListener listener) {
if (invalidateListeners == null) {
invalidateListeners = new ArrayList<>();
invalidateListeners = new CopyOnWriteArrayList<>();
}
invalidateListeners.add(listener);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public interface EventSource extends StateListener {
* @throws NullPointerException if the listener is null
*/
default void addListener(StateListener listener) {
// TODO: handle multithreaded changes to the listener?
Objects.requireNonNull(listener, "UpdateListener must not be null");
getBitState().addChangeListener(listener);
getBitState().getBits(listener); // initialize to the current state
Expand All @@ -48,10 +47,8 @@ default void addListener(StateListener listener) {
* @throws NullPointerException if the listener is null
*/
default void removeListener(StateListener listener) {
synchronized (getBitState()) {
Objects.requireNonNull(listener, "UpdateListener must not be null");
getBitState().removeChangeListener(listener);
}
Objects.requireNonNull(listener, "UpdateListener must not be null");
getBitState().removeChangeListener(listener);
}

default void accept(BitState source, int bits) {
Expand Down

0 comments on commit e841751

Please sign in to comment.