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
This commit is contained in:
Pádraig Brady 2015-10-16 10:51:30 +01:00
parent 2188cd120c
commit 5319c0d347
4 changed files with 104 additions and 128 deletions

View File

@ -1,49 +0,0 @@
From 0736aab9093ae3043f8e2b11ecc23924ac2b7e01 Mon Sep 17 00:00:00 2001
From: Jaromir Capik <jcapik@redhat.com>
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 <N> Measure and show process memory every N seconds\n'\
- '-p <pid>[,pid2,...pidN] Only show memory usage PIDs in the specified list\n'
+ '-p <pid>[,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

View File

@ -1,20 +1,21 @@
.\" Simple man page to ps_mem.py script .\" Simple man page to ps_mem script
.\" Contact fholec@redhat.com .\" Contact fholec@redhat.com
.TH ps_mem 1 "31 July 2013" "" "" .TH ps_mem 1 "04 October 2014" "" ""
.SH NAME .SH NAME
ps_mem \- Memory profiling tool ps_mem \- Memory profiling tool
.SH SYNOPSIS .SH SYNOPSIS
.B ps_mem .B ps_mem [OPTION]...
[\-h|\-\-help] [\-s|\-\-show\-cmdline] [\-p PID] [\-w N]
.SH DESCRIPTION .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 .br
.PP .PP
In detail it reports: In detail it reports:
.br .br
.PP .PP
.RS .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 .br
.RE .RE
.PP .PP
@ -24,11 +25,15 @@ The shared RAM is problematic to calculate, and the tool automatically selects t
\-h \-\-help \-h \-\-help
Show help message Show help message
.TP .TP
\-s \-\-show\-cmdline \-p PID[,PID2,...PIDN]
Show complete program path with options Show memory consumption for the specified processes
.TP .TP
\-p PID \-s \-\-split\-args
Show memory consumption of process with specified PID Show and separate memory usage entries by command line arguments
and not just the program name.
.TP
\-t \-\-total
Only display the total number of bytes for the selected processes
.TP .TP
\-w N \-w N
Report memory consumption every N seconds Report memory consumption every N seconds

96
ps_mem.py Normal file → Executable file
View File

@ -36,7 +36,7 @@
# Patch from patrice.bouchand.fedora@gmail.com # Patch from patrice.bouchand.fedora@gmail.com
# V1.9 20 Feb 2008 Fix invalid values reported when PSS is available. # V1.9 20 Feb 2008 Fix invalid values reported when PSS is available.
# Reported by Andrey Borzenkov <arvidjaar@mail.ru> # Reported by Andrey Borzenkov <arvidjaar@mail.ru>
# V3.1 10 May 2013 # V3.5 29 Sep 2015
# http://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py # http://github.com/pixelb/scripts/commits/master/scripts/ps_mem.py
# Notes: # Notes:
@ -79,16 +79,6 @@ import errno
import os import os
import sys 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 # The following exits cleanly on Ctrl-C or EPIPE
# while treating other exceptions as before. # while treating other exceptions as before.
def std_exceptions(etype, value, tb): def std_exceptions(etype, value, tb):
@ -123,12 +113,16 @@ class Proc:
def open(self, *args): def open(self, *args):
try: try:
if sys.version_info < (3,):
return open(self.path(*args)) return open(self.path(*args))
else:
return open(self.path(*args), errors='ignore')
except (IOError, OSError): except (IOError, OSError):
val = sys.exc_info()[1] val = sys.exc_info()[1]
if (val.errno == errno.ENOENT or # kernel thread or process gone if (val.errno == errno.ENOENT or # kernel thread or process gone
val.errno == errno.EPERM): val.errno == errno.EPERM):
raise LookupError raise LookupError
raise
proc = Proc() proc = Proc()
@ -139,20 +133,27 @@ proc = Proc()
def parse_options(): def parse_options():
try: try:
long_options = ['split-args', 'help'] long_options = ['split-args', 'help', 'total']
opts, args = getopt.getopt(sys.argv[1:], "shp:w:", long_options) opts, args = getopt.getopt(sys.argv[1:], "shtp:w:", long_options)
except getopt.GetoptError: except getopt.GetoptError:
sys.stderr.write(help()) sys.stderr.write(help())
sys.exit(3) sys.exit(3)
if len(args):
sys.stderr.write("Extraneous arguments: %s\n" % args)
sys.exit(3)
# ps_mem.py options # ps_mem.py options
split_args = False split_args = False
pids_to_show = None pids_to_show = None
watch = None watch = None
only_total = False
for o, a in opts: for o, a in opts:
if o in ('-s', '--split-args'): if o in ('-s', '--split-args'):
split_args = True split_args = True
if o in ('-t', '--total'):
only_total = True
if o in ('-h', '--help'): if o in ('-h', '--help'):
sys.stdout.write(help()) sys.stdout.write(help())
sys.exit(0) sys.exit(0)
@ -169,14 +170,17 @@ def parse_options():
sys.stderr.write(help()) sys.stderr.write(help())
sys.exit(3) sys.exit(3)
return (split_args, pids_to_show, watch) return (split_args, pids_to_show, watch, only_total)
def help(): def help():
help_msg = 'ps_mem.py - Show process memory usage\n'\ help_msg = 'Usage: ps_mem [OPTION]...\n' \
'Show program core memory usage\n' \
'\n' \ '\n' \
'-h Show this help\n'\ ' -h, -help Show this help\n' \
'-w <N> Measure and show process memory every N seconds\n'\ ' -p <pid>[,pid2,...pidN] Only show memory usage PIDs in the specified list\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 return help_msg
@ -187,12 +191,14 @@ def kernel_ver():
if last == 2: if last == 2:
kv.append('0') kv.append('0')
last -= 1 last -= 1
while last > 0:
for char in "-_": for char in "-_":
kv[last] = kv[last].split(char)[0] kv[last] = kv[last].split(char)[0]
try: try:
int(kv[last]) int(kv[last])
except: except:
kv[last] = 0 kv[last] = 0
last -= 1
return (int(kv[0]), int(kv[1]), int(kv[2])) 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]) Rss = (int(proc.open(pid, 'statm').readline().split()[1])
* PAGESIZE) * PAGESIZE)
if os.path.exists(proc.path(pid, 'smaps')): #stat if os.path.exists(proc.path(pid, 'smaps')): #stat
digester = md5_new() lines = proc.open(pid, 'smaps').readlines() #open
for line in proc.open(pid, 'smaps').readlines(): #open
# Note we checksum smaps as maps is usually but # Note we checksum smaps as maps is usually but
# not always different for separate processes. # not always different for separate processes.
digester.update(line.encode('latin1')) mem_id = hash(''.join(lines))
for line in lines:
if line.startswith("Shared"): if line.startswith("Shared"):
Shared_lines.append(line) Shared_lines.append(line)
elif line.startswith("Private"): elif line.startswith("Private"):
@ -219,7 +225,6 @@ def getMemStats(pid):
elif line.startswith("Pss"): elif line.startswith("Pss"):
have_pss = 1 have_pss = 1
Pss_lines.append(line) Pss_lines.append(line)
mem_id = digester.hexdigest()
Shared = sum([int(line.split()[1]) for line in Shared_lines]) Shared = sum([int(line.split()[1]) for line in Shared_lines])
Private = sum([int(line.split()[1]) for line in Private_lines]) Private = sum([int(line.split()[1]) for line in Private_lines])
#Note Shared + Private = Rss above #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 if (val.errno == errno.ENOENT or # either kernel thread or process gone
val.errno == errno.EPERM): val.errno == errno.EPERM):
raise LookupError raise LookupError
raise
if split_args: if split_args:
return " ".join(cmdline) return " ".join(cmdline)
@ -277,17 +283,23 @@ def getCmdName(pid, split_args):
#one can have separated programs as follows: #one can have separated programs as follows:
#584.0 KiB + 1.0 MiB = 1.6 MiB mozilla-thunder (exe -> bash) #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 # 56.0 MiB + 22.2 MiB = 78.2 MiB mozilla-thunderbird-bin
if sys.version_info < (3,):
return cmd return cmd
else:
return cmd.encode(errors='replace').decode()
#The following matches "du -h" output #The following matches "du -h" output
#see also human.py #see also human.py
def human(num, power="Ki"): def human(num, power="Ki", units=None):
if units is None:
powers = ["Ki", "Mi", "Gi", "Ti"] powers = ["Ki", "Mi", "Gi", "Ti"]
while num >= 1000: #4 digits while num >= 1000: #4 digits
num /= 1024.0 num /= 1024.0
power = powers[powers.index(power)+1] power = powers[powers.index(power)+1]
return "%.1f %s" % (num, power) return "%.1f %sB" % (num, power)
else:
return "%.f" % ((num * 1024) / units)
def cmd_with_count(cmd, count): def cmd_with_count(cmd, count):
@ -304,12 +316,12 @@ def cmd_with_count(cmd, count):
def shared_val_accuracy(): def shared_val_accuracy():
"""http://wiki.apache.org/spamassassin/TopSharedMemoryBug""" """http://wiki.apache.org/spamassassin/TopSharedMemoryBug"""
kv = kernel_ver() kv = kernel_ver()
pid = os.getpid()
if kv[:2] == (2,4): if kv[:2] == (2,4):
if proc.open('meminfo').read().find("Inact_") == -1: if proc.open('meminfo').read().find("Inact_") == -1:
return 1 return 1
return 0 return 0
elif kv[:2] == (2,6): elif kv[:2] == (2,6):
pid = os.getpid()
if os.path.exists(proc.path(pid, 'smaps')): 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 return 2
@ -318,32 +330,35 @@ def shared_val_accuracy():
if (2,6,1) <= kv <= (2,6,9): if (2,6,1) <= kv <= (2,6,9):
return -1 return -1
return 0 return 0
elif kv[0] > 2: elif kv[0] > 2 and os.path.exists(proc.path(pid, 'smaps')):
return 2 return 2
else: else:
return 1 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: if possible_inacc == -1:
sys.stderr.write( 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( 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: elif possible_inacc == 0:
sys.stderr.write( 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( 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: elif possible_inacc == 1:
sys.stderr.write( sys.stderr.write(
"Warning: Shared memory is slightly over-estimated by this system\n" "%s: Shared memory is slightly over-estimated by this system\n"
"for each program, so totals are not reported.\n" "for each program, so totals are not reported.\n" % level
) )
sys.stderr.close() 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 = {} cmds = {}
@ -366,7 +381,7 @@ def get_memory_usage( pids_to_show, split_args, include_self=False, only_self=Fa
try: try:
cmd = getCmdName(pid, split_args) cmd = getCmdName(pid, split_args)
except LookupError: except LookupError:
#permission denied or #operation not permitted
#kernel threads don't have exe links or #kernel threads don't have exe links or
#process gone #process gone
continue continue
@ -412,12 +427,12 @@ def print_header():
def print_memory_usage(sorted_cmds, shareds, count, total): def print_memory_usage(sorted_cmds, shareds, count, total):
for cmd in sorted_cmds: 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(cmd[1]-shareds[cmd[0]]),
human(shareds[cmd[0]]), human(cmd[1]), human(shareds[cmd[0]]), human(cmd[1]),
cmd_with_count(cmd[0], count[cmd[0]]))) cmd_with_count(cmd[0], count[cmd[0]])))
if have_pss: 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)) ("-" * 33, " " * 24, human(total), "=" * 33))
def verify_environment(): def verify_environment():
@ -440,9 +455,10 @@ def verify_environment():
raise raise
if __name__ == '__main__': if __name__ == '__main__':
split_args, pids_to_show, watch, only_total = parse_options()
verify_environment() verify_environment()
split_args, pids_to_show, watch = parse_options()
if not only_total:
print_header() print_header()
if watch is not None: if watch is not None:
@ -450,6 +466,9 @@ if __name__ == '__main__':
sorted_cmds = True sorted_cmds = True
while sorted_cmds: 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')
elif not only_total:
print_memory_usage(sorted_cmds, shareds, count, total) print_memory_usage(sorted_cmds, shareds, count, total)
time.sleep(watch) time.sleep(watch)
else: else:
@ -459,14 +478,15 @@ if __name__ == '__main__':
else: else:
# This is the default behavior # 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')
elif not only_total:
print_memory_usage(sorted_cmds, shareds, count, total) print_memory_usage(sorted_cmds, shareds, count, total)
# We must close explicitly, so that any EPIPE exception # We must close explicitly, so that any EPIPE exception
# is handled by our excepthook, rather than the default # is handled by our excepthook, rather than the default
# one which is reenabled after this script finishes. # one which is reenabled after this script finishes.
sys.stdout.close() sys.stdout.close()
vm_accuracy = shared_val_accuracy() vm_accuracy = shared_val_accuracy()
show_shared_val_accuracy( vm_accuracy ) show_shared_val_accuracy( vm_accuracy, only_total )

View File

@ -1,26 +1,23 @@
Name: ps_mem Name: ps_mem
Version: 3.1 Version: 3.5
Release: 6%{?dist} Release: 1%{?dist}
Summary: Memory profiling tool Summary: Memory profiling tool
Group: Applications/System Group: Applications/System
License: LGPLv2 License: LGPLv2
URL: https://github.com/pixelb/ps_mem 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 Source1: http://www.gnu.org/licenses/lgpl-2.1.txt
Source2: ps_mem.1 Source2: ps_mem.1
Patch0: ps_mem-ennobling-the-s-switch.patch
BuildArch: noarch BuildArch: noarch
Requires: python3 Requires: python
BuildRequires: python3-devel
%description %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: (not per process). In detail it reports:
sum(private RAM for program processes) + sum(Shared RAM for program processes) sum(private RAM for program processes) + sum(Shared RAM for program processes)
The shared RAM is problematic to calculate, and the tool automatically 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 %{SOURCE1} LICENSE
cp -p %{SOURCE2} %{name}.1 cp -p %{SOURCE2} %{name}.1
# force python3 # use system default python
sed -i "s|/usr/bin/env python|%{__python3}|" %{name} sed -i "s|/usr/bin/env python|%{__python}|" %{name}
touch -r %{SOURCE0} %{name}
%patch0 -p2
%install %install
@ -52,6 +48,10 @@ install -Dpm644 %{name}.1 %{buildroot}%{_mandir}/man1/%{name}.1
%changelog %changelog
* Fri Oct 16 2015 Pádraig Brady <pbrady@redhat.com> - 3.5-1
- Latest upstream
- Depend on default python implementation
* Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.1-6 * Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.1-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild