mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-27 17:34:48 +00:00
Move MainThread config to its own class
This means the config is no longer stored as static fields, which is a little cleaner. Would like to move everything else in the future, but this is a good first step.
This commit is contained in:
parent
590ef86c93
commit
5082b1677c
@ -12,6 +12,7 @@ import dan200.computercraft.core.ComputerContext;
|
||||
import dan200.computercraft.core.computer.ComputerThread;
|
||||
import dan200.computercraft.core.computer.GlobalEnvironment;
|
||||
import dan200.computercraft.core.computer.mainthread.MainThread;
|
||||
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
||||
import dan200.computercraft.core.lua.CobaltLuaMachine;
|
||||
import dan200.computercraft.core.lua.ILuaMachine;
|
||||
import dan200.computercraft.impl.AbstractComputerCraftAPI;
|
||||
@ -65,7 +66,7 @@ public final class ServerContext {
|
||||
private ServerContext(MinecraftServer server) {
|
||||
this.server = server;
|
||||
storageDir = server.getWorldPath(FOLDER);
|
||||
mainThread = new MainThread();
|
||||
mainThread = new MainThread(mainThreadConfig);
|
||||
context = new ComputerContext(
|
||||
new Environment(server),
|
||||
new ComputerThread(ConfigSpec.computerThreads.get()),
|
||||
@ -215,4 +216,16 @@ public final class ServerContext {
|
||||
return ComputerCraftAPI.MOD_ID + "/" + ComputerCraftAPI.getInstalledVersion();
|
||||
}
|
||||
}
|
||||
|
||||
private static final MainThreadConfig mainThreadConfig = new MainThreadConfig() {
|
||||
@Override
|
||||
public long maxGlobalTime() {
|
||||
return TimeUnit.MILLISECONDS.toNanos(ConfigSpec.maxMainGlobalTime.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long maxComputerTime() {
|
||||
return TimeUnit.MILLISECONDS.toNanos(ConfigSpec.maxMainComputerTime.get());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import dan200.computercraft.core.CoreConfig;
|
||||
import dan200.computercraft.core.Logging;
|
||||
import dan200.computercraft.core.apis.http.NetworkUtils;
|
||||
import dan200.computercraft.core.apis.http.options.Action;
|
||||
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -155,14 +156,14 @@ public final class ConfigSpec {
|
||||
milliseconds.
|
||||
Note, we will quite possibly go over this limit, as there's no way to tell how
|
||||
long a will take - this aims to be the upper bound of the average time.""")
|
||||
.defineInRange("max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis(CoreConfig.maxMainGlobalTime), 1, Integer.MAX_VALUE);
|
||||
.defineInRange("max_main_global_time", (int) TimeUnit.NANOSECONDS.toMillis(MainThreadConfig.DEFAULT_MAX_GLOBAL_TIME), 1, Integer.MAX_VALUE);
|
||||
|
||||
maxMainComputerTime = builder
|
||||
.comment("""
|
||||
The ideal maximum time a computer can execute for in a tick, in milliseconds.
|
||||
Note, we will quite possibly go over this limit, as there's no way to tell how
|
||||
long a will take - this aims to be the upper bound of the average time.""")
|
||||
.defineInRange("max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis(CoreConfig.maxMainComputerTime), 1, Integer.MAX_VALUE);
|
||||
.defineInRange("max_main_computer_time", (int) TimeUnit.NANOSECONDS.toMillis(MainThreadConfig.DEFAULT_MAX_COMPUTER_TIME), 1, Integer.MAX_VALUE);
|
||||
|
||||
builder.pop();
|
||||
}
|
||||
@ -348,10 +349,6 @@ public final class ConfigSpec {
|
||||
CoreConfig.defaultComputerSettings = defaultComputerSettings.get();
|
||||
Config.commandRequireCreative = commandRequireCreative.get();
|
||||
|
||||
// Execution
|
||||
CoreConfig.maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos(maxMainGlobalTime.get());
|
||||
CoreConfig.maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos(maxMainComputerTime.get());
|
||||
|
||||
// Update our log filter if needed.
|
||||
var logFilter = MarkerFilter.createFilter(
|
||||
Logging.COMPUTER_ERROR.getName(),
|
||||
|
@ -9,7 +9,6 @@ import dan200.computercraft.core.apis.http.options.AddressRule;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Config options for ComputerCraft's Lua runtime.
|
||||
@ -25,9 +24,6 @@ public final class CoreConfig {
|
||||
public static boolean disableLua51Features = false;
|
||||
public static String defaultComputerSettings = "";
|
||||
|
||||
public static long maxMainGlobalTime = TimeUnit.MILLISECONDS.toNanos(10);
|
||||
public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos(5);
|
||||
|
||||
public static boolean httpEnabled = true;
|
||||
public static boolean httpWebsocketEnabled = true;
|
||||
public static List<AddressRule> httpRules = List.of(
|
||||
|
@ -18,7 +18,6 @@ import java.util.Map;
|
||||
/**
|
||||
* Implementation of {@link IComputerAccess}/{@link IComputerSystem} for usage by externally registered APIs.
|
||||
*
|
||||
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||
* @see ILuaAPIFactory
|
||||
* @see ApiWrapper
|
||||
*/
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package dan200.computercraft.core.computer.mainthread;
|
||||
|
||||
import dan200.computercraft.core.CoreConfig;
|
||||
import dan200.computercraft.core.metrics.MetricsObserver;
|
||||
|
||||
import java.util.HashSet;
|
||||
@ -20,7 +19,7 @@ import java.util.TreeSet;
|
||||
* {@link MainThread} starts cool, and runs as many tasks as it can in the current {@link #budget}ns. Any external tasks
|
||||
* (those run by tile entities, etc...) will also consume the budget
|
||||
* <p>
|
||||
* Next tick, we add {@link CoreConfig#maxMainGlobalTime} to our budget (clamp it to that value too). If we're still
|
||||
* Next tick, we add {@link MainThreadConfig#maxGlobalTime()} to our budget (clamp it to that value too). If we're still
|
||||
* over budget, then we should not execute <em>any</em> work (either as part of {@link MainThread} or externally).
|
||||
*/
|
||||
public final class MainThread implements MainThreadScheduler {
|
||||
@ -35,6 +34,8 @@ public final class MainThread implements MainThreadScheduler {
|
||||
return at < bt ? -1 : 1;
|
||||
});
|
||||
|
||||
final MainThreadConfig config;
|
||||
|
||||
/**
|
||||
* The set of executors which went over budget in a previous tick, and are waiting for their time to run down.
|
||||
*
|
||||
@ -66,6 +67,11 @@ public final class MainThread implements MainThreadScheduler {
|
||||
private long minimumTime = 0;
|
||||
|
||||
public MainThread() {
|
||||
this(MainThreadConfig.DEFAULT);
|
||||
}
|
||||
|
||||
public MainThread(MainThreadConfig config) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
void queue(MainThreadExecutor executor) {
|
||||
@ -79,7 +85,7 @@ public final class MainThread implements MainThreadScheduler {
|
||||
var newRuntime = minimumTime;
|
||||
|
||||
// Slow down new computers a little bit.
|
||||
if (executor.virtualTime == 0) newRuntime += CoreConfig.maxMainComputerTime;
|
||||
if (executor.virtualTime == 0) newRuntime += config.maxComputerTime();
|
||||
|
||||
executor.virtualTime = Math.max(newRuntime, executor.virtualTime);
|
||||
|
||||
@ -110,7 +116,8 @@ public final class MainThread implements MainThreadScheduler {
|
||||
// Of course, we'll go over the MAX_TICK_TIME most of the time, but eventually that overrun will accumulate
|
||||
// and we'll skip a whole tick - bringing the average back down again.
|
||||
currentTick++;
|
||||
budget = Math.min(budget + CoreConfig.maxMainGlobalTime, CoreConfig.maxMainGlobalTime);
|
||||
var maxGlobal = config.maxGlobalTime();
|
||||
budget = Math.min(budget + maxGlobal, maxGlobal);
|
||||
canExecute = budget > 0;
|
||||
|
||||
// Cool down any warm computers.
|
||||
|
@ -0,0 +1,50 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.computer.mainthread;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Options to configure the {@link MainThread}.
|
||||
*/
|
||||
public interface MainThreadConfig {
|
||||
/**
|
||||
* The default value for {@link #maxGlobalTime()}.
|
||||
*/
|
||||
long DEFAULT_MAX_GLOBAL_TIME = TimeUnit.MILLISECONDS.toNanos(10);
|
||||
|
||||
/**
|
||||
* The default value for {@link #maxComputerTime()}.
|
||||
*/
|
||||
long DEFAULT_MAX_COMPUTER_TIME = TimeUnit.MILLISECONDS.toNanos(5);
|
||||
|
||||
/**
|
||||
* The default config.
|
||||
*/
|
||||
MainThreadConfig DEFAULT = new Basic(DEFAULT_MAX_GLOBAL_TIME, DEFAULT_MAX_COMPUTER_TIME);
|
||||
|
||||
/**
|
||||
* The ideal maximum time that can be spent executing tasks in a tick, in nanoseconds.
|
||||
*
|
||||
* @return The max time a that can be spent executing tasks in a single tick.
|
||||
*/
|
||||
long maxGlobalTime();
|
||||
|
||||
/**
|
||||
* The ideal maximum time a computer can execute for in a tick, in nanoseconds.
|
||||
*
|
||||
* @return The max time a computer can execute in a single tick.
|
||||
*/
|
||||
long maxComputerTime();
|
||||
|
||||
/**
|
||||
* A basic implementation of {@link MainThreadConfig}, which works on constant values.
|
||||
*
|
||||
* @param maxGlobalTime See {@link MainThreadConfig#maxGlobalTime()}.
|
||||
* @param maxComputerTime See {@link MainThreadConfig#maxComputerTime()}.
|
||||
*/
|
||||
record Basic(long maxGlobalTime, long maxComputerTime) implements MainThreadConfig {
|
||||
}
|
||||
}
|
@ -5,7 +5,6 @@
|
||||
package dan200.computercraft.core.computer.mainthread;
|
||||
|
||||
import dan200.computercraft.api.peripheral.WorkMonitor;
|
||||
import dan200.computercraft.core.CoreConfig;
|
||||
import dan200.computercraft.core.computer.Computer;
|
||||
import dan200.computercraft.core.metrics.Metrics;
|
||||
import dan200.computercraft.core.metrics.MetricsObserver;
|
||||
@ -22,7 +21,7 @@ import java.util.concurrent.TimeUnit;
|
||||
* those run elsewhere (such as during the turtle's tick). In order to handle this, the executor goes through three
|
||||
* stages:
|
||||
* <p>
|
||||
* When {@link State#COOL}, the computer is allocated {@link CoreConfig#maxMainComputerTime}ns to execute any work
|
||||
* When {@link State#COOL}, the computer is allocated {@link MainThreadConfig#maxComputerTime()}ns to execute any work
|
||||
* this tick. At the beginning of the tick, we execute as many {@link MainThread} tasks as possible, until our
|
||||
* time-frame or the global time frame has expired.
|
||||
* <p>
|
||||
@ -33,13 +32,13 @@ import java.util.concurrent.TimeUnit;
|
||||
* {@link State#HOT}. This means it will no longer be able to execute {@link MainThread} tasks (though will still
|
||||
* execute tile entity tasks, in order to prevent the main thread from exhausting work every tick).
|
||||
* <p>
|
||||
* At the beginning of the next tick, we increment the budget e by {@link CoreConfig#maxMainComputerTime} and any
|
||||
* At the beginning of the next tick, we increment the budget e by {@link MainThreadConfig#maxComputerTime()} and any
|
||||
* {@link State#HOT} executors are marked as {@link State#COOLING}. They will remain cooling until their budget is fully
|
||||
* replenished (is equal to {@link CoreConfig#maxMainComputerTime}). Note, this is different to {@link MainThread},
|
||||
* replenished (is equal to {@link MainThreadConfig#maxComputerTime()}). Note, this is different to {@link MainThread},
|
||||
* which allows running when it has any budget left. When cooling, <em>no</em> tasks are executed - be they on the tile
|
||||
* entity or main thread.
|
||||
* <p>
|
||||
* This mechanism means that, on average, computers will use at most {@link CoreConfig#maxMainComputerTime}ns per
|
||||
* This mechanism means that, on average, computers will use at most {@link MainThreadConfig#maxComputerTime()}ns per
|
||||
* second, but one task source will not prevent others from executing.
|
||||
*
|
||||
* @see MainThread
|
||||
@ -189,7 +188,7 @@ final class MainThreadExecutor implements MainThreadScheduler.Executor {
|
||||
// #tickCooling() isn't called, and so we didn't overrun the previous tick.
|
||||
if (currentTick != scheduler.currentTick()) {
|
||||
currentTick = scheduler.currentTick();
|
||||
budget = CoreConfig.maxMainComputerTime;
|
||||
budget = scheduler.config.maxComputerTime();
|
||||
}
|
||||
|
||||
budget -= time;
|
||||
@ -202,15 +201,16 @@ final class MainThreadExecutor implements MainThreadScheduler.Executor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Move this executor forward one tick, replenishing the budget by {@link CoreConfig#maxMainComputerTime}.
|
||||
* Move this executor forward one tick, replenishing the budget by {@link MainThreadConfig#maxComputerTime()}.
|
||||
*
|
||||
* @return Whether this executor has cooled down, and so is safe to run again.
|
||||
*/
|
||||
boolean tickCooling() {
|
||||
state = State.COOLING;
|
||||
currentTick = scheduler.currentTick();
|
||||
budget = Math.min(budget + CoreConfig.maxMainComputerTime, CoreConfig.maxMainComputerTime);
|
||||
if (budget < CoreConfig.maxMainComputerTime) return false;
|
||||
var maxTime = scheduler.config.maxComputerTime();
|
||||
budget = Math.min(budget + maxTime, maxTime);
|
||||
if (budget < maxTime) return false;
|
||||
|
||||
state = State.COOL;
|
||||
synchronized (queueLock) {
|
||||
|
@ -10,8 +10,8 @@ import dan200.computercraft.api.lua.ILuaAPI;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.core.ComputerContext;
|
||||
import dan200.computercraft.core.CoreConfig;
|
||||
import dan200.computercraft.core.computer.mainthread.MainThread;
|
||||
import dan200.computercraft.core.computer.mainthread.MainThreadConfig;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.test.core.computer.BasicEnvironment;
|
||||
import dan200.computercraft.test.core.filesystem.MemoryMount;
|
||||
@ -46,10 +46,8 @@ public class ComputerBootstrap {
|
||||
}
|
||||
|
||||
public static void run(WritableMount mount, Consumer<Computer> setup, int maxTicks) {
|
||||
CoreConfig.maxMainComputerTime = CoreConfig.maxMainGlobalTime = Integer.MAX_VALUE;
|
||||
|
||||
var term = new Terminal(51, 19, true);
|
||||
var mainThread = new MainThread();
|
||||
var mainThread = new MainThread(new MainThreadConfig.Basic(Integer.MAX_VALUE, Integer.MAX_VALUE));
|
||||
var environment = new BasicEnvironment(mount);
|
||||
var context = new ComputerContext(environment, 1, mainThread);
|
||||
final var computer = new Computer(context, environment, term, 0);
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.terminal;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.terminal;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.test.core;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.test.core.terminal;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user