Refactor event system - #5240
Conversation
|
What a coincidence, I was actually looking into the event system bottlenecks as well! Really nice work on this, the benchmarks and entityType filtering look great. Just took a quick look at the code and noticed a couple of small things: In Also with For the Solid PR overall. |
|
Good point. I added the mentioned handler count for each entity to avoid unnecessary map lookups. Thanks for the review! |
Thank you so much dude |
Small update
|
### Summary Optimizes `CClientPerfStatLuaTiming` and `CPerfStatLuaTiming` modules to eliminate CPU throttling and framerate drops caused by `UpdateLuaTiming`. This PR is required by and resolves the performance bottleneck identified in **#5240**, where profiling frequent events under heavy handler load resulted in a **30–40 FPS drop**. With these changes, the event system can profile handlers with zero impact during normal gameplay and minimal overhead when stats are polled.
Summary
This PR introduces a new, more efficient event system. The event system has been somewhat of a bottleneck in MTA for years, and experienced scripters have often recommended limiting the number of handlers attached to frequently triggered events.
The current event system is also unnecessarily complex and performs a significant amount of redundant work. During the investigation of the existing implementation, I found several cases where the same work is repeated unnecessarily.
New event system
The new system is designed to minimize unnecessary iterations and make event dispatch and management considerably cheaper.
Main improvements
For example:
This allows the event system to avoid invoking handlers for entity types they are not interested in.
isEventHandledfunction to check whether a handler function is already attached to an eventPerformance
Thanks to @Dryxio for helping with performance measurements.
Frame time with empty

onClientRenderhandlers (Neon = old events system)At the moment, dispatching 5,000
onClientRenderhandlers (with empty Lua handlers) takes approximately 0.3 ms on the C++ side, compared to around 11 ms with the old system. These results are not yet fully representative, as they do not account for things such as Lua timing or debug hooks.Adding 5,000 handlers with the old system takes around 2 seconds (17,022 ms) and causes noticeable lag (the spinning loading circle appears at the bottom of the screen). With the new system, it takes around 200 ms with no visible loading.
With a 100 FPS cap, the new system currently maintains around 80 FPS with 5K handlers. With the old event system, 5K handlers reduce the framerate to around 25 FPS.
There are still some areas that require further investigation and optimization. For example,
CClientPerfStatLuaTiming::GetSingleton()->UpdateLuaTimingcurrently has a significant impact on performance and can reduce the framerate by roughly 30-40 FPS, resulting in around 40-50 FPS in this particular test.CLuaArgumentsmay also be another area worth optimizing. I want to investigate these areas further and squeeze as much performance as possible out of the new event system.Additional changes
For setting event globals such as
source,this, etc., I used a Lua-side implementation instead of setting them directly from C++. This approach was inspired by @Pirulax 's PR and appears to be both cleaner and more efficient than the previous implementation.Scope
For now, this PR only implements the new system on the client side.
Once the remaining issues have been resolved and the implementation is considered ready, the same system can be implemented on the server side (shared).
This PR is intended to introduce the new event system, but not replace the existing system yet.
To keep this PR reasonably sized, I am not converting all existing built-in events to the new system here. That will be done in a separate PR.
The planned migration is therefore:
Checklist