Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 3 | # Based on ps_mem.py: |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 4 | # Licence: LGPLv2 |
| 5 | # Author: P@draigBrady.com |
| 6 | # Source: http://www.pixelbeat.org/scripts/ps_mem.py |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 7 | # http://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py |
| 8 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 9 | import errno |
| 10 | import os |
| 11 | import sys |
| 12 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 13 | |
| 14 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 15 | class Proc: |
| 16 | def __init__(self): |
| 17 | uname = os.uname() |
| 18 | if uname[0] == "FreeBSD": |
| 19 | self.proc = '/compat/linux/proc' |
| 20 | else: |
| 21 | self.proc = '/proc' |
| 22 | |
| 23 | def path(self, *args): |
| 24 | return os.path.join(self.proc, *(str(a) for a in args)) |
| 25 | |
| 26 | def open(self, *args): |
| 27 | try: |
| 28 | return open(self.path(*args)) |
| 29 | except (IOError, OSError): |
| 30 | val = sys.exc_info()[1] |
| 31 | if (val.errno == errno.ENOENT or # kernel thread or process gone |
| 32 | val.errno == errno.EPERM): |
| 33 | raise LookupError |
| 34 | raise |
| 35 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 36 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 37 | def kernel_ver(): |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 38 | """ Return (major,minor,release)""" |
| 39 | proc = Proc() |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 40 | kv = proc.open('sys/kernel/osrelease').readline().split(".")[:3] |
| 41 | last = len(kv) |
| 42 | if last == 2: |
| 43 | kv.append('0') |
| 44 | last -= 1 |
| 45 | while last > 0: |
| 46 | for char in "-_": |
| 47 | kv[last] = kv[last].split(char)[0] |
| 48 | try: |
| 49 | int(kv[last]) |
| 50 | except: |
| 51 | kv[last] = 0 |
| 52 | last -= 1 |
| 53 | return (int(kv[0]), int(kv[1]), int(kv[2])) |
| 54 | |
| 55 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 56 | #Note shared is always a subset of rss (trs is not always) |
| 57 | def getMemStats(pid): |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 58 | """ Return memory data of pid in format (Private, Shared) """ |
| 59 | |
| 60 | PAGESIZE = os.sysconf("SC_PAGE_SIZE") / 1024 #KiB |
| 61 | proc = Proc() |
| 62 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 63 | Private_lines = [] |
| 64 | Shared_lines = [] |
| 65 | Pss_lines = [] |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 66 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 67 | Rss = (int(proc.open(pid, 'statm').readline().split()[1]) |
| 68 | * PAGESIZE) |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 69 | |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 70 | if os.path.exists(proc.path(pid, 'smaps')): #stat |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 71 | for line in proc.open(pid, 'smaps').readlines(): #open |
| 72 | # Note we checksum smaps as maps is usually but |
| 73 | # not always different for separate processes. |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 74 | if line.startswith("Shared"): |
| 75 | Shared_lines.append(line) |
| 76 | elif line.startswith("Private"): |
| 77 | Private_lines.append(line) |
| 78 | elif line.startswith("Pss"): |
| 79 | have_pss = 1 |
| 80 | Pss_lines.append(line) |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 81 | Shared = sum([int(line.split()[1]) for line in Shared_lines]) |
| 82 | Private = sum([int(line.split()[1]) for line in Private_lines]) |
| 83 | #Note Shared + Private = Rss above |
| 84 | #The Rss in smaps includes video card mem etc. |
| 85 | if have_pss: |
| 86 | pss_adjust = 0.5 # add 0.5KiB as this avg error due to trunctation |
| 87 | Pss = sum([float(line.split()[1])+pss_adjust for line in Pss_lines]) |
| 88 | Shared = Pss - Private |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 89 | elif (2, 6, 1) <= kernel_ver() <= (2, 6, 9): |
Ved-vampir | 98a9917 | 2015-03-17 14:58:15 +0300 | [diff] [blame] | 90 | Shared = 0 #lots of overestimation, but what can we do? |
| 91 | Private = Rss |
| 92 | else: |
| 93 | Shared = int(proc.open(pid, 'statm').readline().split()[2]) |
| 94 | Shared *= PAGESIZE |
| 95 | Private = Rss - Shared |
Ved-vampir | 501065c | 2015-03-17 16:16:57 +0300 | [diff] [blame^] | 96 | return (Private, Shared) |