mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-25 02:27:38 +01:00
Improve tasks performance
This commit is contained in:
parent
b906bd89ce
commit
024ba736ce
@ -0,0 +1,35 @@
|
||||
package net.minestom.jmh.timer;
|
||||
|
||||
import net.minestom.server.timer.Scheduler;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Fork(3)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Benchmark)
|
||||
public class SchedulerTickBenchmark {
|
||||
|
||||
@Param({"0", "1", "5"})
|
||||
public int tickTasks;
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
this.scheduler = Scheduler.newScheduler();
|
||||
for (int i = 0; i < this.tickTasks; i++) {
|
||||
this.scheduler.scheduleTask(() -> {
|
||||
}, TaskSchedule.nextTick(), TaskSchedule.nextTick());
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public void call() {
|
||||
this.scheduler.processTick();
|
||||
}
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
package net.minestom.server.timer;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import org.jctools.queues.MpscUnboundedArrayQueue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -26,9 +24,6 @@ final class SchedulerImpl implements Scheduler {
|
||||
private static final ForkJoinPool EXECUTOR = ForkJoinPool.commonPool();
|
||||
|
||||
private final MpscUnboundedArrayQueue<TaskImpl> taskQueue = new MpscUnboundedArrayQueue<>(64);
|
||||
private final IntSet registeredTasks = new IntOpenHashSet();
|
||||
private final IntSet parkedTasks = new IntOpenHashSet();
|
||||
|
||||
// Tasks scheduled on a certain tick
|
||||
private final Int2ObjectAVLTreeMap<List<TaskImpl>> tickTaskQueue = new Int2ObjectAVLTreeMap<>();
|
||||
|
||||
@ -68,36 +63,17 @@ final class SchedulerImpl implements Scheduler {
|
||||
@Override
|
||||
public @NotNull Task submitTask(@NotNull Supplier<TaskSchedule> task,
|
||||
@NotNull ExecutionType executionType) {
|
||||
final TaskImpl taskRef = register(task, executionType);
|
||||
final TaskImpl taskRef = new TaskImpl(TASK_COUNTER.getAndIncrement(), task,
|
||||
executionType, this);
|
||||
handleTask(taskRef);
|
||||
return taskRef;
|
||||
}
|
||||
|
||||
synchronized void unparkTask(TaskImpl task) {
|
||||
if (parkedTasks.remove(task.id()))
|
||||
void unparkTask(TaskImpl task) {
|
||||
if (task.tryUnpark())
|
||||
this.taskQueue.relaxedOffer(task);
|
||||
}
|
||||
|
||||
synchronized boolean isTaskParked(TaskImpl task) {
|
||||
return parkedTasks.contains(task.id());
|
||||
}
|
||||
|
||||
synchronized void cancelTask(TaskImpl task) {
|
||||
this.registeredTasks.remove(task.id());
|
||||
}
|
||||
|
||||
synchronized boolean isTaskAlive(TaskImpl task) {
|
||||
return registeredTasks.contains(task.id());
|
||||
}
|
||||
|
||||
private synchronized TaskImpl register(@NotNull Supplier<TaskSchedule> task,
|
||||
@NotNull ExecutionType executionType) {
|
||||
TaskImpl taskRef = new TaskImpl(TASK_COUNTER.getAndIncrement(), task,
|
||||
executionType, this);
|
||||
this.registeredTasks.add(taskRef.id());
|
||||
return taskRef;
|
||||
}
|
||||
|
||||
private void safeExecute(TaskImpl task) {
|
||||
// Prevent the task from being executed in the current thread
|
||||
// By either adding the task to the execution queue or submitting it to the pool
|
||||
@ -120,11 +96,9 @@ final class SchedulerImpl implements Scheduler {
|
||||
} else if (schedule instanceof TaskScheduleImpl.FutureSchedule futureSchedule) {
|
||||
futureSchedule.future().thenRun(() -> safeExecute(task));
|
||||
} else if (schedule instanceof TaskScheduleImpl.Park) {
|
||||
synchronized (this) {
|
||||
this.parkedTasks.add(task.id());
|
||||
}
|
||||
task.parked = true;
|
||||
} else if (schedule instanceof TaskScheduleImpl.Stop) {
|
||||
cancelTask(task);
|
||||
task.cancel();
|
||||
} else if (schedule instanceof TaskScheduleImpl.Immediate) {
|
||||
this.taskQueue.relaxedOffer(task);
|
||||
}
|
||||
|
@ -1,30 +1,102 @@
|
||||
package net.minestom.server.timer;
|
||||
|
||||
import it.unimi.dsi.fastutil.HashCommon;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
record TaskImpl(int id,
|
||||
final class TaskImpl implements Task {
|
||||
private static final VarHandle PARKED;
|
||||
|
||||
static {
|
||||
try {
|
||||
PARKED = MethodHandles.lookup().findVarHandle(TaskImpl.class, "parked", boolean.class);
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final int id;
|
||||
private final @NotNull Supplier<TaskSchedule> task;
|
||||
private final @NotNull ExecutionType executionType;
|
||||
private final @NotNull SchedulerImpl owner;
|
||||
|
||||
volatile boolean alive;
|
||||
volatile boolean parked;
|
||||
|
||||
TaskImpl(int id,
|
||||
@NotNull Supplier<TaskSchedule> task,
|
||||
@NotNull ExecutionType executionType,
|
||||
@NotNull SchedulerImpl owner) implements Task {
|
||||
@NotNull SchedulerImpl owner) {
|
||||
this.id = id;
|
||||
this.task = task;
|
||||
this.executionType = executionType;
|
||||
this.owner = owner;
|
||||
this.alive = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unpark() {
|
||||
this.owner.unparkTask(this);
|
||||
}
|
||||
|
||||
boolean tryUnpark() {
|
||||
return PARKED.compareAndSet(this, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isParked() {
|
||||
return owner.isTaskParked(this);
|
||||
return parked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.owner.cancelTask(this);
|
||||
this.alive = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return owner.isTaskAlive(this);
|
||||
return alive;
|
||||
}
|
||||
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @NotNull Supplier<TaskSchedule> task() {
|
||||
return task;
|
||||
}
|
||||
|
||||
public @NotNull ExecutionType executionType() {
|
||||
return executionType;
|
||||
}
|
||||
|
||||
public @NotNull SchedulerImpl owner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null || obj.getClass() != this.getClass()) return false;
|
||||
var that = (TaskImpl) obj;
|
||||
return this.id == that.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCommon.murmurHash3(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TaskImpl[" +
|
||||
"id=" + id + ", " +
|
||||
"task=" + task + ", " +
|
||||
"executionType=" + executionType + ", " +
|
||||
"owner=" + owner + ']';
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user