From 865d7f2560824e8cc74b3780b818dd6c75a865a5 Mon Sep 17 00:00:00 2001 From: knokko Date: Mon, 12 Feb 2024 14:37:37 +0100 Subject: [PATCH] Avoid stability problems --- README.md | 6 +- .../com/github/knokko/update/Reference.java | 7 ++ .../github/knokko/update/SlidingEntry.java | 30 ------- .../github/knokko/update/SlidingWindow.java | 31 ------- .../com/github/knokko/update/UpdateLoop.java | 81 +++++++++++------- .../knokko/update/TestSlidingWindow.java | 64 -------------- .../github/knokko/update/TestUpdateLoop.java | 61 +++++-------- .../github/knokko/update/UpdateMonitor.java | 40 +++++++-- update-loops-overview.md | 33 +++---- update-monitor.png | Bin 19884 -> 26727 bytes 10 files changed, 125 insertions(+), 228 deletions(-) create mode 100644 implementation/src/main/java/com/github/knokko/update/Reference.java delete mode 100644 implementation/src/main/java/com/github/knokko/update/SlidingEntry.java delete mode 100644 implementation/src/main/java/com/github/knokko/update/SlidingWindow.java delete mode 100644 implementation/src/test/java/com/github/knokko/update/TestSlidingWindow.java diff --git a/README.md b/README.md index 9f3344c..51e2e88 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ For demonstration purposes, this project also has a `testbench` [module ![](./update-monitor.png) ### Add as dependency -Since this library only has 4 small classes, you could just +Since this library only has 3 small classes, you could just copy & paste them into your own project. If you prefer proper dependency management, you can use Jitpack: @@ -71,7 +71,7 @@ repositories { ... dependencies { ... - implementation 'com.github.knokko.update-loop:implementation:v1.0.0' + implementation 'com.github.knokko.update-loop:implementation:v1.0.1' } ``` @@ -89,6 +89,6 @@ dependencies { com.github.knokko.update-loop implementation - v1.0.0 + v1.0.1 ``` \ No newline at end of file diff --git a/implementation/src/main/java/com/github/knokko/update/Reference.java b/implementation/src/main/java/com/github/knokko/update/Reference.java new file mode 100644 index 0000000..0b17621 --- /dev/null +++ b/implementation/src/main/java/com/github/knokko/update/Reference.java @@ -0,0 +1,7 @@ +package com.github.knokko.update; + +class Reference { + + long time = System.nanoTime(); + long counter; +} diff --git a/implementation/src/main/java/com/github/knokko/update/SlidingEntry.java b/implementation/src/main/java/com/github/knokko/update/SlidingEntry.java deleted file mode 100644 index acb038e..0000000 --- a/implementation/src/main/java/com/github/knokko/update/SlidingEntry.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.github.knokko.update; - -class SlidingEntry { - - final int age; - final long value; - - SlidingEntry(int age, long value) { - this.age = age; - this.value = value; - } - - @Override - public boolean equals(Object other) { - if (other instanceof SlidingEntry) { - SlidingEntry entry = (SlidingEntry) other; - return this.age == entry.age && this.value == entry.value; - } else return false; - } - - @Override - public int hashCode() { - return 3 * age - 31 * (int) value; - } - - @Override - public String toString() { - return "(age=" + age + ",value=" + value + ")"; - } -} diff --git a/implementation/src/main/java/com/github/knokko/update/SlidingWindow.java b/implementation/src/main/java/com/github/knokko/update/SlidingWindow.java deleted file mode 100644 index c05d6df..0000000 --- a/implementation/src/main/java/com/github/knokko/update/SlidingWindow.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.github.knokko.update; - -class SlidingWindow { - - final long[] values; - - private int writeIndex = 0; - private int numReadableElements = 0; - - SlidingWindow(int capacity) { - if (capacity <= 0) throw new IllegalArgumentException("Capacity (" + capacity + ") must be positive"); - this.values = new long[capacity]; - } - - synchronized void insert(long value) { - values[writeIndex] = value; - writeIndex = (writeIndex + 1) % values.length; - if (numReadableElements < values.length) numReadableElements += 1; - } - - synchronized SlidingEntry oldest() { - if (numReadableElements == 0) return null; - - int valueIndex = (values.length + writeIndex - numReadableElements) % values.length; - return new SlidingEntry(numReadableElements - 1, values[valueIndex]); - } - - synchronized void forget() { - numReadableElements = 0; - } -} diff --git a/implementation/src/main/java/com/github/knokko/update/UpdateLoop.java b/implementation/src/main/java/com/github/knokko/update/UpdateLoop.java index 29e323c..bd80249 100644 --- a/implementation/src/main/java/com/github/knokko/update/UpdateLoop.java +++ b/implementation/src/main/java/com/github/knokko/update/UpdateLoop.java @@ -2,68 +2,70 @@ import java.util.function.Consumer; -import static java.lang.Math.max; - /** * An `UpdateLoop` tries to ensure that a given (update) function is executed periodically with a given period. */ public class UpdateLoop implements Runnable { - static long determineSleepTime(SlidingWindow window, long currentTime, long period) { - SlidingEntry oldest = window.oldest(); - if (oldest == null) return 0L; - - long updateAt = oldest.value + (oldest.age + 1) * period; - long sleepNanoTime = updateAt - currentTime; - - return sleepNanoTime / 1_000_000; - } - private final Consumer updateFunction; - private final SlidingWindow slidingWindow; private volatile long period; + private volatile long maximumBacklog; + private volatile Reference reference; private volatile boolean shouldContinue = true; private volatile boolean didStart = false; /** * Constructs an UpdateLoop that attempts to execute {@code updateFunction} every {@code initialPeriod} - * nanoseconds. It will keep track of how many updates occurred the last {@code initialPeriod * windowSize} - * nanoseconds and use this information to maintain a stable update rate. + * nanoseconds. It will allow a maximum backlog of {@code initialMaximumBacklog} nanoseconds. Any additional + * backlog will be discarded. The period and maximum backlog can be changed at any time. * @param updateFunction The function that should be called periodically. The parameter will always be this * UpdateLoop, which is convenient for e.g. stopping it. * @param initialPeriod The initial period of the update function, in nanoseconds. - * @param windowSize The number of past updates from which their timestamps will be remembered. This information - * is needed to achieve a robust update rate. + * @param initialMaximumBacklog The initial maximum backlog of the update function, in nanoseconds. */ - public UpdateLoop(Consumer updateFunction, long initialPeriod, int windowSize) { + public UpdateLoop(Consumer updateFunction, long initialPeriod, long initialMaximumBacklog) { + if (updateFunction == null || initialPeriod < 0 || initialMaximumBacklog < 0) { + throw new IllegalArgumentException(); + } this.updateFunction = updateFunction; - this.slidingWindow = new SlidingWindow(windowSize); this.period = initialPeriod; + this.maximumBacklog = initialMaximumBacklog; } /** * Constructs an UpdateLoop that attempts to execute {@code updateFunction} every {@code initialPeriod} - * nanoseconds. It will use a default sliding window of 1 second. + * nanoseconds. It will use a default maximum backlog of 500 milliseconds. * @param updateFunction The function that should be called periodically * @param initialPeriod The initial period of the update function, in nanoseconds */ public UpdateLoop(Consumer updateFunction, long initialPeriod) { - this(updateFunction, initialPeriod, max(4, (int) (1_000_000_000L / initialPeriod))); + this(updateFunction, initialPeriod, 500_000_000L); } /** - * Changes the period of this update loop to {@code newPeriod} nanoseconds. Note that the performance of the - * update loop may degrade if the sliding window is too small. This would for instance happen if the sliding - * window size was determined automatically, and the new period is much smaller than the original period.
+ * Changes the period of this update loop to {@code newPeriod} nanoseconds. Even though this class allows any + * non-negative period, periods below approximately 100 nanoseconds can't be achieved because the + * update loop overhead will become larger than the update period...
* Thread safety: this method can be called from any thread at any time. * @param newPeriod The new period, in nanoseconds */ public void setPeriod(long newPeriod) { - slidingWindow.forget(); + if (newPeriod < 0) throw new IllegalArgumentException(); + reference = new Reference(); period = newPeriod; } + /** + * Changes the maximum backlog of this update loop to {@code newBacklog} nanoseconds.
+ * Thread safety: this method can be called from any thread at any time. + * @param newBacklog The new maximum backlog, in nanoseconds + */ + public void setMaximumBacklog(long newBacklog) { + if (newBacklog < 0) throw new IllegalArgumentException(); + maximumBacklog = newBacklog; + } + /** * Thread safety: this method can be called from any thread at any time. * @return The current period of this update loop, in nanoseconds. @@ -72,6 +74,14 @@ public long getPeriod() { return period; } + /** + * Thread safety: this method can be called from any thread at any time. + * @return The current maximum backlog of this update loop, in nanoseconds. + */ + public long getMaximumBacklog() { + return maximumBacklog; + } + /** * Starts this update loop on a new thread. This function must be called at most once. */ @@ -80,7 +90,8 @@ public void start() { } /** - * Stops this update loop. After invoking this method, the update function will be called at most once. Calling + * Stops this update loop. After invoking this method, the update function will be called at most once. + * If this method is called during the update function, the update function won't be invoked again. Calling * this method more than once has the same effect as calling it once. * Thread safety: this method can be called from any thread at any time. */ @@ -88,6 +99,15 @@ public void stop() { shouldContinue = false; } + private long determineSleepTime(long currentTime) { + long nextUpdateAt = reference.time + reference.counter * period; + long nextSleepTime = nextUpdateAt - currentTime; + + if (-nextSleepTime > maximumBacklog) reference.time += -nextSleepTime - maximumBacklog; + + return nextSleepTime / 1000_000L; + } + /** * Runs this update loop on the current thread. It won't return until the update loop is finished. * This method must be called at most once. @@ -96,12 +116,13 @@ public void stop() { public void run() { if (didStart) throw new IllegalStateException("This update loop has already started"); didStart = true; + reference = new Reference(); outerLoop: while (shouldContinue) { long sleepTime; do { - sleepTime = determineSleepTime(slidingWindow, System.nanoTime(), period); + sleepTime = determineSleepTime(System.nanoTime()); if (sleepTime > 0L) { try { //noinspection BusyWait @@ -112,8 +133,10 @@ public void run() { } } while (sleepTime > 0L); - slidingWindow.insert(System.nanoTime()); - if (shouldContinue) updateFunction.accept(this); + if (shouldContinue) { + updateFunction.accept(this); + reference.counter += 1; + } } } } diff --git a/implementation/src/test/java/com/github/knokko/update/TestSlidingWindow.java b/implementation/src/test/java/com/github/knokko/update/TestSlidingWindow.java deleted file mode 100644 index e8199c9..0000000 --- a/implementation/src/test/java/com/github/knokko/update/TestSlidingWindow.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.github.knokko.update; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -public class TestSlidingWindow { - - @Test - public void testSingleElementWindow() { - SlidingWindow window = new SlidingWindow(1); - assertNull(window.oldest()); - window.insert(5L); - assertEquals(new SlidingEntry(0, 5L), window.oldest()); - window.insert(3L); - assertEquals(new SlidingEntry(0, 3L), window.oldest()); - window.forget(); - assertNull(window.oldest()); - window.insert(8L); - assertEquals(new SlidingEntry(0, 8L), window.oldest()); - window.insert(7L); - assertEquals(new SlidingEntry(0, 7L), window.oldest()); - } - - @Test - public void testTwoElementWindow() { - SlidingWindow window = new SlidingWindow(2); - assertNull(window.oldest()); - window.insert(3L); - assertEquals(new SlidingEntry(0, 3L), window.oldest()); - window.insert(2L); - assertEquals(new SlidingEntry(1, 3L), window.oldest()); - window.insert(5L); - assertEquals(new SlidingEntry(1, 2L), window.oldest()); - - window.forget(); - assertNull(window.oldest()); - window.insert(10L); - assertEquals(new SlidingEntry(0, 10L), window.oldest()); - window.insert(8L); - assertEquals(new SlidingEntry(1, 10L), window.oldest()); - window.insert(6L); - assertEquals(new SlidingEntry(1, 8L), window.oldest()); - } - - @Test - public void testLargerSlidingWindow() { - SlidingWindow window = new SlidingWindow(4); - window.insert(6L); - window.insert(7L); - window.insert(8L); - assertEquals(new SlidingEntry(2, 6L), window.oldest()); - window.insert(9L); - assertEquals(new SlidingEntry(3, 6L), window.oldest()); - window.insert(10L); - assertEquals(new SlidingEntry(3, 7L), window.oldest()); - - window.forget(); - assertNull(window.oldest()); - window.insert(15L); - assertEquals(new SlidingEntry(0, 15L), window.oldest()); - } -} diff --git a/implementation/src/test/java/com/github/knokko/update/TestUpdateLoop.java b/implementation/src/test/java/com/github/knokko/update/TestUpdateLoop.java index 90d8410..4d23da9 100644 --- a/implementation/src/test/java/com/github/knokko/update/TestUpdateLoop.java +++ b/implementation/src/test/java/com/github/knokko/update/TestUpdateLoop.java @@ -4,52 +4,11 @@ import java.util.concurrent.atomic.AtomicInteger; -import static com.github.knokko.update.UpdateLoop.determineSleepTime; import static java.lang.Math.abs; import static org.junit.jupiter.api.Assertions.*; public class TestUpdateLoop { - @Test - public void testDetermineSleepTime() { - assertEquals(0L, determineSleepTime(new SlidingWindow(5), 1234, 10)); - - long m = 1_000_000L; - long period = 10 * m; - SlidingWindow window = new SlidingWindow(4); - - // Oldest entry is (0, 2500) - window.insert(2500 * m); - assertEquals(7, determineSleepTime(window, 2503 * m, period)); - assertEquals(6, determineSleepTime(window, 1 + 2503 * m, period)); - - // Oldest entry is (1, 2500) - window.insert(2510 * m); - assertEquals(17, determineSleepTime(window, 2503 * m, period)); - assertEquals(7, determineSleepTime(window, 2513 * m, period)); - assertTrue(determineSleepTime(window, 2523 * m, period) <= 0); - - // Oldest entry is (2, 2500) - window.insert(2600 * m); - assertEquals(7, determineSleepTime(window, 2523 * m, period)); - assertTrue(determineSleepTime(window, 2550 * m, period) <= 0); - - // Oldest entry is (3, 2500) - window.insert(2601 * m); - assertEquals(37, determineSleepTime(window, 2503 * m, period)); - assertTrue(determineSleepTime(window, 2540 * m, period) <= 0); - - // Oldest entry becomes 2510 - window.insert(2602 * m); - assertEquals(4L, determineSleepTime(window, 2546 * m, period)); - assertTrue(determineSleepTime(window, 1 + 2549 * m, period) <= 0); - assertTrue(determineSleepTime(window, 2615 * m, period) <= 0); - - // Oldest entry becomes 2600 - window.insert(2610 * m); - assertEquals(8L, determineSleepTime(window, 2632 * m, period)); - } - private void testConstantPeriod(long period, long sleepTime) throws InterruptedException { AtomicInteger counter = new AtomicInteger(0); @@ -102,6 +61,26 @@ public void testWithDynamicPeriod() throws InterruptedException { if (abs(finalValue - expectedValue) > 3) assertEquals(expectedValue, finalValue); } + @Test + public void testWithDynamicMaximumBacklog() throws InterruptedException { + AtomicInteger counter = new AtomicInteger(0); + UpdateLoop updater = new UpdateLoop(loop -> counter.incrementAndGet(), 1_000_000L); + + updater.start(); + Thread.sleep(500); + + updater.setMaximumBacklog(1_000_000_000L); + int midValue = counter.get(); + + Thread.sleep(500); + updater.stop(); + + int finalValue = counter.get(); + int expectedValue = midValue + 500; + + if (abs(finalValue - expectedValue) > 150) assertEquals(expectedValue, finalValue); + } + @Test public void testCannotStartTwice() throws InterruptedException { UpdateLoop updateLoop = new UpdateLoop(loop -> {}, 100_000_000L); diff --git a/testbench/src/main/java/com/github/knokko/update/UpdateMonitor.java b/testbench/src/main/java/com/github/knokko/update/UpdateMonitor.java index b2f3a72..e29cf6a 100644 --- a/testbench/src/main/java/com/github/knokko/update/UpdateMonitor.java +++ b/testbench/src/main/java/com/github/knokko/update/UpdateMonitor.java @@ -6,6 +6,7 @@ import java.awt.event.KeyListener; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import static java.awt.event.KeyEvent.*; import static java.lang.Math.sqrt; @@ -14,15 +15,13 @@ public class UpdateMonitor extends JFrame implements KeyListener { public static void main(String[] args) { - int windowSize = 100_000; - UpdateMonitor monitor = new UpdateMonitor(); monitor.setDefaultCloseOperation(DISPOSE_ON_CLOSE); - monitor.setSize(1400, 600); + monitor.setSize(1400, 800); monitor.setVisible(true); monitor.addKeyListener(monitor); - UpdateLoop updateLoop = new UpdateLoop(monitor::updateFunction, 20_000_000L, windowSize); + UpdateLoop updateLoop = new UpdateLoop(monitor::updateFunction, 20_000_000L); updateLoop.start(); new UpdateLoop(paintLoop -> { @@ -42,9 +41,9 @@ public static void main(String[] args) { private UpdateLoop updateLoop; - private final int[] startCounterHistory = new int[300]; private final int[] finishCounterHistory = new int[startCounterHistory.length]; + private final int[] updateDelayHistory = new int[startCounterHistory.length]; private volatile int executionTime = 3; @@ -54,8 +53,14 @@ public static void main(String[] args) { private final Random rng = new Random(); + private long lastStartUpdateTime = System.nanoTime(); + private final AtomicLong lastUpdateDelay = new AtomicLong(0); private void updateFunction(UpdateLoop updater) { + long startUpdateTime = System.nanoTime(); + lastUpdateDelay.set(startUpdateTime - lastStartUpdateTime); + lastStartUpdateTime = startUpdateTime; + startUpdateCounter.incrementAndGet(); //noinspection StatementWithEmptyBody while (spaceDown) ; @@ -88,13 +93,15 @@ public void paint(Graphics g) { int finishValue = finishUpdateCounter.getAndSet(0); System.arraycopy(startCounterHistory, 0, startCounterHistory, 1, length - 1); System.arraycopy(finishCounterHistory, 0, finishCounterHistory, 1, length - 1); + System.arraycopy(updateDelayHistory, 0, updateDelayHistory, 1, length - 1); startCounterHistory[0] = startValue; finishCounterHistory[0] = finishValue; + updateDelayHistory[0] = (int) (5 * lastUpdateDelay.getAndSet(0) / 1000_000L); int baseWidth = 4; int baseHeight = 40; int offsetX = 10 + baseWidth; - int offsetY = height - 200; + int offsetY = height - 400; g.setColor(new Color(0, 150, 255)); for (int index = 0; index < length; index++) { @@ -112,6 +119,15 @@ public void paint(Graphics g) { } } + offsetY += 350; + g.setColor(new Color(250, 150, 0)); + for (int index = 0; index < length; index++) { + int barHeight = updateDelayHistory[index]; + if (barHeight > 0) { + g.fillRect(width - offsetX - baseWidth * index, offsetY - barHeight, baseWidth, barHeight); + } + } + g.setColor(Color.BLACK); g.setFont(new Font("TimesRoman", Font.PLAIN, 20)); g.drawString("Updates per second = " + updateCounter.getValue(), 15, 80); @@ -125,14 +141,17 @@ public void paint(Graphics g) { g.drawString("Execution time = " + executionTime + "ms", 15, 200); g.drawString("Spike time = " + spikeTime + "ms", 15, 230); g.drawString("Spike probability = " + spikeProbability + "%", 15, 260); + g.drawString("Maximum backlog = " + updateLoop.getMaximumBacklog() + "ns", 15, 290); g.drawString("Use left/right arrow key to change the period", 600, 80); g.drawString("Use the a/d keys to change the execution time", 600, 110); g.drawString("Use shift + left/right arrow key to change the spike time", 600, 140); g.drawString("Use shift + a/d keys to change the spike chance", 600, 170); g.drawString("Hold the space bar to block the current or next update", 600, 200); - g.drawString("The blue staves indicate how many updates started between each frame", 600, 230); - g.drawString("The pink staves indicate how many updates finished between each frame", 600, 260); + g.drawString("Use the e/q keys to change the maximum backlog", 600, 230); + g.drawString("The blue staves indicate how many updates started between each frame", 600, 260); + g.drawString("The pink staves indicate how many updates finished between each frame", 600, 290); + g.drawString("The orange staves indicate the difference between the start times of updates", 600, 320); Toolkit.getDefaultToolkit().sync(); } @@ -145,16 +164,19 @@ public void keyTyped(KeyEvent keyEvent) {} public void keyPressed(KeyEvent keyEvent) { int code = keyEvent.getKeyCode(); long period = updateLoop.getPeriod(); + long maximumBacklog = updateLoop.getMaximumBacklog(); if (keyEvent.isShiftDown()) { if (code == VK_LEFT && spikeTime > 0) spikeTime -= 10; if (code == VK_RIGHT) spikeTime += 10; if (code == VK_A && spikeProbability > 0) spikeProbability -= 1; if (code == VK_D && spikeProbability < 100) spikeProbability += 1; } else { - if (code == VK_LEFT && period > 100_000) updateLoop.setPeriod(period / 2); + if (code == VK_LEFT && period > 10) updateLoop.setPeriod(period / 2); if (code == VK_RIGHT && period < 100_000_000_000L) updateLoop.setPeriod(period * 2); if (code == VK_A && executionTime > 0) executionTime -= 1; if (code == VK_D) executionTime += 1; + if (code == VK_Q && maximumBacklog > 100) updateLoop.setMaximumBacklog(maximumBacklog / 2); + if (code == VK_E && maximumBacklog < 100_000_000_000L) updateLoop.setMaximumBacklog(maximumBacklog * 2); } if (code == VK_SPACE) spaceDown = true; } diff --git a/update-loops-overview.md b/update-loops-overview.md index 30b936a..d872d9d 100644 --- a/update-loops-overview.md +++ b/update-loops-overview.md @@ -115,7 +115,7 @@ the update function to be called 100 times per second for 2 minutes long (rather than the desired update frequency of 20 times). -## Sliding window +## Limit maximum backlog Whether this behavior is desired, depends on the application. For games, it probably isn't (imagine all enemies suddenly running 5 times as fast @@ -126,25 +126,16 @@ you should use an approach that is more robust than the naive sleep approach, but is not as desperate as the smarter sleeping approach. -For instance, instead of counting the number of updates -since the start of the application, you could count the -number of updates the past second. When a single update -invocation takes too long, the system will simply cancel -or shorten the `sleepTime` of the next iteration (and -possibly affect some more iterations). When the execution -time of the update function is consistently larger than -the desired update period, the system won't sleep -because the number of updates per second is always smaller -than desired. When the execution time of the update -function suddenly drops, the system will try to compensate -for the *missed updates during the last second* rather -than all missed updates during the peak hours. Thus the -system will continue normal operation after at most 1 -second. +The lagg problem of the *smarter sleeping* approach can +be solved by limiting the maximum backlog: when the +backlog is larger than some constant, any additional +backlog should be discarded. This can be implemented by +increasing the `startTime` by the additional backlog. ## The `UpdateLoop` class -The `UpdateLoop` class of this library uses a sliding -window to track the number of updates that happened -during the past N updates. Both the update period and the -length of the sliding window are configurable. Together, -they determine how much time it 'looks back' \ No newline at end of file +The `UpdateLoop` class of this library implements the +*smarter sleeping* approach with a maximum backlog. +It is slightly more complicated because it also allows +the period and maximum backlog to be changed at any time. +Instead of trying to implement all this logic yourself, +you can just use `UpdateLoop`. \ No newline at end of file diff --git a/update-monitor.png b/update-monitor.png index 0d91cffd3edcc65547256de02fcda1e453ad5f79..e4570b40a0f0d256f6010af8d4abff5bbb650f91 100644 GIT binary patch literal 26727 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 literal 19884 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