mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
748 lines
20 KiB
Python
Executable File
748 lines
20 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright 2013 The Chromium Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
# A Python library to read and store procfs (/proc) information on Linux.
|
|
#
|
|
# Each information storage class in this file stores original data as original
|
|
# as reasonablly possible. Translation is done when requested. It is to make it
|
|
# always possible to probe the original data.
|
|
|
|
|
|
import collections
|
|
import logging
|
|
import os
|
|
import re
|
|
import struct
|
|
import sys
|
|
|
|
|
|
class _NullHandler(logging.Handler):
|
|
def emit(self, record):
|
|
pass
|
|
|
|
|
|
_LOGGER = logging.getLogger('procfs')
|
|
_LOGGER.addHandler(_NullHandler())
|
|
|
|
|
|
class ProcStat(object):
|
|
"""Reads and stores information in /proc/pid/stat."""
|
|
_PATTERN = re.compile(r'^'
|
|
'(?P<PID>-?[0-9]+) '
|
|
'\((?P<COMM>.+)\) '
|
|
'(?P<STATE>[RSDZTW]) '
|
|
'(?P<PPID>-?[0-9]+) '
|
|
'(?P<PGRP>-?[0-9]+) '
|
|
'(?P<SESSION>-?[0-9]+) '
|
|
'(?P<TTY_NR>-?[0-9]+) '
|
|
'(?P<TPGID>-?[0-9]+) '
|
|
'(?P<FLAGS>[0-9]+) '
|
|
'(?P<MINFIT>[0-9]+) '
|
|
'(?P<CMINFIT>[0-9]+) '
|
|
'(?P<MAJFIT>[0-9]+) '
|
|
'(?P<CMAJFIT>[0-9]+) '
|
|
'(?P<UTIME>[0-9]+) '
|
|
'(?P<STIME>[0-9]+) '
|
|
'(?P<CUTIME>[0-9]+) '
|
|
'(?P<CSTIME>[0-9]+) '
|
|
'(?P<PRIORITY>[0-9]+) '
|
|
'(?P<NICE>[0-9]+) '
|
|
'(?P<NUM_THREADS>[0-9]+) '
|
|
'(?P<ITREALVALUE>[0-9]+) '
|
|
'(?P<STARTTIME>[0-9]+) '
|
|
'(?P<VSIZE>[0-9]+) '
|
|
'(?P<RSS>[0-9]+) '
|
|
'(?P<RSSLIM>[0-9]+) '
|
|
'(?P<STARTCODE>[0-9]+) '
|
|
'(?P<ENDCODE>[0-9]+) '
|
|
'(?P<STARTSTACK>[0-9]+) '
|
|
'(?P<KSTKESP>[0-9]+) '
|
|
'(?P<KSTKEIP>[0-9]+) '
|
|
'(?P<SIGNAL>[0-9]+) '
|
|
'(?P<BLOCKED>[0-9]+) '
|
|
'(?P<SIGIGNORE>[0-9]+) '
|
|
'(?P<SIGCATCH>[0-9]+) '
|
|
'(?P<WCHAN>[0-9]+) '
|
|
'(?P<NSWAP>[0-9]+) '
|
|
'(?P<CNSWAP>[0-9]+) '
|
|
'(?P<EXIT_SIGNAL>[0-9]+) '
|
|
'(?P<PROCESSOR>[0-9]+) '
|
|
'(?P<RT_PRIORITY>[0-9]+) '
|
|
'(?P<POLICY>[0-9]+) '
|
|
'(?P<DELAYACCT_BLKIO_TICKS>[0-9]+) '
|
|
'(?P<GUEST_TIME>[0-9]+) '
|
|
'(?P<CGUEST_TIME>[0-9]+)', re.IGNORECASE)
|
|
|
|
def __init__(self, raw, pid, vsize, rss):
|
|
self._raw = raw
|
|
self._pid = pid
|
|
self._vsize = vsize
|
|
self._rss = rss
|
|
|
|
@staticmethod
|
|
def load_file(stat_f):
|
|
raw = stat_f.readlines()
|
|
stat = ProcStat._PATTERN.match(raw[0])
|
|
return ProcStat(raw,
|
|
stat.groupdict().get('PID'),
|
|
stat.groupdict().get('VSIZE'),
|
|
stat.groupdict().get('RSS'))
|
|
|
|
@staticmethod
|
|
def load(pid):
|
|
try:
|
|
with open(os.path.join('/proc', str(pid), 'stat'), 'r') as stat_f:
|
|
return ProcStat.load_file(stat_f)
|
|
except IOError:
|
|
return None
|
|
|
|
@property
|
|
def raw(self):
|
|
return self._raw
|
|
|
|
@property
|
|
def pid(self):
|
|
return int(self._pid)
|
|
|
|
@property
|
|
def vsize(self):
|
|
return int(self._vsize)
|
|
|
|
@property
|
|
def rss(self):
|
|
return int(self._rss)
|
|
|
|
|
|
class ProcStatm(object):
|
|
"""Reads and stores information in /proc/pid/statm."""
|
|
_PATTERN = re.compile(r'^'
|
|
'(?P<SIZE>[0-9]+) '
|
|
'(?P<RESIDENT>[0-9]+) '
|
|
'(?P<SHARE>[0-9]+) '
|
|
'(?P<TEXT>[0-9]+) '
|
|
'(?P<LIB>[0-9]+) '
|
|
'(?P<DATA>[0-9]+) '
|
|
'(?P<DT>[0-9]+)', re.IGNORECASE)
|
|
|
|
def __init__(self, raw, size, resident, share, text, lib, data, dt):
|
|
self._raw = raw
|
|
self._size = size
|
|
self._resident = resident
|
|
self._share = share
|
|
self._text = text
|
|
self._lib = lib
|
|
self._data = data
|
|
self._dt = dt
|
|
|
|
@staticmethod
|
|
def load_file(statm_f):
|
|
try:
|
|
raw = statm_f.readlines()
|
|
except (IOError, OSError):
|
|
return None
|
|
statm = ProcStatm._PATTERN.match(raw[0])
|
|
return ProcStatm(raw,
|
|
statm.groupdict().get('SIZE'),
|
|
statm.groupdict().get('RESIDENT'),
|
|
statm.groupdict().get('SHARE'),
|
|
statm.groupdict().get('TEXT'),
|
|
statm.groupdict().get('LIB'),
|
|
statm.groupdict().get('DATA'),
|
|
statm.groupdict().get('DT'))
|
|
|
|
@staticmethod
|
|
def load(pid):
|
|
try:
|
|
with open(os.path.join('/proc', str(pid), 'statm'), 'r') as statm_f:
|
|
return ProcStatm.load_file(statm_f)
|
|
except (IOError, OSError):
|
|
return None
|
|
|
|
@property
|
|
def raw(self):
|
|
return self._raw
|
|
|
|
@property
|
|
def size(self):
|
|
return int(self._size)
|
|
|
|
@property
|
|
def resident(self):
|
|
return int(self._resident)
|
|
|
|
@property
|
|
def share(self):
|
|
return int(self._share)
|
|
|
|
@property
|
|
def text(self):
|
|
return int(self._text)
|
|
|
|
@property
|
|
def lib(self):
|
|
return int(self._lib)
|
|
|
|
@property
|
|
def data(self):
|
|
return int(self._data)
|
|
|
|
@property
|
|
def dt(self):
|
|
return int(self._dt)
|
|
|
|
|
|
class ProcStatus(object):
|
|
"""Reads and stores information in /proc/pid/status."""
|
|
_PATTERN = re.compile(r'^(?P<NAME>[A-Za-z0-9_]+):\s+(?P<VALUE>.*)')
|
|
|
|
def __init__(self, raw, dct):
|
|
self._raw = raw
|
|
self._pid = dct.get('Pid')
|
|
self._name = dct.get('Name')
|
|
self._vm_peak = dct.get('VmPeak')
|
|
self._vm_size = dct.get('VmSize')
|
|
self._vm_lck = dct.get('VmLck')
|
|
self._vm_pin = dct.get('VmPin')
|
|
self._vm_hwm = dct.get('VmHWM')
|
|
self._vm_rss = dct.get('VmRSS')
|
|
self._vm_data = dct.get('VmData')
|
|
self._vm_stack = dct.get('VmStk')
|
|
self._vm_exe = dct.get('VmExe')
|
|
self._vm_lib = dct.get('VmLib')
|
|
self._vm_pte = dct.get('VmPTE')
|
|
self._vm_swap = dct.get('VmSwap')
|
|
|
|
@staticmethod
|
|
def load_file(status_f):
|
|
raw = status_f.readlines()
|
|
dct = {}
|
|
for line in raw:
|
|
status_match = ProcStatus._PATTERN.match(line)
|
|
if status_match:
|
|
match_dict = status_match.groupdict()
|
|
dct[match_dict['NAME']] = match_dict['VALUE']
|
|
else:
|
|
raise SyntaxError('Unknown /proc/pid/status format.')
|
|
return ProcStatus(raw, dct)
|
|
|
|
@staticmethod
|
|
def load(pid):
|
|
with open(os.path.join('/proc', str(pid), 'status'), 'r') as status_f:
|
|
return ProcStatus.load_file(status_f)
|
|
|
|
@property
|
|
def raw(self):
|
|
return self._raw
|
|
|
|
@property
|
|
def pid(self):
|
|
return int(self._pid)
|
|
|
|
@property
|
|
def vm_peak(self):
|
|
"""Returns a high-water (peak) virtual memory size in kilo-bytes."""
|
|
if self._vm_peak.endswith('kB'):
|
|
return int(self._vm_peak.split()[0])
|
|
raise ValueError('VmPeak is not in kB.')
|
|
|
|
@property
|
|
def vm_size(self):
|
|
"""Returns a virtual memory size in kilo-bytes."""
|
|
if self._vm_size.endswith('kB'):
|
|
return int(self._vm_size.split()[0])
|
|
raise ValueError('VmSize is not in kB.')
|
|
|
|
@property
|
|
def vm_hwm(self):
|
|
"""Returns a high-water (peak) resident set size (RSS) in kilo-bytes."""
|
|
if self._vm_hwm.endswith('kB'):
|
|
return int(self._vm_hwm.split()[0])
|
|
raise ValueError('VmHWM is not in kB.')
|
|
|
|
@property
|
|
def vm_rss(self):
|
|
"""Returns a resident set size (RSS) in kilo-bytes."""
|
|
if self._vm_rss.endswith('kB'):
|
|
return int(self._vm_rss.split()[0])
|
|
raise ValueError('VmRSS is not in kB.')
|
|
|
|
|
|
class ProcMapsEntry(object):
|
|
"""A class representing one line in /proc/pid/maps."""
|
|
|
|
def __init__(
|
|
self, begin, end, readable, writable, executable, private, offset,
|
|
major, minor, inode, name):
|
|
self.begin = begin
|
|
self.end = end
|
|
self.readable = readable
|
|
self.writable = writable
|
|
self.executable = executable
|
|
self.private = private
|
|
self.offset = offset
|
|
self.major = major
|
|
self.minor = minor
|
|
self.inode = inode
|
|
self.name = name
|
|
|
|
def as_dict(self):
|
|
return {
|
|
'begin': self.begin,
|
|
'end': self.end,
|
|
'readable': self.readable,
|
|
'writable': self.writable,
|
|
'executable': self.executable,
|
|
'private': self.private,
|
|
'offset': self.offset,
|
|
'major': self.major,
|
|
'minor': self.minor,
|
|
'inode': self.inode,
|
|
'name': self.name,
|
|
}
|
|
|
|
|
|
class ProcMaps(object):
|
|
"""Reads and stores information in /proc/pid/maps."""
|
|
|
|
MAPS_PATTERN = re.compile(
|
|
r'^([a-f0-9]+)-([a-f0-9]+)\s+(.)(.)(.)(.)\s+([a-f0-9]+)\s+(\S+):(\S+)\s+'
|
|
r'(\d+)\s*(.*)$', re.IGNORECASE)
|
|
|
|
EXECUTABLE_PATTERN = re.compile(
|
|
r'\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?')
|
|
|
|
def __init__(self):
|
|
self._sorted_indexes = []
|
|
self._dictionary = {}
|
|
self._sorted = True
|
|
|
|
def iter(self, condition):
|
|
if not self._sorted:
|
|
self._sorted_indexes.sort()
|
|
self._sorted = True
|
|
for index in self._sorted_indexes:
|
|
if not condition or condition(self._dictionary[index]):
|
|
yield self._dictionary[index]
|
|
|
|
def __iter__(self):
|
|
if not self._sorted:
|
|
self._sorted_indexes.sort()
|
|
self._sorted = True
|
|
for index in self._sorted_indexes:
|
|
yield self._dictionary[index]
|
|
|
|
@staticmethod
|
|
def load_file(maps_f):
|
|
table = ProcMaps()
|
|
for line in maps_f:
|
|
table.append_line(line)
|
|
return table
|
|
|
|
@staticmethod
|
|
def load(pid):
|
|
try:
|
|
with open(os.path.join('/proc', str(pid), 'maps'), 'r') as maps_f:
|
|
return ProcMaps.load_file(maps_f)
|
|
except (IOError, OSError):
|
|
return None
|
|
|
|
def append_line(self, line):
|
|
entry = self.parse_line(line)
|
|
if entry:
|
|
self._append_entry(entry)
|
|
return entry
|
|
|
|
@staticmethod
|
|
def parse_line(line):
|
|
matched = ProcMaps.MAPS_PATTERN.match(line)
|
|
if matched:
|
|
return ProcMapsEntry( # pylint: disable=W0212
|
|
int(matched.group(1), 16), # begin
|
|
int(matched.group(2), 16), # end
|
|
matched.group(3), # readable
|
|
matched.group(4), # writable
|
|
matched.group(5), # executable
|
|
matched.group(6), # private
|
|
int(matched.group(7), 16), # offset
|
|
matched.group(8), # major
|
|
matched.group(9), # minor
|
|
int(matched.group(10), 10), # inode
|
|
matched.group(11) # name
|
|
)
|
|
else:
|
|
return None
|
|
|
|
@staticmethod
|
|
def constants(entry):
|
|
return entry.writable == '-' and entry.executable == '-'
|
|
|
|
@staticmethod
|
|
def executable(entry):
|
|
return entry.executable == 'x'
|
|
|
|
@staticmethod
|
|
def executable_and_constants(entry):
|
|
return ((entry.writable == '-' and entry.executable == '-') or
|
|
entry.executable == 'x')
|
|
|
|
def _append_entry(self, entry):
|
|
if self._sorted_indexes and self._sorted_indexes[-1] > entry.begin:
|
|
self._sorted = False
|
|
self._sorted_indexes.append(entry.begin)
|
|
self._dictionary[entry.begin] = entry
|
|
|
|
|
|
class ProcSmaps(object):
|
|
"""Reads and stores information in /proc/pid/smaps."""
|
|
_SMAPS_PATTERN = re.compile(r'^(?P<NAME>[A-Za-z0-9_]+):\s+(?P<VALUE>.*)')
|
|
|
|
class VMA(object):
|
|
def __init__(self):
|
|
self._size = 0
|
|
self._rss = 0
|
|
self._pss = 0
|
|
|
|
def append(self, name, value):
|
|
dct = {
|
|
'Size': '_size',
|
|
'Rss': '_rss',
|
|
'Pss': '_pss',
|
|
'Referenced': '_referenced',
|
|
'Private_Clean': '_private_clean',
|
|
'Shared_Clean': '_shared_clean',
|
|
'KernelPageSize': '_kernel_page_size',
|
|
'MMUPageSize': '_mmu_page_size',
|
|
}
|
|
if name in dct:
|
|
self.__setattr__(dct[name], value)
|
|
|
|
@property
|
|
def size(self):
|
|
if self._size.endswith('kB'):
|
|
return int(self._size.split()[0])
|
|
return int(self._size)
|
|
|
|
@property
|
|
def rss(self):
|
|
if self._rss.endswith('kB'):
|
|
return int(self._rss.split()[0])
|
|
return int(self._rss)
|
|
|
|
@property
|
|
def pss(self):
|
|
if self._pss.endswith('kB'):
|
|
return int(self._pss.split()[0])
|
|
return int(self._pss)
|
|
|
|
def __init__(self, raw, total_dct, maps, vma_internals):
|
|
self._raw = raw
|
|
self._size = total_dct['Size']
|
|
self._rss = total_dct['Rss']
|
|
self._pss = total_dct['Pss']
|
|
self._referenced = total_dct['Referenced']
|
|
self._shared_clean = total_dct['Shared_Clean']
|
|
self._private_clean = total_dct['Private_Clean']
|
|
self._kernel_page_size = total_dct['KernelPageSize']
|
|
self._mmu_page_size = total_dct['MMUPageSize']
|
|
self._maps = maps
|
|
self._vma_internals = vma_internals
|
|
|
|
@staticmethod
|
|
def load(pid):
|
|
with open(os.path.join('/proc', str(pid), 'smaps'), 'r') as smaps_f:
|
|
raw = smaps_f.readlines()
|
|
|
|
vma = None
|
|
vma_internals = collections.OrderedDict()
|
|
total_dct = collections.defaultdict(int)
|
|
maps = ProcMaps()
|
|
for line in raw:
|
|
maps_match = ProcMaps.MAPS_PATTERN.match(line)
|
|
if maps_match:
|
|
vma = maps.append_line(line.strip())
|
|
vma_internals[vma] = ProcSmaps.VMA()
|
|
else:
|
|
smaps_match = ProcSmaps._SMAPS_PATTERN.match(line)
|
|
if smaps_match:
|
|
match_dict = smaps_match.groupdict()
|
|
vma_internals[vma].append(match_dict['NAME'], match_dict['VALUE'])
|
|
total_dct[match_dict['NAME']] += int(match_dict['VALUE'].split()[0])
|
|
|
|
return ProcSmaps(raw, total_dct, maps, vma_internals)
|
|
|
|
@property
|
|
def size(self):
|
|
return self._size
|
|
|
|
@property
|
|
def rss(self):
|
|
return self._rss
|
|
|
|
@property
|
|
def referenced(self):
|
|
return self._referenced
|
|
|
|
@property
|
|
def pss(self):
|
|
return self._pss
|
|
|
|
@property
|
|
def private_clean(self):
|
|
return self._private_clean
|
|
|
|
@property
|
|
def shared_clean(self):
|
|
return self._shared_clean
|
|
|
|
@property
|
|
def kernel_page_size(self):
|
|
return self._kernel_page_size
|
|
|
|
@property
|
|
def mmu_page_size(self):
|
|
return self._mmu_page_size
|
|
|
|
@property
|
|
def vma_internals(self):
|
|
return self._vma_internals
|
|
|
|
|
|
class ProcPagemap(object):
|
|
"""Reads and stores partial information in /proc/pid/pagemap.
|
|
|
|
It picks up virtual addresses to read based on ProcMaps (/proc/pid/maps).
|
|
See https://www.kernel.org/doc/Documentation/vm/pagemap.txt for details.
|
|
"""
|
|
_BYTES_PER_PAGEMAP_VALUE = 8
|
|
_BYTES_PER_OS_PAGE = 4096
|
|
_VIRTUAL_TO_PAGEMAP_OFFSET = _BYTES_PER_OS_PAGE / _BYTES_PER_PAGEMAP_VALUE
|
|
|
|
_MASK_PRESENT = 1 << 63
|
|
_MASK_SWAPPED = 1 << 62
|
|
_MASK_FILEPAGE_OR_SHAREDANON = 1 << 61
|
|
_MASK_SOFTDIRTY = 1 << 55
|
|
_MASK_PFN = (1 << 55) - 1
|
|
|
|
class VMA(object):
|
|
def __init__(self, vsize, present, swapped, pageframes):
|
|
self._vsize = vsize
|
|
self._present = present
|
|
self._swapped = swapped
|
|
self._pageframes = pageframes
|
|
|
|
@property
|
|
def vsize(self):
|
|
return int(self._vsize)
|
|
|
|
@property
|
|
def present(self):
|
|
return int(self._present)
|
|
|
|
@property
|
|
def swapped(self):
|
|
return int(self._swapped)
|
|
|
|
@property
|
|
def pageframes(self):
|
|
return self._pageframes
|
|
|
|
def __init__(self, vsize, present, swapped, vma_internals, in_process_dup):
|
|
self._vsize = vsize
|
|
self._present = present
|
|
self._swapped = swapped
|
|
self._vma_internals = vma_internals
|
|
self._in_process_dup = in_process_dup
|
|
|
|
@staticmethod
|
|
def load(pid, maps):
|
|
total_present = 0
|
|
total_swapped = 0
|
|
total_vsize = 0
|
|
in_process_dup = 0
|
|
vma_internals = collections.OrderedDict()
|
|
process_pageframe_set = set()
|
|
|
|
try:
|
|
pagemap_fd = os.open(
|
|
os.path.join('/proc', str(pid), 'pagemap'), os.O_RDONLY)
|
|
except (IOError, OSError):
|
|
return None
|
|
for vma in maps:
|
|
present = 0
|
|
swapped = 0
|
|
vsize = 0
|
|
pageframes = collections.defaultdict(int)
|
|
begin_offset = ProcPagemap._offset(vma.begin)
|
|
chunk_size = ProcPagemap._offset(vma.end) - begin_offset
|
|
try:
|
|
os.lseek(pagemap_fd, begin_offset, os.SEEK_SET)
|
|
buf = os.read(pagemap_fd, chunk_size)
|
|
except (IOError, OSError):
|
|
return None
|
|
if len(buf) < chunk_size:
|
|
_LOGGER.warn('Failed to read pagemap at 0x%x in %d.' % (vma.begin, pid))
|
|
pagemap_values = struct.unpack(
|
|
'=%dQ' % (len(buf) / ProcPagemap._BYTES_PER_PAGEMAP_VALUE), buf)
|
|
for pagemap_value in pagemap_values:
|
|
vsize += ProcPagemap._BYTES_PER_OS_PAGE
|
|
if pagemap_value & ProcPagemap._MASK_PRESENT:
|
|
if (pagemap_value & ProcPagemap._MASK_PFN) in process_pageframe_set:
|
|
in_process_dup += ProcPagemap._BYTES_PER_OS_PAGE
|
|
else:
|
|
process_pageframe_set.add(pagemap_value & ProcPagemap._MASK_PFN)
|
|
if (pagemap_value & ProcPagemap._MASK_PFN) not in pageframes:
|
|
present += ProcPagemap._BYTES_PER_OS_PAGE
|
|
pageframes[pagemap_value & ProcPagemap._MASK_PFN] += 1
|
|
if pagemap_value & ProcPagemap._MASK_SWAPPED:
|
|
swapped += ProcPagemap._BYTES_PER_OS_PAGE
|
|
vma_internals[vma] = ProcPagemap.VMA(vsize, present, swapped, pageframes)
|
|
total_present += present
|
|
total_swapped += swapped
|
|
total_vsize += vsize
|
|
try:
|
|
os.close(pagemap_fd)
|
|
except OSError:
|
|
return None
|
|
|
|
return ProcPagemap(total_vsize, total_present, total_swapped,
|
|
vma_internals, in_process_dup)
|
|
|
|
@staticmethod
|
|
def _offset(virtual_address):
|
|
return virtual_address / ProcPagemap._VIRTUAL_TO_PAGEMAP_OFFSET
|
|
|
|
@property
|
|
def vsize(self):
|
|
return int(self._vsize)
|
|
|
|
@property
|
|
def present(self):
|
|
return int(self._present)
|
|
|
|
@property
|
|
def swapped(self):
|
|
return int(self._swapped)
|
|
|
|
@property
|
|
def vma_internals(self):
|
|
return self._vma_internals
|
|
|
|
|
|
class _ProcessMemory(object):
|
|
"""Aggregates process memory information from /proc for manual testing."""
|
|
def __init__(self, pid):
|
|
self._pid = pid
|
|
self._maps = None
|
|
self._pagemap = None
|
|
self._stat = None
|
|
self._status = None
|
|
self._statm = None
|
|
self._smaps = []
|
|
|
|
def _read(self, proc_file):
|
|
lines = []
|
|
with open(os.path.join('/proc', str(self._pid), proc_file), 'r') as proc_f:
|
|
lines = proc_f.readlines()
|
|
return lines
|
|
|
|
def read_all(self):
|
|
self.read_stat()
|
|
self.read_statm()
|
|
self.read_status()
|
|
self.read_smaps()
|
|
self.read_maps()
|
|
self.read_pagemap(self._maps)
|
|
|
|
def read_maps(self):
|
|
self._maps = ProcMaps.load(self._pid)
|
|
|
|
def read_pagemap(self, maps):
|
|
self._pagemap = ProcPagemap.load(self._pid, maps)
|
|
|
|
def read_smaps(self):
|
|
self._smaps = ProcSmaps.load(self._pid)
|
|
|
|
def read_stat(self):
|
|
self._stat = ProcStat.load(self._pid)
|
|
|
|
def read_statm(self):
|
|
self._statm = ProcStatm.load(self._pid)
|
|
|
|
def read_status(self):
|
|
self._status = ProcStatus.load(self._pid)
|
|
|
|
@property
|
|
def pid(self):
|
|
return self._pid
|
|
|
|
@property
|
|
def maps(self):
|
|
return self._maps
|
|
|
|
@property
|
|
def pagemap(self):
|
|
return self._pagemap
|
|
|
|
@property
|
|
def smaps(self):
|
|
return self._smaps
|
|
|
|
@property
|
|
def stat(self):
|
|
return self._stat
|
|
|
|
@property
|
|
def statm(self):
|
|
return self._statm
|
|
|
|
@property
|
|
def status(self):
|
|
return self._status
|
|
|
|
|
|
def main(argv):
|
|
"""The main function for manual testing."""
|
|
_LOGGER.setLevel(logging.WARNING)
|
|
handler = logging.StreamHandler()
|
|
handler.setLevel(logging.WARNING)
|
|
handler.setFormatter(logging.Formatter(
|
|
'%(asctime)s:%(name)s:%(levelname)s:%(message)s'))
|
|
_LOGGER.addHandler(handler)
|
|
|
|
pids = []
|
|
for arg in argv[1:]:
|
|
try:
|
|
pid = int(arg)
|
|
except ValueError:
|
|
raise SyntaxError("%s is not an integer." % arg)
|
|
else:
|
|
pids.append(pid)
|
|
|
|
procs = {}
|
|
for pid in pids:
|
|
procs[pid] = _ProcessMemory(pid)
|
|
procs[pid].read_all()
|
|
|
|
print '=== PID: %d ===' % pid
|
|
|
|
print ' stat: %d' % procs[pid].stat.vsize
|
|
print ' statm: %d' % (procs[pid].statm.size * 4096)
|
|
print ' status: %d (Peak:%d)' % (procs[pid].status.vm_size * 1024,
|
|
procs[pid].status.vm_peak * 1024)
|
|
print ' smaps: %d' % (procs[pid].smaps.size * 1024)
|
|
print 'pagemap: %d' % procs[pid].pagemap.vsize
|
|
print ' stat: %d' % (procs[pid].stat.rss * 4096)
|
|
print ' statm: %d' % (procs[pid].statm.resident * 4096)
|
|
print ' status: %d (Peak:%d)' % (procs[pid].status.vm_rss * 1024,
|
|
procs[pid].status.vm_hwm * 1024)
|
|
print ' smaps: %d' % (procs[pid].smaps.rss * 1024)
|
|
print 'pagemap: %d' % procs[pid].pagemap.present
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main(sys.argv))
|