Skip to content

Commit 775f0da

Browse files
committed
Search indexing profiler (not actually that useful lol)
1 parent 2f91bf8 commit 775f0da

11 files changed

Lines changed: 319 additions & 4 deletions

CHANGELOG-LATEST.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- Items dragged from EMI into the inventory now are added to the inventory (as long as the player is an operator).
1414
- Maple leaf tinting can now be disabled in the mod config.
1515
- Spruce leaf tinting can now be disabled in the mod config.
16+
- Optional profiler for creative mode/EMI search indexing.
1617

1718
### Changed
1819
- Removed leash backport in favor of Vanilla Backport's implementation.
@@ -26,6 +27,7 @@
2627
- Boat leash connections persist on world reload.
2728
- Music and sound settings being broken on 1.20.
2829
- Tablet recipes now work on 1.20.
29-
- A spectator with Bracewalk no longer can break blocks. (Additional Enchantments)
30+
- Spectators with Bracewalk no longer can break blocks. (Additional Enchantments)
3031
- Aloe Vera blocks can now be harvested with modded shears. (Atmospheric)
31-
- Beacon recipes now match the current version of RF.
32+
- Beacon recipes now match the current version of RF.
33+
- Errors caused by missing buckets from Respiteful.

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [Unreleased]
8-
- Fixed missing buckets from Respiteful causing issues.
98

109
## [1.10.1] - 2025-12-18
1110

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G
33
loom.platform = forge
44

55
# Mod properties
6-
mod_version = 1.11-pre7
6+
mod_version = 1.11-pre8
77
maven_group = cc.cassian.raspberry
88
archives_name = raspberry_core
99

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package cc.cassian.raspberry.mixin.profiler;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import cc.cassian.raspberry.util.RaspberryProfiler;
5+
import net.minecraft.world.item.CreativeModeTab;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
10+
11+
@Mixin(CreativeModeTab.class)
12+
public class CreativeModeTabsMixin {
13+
14+
@Inject(method = "buildContents", at = @At("HEAD"))
15+
private void raspberry$startProfile(CreativeModeTab.ItemDisplayParameters parameters, CallbackInfo ci) {
16+
if (ModConfig.get().enableProfiler) {
17+
RaspberryProfiler.TAB_START_TIME.set(System.nanoTime());
18+
}
19+
}
20+
21+
@Inject(method = "buildContents", at = @At("RETURN"))
22+
private void raspberry$endProfile(CreativeModeTab.ItemDisplayParameters parameters, CallbackInfo ci) {
23+
if (ModConfig.get().enableProfiler) {
24+
long start = RaspberryProfiler.TAB_START_TIME.get();
25+
long end = System.nanoTime();
26+
27+
CreativeModeTab tab = (CreativeModeTab) (Object) this;
28+
29+
String name = tab.getDisplayName().getString();
30+
if (name.isEmpty()) name = "Unknown Tab";
31+
32+
RaspberryProfiler.recordCreativeTab(name, end - start);
33+
34+
if (tab.getType() == CreativeModeTab.Type.SEARCH) {
35+
RaspberryProfiler.dumpLogs();
36+
}
37+
}
38+
}
39+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package cc.cassian.raspberry.mixin.profiler;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import cc.cassian.raspberry.util.RaspberryProfiler;
5+
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
6+
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
7+
import dev.emi.emi.api.EmiPlugin;
8+
import dev.emi.emi.api.EmiRegistry;
9+
import org.spongepowered.asm.mixin.Mixin;
10+
import org.spongepowered.asm.mixin.injection.At;
11+
import org.spongepowered.asm.mixin.injection.Inject;
12+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
13+
14+
@Mixin(targets = "dev.emi.emi.runtime.EmiReloadManager$ReloadWorker", remap = false)
15+
public class EmiRegistryMixin {
16+
17+
@WrapOperation(method = "run", at = @At(value = "INVOKE", target = "Ldev/emi/emi/api/EmiPlugin;register(Ldev/emi/emi/api/EmiRegistry;)V"))
18+
private void raspberry$profilePlugin(EmiPlugin plugin, EmiRegistry registry, Operation<Void> original) {
19+
if (!ModConfig.get().enableProfiler) {
20+
original.call(plugin, registry);
21+
return;
22+
}
23+
24+
long start = System.nanoTime();
25+
original.call(plugin, registry);
26+
long end = System.nanoTime();
27+
28+
RaspberryProfiler.recordEmiPlugin(plugin.getClass().getSimpleName(), end - start);
29+
}
30+
31+
@Inject(method = "run", at = @At("RETURN"))
32+
private void raspberry$onFinish(CallbackInfo ci) {
33+
if (ModConfig.get().enableProfiler) {
34+
RaspberryProfiler.dumpLogs();
35+
}
36+
}
37+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package cc.cassian.raspberry.mixin.profiler;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import cc.cassian.raspberry.util.RaspberryProfiler;
5+
import net.minecraft.client.searchtree.FullTextSearchTree;
6+
import net.minecraft.resources.ResourceLocation;
7+
import net.minecraft.world.item.ItemStack;
8+
import net.minecraftforge.registries.ForgeRegistries;
9+
import org.spongepowered.asm.mixin.Mixin;
10+
import org.spongepowered.asm.mixin.Unique;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
import org.spongepowered.asm.mixin.injection.ModifyVariable;
13+
14+
import java.util.function.Function;
15+
import java.util.stream.Stream;
16+
17+
@Mixin(FullTextSearchTree.class)
18+
public class FullTextSearchTreeMixin {
19+
20+
@ModifyVariable(method = "<init>", at = @At("HEAD"), argsOnly = true, ordinal = 0)
21+
private static Function<Object, Stream<String>> raspberry$profileTextIndexing(Function<Object, Stream<String>> original) {
22+
if (!ModConfig.get().enableProfiler) return original;
23+
24+
return (element) -> {
25+
long start = System.nanoTime();
26+
Stream<String> result = original.apply(element);
27+
long end = System.nanoTime();
28+
29+
raspberry$recordTime(element, end - start);
30+
return result;
31+
};
32+
}
33+
34+
@Unique
35+
private static void raspberry$recordTime(Object element, long nanos) {
36+
String modid = "unknown";
37+
if (element instanceof ItemStack stack) {
38+
try {
39+
modid = stack.getItem().getCreatorModId(stack);
40+
if (modid == null) {
41+
ResourceLocation key = ForgeRegistries.ITEMS.getKey(stack.getItem());
42+
if (key != null) modid = key.getNamespace();
43+
}
44+
} catch (Exception ignored) {}
45+
}
46+
RaspberryProfiler.recordSearchIndex(modid, nanos);
47+
}
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package cc.cassian.raspberry.mixin.profiler;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import cc.cassian.raspberry.util.RaspberryProfiler;
5+
import net.minecraft.client.searchtree.IdSearchTree;
6+
import net.minecraft.resources.ResourceLocation;
7+
import net.minecraft.world.item.ItemStack;
8+
import net.minecraftforge.registries.ForgeRegistries;
9+
import org.spongepowered.asm.mixin.Mixin;
10+
import org.spongepowered.asm.mixin.Unique;
11+
import org.spongepowered.asm.mixin.injection.At;
12+
import org.spongepowered.asm.mixin.injection.ModifyVariable;
13+
14+
import java.util.function.Function;
15+
import java.util.stream.Stream;
16+
17+
@Mixin(IdSearchTree.class)
18+
public class IdSearchTreeMixin {
19+
20+
@ModifyVariable(method = "<init>", at = @At("HEAD"), argsOnly = true, ordinal = 0)
21+
private static Function<Object, Stream<ResourceLocation>> raspberry$profileIdIndexing(Function<Object, Stream<ResourceLocation>> original) {
22+
if (!ModConfig.get().enableProfiler) return original;
23+
24+
return (element) -> {
25+
long start = System.nanoTime();
26+
Stream<ResourceLocation> result = original.apply(element);
27+
long end = System.nanoTime();
28+
29+
raspberry$recordTime(element, end - start);
30+
return result;
31+
};
32+
}
33+
34+
@Unique
35+
private static void raspberry$recordTime(Object element, long nanos) {
36+
String modid = "unknown";
37+
if (element instanceof ItemStack stack) {
38+
try {
39+
modid = stack.getItem().getCreatorModId(stack);
40+
if (modid == null) {
41+
ResourceLocation key = ForgeRegistries.ITEMS.getKey(stack.getItem());
42+
if (key != null) modid = key.getNamespace();
43+
}
44+
} catch (Exception ignored) {}
45+
}
46+
RaspberryProfiler.recordSearchIndex(modid, nanos);
47+
}
48+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package cc.cassian.raspberry.mixin.profiler;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import cc.cassian.raspberry.util.RaspberryProfiler;
5+
import net.minecraft.client.searchtree.SearchRegistry;
6+
import net.minecraft.server.packs.resources.ResourceManager;
7+
import org.spongepowered.asm.mixin.Mixin;
8+
import org.spongepowered.asm.mixin.injection.At;
9+
import org.spongepowered.asm.mixin.injection.Inject;
10+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
11+
12+
@Mixin(SearchRegistry.class)
13+
public class SearchRegistryMixin {
14+
15+
@Inject(method = "onResourceManagerReload", at = @At("RETURN"))
16+
private void raspberry$onReloadComplete(ResourceManager resourceManager, CallbackInfo ci) {
17+
if (ModConfig.get().enableProfiler) {
18+
RaspberryProfiler.dumpLogs();
19+
}
20+
}
21+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package cc.cassian.raspberry.mixin.profiler;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import cc.cassian.raspberry.util.RaspberryProfiler;
5+
import net.minecraft.client.Minecraft;
6+
import org.spongepowered.asm.mixin.Mixin;
7+
import org.spongepowered.asm.mixin.injection.At;
8+
import org.spongepowered.asm.mixin.injection.Inject;
9+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
10+
11+
@Mixin(Minecraft.class)
12+
public class ShutdownHookMixin {
13+
14+
@Inject(method = "stop", at = @At("HEAD"))
15+
private void raspberry$dumpOnExit(CallbackInfo ci) {
16+
if (ModConfig.get().enableProfiler) {
17+
RaspberryProfiler.dumpLogs();
18+
}
19+
}
20+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package cc.cassian.raspberry.util;
2+
3+
import cc.cassian.raspberry.config.ModConfig;
4+
import net.minecraft.client.Minecraft;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import java.io.BufferedWriter;
8+
import java.io.File;
9+
import java.io.FileWriter;
10+
import java.io.IOException;
11+
import java.time.LocalDateTime;
12+
import java.time.format.DateTimeFormatter;
13+
import java.util.Comparator;
14+
import java.util.LinkedHashMap;
15+
import java.util.Map;
16+
import java.util.TreeMap;
17+
18+
public class RaspberryProfiler {
19+
private static final Logger LOGGER = LoggerFactory.getLogger("RaspberryProfiler");
20+
public static final ThreadLocal<Long> TAB_START_TIME = ThreadLocal.withInitial(() -> 0L);
21+
22+
private static final Map<String, Long> creativeTabTimes = new LinkedHashMap<>();
23+
private static final Map<String, Long> emiPluginTimes = new LinkedHashMap<>();
24+
private static final Map<String, Long> searchIndexTimes = new TreeMap<>();
25+
26+
public static void recordCreativeTab(String tabName, long nanos) {
27+
if (ModConfig.get().enableProfiler) {
28+
creativeTabTimes.put(tabName, nanos);
29+
}
30+
}
31+
32+
public static void recordEmiPlugin(String pluginName, long nanos) {
33+
if (ModConfig.get().enableProfiler) {
34+
emiPluginTimes.put(pluginName, nanos);
35+
}
36+
}
37+
38+
public static void recordSearchIndex(String modId, long nanos) {
39+
if (ModConfig.get().enableProfiler) {
40+
searchIndexTimes.merge(modId, nanos, Long::sum);
41+
}
42+
}
43+
44+
public static void dumpLogs() {
45+
if (!ModConfig.get().enableProfiler) return;
46+
47+
File logDir = new File(Minecraft.getInstance().gameDirectory, "logs");
48+
if (!logDir.exists()) logDir.mkdirs();
49+
File logFile = new File(logDir, "raspberry_profiler.log");
50+
51+
try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFile))) {
52+
writer.write("Raspberry Core Profiler Log - " + LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
53+
writer.newLine();
54+
writer.write("==================================================");
55+
writer.newLine();
56+
57+
writer.write("--- Creative Mode Tabs Rebuild ---");
58+
writer.newLine();
59+
long totalTabTime = 0;
60+
creativeTabTimes.entrySet().stream()
61+
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
62+
.forEach(entry -> writeEntry(writer, entry.getKey(), entry.getValue()));
63+
64+
for (Long val : creativeTabTimes.values()) totalTabTime += val;
65+
writer.write(String.format("TOTAL TAB TIME: %.2f ms", totalTabTime / 1_000_000.0));
66+
writer.newLine();
67+
writer.newLine();
68+
69+
writer.write("--- Search Tree Indexing (Total) ---");
70+
writer.newLine();
71+
searchIndexTimes.forEach((key1, value1) -> writeEntry(writer, key1, value1));
72+
writer.newLine();
73+
74+
writer.write("--- EMI Plugin Loading (Total) ---");
75+
writer.newLine();
76+
emiPluginTimes.forEach((key, value) -> writeEntry(writer, key, value));
77+
writer.newLine();
78+
79+
LOGGER.info("Dumped profiling info to {}", logFile.getAbsolutePath());
80+
81+
} catch (IOException e) {
82+
LOGGER.error("Failed to dump Raspberry Profiler logs", e);
83+
}
84+
}
85+
86+
private static void writeEntry(BufferedWriter writer, String name, long nanos) {
87+
try {
88+
double ms = nanos / 1_000_000.0;
89+
writer.write(String.format("[%s]: %.2f ms", name, ms));
90+
writer.newLine();
91+
} catch (IOException e) {
92+
e.printStackTrace();
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)