From 4fa7f50534c38dfb336cef9594cd35654684309f Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Thu, 15 Dec 2022 22:12:53 +0000 Subject: [PATCH] Time fs and peripheral operations --- .../dan200/computercraft/core/apis/FSAPI.java | 31 ++++++--------- .../core/apis/IAPIEnvironment.java | 16 +++++++- .../core/apis/PeripheralAPI.java | 5 ++- .../core/computer/Environment.java | 10 +---- .../computercraft/core/metrics/Metrics.java | 8 ++-- .../core/metrics/OperationTimer.java | 38 +++++++++++++++++++ .../core/ComputerTestDelegate.java | 2 +- .../test/core/apis/BasicApiEnvironment.java | 9 ++--- 8 files changed, 77 insertions(+), 42 deletions(-) create mode 100644 projects/core/src/main/java/dan200/computercraft/core/metrics/OperationTimer.java diff --git a/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java index eeb3b4b95..5d3ed8045 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -102,8 +102,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final String[] list(String path) throws LuaException { - environment.observe(Metrics.FS_OPS); - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { return getFileSystem().list(path); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -184,7 +183,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final long getSize(String path) throws LuaException { - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { return getFileSystem().getSize(path); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -199,7 +198,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final boolean exists(String path) { - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { return getFileSystem().exists(path); } catch (FileSystemException e) { return false; @@ -214,7 +213,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final boolean isDir(String path) { - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { return getFileSystem().isDir(path); } catch (FileSystemException e) { return false; @@ -229,7 +228,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final boolean isReadOnly(String path) { - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { return getFileSystem().isReadOnly(path); } catch (FileSystemException e) { return false; @@ -244,8 +243,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final void makeDir(String path) throws LuaException { - try { - environment.observe(Metrics.FS_OPS); + try (var ignored = environment.time(Metrics.FS_OPS)) { getFileSystem().makeDir(path); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -263,8 +261,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final void move(String path, String dest) throws LuaException { - try { - environment.observe(Metrics.FS_OPS); + try (var ignored = environment.time(Metrics.FS_OPS)) { getFileSystem().move(path, dest); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -282,8 +279,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final void copy(String path, String dest) throws LuaException { - try { - environment.observe(Metrics.FS_OPS); + try (var ignored = environment.time(Metrics.FS_OPS)) { getFileSystem().copy(path, dest); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -301,8 +297,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final void delete(String path) throws LuaException { - try { - environment.observe(Metrics.FS_OPS); + try (var ignored = environment.time(Metrics.FS_OPS)) { getFileSystem().delete(path); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -365,8 +360,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final Object[] open(String path, String mode) throws LuaException { - environment.observe(Metrics.FS_OPS); - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { switch (mode) { case "r" -> { // Open the file for reading, then create a wrapper around the reader @@ -465,8 +459,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final String[] find(String path) throws LuaException { - try { - environment.observe(Metrics.FS_OPS); + try (var ignored = environment.time(Metrics.FS_OPS)) { return getFileSystem().find(path); } catch (FileSystemException e) { throw new LuaException(e.getMessage()); @@ -516,7 +509,7 @@ public class FSAPI implements ILuaAPI { */ @LuaFunction public final Map attributes(String path) throws LuaException { - try { + try (var ignored = environment.time(Metrics.FS_OPS)) { var attributes = getFileSystem().getAttributes(path); Map result = new HashMap<>(); result.put("modification", getFileTime(attributes.lastModifiedTime())); diff --git a/projects/core/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java b/projects/core/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java index 34d893058..c5735b686 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java +++ b/projects/core/src/main/java/dan200/computercraft/core/apis/IAPIEnvironment.java @@ -11,7 +11,9 @@ import dan200.computercraft.core.computer.ComputerEnvironment; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.GlobalEnvironment; import dan200.computercraft.core.filesystem.FileSystem; +import dan200.computercraft.core.metrics.OperationTimer; import dan200.computercraft.core.metrics.Metric; +import dan200.computercraft.core.metrics.MetricsObserver; import dan200.computercraft.core.terminal.Terminal; import javax.annotation.Nullable; @@ -68,7 +70,17 @@ public interface IAPIEnvironment { void cancelTimer(int id); - void observe(Metric.Event event, long change); + MetricsObserver metrics(); - void observe(Metric.Counter counter); + default void observe(Metric.Event event, long change) { + metrics().observe(event, change); + } + + default void observe(Metric.Counter counter) { + metrics().observe(counter); + } + + default OperationTimer time(Metric.Event event) { + return OperationTimer.start(metrics(), event); + } } diff --git a/projects/core/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/projects/core/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index e62a97634..b44054cac 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/projects/core/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -93,8 +93,9 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange if (method == null) throw new LuaException("No such method " + methodName); - environment.observe(Metrics.PERIPHERAL_OPS); - return method.apply(peripheral, context, this, arguments); + try (var ignored = environment.time(Metrics.PERIPHERAL_OPS)) { + return method.apply(peripheral, context, this, arguments); + } } // IComputerAccess implementation diff --git a/projects/core/src/main/java/dan200/computercraft/core/computer/Environment.java b/projects/core/src/main/java/dan200/computercraft/core/computer/Environment.java index 76b6a9a95..4274c6024 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/projects/core/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -10,7 +10,6 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.WorkMonitor; import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.filesystem.FileSystem; -import dan200.computercraft.core.metrics.Metric; import dan200.computercraft.core.metrics.MetricsObserver; import dan200.computercraft.core.terminal.Terminal; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -313,13 +312,8 @@ public final class Environment implements IAPIEnvironment { } @Override - public void observe(Metric.Event event, long change) { - metrics.observe(event, change); - } - - @Override - public void observe(Metric.Counter counter) { - metrics.observe(counter); + public MetricsObserver metrics() { + return metrics; } private static class Timer { diff --git a/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java b/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java index fedce2e51..2882d341a 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java +++ b/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java @@ -12,11 +12,11 @@ public final class Metrics { private Metrics() { } - public static final Metric.Event COMPUTER_TASKS = new Metric.Event("computer_tasks", "ms", Metric::formatTime); - public static final Metric.Event SERVER_TASKS = new Metric.Event("server_tasks", "ms", Metric::formatTime); + public static final Metric.Event COMPUTER_TASKS = new Metric.Event("computer_tasks", "ns", Metric::formatTime); + public static final Metric.Event SERVER_TASKS = new Metric.Event("server_tasks", "ns", Metric::formatTime); - public static final Metric.Counter PERIPHERAL_OPS = new Metric.Counter("peripheral"); - public static final Metric.Counter FS_OPS = new Metric.Counter("fs"); + public static final Metric.Event PERIPHERAL_OPS = new Metric.Event("peripheral", "ns", Metric::formatTime); + public static final Metric.Event FS_OPS = new Metric.Event("fs", "ns", Metric::formatTime); public static final Metric.Counter HTTP_REQUESTS = new Metric.Counter("http_requests"); public static final Metric.Event HTTP_UPLOAD = new Metric.Event("http_upload", "bytes", Metric::formatBytes); diff --git a/projects/core/src/main/java/dan200/computercraft/core/metrics/OperationTimer.java b/projects/core/src/main/java/dan200/computercraft/core/metrics/OperationTimer.java new file mode 100644 index 000000000..d9ed84a98 --- /dev/null +++ b/projects/core/src/main/java/dan200/computercraft/core/metrics/OperationTimer.java @@ -0,0 +1,38 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.core.metrics; + +/** + * Times how long an operation takes, observing the duration as a {@link Metric.Event}. + */ +public final class OperationTimer implements AutoCloseable { + private final MetricsObserver observer; + private final Metric.Event event; + private final long start; + + private OperationTimer(MetricsObserver observer, Metric.Event event, long start) { + this.observer = observer; + this.event = event; + this.start = start; + } + + /** + * Start a timer for an operation. + * + * @param observer The metrics observer to submit the operation to. + * @param event The event to observe. The resulting value will be a duration in nanoseconds, and so its + * {@linkplain Metric#unit() unit} should be {@code "ns"}. + * @return The running operation timer. + */ + public static OperationTimer start(MetricsObserver observer, Metric.Event event) { + return new OperationTimer(observer, event, System.nanoTime()); + } + + @Override + public void close() { + observer.observe(event, System.nanoTime() - start); + } +} diff --git a/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 95d38e535..71c9dc8b8 100644 --- a/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -150,7 +150,7 @@ public class ComputerTestDelegate { lock.lockInterruptibly(); try { var remaining = TIMEOUT; - while (remaining > 0 & tests == null) { + while (remaining > 0 && tests == null) { tick(); if (hasTests.awaitNanos(TICK_TIME) > 0) break; remaining -= TICK_TIME; diff --git a/projects/core/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java b/projects/core/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java index 42dc79ce0..0dbaa7f7f 100644 --- a/projects/core/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java +++ b/projects/core/src/testFixtures/java/dan200/computercraft/test/core/apis/BasicApiEnvironment.java @@ -12,7 +12,7 @@ import dan200.computercraft.core.computer.ComputerEnvironment; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.GlobalEnvironment; import dan200.computercraft.core.filesystem.FileSystem; -import dan200.computercraft.core.metrics.Metric; +import dan200.computercraft.core.metrics.MetricsObserver; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.test.core.computer.BasicEnvironment; @@ -123,10 +123,7 @@ public abstract class BasicApiEnvironment implements IAPIEnvironment { } @Override - public void observe(Metric.Event summary, long value) { - } - - @Override - public void observe(Metric.Counter counter) { + public MetricsObserver metrics() { + return environment.getMetrics(); } }