Permalink
Switch branches/tags
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 340 lines (307 sloc) 11.7 KB
#!/usr/bin/env python
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Print detailed information about a process.
Author: Giampaolo Rodola' <g.rodola@gmail.com>
$ python scripts/procinfo.py
pid 4600
name chrome
parent 4554 (bash)
exe /opt/google/chrome/chrome
cwd /home/giampaolo
cmdline /opt/google/chrome/chrome
started 2016-09-19 11:12
cpu-tspent 27:27.68
cpu-times user=8914.32, system=3530.59,
children_user=1.46, children_system=1.31
cpu-affinity [0, 1, 2, 3, 4, 5, 6, 7]
memory rss=520.5M, vms=1.9G, shared=132.6M, text=95.0M, lib=0B,
data=816.5M, dirty=0B
memory % 3.26
user giampaolo
uids real=1000, effective=1000, saved=1000
uids real=1000, effective=1000, saved=1000
terminal /dev/pts/2
status sleeping
nice 0
ionice class=IOPriority.IOPRIO_CLASS_NONE, value=0
num-threads 47
num-fds 379
I/O read_count=96.6M, write_count=80.7M,
read_bytes=293.2M, write_bytes=24.5G
ctx-switches voluntary=30426463, involuntary=460108
children PID NAME
4605 cat
4606 cat
4609 chrome
4669 chrome
open-files PATH
/opt/google/chrome/icudtl.dat
/opt/google/chrome/snapshot_blob.bin
/opt/google/chrome/natives_blob.bin
/opt/google/chrome/chrome_100_percent.pak
[...]
connections PROTO LOCAL ADDR REMOTE ADDR STATUS
UDP 10.0.0.3:3693 *:* NONE
TCP 10.0.0.3:55102 172.217.22.14:443 ESTABLISHED
UDP 10.0.0.3:35172 *:* NONE
TCP 10.0.0.3:32922 172.217.16.163:443 ESTABLISHED
UDP :::5353 *:* NONE
UDP 10.0.0.3:59925 *:* NONE
threads TID USER SYSTEM
11795 0.7 1.35
11796 0.68 1.37
15887 0.74 0.03
19055 0.77 0.01
[...]
total=47
res-limits RLIMIT SOFT HARD
virtualmem infinity infinity
coredumpsize 0 infinity
cputime infinity infinity
datasize infinity infinity
filesize infinity infinity
locks infinity infinity
memlock 65536 65536
msgqueue 819200 819200
nice 0 0
openfiles 8192 65536
maxprocesses 63304 63304
rss infinity infinity
realtimeprio 0 0
rtimesched infinity infinity
sigspending 63304 63304
stack 8388608 infinity
mem-maps RSS PATH
381.4M [anon]
62.8M /opt/google/chrome/chrome
15.8M /home/giampaolo/.config/google-chrome/Default/History
6.6M /home/giampaolo/.config/google-chrome/Default/Favicons
[...]
"""
import argparse
import datetime
import socket
import sys
import psutil
ACCESS_DENIED = ''
NON_VERBOSE_ITERATIONS = 4
RLIMITS_MAP = {
"RLIMIT_AS": "virtualmem",
"RLIMIT_CORE": "coredumpsize",
"RLIMIT_CPU": "cputime",
"RLIMIT_DATA": "datasize",
"RLIMIT_FSIZE": "filesize",
"RLIMIT_LOCKS": "locks",
"RLIMIT_MEMLOCK": "memlock",
"RLIMIT_MSGQUEUE": "msgqueue",
"RLIMIT_NICE": "nice",
"RLIMIT_NOFILE": "openfiles",
"RLIMIT_NPROC": "maxprocesses",
"RLIMIT_RSS": "rss",
"RLIMIT_RTPRIO": "realtimeprio",
"RLIMIT_RTTIME": "rtimesched",
"RLIMIT_SIGPENDING": "sigspending",
"RLIMIT_STACK": "stack",
}
def convert_bytes(n):
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
prefix = {}
for i, s in enumerate(symbols):
prefix[s] = 1 << (i + 1) * 10
for s in reversed(symbols):
if n >= prefix[s]:
value = float(n) / prefix[s]
return '%.1f%s' % (value, s)
return "%sB" % n
def print_(a, b):
if sys.stdout.isatty() and psutil.POSIX:
fmt = '\x1b[1;32m%-13s\x1b[0m %s' % (a, b)
else:
fmt = '%-11s %s' % (a, b)
print(fmt)
def str_ntuple(nt, bytes2human=False):
if nt == ACCESS_DENIED:
return ""
if not bytes2human:
return ", ".join(["%s=%s" % (x, getattr(nt, x)) for x in nt._fields])
else:
return ", ".join(["%s=%s" % (x, convert_bytes(getattr(nt, x)))
for x in nt._fields])
def run(pid, verbose=False):
try:
proc = psutil.Process(pid)
pinfo = proc.as_dict(ad_value=ACCESS_DENIED)
except psutil.NoSuchProcess as err:
sys.exit(str(err))
# collect other proc info
with proc.oneshot():
try:
parent = proc.parent()
if parent:
parent = '(%s)' % parent.name()
else:
parent = ''
except psutil.Error:
parent = ''
try:
pinfo['children'] = proc.children()
except psutil.Error:
pinfo['children'] = []
if pinfo['create_time']:
started = datetime.datetime.fromtimestamp(
pinfo['create_time']).strftime('%Y-%m-%d %H:%M')
else:
started = ACCESS_DENIED
# here we go
print_('pid', pinfo['pid'])
print_('name', pinfo['name'])
print_('parent', '%s %s' % (pinfo['ppid'], parent))
print_('exe', pinfo['exe'])
print_('cwd', pinfo['cwd'])
print_('cmdline', ' '.join(pinfo['cmdline']))
print_('started', started)
cpu_tot_time = datetime.timedelta(seconds=sum(pinfo['cpu_times']))
cpu_tot_time = "%s:%s.%s" % (
cpu_tot_time.seconds // 60 % 60,
str((cpu_tot_time.seconds % 60)).zfill(2),
str(cpu_tot_time.microseconds)[:2])
print_('cpu-tspent', cpu_tot_time)
print_('cpu-times', str_ntuple(pinfo['cpu_times']))
if hasattr(proc, "cpu_affinity"):
print_("cpu-affinity", pinfo["cpu_affinity"])
if hasattr(proc, "cpu_num"):
print_("cpu-num", pinfo["cpu_num"])
print_('memory', str_ntuple(pinfo['memory_info'], bytes2human=True))
print_('memory %', round(pinfo['memory_percent'], 2))
print_('user', pinfo['username'])
if psutil.POSIX:
print_('uids', str_ntuple(pinfo['uids']))
if psutil.POSIX:
print_('uids', str_ntuple(pinfo['uids']))
if psutil.POSIX:
print_('terminal', pinfo['terminal'] or '')
print_('status', pinfo['status'])
print_('nice', pinfo['nice'])
if hasattr(proc, "ionice"):
try:
ionice = proc.ionice()
except psutil.Error:
pass
else:
if psutil.WINDOWS:
print_("ionice", ionice)
else:
print_("ionice", "class=%s, value=%s" % (
str(ionice.ioclass), ionice.value))
print_('num-threads', pinfo['num_threads'])
if psutil.POSIX:
print_('num-fds', pinfo['num_fds'])
if psutil.WINDOWS:
print_('num-handles', pinfo['num_handles'])
if 'io_counters' in pinfo:
print_('I/O', str_ntuple(pinfo['io_counters'], bytes2human=True))
if 'num_ctx_switches' in pinfo:
print_("ctx-switches", str_ntuple(pinfo['num_ctx_switches']))
if pinfo['children']:
template = "%-6s %s"
print_("children", template % ("PID", "NAME"))
for child in pinfo['children']:
try:
print_('', template % (child.pid, child.name()))
except psutil.AccessDenied:
print_('', template % (child.pid, ""))
except psutil.NoSuchProcess:
pass
if pinfo['open_files']:
print_('open-files', 'PATH')
for i, file in enumerate(pinfo['open_files']):
if not verbose and i >= NON_VERBOSE_ITERATIONS:
print_("", "[...]")
break
print_('', file.path)
else:
print_('open-files', '')
if pinfo['connections']:
template = '%-5s %-25s %-25s %s'
print_('connections',
template % ('PROTO', 'LOCAL ADDR', 'REMOTE ADDR', 'STATUS'))
for conn in pinfo['connections']:
if conn.type == socket.SOCK_STREAM:
type = 'TCP'
elif conn.type == socket.SOCK_DGRAM:
type = 'UDP'
else:
type = 'UNIX'
lip, lport = conn.laddr
if not conn.raddr:
rip, rport = '*', '*'
else:
rip, rport = conn.raddr
print_('', template % (
type,
"%s:%s" % (lip, lport),
"%s:%s" % (rip, rport),
conn.status))
else:
print_('connections', '')
if pinfo['threads'] and len(pinfo['threads']) > 1:
template = "%-5s %12s %12s"
print_('threads', template % ("TID", "USER", "SYSTEM"))
for i, thread in enumerate(pinfo['threads']):
if not verbose and i >= NON_VERBOSE_ITERATIONS:
print_("", "[...]")
break
print_('', template % thread)
print_('', "total=%s" % len(pinfo['threads']))
else:
print_('threads', '')
if hasattr(proc, "rlimit"):
res_names = [x for x in dir(psutil) if x.startswith("RLIMIT")]
resources = []
for res_name in res_names:
try:
soft, hard = proc.rlimit(getattr(psutil, res_name))
except psutil.AccessDenied:
pass
else:
resources.append((res_name, soft, hard))
if resources:
template = "%-12s %15s %15s"
print_("res-limits", template % ("RLIMIT", "SOFT", "HARD"))
for res_name, soft, hard in resources:
if soft == psutil.RLIM_INFINITY:
soft = "infinity"
if hard == psutil.RLIM_INFINITY:
hard = "infinity"
print_('', template % (
RLIMITS_MAP.get(res_name, res_name), soft, hard))
if hasattr(proc, "environ") and pinfo['environ']:
template = "%-25s %s"
print_("environ", template % ("NAME", "VALUE"))
for i, k in enumerate(sorted(pinfo['environ'])):
if not verbose and i >= NON_VERBOSE_ITERATIONS:
print_("", "[...]")
break
print_("", template % (k, pinfo['environ'][k]))
if pinfo.get('memory_maps', None):
template = "%-8s %s"
print_("mem-maps", template % ("RSS", "PATH"))
maps = sorted(pinfo['memory_maps'], key=lambda x: x.rss, reverse=True)
for i, region in enumerate(maps):
if not verbose and i >= NON_VERBOSE_ITERATIONS:
print_("", "[...]")
break
print_("", template % (convert_bytes(region.rss), region.path))
def main(argv=None):
parser = argparse.ArgumentParser(
description="print information about a process")
parser.add_argument("pid", type=int, help="process pid")
parser.add_argument('--verbose', '-v', action='store_true',
help="print more info")
args = parser.parse_args()
run(args.pid, args.verbose)
if __name__ == '__main__':
sys.exit(main())