John Vandenberg has uploaded a new change for review. https://gerrit.wikimedia.org/r/264028
Change subject: Sync ps_mem.py from origin ...................................................................... Sync ps_mem.py from origin Sync ps_mem.py from https://github.com/pixelb/ps_mem/ which has been improved to pass pyflakes. Change-Id: If24ac49e96adb1e471764b615c3e87a647627c3f --- M modules/admin/files/home/ori/.binned/ps_mem.py 1 file changed, 103 insertions(+), 127 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/operations/puppet refs/changes/28/264028/1 diff --git a/modules/admin/files/home/ori/.binned/ps_mem.py b/modules/admin/files/home/ori/.binned/ps_mem.py index 274c955..f3fd2e5 100755 --- a/modules/admin/files/home/ori/.binned/ps_mem.py +++ b/modules/admin/files/home/ori/.binned/ps_mem.py @@ -3,9 +3,9 @@ # Try to determine how much RAM is currently being used per program. # Note per _program_, not per process. So for example this script # will report RAM used by all httpd process together. In detail it reports: -# sum(private RAM for program processes) + sum(Shared RAM for program -# processes) The shared RAM is problematic to calculate, and this script -# automatically selects the most accurate method available for your kernel. +# sum(private RAM for program processes) + sum(Shared RAM for program processes) +# The shared RAM is problematic to calculate, and this script automatically +# selects the most accurate method available for your kernel. # Licence: LGPLv2 # Author: [email protected] @@ -31,13 +31,12 @@ # which fixes the possible race between reading # RSS with ps, and shared memory with this program. # Also we can show non truncated command names. -# V1.8 28 Sep 2007 More accurate matching for stats in -# /proc/$pid/smaps as otherwise could match libraries -# causing a crash. +# V1.8 28 Sep 2007 More accurate matching for stats in /proc/$pid/smaps +# as otherwise could match libraries causing a crash. # Patch from [email protected] # V1.9 20 Feb 2008 Fix invalid values reported when PSS is available. # Reported by Andrey Borzenkov <[email protected]> -# V3.3 24 Jun 2014 +# V3.6 16 Oct 2015 # http://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py # Notes: @@ -45,7 +44,7 @@ # All interpreted programs where the interpreter is started # by the shell or with env, will be merged to the interpreter # (as that's what's given to exec). For e.g. all python programs -# starting with "# !/usr/bin/env python" will be grouped under python. +# starting with "#!/usr/bin/env python" will be grouped under python. # You can change this by using the full command line but that will # have the undesirable affect of splitting up programs started with # differing parameters (for e.g. mingetty tty[1-6]). @@ -80,16 +79,6 @@ import os import sys -try: - # md5 module is deprecated on python 2.6 - # so try the newer hashlib first - import hashlib - md5_new = hashlib.md5 -except ImportError: - import md5 - md5_new = md5.new - - # The following exits cleanly on Ctrl-C or EPIPE # while treating other exceptions as before. def std_exceptions(etype, value, tb): @@ -106,24 +95,12 @@ # Define some global variables # -PAGESIZE = os.sysconf("SC_PAGE_SIZE") / 1024 # KiB +PAGESIZE = os.sysconf("SC_PAGE_SIZE") / 1024 #KiB our_pid = os.getpid() have_pss = 0 -help_msg = """Usage: ps_mem [OPTION]... -Show program core memory usage - - -h, -help Show this help - -p <pid>[,pid2,...pidN] Only show memory usage PIDs in the specified list - -s, --split-args Show and separate by, all command line arguments - -t, --total Show only the total value - -w <N> Measure and show process memory every N seconds - -""" - class Proc: - def __init__(self): uname = os.uname() if uname[0] == "FreeBSD": @@ -136,11 +113,14 @@ def open(self, *args): try: - return open(self.path(*args)) + if sys.version_info < (3,): + return open(self.path(*args)) + else: + return open(self.path(*args), errors='ignore') except (IOError, OSError): val = sys.exc_info()[1] - if (val.errno == errno.ENOENT or # kernel thread or process gone - val.errno == errno.EPERM): + if (val.errno == errno.ENOENT or # kernel thread or process gone + val.errno == errno.EPERM): raise LookupError raise @@ -192,14 +172,19 @@ return (split_args, pids_to_show, watch, only_total) - def help(): - global help_msg + help_msg = 'Usage: ps_mem [OPTION]...\n' \ + 'Show program core memory usage\n' \ + '\n' \ + ' -h, -help Show this help\n' \ + ' -p <pid>[,pid2,...pidN] Only show memory usage PIDs in the specified list\n' \ + ' -s, --split-args Show and separate by, all command line arguments\n' \ + ' -t, --total Show only the total value\n' \ + ' -w <N> Measure and show process memory every N seconds\n' + return help_msg -# (major,minor,release) - - +#(major,minor,release) def kernel_ver(): kv = proc.open('sys/kernel/osrelease').readline().split(".")[:3] last = len(kv) @@ -217,22 +202,22 @@ return (int(kv[0]), int(kv[1]), int(kv[2])) -# return Private,Shared -# Note shared is always a subset of rss (trs is not always) +#return Private,Shared +#Note shared is always a subset of rss (trs is not always) def getMemStats(pid): global have_pss - mem_id = pid # unique + mem_id = pid #unique Private_lines = [] Shared_lines = [] Pss_lines = [] - Rss = (int(proc.open(pid, 'statm').readline().split()[1]) * - PAGESIZE) - if os.path.exists(proc.path(pid, 'smaps')): # stat - digester = md5_new() - for line in proc.open(pid, 'smaps').readlines(): # open - # Note we checksum smaps as maps is usually but - # not always different for separate processes. - digester.update(line.encode('latin1')) + Rss = (int(proc.open(pid, 'statm').readline().split()[1]) + * PAGESIZE) + if os.path.exists(proc.path(pid, 'smaps')): #stat + lines = proc.open(pid, 'smaps').readlines() #open + # Note we checksum smaps as maps is usually but + # not always different for separate processes. + mem_id = hash(''.join(lines)) + for line in lines: if line.startswith("Shared"): Shared_lines.append(line) elif line.startswith("Private"): @@ -240,18 +225,16 @@ elif line.startswith("Pss"): have_pss = 1 Pss_lines.append(line) - mem_id = digester.hexdigest() Shared = sum([int(line.split()[1]) for line in Shared_lines]) Private = sum([int(line.split()[1]) for line in Private_lines]) - # Note Shared + Private = Rss above - # The Rss in smaps includes video card mem etc. + #Note Shared + Private = Rss above + #The Rss in smaps includes video card mem etc. if have_pss: - pss_adjust = 0.5 # add 0.5KiB as this avg error due to trunctation - Pss = sum( - [float(line.split()[1]) + pss_adjust for line in Pss_lines]) + pss_adjust = 0.5 # add 0.5KiB as this avg error due to trunctation + Pss = sum([float(line.split()[1])+pss_adjust for line in Pss_lines]) Shared = Pss - Private - elif (2, 6, 1) <= kernel_ver() <= (2, 6, 9): - Shared = 0 # lots of overestimation, but what can we do? + elif (2,6,1) <= kernel_ver() <= (2,6,9): + Shared = 0 #lots of overestimation, but what can we do? Private = Rss else: Shared = int(proc.open(pid, 'statm').readline().split()[2]) @@ -273,7 +256,8 @@ path = path.split('\0')[0] except OSError: val = sys.exc_info()[1] - if (val.errno == errno.ENOENT or val.errno == errno.EPERM): + if (val.errno == errno.ENOENT or # either kernel thread or process gone + val.errno == errno.EPERM): raise LookupError raise @@ -284,8 +268,9 @@ if os.path.exists(path): path += " [updated]" else: - # The path could be have prelink stuff so try cmdline - # which might have the full path present. + #The path could be have prelink stuff so try cmdline + #which might have the full path present. This helped for: + #/usr/libexec/notification-area-applet.#prelink#.fX7LCT (deleted) if os.path.exists(cmdline[0]): path = cmdline[0] + " [updated]" else: @@ -293,22 +278,25 @@ exe = os.path.basename(path) cmd = proc.open(pid, 'status').readline()[6:-1] if exe.startswith(cmd): - cmd = exe # show non truncated version - # Note because we show the non truncated name - # one can have separated programs as follows: - # 584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash) + cmd = exe #show non truncated version + #Note because we show the non truncated name + #one can have separated programs as follows: + #584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash) # 56.0 MiB + 22.2 MiB = 78.2 MiB mozilla-thunderbird-bin - return cmd + if sys.version_info < (3,): + return cmd + else: + return cmd.encode(errors='replace').decode() -# The following matches "du -h" output -# see also human.py +#The following matches "du -h" output +#see also human.py def human(num, power="Ki", units=None): if units is None: powers = ["Ki", "Mi", "Gi", "Ti"] - while num >= 1000: # 4 digits + while num >= 1000: #4 digits num /= 1024.0 - power = powers[powers.index(power) + 1] + power = powers[powers.index(power)+1] return "%.1f %sB" % (num, power) else: return "%.f" % ((num * 1024) / units) @@ -320,67 +308,59 @@ else: return cmd -# Warn of possible inaccuracies -# 2 = accurate & can total -# 1 = accurate only considering each process in isolation -# 0 = some shared mem not reported -# -1= all shared mem not reported - - +#Warn of possible inaccuracies +#2 = accurate & can total +#1 = accurate only considering each process in isolation +#0 = some shared mem not reported +#-1= all shared mem not reported def shared_val_accuracy(): """http://wiki.apache.org/spamassassin/TopSharedMemoryBug""" kv = kernel_ver() - if kv[:2] == (2, 4): + pid = os.getpid() + if kv[:2] == (2,4): if proc.open('meminfo').read().find("Inact_") == -1: return 1 return 0 - elif kv[:2] == (2, 6): - pid = os.getpid() + elif kv[:2] == (2,6): if os.path.exists(proc.path(pid, 'smaps')): - if proc.open(pid, 'smaps').read().find("Pss:") != -1: + if proc.open(pid, 'smaps').read().find("Pss:")!=-1: return 2 else: return 1 - if (2, 6, 1) <= kv <= (2, 6, 9): + if (2,6,1) <= kv <= (2,6,9): return -1 return 0 - elif kv[0] > 2: + elif kv[0] > 2 and os.path.exists(proc.path(pid, 'smaps')): return 2 else: return 1 - -def show_shared_val_accuracy(possible_inacc, only_total=False): - level = ("Warning", "Error")[only_total] +def show_shared_val_accuracy( possible_inacc, only_total=False ): + level = ("Warning","Error")[only_total] if possible_inacc == -1: sys.stderr.write( - "%s: Shared memory is not reported by this system.\n" % level + "%s: Shared memory is not reported by this system.\n" % level ) sys.stderr.write( - "Values reported will be too large, and totals are not reported\n" + "Values reported will be too large, and totals are not reported\n" ) elif possible_inacc == 0: sys.stderr.write( - "%s: Shared memory is not reported accurately by this system.\n" % - level) + "%s: Shared memory is not reported accurately by this system.\n" % level + ) sys.stderr.write( - "Values reported could be too large, and totals are not reported\n" + "Values reported could be too large, and totals are not reported\n" ) elif possible_inacc == 1: sys.stderr.write( - "%s: Shared memory is slightly over-estimated by this system\n" - "for each program, so totals are not reported.\n" % level + "%s: Shared memory is slightly over-estimated by this system\n" + "for each program, so totals are not reported.\n" % level ) sys.stderr.close() if only_total and possible_inacc != 2: sys.exit(1) - -def get_memory_usage( - pids_to_show, - split_args, - include_self=False, - only_self=False): +def get_memory_usage( pids_to_show, split_args, include_self=False, only_self=False ): cmds = {} shareds = {} mem_ids = {} @@ -401,19 +381,19 @@ try: cmd = getCmdName(pid, split_args) except LookupError: - # operation not permitted - # kernel threads don't have exe links or - # process gone + #operation not permitted + #kernel threads don't have exe links or + #process gone continue try: private, shared, mem_id = getMemStats(pid) except RuntimeError: - continue # process gone + continue #process gone if shareds.get(cmd): - if have_pss: # add shared portion of PSS together + if have_pss: #add shared portion of PSS together shareds[cmd] += shared - elif shareds[cmd] < shared: # just take largest shared val + elif shareds[cmd] < shared: #just take largest shared val shareds[cmd] = shared else: shareds[cmd] = shared @@ -422,9 +402,9 @@ count[cmd] += 1 else: count[cmd] = 1 - mem_ids.setdefault(cmd, {}).update({mem_id: None}) + mem_ids.setdefault(cmd, {}).update({mem_id:None}) - # Add shared mem for each program + #Add shared mem for each program total = 0 for cmd in cmds: cmd_count = count[cmd] @@ -435,49 +415,45 @@ if have_pss: shareds[cmd] /= cmd_count cmds[cmd] = cmds[cmd] + shareds[cmd] - total += cmds[cmd] # valid if PSS available + total += cmds[cmd] #valid if PSS available - sorted_cmds = sorted(cmds.items(), key=lambda x: x[1]) + sorted_cmds = sorted(cmds.items(), key=lambda x:x[1]) sorted_cmds = [x for x in sorted_cmds if x[1]] return sorted_cmds, shareds, count, total - def print_header(): sys.stdout.write(" Private + Shared = RAM used\tProgram\n\n") - def print_memory_usage(sorted_cmds, shareds, count, total): for cmd in sorted_cmds: sys.stdout.write("%9s + %9s = %9s\t%s\n" % - (human(cmd[1] - shareds[cmd[0]]), + (human(cmd[1]-shareds[cmd[0]]), human(shareds[cmd[0]]), human(cmd[1]), cmd_with_count(cmd[0], count[cmd[0]]))) if have_pss: sys.stdout.write("%s\n%s%9s\n%s\n" % ("-" * 33, " " * 24, human(total), "=" * 33)) - def verify_environment(): if os.geteuid() != 0: sys.stderr.write("Sorry, root permission required.\n") - if __name__ == '__main__': - sys.stderr.close() - sys.exit(1) + sys.stderr.close() + sys.exit(1) try: - kv = kernel_ver() + kernel_ver() except (IOError, OSError): val = sys.exc_info()[1] if val.errno == errno.ENOENT: sys.stderr.write( - "Couldn't access " + proc.path('') + "\n" - "Only GNU/Linux and FreeBSD (with linprocfs) are supported\n") + "Couldn't access " + proc.path('') + "\n" + "Only GNU/Linux and FreeBSD (with linprocfs) are supported\n") sys.exit(2) else: raise -if __name__ == '__main__': +def main(): split_args, pids_to_show, watch, only_total = parse_options() verify_environment() @@ -488,10 +464,9 @@ try: sorted_cmds = True while sorted_cmds: - sorted_cmds, shareds, count, total = get_memory_usage( - pids_to_show, split_args) + sorted_cmds, shareds, count, total = get_memory_usage( pids_to_show, split_args ) if only_total and have_pss: - sys.stdout.write(human(total, units=1) + '\n') + sys.stdout.write(human(total, units=1)+'\n') elif not only_total: print_memory_usage(sorted_cmds, shareds, count, total) time.sleep(watch) @@ -501,10 +476,9 @@ pass else: # This is the default behavior - sorted_cmds, shareds, count, total = get_memory_usage( - pids_to_show, split_args) + sorted_cmds, shareds, count, total = get_memory_usage( pids_to_show, split_args ) if only_total and have_pss: - sys.stdout.write(human(total, units=1) + '\n') + sys.stdout.write(human(total, units=1)+'\n') elif not only_total: print_memory_usage(sorted_cmds, shareds, count, total) @@ -514,4 +488,6 @@ sys.stdout.close() vm_accuracy = shared_val_accuracy() - show_shared_val_accuracy(vm_accuracy, only_total) + show_shared_val_accuracy( vm_accuracy, only_total ) + +if __name__ == '__main__': main() -- To view, visit https://gerrit.wikimedia.org/r/264028 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: If24ac49e96adb1e471764b615c3e87a647627c3f Gerrit-PatchSet: 1 Gerrit-Project: operations/puppet Gerrit-Branch: production Gerrit-Owner: John Vandenberg <[email protected]> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
