diff --git a/lib/Rex/Hardware/DarwinProbe.pm b/lib/Rex/Hardware/DarwinProbe.pm new file mode 100644 index 000000000..503428da7 --- /dev/null +++ b/lib/Rex/Hardware/DarwinProbe.pm @@ -0,0 +1,45 @@ +package Rex::Hardware::DarwinProbe; + +use strict; +use warnings; + +sub memory_mb { + my (%args) = @_; + my $bytes = $args{memsize} || 0; + my $pagesize = $args{pagesize} || 0; + my $vm_stat = $args{vm_stat} || ''; + my $free_pages = 0; + my $spec_pages = 0; + if ( $vm_stat =~ /Pages free:\s+(\d+)/ ) { + $free_pages = $1; + } + if ( $vm_stat =~ /Pages speculative:\s+(\d+)/ ) { + $spec_pages = $1; + } + my $total = int( $bytes / 1024 / 1024 ); + my $free = int( ( $free_pages + $spec_pages ) * $pagesize / 1024 / 1024 ); + my $used = $total - $free; + $used = 0 if $used < 0; + return { + total => $total, + used => $used, + free => $free, + shared => 0, + buffers => 0, + cached => 0, + }; +} + +sub swap_mb { + my ($line) = @_; + $line ||= ''; + my ( $total, $used, $free ) = + ( $line =~ /total = ([\d.]+)M\s+used = ([\d.]+)M\s+free = ([\d.]+)M/ ); + return { + total => int( $total || 0 ), + used => int( $used || 0 ), + free => int( $free || 0 ), + }; +} + +1; diff --git a/lib/Rex/Hardware/Memory.pm b/lib/Rex/Hardware/Memory.pm index fc7ef49ef..1a85fb3e0 100644 --- a/lib/Rex/Hardware/Memory.pm +++ b/lib/Rex/Hardware/Memory.pm @@ -14,6 +14,7 @@ use Rex::Hardware::Host; use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::Sysctl; +use Rex::Hardware::DarwinProbe; require Rex::Hardware; @@ -181,6 +182,16 @@ sub get { cached => $cached }; } + elsif ( $os eq "Darwin" ) { + my $bytes = i_run "sysctl -n hw.memsize", fail_ok => 1; + my $pagesize = i_run "sysctl -n hw.pagesize", fail_ok => 1; + my $vm_stat = i_run "vm_stat", fail_ok => 1; + $data = Rex::Hardware::DarwinProbe::memory_mb( + memsize => $bytes, + pagesize => $pagesize, + vm_stat => $vm_stat, + ); + } else { # default for linux if ( !can_run("free") ) { diff --git a/lib/Rex/Hardware/Swap.pm b/lib/Rex/Hardware/Swap.pm index 39255ab77..9aeb83614 100644 --- a/lib/Rex/Hardware/Swap.pm +++ b/lib/Rex/Hardware/Swap.pm @@ -12,6 +12,7 @@ our $VERSION = '9999.99.99_99'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Hardware::Host; +use Rex::Hardware::DarwinProbe; require Rex::Hardware; @@ -125,6 +126,10 @@ sub get { free => $free || 0, }; } + elsif ( $os eq "Darwin" ) { + my $swap = i_run "sysctl -n vm.swapusage", fail_ok => 1; + $data = Rex::Hardware::DarwinProbe::swap_mb($swap); + } else { # linux as default if ( !can_run("free") ) { diff --git a/xt/darwin-memory.sh b/xt/darwin-memory.sh new file mode 100644 index 000000000..28a5dd406 --- /dev/null +++ b/xt/darwin-memory.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -eo pipefail +root=$(cd "$(dirname "$0")/.." && pwd) + +set +e +free -m >/tmp/rex-free.out 2>/tmp/rex-free.err +red=$? +set -e +if [ "$red" -eq 0 ]; then + echo "free unexpectedly succeeded" >&2 + exit 1 +fi +grep -q "command not found" /tmp/rex-free.err + +if ! grep -q 'os eq "Darwin"' "$root/lib/Rex/Hardware/Memory.pm"; then + echo "Memory.pm has no Darwin branch" >&2 + exit 1 +fi +if ! grep -q 'os eq "Darwin"' "$root/lib/Rex/Hardware/Swap.pm"; then + echo "Swap.pm has no Darwin branch" >&2 + exit 1 +fi + +perl -I"$root/lib" -MRex::Hardware::DarwinProbe -e ' + my $bytes = `sysctl -n hw.memsize`; + my $pages = `sysctl -n hw.pagesize`; + my $vm = `vm_stat`; + my $swap = `sysctl -n vm.swapusage`; + chomp($bytes, $pages, $swap); + my $mem = Rex::Hardware::DarwinProbe::memory_mb(memsize => $bytes, pagesize => $pages, vm_stat => $vm); + my $sw = Rex::Hardware::DarwinProbe::swap_mb($swap); + my $expect = int($bytes / 1024 / 1024); + die "total $mem->{total} != $expect\n" unless $mem->{total} == $expect; + die "free larger than total\n" unless $mem->{free} <= $mem->{total}; + die "swap total missing from [$swap]\n" unless $sw->{total} > 0; + print "rex darwin ok total=$mem->{total} free=$mem->{free} swap=$sw->{total} used=$sw->{used} free_swap=$sw->{free}\n"; +'