From 9c057328aeb634b70b20d5fe932d13a896528906 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 29 Oct 2012 14:59:55 -0500 Subject: [PATCH 02/17] update COPYING for FSF address change --- COPYING | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/COPYING b/COPYING index d60c31a..d159169 100644 --- a/COPYING +++ b/COPYING @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - Gnomovision version 69, Copyright (C) year name of author + Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. @@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names: This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General +library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. From e570a14243c36b31cfef8e3732f91e6b209a3a06 Mon Sep 17 00:00:00 2001 From: Jani Monoses Date: Thu, 8 Nov 2012 14:25:42 -0600 Subject: [PATCH 03/17] drop trailing slashes when looking up user/group in tar snapshots --- smem | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/smem b/smem index 506a394..5be289b 100755 --- a/smem +++ b/smem @@ -94,12 +94,12 @@ class tardata(procdata): def _readlines(self, f): return self.tar.extractfile(f).readlines() def piduser(self, p): - t = self.tar.getmember("%d/" % p) + t = self.tar.getmember("%d" % p) if t.uname: self._ucache[t.uid] = t.uname return t.uid def pidgroup(self, p): - t = self.tar.getmember("%d/" % p) + t = self.tar.getmember("%d" % p) if t.gname: self._gcache[t.gid] = t.gname return t.gid From 2346c2b07580b95d7d741ecf01c20cae2ebd59d2 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Fri, 22 Feb 2013 14:03:46 -0600 Subject: [PATCH 04/17] fix handling of new fields in smaps reported by Loic Minier --- smem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smem b/smem index 5be289b..7a3170d 100755 --- a/smem +++ b/smem @@ -149,7 +149,7 @@ def pidmaps(pid): if f[0].startswith('Pss'): seen = True maps[start][f[0][:-1].lower()] = int(f[1]) - else: + elif '-' in f[0] and ':' not in f[0]: # looks like a mapping range start, end = f[0].split('-') start = int(start, 16) name = "" From f8dee1586aa450b8df6f551ccc6d897700a1750c Mon Sep 17 00:00:00 2001 From: Lo?c Minier Date: Wed, 27 Mar 2013 20:01:07 -0700 Subject: [PATCH 05/17] avoid bogus warning on PSS measurement with empty smaps files --- smem | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/smem b/smem index 7a3170d..5b0ef8a 100755 --- a/smem +++ b/smem @@ -143,7 +143,9 @@ def pidmaps(pid): maps = {} start = None seen = False + empty = True for l in src.mapdata(pid): + empty = False f = l.split() if f[-1] == 'kB': if f[0].startswith('Pss'): @@ -159,7 +161,7 @@ def pidmaps(pid): offset=int(f[2], 16), device=f[3], inode=f[4], name=name) - if not seen and not warned: + if not empty and not seen and not warned: sys.stderr.write('warning: kernel does not appear to support PSS measurement\n') warned = True if not options.sort: From 9e788b26c663b631949af7970162b0fb835eaf80 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Mon, 22 Apr 2013 17:21:03 -0500 Subject: [PATCH 07/17] drop unused import of grp --- smem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smem b/smem index 5b0ef8a..2d9a9c0 100755 --- a/smem +++ b/smem @@ -8,7 +8,7 @@ # the GNU General Public License version 2 or later, incorporated # herein by reference. -import re, os, sys, pwd, grp, optparse, errno, tarfile +import re, os, sys, pwd, optparse, errno, tarfile warned = False From 02bda05e5b2dcea76faa9c46dbfa7747a6b3a4ba Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Wed, 8 May 2013 14:21:28 -0500 Subject: [PATCH 08/17] handle division by zero with no swap Reported by Stefan Praszalowicz --- smem | 2 ++ 1 file changed, 2 insertions(+) diff --git a/smem b/smem index 2d9a9c0..0cbd925 100755 --- a/smem +++ b/smem @@ -222,6 +222,8 @@ def showamount(a, total): if options.abbreviate: return units(a * 1024) elif options.percent: + if total == 0: + return 'N/A' return "%.2f%%" % (100.0 * a / total) return a From 834dc815c8f3e446cdb70321d5072bb7ead50125 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Thu, 22 May 2014 17:04:26 -0500 Subject: [PATCH 10/17] switch file() to open() --- smem | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smem b/smem index 0cbd925..0222631 100755 --- a/smem +++ b/smem @@ -21,7 +21,7 @@ class procdata(object): def _list(self): return os.listdir(self.source + "/proc") def _read(self, f): - return file(self.source + '/proc/' + f).read() + return open(self.source + '/proc/' + f).read() def _readlines(self, f): return self._read(f).splitlines(True) def _stat(self, f): From 02dabc0b86da32dc0107168cfbe5517a9f75b700 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Tue, 15 Jul 2014 01:33:26 -0500 Subject: [PATCH 11/17] rename filter to filters to make 2to3 happy --- smem | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/smem b/smem index 0222631..de221df 100755 --- a/smem +++ b/smem @@ -170,7 +170,7 @@ def pidmaps(pid): if options.mapfilter: f = {} for m in maps: - if not filter(options.mapfilter, m, lambda x: maps[x]['name']): + if not filters(options.mapfilter, m, lambda x: maps[x]['name']): f[m] = maps[m] return f @@ -227,7 +227,7 @@ def showamount(a, total): return "%.2f%%" % (100.0 * a / total) return a -def filter(opt, arg, *sources): +def filters(opt, arg, *sources): if not opt: return False @@ -252,8 +252,8 @@ def pidtotals(pid): def processtotals(pids): totals = {} for pid in pids: - if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or - filter(options.userfilter, pid, pidusername)): + if (filters(options.processfilter, pid, src.pidname, src.pidcmd) or + filters(options.userfilter, pid, pidusername)): continue try: p = pidtotals(pid) @@ -301,8 +301,8 @@ def showpids(): def maptotals(pids): totals = {} for pid in pids: - if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or - filter(options.userfilter, pid, pidusername)): + if (filters(options.processfilter, pid, src.pidname, src.pidcmd) or + filters(options.userfilter, pid, pidusername)): continue try: maps = pidmaps(pid) @@ -366,8 +366,8 @@ def showmaps(): def usertotals(pids): totals = {} for pid in pids: - if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or - filter(options.userfilter, pid, pidusername)): + if (filters(options.processfilter, pid, src.pidname, src.pidcmd) or + filters(options.userfilter, pid, pidusername)): continue try: maps = pidmaps(pid) From 29fc357a3174511828e6b97110b3ced2d16d9d72 Mon Sep 17 00:00:00 2001 From: Cybjit Date: Tue, 18 Nov 2014 16:26:12 -0600 Subject: [PATCH 12/17] showfields: complain about sets --- smem | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/smem b/smem index de221df..c692f73 100755 --- a/smem +++ b/smem @@ -463,7 +463,9 @@ def showsystem(): showtable(range(len(l)), fields, columns.split(), options.sort or 'order') def showfields(fields, f): - if f != list: + if type(f) in (list, set): + print "unknown fields:", " ".join(f) + else: print "unknown field", f print "known fields:" for l in sorted(fields.keys()): @@ -486,11 +488,12 @@ def showtable(rows, fields, columns, sort): mt = totalmem() st = memory()['swaptotal'] - for n in columns: - if n not in fields: - showfields(fields, n) - sys.exit(-1) + missing = set(columns) - set(fields) + if len(missing) > 0: + showfields(fields, missing) + sys.exit(-1) + for n in columns: f = fields[n][2] if 'a' in f: if n == 'swap': From 272cb17cf9d37f4441e74ddfa36d1250c1d5a625 Mon Sep 17 00:00:00 2001 From: Cybjit Date: Tue, 18 Nov 2014 20:01:16 -0600 Subject: [PATCH 13/17] smem: allow column auto-sizing --- smem | 40 ++++++++++++++++++++++++++++++++++++++++ smem.8 | 4 ++++ 2 files changed, 44 insertions(+) diff --git a/smem b/smem index c692f73..2404835 100755 --- a/smem +++ b/smem @@ -471,6 +471,37 @@ def showfields(fields, f): for l in sorted(fields.keys()): print "%-8s %s" % (l, fields[l][-1]) +def autosize(columns, fields, rows): + colsizes = {} + for c in columns: + sizes = [1] + + if not options.no_header: + sizes.append(len(fields[c][0])) + + if (options.abbreviate or options.percent) and 'a' in fields[c][2]: + sizes.append(7) + else: + for r in rows: + sizes.append(len(str(fields[c][1](r)))) + + colsizes[c] = max(sizes) + + overflowcols = set(["command", "map"]) & set(columns) + if len(overflowcols) > 0: + overflowcol = overflowcols.pop() + totnoflow = sum(colsizes.values()) - colsizes[overflowcol] + try: + ttyrows, ttycolumns = os.popen('stty size', 'r').read().split() + ttyrows, ttycolumns = int(ttyrows), int(ttycolumns) + except: + ttyrows, ttycolumns = (24, 80) + maxflowcol = ttycolumns - totnoflow - len(columns) + maxflowcol = max(maxflowcol, 10) + colsizes[overflowcol] = min(colsizes[overflowcol], maxflowcol) + + return colsizes + def showtable(rows, fields, columns, sort): header = "" format = "" @@ -493,6 +524,11 @@ def showtable(rows, fields, columns, sort): showfields(fields, missing) sys.exit(-1) + if options.autosize: + colsizes = autosize(columns, fields, rows) + else: + colsizes = {} + for n in columns: f = fields[n][2] if 'a' in f: @@ -503,6 +539,8 @@ def showtable(rows, fields, columns, sort): f = f.replace('a', 's') else: formatter.append(lambda x: x) + if n in colsizes: + f = re.sub(r"[0-9]+", str(colsizes[n]), f) format += f + " " header += f % fields[n][0] + " " @@ -626,6 +664,8 @@ parser.add_option("-c", "--columns", type="str", help="columns to show") parser.add_option("-t", "--totals", action="store_true", help="show totals") +parser.add_option("-a", "--autosize", action="store_true", + help="size columns to fit terminal size") parser.add_option("-R", "--realmem", type="str", help="amount of physical RAM") diff --git a/smem.8 b/smem.8 index 6184a16..b71bd32 100644 --- a/smem.8 +++ b/smem.8 @@ -95,6 +95,10 @@ User filter regular expression. .SS OUTPUT FORMATTING +.TP +.B \-a, \-\-autosize +Size columns to fit terminal size. + .TP .BI "\-c " COLUMNS ", \-\-columns=" COLUMNS Columns to show. From afc19f79b684dc5541aa5a3cb0224ea8ef2a8cd0 Mon Sep 17 00:00:00 2001 From: Oren Tirosh Date: Fri, 15 May 2015 12:49:06 -0500 Subject: [PATCH 14/17] py3: stop using iterkeys() --- smem | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/smem b/smem index 2404835..b583835 100755 --- a/smem +++ b/smem @@ -240,7 +240,7 @@ def pidtotals(pid): maps = pidmaps(pid) t = dict(size=0, rss=0, pss=0, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=0, referenced=0, swap=0) - for m in maps.iterkeys(): + for m in maps: for k in t: t[k] += maps[m].get(k, 0) @@ -307,7 +307,7 @@ def maptotals(pids): try: maps = pidmaps(pid) seen = {} - for m in maps.iterkeys(): + for m in maps: name = maps[m]['name'] if name not in totals: t = dict(size=0, rss=0, pss=0, shared_clean=0, @@ -383,7 +383,7 @@ def usertotals(pids): else: t = totals[user] - for m in maps.iterkeys(): + for m in maps: for k in t: t[k] += maps[m].get(k, 0) From 0deddadf8807121e6a66dc6c0802b59ef8d81c01 Mon Sep 17 00:00:00 2001 From: Oren Tirosh Date: Fri, 15 May 2015 12:50:59 -0500 Subject: [PATCH 15/17] py3: add () to print statements It's a function call in 3.x and redundant parentheses around an expression on 2.x. This works fine as long as all prints have just a single argument. One print statement with two arguments was changed to use % formatting instead. --- smem | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/smem b/smem index b583835..9157ce0 100755 --- a/smem +++ b/smem @@ -464,12 +464,12 @@ def showsystem(): def showfields(fields, f): if type(f) in (list, set): - print "unknown fields:", " ".join(f) + print("unknown fields: " + " ".join(f)) else: - print "unknown field", f - print "known fields:" - for l in sorted(fields.keys()): - print "%-8s %s" % (l, fields[l][-1]) + print("unknown field %s" % f) + print("known fields:") + for l in sorted(fields): + print("%-8s %s" % (l, fields[l][-1])) def autosize(columns, fields, rows): colsizes = {} @@ -559,10 +559,10 @@ def showtable(rows, fields, columns, sort): return if not options.no_header: - print header + print(header) for k,r in l: - print format % tuple([f(v) for f,v in zip(formatter, r)]) + print(format % tuple([f(v) for f,v in zip(formatter, r)])) if options.totals: # totals @@ -574,8 +574,8 @@ def showtable(rows, fields, columns, sort): else: t.append("") - print "-" * len(header) - print format % tuple([f(v) for f,v in zip(formatter, t)]) + print("-" * len(header)) + print(format % tuple([f(v) for f,v in zip(formatter, t)])) def showpie(l, sort): try: From 8f2294477c1b3c62ec7e7384147c487d71a7ba81 Mon Sep 17 00:00:00 2001 From: Oren Tirosh Date: Fri, 15 May 2015 12:52:02 -0500 Subject: [PATCH 16/17] py3: do not use "except Exception, e:" syntax If catching the exception is done with "except Exception as e:" this will work only from 2.6. To maintain backward compatibility with 2.4 I have used sys.exc_info(). A bit of a wart, but it works. --- smem | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/smem b/smem index 9157ce0..7020a27 100755 --- a/smem +++ b/smem @@ -725,7 +725,8 @@ try: showsystem() else: showpids() -except IOError, e: +except IOError: + _, e, _ = sys.exc_info() if e.errno == errno.EPIPE: pass except KeyboardInterrupt: