backport 23071d257 + deprecations: Extract process-related functions from Utils into a separate Process class

This commit is contained in:
Dylan K. Taylor 2019-03-24 18:57:32 +00:00
parent a8433697ad
commit 4635b93f4d
9 changed files with 218 additions and 117 deletions

View File

@ -27,6 +27,7 @@ use pocketmine\event\server\LowMemoryEvent;
use pocketmine\scheduler\DumpWorkerMemoryTask; use pocketmine\scheduler\DumpWorkerMemoryTask;
use pocketmine\scheduler\GarbageCollectionTask; use pocketmine\scheduler\GarbageCollectionTask;
use pocketmine\timings\Timings; use pocketmine\timings\Timings;
use pocketmine\utils\Process;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use function arsort; use function arsort;
use function count; use function count;
@ -236,7 +237,7 @@ class MemoryManager{
if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){ if(($this->memoryLimit > 0 or $this->globalMemoryLimit > 0) and ++$this->checkTicker >= $this->checkRate){
$this->checkTicker = 0; $this->checkTicker = 0;
$memory = Utils::getMemoryUsage(true); $memory = Process::getMemoryUsage(true);
$trigger = false; $trigger = false;
if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){ if($this->memoryLimit > 0 and $memory[0] > $this->memoryLimit){
$trigger = 0; $trigger = 0;

View File

@ -29,6 +29,7 @@ namespace {
namespace pocketmine { namespace pocketmine {
use pocketmine\utils\MainLogger; use pocketmine\utils\MainLogger;
use pocketmine\utils\Process;
use pocketmine\utils\ServerKiller; use pocketmine\utils\ServerKiller;
use pocketmine\utils\Terminal; use pocketmine\utils\Terminal;
use pocketmine\utils\Timezone; use pocketmine\utils\Timezone;
@ -238,9 +239,9 @@ namespace pocketmine {
$gitHash = str_repeat("00", 20); $gitHash = str_repeat("00", 20);
if(\Phar::running(true) === ""){ 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); $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"; $gitHash .= "-dirty";
} }
} }
@ -283,7 +284,7 @@ namespace pocketmine {
if(\pocketmine\DEBUG > 1){ if(\pocketmine\DEBUG > 1){
echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL; echo "Some threads could not be stopped, performing a force-kill" . PHP_EOL . PHP_EOL;
} }
Utils::kill(getmypid()); Process::kill(getmypid());
} }
}while(false); }while(false);

View File

@ -101,6 +101,7 @@ use pocketmine\updater\AutoUpdater;
use pocketmine\utils\Config; use pocketmine\utils\Config;
use pocketmine\utils\Internet; use pocketmine\utils\Internet;
use pocketmine\utils\MainLogger; use pocketmine\utils\MainLogger;
use pocketmine\utils\Process;
use pocketmine\utils\Terminal; use pocketmine\utils\Terminal;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
@ -2150,7 +2151,7 @@ class Server{
}catch(\Throwable $e){ }catch(\Throwable $e){
$this->logger->logException($e); $this->logger->logException($e);
$this->logger->emergency("Crashed while crashing, killing process"); $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; echo "--- Waiting $spacing seconds to throttle automatic restart (you can kill the process safely now) ---" . PHP_EOL;
sleep($spacing); sleep($spacing);
} }
@Utils::kill(getmypid()); @Process::kill(getmypid());
exit(1); exit(1);
} }
@ -2507,10 +2508,10 @@ class Server{
private function titleTick(){ private function titleTick(){
Timings::$titleTickTimer->startTiming(); Timings::$titleTickTimer->startTiming();
$d = Utils::getRealMemoryUsage(); $d = Process::getRealMemoryUsage();
$u = Utils::getMemoryUsage(true); $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), Utils::getThreadCount()); $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() . " " . echo "\x1b]0;" . $this->getName() . " " .
$this->getPocketMineVersion() . $this->getPocketMineVersion() .

View File

@ -24,8 +24,8 @@ declare(strict_types=1);
namespace pocketmine\command\defaults; namespace pocketmine\command\defaults;
use pocketmine\command\CommandSender; use pocketmine\command\CommandSender;
use pocketmine\utils\Process;
use pocketmine\utils\TextFormat; use pocketmine\utils\TextFormat;
use pocketmine\utils\Utils;
use function count; use function count;
use function floor; use function floor;
use function microtime; use function microtime;
@ -48,8 +48,8 @@ class StatusCommand extends VanillaCommand{
return true; return true;
} }
$rUsage = Utils::getRealMemoryUsage(); $rUsage = Process::getRealMemoryUsage();
$mUsage = Utils::getMemoryUsage(true); $mUsage = Process::getMemoryUsage(true);
$server = $sender->getServer(); $server = $sender->getServer();
$sender->sendMessage(TextFormat::GREEN . "---- " . TextFormat::WHITE . "Server status" . TextFormat::GREEN . " ----"); $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 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 . "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 . "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."); $sender->sendMessage(TextFormat::GOLD . "Total memory: " . TextFormat::RED . number_format(round(($mUsage[1] / 1024) / 1024, 2), 2) . " MB.");

View File

@ -23,7 +23,7 @@ declare(strict_types=1);
namespace pocketmine\event\server; namespace pocketmine\event\server;
use pocketmine\utils\Utils; use pocketmine\utils\Process;
/** /**
@ -87,6 +87,6 @@ class LowMemoryEvent extends ServerEvent{
* @return int * @return int
*/ */
public function getMemoryFreed() : 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]);
} }
} }

View File

@ -26,6 +26,7 @@ namespace pocketmine\scheduler;
use pocketmine\network\mcpe\protocol\ProtocolInfo; use pocketmine\network\mcpe\protocol\ProtocolInfo;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\utils\Internet; use pocketmine\utils\Internet;
use pocketmine\utils\Process;
use pocketmine\utils\Utils; use pocketmine\utils\Utils;
use pocketmine\utils\UUID; use pocketmine\utils\UUID;
use pocketmine\utils\VersionString; use pocketmine\utils\VersionString;
@ -135,12 +136,12 @@ class SendUsageTask extends AsyncTask{
"historyList" => array_values($playerList) "historyList" => array_values($playerList)
]; ];
$info = Utils::getMemoryUsage(true); $info = Process::getMemoryUsage(true);
$data["system"] = [ $data["system"] = [
"mainMemory" => $info[0], "mainMemory" => $info[0],
"totalMemory" => $info[1], "totalMemory" => $info[1],
"availableMemory" => $info[2], "availableMemory" => $info[2],
"threadCount" => Utils::getThreadCount() "threadCount" => Process::getThreadCount()
]; ];
break; break;

View File

@ -0,0 +1,170 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\utils;
use pocketmine\ThreadManager;
use function count;
use function exec;
use function fclose;
use function file;
use function file_get_contents;
use function function_exists;
use function hexdec;
use function memory_get_usage;
use function preg_match;
use function proc_close;
use function proc_open;
use function stream_get_contents;
use function strpos;
use function trim;
final class Process{
private function __construct(){
//NOOP
}
/**
* @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 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);
}
}

View File

@ -48,7 +48,7 @@ class ServerKiller extends Thread{
}); });
if(time() - $start >= $this->time){ if(time() - $start >= $this->time){
echo "\nTook too long to stop, server was killed forcefully!\n"; echo "\nTook too long to stop, server was killed forcefully!\n";
@Utils::kill(getmypid()); @Process::kill(getmypid());
} }
} }

View File

@ -28,7 +28,6 @@ declare(strict_types=1);
namespace pocketmine\utils; namespace pocketmine\utils;
use DaveRandom\CallbackValidator\CallbackType; use DaveRandom\CallbackValidator\CallbackType;
use pocketmine\ThreadManager;
use function array_combine; use function array_combine;
use function array_map; use function array_map;
use function array_reverse; use function array_reverse;
@ -42,7 +41,6 @@ use function dechex;
use function error_reporting; use function error_reporting;
use function exec; use function exec;
use function explode; use function explode;
use function fclose;
use function file; use function file;
use function file_exists; use function file_exists;
use function file_get_contents; use function file_get_contents;
@ -51,7 +49,6 @@ use function get_current_user;
use function get_loaded_extensions; use function get_loaded_extensions;
use function getenv; use function getenv;
use function gettype; use function gettype;
use function hexdec;
use function implode; use function implode;
use function is_array; use function is_array;
use function is_dir; use function is_dir;
@ -60,20 +57,16 @@ use function is_object;
use function is_readable; use function is_readable;
use function is_string; use function is_string;
use function json_decode; use function json_decode;
use function memory_get_usage;
use function ob_end_clean; use function ob_end_clean;
use function ob_get_contents; use function ob_get_contents;
use function ob_start; use function ob_start;
use function ord; use function ord;
use function php_uname; use function php_uname;
use function phpversion; use function phpversion;
use function posix_kill;
use function preg_grep; use function preg_grep;
use function preg_match; use function preg_match;
use function preg_match_all; use function preg_match_all;
use function preg_replace; use function preg_replace;
use function proc_close;
use function proc_open;
use function rmdir; use function rmdir;
use function scandir; use function scandir;
use function sha1; use function sha1;
@ -81,7 +74,6 @@ use function spl_object_hash;
use function str_pad; use function str_pad;
use function str_replace; use function str_replace;
use function str_split; use function str_split;
use function stream_get_contents;
use function stripos; use function stripos;
use function strlen; use function strlen;
use function strpos; use function strpos;
@ -289,74 +281,35 @@ class Utils{
} }
/** /**
* @deprecated
* @see Process::getRealMemoryUsage()
*
* @return int[] * @return int[]
*/ */
public static function getRealMemoryUsage() : array{ public static function getRealMemoryUsage() : array{
$stack = 0; return Process::getRealMemoryUsage();
$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];
} }
/** /**
* @deprecated
* @see Process::getMemoryUsage()
*
* @param bool $advanced * @param bool $advanced
* *
* @return int[]|int * @return int[]|int
*/ */
public static function getMemoryUsage(bool $advanced = false){ public static function getMemoryUsage(bool $advanced = false){
$reserved = memory_get_usage(); return Process::getMemoryUsage($advanced);
$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];
} }
/**
* @deprecated
* @see Process::getThreadCount()
*
* @return int
*/
public static function getThreadCount() : int{ public static function getThreadCount() : int{
if(Utils::getOS() === "linux" or Utils::getOS() === "android"){ return Process::getThreadCount();
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
} }
/** /**
@ -520,6 +473,9 @@ class Utils{
/** /**
* @deprecated
* @see Process::execute()
*
* @param string $command Command to execute * @param string $command Command to execute
* @param string|null &$stdout Reference parameter to write stdout to * @param string|null &$stdout Reference parameter to write stdout to
* @param string|null &$stderr Reference parameter to write stderr to * @param string|null &$stderr Reference parameter to write stderr to
@ -527,27 +483,7 @@ class Utils{
* @return int process exit code * @return int process exit code
*/ */
public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{ public static function execute(string $command, string &$stdout = null, string &$stderr = null) : int{
$process = proc_open($command, [ return Process::execute($command, $stdout, $stderr);
["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);
} }
public static function decodeJWT(string $token) : array{ public static function decodeJWT(string $token) : array{
@ -556,23 +492,14 @@ class Utils{
return json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true); return json_decode(base64_decode(strtr($payloadB64, '-_', '+/'), true), true);
} }
/**
* @deprecated
* @see Process::kill()
*
* @param int $pid
*/
public static function kill($pid) : void{ public static function kill($pid) : void{
if(MainLogger::isRegisteredStatic()){ Process::kill($pid);
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");
}
}
} }
/** /**