From 23071d257e9694157e8ed32efe854a8e4cb4018d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 24 Mar 2019 18:57:32 +0000 Subject: [PATCH] Extract process-related functions from Utils into a separate Process class --- src/pocketmine/MemoryManager.php | 3 +- src/pocketmine/PocketMine.php | 8 +- src/pocketmine/Server.php | 11 +- .../command/defaults/StatusCommand.php | 8 +- .../event/server/LowMemoryEvent.php | 4 +- src/pocketmine/scheduler/SendUsageTask.php | 5 +- src/pocketmine/utils/Process.php | 171 ++++++++++++++++++ src/pocketmine/utils/ServerKiller.php | 2 +- src/pocketmine/utils/Utils.php | 130 ------------- 9 files changed, 193 insertions(+), 149 deletions(-) create mode 100644 src/pocketmine/utils/Process.php diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index db35ca765..3392ea2c6 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -27,6 +27,7 @@ use pocketmine\event\server\LowMemoryEvent; use pocketmine\scheduler\DumpWorkerMemoryTask; use pocketmine\scheduler\GarbageCollectionTask; use pocketmine\timings\Timings; +use pocketmine\utils\Process; use pocketmine\utils\Utils; use function arsort; use function count; @@ -236,7 +237,7 @@ class MemoryManager{ if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){ $this->checkTicker = 0; - $memory = Utils::getMemoryUsage(true); + $memory = Process::getMemoryUsage(true); $trigger = false; if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){ $trigger = 0; diff --git a/src/pocketmine/PocketMine.php b/src/pocketmine/PocketMine.php index f98081703..ce4392582 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -29,10 +29,10 @@ namespace { namespace pocketmine { use pocketmine\utils\MainLogger; + use pocketmine\utils\Process; use pocketmine\utils\ServerKiller; use pocketmine\utils\Terminal; use pocketmine\utils\Timezone; - use pocketmine\utils\Utils; use pocketmine\utils\VersionString; use pocketmine\wizard\SetupWizard; @@ -223,9 +223,9 @@ namespace pocketmine { $gitHash = str_repeat("00", 20); if(\Phar::running(true) === ""){ - if(Utils::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ + if(Process::execute("git rev-parse HEAD", $out) === 0 and $out !== false and strlen($out = trim($out)) === 40){ $gitHash = trim($out); - if(Utils::execute("git diff --quiet") === 1 or Utils::execute("git diff --cached --quiet") === 1){ //Locally-modified + if(Process::execute("git diff --quiet") === 1 or Process::execute("git diff --cached --quiet") === 1){ //Locally-modified $gitHash .= "-dirty"; } } @@ -268,7 +268,7 @@ namespace pocketmine { if(\pocketmine\DEBUG > 1){ echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; } - Utils::kill(getmypid()); + Process::kill(getmypid()); } }while(false); diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 6f33abae0..576504f5b 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -97,6 +97,7 @@ use pocketmine\updater\AutoUpdater; use pocketmine\utils\Config; use pocketmine\utils\Internet; use pocketmine\utils\MainLogger; +use pocketmine\utils\Process; use pocketmine\utils\Terminal; use pocketmine\utils\TextFormat; use pocketmine\utils\Utils; @@ -1682,7 +1683,7 @@ class Server{ }catch(\Throwable $e){ $this->logger->logException($e); $this->logger->emergency("Crashed while crashing, killing process"); - @Utils::kill(getmypid()); + @Process::kill(getmypid()); } } @@ -1807,7 +1808,7 @@ class Server{ echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL; sleep($spacing); } - @Utils::kill(getmypid()); + @Process::kill(getmypid()); exit(1); } @@ -1927,10 +1928,10 @@ class Server{ private function titleTick() : void{ Timings::$titleTickTimer->startTiming(); - $d = Utils::getRealMemoryUsage(); + $d = Process::getRealMemoryUsage(); - $u = Utils::getMemoryUsage(true); - $usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Utils::getThreadCount()); + $u = Process::getMemoryUsage(true); + $usage = sprintf("%g/%g/%g/%g MB @ %d threads", round(($u[0] / 1024) / 1024, 2), round(($d[0] / 1024) / 1024, 2), round(($u[1] / 1024) / 1024, 2), round(($u[2] / 1024) / 1024, 2), Process::getThreadCount()); $online = count($this->playerList); $connecting = $this->network->getConnectionCount() - $online; diff --git a/src/pocketmine/command/defaults/StatusCommand.php b/src/pocketmine/command/defaults/StatusCommand.php index 2a1d474e1..ac707ca78 100644 --- a/src/pocketmine/command/defaults/StatusCommand.php +++ b/src/pocketmine/command/defaults/StatusCommand.php @@ -24,8 +24,8 @@ declare(strict_types=1); namespace pocketmine\command\defaults; use pocketmine\command\CommandSender; +use pocketmine\utils\Process; use pocketmine\utils\TextFormat; -use pocketmine\utils\Utils; use function count; use function floor; use function microtime; @@ -48,8 +48,8 @@ class StatusCommand extends VanillaCommand{ return true; } - $rUsage = Utils::getRealMemoryUsage(); - $mUsage = Utils::getMemoryUsage(true); + $rUsage = Process::getRealMemoryUsage(); + $mUsage = Process::getMemoryUsage(true); $server = $sender->getServer(); $sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----"); @@ -94,7 +94,7 @@ class StatusCommand extends VanillaCommand{ $sender->sendMessage(TextFormat::GOLD . "Network upload: " . TextFormat::RED . round($server->getNetwork()->getUpload() / 1024, 2) . " kB/s"); $sender->sendMessage(TextFormat::GOLD . "Network download: " . TextFormat::RED . round($server->getNetwork()->getDownload() / 1024, 2) . " kB/s"); - $sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Utils::getThreadCount()); + $sender->sendMessage(TextFormat::GOLD . "Thread count: " . TextFormat::RED . Process::getThreadCount()); $sender->sendMessage(TextFormat::GOLD . "Main thread memory: " . TextFormat::RED . number_format(round(($mUsage[0] / 1024) / 1024, 2), 2) . " MB."); $sender->sendMessage(TextFormat::GOLD . "Total memory: " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2), 2) . " MB."); diff --git a/src/pocketmine/event/server/LowMemoryEvent.php b/src/pocketmine/event/server/LowMemoryEvent.php index 5e7412b1f..aaaaded62 100644 --- a/src/pocketmine/event/server/LowMemoryEvent.php +++ b/src/pocketmine/event/server/LowMemoryEvent.php @@ -23,7 +23,7 @@ declare(strict_types=1); namespace pocketmine\event\server; -use pocketmine\utils\Utils; +use pocketmine\utils\Process; /** @@ -87,6 +87,6 @@ class LowMemoryEvent extends ServerEvent{ * @return int */ public function getMemoryFreed() : int{ - return $this->getMemory() - ($this->isGlobal() ? Utils::getMemoryUsage(true)[1] : Utils::getMemoryUsage(true)[0]); + return $this->getMemory() - ($this->isGlobal() ? Process::getMemoryUsage(true)[1] : Process::getMemoryUsage(true)[0]); } } diff --git a/src/pocketmine/scheduler/SendUsageTask.php b/src/pocketmine/scheduler/SendUsageTask.php index ce0fce78e..c37cd1d4e 100644 --- a/src/pocketmine/scheduler/SendUsageTask.php +++ b/src/pocketmine/scheduler/SendUsageTask.php @@ -26,6 +26,7 @@ namespace pocketmine\scheduler; use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\Server; use pocketmine\utils\Internet; +use pocketmine\utils\Process; use pocketmine\utils\Utils; use pocketmine\utils\UUID; use pocketmine\utils\VersionString; @@ -135,12 +136,12 @@ class SendUsageTask extends AsyncTask{ "historyList" => array_values($playerList) ]; - $info = Utils::getMemoryUsage(true); + $info = Process::getMemoryUsage(true); $data["system"] = [ "mainMemory" => $info[0], "totalMemory" => $info[1], "availableMemory" => $info[2], - "threadCount" => Utils::getThreadCount() + "threadCount" => Process::getThreadCount() ]; break; diff --git a/src/pocketmine/utils/Process.php b/src/pocketmine/utils/Process.php new file mode 100644 index 000000000..3bca4302a --- /dev/null +++ b/src/pocketmine/utils/Process.php @@ -0,0 +1,171 @@ + 0){ + $VmRSS = $matches[1] * 1024; + } + + if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ + $VmSize = $matches[1] * 1024; + } + } + + //TODO: more OS + + if($VmRSS === null){ + $VmRSS = memory_get_usage(); + } + + if(!$advanced){ + return $VmRSS; + } + + if($VmSize === null){ + $VmSize = memory_get_usage(true); + } + + return [$reserved, $VmRSS, $VmSize]; + } + + /** + * @return int[] + */ + public static function getRealMemoryUsage() : array{ + $stack = 0; + $heap = 0; + + if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + $mappings = file("/proc/self/maps"); + foreach($mappings as $line){ + if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){ + if(strpos($matches[3], "heap") === 0){ + $heap += hexdec($matches[2]) - hexdec($matches[1]); + }elseif(strpos($matches[3], "stack") === 0){ + $stack += hexdec($matches[2]) - hexdec($matches[1]); + } + } + } + } + + return [$heap, $stack]; + } + + + public static function getThreadCount() : int{ + if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ + if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){ + return (int) $matches[1]; + } + } + + //TODO: more OS + + return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread + } + + public static function kill($pid) : void{ + $logger = \GlobalLogger::get(); + if($logger instanceof MainLogger){ + $logger->syncFlushBuffer(); + } + switch(Utils::getOS()){ + case "win": + exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL"); + break; + case "mac": + case "linux": + default: + if(function_exists("posix_kill")){ + posix_kill($pid, 9); //SIGKILL + }else{ + exec("kill -9 " . ((int) $pid) . " > /dev/null 2>&1"); + } + } + } + + /** + * @param string $command Command to execute + * @param string|null &$stdout Reference parameter to write stdout to + * @param string|null &$stderr Reference parameter to write stderr to + * + * @return int process exit code + */ + public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{ + $process = proc_open($command, [ + ["pipe", "r"], + ["pipe", "w"], + ["pipe", "w"] + ], $pipes); + + if($process === false){ + $stderr = "Failed to open process"; + $stdout = ""; + + return -1; + } + + $stdout = stream_get_contents($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + + foreach($pipes as $p){ + fclose($p); + } + + return proc_close($process); + } +} diff --git a/src/pocketmine/utils/ServerKiller.php b/src/pocketmine/utils/ServerKiller.php index 4a4dfe81d..d8abd40d3 100644 --- a/src/pocketmine/utils/ServerKiller.php +++ b/src/pocketmine/utils/ServerKiller.php @@ -48,7 +48,7 @@ class ServerKiller extends Thread{ }); if(time() - $start >= $this->time){ echo "\nTook too long to stop, server was killed forcefully!\n"; - @Utils::kill(getmypid()); + @Process::kill(getmypid()); } } diff --git a/src/pocketmine/utils/Utils.php b/src/pocketmine/utils/Utils.php index 244784165..25c3142e5 100644 --- a/src/pocketmine/utils/Utils.php +++ b/src/pocketmine/utils/Utils.php @@ -28,7 +28,6 @@ declare(strict_types=1); namespace pocketmine\utils; use DaveRandom\CallbackValidator\CallbackType; -use pocketmine\ThreadManager; use function array_combine; use function array_map; use function array_reverse; @@ -41,7 +40,6 @@ use function debug_zval_dump; use function dechex; use function exec; use function explode; -use function fclose; use function file; use function file_exists; use function file_get_contents; @@ -51,7 +49,6 @@ use function get_current_user; use function get_loaded_extensions; use function getenv; use function gettype; -use function hexdec; use function implode; use function is_array; use function is_dir; @@ -61,20 +58,16 @@ use function is_readable; use function is_string; use function json_decode; use function json_last_error_msg; -use function memory_get_usage; use function ob_end_clean; use function ob_get_contents; use function ob_start; use function ord; use function php_uname; use function phpversion; -use function posix_kill; use function preg_grep; use function preg_match; use function preg_match_all; use function preg_replace; -use function proc_close; -use function proc_open; use function rmdir; use function scandir; use function sha1; @@ -82,7 +75,6 @@ use function spl_object_hash; use function str_pad; use function str_replace; use function str_split; -use function stream_get_contents; use function stripos; use function strlen; use function strpos; @@ -279,77 +271,6 @@ class Utils{ return self::$os; } - /** - * @return int[] - */ - public static function getRealMemoryUsage() : array{ - $stack = 0; - $heap = 0; - - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - $mappings = file("/proc/self/maps"); - foreach($mappings as $line){ - if(preg_match("#([a-z0-9]+)\\-([a-z0-9]+) [rwxp\\-]{4} [a-z0-9]+ [^\\[]*\\[([a-zA-z0-9]+)\\]#", trim($line), $matches) > 0){ - if(strpos($matches[3], "heap") === 0){ - $heap += hexdec($matches[2]) - hexdec($matches[1]); - }elseif(strpos($matches[3], "stack") === 0){ - $stack += hexdec($matches[2]) - hexdec($matches[1]); - } - } - } - } - - return [$heap, $stack]; - } - - /** - * @param bool $advanced - * - * @return int[]|int - */ - public static function getMemoryUsage(bool $advanced = false){ - $reserved = memory_get_usage(); - $VmSize = null; - $VmRSS = null; - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - $status = file_get_contents("/proc/self/status"); - if(preg_match("/VmRSS:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ - $VmRSS = $matches[1] * 1024; - } - - if(preg_match("/VmSize:[ \t]+([0-9]+) kB/", $status, $matches) > 0){ - $VmSize = $matches[1] * 1024; - } - } - - //TODO: more OS - - if($VmRSS === null){ - $VmRSS = memory_get_usage(); - } - - if(!$advanced){ - return $VmRSS; - } - - if($VmSize === null){ - $VmSize = memory_get_usage(true); - } - - return [$reserved, $VmRSS, $VmSize]; - } - - public static function getThreadCount() : int{ - if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ - if(preg_match("/Threads:[ \t]+([0-9]+)/", file_get_contents("/proc/self/status"), $matches) > 0){ - return (int) $matches[1]; - } - } - //TODO: more OS - - return count(ThreadManager::getInstance()->getAll()) + 3; //RakLib + MainLogger + Main Thread - } - /** * @param bool $recalculate * @@ -457,37 +378,6 @@ class Utils{ } - /** - * @param string $command Command to execute - * @param string|null &$stdout Reference parameter to write stdout to - * @param string|null &$stderr Reference parameter to write stderr to - * - * @return int process exit code - */ - public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{ - $process = proc_open($command, [ - ["pipe", "r"], - ["pipe", "w"], - ["pipe", "w"] - ], $pipes); - - if($process === false){ - $stderr = "Failed to open process"; - $stdout = ""; - - return -1; - } - - $stdout = stream_get_contents($pipes[1]); - $stderr = stream_get_contents($pipes[2]); - - foreach($pipes as $p){ - fclose($p); - } - - return proc_close($process); - } - /** * @param string $token * @@ -513,26 +403,6 @@ class Utils{ return $result; } - public static function kill($pid) : void{ - $logger = \GlobalLogger::get(); - if($logger instanceof MainLogger){ - $logger->syncFlushBuffer(); - } - switch(Utils::getOS()){ - case "win": - exec("taskkill.exe /F /PID " . ((int) $pid) . " > NUL"); - break; - case "mac": - case "linux": - default: - if(function_exists("posix_kill")){ - posix_kill($pid, 9); //SIGKILL - }else{ - exec("kill -9 " . ((int) $pid) . " > /dev/null 2>&1"); - } - } - } - /** * @param object $value * @param bool $includeCurrent