Ihar Hrachyshka | 2b4735f | 2017-02-10 06:17:37 +0000 | [diff] [blame^] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # This tool lists processes that lock memory pages from swapping to disk. |
| 4 | |
| 5 | import re |
| 6 | import subprocess |
| 7 | |
| 8 | import psutil |
| 9 | |
| 10 | |
| 11 | SUMMARY_REGEX = re.compile(r".*\s+(?P<locked>[\d]+)\s+KB") |
| 12 | |
| 13 | |
| 14 | def main(): |
| 15 | try: |
| 16 | print _get_report() |
| 17 | except Exception as e: |
| 18 | print "Failure listing processes locking memory: %s" % str(e) |
| 19 | |
| 20 | |
| 21 | def _get_report(): |
| 22 | mlock_users = [] |
| 23 | for proc in psutil.process_iter(): |
| 24 | pid = proc.pid |
| 25 | # sadly psutil does not expose locked pages info, that's why we |
| 26 | # call to pmap and parse the output here |
| 27 | try: |
| 28 | out = subprocess.check_output(['pmap', '-XX', str(pid)]) |
| 29 | except subprocess.CalledProcessError as e: |
| 30 | # 42 means process just vanished, which is ok |
| 31 | if e.returncode == 42: |
| 32 | continue |
| 33 | raise |
| 34 | last_line = out.splitlines()[-1] |
| 35 | |
| 36 | # some processes don't provide a memory map, for example those |
| 37 | # running as kernel services, so we need to skip those that don't |
| 38 | # match |
| 39 | result = SUMMARY_REGEX.match(last_line) |
| 40 | if result: |
| 41 | locked = int(result.group('locked')) |
| 42 | if locked: |
| 43 | mlock_users.append({'name': proc.name(), |
| 44 | 'pid': pid, |
| 45 | 'locked': locked}) |
| 46 | |
| 47 | # produce a single line log message with per process mlock stats |
| 48 | if mlock_users: |
| 49 | return "; ".join( |
| 50 | "[%(name)s (pid:%(pid)s)]=%(locked)dKB" % args |
| 51 | # log heavy users first |
| 52 | for args in sorted(mlock_users, key=lambda d: d['locked']) |
| 53 | ) |
| 54 | else: |
| 55 | return "no locked memory" |
| 56 | |
| 57 | |
| 58 | if __name__ == "__main__": |
| 59 | main() |