Report debug stats for cost accounting every 10 seconds

This commit is contained in:
Dylan K. Taylor 2025-03-11 12:41:59 +00:00
parent afc4a3c7f1
commit 41789bc67a
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
3 changed files with 91 additions and 13 deletions

View File

@ -37,7 +37,7 @@
"pocketmine/bedrock-data": "~4.0.0+bedrock-1.21.60", "pocketmine/bedrock-data": "~4.0.0+bedrock-1.21.60",
"pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50", "pocketmine/bedrock-item-upgrade-schema": "~1.14.0+bedrock-1.21.50",
"pocketmine/bedrock-protocol": "~36.0.0+bedrock-1.21.60", "pocketmine/bedrock-protocol": "~36.0.0+bedrock-1.21.60",
"pocketmine/binaryutils": "^0.2.1", "pocketmine/binaryutils": "dev-experimental/read-ops-accounting as 0.2.6",
"pocketmine/callback-validator": "^1.0.2", "pocketmine/callback-validator": "^1.0.2",
"pocketmine/color": "^0.3.0", "pocketmine/color": "^0.3.0",
"pocketmine/errorhandler": "^0.7.0", "pocketmine/errorhandler": "^0.7.0",

33
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "bef9decc40d9f5bd82e1de2d151bd99f", "content-hash": "415cb668882a32039066467bb308421f",
"packages": [ "packages": [
{ {
"name": "adhocore/json-comment", "name": "adhocore/json-comment",
@ -302,16 +302,16 @@
}, },
{ {
"name": "pocketmine/binaryutils", "name": "pocketmine/binaryutils",
"version": "0.2.6", "version": "dev-experimental/read-ops-accounting",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/pmmp/BinaryUtils.git", "url": "https://github.com/pmmp/BinaryUtils.git",
"reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84" "reference": "8cfa34c9d5aae11886a4142c172cff05f1e87ee2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/ccfc1899b859d45814ea3592e20ebec4cb731c84", "url": "https://api.github.com/repos/pmmp/BinaryUtils/zipball/8cfa34c9d5aae11886a4142c172cff05f1e87ee2",
"reference": "ccfc1899b859d45814ea3592e20ebec4cb731c84", "reference": "8cfa34c9d5aae11886a4142c172cff05f1e87ee2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -320,9 +320,9 @@
}, },
"require-dev": { "require-dev": {
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "~1.10.3", "phpstan/phpstan": "2.1.0",
"phpstan/phpstan-phpunit": "^1.0", "phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-strict-rules": "^1.0.0", "phpstan/phpstan-strict-rules": "^2.0.0",
"phpunit/phpunit": "^9.5 || ^10.0 || ^11.0" "phpunit/phpunit": "^9.5 || ^10.0 || ^11.0"
}, },
"type": "library", "type": "library",
@ -338,9 +338,9 @@
"description": "Classes and methods for conveniently handling binary data", "description": "Classes and methods for conveniently handling binary data",
"support": { "support": {
"issues": "https://github.com/pmmp/BinaryUtils/issues", "issues": "https://github.com/pmmp/BinaryUtils/issues",
"source": "https://github.com/pmmp/BinaryUtils/tree/0.2.6" "source": "https://github.com/pmmp/BinaryUtils/tree/experimental/read-ops-accounting"
}, },
"time": "2024-03-04T15:04:17+00:00" "time": "2025-03-11T11:50:46+00:00"
}, },
{ {
"name": "pocketmine/callback-validator", "name": "pocketmine/callback-validator",
@ -2930,9 +2930,18 @@
"time": "2024-03-03T12:36:25+00:00" "time": "2024-03-03T12:36:25+00:00"
} }
], ],
"aliases": [], "aliases": [
{
"package": "pocketmine/binaryutils",
"version": "dev-experimental/read-ops-accounting",
"alias": "0.2.6",
"alias_normalized": "0.2.6.0"
}
],
"minimum-stability": "stable", "minimum-stability": "stable",
"stability-flags": [], "stability-flags": {
"pocketmine/binaryutils": 20
},
"prefer-stable": false, "prefer-stable": false,
"prefer-lowest": false, "prefer-lowest": false,
"platform": { "platform": {

View File

@ -113,6 +113,7 @@ use pocketmine\utils\BinaryDataException;
use pocketmine\utils\BinaryStream; use pocketmine\utils\BinaryStream;
use pocketmine\utils\ObjectSet; use pocketmine\utils\ObjectSet;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use pocketmine\world\format\io\GlobalItemDataHandlers; use pocketmine\world\format\io\GlobalItemDataHandlers;
use pocketmine\world\Position; use pocketmine\world\Position;
use pocketmine\world\World; use pocketmine\world\World;
@ -122,10 +123,12 @@ use function base64_encode;
use function bin2hex; use function bin2hex;
use function count; use function count;
use function get_class; use function get_class;
use function hrtime;
use function implode; use function implode;
use function in_array; use function in_array;
use function is_string; use function is_string;
use function json_encode; use function json_encode;
use function microtime;
use function ord; use function ord;
use function random_bytes; use function random_bytes;
use function str_split; use function str_split;
@ -135,7 +138,9 @@ use function strtolower;
use function substr; use function substr;
use function time; use function time;
use function ucfirst; use function ucfirst;
use const JSON_PRETTY_PRINT;
use const JSON_THROW_ON_ERROR; use const JSON_THROW_ON_ERROR;
use const PHP_INT_MAX;
class NetworkSession{ class NetworkSession{
private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions arrive separately private const INCOMING_PACKET_BATCH_PER_TICK = 2; //usually max 1 per tick, but transactions arrive separately
@ -194,6 +199,29 @@ class NetworkSession{
*/ */
private ObjectSet $disposeHooks; private ObjectSet $disposeHooks;
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private array $packetCostsMin = [];
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private array $packetCostsMax = [];
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private array $packetCostsTotal = [];
/**
* @var int[]
* @phpstan-var array<string, int>
*/
private array $packetCounts = [];
private int $decodeCostTotal = 0;
private int $sessionStartHrtime;
public function __construct( public function __construct(
private Server $server, private Server $server,
private NetworkSessionManager $manager, private NetworkSessionManager $manager,
@ -223,6 +251,8 @@ class NetworkSession{
$this->manager->add($this); $this->manager->add($this);
$this->logger->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_network_session_open())); $this->logger->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_network_session_open()));
$this->sessionStartHrtime = hrtime(true);
} }
private function getLogPrefix() : string{ private function getLogPrefix() : string{
@ -450,7 +480,17 @@ class NetworkSession{
try{ try{
$stream = PacketSerializer::decoder($buffer, 0); $stream = PacketSerializer::decoder($buffer, 0);
try{ try{
$stream->setReadOpsLimit(PHP_INT_MAX); //just for stats collection
$packet->decode($stream); $packet->decode($stream);
$readOps = $stream->getReadOps();
$this->decodeCostTotal += $readOps;
$key = $packet->getName();
$this->packetCostsTotal[$key] = ($this->packetCostsTotal[$key] ?? 0) + $readOps;
$this->packetCostsMin[$key] = min($this->packetCostsMin[$key] ?? PHP_INT_MAX, $readOps);
$this->packetCostsMax[$key] = max($this->packetCostsMax[$key] ?? 0, $readOps);
$this->packetCounts[$key] = ($this->packetCounts[$key] ?? 0) + 1;
}catch(PacketDecodeException $e){ }catch(PacketDecodeException $e){
throw PacketHandlingException::wrap($e); throw PacketHandlingException::wrap($e);
} }
@ -483,6 +523,27 @@ class NetworkSession{
} }
} }
/**
* @return int[]|float[]
* @phpstan-return array<string, int|float|array<string, int|float>>
*/
public function dumpDecodeCostStats() : array{
$sessionTime = ((hrtime(true) - $this->sessionStartHrtime) / 1_000_000_000);
$packetDecodeAverages = [];
$packetCostsPerSecondAverages = [];
foreach(Utils::stringifyKeys($this->packetCostsTotal) as $packet => $total){
$packetDecodeAverages[$packet] = $total / $this->packetCounts[$packet];
$packetCostsPerSecondAverages[$packet] = $total / $sessionTime;
}
return [
"decodeCostAvgPerSecond" => $this->decodeCostTotal / $sessionTime,
"decodeCostAvgPerPacketPerSecond" => $packetCostsPerSecondAverages,
"decodeCostAvgPerPacket" => $packetDecodeAverages,
"decodeCostMinPerPacket" => $this->packetCostsMin,
"decodeCostMaxPerPacket" => $this->packetCostsMax
];
}
public function handleAckReceipt(int $receiptId) : void{ public function handleAckReceipt(int $receiptId) : void{
if(!$this->connected){ if(!$this->connected){
return; return;
@ -1346,5 +1407,13 @@ class NetworkSession{
} }
$this->flushSendBuffer(); $this->flushSendBuffer();
$now = microtime(true);
if($now - $this->lastStatsReportTime > 10){
$this->logger->debug("Decode cost stats: " . json_encode($this->dumpDecodeCostStats(), JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR));
$this->lastStatsReportTime = $now;
}
} }
private float $lastStatsReportTime = 0;
} }