Skip to content

Instantly share code, notes, and snippets.

@eMPee584
Forked from mgedmin/strace_process_tree.py
Created June 28, 2013 08:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eMPee584/5883444 to your computer and use it in GitHub Desktop.
Save eMPee584/5883444 to your computer and use it in GitHub Desktop.
$ strace-process-tree zdaemon-py3.GIT/TRACE3
6184 execve("bin/test", ["bin/test", "-pvc", "-t", "README"], [/* 65 vars */])
├─6196 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -p 'echo hello world' "...], [/* 67 vars */])
│ └─6197 execve("./zdaemon", ["./zdaemon", "-p", "echo hello world", "fg"], [/* 67 vars */])
│ └─6199 execve("/bin/echo", ["echo", "hello", "world"], [/* 67 vars */])
├─6200 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -p 'sleep 100' start"], [/* 67 vars */])
│ └─6201 execve("./zdaemon", ["./zdaemon", "-p", "sleep 100", "start"], [/* 67 vars */])
│ └─6205 execve("/usr/bin/python3.3", ["/usr/bin/python3.3", "./zdaemon", "-S", "schema.xml", "-b", "10", "-s", "zdsock", "-m", "0o22", "-x", "0,2", "sleep", "100"], [/* 68 vars */])
│ └─6212 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f163fcab9d0)
│ ├─6213 clone(child_stack=0x7f163e4b4ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f163e4b59d0, tls=0x7f163e4b5700, child_tidptr=0x7f163e4b59d0)
│ └─6214 execve("/bin/sleep", ["sleep", "100"], [/* 67 vars */])
├─6215 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -p 'sleep 100' status"], [/* 67 vars */])
│ └─6216 execve("./zdaemon", ["./zdaemon", "-p", "sleep 100", "status"], [/* 67 vars */])
├─6217 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -p 'sleep 100' stop"], [/* 67 vars */])
│ └─6218 execve("./zdaemon", ["./zdaemon", "-p", "sleep 100", "stop"], [/* 67 vars */])
├─6220 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -p 'sleep 100' status"], [/* 67 vars */])
│ └─6221 execve("./zdaemon", ["./zdaemon", "-p", "sleep 100", "status"], [/* 67 vars */])
├─6225 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf start"], [/* 67 vars */])
│ └─6226 execve("./zdaemon", ["./zdaemon", "-Cconf", "start"], [/* 67 vars */])
│ └─6253 execve("/usr/bin/python3.3", ["/usr/bin/python3.3", "./zdaemon", "-S", "/home/mg/src/zdaemon-py3.GIT/src"..., "-C", "conf", "sleep", "100"], [/* 68 vars */])
│ └─6262 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fd2a97bf9d0)
│ ├─6263 clone(child_stack=0x7fd2a7fc8ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fd2a7fc99d0, tls=0x7fd2a7fc9700, child_tidptr=0x7fd2a7fc99d0)
│ └─6264 execve("/bin/sleep", ["sleep", "100"], [/* 67 vars */])
├─6269 execve("/bin/sh", ["/bin/sh", "-c", "ls"], [/* 67 vars */])
│ └─6270 execve("/bin/ls", ["ls"], [/* 67 vars */])
├─6271 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf stop"], [/* 67 vars */])
│ └─6272 execve("./zdaemon", ["./zdaemon", "-Cconf", "stop"], [/* 67 vars */])
├─6278 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf start"], [/* 67 vars */])
│ └─6279 execve("./zdaemon", ["./zdaemon", "-Cconf", "start"], [/* 67 vars */])
│ └─6288 execve("/usr/bin/python3.3", ["/usr/bin/python3.3", "./zdaemon", "-S", "/home/mg/src/zdaemon-py3.GIT/src"..., "-C", "conf", "sleep", "100"], [/* 68 vars */])
│ └─6294 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f44cb0e79d0)
│ ├─6295 clone(child_stack=0x7f44c98f0ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f44c98f19d0, tls=0x7f44c98f1700, child_tidptr=0x7f44c98f19d0)
│ └─6296 execve("/bin/sleep", ["sleep", "100"], [/* 67 vars */])
├─6298 execve("/bin/sh", ["/bin/sh", "-c", "ls"], [/* 67 vars */])
│ └─6300 execve("/bin/ls", ["ls"], [/* 67 vars */])
├─6301 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf stop"], [/* 67 vars */])
│ └─6302 execve("./zdaemon", ["./zdaemon", "-Cconf", "stop"], [/* 67 vars */])
├─6304 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf start 100"], [/* 67 vars */])
│ └─6305 execve("./zdaemon", ["./zdaemon", "-Cconf", "start", "100"], [/* 67 vars */])
│ └─6314 execve("/usr/bin/python3.3", ["/usr/bin/python3.3", "./zdaemon", "-S", "/home/mg/src/zdaemon-py3.GIT/src"..., "-C", "conf", "sleep", "100"], [/* 68 vars */])
│ └─6322 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff8f14959d0)
│ ├─6323 clone(child_stack=0x7ff8efc9eff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7ff8efc9f9d0, tls=0x7ff8efc9f700, child_tidptr=0x7ff8efc9f9d0)
│ └─6324 execve("/bin/sleep", ["sleep", "100"], [/* 67 vars */])
├─6333 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf status"], [/* 67 vars */])
│ └─6334 execve("./zdaemon", ["./zdaemon", "-Cconf", "status"], [/* 67 vars */])
├─6346 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf stop"], [/* 67 vars */])
│ └─6347 execve("./zdaemon", ["./zdaemon", "-Cconf", "stop"], [/* 67 vars */])
├─6348 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf fg"], [/* 67 vars */])
│ └─6349 execve("./zdaemon", ["./zdaemon", "-Cconf", "fg"], [/* 67 vars */])
│ └─6350 execve("/usr/bin/env", ["env"], [/* 68 vars */])
├─6351 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf start"], [/* 67 vars */])
│ └─6352 execve("./zdaemon", ["./zdaemon", "-Cconf", "start"], [/* 67 vars */])
│ └─6354 execve("/usr/bin/python3.3", ["/usr/bin/python3.3", "./zdaemon", "-S", "/home/mg/src/zdaemon-py3.GIT/src"..., "-C", "conf", "tail", "-f", "data"], [/* 68 vars */])
│ └─6380 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fb4506119d0)
│ ├─6381 clone(child_stack=0x7fb44ee1aff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fb44ee1b9d0, tls=0x7fb44ee1b700, child_tidptr=0x7fb44ee1b9d0)
│ └─6382 execve("/usr/bin/tail", ["tail", "-f", "data"], [/* 67 vars */])
└─6399 execve("/bin/sh", ["/bin/sh", "-c", "./zdaemon -Cconf reopen_transcri"...], [/* 67 vars */])
└─6400 execve("./zdaemon", ["./zdaemon", "-Cconf", "reopen_transcript"], [/* 67 vars */])
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
Usage:
strace-process-tree [filename]
Read strace -f output and produce a process tree.
"""
import re
import fileinput
from collections import defaultdict
__version__ = '0.2.2'
__author__ = 'Marius Gedminas <marius@gedmin.as>'
__url__ = 'https://gist.github.com/mgedmin/4953427'
__licence__ = 'GPL v2 or later' # or ask me for MIT
def events(stream):
RESUMED_PREFIX = re.compile('<... \w+ resumed> ')
UNFINISHED_SUFFIX = ' <unfinished ...>'
pending = {}
for line in stream:
pid, spaces, event = line.rstrip().partition(' ')
pid = int(pid)
event = event.lstrip()
m = RESUMED_PREFIX.match(event)
if m is not None:
event = pending.pop(pid) + event[len(m.group()):]
if event.endswith(UNFINISHED_SUFFIX):
pending[pid] = event[:-len(UNFINISHED_SUFFIX)]
else:
yield (pid, event)
class ProcessTree:
def __init__(self):
self.names = {}
self.parents = {}
self.children = defaultdict(list)
self.roots = set()
self.all = set()
# invariant: self.roots == self.all - set(self.parents), probably
def make_known(self, pid):
if pid not in self.all:
self.roots.add(pid)
self.all.add(pid)
def set_name(self, pid, name):
self.make_known(pid)
self.names[pid] = name
def add_child(self, ppid, pid):
self.make_known(ppid)
self.make_known(pid)
if pid in self.roots:
self.roots.remove(pid)
self.parents[pid] = ppid
self.children[ppid].append(pid)
def _format(self, pids, indent='', level=0):
r = []
for n, pid in enumerate(pids):
if level == 0:
s, cs = '', ''
elif n < len(pids) - 1:
s, cs = ' ├─', ' │ '
else:
s, cs = ' └─', ' '
r.append(indent + s + '{} {}\n'.format(pid, self.names.get(pid, '')))
r.append(self._format(sorted(self.children.get(pid, [])),
indent+cs, level+1))
return ''.join(r)
def __str__(self):
return self._format(sorted(self.roots))
def main():
tree = ProcessTree()
for pid, event in events(fileinput.input()):
if event.startswith('execve('):
args, equal, result = event.rpartition(' = ')
if result == '0':
tree.set_name(pid, args)
if event.startswith('clone('):
args, equal, result = event.rpartition(' = ')
if result.isdigit():
child_pid = int(result)
tree.set_name(child_pid, args)
tree.add_child(pid, child_pid)
print(str(tree).rstrip())
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment