Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15395834
D11863.id28576.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D11863.id28576.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -317,6 +317,8 @@
'PhutilSyntaxHighlighter' => 'markup/syntax/highlighter/PhutilSyntaxHighlighter.php',
'PhutilSyntaxHighlighterEngine' => 'markup/syntax/engine/PhutilSyntaxHighlighterEngine.php',
'PhutilSyntaxHighlighterException' => 'markup/syntax/highlighter/PhutilSyntaxHighlighterException.php',
+ 'PhutilSystem' => 'utils/PhutilSystem.php',
+ 'PhutilSystemTestCase' => 'utils/__tests__/PhutilSystemTestCase.php',
'PhutilTestCase' => 'infrastructure/testing/PhutilTestCase.php',
'PhutilTestPhobject' => 'object/__tests__/PhutilTestPhobject.php',
'PhutilTortureTestDaemon' => 'daemon/torture/PhutilTortureTestDaemon.php',
@@ -715,6 +717,8 @@
'PhutilSimpleOptionsTestCase' => 'PhutilTestCase',
'PhutilSocketChannel' => 'PhutilChannel',
'PhutilSyntaxHighlighterException' => 'Exception',
+ 'PhutilSystem' => 'Phobject',
+ 'PhutilSystemTestCase' => 'PhutilTestCase',
'PhutilTestCase' => 'ArcanistPhutilTestCase',
'PhutilTestPhobject' => 'Phobject',
'PhutilTortureTestDaemon' => 'PhutilDaemon',
diff --git a/src/utils/PhutilSystem.php b/src/utils/PhutilSystem.php
new file mode 100644
--- /dev/null
+++ b/src/utils/PhutilSystem.php
@@ -0,0 +1,158 @@
+<?php
+
+/**
+ * Interact with the operating system.
+ *
+ * @task memory Interacting with System Memory
+ */
+final class PhutilSystem extends Phobject {
+
+
+ /**
+ * Get information about total and free memory on the system.
+ *
+ * Because "free memory" is a murky concept, the interpretation of the values
+ * returned from this method will vary from system to system and the numbers
+ * themselves may be only roughly accurate.
+ *
+ * @return map<string, wild> Dictionary of memory information.
+ * @task memory
+ */
+ public static function getSystemMemoryInformation() {
+ $meminfo_path = '/proc/meminfo';
+ if (Filesystem::pathExists($meminfo_path)) {
+ $meminfo_data = Filesystem::readFile($meminfo_path);
+ return self::parseMemInfo($meminfo_data);
+ } else if (Filesystem::binaryExists('vm_stat')) {
+ list($vm_stat_stdout) = execx('vm_stat');
+ return self::parseVMStat($vm_stat_stdout);
+ } else {
+ throw new Exception(
+ pht(
+ 'Unable to access /proc/meminfo or `vm_stat` on this system to '.
+ 'get system memory information.'));
+ }
+ }
+
+
+ /**
+ * Parse the output of `/proc/meminfo`.
+ *
+ * See @{method:getSystemMemoryInformation}. This method is used to get memory
+ * information on Linux.
+ *
+ * @param string Raw `/proc/meminfo`.
+ * @return map<string, wild> Parsed memory information.
+ * @task memory
+ */
+ public static function parseMemInfo($data) {
+ $data = phutil_split_lines($data);
+
+ $map = array();
+ foreach ($data as $line) {
+ list($key, $value) = explode(':', $line, 2);
+ $key = trim($key);
+ $value = trim($value);
+
+ $matches = null;
+ if (preg_match('/^(\d+) kB\z/', $value, $matches)) {
+ $value = (int)$matches[1] * 1024;
+ }
+
+ $map[$key] = $value;
+ }
+
+ $expect = array(
+ 'MemTotal',
+ 'MemFree',
+ 'Buffers',
+ 'Cached',
+ );
+ foreach ($expect as $key) {
+ if (!array_key_exists($key, $map)) {
+ throw new Exception(
+ pht(
+ 'Expected to find "%s" in "/proc/meminfo" output, but did not.',
+ $key));
+ }
+ }
+
+ $total = $map['MemTotal'];
+ $free = $map['MemFree'] + $map['Buffers'] + $map['Cached'];
+
+ return array(
+ 'total' => $total,
+ 'free' => $free,
+ );
+ }
+
+
+ /**
+ * Parse the output of `vm_stat`.
+ *
+ * See @{method:getSystemMemoryInformation}. This method is used to get memory
+ * information on Mac OS X.
+ *
+ * @param string Raw `vm_stat` output.
+ * @return map<string, wild> Parsed memory information.
+ * @task memory
+ */
+ public static function parseVMStat($data) {
+ $data = phutil_split_lines($data);
+
+ $page_size = null;
+ $map = array();
+
+ foreach ($data as $line) {
+ list($key, $value) = explode(':', $line, 2);
+ $key = trim($key);
+ $value = trim($value);
+
+ $matches = null;
+ if (preg_match('/page size of (\d+) bytes/', $value, $matches)) {
+ $page_size = (int)$matches[1];
+ continue;
+ }
+
+ $value = trim($value, '.');
+ $map[$key] = $value;
+ }
+
+ if (!$page_size) {
+ throw new Exception(
+ pht(
+ 'Expected to find "page size" in `vm_stat` output, but did not.'));
+ }
+
+ $expect = array(
+ 'Pages free',
+ 'Pages active',
+ 'Pages inactive',
+ 'Pages wired down',
+ );
+ foreach ($expect as $key) {
+ if (!array_key_exists($key, $map)) {
+ throw new Exception(
+ pht(
+ 'Expected to find "%s" in `vm_stat` output, but did not.',
+ $key));
+ }
+ }
+
+ // NOTE: This calculation probably isn't quite right. In particular,
+ // the numbers don't exactly add up, and "Pages inactive" includes a
+ // bunch of disk cache. So these numbers aren't totally reliable and they
+ // aren't directly comparable to the /proc/meminfo numbers.
+
+ $free = $map['Pages free'];
+ $active = $map['Pages active'];
+ $inactive = $map['Pages inactive'];
+ $wired = $map['Pages wired down'];
+
+ return array(
+ 'total' => ($free + $active + $inactive + $wired) * $page_size,
+ 'free' => ($free) * $page_size,
+ );
+ }
+
+}
diff --git a/src/utils/__tests__/PhutilSystemTestCase.php b/src/utils/__tests__/PhutilSystemTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/utils/__tests__/PhutilSystemTestCase.php
@@ -0,0 +1,43 @@
+<?php
+
+final class PhutilSystemTestCase extends PhutilTestCase {
+
+ public function testParseVMStat() {
+ $tests = array(
+ 'vmstat.yosemite.txt' => array(
+ 'total' => 16503578624,
+ 'free' => 1732366336,
+ ),
+ );
+
+ $dir = dirname(__FILE__).'/memory';
+ foreach ($tests as $input => $expect) {
+ $raw = Filesystem::readFile($dir.'/'.$input);
+ $actual = PhutilSystem::parseVMStat($raw);
+ $this->assertEqual(
+ $expect,
+ $actual,
+ pht('Parse of "%s".', $input));
+ }
+ }
+
+ public function testParseMeminfo() {
+ $tests = array(
+ 'meminfo.ubuntu14.txt' => array(
+ 'total' => 7843336192,
+ 'free' => 3758297088,
+ ),
+ );
+
+ $dir = dirname(__FILE__).'/memory';
+ foreach ($tests as $input => $expect) {
+ $raw = Filesystem::readFile($dir.'/'.$input);
+ $actual = PhutilSystem::parseMemInfo($raw);
+ $this->assertEqual(
+ $expect,
+ $actual,
+ pht('Parse of "%s".', $input));
+ }
+ }
+
+}
diff --git a/src/utils/__tests__/memory/meminfo.ubuntu14.txt b/src/utils/__tests__/memory/meminfo.ubuntu14.txt
new file mode 100644
--- /dev/null
+++ b/src/utils/__tests__/memory/meminfo.ubuntu14.txt
@@ -0,0 +1,42 @@
+MemTotal: 7659508 kB
+MemFree: 246684 kB
+Buffers: 126580 kB
+Cached: 3296948 kB
+SwapCached: 0 kB
+Active: 4916076 kB
+Inactive: 1732880 kB
+Active(anon): 3225504 kB
+Inactive(anon): 20576 kB
+Active(file): 1690572 kB
+Inactive(file): 1712304 kB
+Unevictable: 0 kB
+Mlocked: 0 kB
+SwapTotal: 0 kB
+SwapFree: 0 kB
+Dirty: 32 kB
+Writeback: 0 kB
+AnonPages: 3225428 kB
+Mapped: 37500 kB
+Shmem: 20652 kB
+Slab: 633908 kB
+SReclaimable: 467472 kB
+SUnreclaim: 166436 kB
+KernelStack: 2416 kB
+PageTables: 64744 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 3829752 kB
+Committed_AS: 4935116 kB
+VmallocTotal: 34359738367 kB
+VmallocUsed: 17244 kB
+VmallocChunk: 34359712740 kB
+HardwareCorrupted: 0 kB
+AnonHugePages: 954368 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB
+DirectMap4k: 45056 kB
+DirectMap2M: 7950336 kB
diff --git a/src/utils/__tests__/memory/vmstat.yosemite.txt b/src/utils/__tests__/memory/vmstat.yosemite.txt
new file mode 100644
--- /dev/null
+++ b/src/utils/__tests__/memory/vmstat.yosemite.txt
@@ -0,0 +1,23 @@
+Mach Virtual Memory Statistics: (page size of 4096 bytes)
+Pages free: 422941.
+Pages active: 2348641.
+Pages inactive: 830440.
+Pages speculative: 110635.
+Pages throttled: 0.
+Pages wired down: 427172.
+Pages purgeable: 33368.
+"Translation faults": 931955891.
+Pages copy-on-write: 59498342.
+Pages zero filled: 411628732.
+Pages reactivated: 175636.
+Pages purged: 569552.
+File-backed pages: 926777.
+Anonymous pages: 2362939.
+Pages stored in compressor: 125673.
+Pages occupied by compressor: 51938.
+Decompressions: 32945.
+Compressions: 197789.
+Pageins: 13750115.
+Pageouts: 39562.
+Swapins: 0.
+Swapouts: 2290.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 17, 10:00 AM (1 w, 2 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7708222
Default Alt Text
D11863.id28576.diff (9 KB)
Attached To
Mode
D11863: Add a utility class for getting system memory information
Attached
Detach File
Event Timeline
Log In to Comment