The following callbacks can now be registered in timings, to allow threads to be notified of these events:
- Turning on/off (`TimingsHandler::getToggleCallbacks()->add(...)`)
- Reset (`TimingsHandler::getReloadCallbacks()->add(...)`)
- Collect (`TimingsHandler::getCollectCallbacks()->add(...)`)
Collect callbacks must return `list<Promise>`. The promises must be `resolve()`d with `list<string>` of printed timings records, as returned by `TimingsHandler::printCurrentThreadRecords()`. It's recommended to use 1 promise per thread.
A timings report will be produced once all promises have been resolved.
This system is used internally to collect timings for async tasks (closes#6166).
For timings viewer developers:
Timings format version has been bumped to 3 to accommodate this change. Timings groups should now include a `ThreadId` at the end of timings group names to ensure that their record IDs are segregated correctly, as they could otherwise conflict between threads. The main thread is not required to specify a thread ID. See pmmp/timings@13cefa6279 for implementation examples.
New PHPStan error is caused by phpstan/phpstan#10924
When timings was disabled, internalStopTiming is not called, and timer depth is not decremented.
If timings is later reenabled, the next call to internalStartTiming will think the timer is already running, and won't generate any new records for the timer.
This has led to broken timings reports with missing Full Server Tick entries, amongst other things.
due to direct repeated usage of registerEvent() with closures, we've seen some libraries like muqsit/SimplePacketHandler generate very large timings reports, because a new timings handler gets created every time a plugin registers or unregisters a new packet handler callback.
This change fixes the problem by ensuring that any handlers derived from the same function, handling the same event class, will share the same timer.
this is usually because of an uncaught exception interacting with a try...finally block.
This will normally result in a crash anyway, and we don't want to obscure the real error.
on multi version servers, the same packet may have different IDs, or different packets might use the same ID. In these cases, we don't want the timings to get split up or erroneously reused.
Split timings into tree reports
this will allow the timings site to display timings as a tree, instead of as a list as is done now, which will enable more precise identification of performance issues.
An example of this can be seen here: https://timings.pmmp.io/?id=302629
The format changes are fully backwards compatible, as the timings site
aggregates timings from timers with the same names, and doesn't limit
how much extra data can appear at the end of a line.
this gives a somewhat better overview of events, particularly if many plugins are subscribed to the same costly event (e.g. PlayerMoveEvent).
In addition, it allows us to see the frequency that events are occurring.