3 exec python
$0 ${1+"$@"}
10 from time import sleep
11 from subprocess import *
13 # -o file.txt : output information to a file rather than stderr
15 # -m : monitor mode: output every measurement
16 # -p rate : poll every rate seconds (default is 0.1)
17 # -h : Show usage info
23 SIGNALS = [signal.SIGINT, signal.SIGTERM, signal.SIGABRT]
26 print("USAGE
: {} [-d] [-m] [-p TIME
] [-o FILE
] COMMAND
[ARG
[ARG
[...
]]]".format(cmd))
28 print(" -m : Output every tick instead of
at the end
")
29 print(" -p TIME
: Set the
time period
in seconds
")
30 print(" -o FILE
: Output to
file (default is stdout
)")
31 print(" -d : Debug mode
(verbose output
)")
34 # Handle command-line input
37 while i < len(sys.argv):
38 if sys.argv[i] == '-o':
40 out = open(sys.argv[i], 'w')
41 elif sys.argv[i] == '-d':
43 elif sys.argv[i] == '-m':
45 elif sys.argv[i] == '-p':
47 poll_rate = float(sys.argv[i])
48 elif sys.argv[i] == '-h':
49 print_usage(sys.argv[0])
52 child_args.append(sys.argv[i])
55 # child_command should be a single argument as if to "/bin
/sh
-c 'child_command'"
56 # when shell=True is enabled
57 child_command = ' '.join(child_args)
61 print >>sys.stderr, "memusg
: {}".format(msg)
64 out.flush # Only works if run with python -u
68 # Example: /bin/ps -o vsize= --sid 23928
69 proc = Popen(['ps', '-o', 'vsize=', '-g', str(sid)], stdout=PIPE, stderr=None, shell=False)
70 (stdout, _stderr) = proc.communicate()
71 # Iterate over each process within the process tree of our process session
72 # (this ensures that we include processes launched by a child bash script, etc.)
73 for line in stdout.split():
74 vsize += int(line.strip())
77 def handle_signal(signal, frame):
78 # If the proc is running, pass the signal down.
79 if proc and not proc.returncode:
80 proc.send_signal(signal)
82 os.kill(fork_pid, signal)
86 # Create a new process session for this process so that we can
87 # easily calculate the memory usage of the whole process tree using ps
89 # Since we need a new session using os.setsid(), we must first fork()
92 pgid = os.getpgid(pid)
93 log("Pre-fork
: PID is
{} ; PGID is
{} ; SID is
{}".format(pid, pgid, sid))
97 # Attach signal handler to everything we want to pass through
98 proc = None # after ^C, returns here and need `proc` being defined.
100 signal.signal(s, handle_signal)
103 # We *are* the new fork (not the original process)
106 pgid = os.getpgid(pid)
107 log("Post-fork
: PID is
{} ; PGID is
{} ; SID is
{}".format(pid, pgid, sid))
109 log("Trying to init our own session
".format(pid, pgid))
112 pgid = os.getpgid(pid)
113 log("Post-session init
: PID is
{} ; PGID is
{} ; SID is
{}".format(pid, pgid, sid))
115 log("Starting child
: {}".format(child_command))
116 # "None
" means "inherit from parent
"
117 proc = Popen(child_command, stdin=None, stdout=None, stderr=None, env=None, shell=True)
120 while proc.returncode == None:
121 #vmpeak = max(get_vsize(pgid), vmpeak)
122 size = get_vsize(pgid)
124 put("memusg
: {} kb
\n".format(size))
125 vmpeak = max(size, vmpeak)
126 log("Waiting
for child to
exit. vmpeak
={}".format(vmpeak))
128 sleep(poll_rate) # Time in seconds (float)
130 put("memusg
: vmpeak
: {} kb
\n".format(vmpeak))
132 status = proc.returncode
133 log("Child process returned
{}".format(status))
137 # This is the branch of fork that continues the original process
138 (_fork_pid, full_status) = os.waitpid(fork_pid, 0)
139 status = full_status >> 8
140 log("Fork returned
{}".format(status))