mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 08:12:40 +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:
parent
7cbdf37819
commit
c53bb21bbd
9 changed files with 321 additions and 0 deletions
|
@ -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',
|
||||||
|
|
156
src/filesystem/memory/ArcanistHostMemorySnapshot.php
Normal file
156
src/filesystem/memory/ArcanistHostMemorySnapshot.php
Normal 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'];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
MemTotal: 8140924 kB
|
||||||
|
SwapTotal: 4194 mB
|
|
@ -0,0 +1,3 @@
|
||||||
|
MemTotal: 8140924 kB
|
||||||
|
SwapTotal: 4194300 kB
|
||||||
|
SwapTotal: 4194300 kB
|
|
@ -0,0 +1,2 @@
|
||||||
|
MemTotal: 8140924 kB
|
||||||
|
SwapTotal: aardvark kB
|
|
@ -0,0 +1 @@
|
||||||
|
MemTotal: 8140924 kB
|
51
src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt
Normal file
51
src/filesystem/memory/__tests__/data/meminfo_swap_normal.txt
Normal 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
|
51
src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt
Normal file
51
src/filesystem/memory/__tests__/data/meminfo_swap_zero.txt
Normal 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
|
Loading…
Reference in a new issue