Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15395339
D21733.id51793.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D21733.id51793.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
@@ -264,6 +264,8 @@
'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php',
'ArcanistHgProxyServer' => 'hgdaemon/ArcanistHgProxyServer.php',
'ArcanistHgServerChannel' => 'hgdaemon/ArcanistHgServerChannel.php',
+ 'ArcanistHostMemorySnapshot' => 'filesystem/memory/ArcanistHostMemorySnapshot.php',
+ 'ArcanistHostMemorySnapshotTestCase' => 'filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php',
'ArcanistImplicitConstructorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitConstructorXHPASTLinterRule.php',
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitConstructorXHPASTLinterRuleTestCase.php',
'ArcanistImplicitFallthroughXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitFallthroughXHPASTLinterRule.php',
@@ -1323,6 +1325,8 @@
'ArcanistHgProxyClient' => 'Phobject',
'ArcanistHgProxyServer' => 'Phobject',
'ArcanistHgServerChannel' => 'PhutilProtocolChannel',
+ 'ArcanistHostMemorySnapshot' => 'Phobject',
+ 'ArcanistHostMemorySnapshotTestCase' => 'PhutilTestCase',
'ArcanistImplicitConstructorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistImplicitFallthroughXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
diff --git a/src/filesystem/memory/ArcanistHostMemorySnapshot.php b/src/filesystem/memory/ArcanistHostMemorySnapshot.php
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/ArcanistHostMemorySnapshot.php
@@ -0,0 +1,156 @@
+<?php
+
+final class ArcanistHostMemorySnapshot
+ extends Phobject {
+
+ private $memorySnapshot;
+
+ public static function newFromRawMeminfo($meminfo_source, $meminfo_raw) {
+ $snapshot = new self();
+
+ $snapshot->memorySnapshot = $snapshot->readMeminfoSnapshot(
+ $meminfo_source,
+ $meminfo_raw);
+
+ return $snapshot;
+ }
+
+ public function getTotalSwapBytes() {
+ $info = $this->getMemorySnapshot();
+ return $info['swap.total'];
+ }
+
+ private function getMemorySnapshot() {
+ if ($this->memorySnapshot === null) {
+ $this->memorySnapshot = $this->newMemorySnapshot();
+ }
+
+ return $this->memorySnapshot;
+ }
+
+ private function newMemorySnapshot() {
+ $meminfo_source = '/proc/meminfo';
+ list($meminfo_raw) = execx('cat %s', $meminfo_source);
+ return $this->readMeminfoSnapshot($meminfo_source, $meminfo_raw);
+ }
+
+ private function readMeminfoSnapshot($meminfo_source, $meminfo_raw) {
+ $meminfo_pattern = '/^([^:]+):\s+(\S+)(?:\s+(kB))?\z/';
+
+ $meminfo_map = array();
+
+ $meminfo_lines = phutil_split_lines($meminfo_raw, false);
+ foreach ($meminfo_lines as $meminfo_line) {
+ $meminfo_parts = phutil_preg_match($meminfo_pattern, $meminfo_line);
+
+ if (!$meminfo_parts) {
+ throw new Exception(
+ pht(
+ 'Unable to parse line in meminfo source "%s": "%s".',
+ $meminfo_source,
+ $meminfo_line));
+ }
+
+ $meminfo_key = $meminfo_parts[1];
+ $meminfo_value = $meminfo_parts[2];
+ $meminfo_unit = idx($meminfo_parts, 3);
+
+ if (isset($meminfo_map[$meminfo_key])) {
+ throw new Exception(
+ pht(
+ 'Encountered duplicate meminfo key "%s" in meminfo source "%s".',
+ $meminfo_key,
+ $meminfo_source));
+ }
+
+ $meminfo_map[$meminfo_key] = array(
+ 'value' => $meminfo_value,
+ 'unit' => $meminfo_unit,
+ );
+ }
+
+ $swap_total_bytes = $this->readMeminfoBytes(
+ $meminfo_source,
+ $meminfo_map,
+ 'SwapTotal');
+
+ return array(
+ 'swap.total' => $swap_total_bytes,
+ );
+ }
+
+ private function readMeminfoBytes(
+ $meminfo_source,
+ $meminfo_map,
+ $meminfo_key) {
+
+ $meminfo_integer = $this->readMeminfoIntegerValue(
+ $meminfo_source,
+ $meminfo_map,
+ $meminfo_key);
+
+ $meminfo_unit = $meminfo_map[$meminfo_key]['unit'];
+ if ($meminfo_unit === null) {
+ throw new Exception(
+ pht(
+ 'Expected to find a byte unit for meminfo key "%s" in meminfo '.
+ 'source "%s", found no unit.',
+ $meminfo_key,
+ $meminfo_source));
+ }
+
+ if ($meminfo_unit !== 'kB') {
+ throw new Exception(
+ pht(
+ 'Expected unit for meminfo key "%s" in meminfo source "%s" '.
+ 'to be "kB", found "%s".',
+ $meminfo_key,
+ $meminfo_source,
+ $meminfo_unit));
+ }
+
+ $meminfo_bytes = ($meminfo_integer * 1024);
+
+ return $meminfo_bytes;
+ }
+
+ private function readMeminfoIntegerValue(
+ $meminfo_source,
+ $meminfo_map,
+ $meminfo_key) {
+
+ $meminfo_value = $this->readMeminfoValue(
+ $meminfo_source,
+ $meminfo_map,
+ $meminfo_key);
+
+ if (!phutil_preg_match('/^\d+\z/', $meminfo_value)) {
+ throw new Exception(
+ pht(
+ 'Expected to find an integer value for meminfo key "%s" in '.
+ 'meminfo source "%s", found "%s".',
+ $meminfo_key,
+ $meminfo_source,
+ $meminfo_value));
+ }
+
+ return (int)$meminfo_value;
+ }
+
+ private function readMeminfoValue(
+ $meminfo_source,
+ $meminfo_map,
+ $meminfo_key) {
+
+ if (!isset($meminfo_map[$meminfo_key])) {
+ throw new Exception(
+ pht(
+ 'Expected to find meminfo key "%s" in meminfo source "%s".',
+ $meminfo_key,
+ $meminfo_source));
+ }
+
+ return $meminfo_map[$meminfo_key]['value'];
+ }
+
+}
diff --git a/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php b/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php
@@ -0,0 +1,51 @@
+<?php
+
+final class ArcanistHostMemorySnapshotTestCase
+ extends PhutilTestCase {
+
+ public function testSnapshotSwapTotalBytes() {
+ $test_cases = array(
+ 'meminfo_swap_normal.txt' => 4294963200,
+ 'meminfo_swap_zero.txt' => 0,
+ 'meminfo_swap_missing.txt' => false,
+ 'meminfo_swap_invalid.txt' => false,
+ 'meminfo_swap_badunits.txt' => false,
+ 'meminfo_swap_duplicate.txt' => false,
+ );
+
+ $test_dir = dirname(__FILE__).'/data/';
+
+ foreach ($test_cases as $test_file => $expect) {
+ $test_data = Filesystem::readFile($test_dir.$test_file);
+
+ $caught = null;
+ $actual = null;
+ try {
+ $snapshot = ArcanistHostMemorySnapshot::newFromRawMeminfo(
+ $test_file,
+ $test_data);
+ $actual = $snapshot->getTotalSwapBytes();
+ } catch (Exception $ex) {
+ if ($expect === false) {
+ $caught = $ex;
+ } else {
+ throw $ex;
+ }
+ } catch (Throwable $ex) {
+ throw $ex;
+ }
+
+ if ($expect === false) {
+ $this->assertTrue(
+ ($caught instanceof Exception),
+ pht('Expected exception for "%s".', $test_file));
+ } else {
+ $this->assertEqual(
+ $expect,
+ $actual,
+ pht('Result for "%s".', $test_file));
+ }
+ }
+ }
+
+}
diff --git a/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt b/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/data/meminfo_swap_badunits.txt
@@ -0,0 +1,2 @@
+MemTotal: 8140924 kB
+SwapTotal: 4194 mB
diff --git a/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt b/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/data/meminfo_swap_duplicate.txt
@@ -0,0 +1,3 @@
+MemTotal: 8140924 kB
+SwapTotal: 4194300 kB
+SwapTotal: 4194300 kB
diff --git a/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt b/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/data/meminfo_swap_invalid.txt
@@ -0,0 +1,2 @@
+MemTotal: 8140924 kB
+SwapTotal: aardvark kB
diff --git a/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt b/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/data/meminfo_swap_missing.txt
@@ -0,0 +1 @@
+MemTotal: 8140924 kB
diff --git a/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt b/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt
@@ -0,0 +1,51 @@
+MemTotal: 8140924 kB
+MemFree: 1760456 kB
+MemAvailable: 4264888 kB
+Buffers: 36784 kB
+Cached: 2654788 kB
+SwapCached: 2132 kB
+Active: 331128 kB
+Inactive: 5677400 kB
+Active(anon): 22692 kB
+Inactive(anon): 3325560 kB
+Active(file): 308436 kB
+Inactive(file): 2351840 kB
+Unevictable: 23012 kB
+Mlocked: 18476 kB
+SwapTotal: 4194300 kB
+SwapFree: 2440444 kB
+Dirty: 44 kB
+Writeback: 0 kB
+AnonPages: 3337944 kB
+Mapped: 117424 kB
+Shmem: 19872 kB
+KReclaimable: 124728 kB
+Slab: 240640 kB
+SReclaimable: 124728 kB
+SUnreclaim: 115912 kB
+KernelStack: 6736 kB
+PageTables: 42044 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 8264760 kB
+Committed_AS: 6994880 kB
+VmallocTotal: 34359738367 kB
+VmallocUsed: 16656 kB
+VmallocChunk: 0 kB
+Percpu: 9856 kB
+HardwareCorrupted: 0 kB
+AnonHugePages: 0 kB
+ShmemHugePages: 0 kB
+ShmemPmdMapped: 0 kB
+FileHugePages: 0 kB
+FilePmdMapped: 0 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB
+Hugetlb: 0 kB
+DirectMap4k: 270336 kB
+DirectMap2M: 8118272 kB
+DirectMap1G: 1048576 kB
diff --git a/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt b/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt
new file mode 100644
--- /dev/null
+++ b/src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt
@@ -0,0 +1,51 @@
+MemTotal: 8140924 kB
+MemFree: 1760456 kB
+MemAvailable: 4264888 kB
+Buffers: 36784 kB
+Cached: 2654788 kB
+SwapCached: 2132 kB
+Active: 331128 kB
+Inactive: 5677400 kB
+Active(anon): 22692 kB
+Inactive(anon): 3325560 kB
+Active(file): 308436 kB
+Inactive(file): 2351840 kB
+Unevictable: 23012 kB
+Mlocked: 18476 kB
+SwapTotal: 0 kB
+SwapFree: 2440444 kB
+Dirty: 44 kB
+Writeback: 0 kB
+AnonPages: 3337944 kB
+Mapped: 117424 kB
+Shmem: 19872 kB
+KReclaimable: 124728 kB
+Slab: 240640 kB
+SReclaimable: 124728 kB
+SUnreclaim: 115912 kB
+KernelStack: 6736 kB
+PageTables: 42044 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 8264760 kB
+Committed_AS: 6994880 kB
+VmallocTotal: 34359738367 kB
+VmallocUsed: 16656 kB
+VmallocChunk: 0 kB
+Percpu: 9856 kB
+HardwareCorrupted: 0 kB
+AnonHugePages: 0 kB
+ShmemHugePages: 0 kB
+ShmemPmdMapped: 0 kB
+FileHugePages: 0 kB
+FilePmdMapped: 0 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB
+Hugetlb: 0 kB
+DirectMap4k: 270336 kB
+DirectMap2M: 8118272 kB
+DirectMap1G: 1048576 kB
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 17, 5:57 AM (2 d, 1 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7385590
Default Alt Text
D21733.id51793.diff (11 KB)
Attached To
Mode
D21733: Provide an API for parsing swap information from "/proc/meminfo"
Attached
Detach File
Event Timeline
Log In to Comment