From 04b8268cf1d75f939591ae9aaacfea62687cc030 Mon Sep 17 00:00:00 2001 From: Aikar Date: Fri, 12 Oct 2018 01:29:28 -0400 Subject: [PATCH] Improvements to DataFixers for performance Mojang asked me to make some changes, so applied them here. --- ...and-performance-issues-in-DataFixers.patch | 82 ++++++------------- ...taFixer-Bootstrap-to-prebuild-faster.patch | 65 +++++++++++++++ scripts/importmcdev.sh | 1 + 3 files changed, 91 insertions(+), 57 deletions(-) create mode 100644 Spigot-Server-Patches/0391-Optimize-DataFixer-Bootstrap-to-prebuild-faster.patch diff --git a/Spigot-Server-Patches/0354-Fix-concurrency-and-performance-issues-in-DataFixers.patch b/Spigot-Server-Patches/0354-Fix-concurrency-and-performance-issues-in-DataFixers.patch index d445a78e38..3372e19553 100644 --- a/Spigot-Server-Patches/0354-Fix-concurrency-and-performance-issues-in-DataFixers.patch +++ b/Spigot-Server-Patches/0354-Fix-concurrency-and-performance-issues-in-DataFixers.patch @@ -1,4 +1,4 @@ -From ab1a408584e0f6e7e28319956b32047f552bf668 Mon Sep 17 00:00:00 2001 +From 296dfee228fa6471e26b9d4d697ba514cf5db998 Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 3 Sep 2018 22:18:38 -0400 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))); } 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 +++ b/src/main/java/com/mojang/datafixers/functions/PointFree.java -@@ -14,7 +14,7 @@ public abstract class PointFree { +@@ -9,15 +9,19 @@ import java.util.Optional; + import java.util.function.Function; + + public abstract class PointFree { +- private boolean initialized; ++ private volatile boolean initialized; + @Nullable private Function, T> value; @SuppressWarnings("ConstantConditions") -- public Function, T> evalCached() { -+ public synchronized Function, T> evalCached() { // Paper + public Function, T> evalCached() { if (!initialized) { - initialized = true; - value = eval(); +- initialized = true; +- 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 -index 7c67d989e0..7faca88a88 100644 +index 7c67d989e0..d81e8d1a1a 100644 --- a/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; - import java.util.function.Supplier; +@@ -50,8 +50,11 @@ public class Schema { - public class Schema { -- protected final Object2IntMap RECURSIVE_TYPES = new Object2IntOpenHashMap<>(); -- private final Map> TYPE_TEMPLATES = Maps.newHashMap(); -+ protected final Object2IntMap RECURSIVE_TYPES = it.unimi.dsi.fastutil.objects.Object2IntMaps.synchronize(new Object2IntOpenHashMap<>()); // Paper -+ private final Map> TYPE_TEMPLATES = Maps.newConcurrentMap(); // Paper - private final Map> TYPES; - private final int versionKey; - private final String name; -@@ -37,26 +37,31 @@ public class Schema { - } - - protected Map> buildTypes() { -- final Map> types = Maps.newHashMap(); -+ final Map> types = Maps.newConcurrentMap(); // Paper - - final List templates = Lists.newArrayList(); - -+ synchronized (RECURSIVE_TYPES) { // Paper - for (final Object2IntMap.Entry 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()) { final Type type; - if (RECURSIVE_TYPES.containsKey(name)) { @@ -133,13 +119,7 @@ index 7c67d989e0..7faca88a88 100644 } else { type = getTemplate(name).apply(family).apply(-1); } - types.put(name, type); -- } -+ } } // Paper - return types; - } - -@@ -89,8 +94,11 @@ public class Schema { +@@ -89,8 +92,11 @@ public class Schema { } public TypeTemplate id(final String name) { @@ -153,18 +133,6 @@ index 7c67d989e0..7faca88a88 100644 } return getTemplate(name); } -@@ -138,9 +146,10 @@ public class Schema { - public void registerType(final boolean recursive, final DSL.TypeReference type, final Supplier 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 index 3c76929f24..f21531b3cd 100644 --- a/src/main/java/com/mojang/datafixers/types/DynamicOps.java @@ -321,5 +289,5 @@ index e6dd31233a..77d64362b1 100644 } -- -2.19.0 +2.19.1 diff --git a/Spigot-Server-Patches/0391-Optimize-DataFixer-Bootstrap-to-prebuild-faster.patch b/Spigot-Server-Patches/0391-Optimize-DataFixer-Bootstrap-to-prebuild-faster.patch new file mode 100644 index 0000000000..f1b36aff3e --- /dev/null +++ b/Spigot-Server-Patches/0391-Optimize-DataFixer-Bootstrap-to-prebuild-faster.patch @@ -0,0 +1,65 @@ +From 757fd2730e797d31f71492826e972f9a49dbe8ac Mon Sep 17 00:00:00 2001 +From: Aikar +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 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> buildQueue = new ArrayList<>(); ++ List 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 + diff --git a/scripts/importmcdev.sh b/scripts/importmcdev.sh index dbfda717fe..c893fd2850 100755 --- a/scripts/importmcdev.sh +++ b/scripts/importmcdev.sh @@ -104,6 +104,7 @@ done # # group # lib # prefix # many files importLibrary com.mojang datafixerupper com/mojang/datafixers \ schemas/Schema.java \ + DataFixerBuilder.java \ DataFixerUpper.java \ NamedChoiceFinder.java \ functions/PointFree.java \