diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index d6e03a393..77ecca9d4 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 732026434..4b79ed5da 100644 --- a/src/pocketmine/PocketMine.php +++ b/src/pocketmine/PocketMine.php @@ -29,6 +29,7 @@ namespace { namespace pocketmine { use pocketmine\utils\MainLogger; + use pocketmine\utils\Process; use pocketmine\utils\ServerKiller; use pocketmine\utils\Terminal; use pocketmine\utils\Timezone; @@ -238,9 +239,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"; } } @@ -283,7 +284,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 8de8151d4..3468c6c83 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -101,6 +101,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; @@ -2150,7 +2151,7 @@ class Server{ }catch(\Throwable $e){ $this->logger->logException($e); $this->logger->emergency("Crashed while crashing, killing process"); - @Utils::kill(getmypid()); + @Process::kill(getmypid()); } } @@ -2326,7 +2327,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); } @@ -2507,10 +2508,10 @@ class Server{ private function titleTick(){ 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()); echo "\x1b]0;" . $this->getName() . " " . $this->getPocketMineVersion() . diff --git a/src/pocketmine/command/defaults/StatusCommand.php b/src/pocketmine/command/defaults/StatusCommand.php index d43f7df28..9fb0253bb 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 7edd523f7..a566364a9 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..f5df0f703 --- /dev/null +++ b/src/pocketmine/utils/Process.php @@ -0,0 +1,170 @@ + 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{ + if(MainLogger::isRegisteredStatic()){ + MainLogger::getLogger()->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 ff3ecd448..539f00af8 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 a2fdf85a0..d4d89f1e5 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; @@ -42,7 +41,6 @@ use function dechex; use function error_reporting; 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; @@ -60,20 +57,16 @@ use function is_object; use function is_readable; use function is_string; use function json_decode; -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; @@ -81,7 +74,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; @@ -289,74 +281,35 @@ class Utils{ } /** + * @deprecated + * @see Process::getRealMemoryUsage() + * * @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]; + return Process::getRealMemoryUsage(); } /** + * @deprecated + * @see Process::getMemoryUsage() + * * @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]; + return Process::getMemoryUsage($advanced); } + /** + * @deprecated + * @see Process::getThreadCount() + * + * @return int + */ 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 + return Process::getThreadCount(); } /** @@ -520,6 +473,9 @@ class Utils{ /** + * @deprecated + * @see Process::execute() + * * @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 @@ -527,27 +483,7 @@ class Utils{ * @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); + return Process::execute($command, $stdout, $stderr); } public static function decodeJWT(string $token) : array{ @@ -556,23 +492,14 @@ class Utils{ return json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true); } + /** + * @deprecated + * @see Process::kill() + * + * @param int $pid + */ public static function kill($pid) : void{ - if(MainLogger::isRegisteredStatic()){ - MainLogger::getLogger()->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"); - } - } + Process::kill($pid); } /**