mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-12-22 13:30:54 +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',
|
||||
'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 @@ phutil_register_library_map(array(
|
|||
'ArcanistHgProxyClient' => 'Phobject',
|
||||
'ArcanistHgProxyServer' => 'Phobject',
|
||||
'ArcanistHgServerChannel' => 'PhutilProtocolChannel',
|
||||
'ArcanistHostMemorySnapshot' => 'Phobject',
|
||||
'ArcanistHostMemorySnapshotTestCase' => 'PhutilTestCase',
|
||||
'ArcanistImplicitConstructorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistImplicitConstructorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'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