changeset 28372:2f571bfff344

Add "memory" function (patch #9924). * scripts/miscellaneous/memory.m: Add function that returns memory information on Linux and Windows platforms. * scripts/miscellaneous/module.mk: Include new file in build system. * doc/interpreter/system.txi: Include function documentation in manual. * scripts/help/__unimplemented__.m: Remove from list. * NEWS: Add to list of new functions.
author Lars Kindermann <lars.kindermann@reglos.de>
date Sat, 02 May 2020 20:18:10 +0200
parents 401599248e4d
children 29c655998ac3
files NEWS doc/interpreter/system.txi scripts/help/__unimplemented__.m scripts/miscellaneous/memory.m scripts/miscellaneous/module.mk
diffstat 5 files changed, 214 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Apr 22 16:04:48 2020 +0200
+++ b/NEWS	Sat May 02 20:18:10 2020 +0200
@@ -101,6 +101,7 @@
 
 * `getpixelposition`
 * `endsWith`
+* `memory`
 * `rng`
 * `startsWith`
 
--- a/doc/interpreter/system.txi	Wed Apr 22 16:04:48 2020 +0200
+++ b/doc/interpreter/system.txi	Sat May 02 20:18:10 2020 +0200
@@ -554,6 +554,8 @@
 
 @DOCSTRING(license)
 
+@DOCSTRING(memory)
+
 @DOCSTRING(getrusage)
 
 @DOCSTRING(winqueryreg)
--- a/scripts/help/__unimplemented__.m	Wed Apr 22 16:04:48 2020 +0200
+++ b/scripts/help/__unimplemented__.m	Sat May 02 20:18:10 2020 +0200
@@ -981,7 +981,6 @@
   "memmapfile",
   "memoize",
   "MemoizedFunction",
-  "memory",
   "mergecats",
   "meta.abstractDetails",
   "meta.class.fromName",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/miscellaneous/memory.m	Sat May 02 20:18:10 2020 +0200
@@ -0,0 +1,210 @@
+########################################################################
+##
+## Copyright (C) 2020 The Octave Project Developers
+##
+## See the file COPYRIGHT.md in the top-level directory of this
+## distribution or <https://octave.org/copyright/>.
+##
+## This file is part of Octave.
+##
+## Octave is free software: you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, see
+## <https://www.gnu.org/licenses/>.
+##
+########################################################################
+
+## -*- texinfo -*-
+## @deftypefn  {} {} memory ()
+## @deftypefnx {} {[@var{userdata}, @var{systemdata}] =} memory ()
+## Display or return information about memory usage by Octave.
+##
+## @example
+## @group
+## memory ()
+##    @result{} System    RAM: 3934008 KiB,  swap: 4087804 KiB
+##       Octave    RAM:  170596 KiB,  virt: 1347944 KiB
+##       Free      RAM: 1954940 KiB,  swap: 4087804 KiB
+##       Available RAM: 2451948 KiB, total: 6042744 KiB
+## @end group
+##
+## @group
+## [userdata, systemdata] = memory ()
+##    @result{} userdata =
+##      scalar structure containing the fields:
+##      MaxPossibleArrayBytes = 6.1622e+09
+##      MemAvailableAllArrays = 6.1622e+09
+##      ram_available_all_arrays = 2.4883e+09
+##      MemUsedMATLAB = 1.3825e+09
+##      mem_used_octave = 1.3825e+09
+##      ram_used_octave = 1.7824e+08
+##
+##    systemdata =
+##      scalar structure containing the fields:
+##      PhysicalMemory =
+##        scalar structure containing the fields:
+##          Available = 2.4954e+09
+##          Total = 4.0284e+09
+##      SystemMemory =
+##        scalar structure containing the fields:
+##          Available = 6.6813e+09
+##          Total = 8.2143e+09
+##      VirtualAddressSpace =
+##        scalar structure containing the fields:
+##          Available = 2.8147e+14
+##          Total = 2.8147e+14
+## @end group
+## @end example
+##
+## This function is implemented for Linux and Windows only.
+##
+## @seealso{computer, getpid, getrusage, nproc, uname}
+## @end deftypefn
+
+function [userdata, systemdata] = memory ()
+
+  if (! isunix () && ! ispc ())
+    if (nargout > 0)
+      error ('memory: function not yet implemented for this architecture');
+    else
+      warning ('memory: function not yet implemented for this architecture');
+    endif
+    return;
+  endif
+
+  kiB = 1024;
+  [architecture, bits] = computer ();
+
+  if (isunix ())
+    ## Read values from pseudofiles
+    [status, meminfo] = lmemory ();
+
+    ## FIXME: Query the actual size of the user address space,
+    ## e.g. with getrlimit (RLIMIT_AS, rlp)
+    if (log2 (bits) > 32)
+      ## 64bit platform
+      address_space = 2^48;  # 256 TiB
+    else
+      ## 32bit platform
+      address_space =  3 * 2^30;  # 3 GiB
+    endif
+
+    total_ram = meminfo.MemTotal * kiB;
+    total_swap = meminfo.SwapTotal * kiB;
+    free_ram = meminfo.MemFree * kiB;
+    if isfield (meminfo, "MemAvailable")
+      available_ram = meminfo.MemAvailable * kiB;
+    else
+      ## On kernels from before 2014 MemAvailable is not present.
+      ## This is a rough estimate that can be used instead.
+      available_ram = (meminfo.MemFree + meminfo.Cached) * kiB;
+    endif
+    free_swap = meminfo.SwapFree * kiB;
+    used_ram = status.VmRSS * kiB;
+    used_virtual = status.VmSize * kiB;
+    avail_virtual = address_space - used_virtual;
+
+  elseif (ispc ())
+    [proc, sys] = __wmemory__ ();
+
+    total_ram = sys.TotalPhys;
+    total_swap = sys.TotalPageFile;
+    available_ram = sys.AvailPhys;
+    free_swap = sys.AvailPageFile;
+    used_ram = proc.WorkingSetSize;
+    used_virtual = proc.PagefileUsage;
+    avail_virtual = sys.AvailVirtual;
+    address_space = sys.TotalVirtual;
+
+  endif
+
+  available = min (available_ram + free_swap, avail_virtual);
+  ram_available = min (available_ram, avail_virtual);
+
+  ## FIXME: On 32bit systems, the largest possible array is limited by the
+  ## largest contiguous block in memory.
+  user.MaxPossibleArrayBytes = available;
+  user.MemAvailableAllArrays = available;
+  user.ram_available_all_arrays = ram_available;
+  user.MemUsedMATLAB = used_virtual;  # For Compatibility
+  user.mem_used_octave = used_virtual;
+  user.ram_used_octave = used_ram;
+
+  syst.PhysicalMemory.Available = available_ram;
+  syst.PhysicalMemory.Total = total_ram;
+  syst.SystemMemory.Available = available_ram + free_swap;
+  syst.SystemMemory.Total = total_ram + total_swap;
+  syst.VirtualAddressSpace.Available = avail_virtual;
+  syst.VirtualAddressSpace.Total = address_space;
+
+
+  if (nargout)
+    userdata = user;
+    systemdata = syst;
+  else
+    unitsize = kiB;
+    unitname = 'kiB';
+    disp (sprintf ('Octave is running on %s', architecture))
+    disp (sprintf ('System    RAM: %9.0f %s,  swap: %9.0f %s',
+                   round (syst.PhysicalMemory.Total / unitsize), unitname,
+                   round (total_swap / unitsize), unitname ))
+    disp (sprintf ('Octave    RAM: %9.0f %s,  virt: %9.0f %s',
+                   round (user.ram_used_octave / unitsize), unitname,
+                   round (user.mem_used_octave / unitsize), unitname))
+    if (isunix ())
+      ## The concept of free vs. available RAM doesn't seem to exist on Windows
+      disp (sprintf ('Free      RAM: %9.0f %s,  swap: %9.0f %s',
+                     round (free_ram / unitsize), unitname,
+                     round (free_swap / unitsize), unitname))
+    endif
+    disp (sprintf ('Available RAM: %9.0f %s, total: %9.0f %s',
+                   round (user.ram_available_all_arrays / unitsize), unitname,
+                   round (user.MemAvailableAllArrays / unitsize), unitname))
+  endif
+
+endfunction
+
+function [status, meminfo] = lmemory ()
+  ## Read pseudo files to gather memory information on Linux
+
+  ## Read the proc/self/status pseudofile
+  ## see https://linuxwiki.de/proc/pid#A.2Fproc.2Fpid.2Fstatus
+  ## It contains a variable number of lines with name-value pairs.
+
+  f = fopen ('/proc/self/status');
+  buffer = textscan (f, '%s %s', 'delimiter', ':\n');
+  fclose (f);
+  for i = 1:size (buffer{1}, 1)
+    status.(buffer{1}{i}) = textscan (buffer{2}{i}){1};
+  endfor
+
+  ## Read the /proc/meminfo pseudofile
+  ## see https://linuxwiki.de/proc/meminfo
+  ## It contains a variable number of lines with name-value pairs.
+
+  f = fopen ('/proc/meminfo');
+  buffer = textscan (f, '%s %s', 'delimiter', ':\n');
+  fclose (f);
+  for i = 1:size (buffer{1}, 1)
+    meminfo.(buffer{1}{i}) = textscan (buffer{2}{i}){1};
+  endfor
+
+endfunction
+
+
+%!testif ; isunix () || ispc ()
+%! [user, syst] = memory ();
+%! assert (user.mem_used_octave > 0);
+%! assert (user.ram_used_octave <= user.mem_used_octave);
+%! assert (user.mem_used_octave < syst.SystemMemory.Total);
+%! assert (user.MemAvailableAllArrays <= syst.SystemMemory.Available);
+
--- a/scripts/miscellaneous/module.mk	Wed Apr 22 16:04:48 2020 +0200
+++ b/scripts/miscellaneous/module.mk	Sat May 02 20:18:10 2020 +0200
@@ -45,6 +45,7 @@
   %reldir%/loadobj.m \
   %reldir%/ls.m \
   %reldir%/ls_command.m \
+  %reldir%/memory.m \
   %reldir%/menu.m \
   %reldir%/methods.m \
   %reldir%/mex.m \