~vila/ubuntu-test-cases/retry-apt-get-update

« back to all changes in this revision

Viewing changes to tests/smem/smem/smem-tabs

  • Committer: Leo Arias
  • Date: 2014-11-10 19:28:56 UTC
  • mfrom: (345 touch)
  • mto: This revision was merged to the branch mainline in revision 352.
  • Revision ID: leo.arias@canonical.com-20141110192856-rgpksx9n9j0b39yl
Merged with the touch branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python3
 
2
#
 
3
# smem - a tool for meaningful memory reporting
 
4
#
 
5
# Copyright 2008-2009 Matt Mackall <mpm@selenic.com>
 
6
#
 
7
# This software may be used and distributed according to the terms of
 
8
# the GNU General Public License version 2 or later, incorporated
 
9
# herein by reference.
 
10
 
 
11
import re, os, sys, pwd, optparse, errno, tarfile
 
12
 
 
13
warned = False
 
14
 
 
15
class procdata(object):
 
16
    def __init__(self, source):
 
17
        self._ucache = {}
 
18
        self._gcache = {}
 
19
        self.source = source and source or ""
 
20
        self._memdata = None
 
21
    def _list(self):
 
22
        return os.listdir(self.source + "/proc")
 
23
    def _read(self, f):
 
24
        return open(self.source + '/proc/' + f).read()
 
25
    def _readlines(self, f):
 
26
        return self._read(f).splitlines(True)
 
27
    def _stat(self, f):
 
28
        return os.stat(self.source + "/proc/" + f)
 
29
 
 
30
    def pids(self):
 
31
        '''get a list of processes'''
 
32
        return [int(e) for e in self._list()
 
33
                if e.isdigit() and not iskernel(e)]
 
34
    def mapdata(self, pid):
 
35
        return self._readlines('%s/smaps' % pid)
 
36
    def memdata(self):
 
37
        if self._memdata is None:
 
38
            self._memdata = self._readlines('meminfo')
 
39
        return self._memdata
 
40
    def version(self):
 
41
        return self._readlines('version')[0]
 
42
    def pidname(self, pid):
 
43
        try:
 
44
            l = self.pidcmd(pid).split(' ')[0]
 
45
            return os.path.basename(l)
 
46
        except:
 
47
            return '?'
 
48
    def pidcmd(self, pid):
 
49
        try:
 
50
            c = self._read('%s/cmdline' % pid)[:-1]
 
51
            return c.replace('\0', ' ')
 
52
        except:
 
53
            return '?'
 
54
    def piduser(self, pid):
 
55
        try:
 
56
            return self._stat('%d' % pid).st_uid
 
57
        except:
 
58
            return -1
 
59
    def pidgroup(self, pid):
 
60
        try:
 
61
            return self._stat('%d' % pid).st_gid
 
62
        except:
 
63
            return -1
 
64
    def username(self, uid):
 
65
        if uid == -1:
 
66
            return '?'
 
67
        if uid not in self._ucache:
 
68
            try:
 
69
                self._ucache[uid] = pwd.getpwuid(uid)[0]
 
70
            except KeyError:
 
71
                self._ucache[uid] = str(uid)
 
72
        return self._ucache[uid]
 
73
    def groupname(self, gid):
 
74
        if gid == -1:
 
75
            return '?'
 
76
        if gid not in self._gcache:
 
77
            try:
 
78
                self._gcache[gid] = pwd.getgrgid(gid)[0]
 
79
            except KeyError:
 
80
                self._gcache[gid] = str(gid)
 
81
        return self._gcache[gid]
 
82
 
 
83
class tardata(procdata):
 
84
    def __init__(self, source):
 
85
        procdata.__init__(self, source)
 
86
        self.tar = tarfile.open(source)
 
87
    def _list(self):
 
88
        for ti in self.tar:
 
89
            if ti.name.endswith('/smaps'):
 
90
                d,f = ti.name.split('/')
 
91
                yield d
 
92
    def _read(self, f):
 
93
        return self.tar.extractfile(f).read()
 
94
    def _readlines(self, f):
 
95
        return self.tar.extractfile(f).readlines()
 
96
    def piduser(self, p):
 
97
        t = self.tar.getmember("%d" % p)
 
98
        if t.uname:
 
99
            self._ucache[t.uid] = t.uname
 
100
        return t.uid
 
101
    def pidgroup(self, p):
 
102
        t = self.tar.getmember("%d" % p)
 
103
        if t.gname:
 
104
            self._gcache[t.gid] = t.gname
 
105
        return t.gid
 
106
    def username(self, u):
 
107
        return self._ucache.get(u, str(u))
 
108
    def groupname(self, g):
 
109
        return self._gcache.get(g, str(g))
 
110
 
 
111
_totalmem = 0
 
112
def totalmem():
 
113
    global _totalmem
 
114
    if not _totalmem:
 
115
        if options.realmem:
 
116
            _totalmem = fromunits(options.realmem) / 1024
 
117
        else:
 
118
            _totalmem = memory()['memtotal']
 
119
    return _totalmem
 
120
 
 
121
_kernelsize = 0
 
122
def kernelsize():
 
123
    global _kernelsize
 
124
    if not _kernelsize and options.kernel:
 
125
        try:
 
126
            d = os.popen("size %s" % options.kernel).readlines()[1]
 
127
            _kernelsize = int(d.split()[3]) / 1024
 
128
        except:
 
129
            try:
 
130
                # try some heuristic to find gzipped part in kernel image
 
131
                packedkernel = open(options.kernel).read()
 
132
                pos = packedkernel.find('\x1F\x8B')
 
133
                if pos >= 0 and pos < 25000:
 
134
                    sys.stderr.write("Maybe uncompressed kernel can be extracted by the command:\n"
 
135
                            "  dd if=%s bs=1 skip=%d | gzip -d >%s.unpacked\n\n" % (options.kernel, pos, options.kernel))
 
136
            except:
 
137
                pass
 
138
            sys.stderr.write("Parameter '%s' should be an original uncompressed compiled kernel file.\n\n" % options.kernel)
 
139
    return _kernelsize
 
140
 
 
141
def pidmaps(pid):
 
142
    global warned
 
143
    maps = {}
 
144
    start = None
 
145
    seen = False
 
146
    for l in src.mapdata(pid):
 
147
        f = l.split()
 
148
        if f[-1] == 'kB':
 
149
            if f[0].startswith('Pss'):
 
150
                seen = True
 
151
            maps[start][f[0][:-1].lower()] = int(f[1])
 
152
        elif f[0] == 'VmFlags:':
 
153
            continue
 
154
        else:
 
155
            start, end = f[0].split('-')
 
156
            start = int(start, 16)
 
157
            name = "<anonymous>"
 
158
            if len(f) > 5:
 
159
                name = f[5]
 
160
            maps[start] = dict(end=int(end, 16), mode=f[1],
 
161
                               offset=int(f[2], 16),
 
162
                               device=f[3], inode=f[4], name=name)
 
163
 
 
164
    if not seen and not warned:
 
165
        sys.stderr.write('warning: kernel does not appear to support PSS measurement\n')
 
166
        warned = True
 
167
        if not options.sort:
 
168
            options.sort = 'rss'
 
169
 
 
170
    if options.mapfilter:
 
171
        f = {}
 
172
        for m in maps:
 
173
            if not list(filter(options.mapfilter, m, lambda x: maps[x]['name'])):
 
174
                f[m] = maps[m]
 
175
        return f
 
176
 
 
177
    return maps
 
178
 
 
179
def sortmaps(totals, key):
 
180
    l = []
 
181
    for pid in totals:
 
182
        l.append((totals[pid][key], pid))
 
183
    l.sort()
 
184
    return [pid for pid,key in l]
 
185
 
 
186
def iskernel(pid):
 
187
    return src.pidcmd(pid) == ""
 
188
 
 
189
def memory():
 
190
    t = {}
 
191
    f = re.compile('(\\S+):\\s+(\\d+) kB')
 
192
    for l in src.memdata():
 
193
        m = f.match(l)
 
194
        if m:
 
195
            t[m.group(1).lower()] = int(m.group(2))
 
196
    return t
 
197
 
 
198
def units(x):
 
199
    s = ''
 
200
    if x == 0:
 
201
        return '0'
 
202
    for s in ('', 'K', 'M', 'G', 'T'):
 
203
        if x < 1024:
 
204
            break
 
205
        x /= 1024.0
 
206
    return "%.1f%s" % (x, s)
 
207
 
 
208
def fromunits(x):
 
209
    s = dict(k=2**10, K=2**10, kB=2**10, KB=2**10,
 
210
             M=2**20, MB=2**20, G=2**30, GB=2**30,
 
211
             T=2**40, TB=2**40)
 
212
    for k,v in list(s.items()):
 
213
        if x.endswith(k):
 
214
            return int(float(x[:-len(k)])*v)
 
215
    sys.stderr.write("Memory size should be written with units, for example 1024M\n")
 
216
    sys.exit(-1)
 
217
 
 
218
def pidusername(pid):
 
219
    return src.username(src.piduser(pid))
 
220
 
 
221
def showamount(a, total):
 
222
    if options.abbreviate:
 
223
        return units(a * 1024)
 
224
    elif options.percent:
 
225
        return "%.2f%%" % (100.0 * a / total)
 
226
    return a
 
227
 
 
228
def filter(opt, arg, *sources):
 
229
    if not opt:
 
230
        return False
 
231
 
 
232
    for f in sources:
 
233
        if re.search(opt, f(arg)):
 
234
            return False
 
235
    return True
 
236
 
 
237
def pidtotals(pid):
 
238
    maps = pidmaps(pid)
 
239
    t = dict(size=0, rss=0, pss=0, shared_clean=0, shared_dirty=0,
 
240
             private_clean=0, private_dirty=0, referenced=0, swap=0)
 
241
    for m in maps.keys():
 
242
        for k in t:
 
243
            t[k] += maps[m].get(k, 0)
 
244
 
 
245
    t['uss'] = t['private_clean'] + t['private_dirty']
 
246
    t['maps'] = len(maps)
 
247
 
 
248
    return t
 
249
 
 
250
def processtotals(pids):
 
251
    totals = {}
 
252
    for pid in pids:
 
253
        if (filter(options.processfilter, pid, src.pidname, src.pidcmd) or
 
254
            filter(options.userfilter, pid, pidusername)):
 
255
            continue
 
256
        try:
 
257
            p = pidtotals(pid)
 
258
            if p['maps'] != 0:
 
259
                totals[pid] = p
 
260
        except:
 
261
            continue
 
262
    return totals
 
263
 
 
264
def showpids():
 
265
    p = src.pids()
 
266
    pt = processtotals(p)
 
267
 
 
268
    def showuser(p):
 
269
        if options.numeric:
 
270
            return src.piduser(p)
 
271
        return pidusername(p)
 
272
 
 
273
    fields = dict(
 
274
        pid=('PID', lambda n: n, '% 5s', lambda x: len(pt),
 
275
             'process ID'),
 
276
        user=('User', showuser, '%-8s', lambda x: len(dict.fromkeys(x)),
 
277
              'owner of process'),
 
278
        name=('Name', src.pidname, '%s', None,
 
279
              'name of process'),
 
280
        command=('Command', src.pidcmd, '%s', None,
 
281
                 'process command line'),
 
282
        maps=('Maps',lambda n: pt[n]['maps'], '% 5s', sum,
 
283
              'total number of mappings'),
 
284
        swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum,
 
285
              'amount of swap space consumed (ignoring sharing)'),
 
286
        uss=('USS', lambda n: pt[n]['uss'], '%a', sum,
 
287
             'unique set size'),
 
288
        rss=('RSS', lambda n: pt[n]['rss'], '%a', sum,
 
289
             'resident set size (ignoring sharing)'),
 
290
        pss=('PSS', lambda n: pt[n]['pss'], '%a', sum,
 
291
             'proportional set size (including sharing)'),
 
292
        vss=('VSS', lambda n: pt[n]['size'], '%a', sum,
 
293
             'virtual set size (total virtual memory mapped)'),
 
294
        )
 
295
    columns = options.columns or 'pid user command swap uss pss rss'
 
296
 
 
297
    showtable(list(pt.keys()), fields, columns.split(), options.sort or 'pss')
 
298
 
 
299
def maptotals(pids):
 
300
    totals = {}
 
301
    for pid in pids:
 
302
        if (list(filter(options.processfilter, pid, src.pidname, src.pidcmd)) or
 
303
                list(filter(options.userfilter, pid, pidusername))):
 
304
            continue
 
305
        try:
 
306
            maps = pidmaps(pid)
 
307
            seen = {}
 
308
            for m in maps.keys():
 
309
                name = maps[m]['name']
 
310
                if name not in totals:
 
311
                    t = dict(size=0, rss=0, pss=0, shared_clean=0,
 
312
                             shared_dirty=0, private_clean=0, count=0,
 
313
                             private_dirty=0, referenced=0, swap=0, pids=0)
 
314
                else:
 
315
                    t = totals[name]
 
316
 
 
317
                for k in t:
 
318
                    t[k] += maps[m].get(k, 0)
 
319
                t['count'] += 1
 
320
                if name not in seen:
 
321
                    t['pids'] += 1
 
322
                    seen[name] = 1
 
323
                totals[name] = t
 
324
        except EnvironmentError:
 
325
            continue
 
326
    return totals
 
327
 
 
328
def showmaps():
 
329
    p = src.pids()
 
330
    pt = maptotals(p)
 
331
 
 
332
    fields = dict(
 
333
        map=('Map', lambda n: n, '%-40.40s', len,
 
334
             'mapping name'),
 
335
        count=('Count', lambda n: pt[n]['count'], '% 5s', sum,
 
336
               'number of mappings found'),
 
337
        pids=('PIDs', lambda n: pt[n]['pids'], '% 5s', sum,
 
338
              'number of PIDs using mapping'),
 
339
        swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum,
 
340
              'amount of swap space consumed (ignoring sharing)'),
 
341
        uss=('USS', lambda n: pt[n]['private_clean']
 
342
             + pt[n]['private_dirty'], '% 8a', sum,
 
343
             'unique set size'),
 
344
        rss=('RSS', lambda n: pt[n]['rss'], '% 8a', sum,
 
345
             'resident set size (ignoring sharing)'),
 
346
        pss=('PSS', lambda n: pt[n]['pss'], '% 8a', sum,
 
347
             'proportional set size (including sharing)'),
 
348
        vss=('VSS', lambda n: pt[n]['size'], '% 8a', sum,
 
349
             'virtual set size (total virtual address space mapped)'),
 
350
        avgpss=('AVGPSS', lambda n: int(1.0 * pt[n]['pss']/pt[n]['pids']),
 
351
                '% 8a', sum,
 
352
                'average PSS per PID'),
 
353
        avguss=('AVGUSS', lambda n: int(1.0 * pt[n]['uss']/pt[n]['pids']),
 
354
                '% 8a', sum,
 
355
                'average USS per PID'),
 
356
        avgrss=('AVGRSS', lambda n: int(1.0 * pt[n]['rss']/pt[n]['pids']),
 
357
                '% 8a', sum,
 
358
                'average RSS per PID'),
 
359
        )
 
360
    columns = options.columns or 'map pids avgpss pss'
 
361
 
 
362
    showtable(list(pt.keys()), fields, columns.split(), options.sort or 'pss')
 
363
 
 
364
def usertotals(pids):
 
365
    totals = {}
 
366
    for pid in pids:
 
367
        if (list(filter(options.processfilter, pid, src.pidname, src.pidcmd)) or
 
368
                list(filter(options.userfilter, pid, pidusername))):
 
369
            continue
 
370
        try:
 
371
            maps = pidmaps(pid)
 
372
            if len(maps) == 0:
 
373
                continue
 
374
        except EnvironmentError:
 
375
            continue
 
376
        user = src.piduser(pid)
 
377
        if user not in totals:
 
378
            t = dict(size=0, rss=0, pss=0, shared_clean=0,
 
379
                     shared_dirty=0, private_clean=0, count=0,
 
380
                     private_dirty=0, referenced=0, swap=0)
 
381
        else:
 
382
            t = totals[user]
 
383
 
 
384
        for m in maps.keys():
 
385
            for k in t:
 
386
                t[k] += maps[m].get(k, 0)
 
387
 
 
388
        t['count'] += 1
 
389
        totals[user] = t
 
390
    return totals
 
391
 
 
392
def showusers():
 
393
    p = src.pids()
 
394
    pt = usertotals(p)
 
395
 
 
396
    def showuser(u):
 
397
        if options.numeric:
 
398
            return u
 
399
        return src.username(u)
 
400
 
 
401
    fields = dict(
 
402
        user=('User', showuser, '%-8s', None,
 
403
              'user name or ID'),
 
404
        count=('Count', lambda n: pt[n]['count'], '% 5s', sum,
 
405
               'number of processes'),
 
406
        swap=('Swap',lambda n: pt[n]['swap'], '% 8a', sum,
 
407
              'amount of swapspace consumed (ignoring sharing)'),
 
408
        uss=('USS', lambda n: pt[n]['private_clean']
 
409
             + pt[n]['private_dirty'], '% 8a', sum,
 
410
             'unique set size'),
 
411
        rss=('RSS', lambda n: pt[n]['rss'], '% 8a', sum,
 
412
             'resident set size (ignoring sharing)'),
 
413
        pss=('PSS', lambda n: pt[n]['pss'], '% 8a', sum,
 
414
             'proportional set size (including sharing)'),
 
415
        vss=('VSS', lambda n: pt[n]['pss'], '% 8a', sum,
 
416
             'virtual set size (total virtual memory mapped)'),
 
417
        )
 
418
    columns = options.columns or 'user count swap uss pss rss'
 
419
 
 
420
    showtable(list(pt.keys()), fields, columns.split(), options.sort or 'pss')
 
421
 
 
422
def showsystem():
 
423
    t = totalmem()
 
424
    ki = kernelsize()
 
425
    m = memory()
 
426
 
 
427
    mt = m['memtotal']
 
428
    f = m['memfree']
 
429
 
 
430
    # total amount used by hardware
 
431
    fh = max(t - mt - ki, 0)
 
432
 
 
433
    # total amount mapped into userspace (ie mapped an unmapped pages)
 
434
    u = m['anonpages'] + m['mapped']
 
435
 
 
436
    # total amount allocated by kernel not for userspace
 
437
    kd = mt - f - u
 
438
 
 
439
    # total amount in kernel caches
 
440
    kdc = m['buffers'] + m['sreclaimable'] + (m['cached'] - m['mapped'])
 
441
 
 
442
    l = [("firmware/hardware", fh, 0),
 
443
         ("kernel image", ki, 0),
 
444
         ("kernel dynamic memory", kd, kdc),
 
445
         ("userspace memory", u, m['mapped']),
 
446
         ("free memory", f, f)]
 
447
 
 
448
    fields = dict(
 
449
        order=('Order', lambda n: n, '% 1s', lambda x: '',
 
450
             'hierarchical order'),
 
451
        area=('Area', lambda n: l[n][0], '%-24s', lambda x: '',
 
452
             'memory area'),
 
453
        used=('Used', lambda n: l[n][1], '%10a', sum,
 
454
              'area in use'),
 
455
        cache=('Cache', lambda n: l[n][2], '%10a', sum,
 
456
              'area used as reclaimable cache'),
 
457
        noncache=('Noncache', lambda n: l[n][1] - l[n][2], '%10a', sum,
 
458
              'area not reclaimable'))
 
459
 
 
460
    columns = options.columns or 'area used cache noncache'
 
461
    showtable(list(range(len(l))), fields, columns.split(), options.sort or 'order')
 
462
 
 
463
def showfields(fields, f):
 
464
    if f != list:
 
465
        print("unknown field", f)
 
466
    print("known fields:")
 
467
    for l in sorted(fields.keys()):
 
468
        print("%-8s %s" % (l, fields[l][-1]))
 
469
 
 
470
def showtable(rows, fields, columns, sort):
 
471
    header = ""
 
472
    format = ""
 
473
    formatter = []
 
474
 
 
475
    if sort not in fields:
 
476
            showfields(fields, sort)
 
477
            sys.exit(-1)
 
478
 
 
479
    if options.pie:
 
480
        columns.append(options.pie)
 
481
    if options.bar:
 
482
        columns.append(options.bar)
 
483
 
 
484
    mt = totalmem()
 
485
    st = memory()['swaptotal']
 
486
 
 
487
    for n in columns:
 
488
        if n not in fields:
 
489
            showfields(fields, n)
 
490
            sys.exit(-1)
 
491
 
 
492
        f = fields[n][2]
 
493
        if 'a' in f:
 
494
            if n == 'swap':
 
495
                formatter.append(lambda x: showamount(x, st))
 
496
            else:
 
497
                formatter.append(lambda x: showamount(x, mt))
 
498
            f = f.replace('a', 's')
 
499
        else:
 
500
            formatter.append(lambda x: x)
 
501
        format += f + "\t"
 
502
        header += f % fields[n][0] + "\t"
 
503
 
 
504
    l = []
 
505
    for n in rows:
 
506
        r = [fields[c][1](n) for c in columns]
 
507
        l.append((fields[sort][1](n), r))
 
508
 
 
509
    l.sort(reverse=bool(options.reverse))
 
510
 
 
511
    if options.pie:
 
512
        showpie(l, sort)
 
513
        return
 
514
    elif options.bar:
 
515
        showbar(l, columns, sort)
 
516
        return
 
517
 
 
518
    if not options.no_header:
 
519
        print(header)
 
520
 
 
521
    for k,r in l:
 
522
        print(format % tuple([f(v) for f,v in zip(formatter, r)]))
 
523
 
 
524
    if options.totals:
 
525
        # totals
 
526
        t = []
 
527
        for c in columns:
 
528
            f = fields[c][3]
 
529
            if f:
 
530
                t.append(f([fields[c][1](n) for n in rows]))
 
531
            else:
 
532
                t.append("")
 
533
 
 
534
        print("-" * len(header))
 
535
        print(format % tuple([f(v) for f,v in zip(formatter, t)]))
 
536
 
 
537
def showpie(l, sort):
 
538
    try:
 
539
        import pylab
 
540
    except ImportError:
 
541
        sys.stderr.write("pie chart requires matplotlib\n")
 
542
        sys.exit(-1)
 
543
 
 
544
    if (l[0][0] < l[-1][0]):
 
545
        l.reverse()
 
546
 
 
547
    labels = [r[1][-1] for r in l]
 
548
    values = [r[0] for r in l] # sort field
 
549
 
 
550
    tm = totalmem()
 
551
    s = sum(values)
 
552
    unused = tm - s
 
553
    t = 0
 
554
    while values and (t + values[-1] < (tm * .02) or
 
555
                      values[-1] < (tm * .005)):
 
556
        t += values.pop()
 
557
        labels.pop()
 
558
 
 
559
    if t:
 
560
        values.append(t)
 
561
        labels.append('other')
 
562
 
 
563
    explode = [0] * len(values)
 
564
    if unused > 0:
 
565
        values.insert(0, unused)
 
566
        labels.insert(0, 'unused')
 
567
        explode.insert(0, .05)
 
568
 
 
569
    pylab.figure(1, figsize=(6,6))
 
570
    ax = pylab.axes([0.1, 0.1, 0.8, 0.8])
 
571
    pylab.pie(values, explode = explode, labels=labels,
 
572
              autopct="%.2f%%", shadow=True)
 
573
    pylab.title('%s by %s' % (options.pie, sort))
 
574
    pylab.show()
 
575
 
 
576
def showbar(l, columns, sort):
 
577
    try:
 
578
        import pylab, numpy
 
579
    except ImportError:
 
580
        sys.stderr.write("bar chart requires matplotlib\n")
 
581
        sys.exit(-1)
 
582
 
 
583
    if (l[0][0] < l[-1][0]):
 
584
        l.reverse()
 
585
 
 
586
    rc = []
 
587
    key = []
 
588
    for n in range(len(columns) - 1):
 
589
        try:
 
590
            if columns[n] in 'pid user group'.split():
 
591
                continue
 
592
            float(l[0][1][n])
 
593
            rc.append(n)
 
594
            key.append(columns[n])
 
595
        except:
 
596
            pass
 
597
 
 
598
    width = 1.0 / (len(rc) + 1)
 
599
    offset = width / 2
 
600
 
 
601
    def gc(n):
 
602
        return 'bgrcmyw'[n % 7]
 
603
 
 
604
    pl = []
 
605
    ind = numpy.arange(len(l))
 
606
    for n in range(len(rc)):
 
607
        pl.append(pylab.bar(ind + offset + width * n,
 
608
                             [x[1][rc[n]] for x in l], width, color=gc(n)))
 
609
 
 
610
    #plt.xticks(ind + .5, )
 
611
    pylab.gca().set_xticks(ind + .5)
 
612
    pylab.gca().set_xticklabels([x[1][-1] for x in l], rotation=45)
 
613
    pylab.legend([p[0] for p in pl], key)
 
614
    pylab.show()
 
615
 
 
616
 
 
617
parser = optparse.OptionParser("%prog [options]")
 
618
parser.add_option("-H", "--no-header", action="store_true",
 
619
                  help="disable header line")
 
620
parser.add_option("-c", "--columns", type="str",
 
621
                  help="columns to show")
 
622
parser.add_option("-t", "--totals", action="store_true",
 
623
                  help="show totals")
 
624
 
 
625
parser.add_option("-R", "--realmem", type="str",
 
626
                  help="amount of physical RAM")
 
627
parser.add_option("-K", "--kernel", type="str",
 
628
                  help="path to kernel image")
 
629
 
 
630
parser.add_option("-m", "--mappings", action="store_true",
 
631
                  help="show mappings")
 
632
parser.add_option("-u", "--users", action="store_true",
 
633
                  help="show users")
 
634
parser.add_option("-w", "--system", action="store_true",
 
635
                  help="show whole system")
 
636
 
 
637
parser.add_option("-P", "--processfilter", type="str",
 
638
                  help="process filter regex")
 
639
parser.add_option("-M", "--mapfilter", type="str",
 
640
                  help="map filter regex")
 
641
parser.add_option("-U", "--userfilter", type="str",
 
642
                  help="user filter regex")
 
643
 
 
644
parser.add_option("-n", "--numeric", action="store_true",
 
645
                  help="numeric output")
 
646
parser.add_option("-s", "--sort", type="str",
 
647
                  help="field to sort on")
 
648
parser.add_option("-r", "--reverse", action="store_true",
 
649
                  help="reverse sort")
 
650
 
 
651
parser.add_option("-p", "--percent", action="store_true",
 
652
                  help="show percentage")
 
653
parser.add_option("-k", "--abbreviate", action="store_true",
 
654
                  help="show unit suffixes")
 
655
 
 
656
parser.add_option("", "--pie", type='str',
 
657
                  help="show pie graph")
 
658
parser.add_option("", "--bar", type='str',
 
659
                  help="show bar graph")
 
660
 
 
661
parser.add_option("-S", "--source", type="str",
 
662
                  help="/proc data source")
 
663
 
 
664
 
 
665
defaults = {}
 
666
parser.set_defaults(**defaults)
 
667
(options, args) = parser.parse_args()
 
668
 
 
669
try:
 
670
    src = tardata(options.source)
 
671
except:
 
672
    src = procdata(options.source)
 
673
 
 
674
try:
 
675
    if options.mappings:
 
676
        showmaps()
 
677
    elif options.users:
 
678
        showusers()
 
679
    elif options.system:
 
680
        showsystem()
 
681
    else:
 
682
        showpids()
 
683
except IOError as e:
 
684
    if e.errno == errno.EPIPE:
 
685
        pass
 
686
except KeyboardInterrupt:
 
687
    pass