1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-22 06:42:41 +01:00

Provide an API for parsing swap information from "/proc/meminfo"

Summary: Ref T13653. This entirely exists to support converging into the right swap state in deployment workflows.

Test Plan: Ran unit tests.

Maniphest Tasks: T13653

Differential Revision: https://secure.phabricator.com/D21733
This commit is contained in:
epriestley 2021-11-22 05:19:19 -08:00
parent 7cbdf37819
commit c53bb21bbd
9 changed files with 321 additions and 0 deletions

View file

@ -264,6 +264,8 @@ phutil_register_library_map(array(
'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php', 'ArcanistHgProxyClient' => 'hgdaemon/ArcanistHgProxyClient.php',
'ArcanistHgProxyServer' => 'hgdaemon/ArcanistHgProxyServer.php', 'ArcanistHgProxyServer' => 'hgdaemon/ArcanistHgProxyServer.php',
'ArcanistHgServerChannel' => 'hgdaemon/ArcanistHgServerChannel.php', 'ArcanistHgServerChannel' => 'hgdaemon/ArcanistHgServerChannel.php',
'ArcanistHostMemorySnapshot' => 'filesystem/memory/ArcanistHostMemorySnapshot.php',
'ArcanistHostMemorySnapshotTestCase' => 'filesystem/memory/__tests__/ArcanistHostMemorySnapshotTestCase.php',
'ArcanistImplicitConstructorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitConstructorXHPASTLinterRule.php', 'ArcanistImplicitConstructorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitConstructorXHPASTLinterRule.php',
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitConstructorXHPASTLinterRuleTestCase.php', 'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistImplicitConstructorXHPASTLinterRuleTestCase.php',
'ArcanistImplicitFallthroughXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitFallthroughXHPASTLinterRule.php', 'ArcanistImplicitFallthroughXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistImplicitFallthroughXHPASTLinterRule.php',
@ -1323,6 +1325,8 @@ phutil_register_library_map(array(
'ArcanistHgProxyClient' => 'Phobject', 'ArcanistHgProxyClient' => 'Phobject',
'ArcanistHgProxyServer' => 'Phobject', 'ArcanistHgProxyServer' => 'Phobject',
'ArcanistHgServerChannel' => 'PhutilProtocolChannel', 'ArcanistHgServerChannel' => 'PhutilProtocolChannel',
'ArcanistHostMemorySnapshot' => 'Phobject',
'ArcanistHostMemorySnapshotTestCase' => 'PhutilTestCase',
'ArcanistImplicitConstructorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistImplicitConstructorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistImplicitFallthroughXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistImplicitFallthroughXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',

View file

@ -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'];
}
}

View file

@ -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));
}
}
}
}

View file

@ -0,0 +1,2 @@
MemTotal: 8140924 kB
SwapTotal: 4194 mB

View file

@ -0,0 +1,3 @@
MemTotal: 8140924 kB
SwapTotal: 4194300 kB
SwapTotal: 4194300 kB

View file

@ -0,0 +1,2 @@
MemTotal: 8140924 kB
SwapTotal: aardvark kB

View file

@ -0,0 +1 @@
MemTotal: 8140924 kB

View file

@ -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

View file

@ -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