77
77
78
78
79
79
POWER_SUPPLY_PATH = "/sys/class/power_supply"
80
- HAS_SMAPS = os .path .exists ('/proc/%s/smaps' % os .getpid ())
80
+ HAS_PROC_SMAPS = os .path .exists ('/proc/%s/smaps' % os .getpid ())
81
+ HAS_PROC_SMAPS_ROLLUP = os .path .exists ('/proc/%s/smaps_rollup' % os .getpid ())
81
82
HAS_PROC_IO_PRIORITY = hasattr (cext , "proc_ioprio_get" )
82
83
HAS_CPU_AFFINITY = hasattr (cext , "proc_cpu_affinity_get" )
83
84
@@ -1875,18 +1876,42 @@ def memory_info(self):
1875
1876
[int (x ) * PAGESIZE for x in f .readline ().split ()[:7 ]]
1876
1877
return pmem (rss , vms , shared , text , lib , data , dirty )
1877
1878
1878
- # /proc/pid/smaps does not exist on kernels < 2.6.14 or if
1879
- # CONFIG_MMU kernel configuration option is not enabled.
1880
- if HAS_SMAPS :
1879
+ if HAS_PROC_SMAPS_ROLLUP or HAS_PROC_SMAPS :
1881
1880
1882
1881
@wrap_exceptions
1883
- def memory_full_info (
1882
+ def _parse_smaps_rollup (self ):
1883
+ # /proc/pid/smaps_rollup was added to Linux in 2017. Faster
1884
+ # than /proc/pid/smaps. It reports higher PSS than */smaps
1885
+ # (from 1k up to 200k higher; tested against all processes).
1886
+ uss = pss = swap = 0
1887
+ try :
1888
+ with open_binary ("{}/{}/smaps_rollup" .format (
1889
+ self ._procfs_path , self .pid )) as f :
1890
+ for line in f :
1891
+ if line .startswith (b"Private_" ):
1892
+ # Private_Clean, Private_Dirty, Private_Hugetlb
1893
+ uss += int (line .split ()[1 ]) * 1024
1894
+ elif line .startswith (b"Pss:" ):
1895
+ pss = int (line .split ()[1 ]) * 1024
1896
+ elif line .startswith (b"Swap:" ):
1897
+ swap = int (line .split ()[1 ]) * 1024
1898
+ except ProcessLookupError : # happens on readline()
1899
+ if not pid_exists (self .pid ):
1900
+ raise NoSuchProcess (self .pid , self ._name )
1901
+ else :
1902
+ raise ZombieProcess (self .pid , self ._name , self ._ppid )
1903
+ return (uss , pss , swap )
1904
+
1905
+ @wrap_exceptions
1906
+ def _parse_smaps (
1884
1907
self ,
1885
1908
# Gets Private_Clean, Private_Dirty, Private_Hugetlb.
1886
1909
_private_re = re .compile (br"\nPrivate.*:\s+(\d+)" ),
1887
1910
_pss_re = re .compile (br"\nPss\:\s+(\d+)" ),
1888
1911
_swap_re = re .compile (br"\nSwap\:\s+(\d+)" )):
1889
- basic_mem = self .memory_info ()
1912
+ # /proc/pid/smaps does not exist on kernels < 2.6.14 or if
1913
+ # CONFIG_MMU kernel configuration option is not enabled.
1914
+
1890
1915
# Note: using 3 regexes is faster than reading the file
1891
1916
# line by line.
1892
1917
# XXX: on Python 3 the 2 regexes are 30% slower than on
@@ -1905,12 +1930,20 @@ def memory_full_info(
1905
1930
uss = sum (map (int , _private_re .findall (smaps_data ))) * 1024
1906
1931
pss = sum (map (int , _pss_re .findall (smaps_data ))) * 1024
1907
1932
swap = sum (map (int , _swap_re .findall (smaps_data ))) * 1024
1933
+ return (uss , pss , swap )
1934
+
1935
+ def memory_full_info (self ):
1936
+ if HAS_PROC_SMAPS_ROLLUP : # faster
1937
+ uss , pss , swap = self ._parse_smaps_rollup ()
1938
+ else :
1939
+ uss , pss , swap = self ._parse_smaps ()
1940
+ basic_mem = self .memory_info ()
1908
1941
return pfullmem (* basic_mem + (uss , pss , swap ))
1909
1942
1910
1943
else :
1911
1944
memory_full_info = memory_info
1912
1945
1913
- if HAS_SMAPS :
1946
+ if HAS_PROC_SMAPS :
1914
1947
1915
1948
@wrap_exceptions
1916
1949
def memory_maps (self ):
0 commit comments