Skip to content

Instantly share code, notes, and snippets.

@julian-klode
Created February 3, 2017 22:59
Show Gist options
  • Save julian-klode/356acfbe0bf56957d4e7cd00e9ed19d3 to your computer and use it in GitHub Desktop.
Save julian-klode/356acfbe0bf56957d4e7cd00e9ed19d3 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
import glob, os.path,collections, apt_pkg
interpreters=["bash", "sh", "python", "perl"]
_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
'KB': 1024.0, 'MB': 1024.0*1024.0}
def mem_usage(pid):
sum = 0
try:
# get pseudo file /proc/<pid>/status
with open(os.path.join("/proc", pid, "smaps")) as fil:
for line in fil:
if line.startswith("Pss"):
v = line.split()
sum += float(v[1]) * _scale[v[2]]
return sum
except Exception as e:
print("Error:", e)
return 0
files = collections.defaultdict(list)
for path in glob.glob("/var/lib/dpkg/info/*.list"):
name = os.path.basename(path)
pkg, _ = os.path.splitext(name)
with open(path) as flist:
for f in flist:
files[f.strip()].append(pkg)
if not f.strip().startswith("/usr"):
files["/usr" + f.strip()].append(pkg)
os.chdir("/proc")
processes = collections.defaultdict(set)
pkgcount = collections.defaultdict(int)
total = 0
for proc in os.listdir("."):
if not proc.isdigit():
continue
exe = os.path.join(proc, "exe")
if not os.path.exists(exe):
continue
exe = os.path.realpath(exe)
for interp in interpreters:
if "/" + interp in os.path.realpath(exe):
cwd=os.path.realpath(os.path.join(proc, "cwd"))
for arg in open(os.path.join(proc, "cmdline")).read().split("\0"):
for new_exe in arg, os.path.join(cwd, arg):
if "/" + interp in new_exe:
continue
if new_exe in files:
exe = new_exe
break
if exe == new_exe:
break
break
found=False
#print("=>", exe, files[exe])
pkgcount[proc] = set()
for pkg in files[exe] + files["/usr" + exe]:
pkgcount[proc].add(pkg)
processes[pkg].add(proc)
found=True
if "android-studio" in exe:
pkgcount[proc].add("android-studio")
processes["android-studio"].add(proc)
found=True
if not found:
pkgcount[proc].add("<other>")
processes["<other>"].add(proc)
res = []
mlen = 0
for pkg, proc in processes.items():
mlen=max(mlen, len(pkg))
s=sum((mem_usage(p) / len(pkgcount[p])) for p in proc)
res.append((s, pkg, proc))
total=0
print("%%-%ds\t%%s" % mlen % ("package", "memory used (PSS)"))
print("%s\t%s" % (mlen * "-", 20 * "-"))
for mem, pkg, procs in sorted(res):
print("%%-%ds\t%%s" % mlen % (pkg, apt_pkg.size_to_str(mem)))
total+=mem
for p in sorted(procs, key=lambda p: mem_usage(p)):
pass
#print(" - [%7s] %s" % (p, open(os.path.join(p, "cmdline")).read().replace("\0", " ")[:60]), apt_pkg.size_to_str(mem_usage(p)))
#print(" =>", open(os.path.join(p, "cmdline")).read().split("\0")[0])
print("%s\t%s" % (mlen * "-", 20 * "-"))
print("%%-%ds\t%%s" % mlen % ("<total>", apt_pkg.size_to_str(total)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment