From 5319c0d3479df52cd696cf93085fcf1797d5e855 Mon Sep 17 00:00:00 2001 From: Pádraig Brady Date: Oct 16 2015 09:53:08 +0000 Subject: update to latest upstream Also.. - adjust spec to depend on the default python implementation - maintain timestamp of edited script - don't buildrequire python-devel - remove s/--split-args/--show-cmdline/ patch --- diff --git a/ps_mem-ennobling-the-s-switch.patch b/ps_mem-ennobling-the-s-switch.patch deleted file mode 100644 index ccc83c4..0000000 --- a/ps_mem-ennobling-the-s-switch.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0736aab9093ae3043f8e2b11ecc23924ac2b7e01 Mon Sep 17 00:00:00 2001 -From: Jaromir Capik -Date: Mon, 12 Aug 2013 14:48:03 +0200 -Subject: [PATCH] ps_mem.py: Ennobling the -s switch - -Previously the longopt variant of the -s switch -didn't make much sense. This commit changes the ---split-args switch to the --show-cmdline switch -and adds the switch in the help/usage message -since it was completely missing there. ---- - scripts/ps_mem.py | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/scripts/ps_mem.py b/scripts/ps_mem.py -index 92be618..b30dc30 100755 ---- a/scripts/ps_mem -+++ b/scripts/ps_mem -@@ -139,7 +139,7 @@ proc = Proc() - - def parse_options(): - try: -- long_options = ['split-args', 'help'] -+ long_options = ['show-cmdline', 'help'] - opts, args = getopt.getopt(sys.argv[1:], "shp:w:", long_options) - except getopt.GetoptError: - sys.stderr.write(help()) -@@ -151,7 +151,7 @@ def parse_options(): - watch = None - - for o, a in opts: -- if o in ('-s', '--split-args'): -+ if o in ('-s', '--show-cmdline'): - split_args = True - if o in ('-h', '--help'): - sys.stdout.write(help()) -@@ -176,7 +176,8 @@ def help(): - '\n'\ - '-h Show this help\n'\ - '-w Measure and show process memory every N seconds\n'\ -- '-p [,pid2,...pidN] Only show memory usage PIDs in the specified list\n' -+ '-p [,pid2,...pidN] Only show memory usage PIDs in the specified list\n' \ -+ '-s, --show-cmdline Show cmdline\n' - - return help_msg - --- -1.8.3.1 - diff --git a/ps_mem.1 b/ps_mem.1 index b69e872..12bf337 100644 --- a/ps_mem.1 +++ b/ps_mem.1 @@ -1,20 +1,21 @@ -.\" Simple man page to ps_mem.py script +.\" Simple man page to ps_mem script .\" Contact fholec@redhat.com -.TH ps_mem 1 "31 July 2013" "" "" +.TH ps_mem 1 "04 October 2014" "" "" .SH NAME ps_mem \- Memory profiling tool .SH SYNOPSIS -.B ps_mem -[\-h|\-\-help] [\-s|\-\-show\-cmdline] [\-p PID] [\-w N] +.B ps_mem [OPTION]... .SH DESCRIPTION -The ps_mem tool can determine how much RAM is used per program (not per process). +Display the core memory used per program (not per process) .br .PP In detail it reports: .br .PP .RS -sum(private RAM for program processes) + sum(Shared RAM for program processes). +sum (private RAM for program processes) + +.br +sum (shared RAM for program processes) .br .RE .PP @@ -24,11 +25,15 @@ The shared RAM is problematic to calculate, and the tool automatically selects t \-h \-\-help Show help message .TP -\-s \-\-show\-cmdline -Show complete program path with options +\-p PID[,PID2,...PIDN] +Show memory consumption for the specified processes +.TP +\-s \-\-split\-args +Show and separate memory usage entries by command line arguments +and not just the program name. .TP -\-p PID -Show memory consumption of process with specified PID +\-t \-\-total +Only display the total number of bytes for the selected processes .TP \-w N Report memory consumption every N seconds diff --git a/ps_mem.py b/ps_mem.py old mode 100644 new mode 100755 index 92be618..04d2a19 --- a/ps_mem.py +++ b/ps_mem.py @@ -36,7 +36,7 @@ # Patch from patrice.bouchand.fedora@gmail.com # V1.9 20 Feb 2008 Fix invalid values reported when PSS is available. # Reported by Andrey Borzenkov -# V3.1 10 May 2013 +# V3.5 29 Sep 2015 # http://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py # Notes: @@ -79,16 +79,6 @@ import errno 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): @@ -123,12 +113,16 @@ class Proc: 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): raise LookupError + raise proc = Proc() @@ -139,20 +133,27 @@ proc = Proc() def parse_options(): try: - long_options = ['split-args', 'help'] - opts, args = getopt.getopt(sys.argv[1:], "shp:w:", long_options) + long_options = ['split-args', 'help', 'total'] + opts, args = getopt.getopt(sys.argv[1:], "shtp:w:", long_options) except getopt.GetoptError: sys.stderr.write(help()) sys.exit(3) + if len(args): + sys.stderr.write("Extraneous arguments: %s\n" % args) + sys.exit(3) + # ps_mem.py options split_args = False pids_to_show = None watch = None + only_total = False for o, a in opts: if o in ('-s', '--split-args'): split_args = True + if o in ('-t', '--total'): + only_total = True if o in ('-h', '--help'): sys.stdout.write(help()) sys.exit(0) @@ -169,14 +170,17 @@ def parse_options(): sys.stderr.write(help()) sys.exit(3) - return (split_args, pids_to_show, watch) + return (split_args, pids_to_show, watch, only_total) def help(): - help_msg = 'ps_mem.py - Show process memory usage\n'\ - '\n'\ - '-h Show this help\n'\ - '-w Measure and show process memory every N seconds\n'\ - '-p [,pid2,...pidN] Only show memory usage PIDs in the specified list\n' + help_msg = 'Usage: ps_mem [OPTION]...\n' \ + 'Show program core memory usage\n' \ + '\n' \ + ' -h, -help Show this help\n' \ + ' -p [,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 Measure and show process memory every N seconds\n' return help_msg @@ -187,12 +191,14 @@ def kernel_ver(): if last == 2: kv.append('0') last -= 1 - for char in "-_": - kv[last] = kv[last].split(char)[0] - try: - int(kv[last]) - except: - kv[last] = 0 + while last > 0: + for char in "-_": + kv[last] = kv[last].split(char)[0] + try: + int(kv[last]) + except: + kv[last] = 0 + last -= 1 return (int(kv[0]), int(kv[1]), int(kv[2])) @@ -207,11 +213,11 @@ def getMemStats(pid): 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')) + 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"): @@ -219,7 +225,6 @@ def getMemStats(pid): 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 @@ -254,6 +259,7 @@ def getCmdName(pid, split_args): if (val.errno == errno.ENOENT or # either kernel thread or process gone val.errno == errno.EPERM): raise LookupError + raise if split_args: return " ".join(cmdline) @@ -277,17 +283,23 @@ def getCmdName(pid, split_args): #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 -def human(num, power="Ki"): - powers = ["Ki", "Mi", "Gi", "Ti"] - while num >= 1000: #4 digits - num /= 1024.0 - power = powers[powers.index(power)+1] - return "%.1f %s" % (num, power) +def human(num, power="Ki", units=None): + if units is None: + powers = ["Ki", "Mi", "Gi", "Ti"] + while num >= 1000: #4 digits + num /= 1024.0 + power = powers[powers.index(power)+1] + return "%.1f %sB" % (num, power) + else: + return "%.f" % ((num * 1024) / units) def cmd_with_count(cmd, count): @@ -304,12 +316,12 @@ def cmd_with_count(cmd, count): def shared_val_accuracy(): """http://wiki.apache.org/spamassassin/TopSharedMemoryBug""" kv = kernel_ver() + 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() if os.path.exists(proc.path(pid, 'smaps')): if proc.open(pid, 'smaps').read().find("Pss:")!=-1: return 2 @@ -318,32 +330,35 @@ def shared_val_accuracy(): 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 ): +def show_shared_val_accuracy( possible_inacc, only_total=False ): + level = ("Warning","Error")[only_total] if possible_inacc == -1: sys.stderr.write( - "Warning: Shared memory is not reported by this system.\n" + "%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" ) elif possible_inacc == 0: sys.stderr.write( - "Warning: Shared memory is not reported accurately by this system.\n" + "%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" ) elif possible_inacc == 1: sys.stderr.write( - "Warning: Shared memory is slightly over-estimated by this system\n" - "for each program, so totals are not reported.\n" + "%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 ): cmds = {} @@ -366,7 +381,7 @@ def get_memory_usage( pids_to_show, split_args, include_self=False, only_self=Fa try: cmd = getCmdName(pid, split_args) except LookupError: - #permission denied or + #operation not permitted #kernel threads don't have exe links or #process gone continue @@ -408,16 +423,16 @@ def get_memory_usage( pids_to_show, split_args, include_self=False, only_self=Fa return sorted_cmds, shareds, count, total def print_header(): - sys.stdout.write(" Private + Shared = RAM used\tProgram \n\n") + 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("%8sB + %8sB = %8sB\t%s\n" % + sys.stdout.write("%9s + %9s = %9s\t%s\n" % (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%8sB\n%s\n" % + sys.stdout.write("%s\n%s%9s\n%s\n" % ("-" * 33, " " * 24, human(total), "=" * 33)) def verify_environment(): @@ -440,17 +455,21 @@ def verify_environment(): raise if __name__ == '__main__': + split_args, pids_to_show, watch, only_total = parse_options() verify_environment() - split_args, pids_to_show, watch = parse_options() - print_header() + if not only_total: + print_header() if watch is not None: try: sorted_cmds = True while sorted_cmds: sorted_cmds, shareds, count, total = get_memory_usage( pids_to_show, split_args ) - print_memory_usage(sorted_cmds, shareds, count, total) + if only_total and have_pss: + sys.stdout.write(human(total, units=1)+'\n') + elif not only_total: + print_memory_usage(sorted_cmds, shareds, count, total) time.sleep(watch) else: sys.stdout.write('Process does not exist anymore.\n') @@ -459,8 +478,10 @@ if __name__ == '__main__': else: # This is the default behavior sorted_cmds, shareds, count, total = get_memory_usage( pids_to_show, split_args ) - print_memory_usage(sorted_cmds, shareds, count, total) - + if only_total and have_pss: + sys.stdout.write(human(total, units=1)+'\n') + elif not only_total: + print_memory_usage(sorted_cmds, shareds, count, total) # We must close explicitly, so that any EPIPE exception # is handled by our excepthook, rather than the default @@ -468,5 +489,4 @@ if __name__ == '__main__': sys.stdout.close() vm_accuracy = shared_val_accuracy() - show_shared_val_accuracy( vm_accuracy ) - + show_shared_val_accuracy( vm_accuracy, only_total ) diff --git a/ps_mem.spec b/ps_mem.spec index da45116..978490f 100644 --- a/ps_mem.spec +++ b/ps_mem.spec @@ -1,26 +1,23 @@ Name: ps_mem -Version: 3.1 -Release: 6%{?dist} +Version: 3.5 +Release: 1%{?dist} Summary: Memory profiling tool Group: Applications/System License: LGPLv2 URL: https://github.com/pixelb/ps_mem -Source0: https://raw.github.com/pixelb/scripts/961ff24c805a474080520403409872b04e18f4d9/scripts/ps_mem.py +Source0: https://raw.github.com/pixelb/ps_mem/7e295aec/ps_mem.py Source1: http://www.gnu.org/licenses/lgpl-2.1.txt Source2: ps_mem.1 -Patch0: ps_mem-ennobling-the-s-switch.patch - BuildArch: noarch -Requires: python3 -BuildRequires: python3-devel +Requires: python %description -The ps_mem tool can determine how much RAM is used per program +The ps_mem tool reports how much core memory is used per program (not per process). In detail it reports: sum(private RAM for program processes) + sum(Shared RAM for program processes) The shared RAM is problematic to calculate, and the tool automatically @@ -34,10 +31,9 @@ cp -p %{SOURCE0} %{name} cp -p %{SOURCE1} LICENSE cp -p %{SOURCE2} %{name}.1 -# force python3 -sed -i "s|/usr/bin/env python|%{__python3}|" %{name} - -%patch0 -p2 +# use system default python +sed -i "s|/usr/bin/env python|%{__python}|" %{name} +touch -r %{SOURCE0} %{name} %install @@ -52,6 +48,10 @@ install -Dpm644 %{name}.1 %{buildroot}%{_mandir}/man1/%{name}.1 %changelog +* Fri Oct 16 2015 Pádraig Brady - 3.5-1 +- Latest upstream +- Depend on default python implementation + * Thu Jun 18 2015 Fedora Release Engineering - 3.1-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild