psutil

Форк
0
/
top.py 
269 строк · 7.3 Кб
1
#!/usr/bin/env python3
2

3
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
4
# Use of this source code is governed by a BSD-style license that can be
5
# found in the LICENSE file.
6

7
"""A clone of top / htop.
8

9
Author: Giampaolo Rodola' <g.rodola@gmail.com>
10

11
$ python3 scripts/top.py
12
 CPU0  [||||                                    ]  10.9%
13
 CPU1  [|||||                                   ]  13.1%
14
 CPU2  [|||||                                   ]  12.8%
15
 CPU3  [||||                                    ]  11.5%
16
 Mem   [|||||||||||||||||||||||||||||           ]  73.0% 11017M / 15936M
17
 Swap  [                                        ]   1.3%   276M / 20467M
18
 Processes: 347 (sleeping=273, running=1, idle=73)
19
 Load average: 1.10 1.28 1.34  Uptime: 8 days, 21:15:40
20

21
PID    USER       NI   VIRT    RES  CPU%  MEM%     TIME+  NAME
22
5368   giampaol    0   7.2G   4.3G  41.8  27.7  56:34.18  VirtualBox
23
24976  giampaol    0   2.1G 487.2M  18.7   3.1  22:05.16  Web Content
24
22731  giampaol    0   3.2G 596.2M  11.6   3.7  35:04.90  firefox
25
1202   root        0 807.4M 288.5M  10.6   1.8  12:22.12  Xorg
26
22811  giampaol    0   2.8G 741.8M   9.0   4.7   2:26.61  Web Content
27
2590   giampaol    0   2.3G 579.4M   5.5   3.6  28:02.70  compiz
28
22990  giampaol    0   3.0G   1.2G   4.2   7.6   4:30.32  Web Content
29
18412  giampaol    0  90.1M  14.5M   3.5   0.1   0:00.26  python3
30
26971  netdata     0  20.8M   3.9M   2.9   0.0   3:17.14  apps.plugin
31
2421   giampaol    0   3.3G  36.9M   2.3   0.2  57:14.21  pulseaudio
32
...
33
"""
34

35
import datetime
36
import sys
37
import time
38

39

40
try:
41
    import curses
42
except ImportError:
43
    sys.exit('platform not supported')
44

45
import psutil
46
from psutil._common import bytes2human
47

48

49
win = curses.initscr()
50
lineno = 0
51
colors_map = dict(green=3, red=10, yellow=4)
52

53

54
def printl(line, color=None, bold=False, highlight=False):
55
    """A thin wrapper around curses's addstr()."""
56
    global lineno
57
    try:
58
        flags = 0
59
        if color:
60
            flags |= curses.color_pair(colors_map[color])
61
        if bold:
62
            flags |= curses.A_BOLD
63
        if highlight:
64
            line += " " * (win.getmaxyx()[1] - len(line))
65
            flags |= curses.A_STANDOUT
66
        win.addstr(lineno, 0, line, flags)
67
    except curses.error:
68
        lineno = 0
69
        win.refresh()
70
        raise
71
    else:
72
        lineno += 1
73

74

75
# --- /curses stuff
76

77

78
def poll(interval):
79
    # sleep some time
80
    time.sleep(interval)
81
    procs = []
82
    procs_status = {}
83
    for p in psutil.process_iter():
84
        try:
85
            p.dict = p.as_dict([
86
                'username',
87
                'nice',
88
                'memory_info',
89
                'memory_percent',
90
                'cpu_percent',
91
                'cpu_times',
92
                'name',
93
                'status',
94
            ])
95
            try:
96
                procs_status[p.dict['status']] += 1
97
            except KeyError:
98
                procs_status[p.dict['status']] = 1
99
        except psutil.NoSuchProcess:
100
            pass
101
        else:
102
            procs.append(p)
103

104
    # return processes sorted by CPU percent usage
105
    processes = sorted(
106
        procs, key=lambda p: p.dict['cpu_percent'], reverse=True
107
    )
108
    return (processes, procs_status)
109

110

111
def get_color(perc):
112
    if perc <= 30:
113
        return "green"
114
    elif perc <= 80:
115
        return "yellow"
116
    else:
117
        return "red"
118

119

120
def print_header(procs_status, num_procs):
121
    """Print system-related info, above the process list."""
122

123
    def get_dashes(perc):
124
        dashes = "|" * int(float(perc) / 10 * 4)
125
        empty_dashes = " " * (40 - len(dashes))
126
        return dashes, empty_dashes
127

128
    # cpu usage
129
    percs = psutil.cpu_percent(interval=0, percpu=True)
130
    for cpu_num, perc in enumerate(percs):
131
        dashes, empty_dashes = get_dashes(perc)
132
        line = " CPU%-2s [%s%s] %5s%%" % (cpu_num, dashes, empty_dashes, perc)
133
        printl(line, color=get_color(perc))
134

135
    # memory usage
136
    mem = psutil.virtual_memory()
137
    dashes, empty_dashes = get_dashes(mem.percent)
138
    line = " Mem   [%s%s] %5s%% %6s / %s" % (
139
        dashes,
140
        empty_dashes,
141
        mem.percent,
142
        bytes2human(mem.used),
143
        bytes2human(mem.total),
144
    )
145
    printl(line, color=get_color(mem.percent))
146

147
    # swap usage
148
    swap = psutil.swap_memory()
149
    dashes, empty_dashes = get_dashes(swap.percent)
150
    line = " Swap  [%s%s] %5s%% %6s / %s" % (
151
        dashes,
152
        empty_dashes,
153
        swap.percent,
154
        bytes2human(swap.used),
155
        bytes2human(swap.total),
156
    )
157
    printl(line, color=get_color(swap.percent))
158

159
    # processes number and status
160
    st = []
161
    for x, y in procs_status.items():
162
        if y:
163
            st.append("%s=%s" % (x, y))
164
    st.sort(key=lambda x: x[:3] in ('run', 'sle'), reverse=1)
165
    printl(" Processes: %s (%s)" % (num_procs, ', '.join(st)))
166
    # load average, uptime
167
    uptime = datetime.datetime.now() - datetime.datetime.fromtimestamp(
168
        psutil.boot_time()
169
    )
170
    av1, av2, av3 = psutil.getloadavg()
171
    line = " Load average: %.2f %.2f %.2f  Uptime: %s" % (
172
        av1,
173
        av2,
174
        av3,
175
        str(uptime).split('.')[0],
176
    )
177
    printl(line)
178

179

180
def refresh_window(procs, procs_status):
181
    """Print results on screen by using curses."""
182
    curses.endwin()
183
    templ = "%-6s %-8s %4s %6s %6s %5s %5s %9s  %2s"
184
    win.erase()
185
    header = templ % (
186
        "PID",
187
        "USER",
188
        "NI",
189
        "VIRT",
190
        "RES",
191
        "CPU%",
192
        "MEM%",
193
        "TIME+",
194
        "NAME",
195
    )
196
    print_header(procs_status, len(procs))
197
    printl("")
198
    printl(header, bold=True, highlight=True)
199
    for p in procs:
200
        # TIME+ column shows process CPU cumulative time and it
201
        # is expressed as: "mm:ss.ms"
202
        if p.dict['cpu_times'] is not None:
203
            ctime = datetime.timedelta(seconds=sum(p.dict['cpu_times']))
204
            ctime = "%s:%s.%s" % (
205
                ctime.seconds // 60 % 60,
206
                str(ctime.seconds % 60).zfill(2),
207
                str(ctime.microseconds)[:2],
208
            )
209
        else:
210
            ctime = ''
211
        if p.dict['memory_percent'] is not None:
212
            p.dict['memory_percent'] = round(p.dict['memory_percent'], 1)
213
        else:
214
            p.dict['memory_percent'] = ''
215
        if p.dict['cpu_percent'] is None:
216
            p.dict['cpu_percent'] = ''
217
        username = p.dict['username'][:8] if p.dict['username'] else ''
218
        line = templ % (
219
            p.pid,
220
            username,
221
            p.dict['nice'],
222
            bytes2human(getattr(p.dict['memory_info'], 'vms', 0)),
223
            bytes2human(getattr(p.dict['memory_info'], 'rss', 0)),
224
            p.dict['cpu_percent'],
225
            p.dict['memory_percent'],
226
            ctime,
227
            p.dict['name'] or '',
228
        )
229
        try:
230
            printl(line)
231
        except curses.error:
232
            break
233
        win.refresh()
234

235

236
def setup():
237
    curses.start_color()
238
    curses.use_default_colors()
239
    for i in range(curses.COLORS):
240
        curses.init_pair(i + 1, i, -1)
241
    curses.endwin()
242
    win.nodelay(1)
243

244

245
def tear_down():
246
    win.keypad(0)
247
    curses.nocbreak()
248
    curses.echo()
249
    curses.endwin()
250

251

252
def main():
253
    setup()
254
    try:
255
        interval = 0
256
        while True:
257
            if win.getch() == ord('q'):
258
                break
259
            args = poll(interval)
260
            refresh_window(*args)
261
            interval = 1
262
    except (KeyboardInterrupt, SystemExit):
263
        pass
264
    finally:
265
        tear_down()
266

267

268
if __name__ == '__main__':
269
    main()
270

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.