diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/Chart.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/Chart.java index 6275f3161..eab31f303 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/Chart.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/Chart.java @@ -5,9 +5,9 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -import io.fair_acc.chartfx.profiler.DurationMeasure; -import io.fair_acc.chartfx.profiler.Profileable; -import io.fair_acc.chartfx.profiler.Profiler; +import io.fair_acc.dataset.profiler.DurationMeasure; +import io.fair_acc.dataset.profiler.Profileable; +import io.fair_acc.dataset.profiler.Profiler; import io.fair_acc.chartfx.ui.css.*; import io.fair_acc.chartfx.ui.layout.TitleLabel; import io.fair_acc.chartfx.ui.layout.ChartPane; diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/Axis.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/Axis.java index 99e533a0d..1fbdc8344 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/Axis.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/Axis.java @@ -1,12 +1,9 @@ package io.fair_acc.chartfx.axes; -import java.util.List; - -import io.fair_acc.chartfx.profiler.Profileable; -import io.fair_acc.chartfx.profiler.Profiler; +import io.fair_acc.dataset.profiler.Profileable; +import io.fair_acc.dataset.profiler.Profiler; import io.fair_acc.chartfx.ui.css.LineStyle; import io.fair_acc.chartfx.ui.css.TextStyle; -import io.fair_acc.dataset.events.BitState; import javafx.beans.property.BooleanProperty; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; @@ -14,8 +11,6 @@ import javafx.collections.ObservableList; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; -import javafx.scene.paint.Paint; -import javafx.scene.text.Font; import javafx.util.StringConverter; import io.fair_acc.chartfx.axes.spi.AxisRange; @@ -23,7 +18,6 @@ import io.fair_acc.chartfx.axes.spi.TickMark; import io.fair_acc.chartfx.ui.geometry.Side; import io.fair_acc.dataset.AxisDescription; -import io.fair_acc.dataset.event.UpdateEvent; public interface Axis extends AxisDescription, Profileable { /** diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/spi/AbstractAxis.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/spi/AbstractAxis.java index 8fed314c9..060efe4ff 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/spi/AbstractAxis.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/axes/spi/AbstractAxis.java @@ -4,9 +4,9 @@ import java.util.Objects; import io.fair_acc.chartfx.axes.AxisLabelOverlapPolicy; -import io.fair_acc.chartfx.profiler.DurationMeasure; -import io.fair_acc.chartfx.profiler.Profileable; -import io.fair_acc.chartfx.profiler.Profiler; +import io.fair_acc.dataset.profiler.DurationMeasure; +import io.fair_acc.dataset.profiler.Profileable; +import io.fair_acc.dataset.profiler.Profiler; import io.fair_acc.chartfx.ui.css.LineStyle; import io.fair_acc.chartfx.ui.css.TextStyle; import io.fair_acc.chartfx.utils.FXUtils; diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/ChartProfiler.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/ChartProfiler.java index 5bac7cfe6..f9e6d2095 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/ChartProfiler.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/ChartProfiler.java @@ -3,7 +3,8 @@ import io.fair_acc.chartfx.XYChart; import io.fair_acc.chartfx.marker.DefaultMarker; import io.fair_acc.chartfx.plugins.Zoomer; -import io.fair_acc.chartfx.profiler.DurationMeasure.SimpleDurationMeasure; +import io.fair_acc.dataset.profiler.DurationMeasure; +import io.fair_acc.dataset.profiler.SimpleDurationMeasure; import io.fair_acc.chartfx.renderer.LineStyle; import io.fair_acc.chartfx.renderer.Renderer; import io.fair_acc.chartfx.renderer.spi.AbstractRendererXY; @@ -11,6 +12,7 @@ import io.fair_acc.dataset.DataSet; import io.fair_acc.dataset.events.BitState; import io.fair_acc.dataset.events.ChartBits; +import io.fair_acc.dataset.profiler.Profiler; import io.fair_acc.dataset.spi.AbstractDataSet; import io.fair_acc.dataset.spi.fastutil.DoubleArrayList; import io.fair_acc.dataset.utils.DoubleCircularBuffer; @@ -29,7 +31,7 @@ */ public class ChartProfiler implements Profiler { - public static Profiler showInNewStage(String title) { + public static ChartProfiler showInNewStage(String title) { return createChart(title, chart -> { var stage = new Stage(); stage.setScene(new Scene(chart)); @@ -37,7 +39,7 @@ public static Profiler showInNewStage(String title) { }); } - private static Profiler createChart(String title, Consumer onChart) { + private static ChartProfiler createChart(String title, Consumer onChart) { var chart = new XYChart(); chart.setTitle("Profiler: " + title); chart.getXAxis().setTimeAxis(false); diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/DurationMeasure.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/DurationMeasure.java deleted file mode 100644 index eff19825c..000000000 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/DurationMeasure.java +++ /dev/null @@ -1,138 +0,0 @@ -package io.fair_acc.chartfx.profiler; - -import io.fair_acc.dataset.utils.AssertUtils; - -import java.util.Locale; -import java.util.function.Consumer; -import java.util.function.LongConsumer; -import java.util.function.LongSupplier; - -/** - * Gets called before and after an action. May record time. - * - * @author ennerf - */ -public interface DurationMeasure { - - /** - * Called when an action begins. Sets the start timestamp. - */ - void start(); - - /** - * Called when an action is done. Records delta from the start timestamp. - */ - void stop(); - - /** - * Calling stop without start is typically an invalid call that may throw an - * error. This method explicitly allows it and simply ignores bad measurements. - * - * @return this - */ - default DurationMeasure ignoreMissingStart() { - return this; - } - - /** - * A default implementation that does nothing and may be eliminated at runtime - */ - public static final DurationMeasure DISABLED = new DurationMeasure() { - @Override - public void start() { - //no-op - } - - @Override - public void stop() { - // no-op - } - }; - - /** - * Basic implementation for keeping time using a specifiable clock - */ - public static class SimpleDurationMeasure implements DurationMeasure { - - public SimpleDurationMeasure(LongSupplier clock, LongConsumer recorder) { - this.clock = AssertUtils.notNull("clock", clock); - this.recorder = AssertUtils.notNull("recorder", recorder); - } - - protected SimpleDurationMeasure(LongSupplier clock) { - this(clock, REQUIRE_CHILD_OVERRIDE); - } - - protected void recordDuration(long duration) { - recorder.accept(duration); - } - - @Override - public void start() { - startTime = clock.getAsLong(); - } - - @Override - public void stop() { - if (startTime == INVALID_START_TIME) { - if (ignoreMissingStart) { - return; - } - throw new IllegalStateException("Invalid start time. start() must be called before stop()"); - } - final long endTime = clock.getAsLong(); - recordDuration(endTime - startTime); - startTime = INVALID_START_TIME; - } - - @Override - public DurationMeasure ignoreMissingStart() { - ignoreMissingStart = true; - return this; - } - - final LongSupplier clock; - final LongConsumer recorder; - long startTime = INVALID_START_TIME; - protected static final int INVALID_START_TIME = -1; - protected boolean ignoreMissingStart = false; - - // Workaround to implement recordDuration in child classes where the - // child method can't be referenced when calling the super constructor - private static final LongConsumer REQUIRE_CHILD_OVERRIDE = value -> { - throw new UnsupportedOperationException("child class does not override recordDuration"); - }; - - } - - /** - * A debug implementation that prints start and stop strings with duration information - */ - public static final class MeasurePrinter extends SimpleDurationMeasure { - - public MeasurePrinter(String tag, Consumer logger) { - super(System::nanoTime); - this.tag = tag; - this.logger = logger; - this.startString = tag + " - started"; - this.stopTemplate = tag + " - finished (%.2f ms)"; - } - - @Override - public void start() { - logger.accept(startString); - } - - @Override - protected void recordDuration(long duration) { - logger.accept(String.format(Locale.ENGLISH, stopTemplate, duration * 1E-6)); - } - - final String tag; - final Consumer logger; - final String startString; - final String stopTemplate; - - } - -} diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/HdrHistogramProfiler.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/HdrHistogramProfiler.java index 17e085202..1524f12fd 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/HdrHistogramProfiler.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/HdrHistogramProfiler.java @@ -1,5 +1,8 @@ package io.fair_acc.chartfx.profiler; +import io.fair_acc.dataset.profiler.DurationMeasure; +import io.fair_acc.dataset.profiler.Profiler; +import io.fair_acc.dataset.profiler.SimpleDurationMeasure; import io.fair_acc.dataset.utils.AssertUtils; import org.HdrHistogram.Histogram; import org.HdrHistogram.HistogramLogWriter; @@ -111,7 +114,7 @@ public void close() { private final ScheduledFuture task; private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); - static class HdrHistogramMeasure extends DurationMeasure.SimpleDurationMeasure { + static class HdrHistogramMeasure extends SimpleDurationMeasure { HdrHistogramMeasure(final String tag) { super(System::nanoTime); diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profilers.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profilers.java new file mode 100644 index 000000000..c99d83382 --- /dev/null +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profilers.java @@ -0,0 +1,35 @@ +package io.fair_acc.chartfx.profiler; + +import io.fair_acc.dataset.profiler.Profiler; + +import java.util.concurrent.TimeUnit; + +/** + * Convenience methods for creating commonly used profilers + * + * @author ennerf + */ +public interface Profilers { + + /** + * A low-overhead hdr histogram recorder that writes an aggregate histogram to disk once a second. + * Check hdrhistogram.org for more information + * + * @param fileName the disk file + * @return hdr histogram profiler + */ + static HdrHistogramProfiler hdrHistogramProfiler(String fileName) { + return HdrHistogramProfiler.createStarted(fileName, 1, TimeUnit.SECONDS); + } + + /** + * A profiler that creates a new stage and renders the measures in real time + * + * @param title title of the chart + * @return a chart profiler + */ + static ChartProfiler chartProfiler(String title) { + return ChartProfiler.showInNewStage(title); + } + +} diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/Renderer.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/Renderer.java index 3512083ff..5fafdf8c7 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/Renderer.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/Renderer.java @@ -1,8 +1,8 @@ package io.fair_acc.chartfx.renderer; import io.fair_acc.chartfx.Chart; -import io.fair_acc.chartfx.profiler.Profileable; -import io.fair_acc.chartfx.profiler.Profiler; +import io.fair_acc.dataset.profiler.Profileable; +import io.fair_acc.dataset.profiler.Profiler; import io.fair_acc.chartfx.ui.css.DataSetNode; import javafx.beans.property.BooleanProperty; import javafx.collections.ObservableList; @@ -12,9 +12,6 @@ import io.fair_acc.chartfx.axes.Axis; import io.fair_acc.dataset.DataSet; -import java.util.ArrayList; -import java.util.List; - /** * -- generic renderer interface -- * diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRendererXY.java b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRendererXY.java index 320912b77..e93aa657d 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRendererXY.java +++ b/chartfx-chart/src/main/java/io/fair_acc/chartfx/renderer/spi/AbstractRendererXY.java @@ -3,9 +3,9 @@ import io.fair_acc.chartfx.Chart; import io.fair_acc.chartfx.XYChart; import io.fair_acc.chartfx.axes.Axis; -import io.fair_acc.chartfx.profiler.DurationMeasure; -import io.fair_acc.chartfx.profiler.Profileable; -import io.fair_acc.chartfx.profiler.Profiler; +import io.fair_acc.dataset.profiler.DurationMeasure; +import io.fair_acc.dataset.profiler.Profileable; +import io.fair_acc.dataset.profiler.Profiler; import io.fair_acc.chartfx.ui.css.DataSetNode; import io.fair_acc.dataset.DataSet; import io.fair_acc.dataset.utils.AssertUtils; diff --git a/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/DurationMeasure.java b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/DurationMeasure.java new file mode 100644 index 000000000..ec3e7a226 --- /dev/null +++ b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/DurationMeasure.java @@ -0,0 +1,45 @@ +package io.fair_acc.dataset.profiler; + +/** + * Gets called before and after an action. May record time. + * + * @author ennerf + */ +public interface DurationMeasure { + + /** + * Called when an action begins. Sets the start timestamp. + */ + void start(); + + /** + * Called when an action is done. Records delta from the start timestamp. + */ + void stop(); + + /** + * Calling stop without start is typically an invalid call that may throw an + * error. This method explicitly allows it and simply ignores bad measurements. + * + * @return this + */ + default DurationMeasure ignoreMissingStart() { + return this; + } + + /** + * A default implementation that does nothing and may be eliminated at runtime + */ + public static final DurationMeasure DISABLED = new DurationMeasure() { + @Override + public void start() { + //no-op + } + + @Override + public void stop() { + // no-op + } + }; + +} diff --git a/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/PrintingDurationMeasure.java b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/PrintingDurationMeasure.java new file mode 100644 index 000000000..4ba1f50d0 --- /dev/null +++ b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/PrintingDurationMeasure.java @@ -0,0 +1,49 @@ +package io.fair_acc.dataset.profiler; + +import java.util.Locale; +import java.util.function.Consumer; + +/** + * A duration measure that prints start and stop strings with duration information + * + * @author ennerf + */ +public class PrintingDurationMeasure extends SimpleDurationMeasure { + + public PrintingDurationMeasure(String tag, Consumer log) { + super(System::nanoTime); + this.tag = tag; + this.log = log; + this.startString = tag + " - started"; + this.stopTemplate = tag + " - finished (%.2f ms)"; + } + + public PrintingDurationMeasure setPrintStartedInfo(boolean value) { + printStartedInfo = value; + return this; + } + + @Override + public void start() { + super.start(); + printStarted(); + } + + protected void printStarted() { + if (printStartedInfo) { + log.accept(startString); + } + } + + @Override + protected void recordDuration(long duration) { + log.accept(String.format(Locale.ENGLISH, stopTemplate, duration * 1E-6)); + } + + final String tag; + final Consumer log; + final String startString; + final String stopTemplate; + boolean printStartedInfo = false; + +} diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profileable.java b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/Profileable.java similarity index 87% rename from chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profileable.java rename to chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/Profileable.java index b658dfc09..0cc83e139 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profileable.java +++ b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/Profileable.java @@ -1,4 +1,4 @@ -package io.fair_acc.chartfx.profiler; +package io.fair_acc.dataset.profiler; /** * An interface for classes that can be profiled, i.e., diff --git a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profiler.java b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/Profiler.java similarity index 50% rename from chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profiler.java rename to chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/Profiler.java index 660425ffe..b72b9e6d4 100644 --- a/chartfx-chart/src/main/java/io/fair_acc/chartfx/profiler/Profiler.java +++ b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/Profiler.java @@ -1,13 +1,10 @@ -package io.fair_acc.chartfx.profiler; +package io.fair_acc.dataset.profiler; -import io.fair_acc.chartfx.profiler.DurationMeasure.MeasurePrinter; - -import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; /** - * Creates time traces for benchmarking purposes. + * Profiler interface for benchmarking purposes. * * @author ennerf */ @@ -20,41 +17,21 @@ public interface Profiler { DurationMeasure newDuration(String tag); /** - * A debug profiler that prints start/stop information and timestamps - * - * @param logger log output - * @return debug printer - */ - public static Profiler debugPrinter(Consumer logger) { - return tag -> new MeasurePrinter(tag, logger); - } - - /** - * @return debug printer that prints on System.out + * @return profiler that prints start/stop information on stdout */ - public static Profiler debugPrinter() { - return debugPrinter(System.out::println); + public static Profiler printProfiler() { + return printProfiler(System.out::println, true); } /** - * A low-overhead hdr histogram recorder that writes an aggregate histogram to disk once a second. - * Check hdrhistogram.org for more information + * A profiler that prints basic information to a log * - * @param fileName the disk file - * @return hdr histogram profiler - */ - public static Profiler hdrHistogramProfiler(String fileName) { - return HdrHistogramProfiler.createStarted(fileName, 1, TimeUnit.SECONDS); - } - - /** - * A chart in a new stage that renders the current performance in real time - * - * @param title title of the chart - * @return a chart profiler + * @param log output + * @param printStartInfo whether the start method should also generate log entries + * @return debug printer */ - public static Profiler chartProfiler(String title) { - return ChartProfiler.showInNewStage(title); + public static Profiler printProfiler(Consumer log, boolean printStartInfo) { + return tag -> new PrintingDurationMeasure(tag, log).setPrintStartedInfo(printStartInfo); } default Profiler matches(String pattern) { diff --git a/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/SimpleDurationMeasure.java b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/SimpleDurationMeasure.java new file mode 100644 index 000000000..de0dcf81e --- /dev/null +++ b/chartfx-dataset/src/main/java/io/fair_acc/dataset/profiler/SimpleDurationMeasure.java @@ -0,0 +1,64 @@ +package io.fair_acc.dataset.profiler; + +import io.fair_acc.dataset.utils.AssertUtils; + +import java.util.function.LongConsumer; +import java.util.function.LongSupplier; + +/** + * Basic duration measure for keeping time using a specifiable clock + * + * @author ennerf + */ +public class SimpleDurationMeasure implements DurationMeasure { + + public SimpleDurationMeasure(LongSupplier clock, LongConsumer recorder) { + this.clock = AssertUtils.notNull("clock", clock); + this.recorder = AssertUtils.notNull("recorder", recorder); + } + + protected SimpleDurationMeasure(LongSupplier clock) { + this(clock, REQUIRE_CHILD_OVERRIDE); + } + + protected void recordDuration(long duration) { + recorder.accept(duration); + } + + @Override + public void start() { + startTime = clock.getAsLong(); + } + + @Override + public void stop() { + if (startTime == INVALID_START_TIME) { + if (ignoreMissingStart) { + return; + } + throw new IllegalStateException("Invalid start time. start() must be called before stop()"); + } + final long endTime = clock.getAsLong(); + recordDuration(endTime - startTime); + startTime = INVALID_START_TIME; + } + + @Override + public DurationMeasure ignoreMissingStart() { + ignoreMissingStart = true; + return this; + } + + final LongSupplier clock; + final LongConsumer recorder; + long startTime = INVALID_START_TIME; + protected static final int INVALID_START_TIME = -1; + protected boolean ignoreMissingStart = false; + + // Workaround to implement recordDuration in child classes where the + // child method can't be referenced when calling the super constructor + private static final LongConsumer REQUIRE_CHILD_OVERRIDE = value -> { + throw new UnsupportedOperationException("child class does not override recordDuration"); + }; + +}