Mod

FastEvent

Quick rating

FastEvent

No reviews yet

speeding up the Event system in Forge/Neoforge

No Theme
No Genre
Performance & Optimization
Development: Abandoned
Mod Loaders
Forge
NeoForge
Minecraft

Community voices

Reviews

Versions
Loading versions…
Match includes

Click once to include, again to exclude, again to clear

Rating Any
Any 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
Min
Max
Play Status
Reviews
Time Played
hrs+
Verified developers only
Has developer response
List view
Grid view
Compact view
Sort by
Date
Rating
Helpful
Unhelpful
Edited
Sort ascending
Delete this review?

This removes your review from the project. You can write a new review after.

Review submitted for moderation

Your review has been sent to moderators, who will check that it meets our guidelines before it appears publicly.

No reviews yet. Be the first to review this project!

Get it on

Available Platforms

Compatibility

Supported Environments

Dev Environment
Client Optional
Server Optional

About

Project Details

Type
Mod
License
MIT License
Latest Version
FastEvent-1.16.5-1.2.0.jar
Authors
CurseForge
Modrinth

For authors

Embed Badge

If you're the author of this project, you can embed a live badge anywhere that supports HTML or Markdown. It updates automatically whenever ratings change.

Custom banner text
ModDex rating badge preview

Use HTML for any page that supports it, or Markdown for README files and Markdown-based descriptions.

Identifiers

Platform IDs

CurseForge ID
Modrinth ID

Resources

External Links

Source Issues Wiki Discord

About

Description

Project Abandoned

Long story short, the optimization approach still applies, but Forge/NeoForge does not allow mod to modify EventBus.

Unlike classes from Minecraft or Forge itself, EventBus is loaded not as part of the game, but as "library", which makes it "uncertain" to modify EventBus via Mixin or Transformer.

In 1.2.0, in an effort of further improving performance, I used some dirty hack (or "non-standard approach" if you prefer) to modify the ASMEventHandler class, which is unfortunately broken in 1.18.2+. These releases are archived now, and are likely not receiving further update.

FastEvent

is a Forge/Neoforge optimization mod that optimizes one of the most fundamental systems in Forge: the Event system.

How Fast

It's not easy to make a test case for every supported Minecraft version, especially when the Event system for these versions are different from each other. So instead, I will provide a JMH benchmark report from a PR I made for Cleanroom project, in which I used the same optimization approach as FastEvent:

Register 10,000 event listeners, post event 0 times:

Benchmark                               Mode  Cnt     Score     Error  Units
BusPerformanceTest.register10000Legacy  avgt    5  1126.498 ± 284.633  ms/op
BusPerformanceTest.register10000Modern  avgt    5  1058.961 ± 173.586  ms/op

About 6.4% faster.

Register 1,000 event listeners, post event 10,000 times:

Benchmark                                       Mode  Cnt     Score      Error  Units
BusPerformanceTest.register1000test10000Legacy  avgt    5  4407.963 ± 4250.643  ms/op
BusPerformanceTest.register1000test10000Modern  avgt    5  3550.578 ± 1991.352  ms/op

About 24% faster.

Original PR

https://github.com/CleanroomMC/Cleanroom/pull/328#issuecomment-2801099504

How does it work

(Nerdy technical details alert)

When devs are using @EventBusSubscriber and/or @SubscribeEvent to subscribe event handlers, the EventBus cannot get the event handler magically, instead only a Method object is available. So the most straight-forward approach is use this object directly: method.invoke(...). This invocation will eventually be redirected by JVM back to the original method, allowing an event handler to receive an event after subscribing to it.

But this (method.invoke(...)) is really slow. To make it faster, the EventBus will, at runtime, generate event handler classes for every method it found, eliminating expensive reflection based invocation.

But generating classes introduces another slow-down. To make it even faster, FastEvent replaced class generation with lambda construction, speeding up event handler construction. Another benefit is that lambda is "hidden", allowing JVM to perform more optimization.

If you happen to know a bit Java, code examples below might be more intuitive for you:

class Listen {
    public void onEvent(Event event) {
    }
}
Listen lis = new Listen();

// EventBus will generate a new class for every event handler
class IEventListener$Listen$onEvent implements IEventListener {
    private Listen instance;
    public IEventListener$Listen$onEvent(Listen instance) {
        this.instance = instance;
    }
    @Override
    public void invoke(Event event) {
        instance.onEvent(event);
    }
}
IEventListener handler = new IEventListener$Listen$onEvent(lis);

// FastEvent uses lambda to generate event handler
IEventListener handler = lis::onEvent;

Project Abandoned

Long story short, the optimization approach still applies, but Forge/NeoForge does not allow mod to modify EventBus.

Unlike classes from Minecraft or Forge itself, EventBus is loaded not as part of the game, but as "library", which makes it impossible to modify EventBus via Mixin or Transformer.

In 1.2.0, in an effort of further improving performance, I used some dirty hack (or "non-standard approach" if you prefer) to modify the ASMEventHandler class, which is unfortunately broken in 1.18.2+. These releases are archived now, and are likely not receiving further update.

FastEvent

is a Forge/Neoforge optimization mod that optimizes one of the most fundamental systems in Forge: the Event system.

How Fast

It's not easy to make a test case for every supported Minecraft version, especially when the Event system for these versions are different from each other. So instead, I will provide a JMH benchmark report from a PR I made for Cleanroom project, in which I used the same optimization approach as FastEvent:

Register 10,000 event listeners, post event 0 times:

Benchmark                               Mode  Cnt     Score     Error  Units
BusPerformanceTest.register10000Legacy  avgt    5  1126.498 ± 284.633  ms/op
BusPerformanceTest.register10000Modern  avgt    5  1058.961 ± 173.586  ms/op

About 6.4% faster.

Register 1,000 event listeners, post event 10,000 times:

Benchmark                                       Mode  Cnt     Score      Error  Units
BusPerformanceTest.register1000test10000Legacy  avgt    5  4407.963 ± 4250.643  ms/op
BusPerformanceTest.register1000test10000Modern  avgt    5  3550.578 ± 1991.352  ms/op

About 24% faster.

Original PR

https://github.com/CleanroomMC/Cleanroom/pull/328#issuecomment-2801099504

How does it work

(Nerdy technical details alert)

When devs are using @EventBusSubscriber and/or @SubscribeEvent to subscribe event handlers, the EventBus cannot get the event handler magically, instead only a Method object is available. So the most straight-forward approach is use this object directly: method.invoke(...). This invocation will eventually be redirected by JVM back to the original method, allowing an event handler to receive an event after subscribing to it.

But this (method.invoke(...)) is really slow. To make it faster, the EventBus will, at runtime, generate event handler classes for every method it found, eliminating expensive reflection based invocation.

But generating classes introduces another slow-down. To make it even faster, FastEvent replaced class generation with lambda construction, speeding up event handler construction. Another benefit is that lambda is "hidden", allowing JVM to perform more optimization.

If you happen to know a bit Java, code examples below might be more intuitive for you:

class Listen {
    public void onEvent(Event event) {
    }
}
Listen lis = new Listen();

// EventBus will generate a new class for every event handler
class IEventListener$Listen$onEvent implements IEventListener {
    private Listen instance;
    public IEventListener$Listen$onEvent(Listen instance) {
        this.instance = instance;
    }
    @Override
    public void invoke(Event event) {
        instance.onEvent(event);
    }
}
IEventListener handler = new IEventListener$Listen$onEvent(lis);

// FastEvent uses lambda to generate event handler
IEventListener handler = lis::onEvent;

Screenshots

Gallery

This project has no gallery images yet.

Versions

Files

Relations

Project Relations

More like this

Similar Mods

Suggestions use data such as tags, dependencies, dependents, descriptions, titles, and more to rank how much they overlap with this mod.

On ModDex

Community snapshot

0
Ratings
0
Followers
0
In stacks

By the numbers

Statistics

4.2m
Total Downloads
CurseForge
3m
Modrinth
1.1m
Last Updated
CurseForge
Created
CurseForge
Modrinth
Last synced
When ModDex last fetched and imported data for this project from CurseForge or Modrinth. High-traffic and active projects are checked more often.
Next pipeline sync