util: provide a helper function to estimate RAM size
authorJoerg Sonnenberger <joerg@bec.de>
Tue, 09 Jun 2020 11:22:31 +0200
changeset 45061 02b17231f6c3
parent 45060 baffdfa5bd1a
child 45062 72feaeb510b3
util: provide a helper function to estimate RAM size For POSIX systems, it uses sysconf. For Windows, it uses the win32 API directly. Differential Revision: https://phab.mercurial-scm.org/D8644
mercurial/configitems.py
mercurial/ui.py
mercurial/util.py
--- a/mercurial/configitems.py	Thu Jul 02 19:59:59 2020 +0200
+++ b/mercurial/configitems.py	Tue Jun 09 11:22:31 2020 +0200
@@ -1231,6 +1231,10 @@
     b'ui', b'askusername', default=False,
 )
 coreconfigitem(
+    b'ui', b'available-memory', default=None,
+)
+
+coreconfigitem(
     b'ui', b'clonebundlefallback', default=False,
 )
 coreconfigitem(
--- a/mercurial/ui.py	Thu Jul 02 19:59:59 2020 +0200
+++ b/mercurial/ui.py	Tue Jun 09 11:22:31 2020 +0200
@@ -2119,6 +2119,22 @@
             if (b'ui', b'quiet') in overrides:
                 self.fixconfig(section=b'ui')
 
+    def estimatememory(self):
+        """Provide an estimate for the available system memory in Bytes.
+
+        This can be overriden via ui.available-memory. It returns None, if
+        no estimate can be computed.
+        """
+        value = self.config(b'ui', b'available-memory')
+        if value is not None:
+            try:
+                return util.sizetoint(value)
+            except error.ParseError:
+                raise error.ConfigError(
+                    _(b"ui.available-memory value is invalid ('%s')") % value
+                )
+        return util._estimatememory()
+
 
 class paths(dict):
     """Represents a collection of paths and their configs.
--- a/mercurial/util.py	Thu Jul 02 19:59:59 2020 +0200
+++ b/mercurial/util.py	Tue Jun 09 11:22:31 2020 +0200
@@ -3626,3 +3626,44 @@
             locale.setlocale(locale.LC_CTYPE, oldloc)
     else:
         yield
+
+
+def _estimatememory():
+    """Provide an estimate for the available system memory in Bytes.
+
+    If no estimate can be provided on the platform, returns None.
+    """
+    if pycompat.sysplatform.startswith(b'win'):
+        # On Windows, use the GlobalMemoryStatusEx kernel function directly.
+        from ctypes import c_long as DWORD, c_ulonglong as DWORDLONG
+        from ctypes.wintypes import Structure, byref, sizeof, windll
+
+        class MEMORYSTATUSEX(Structure):
+            _fields_ = [
+                ('dwLength', DWORD),
+                ('dwMemoryLoad', DWORD),
+                ('ullTotalPhys', DWORDLONG),
+                ('ullAvailPhys', DWORDLONG),
+                ('ullTotalPageFile', DWORDLONG),
+                ('ullAvailPageFile', DWORDLONG),
+                ('ullTotalVirtual', DWORDLONG),
+                ('ullAvailVirtual', DWORDLONG),
+                ('ullExtendedVirtual', DWORDLONG),
+            ]
+
+        x = MEMORYSTATUSEX()
+        x.dwLength = sizeof(x)
+        windll.kernel32.GlobalMemoryStatusEx(byref(x))
+        return x.ullAvailPhys
+
+    # On newer Unix-like systems and Mac OSX, the sysconf interface
+    # can be used. _SC_PAGE_SIZE is part of POSIX; _SC_PHYS_PAGES
+    # seems to be implemented on most systems.
+    try:
+        pagesize = os.sysconf(os.sysconf_names['SC_PAGE_SIZE'])
+        pages = os.sysconf(os.sysconf_names['SC_PHYS_PAGES'])
+        return pagesize * pages
+    except OSError:  # sysconf can fail
+        pass
+    except KeyError:  # unknown parameter
+        pass