mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-29 05:55:44 +01:00
Improvements to DataFixers for performance
Mojang asked me to make some changes, so applied them here.
This commit is contained in:
parent
77c6bafe46
commit
04b8268cf1
@ -1,4 +1,4 @@
|
|||||||
From ab1a408584e0f6e7e28319956b32047f552bf668 Mon Sep 17 00:00:00 2001
|
From 296dfee228fa6471e26b9d4d697ba514cf5db998 Mon Sep 17 00:00:00 2001
|
||||||
From: Aikar <aikar@aikar.co>
|
From: Aikar <aikar@aikar.co>
|
||||||
Date: Mon, 3 Sep 2018 22:18:38 -0400
|
Date: Mon, 3 Sep 2018 22:18:38 -0400
|
||||||
Subject: [PATCH] Fix concurrency and performance issues in DataFixers
|
Subject: [PATCH] Fix concurrency and performance issues in DataFixers
|
||||||
@ -75,52 +75,38 @@ index 2c259d74e9..17481fb6e6 100644
|
|||||||
return Either.right(new Type.FieldNotFoundException(String.format("Type error for choice type \"%s\": expected type: %s, actual type: %s)", name, targetType, elementType)));
|
return Either.right(new Type.FieldNotFoundException(String.format("Type error for choice type \"%s\": expected type: %s, actual type: %s)", name, targetType, elementType)));
|
||||||
}
|
}
|
||||||
diff --git a/src/main/java/com/mojang/datafixers/functions/PointFree.java b/src/main/java/com/mojang/datafixers/functions/PointFree.java
|
diff --git a/src/main/java/com/mojang/datafixers/functions/PointFree.java b/src/main/java/com/mojang/datafixers/functions/PointFree.java
|
||||||
index 0d88490f77..028942b8ea 100644
|
index 0d88490f77..4d2af956a0 100644
|
||||||
--- a/src/main/java/com/mojang/datafixers/functions/PointFree.java
|
--- a/src/main/java/com/mojang/datafixers/functions/PointFree.java
|
||||||
+++ b/src/main/java/com/mojang/datafixers/functions/PointFree.java
|
+++ b/src/main/java/com/mojang/datafixers/functions/PointFree.java
|
||||||
@@ -14,7 +14,7 @@ public abstract class PointFree<T> {
|
@@ -9,15 +9,19 @@ import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public abstract class PointFree<T> {
|
||||||
|
- private boolean initialized;
|
||||||
|
+ private volatile boolean initialized;
|
||||||
|
@Nullable
|
||||||
private Function<DynamicOps<?>, T> value;
|
private Function<DynamicOps<?>, T> value;
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
- public Function<DynamicOps<?>, T> evalCached() {
|
public Function<DynamicOps<?>, T> evalCached() {
|
||||||
+ public synchronized Function<DynamicOps<?>, T> evalCached() { // Paper
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialized = true;
|
- initialized = true;
|
||||||
value = eval();
|
- value = eval();
|
||||||
|
+ synchronized (this) {
|
||||||
|
+ if (!initialized) {
|
||||||
|
+ value = eval();
|
||||||
|
+ initialized = true;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
diff --git a/src/main/java/com/mojang/datafixers/schemas/Schema.java b/src/main/java/com/mojang/datafixers/schemas/Schema.java
|
diff --git a/src/main/java/com/mojang/datafixers/schemas/Schema.java b/src/main/java/com/mojang/datafixers/schemas/Schema.java
|
||||||
index 7c67d989e0..7faca88a88 100644
|
index 7c67d989e0..d81e8d1a1a 100644
|
||||||
--- a/src/main/java/com/mojang/datafixers/schemas/Schema.java
|
--- a/src/main/java/com/mojang/datafixers/schemas/Schema.java
|
||||||
+++ b/src/main/java/com/mojang/datafixers/schemas/Schema.java
|
+++ b/src/main/java/com/mojang/datafixers/schemas/Schema.java
|
||||||
@@ -20,8 +20,8 @@ import java.util.function.Function;
|
@@ -50,8 +50,11 @@ public class Schema {
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class Schema {
|
|
||||||
- protected final Object2IntMap<String> RECURSIVE_TYPES = new Object2IntOpenHashMap<>();
|
|
||||||
- private final Map<String, Supplier<TypeTemplate>> TYPE_TEMPLATES = Maps.newHashMap();
|
|
||||||
+ protected final Object2IntMap<String> RECURSIVE_TYPES = it.unimi.dsi.fastutil.objects.Object2IntMaps.synchronize(new Object2IntOpenHashMap<>()); // Paper
|
|
||||||
+ private final Map<String, Supplier<TypeTemplate>> TYPE_TEMPLATES = Maps.newConcurrentMap(); // Paper
|
|
||||||
private final Map<String, Type<?>> TYPES;
|
|
||||||
private final int versionKey;
|
|
||||||
private final String name;
|
|
||||||
@@ -37,26 +37,31 @@ public class Schema {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Map<String, Type<?>> buildTypes() {
|
|
||||||
- final Map<String, Type<?>> types = Maps.newHashMap();
|
|
||||||
+ final Map<String, Type<?>> types = Maps.newConcurrentMap(); // Paper
|
|
||||||
|
|
||||||
final List<TypeTemplate> templates = Lists.newArrayList();
|
|
||||||
|
|
||||||
+ synchronized (RECURSIVE_TYPES) { // Paper
|
|
||||||
for (final Object2IntMap.Entry<String> entry : RECURSIVE_TYPES.object2IntEntrySet()) {
|
|
||||||
templates.add(DSL.check(entry.getKey(), entry.getIntValue(), getTemplate(entry.getKey())));
|
|
||||||
- }
|
|
||||||
+ } } // Paper
|
|
||||||
|
|
||||||
final TypeTemplate choice = templates.stream().reduce(DSL::or).get();
|
|
||||||
final TypeFamily family = new RecursiveTypeFamily(name, choice);
|
|
||||||
|
|
||||||
+ synchronized (TYPE_TEMPLATES) { // Paper
|
|
||||||
for (final String name : TYPE_TEMPLATES.keySet()) {
|
for (final String name : TYPE_TEMPLATES.keySet()) {
|
||||||
final Type<?> type;
|
final Type<?> type;
|
||||||
- if (RECURSIVE_TYPES.containsKey(name)) {
|
- if (RECURSIVE_TYPES.containsKey(name)) {
|
||||||
@ -133,13 +119,7 @@ index 7c67d989e0..7faca88a88 100644
|
|||||||
} else {
|
} else {
|
||||||
type = getTemplate(name).apply(family).apply(-1);
|
type = getTemplate(name).apply(family).apply(-1);
|
||||||
}
|
}
|
||||||
types.put(name, type);
|
@@ -89,8 +92,11 @@ public class Schema {
|
||||||
- }
|
|
||||||
+ } } // Paper
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -89,8 +94,11 @@ public class Schema {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeTemplate id(final String name) {
|
public TypeTemplate id(final String name) {
|
||||||
@ -153,18 +133,6 @@ index 7c67d989e0..7faca88a88 100644
|
|||||||
}
|
}
|
||||||
return getTemplate(name);
|
return getTemplate(name);
|
||||||
}
|
}
|
||||||
@@ -138,9 +146,10 @@ public class Schema {
|
|
||||||
public void registerType(final boolean recursive, final DSL.TypeReference type, final Supplier<TypeTemplate> template) {
|
|
||||||
TYPE_TEMPLATES.put(type.typeName(), template);
|
|
||||||
// TODO: calculate recursiveness instead of hardcoding
|
|
||||||
+ synchronized (RECURSIVE_TYPES) { // Paper
|
|
||||||
if (recursive && !RECURSIVE_TYPES.containsKey(type.typeName())) {
|
|
||||||
RECURSIVE_TYPES.put(type.typeName(), RECURSIVE_TYPES.size());
|
|
||||||
- }
|
|
||||||
+ } } // Paper
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getVersionKey() {
|
|
||||||
diff --git a/src/main/java/com/mojang/datafixers/types/DynamicOps.java b/src/main/java/com/mojang/datafixers/types/DynamicOps.java
|
diff --git a/src/main/java/com/mojang/datafixers/types/DynamicOps.java b/src/main/java/com/mojang/datafixers/types/DynamicOps.java
|
||||||
index 3c76929f24..f21531b3cd 100644
|
index 3c76929f24..f21531b3cd 100644
|
||||||
--- a/src/main/java/com/mojang/datafixers/types/DynamicOps.java
|
--- a/src/main/java/com/mojang/datafixers/types/DynamicOps.java
|
||||||
@ -321,5 +289,5 @@ index e6dd31233a..77d64362b1 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
--
|
--
|
||||||
2.19.0
|
2.19.1
|
||||||
|
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
From 757fd2730e797d31f71492826e972f9a49dbe8ac Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aikar <aikar@aikar.co>
|
||||||
|
Date: Fri, 12 Oct 2018 01:28:32 -0400
|
||||||
|
Subject: [PATCH] Optimize DataFixer Bootstrap to prebuild faster
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/com/mojang/datafixers/DataFixerBuilder.java b/src/main/java/com/mojang/datafixers/DataFixerBuilder.java
|
||||||
|
index 8bc1e3b976..114f958601 100644
|
||||||
|
--- a/src/main/java/com/mojang/datafixers/DataFixerBuilder.java
|
||||||
|
+++ b/src/main/java/com/mojang/datafixers/DataFixerBuilder.java
|
||||||
|
@@ -12,7 +12,9 @@ import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
+import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
+import java.util.Set;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
@@ -60,16 +62,37 @@ public class DataFixerBuilder {
|
||||||
|
final DataFixerUpper fixerUpper = new DataFixerUpper(new Int2ObjectAVLTreeMap<>(schemas), new ArrayList<>(globalList), new IntAVLTreeSet(fixerVersions));
|
||||||
|
|
||||||
|
executor.execute(() -> {
|
||||||
|
- final IntBidirectionalIterator iterator = fixerUpper.fixerVersions().iterator();
|
||||||
|
+ List<Runnable> taskList = new ArrayList<>();
|
||||||
|
+ IntBidirectionalIterator iterator = fixerUpper.fixerVersions().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
final int versionKey = iterator.nextInt();
|
||||||
|
final Schema schema = schemas.get(versionKey);
|
||||||
|
+
|
||||||
|
for (final String typeName: schema.types()) {
|
||||||
|
- final Type<?> dataType = schema.getType(() -> typeName);
|
||||||
|
- final TypeRewriteRule rule = fixerUpper.getRule(DataFixUtils.getVersion(versionKey), dataVersion);
|
||||||
|
- dataType.rewrite(rule, DataFixerUpper.OPTIMIZATION_RULE);
|
||||||
|
+ taskList.add(() -> {
|
||||||
|
+ final Type<?> dataType = schema.getType(() -> typeName);
|
||||||
|
+ final TypeRewriteRule rule = fixerUpper.getRule(DataFixUtils.getVersion(versionKey), dataVersion);
|
||||||
|
+ dataType.rewrite(rule, DataFixerUpper.OPTIMIZATION_RULE);
|
||||||
|
+ });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Divide up into sets of tasks by number of CPU cores
|
||||||
|
+ // Some tasks are faster than others, randomize it to try to divide it more
|
||||||
|
+ Collections.shuffle(taskList);
|
||||||
|
+ List<List<Runnable>> buildQueue = new ArrayList<>();
|
||||||
|
+ List<Runnable> current = new ArrayList<>();
|
||||||
|
+ buildQueue.add(current);
|
||||||
|
+ int maxTasks = (int) Math.max(1, Math.floor(taskList.size() / (float)Math.min(6, Runtime.getRuntime().availableProcessors()-2)));
|
||||||
|
+ for (Runnable task : taskList) {
|
||||||
|
+ if (current.size() > maxTasks) {
|
||||||
|
+ current = new ArrayList<>();
|
||||||
|
+ buildQueue.add(current);
|
||||||
|
+ }
|
||||||
|
+ current.add(task);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ buildQueue.forEach(queue -> executor.execute(() -> queue.forEach(Runnable::run)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return fixerUpper;
|
||||||
|
--
|
||||||
|
2.19.1
|
||||||
|
|
@ -104,6 +104,7 @@ done
|
|||||||
# # group # lib # prefix # many files
|
# # group # lib # prefix # many files
|
||||||
importLibrary com.mojang datafixerupper com/mojang/datafixers \
|
importLibrary com.mojang datafixerupper com/mojang/datafixers \
|
||||||
schemas/Schema.java \
|
schemas/Schema.java \
|
||||||
|
DataFixerBuilder.java \
|
||||||
DataFixerUpper.java \
|
DataFixerUpper.java \
|
||||||
NamedChoiceFinder.java \
|
NamedChoiceFinder.java \
|
||||||
functions/PointFree.java \
|
functions/PointFree.java \
|
||||||
|
Loading…
Reference in New Issue
Block a user