diff --git a/smem b/smem index 0cbd925..7020a27 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): @@ -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 @@ -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) @@ -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,13 +301,13 @@ 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) 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, @@ -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) @@ -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) @@ -463,11 +463,44 @@ def showsystem(): showtable(range(len(l)), fields, columns.split(), options.sort or 'order') def showfields(fields, f): - if f != list: - print "unknown field", f - print "known fields:" - for l in sorted(fields.keys()): - print "%-8s %s" % (l, fields[l][-1]) + if type(f) in (list, set): + print("unknown fields: " + " ".join(f)) + else: + 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 = {} + 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 = "" @@ -486,11 +519,17 @@ 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) + if options.autosize: + colsizes = autosize(columns, fields, rows) + else: + colsizes = {} + + for n in columns: f = fields[n][2] if 'a' in f: if n == 'swap': @@ -500,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] + " " @@ -518,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 @@ -533,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: @@ -623,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") @@ -682,7 +725,8 @@ try: showsystem() else: showpids() -except IOError, e: +except IOError: + _, e, _ = sys.exc_info() if e.errno == errno.EPIPE: pass except KeyboardInterrupt: 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.