Avoid unnecessary events work in handleDataPacket if the events have no registered handlers

this particular optimisation became possible thanks to changes in 4.19.

I observed that the allocation of Event objects and calling ->call() was costing us a significant percentage of the time taken in PlayerAuthInputPacket handlers. This change produces a measurable 2 microsecond reduction in overhead for PlayerAuthInputPacket handling when players are not moving (10.7 -> 8.7 microseconds). On a server with 200 players, this translates into a 1% reduction in CPU load for PlayerAuthInputPacket alone. It will also benefit other packets, but not to the extent that PlayerAuthInputPacket benefits.
This commit is contained in:
Dylan K. Taylor 2023-04-16 20:51:55 +01:00
parent 84cb070d56
commit 0629d11e13
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
2 changed files with 31 additions and 15 deletions

View File

@ -27,6 +27,7 @@ declare(strict_types=1);
namespace pocketmine\event;
use pocketmine\timings\Timings;
use function count;
use function get_class;
abstract class Event{
@ -67,4 +68,14 @@ abstract class Event{
$timings->stopTiming();
}
}
/**
* Returns whether the current class context has any registered global handlers.
* This can be used in hot code paths to avoid unnecessary event object creation.
*
* Usage: SomeEventClass::hasHandlers()
*/
public static function hasHandlers() : bool{
return count(HandlerListManager::global()->getListFor(static::class)->getListenerList()) > 0;
}
}

View File

@ -401,10 +401,12 @@ class NetworkSession{
$timings->startTiming();
try{
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
$ev->call();
if($ev->isCancelled()){
return;
if(DataPacketDecodeEvent::hasHandlers()){
$ev = new DataPacketDecodeEvent($this, $packet->pid(), $buffer);
$ev->call();
if($ev->isCancelled()){
return;
}
}
$decodeTimings = Timings::getDecodeDataPacketTimings($packet);
@ -424,19 +426,22 @@ class NetworkSession{
$decodeTimings->stopTiming();
}
$ev = new DataPacketReceiveEvent($this, $packet);
$ev->call();
if(!$ev->isCancelled()){
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
$handlerTimings->startTiming();
try{
if($this->handler === null || !$packet->handle($this->handler)){
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
}
}finally{
$handlerTimings->stopTiming();
if(DataPacketReceiveEvent::hasHandlers()){
$ev = new DataPacketReceiveEvent($this, $packet);
$ev->call();
if($ev->isCancelled()){
return;
}
}
$handlerTimings = Timings::getHandleDataPacketTimings($packet);
$handlerTimings->startTiming();
try{
if($this->handler === null || !$packet->handle($this->handler)){
$this->logger->debug("Unhandled " . $packet->getName() . ": " . base64_encode($stream->getBuffer()));
}
}finally{
$handlerTimings->stopTiming();
}
}finally{
$timings->stopTiming();
}