7777
7878
7979POWER_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 ())
8182HAS_PROC_IO_PRIORITY = hasattr (cext , "proc_ioprio_get" )
8283HAS_CPU_AFFINITY = hasattr (cext , "proc_cpu_affinity_get" )
8384
@@ -1875,18 +1876,42 @@ def memory_info(self):
18751876 [int (x ) * PAGESIZE for x in f .readline ().split ()[:7 ]]
18761877 return pmem (rss , vms , shared , text , lib , data , dirty )
18771878
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 :
18811880
18821881 @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 (
18841907 self ,
18851908 # Gets Private_Clean, Private_Dirty, Private_Hugetlb.
18861909 _private_re = re .compile (br"\nPrivate.*:\s+(\d+)" ),
18871910 _pss_re = re .compile (br"\nPss\:\s+(\d+)" ),
18881911 _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+
18901915 # Note: using 3 regexes is faster than reading the file
18911916 # line by line.
18921917 # XXX: on Python 3 the 2 regexes are 30% slower than on
@@ -1905,12 +1930,20 @@ def memory_full_info(
19051930 uss = sum (map (int , _private_re .findall (smaps_data ))) * 1024
19061931 pss = sum (map (int , _pss_re .findall (smaps_data ))) * 1024
19071932 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 ()
19081941 return pfullmem (* basic_mem + (uss , pss , swap ))
19091942
19101943 else :
19111944 memory_full_info = memory_info
19121945
1913- if HAS_SMAPS :
1946+ if HAS_PROC_SMAPS :
19141947
19151948 @wrap_exceptions
19161949 def memory_maps (self ):
0 commit comments