Page MenuHomePhabricator

D21733.diff
No OneTemporary

D21733.diff

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

Mime Type
text/plain
Expires
May 9 2024, 8:25 PM (4 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6276761
Default Alt Text
D21733.diff (11 KB)

Event Timeline