Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/psutil/__init__.py: 26%

943 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:35 +0000

1# -*- coding: utf-8 -*- 

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"""psutil is a cross-platform library for retrieving information on 

8running processes and system utilization (CPU, memory, disks, network, 

9sensors) in Python. Supported platforms: 

10 

11 - Linux 

12 - Windows 

13 - macOS 

14 - FreeBSD 

15 - OpenBSD 

16 - NetBSD 

17 - Sun Solaris 

18 - AIX 

19 

20Works with Python versions 2.7 and 3.4+. 

21""" 

22 

23from __future__ import division 

24 

25import collections 

26import contextlib 

27import datetime 

28import functools 

29import os 

30import signal 

31import subprocess 

32import sys 

33import threading 

34import time 

35 

36 

37try: 

38 import pwd 

39except ImportError: 

40 pwd = None 

41 

42from . import _common 

43from ._common import AIX 

44from ._common import BSD 

45from ._common import CONN_CLOSE 

46from ._common import CONN_CLOSE_WAIT 

47from ._common import CONN_CLOSING 

48from ._common import CONN_ESTABLISHED 

49from ._common import CONN_FIN_WAIT1 

50from ._common import CONN_FIN_WAIT2 

51from ._common import CONN_LAST_ACK 

52from ._common import CONN_LISTEN 

53from ._common import CONN_NONE 

54from ._common import CONN_SYN_RECV 

55from ._common import CONN_SYN_SENT 

56from ._common import CONN_TIME_WAIT 

57from ._common import FREEBSD # NOQA 

58from ._common import LINUX 

59from ._common import MACOS 

60from ._common import NETBSD # NOQA 

61from ._common import NIC_DUPLEX_FULL 

62from ._common import NIC_DUPLEX_HALF 

63from ._common import NIC_DUPLEX_UNKNOWN 

64from ._common import OPENBSD # NOQA 

65from ._common import OSX # deprecated alias 

66from ._common import POSIX # NOQA 

67from ._common import POWER_TIME_UNKNOWN 

68from ._common import POWER_TIME_UNLIMITED 

69from ._common import STATUS_DEAD 

70from ._common import STATUS_DISK_SLEEP 

71from ._common import STATUS_IDLE 

72from ._common import STATUS_LOCKED 

73from ._common import STATUS_PARKED 

74from ._common import STATUS_RUNNING 

75from ._common import STATUS_SLEEPING 

76from ._common import STATUS_STOPPED 

77from ._common import STATUS_TRACING_STOP 

78from ._common import STATUS_WAITING 

79from ._common import STATUS_WAKING 

80from ._common import STATUS_ZOMBIE 

81from ._common import SUNOS 

82from ._common import WINDOWS 

83from ._common import AccessDenied 

84from ._common import Error 

85from ._common import NoSuchProcess 

86from ._common import TimeoutExpired 

87from ._common import ZombieProcess 

88from ._common import memoize_when_activated 

89from ._common import wrap_numbers as _wrap_numbers 

90from ._compat import PY3 as _PY3 

91from ._compat import PermissionError 

92from ._compat import ProcessLookupError 

93from ._compat import SubprocessTimeoutExpired as _SubprocessTimeoutExpired 

94from ._compat import long 

95 

96 

97if LINUX: 

98 # This is public API and it will be retrieved from _pslinux.py 

99 # via sys.modules. 

100 PROCFS_PATH = "/proc" 

101 

102 from . import _pslinux as _psplatform 

103 from ._pslinux import IOPRIO_CLASS_BE # NOQA 

104 from ._pslinux import IOPRIO_CLASS_IDLE # NOQA 

105 from ._pslinux import IOPRIO_CLASS_NONE # NOQA 

106 from ._pslinux import IOPRIO_CLASS_RT # NOQA 

107 

108elif WINDOWS: 

109 from . import _pswindows as _psplatform 

110 from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS # NOQA 

111 from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS # NOQA 

112 from ._psutil_windows import HIGH_PRIORITY_CLASS # NOQA 

113 from ._psutil_windows import IDLE_PRIORITY_CLASS # NOQA 

114 from ._psutil_windows import NORMAL_PRIORITY_CLASS # NOQA 

115 from ._psutil_windows import REALTIME_PRIORITY_CLASS # NOQA 

116 from ._pswindows import CONN_DELETE_TCB # NOQA 

117 from ._pswindows import IOPRIO_HIGH # NOQA 

118 from ._pswindows import IOPRIO_LOW # NOQA 

119 from ._pswindows import IOPRIO_NORMAL # NOQA 

120 from ._pswindows import IOPRIO_VERYLOW # NOQA 

121 

122elif MACOS: 

123 from . import _psosx as _psplatform 

124 

125elif BSD: 

126 from . import _psbsd as _psplatform 

127 

128elif SUNOS: 

129 from . import _pssunos as _psplatform 

130 from ._pssunos import CONN_BOUND # NOQA 

131 from ._pssunos import CONN_IDLE # NOQA 

132 

133 # This is public writable API which is read from _pslinux.py and 

134 # _pssunos.py via sys.modules. 

135 PROCFS_PATH = "/proc" 

136 

137elif AIX: 

138 from . import _psaix as _psplatform 

139 

140 # This is public API and it will be retrieved from _pslinux.py 

141 # via sys.modules. 

142 PROCFS_PATH = "/proc" 

143 

144else: # pragma: no cover 

145 raise NotImplementedError('platform %s is not supported' % sys.platform) 

146 

147 

148__all__ = [ 

149 # exceptions 

150 "Error", "NoSuchProcess", "ZombieProcess", "AccessDenied", 

151 "TimeoutExpired", 

152 

153 # constants 

154 "version_info", "__version__", 

155 

156 "STATUS_RUNNING", "STATUS_IDLE", "STATUS_SLEEPING", "STATUS_DISK_SLEEP", 

157 "STATUS_STOPPED", "STATUS_TRACING_STOP", "STATUS_ZOMBIE", "STATUS_DEAD", 

158 "STATUS_WAKING", "STATUS_LOCKED", "STATUS_WAITING", "STATUS_LOCKED", 

159 "STATUS_PARKED", 

160 

161 "CONN_ESTABLISHED", "CONN_SYN_SENT", "CONN_SYN_RECV", "CONN_FIN_WAIT1", 

162 "CONN_FIN_WAIT2", "CONN_TIME_WAIT", "CONN_CLOSE", "CONN_CLOSE_WAIT", 

163 "CONN_LAST_ACK", "CONN_LISTEN", "CONN_CLOSING", "CONN_NONE", 

164 # "CONN_IDLE", "CONN_BOUND", 

165 

166 "AF_LINK", 

167 

168 "NIC_DUPLEX_FULL", "NIC_DUPLEX_HALF", "NIC_DUPLEX_UNKNOWN", 

169 

170 "POWER_TIME_UNKNOWN", "POWER_TIME_UNLIMITED", 

171 

172 "BSD", "FREEBSD", "LINUX", "NETBSD", "OPENBSD", "MACOS", "OSX", "POSIX", 

173 "SUNOS", "WINDOWS", "AIX", 

174 

175 # "RLIM_INFINITY", "RLIMIT_AS", "RLIMIT_CORE", "RLIMIT_CPU", "RLIMIT_DATA", 

176 # "RLIMIT_FSIZE", "RLIMIT_LOCKS", "RLIMIT_MEMLOCK", "RLIMIT_NOFILE", 

177 # "RLIMIT_NPROC", "RLIMIT_RSS", "RLIMIT_STACK", "RLIMIT_MSGQUEUE", 

178 # "RLIMIT_NICE", "RLIMIT_RTPRIO", "RLIMIT_RTTIME", "RLIMIT_SIGPENDING", 

179 

180 # classes 

181 "Process", "Popen", 

182 

183 # functions 

184 "pid_exists", "pids", "process_iter", "wait_procs", # proc 

185 "virtual_memory", "swap_memory", # memory 

186 "cpu_times", "cpu_percent", "cpu_times_percent", "cpu_count", # cpu 

187 "cpu_stats", # "cpu_freq", "getloadavg" 

188 "net_io_counters", "net_connections", "net_if_addrs", # network 

189 "net_if_stats", 

190 "disk_io_counters", "disk_partitions", "disk_usage", # disk 

191 # "sensors_temperatures", "sensors_battery", "sensors_fans" # sensors 

192 "users", "boot_time", # others 

193] 

194 

195 

196__all__.extend(_psplatform.__extra__all__) 

197 

198# Linux, FreeBSD 

199if hasattr(_psplatform.Process, "rlimit"): 

200 # Populate global namespace with RLIM* constants. 

201 from . import _psutil_posix 

202 

203 _globals = globals() 

204 _name = None 

205 for _name in dir(_psutil_posix): 

206 if _name.startswith('RLIM') and _name.isupper(): 

207 _globals[_name] = getattr(_psutil_posix, _name) 

208 __all__.append(_name) 

209 del _globals, _name 

210 

211AF_LINK = _psplatform.AF_LINK 

212 

213__author__ = "Giampaolo Rodola'" 

214__version__ = "5.9.5" 

215version_info = tuple([int(num) for num in __version__.split('.')]) 

216 

217_timer = getattr(time, 'monotonic', time.time) 

218_TOTAL_PHYMEM = None 

219_LOWEST_PID = None 

220_SENTINEL = object() 

221 

222# Sanity check in case the user messed up with psutil installation 

223# or did something weird with sys.path. In this case we might end 

224# up importing a python module using a C extension module which 

225# was compiled for a different version of psutil. 

226# We want to prevent that by failing sooner rather than later. 

227# See: https://github.com/giampaolo/psutil/issues/564 

228if (int(__version__.replace('.', '')) != 

229 getattr(_psplatform.cext, 'version', None)): 

230 msg = "version conflict: %r C extension module was built for another " \ 

231 "version of psutil" % _psplatform.cext.__file__ 

232 if hasattr(_psplatform.cext, 'version'): 

233 msg += " (%s instead of %s)" % ( 

234 '.'.join([x for x in str(_psplatform.cext.version)]), __version__) 

235 else: 

236 msg += " (different than %s)" % __version__ 

237 msg += "; you may try to 'pip uninstall psutil', manually remove %s" % ( 

238 getattr(_psplatform.cext, "__file__", 

239 "the existing psutil install directory")) 

240 msg += " or clean the virtual env somehow, then reinstall" 

241 raise ImportError(msg) 

242 

243 

244# ===================================================================== 

245# --- Utils 

246# ===================================================================== 

247 

248 

249if hasattr(_psplatform, 'ppid_map'): 

250 # Faster version (Windows and Linux). 

251 _ppid_map = _psplatform.ppid_map 

252else: # pragma: no cover 

253 def _ppid_map(): 

254 """Return a {pid: ppid, ...} dict for all running processes in 

255 one shot. Used to speed up Process.children(). 

256 """ 

257 ret = {} 

258 for pid in pids(): 

259 try: 

260 ret[pid] = _psplatform.Process(pid).ppid() 

261 except (NoSuchProcess, ZombieProcess): 

262 pass 

263 return ret 

264 

265 

266def _assert_pid_not_reused(fun): 

267 """Decorator which raises NoSuchProcess in case a process is no 

268 longer running or its PID has been reused. 

269 """ 

270 @functools.wraps(fun) 

271 def wrapper(self, *args, **kwargs): 

272 if not self.is_running(): 

273 if self._pid_reused: 

274 msg = "process no longer exists and its PID has been reused" 

275 else: 

276 msg = None 

277 raise NoSuchProcess(self.pid, self._name, msg=msg) 

278 return fun(self, *args, **kwargs) 

279 return wrapper 

280 

281 

282def _pprint_secs(secs): 

283 """Format seconds in a human readable form.""" 

284 now = time.time() 

285 secs_ago = int(now - secs) 

286 if secs_ago < 60 * 60 * 24: 

287 fmt = "%H:%M:%S" 

288 else: 

289 fmt = "%Y-%m-%d %H:%M:%S" 

290 return datetime.datetime.fromtimestamp(secs).strftime(fmt) 

291 

292 

293# ===================================================================== 

294# --- Process class 

295# ===================================================================== 

296 

297 

298class Process(object): 

299 """Represents an OS process with the given PID. 

300 If PID is omitted current process PID (os.getpid()) is used. 

301 Raise NoSuchProcess if PID does not exist. 

302 

303 Note that most of the methods of this class do not make sure 

304 the PID of the process being queried has been reused over time. 

305 That means you might end up retrieving an information referring 

306 to another process in case the original one this instance 

307 refers to is gone in the meantime. 

308 

309 The only exceptions for which process identity is pre-emptively 

310 checked and guaranteed are: 

311 

312 - parent() 

313 - children() 

314 - nice() (set) 

315 - ionice() (set) 

316 - rlimit() (set) 

317 - cpu_affinity (set) 

318 - suspend() 

319 - resume() 

320 - send_signal() 

321 - terminate() 

322 - kill() 

323 

324 To prevent this problem for all other methods you can: 

325 - use is_running() before querying the process 

326 - if you're continuously iterating over a set of Process 

327 instances use process_iter() which pre-emptively checks 

328 process identity for every yielded instance 

329 """ 

330 

331 def __init__(self, pid=None): 

332 self._init(pid) 

333 

334 def _init(self, pid, _ignore_nsp=False): 

335 if pid is None: 

336 pid = os.getpid() 

337 else: 

338 if not _PY3 and not isinstance(pid, (int, long)): 

339 raise TypeError('pid must be an integer (got %r)' % pid) 

340 if pid < 0: 

341 raise ValueError('pid must be a positive integer (got %s)' 

342 % pid) 

343 self._pid = pid 

344 self._name = None 

345 self._exe = None 

346 self._create_time = None 

347 self._gone = False 

348 self._pid_reused = False 

349 self._hash = None 

350 self._lock = threading.RLock() 

351 # used for caching on Windows only (on POSIX ppid may change) 

352 self._ppid = None 

353 # platform-specific modules define an _psplatform.Process 

354 # implementation class 

355 self._proc = _psplatform.Process(pid) 

356 self._last_sys_cpu_times = None 

357 self._last_proc_cpu_times = None 

358 self._exitcode = _SENTINEL 

359 # cache creation time for later use in is_running() method 

360 try: 

361 self.create_time() 

362 except AccessDenied: 

363 # We should never get here as AFAIK we're able to get 

364 # process creation time on all platforms even as a 

365 # limited user. 

366 pass 

367 except ZombieProcess: 

368 # Zombies can still be queried by this class (although 

369 # not always) and pids() return them so just go on. 

370 pass 

371 except NoSuchProcess: 

372 if not _ignore_nsp: 

373 raise NoSuchProcess(pid, msg='process PID not found') 

374 else: 

375 self._gone = True 

376 # This pair is supposed to identify a Process instance 

377 # univocally over time (the PID alone is not enough as 

378 # it might refer to a process whose PID has been reused). 

379 # This will be used later in __eq__() and is_running(). 

380 self._ident = (self.pid, self._create_time) 

381 

382 def __str__(self): 

383 info = collections.OrderedDict() 

384 info["pid"] = self.pid 

385 if self._name: 

386 info['name'] = self._name 

387 with self.oneshot(): 

388 try: 

389 info["name"] = self.name() 

390 info["status"] = self.status() 

391 except ZombieProcess: 

392 info["status"] = "zombie" 

393 except NoSuchProcess: 

394 info["status"] = "terminated" 

395 except AccessDenied: 

396 pass 

397 if self._exitcode not in (_SENTINEL, None): 

398 info["exitcode"] = self._exitcode 

399 if self._create_time: 

400 info['started'] = _pprint_secs(self._create_time) 

401 return "%s.%s(%s)" % ( 

402 self.__class__.__module__, 

403 self.__class__.__name__, 

404 ", ".join(["%s=%r" % (k, v) for k, v in info.items()])) 

405 

406 __repr__ = __str__ 

407 

408 def __eq__(self, other): 

409 # Test for equality with another Process object based 

410 # on PID and creation time. 

411 if not isinstance(other, Process): 

412 return NotImplemented 

413 return self._ident == other._ident 

414 

415 def __ne__(self, other): 

416 return not self == other 

417 

418 def __hash__(self): 

419 if self._hash is None: 

420 self._hash = hash(self._ident) 

421 return self._hash 

422 

423 @property 

424 def pid(self): 

425 """The process PID.""" 

426 return self._pid 

427 

428 # --- utility methods 

429 

430 @contextlib.contextmanager 

431 def oneshot(self): 

432 """Utility context manager which considerably speeds up the 

433 retrieval of multiple process information at the same time. 

434 

435 Internally different process info (e.g. name, ppid, uids, 

436 gids, ...) may be fetched by using the same routine, but 

437 only one information is returned and the others are discarded. 

438 When using this context manager the internal routine is 

439 executed once (in the example below on name()) and the 

440 other info are cached. 

441 

442 The cache is cleared when exiting the context manager block. 

443 The advice is to use this every time you retrieve more than 

444 one information about the process. If you're lucky, you'll 

445 get a hell of a speedup. 

446 

447 >>> import psutil 

448 >>> p = psutil.Process() 

449 >>> with p.oneshot(): 

450 ... p.name() # collect multiple info 

451 ... p.cpu_times() # return cached value 

452 ... p.cpu_percent() # return cached value 

453 ... p.create_time() # return cached value 

454 ... 

455 >>> 

456 """ 

457 with self._lock: 

458 if hasattr(self, "_cache"): 

459 # NOOP: this covers the use case where the user enters the 

460 # context twice: 

461 # 

462 # >>> with p.oneshot(): 

463 # ... with p.oneshot(): 

464 # ... 

465 # 

466 # Also, since as_dict() internally uses oneshot() 

467 # I expect that the code below will be a pretty common 

468 # "mistake" that the user will make, so let's guard 

469 # against that: 

470 # 

471 # >>> with p.oneshot(): 

472 # ... p.as_dict() 

473 # ... 

474 yield 

475 else: 

476 try: 

477 # cached in case cpu_percent() is used 

478 self.cpu_times.cache_activate(self) 

479 # cached in case memory_percent() is used 

480 self.memory_info.cache_activate(self) 

481 # cached in case parent() is used 

482 self.ppid.cache_activate(self) 

483 # cached in case username() is used 

484 if POSIX: 

485 self.uids.cache_activate(self) 

486 # specific implementation cache 

487 self._proc.oneshot_enter() 

488 yield 

489 finally: 

490 self.cpu_times.cache_deactivate(self) 

491 self.memory_info.cache_deactivate(self) 

492 self.ppid.cache_deactivate(self) 

493 if POSIX: 

494 self.uids.cache_deactivate(self) 

495 self._proc.oneshot_exit() 

496 

497 def as_dict(self, attrs=None, ad_value=None): 

498 """Utility method returning process information as a 

499 hashable dictionary. 

500 If *attrs* is specified it must be a list of strings 

501 reflecting available Process class' attribute names 

502 (e.g. ['cpu_times', 'name']) else all public (read 

503 only) attributes are assumed. 

504 *ad_value* is the value which gets assigned in case 

505 AccessDenied or ZombieProcess exception is raised when 

506 retrieving that particular process information. 

507 """ 

508 valid_names = _as_dict_attrnames 

509 if attrs is not None: 

510 if not isinstance(attrs, (list, tuple, set, frozenset)): 

511 raise TypeError("invalid attrs type %s" % type(attrs)) 

512 attrs = set(attrs) 

513 invalid_names = attrs - valid_names 

514 if invalid_names: 

515 raise ValueError("invalid attr name%s %s" % ( 

516 "s" if len(invalid_names) > 1 else "", 

517 ", ".join(map(repr, invalid_names)))) 

518 

519 retdict = {} 

520 ls = attrs or valid_names 

521 with self.oneshot(): 

522 for name in ls: 

523 try: 

524 if name == 'pid': 

525 ret = self.pid 

526 else: 

527 meth = getattr(self, name) 

528 ret = meth() 

529 except (AccessDenied, ZombieProcess): 

530 ret = ad_value 

531 except NotImplementedError: 

532 # in case of not implemented functionality (may happen 

533 # on old or exotic systems) we want to crash only if 

534 # the user explicitly asked for that particular attr 

535 if attrs: 

536 raise 

537 continue 

538 retdict[name] = ret 

539 return retdict 

540 

541 def parent(self): 

542 """Return the parent process as a Process object pre-emptively 

543 checking whether PID has been reused. 

544 If no parent is known return None. 

545 """ 

546 lowest_pid = _LOWEST_PID if _LOWEST_PID is not None else pids()[0] 

547 if self.pid == lowest_pid: 

548 return None 

549 ppid = self.ppid() 

550 if ppid is not None: 

551 ctime = self.create_time() 

552 try: 

553 parent = Process(ppid) 

554 if parent.create_time() <= ctime: 

555 return parent 

556 # ...else ppid has been reused by another process 

557 except NoSuchProcess: 

558 pass 

559 

560 def parents(self): 

561 """Return the parents of this process as a list of Process 

562 instances. If no parents are known return an empty list. 

563 """ 

564 parents = [] 

565 proc = self.parent() 

566 while proc is not None: 

567 parents.append(proc) 

568 proc = proc.parent() 

569 return parents 

570 

571 def is_running(self): 

572 """Return whether this process is running. 

573 It also checks if PID has been reused by another process in 

574 which case return False. 

575 """ 

576 if self._gone or self._pid_reused: 

577 return False 

578 try: 

579 # Checking if PID is alive is not enough as the PID might 

580 # have been reused by another process: we also want to 

581 # verify process identity. 

582 # Process identity / uniqueness over time is guaranteed by 

583 # (PID + creation time) and that is verified in __eq__. 

584 self._pid_reused = self != Process(self.pid) 

585 return not self._pid_reused 

586 except ZombieProcess: 

587 # We should never get here as it's already handled in 

588 # Process.__init__; here just for extra safety. 

589 return True 

590 except NoSuchProcess: 

591 self._gone = True 

592 return False 

593 

594 # --- actual API 

595 

596 @memoize_when_activated 

597 def ppid(self): 

598 """The process parent PID. 

599 On Windows the return value is cached after first call. 

600 """ 

601 # On POSIX we don't want to cache the ppid as it may unexpectedly 

602 # change to 1 (init) in case this process turns into a zombie: 

603 # https://github.com/giampaolo/psutil/issues/321 

604 # http://stackoverflow.com/questions/356722/ 

605 

606 # XXX should we check creation time here rather than in 

607 # Process.parent()? 

608 if POSIX: 

609 return self._proc.ppid() 

610 else: # pragma: no cover 

611 self._ppid = self._ppid or self._proc.ppid() 

612 return self._ppid 

613 

614 def name(self): 

615 """The process name. The return value is cached after first call.""" 

616 # Process name is only cached on Windows as on POSIX it may 

617 # change, see: 

618 # https://github.com/giampaolo/psutil/issues/692 

619 if WINDOWS and self._name is not None: 

620 return self._name 

621 name = self._proc.name() 

622 if POSIX and len(name) >= 15: 

623 # On UNIX the name gets truncated to the first 15 characters. 

624 # If it matches the first part of the cmdline we return that 

625 # one instead because it's usually more explicative. 

626 # Examples are "gnome-keyring-d" vs. "gnome-keyring-daemon". 

627 try: 

628 cmdline = self.cmdline() 

629 except (AccessDenied, ZombieProcess): 

630 # Just pass and return the truncated name: it's better 

631 # than nothing. Note: there are actual cases where a 

632 # zombie process can return a name() but not a 

633 # cmdline(), see: 

634 # https://github.com/giampaolo/psutil/issues/2239 

635 pass 

636 else: 

637 if cmdline: 

638 extended_name = os.path.basename(cmdline[0]) 

639 if extended_name.startswith(name): 

640 name = extended_name 

641 self._name = name 

642 self._proc._name = name 

643 return name 

644 

645 def exe(self): 

646 """The process executable as an absolute path. 

647 May also be an empty string. 

648 The return value is cached after first call. 

649 """ 

650 def guess_it(fallback): 

651 # try to guess exe from cmdline[0] in absence of a native 

652 # exe representation 

653 cmdline = self.cmdline() 

654 if cmdline and hasattr(os, 'access') and hasattr(os, 'X_OK'): 

655 exe = cmdline[0] # the possible exe 

656 # Attempt to guess only in case of an absolute path. 

657 # It is not safe otherwise as the process might have 

658 # changed cwd. 

659 if (os.path.isabs(exe) and 

660 os.path.isfile(exe) and 

661 os.access(exe, os.X_OK)): 

662 return exe 

663 if isinstance(fallback, AccessDenied): 

664 raise fallback 

665 return fallback 

666 

667 if self._exe is None: 

668 try: 

669 exe = self._proc.exe() 

670 except AccessDenied as err: 

671 return guess_it(fallback=err) 

672 else: 

673 if not exe: 

674 # underlying implementation can legitimately return an 

675 # empty string; if that's the case we don't want to 

676 # raise AD while guessing from the cmdline 

677 try: 

678 exe = guess_it(fallback=exe) 

679 except AccessDenied: 

680 pass 

681 self._exe = exe 

682 return self._exe 

683 

684 def cmdline(self): 

685 """The command line this process has been called with.""" 

686 return self._proc.cmdline() 

687 

688 def status(self): 

689 """The process current status as a STATUS_* constant.""" 

690 try: 

691 return self._proc.status() 

692 except ZombieProcess: 

693 return STATUS_ZOMBIE 

694 

695 def username(self): 

696 """The name of the user that owns the process. 

697 On UNIX this is calculated by using *real* process uid. 

698 """ 

699 if POSIX: 

700 if pwd is None: 

701 # might happen if python was installed from sources 

702 raise ImportError( 

703 "requires pwd module shipped with standard python") 

704 real_uid = self.uids().real 

705 try: 

706 return pwd.getpwuid(real_uid).pw_name 

707 except KeyError: 

708 # the uid can't be resolved by the system 

709 return str(real_uid) 

710 else: 

711 return self._proc.username() 

712 

713 def create_time(self): 

714 """The process creation time as a floating point number 

715 expressed in seconds since the epoch. 

716 The return value is cached after first call. 

717 """ 

718 if self._create_time is None: 

719 self._create_time = self._proc.create_time() 

720 return self._create_time 

721 

722 def cwd(self): 

723 """Process current working directory as an absolute path.""" 

724 return self._proc.cwd() 

725 

726 def nice(self, value=None): 

727 """Get or set process niceness (priority).""" 

728 if value is None: 

729 return self._proc.nice_get() 

730 else: 

731 if not self.is_running(): 

732 raise NoSuchProcess(self.pid, self._name) 

733 self._proc.nice_set(value) 

734 

735 if POSIX: 

736 

737 @memoize_when_activated 

738 def uids(self): 

739 """Return process UIDs as a (real, effective, saved) 

740 namedtuple. 

741 """ 

742 return self._proc.uids() 

743 

744 def gids(self): 

745 """Return process GIDs as a (real, effective, saved) 

746 namedtuple. 

747 """ 

748 return self._proc.gids() 

749 

750 def terminal(self): 

751 """The terminal associated with this process, if any, 

752 else None. 

753 """ 

754 return self._proc.terminal() 

755 

756 def num_fds(self): 

757 """Return the number of file descriptors opened by this 

758 process (POSIX only). 

759 """ 

760 return self._proc.num_fds() 

761 

762 # Linux, BSD, AIX and Windows only 

763 if hasattr(_psplatform.Process, "io_counters"): 

764 

765 def io_counters(self): 

766 """Return process I/O statistics as a 

767 (read_count, write_count, read_bytes, write_bytes) 

768 namedtuple. 

769 Those are the number of read/write calls performed and the 

770 amount of bytes read and written by the process. 

771 """ 

772 return self._proc.io_counters() 

773 

774 # Linux and Windows 

775 if hasattr(_psplatform.Process, "ionice_get"): 

776 

777 def ionice(self, ioclass=None, value=None): 

778 """Get or set process I/O niceness (priority). 

779 

780 On Linux *ioclass* is one of the IOPRIO_CLASS_* constants. 

781 *value* is a number which goes from 0 to 7. The higher the 

782 value, the lower the I/O priority of the process. 

783 

784 On Windows only *ioclass* is used and it can be set to 2 

785 (normal), 1 (low) or 0 (very low). 

786 

787 Available on Linux and Windows > Vista only. 

788 """ 

789 if ioclass is None: 

790 if value is not None: 

791 raise ValueError("'ioclass' argument must be specified") 

792 return self._proc.ionice_get() 

793 else: 

794 return self._proc.ionice_set(ioclass, value) 

795 

796 # Linux / FreeBSD only 

797 if hasattr(_psplatform.Process, "rlimit"): 

798 

799 def rlimit(self, resource, limits=None): 

800 """Get or set process resource limits as a (soft, hard) 

801 tuple. 

802 

803 *resource* is one of the RLIMIT_* constants. 

804 *limits* is supposed to be a (soft, hard) tuple. 

805 

806 See "man prlimit" for further info. 

807 Available on Linux and FreeBSD only. 

808 """ 

809 return self._proc.rlimit(resource, limits) 

810 

811 # Windows, Linux and FreeBSD only 

812 if hasattr(_psplatform.Process, "cpu_affinity_get"): 

813 

814 def cpu_affinity(self, cpus=None): 

815 """Get or set process CPU affinity. 

816 If specified, *cpus* must be a list of CPUs for which you 

817 want to set the affinity (e.g. [0, 1]). 

818 If an empty list is passed, all egible CPUs are assumed 

819 (and set). 

820 (Windows, Linux and BSD only). 

821 """ 

822 if cpus is None: 

823 return sorted(set(self._proc.cpu_affinity_get())) 

824 else: 

825 if not cpus: 

826 if hasattr(self._proc, "_get_eligible_cpus"): 

827 cpus = self._proc._get_eligible_cpus() 

828 else: 

829 cpus = tuple(range(len(cpu_times(percpu=True)))) 

830 self._proc.cpu_affinity_set(list(set(cpus))) 

831 

832 # Linux, FreeBSD, SunOS 

833 if hasattr(_psplatform.Process, "cpu_num"): 

834 

835 def cpu_num(self): 

836 """Return what CPU this process is currently running on. 

837 The returned number should be <= psutil.cpu_count() 

838 and <= len(psutil.cpu_percent(percpu=True)). 

839 It may be used in conjunction with 

840 psutil.cpu_percent(percpu=True) to observe the system 

841 workload distributed across CPUs. 

842 """ 

843 return self._proc.cpu_num() 

844 

845 # All platforms has it, but maybe not in the future. 

846 if hasattr(_psplatform.Process, "environ"): 

847 

848 def environ(self): 

849 """The environment variables of the process as a dict. Note: this 

850 might not reflect changes made after the process started. """ 

851 return self._proc.environ() 

852 

853 if WINDOWS: 

854 

855 def num_handles(self): 

856 """Return the number of handles opened by this process 

857 (Windows only). 

858 """ 

859 return self._proc.num_handles() 

860 

861 def num_ctx_switches(self): 

862 """Return the number of voluntary and involuntary context 

863 switches performed by this process. 

864 """ 

865 return self._proc.num_ctx_switches() 

866 

867 def num_threads(self): 

868 """Return the number of threads used by this process.""" 

869 return self._proc.num_threads() 

870 

871 if hasattr(_psplatform.Process, "threads"): 

872 

873 def threads(self): 

874 """Return threads opened by process as a list of 

875 (id, user_time, system_time) namedtuples representing 

876 thread id and thread CPU times (user/system). 

877 On OpenBSD this method requires root access. 

878 """ 

879 return self._proc.threads() 

880 

881 @_assert_pid_not_reused 

882 def children(self, recursive=False): 

883 """Return the children of this process as a list of Process 

884 instances, pre-emptively checking whether PID has been reused. 

885 If *recursive* is True return all the parent descendants. 

886 

887 Example (A == this process): 

888 

889 A ─┐ 

890 

891 ├─ B (child) ─┐ 

892 │ └─ X (grandchild) ─┐ 

893 │ └─ Y (great grandchild) 

894 ├─ C (child) 

895 └─ D (child) 

896 

897 >>> import psutil 

898 >>> p = psutil.Process() 

899 >>> p.children() 

900 B, C, D 

901 >>> p.children(recursive=True) 

902 B, X, Y, C, D 

903 

904 Note that in the example above if process X disappears 

905 process Y won't be listed as the reference to process A 

906 is lost. 

907 """ 

908 ppid_map = _ppid_map() 

909 ret = [] 

910 if not recursive: 

911 for pid, ppid in ppid_map.items(): 

912 if ppid == self.pid: 

913 try: 

914 child = Process(pid) 

915 # if child happens to be older than its parent 

916 # (self) it means child's PID has been reused 

917 if self.create_time() <= child.create_time(): 

918 ret.append(child) 

919 except (NoSuchProcess, ZombieProcess): 

920 pass 

921 else: 

922 # Construct a {pid: [child pids]} dict 

923 reverse_ppid_map = collections.defaultdict(list) 

924 for pid, ppid in ppid_map.items(): 

925 reverse_ppid_map[ppid].append(pid) 

926 # Recursively traverse that dict, starting from self.pid, 

927 # such that we only call Process() on actual children 

928 seen = set() 

929 stack = [self.pid] 

930 while stack: 

931 pid = stack.pop() 

932 if pid in seen: 

933 # Since pids can be reused while the ppid_map is 

934 # constructed, there may be rare instances where 

935 # there's a cycle in the recorded process "tree". 

936 continue 

937 seen.add(pid) 

938 for child_pid in reverse_ppid_map[pid]: 

939 try: 

940 child = Process(child_pid) 

941 # if child happens to be older than its parent 

942 # (self) it means child's PID has been reused 

943 intime = self.create_time() <= child.create_time() 

944 if intime: 

945 ret.append(child) 

946 stack.append(child_pid) 

947 except (NoSuchProcess, ZombieProcess): 

948 pass 

949 return ret 

950 

951 def cpu_percent(self, interval=None): 

952 """Return a float representing the current process CPU 

953 utilization as a percentage. 

954 

955 When *interval* is 0.0 or None (default) compares process times 

956 to system CPU times elapsed since last call, returning 

957 immediately (non-blocking). That means that the first time 

958 this is called it will return a meaningful 0.0 value. 

959 

960 When *interval* is > 0.0 compares process times to system CPU 

961 times elapsed before and after the interval (blocking). 

962 

963 In this case is recommended for accuracy that this function 

964 be called with at least 0.1 seconds between calls. 

965 

966 A value > 100.0 can be returned in case of processes running 

967 multiple threads on different CPU cores. 

968 

969 The returned value is explicitly NOT split evenly between 

970 all available logical CPUs. This means that a busy loop process 

971 running on a system with 2 logical CPUs will be reported as 

972 having 100% CPU utilization instead of 50%. 

973 

974 Examples: 

975 

976 >>> import psutil 

977 >>> p = psutil.Process(os.getpid()) 

978 >>> # blocking 

979 >>> p.cpu_percent(interval=1) 

980 2.0 

981 >>> # non-blocking (percentage since last call) 

982 >>> p.cpu_percent(interval=None) 

983 2.9 

984 >>> 

985 """ 

986 blocking = interval is not None and interval > 0.0 

987 if interval is not None and interval < 0: 

988 raise ValueError("interval is not positive (got %r)" % interval) 

989 num_cpus = cpu_count() or 1 

990 

991 def timer(): 

992 return _timer() * num_cpus 

993 

994 if blocking: 

995 st1 = timer() 

996 pt1 = self._proc.cpu_times() 

997 time.sleep(interval) 

998 st2 = timer() 

999 pt2 = self._proc.cpu_times() 

1000 else: 

1001 st1 = self._last_sys_cpu_times 

1002 pt1 = self._last_proc_cpu_times 

1003 st2 = timer() 

1004 pt2 = self._proc.cpu_times() 

1005 if st1 is None or pt1 is None: 

1006 self._last_sys_cpu_times = st2 

1007 self._last_proc_cpu_times = pt2 

1008 return 0.0 

1009 

1010 delta_proc = (pt2.user - pt1.user) + (pt2.system - pt1.system) 

1011 delta_time = st2 - st1 

1012 # reset values for next call in case of interval == None 

1013 self._last_sys_cpu_times = st2 

1014 self._last_proc_cpu_times = pt2 

1015 

1016 try: 

1017 # This is the utilization split evenly between all CPUs. 

1018 # E.g. a busy loop process on a 2-CPU-cores system at this 

1019 # point is reported as 50% instead of 100%. 

1020 overall_cpus_percent = ((delta_proc / delta_time) * 100) 

1021 except ZeroDivisionError: 

1022 # interval was too low 

1023 return 0.0 

1024 else: 

1025 # Note 1: 

1026 # in order to emulate "top" we multiply the value for the num 

1027 # of CPU cores. This way the busy process will be reported as 

1028 # having 100% (or more) usage. 

1029 # 

1030 # Note 2: 

1031 # taskmgr.exe on Windows differs in that it will show 50% 

1032 # instead. 

1033 # 

1034 # Note 3: 

1035 # a percentage > 100 is legitimate as it can result from a 

1036 # process with multiple threads running on different CPU 

1037 # cores (top does the same), see: 

1038 # http://stackoverflow.com/questions/1032357 

1039 # https://github.com/giampaolo/psutil/issues/474 

1040 single_cpu_percent = overall_cpus_percent * num_cpus 

1041 return round(single_cpu_percent, 1) 

1042 

1043 @memoize_when_activated 

1044 def cpu_times(self): 

1045 """Return a (user, system, children_user, children_system) 

1046 namedtuple representing the accumulated process time, in 

1047 seconds. 

1048 This is similar to os.times() but per-process. 

1049 On macOS and Windows children_user and children_system are 

1050 always set to 0. 

1051 """ 

1052 return self._proc.cpu_times() 

1053 

1054 @memoize_when_activated 

1055 def memory_info(self): 

1056 """Return a namedtuple with variable fields depending on the 

1057 platform, representing memory information about the process. 

1058 

1059 The "portable" fields available on all platforms are `rss` and `vms`. 

1060 

1061 All numbers are expressed in bytes. 

1062 """ 

1063 return self._proc.memory_info() 

1064 

1065 @_common.deprecated_method(replacement="memory_info") 

1066 def memory_info_ex(self): 

1067 return self.memory_info() 

1068 

1069 def memory_full_info(self): 

1070 """This method returns the same information as memory_info(), 

1071 plus, on some platform (Linux, macOS, Windows), also provides 

1072 additional metrics (USS, PSS and swap). 

1073 The additional metrics provide a better representation of actual 

1074 process memory usage. 

1075 

1076 Namely USS is the memory which is unique to a process and which 

1077 would be freed if the process was terminated right now. 

1078 

1079 It does so by passing through the whole process address. 

1080 As such it usually requires higher user privileges than 

1081 memory_info() and is considerably slower. 

1082 """ 

1083 return self._proc.memory_full_info() 

1084 

1085 def memory_percent(self, memtype="rss"): 

1086 """Compare process memory to total physical system memory and 

1087 calculate process memory utilization as a percentage. 

1088 *memtype* argument is a string that dictates what type of 

1089 process memory you want to compare against (defaults to "rss"). 

1090 The list of available strings can be obtained like this: 

1091 

1092 >>> psutil.Process().memory_info()._fields 

1093 ('rss', 'vms', 'shared', 'text', 'lib', 'data', 'dirty', 'uss', 'pss') 

1094 """ 

1095 valid_types = list(_psplatform.pfullmem._fields) 

1096 if memtype not in valid_types: 

1097 raise ValueError("invalid memtype %r; valid types are %r" % ( 

1098 memtype, tuple(valid_types))) 

1099 fun = self.memory_info if memtype in _psplatform.pmem._fields else \ 

1100 self.memory_full_info 

1101 metrics = fun() 

1102 value = getattr(metrics, memtype) 

1103 

1104 # use cached value if available 

1105 total_phymem = _TOTAL_PHYMEM or virtual_memory().total 

1106 if not total_phymem > 0: 

1107 # we should never get here 

1108 raise ValueError( 

1109 "can't calculate process memory percent because " 

1110 "total physical system memory is not positive (%r)" 

1111 % total_phymem) 

1112 return (value / float(total_phymem)) * 100 

1113 

1114 if hasattr(_psplatform.Process, "memory_maps"): 

1115 def memory_maps(self, grouped=True): 

1116 """Return process' mapped memory regions as a list of namedtuples 

1117 whose fields are variable depending on the platform. 

1118 

1119 If *grouped* is True the mapped regions with the same 'path' 

1120 are grouped together and the different memory fields are summed. 

1121 

1122 If *grouped* is False every mapped region is shown as a single 

1123 entity and the namedtuple will also include the mapped region's 

1124 address space ('addr') and permission set ('perms'). 

1125 """ 

1126 it = self._proc.memory_maps() 

1127 if grouped: 

1128 d = {} 

1129 for tupl in it: 

1130 path = tupl[2] 

1131 nums = tupl[3:] 

1132 try: 

1133 d[path] = map(lambda x, y: x + y, d[path], nums) 

1134 except KeyError: 

1135 d[path] = nums 

1136 nt = _psplatform.pmmap_grouped 

1137 return [nt(path, *d[path]) for path in d] # NOQA 

1138 else: 

1139 nt = _psplatform.pmmap_ext 

1140 return [nt(*x) for x in it] 

1141 

1142 def open_files(self): 

1143 """Return files opened by process as a list of 

1144 (path, fd) namedtuples including the absolute file name 

1145 and file descriptor number. 

1146 """ 

1147 return self._proc.open_files() 

1148 

1149 def connections(self, kind='inet'): 

1150 """Return socket connections opened by process as a list of 

1151 (fd, family, type, laddr, raddr, status) namedtuples. 

1152 The *kind* parameter filters for connections that match the 

1153 following criteria: 

1154 

1155 +------------+----------------------------------------------------+ 

1156 | Kind Value | Connections using | 

1157 +------------+----------------------------------------------------+ 

1158 | inet | IPv4 and IPv6 | 

1159 | inet4 | IPv4 | 

1160 | inet6 | IPv6 | 

1161 | tcp | TCP | 

1162 | tcp4 | TCP over IPv4 | 

1163 | tcp6 | TCP over IPv6 | 

1164 | udp | UDP | 

1165 | udp4 | UDP over IPv4 | 

1166 | udp6 | UDP over IPv6 | 

1167 | unix | UNIX socket (both UDP and TCP protocols) | 

1168 | all | the sum of all the possible families and protocols | 

1169 +------------+----------------------------------------------------+ 

1170 """ 

1171 return self._proc.connections(kind) 

1172 

1173 # --- signals 

1174 

1175 if POSIX: 

1176 def _send_signal(self, sig): 

1177 assert not self.pid < 0, self.pid 

1178 if self.pid == 0: 

1179 # see "man 2 kill" 

1180 raise ValueError( 

1181 "preventing sending signal to process with PID 0 as it " 

1182 "would affect every process in the process group of the " 

1183 "calling process (os.getpid()) instead of PID 0") 

1184 try: 

1185 os.kill(self.pid, sig) 

1186 except ProcessLookupError: 

1187 if OPENBSD and pid_exists(self.pid): 

1188 # We do this because os.kill() lies in case of 

1189 # zombie processes. 

1190 raise ZombieProcess(self.pid, self._name, self._ppid) 

1191 else: 

1192 self._gone = True 

1193 raise NoSuchProcess(self.pid, self._name) 

1194 except PermissionError: 

1195 raise AccessDenied(self.pid, self._name) 

1196 

1197 @_assert_pid_not_reused 

1198 def send_signal(self, sig): 

1199 """Send a signal *sig* to process pre-emptively checking 

1200 whether PID has been reused (see signal module constants) . 

1201 On Windows only SIGTERM is valid and is treated as an alias 

1202 for kill(). 

1203 """ 

1204 if POSIX: 

1205 self._send_signal(sig) 

1206 else: # pragma: no cover 

1207 self._proc.send_signal(sig) 

1208 

1209 @_assert_pid_not_reused 

1210 def suspend(self): 

1211 """Suspend process execution with SIGSTOP pre-emptively checking 

1212 whether PID has been reused. 

1213 On Windows this has the effect of suspending all process threads. 

1214 """ 

1215 if POSIX: 

1216 self._send_signal(signal.SIGSTOP) 

1217 else: # pragma: no cover 

1218 self._proc.suspend() 

1219 

1220 @_assert_pid_not_reused 

1221 def resume(self): 

1222 """Resume process execution with SIGCONT pre-emptively checking 

1223 whether PID has been reused. 

1224 On Windows this has the effect of resuming all process threads. 

1225 """ 

1226 if POSIX: 

1227 self._send_signal(signal.SIGCONT) 

1228 else: # pragma: no cover 

1229 self._proc.resume() 

1230 

1231 @_assert_pid_not_reused 

1232 def terminate(self): 

1233 """Terminate the process with SIGTERM pre-emptively checking 

1234 whether PID has been reused. 

1235 On Windows this is an alias for kill(). 

1236 """ 

1237 if POSIX: 

1238 self._send_signal(signal.SIGTERM) 

1239 else: # pragma: no cover 

1240 self._proc.kill() 

1241 

1242 @_assert_pid_not_reused 

1243 def kill(self): 

1244 """Kill the current process with SIGKILL pre-emptively checking 

1245 whether PID has been reused. 

1246 """ 

1247 if POSIX: 

1248 self._send_signal(signal.SIGKILL) 

1249 else: # pragma: no cover 

1250 self._proc.kill() 

1251 

1252 def wait(self, timeout=None): 

1253 """Wait for process to terminate and, if process is a children 

1254 of os.getpid(), also return its exit code, else None. 

1255 On Windows there's no such limitation (exit code is always 

1256 returned). 

1257 

1258 If the process is already terminated immediately return None 

1259 instead of raising NoSuchProcess. 

1260 

1261 If *timeout* (in seconds) is specified and process is still 

1262 alive raise TimeoutExpired. 

1263 

1264 To wait for multiple Process(es) use psutil.wait_procs(). 

1265 """ 

1266 if timeout is not None and not timeout >= 0: 

1267 raise ValueError("timeout must be a positive integer") 

1268 if self._exitcode is not _SENTINEL: 

1269 return self._exitcode 

1270 self._exitcode = self._proc.wait(timeout) 

1271 return self._exitcode 

1272 

1273 

1274# The valid attr names which can be processed by Process.as_dict(). 

1275_as_dict_attrnames = set( 

1276 [x for x in dir(Process) if not x.startswith('_') and x not in 

1277 ['send_signal', 'suspend', 'resume', 'terminate', 'kill', 'wait', 

1278 'is_running', 'as_dict', 'parent', 'parents', 'children', 'rlimit', 

1279 'memory_info_ex', 'oneshot']]) 

1280 

1281 

1282# ===================================================================== 

1283# --- Popen class 

1284# ===================================================================== 

1285 

1286 

1287class Popen(Process): 

1288 """Same as subprocess.Popen, but in addition it provides all 

1289 psutil.Process methods in a single class. 

1290 For the following methods which are common to both classes, psutil 

1291 implementation takes precedence: 

1292 

1293 * send_signal() 

1294 * terminate() 

1295 * kill() 

1296 

1297 This is done in order to avoid killing another process in case its 

1298 PID has been reused, fixing BPO-6973. 

1299 

1300 >>> import psutil 

1301 >>> from subprocess import PIPE 

1302 >>> p = psutil.Popen(["python", "-c", "print 'hi'"], stdout=PIPE) 

1303 >>> p.name() 

1304 'python' 

1305 >>> p.uids() 

1306 user(real=1000, effective=1000, saved=1000) 

1307 >>> p.username() 

1308 'giampaolo' 

1309 >>> p.communicate() 

1310 ('hi\n', None) 

1311 >>> p.terminate() 

1312 >>> p.wait(timeout=2) 

1313 0 

1314 >>> 

1315 """ 

1316 

1317 def __init__(self, *args, **kwargs): 

1318 # Explicitly avoid to raise NoSuchProcess in case the process 

1319 # spawned by subprocess.Popen terminates too quickly, see: 

1320 # https://github.com/giampaolo/psutil/issues/193 

1321 self.__subproc = subprocess.Popen(*args, **kwargs) 

1322 self._init(self.__subproc.pid, _ignore_nsp=True) 

1323 

1324 def __dir__(self): 

1325 return sorted(set(dir(Popen) + dir(subprocess.Popen))) 

1326 

1327 def __enter__(self): 

1328 if hasattr(self.__subproc, '__enter__'): 

1329 self.__subproc.__enter__() 

1330 return self 

1331 

1332 def __exit__(self, *args, **kwargs): 

1333 if hasattr(self.__subproc, '__exit__'): 

1334 return self.__subproc.__exit__(*args, **kwargs) 

1335 else: 

1336 if self.stdout: 

1337 self.stdout.close() 

1338 if self.stderr: 

1339 self.stderr.close() 

1340 try: 

1341 # Flushing a BufferedWriter may raise an error. 

1342 if self.stdin: 

1343 self.stdin.close() 

1344 finally: 

1345 # Wait for the process to terminate, to avoid zombies. 

1346 self.wait() 

1347 

1348 def __getattribute__(self, name): 

1349 try: 

1350 return object.__getattribute__(self, name) 

1351 except AttributeError: 

1352 try: 

1353 return object.__getattribute__(self.__subproc, name) 

1354 except AttributeError: 

1355 raise AttributeError("%s instance has no attribute '%s'" 

1356 % (self.__class__.__name__, name)) 

1357 

1358 def wait(self, timeout=None): 

1359 if self.__subproc.returncode is not None: 

1360 return self.__subproc.returncode 

1361 ret = super(Popen, self).wait(timeout) 

1362 self.__subproc.returncode = ret 

1363 return ret 

1364 

1365 

1366# ===================================================================== 

1367# --- system processes related functions 

1368# ===================================================================== 

1369 

1370 

1371def pids(): 

1372 """Return a list of current running PIDs.""" 

1373 global _LOWEST_PID 

1374 ret = sorted(_psplatform.pids()) 

1375 _LOWEST_PID = ret[0] 

1376 return ret 

1377 

1378 

1379def pid_exists(pid): 

1380 """Return True if given PID exists in the current process list. 

1381 This is faster than doing "pid in psutil.pids()" and 

1382 should be preferred. 

1383 """ 

1384 if pid < 0: 

1385 return False 

1386 elif pid == 0 and POSIX: 

1387 # On POSIX we use os.kill() to determine PID existence. 

1388 # According to "man 2 kill" PID 0 has a special meaning 

1389 # though: it refers to <<every process in the process 

1390 # group of the calling process>> and that is not we want 

1391 # to do here. 

1392 return pid in pids() 

1393 else: 

1394 return _psplatform.pid_exists(pid) 

1395 

1396 

1397_pmap = {} 

1398 

1399 

1400def process_iter(attrs=None, ad_value=None): 

1401 """Return a generator yielding a Process instance for all 

1402 running processes. 

1403 

1404 Every new Process instance is only created once and then cached 

1405 into an internal table which is updated every time this is used. 

1406 

1407 Cached Process instances are checked for identity so that you're 

1408 safe in case a PID has been reused by another process, in which 

1409 case the cached instance is updated. 

1410 

1411 The sorting order in which processes are yielded is based on 

1412 their PIDs. 

1413 

1414 *attrs* and *ad_value* have the same meaning as in 

1415 Process.as_dict(). If *attrs* is specified as_dict() is called 

1416 and the resulting dict is stored as a 'info' attribute attached 

1417 to returned Process instance. 

1418 If *attrs* is an empty list it will retrieve all process info 

1419 (slow). 

1420 """ 

1421 global _pmap 

1422 

1423 def add(pid): 

1424 proc = Process(pid) 

1425 if attrs is not None: 

1426 proc.info = proc.as_dict(attrs=attrs, ad_value=ad_value) 

1427 pmap[proc.pid] = proc 

1428 return proc 

1429 

1430 def remove(pid): 

1431 pmap.pop(pid, None) 

1432 

1433 pmap = _pmap.copy() 

1434 a = set(pids()) 

1435 b = set(pmap.keys()) 

1436 new_pids = a - b 

1437 gone_pids = b - a 

1438 for pid in gone_pids: 

1439 remove(pid) 

1440 try: 

1441 ls = sorted(list(pmap.items()) + list(dict.fromkeys(new_pids).items())) 

1442 for pid, proc in ls: 

1443 try: 

1444 if proc is None: # new process 

1445 yield add(pid) 

1446 else: 

1447 # use is_running() to check whether PID has been 

1448 # reused by another process in which case yield a 

1449 # new Process instance 

1450 if proc.is_running(): 

1451 if attrs is not None: 

1452 proc.info = proc.as_dict( 

1453 attrs=attrs, ad_value=ad_value) 

1454 yield proc 

1455 else: 

1456 yield add(pid) 

1457 except NoSuchProcess: 

1458 remove(pid) 

1459 except AccessDenied: 

1460 # Process creation time can't be determined hence there's 

1461 # no way to tell whether the pid of the cached process 

1462 # has been reused. Just return the cached version. 

1463 if proc is None and pid in pmap: 

1464 try: 

1465 yield pmap[pid] 

1466 except KeyError: 

1467 # If we get here it is likely that 2 threads were 

1468 # using process_iter(). 

1469 pass 

1470 else: 

1471 raise 

1472 finally: 

1473 _pmap = pmap 

1474 

1475 

1476def wait_procs(procs, timeout=None, callback=None): 

1477 """Convenience function which waits for a list of processes to 

1478 terminate. 

1479 

1480 Return a (gone, alive) tuple indicating which processes 

1481 are gone and which ones are still alive. 

1482 

1483 The gone ones will have a new *returncode* attribute indicating 

1484 process exit status (may be None). 

1485 

1486 *callback* is a function which gets called every time a process 

1487 terminates (a Process instance is passed as callback argument). 

1488 

1489 Function will return as soon as all processes terminate or when 

1490 *timeout* occurs. 

1491 Differently from Process.wait() it will not raise TimeoutExpired if 

1492 *timeout* occurs. 

1493 

1494 Typical use case is: 

1495 

1496 - send SIGTERM to a list of processes 

1497 - give them some time to terminate 

1498 - send SIGKILL to those ones which are still alive 

1499 

1500 Example: 

1501 

1502 >>> def on_terminate(proc): 

1503 ... print("process {} terminated".format(proc)) 

1504 ... 

1505 >>> for p in procs: 

1506 ... p.terminate() 

1507 ... 

1508 >>> gone, alive = wait_procs(procs, timeout=3, callback=on_terminate) 

1509 >>> for p in alive: 

1510 ... p.kill() 

1511 """ 

1512 def check_gone(proc, timeout): 

1513 try: 

1514 returncode = proc.wait(timeout=timeout) 

1515 except TimeoutExpired: 

1516 pass 

1517 except _SubprocessTimeoutExpired: 

1518 pass 

1519 else: 

1520 if returncode is not None or not proc.is_running(): 

1521 # Set new Process instance attribute. 

1522 proc.returncode = returncode 

1523 gone.add(proc) 

1524 if callback is not None: 

1525 callback(proc) 

1526 

1527 if timeout is not None and not timeout >= 0: 

1528 msg = "timeout must be a positive integer, got %s" % timeout 

1529 raise ValueError(msg) 

1530 gone = set() 

1531 alive = set(procs) 

1532 if callback is not None and not callable(callback): 

1533 raise TypeError("callback %r is not a callable" % callable) 

1534 if timeout is not None: 

1535 deadline = _timer() + timeout 

1536 

1537 while alive: 

1538 if timeout is not None and timeout <= 0: 

1539 break 

1540 for proc in alive: 

1541 # Make sure that every complete iteration (all processes) 

1542 # will last max 1 sec. 

1543 # We do this because we don't want to wait too long on a 

1544 # single process: in case it terminates too late other 

1545 # processes may disappear in the meantime and their PID 

1546 # reused. 

1547 max_timeout = 1.0 / len(alive) 

1548 if timeout is not None: 

1549 timeout = min((deadline - _timer()), max_timeout) 

1550 if timeout <= 0: 

1551 break 

1552 check_gone(proc, timeout) 

1553 else: 

1554 check_gone(proc, max_timeout) 

1555 alive = alive - gone 

1556 

1557 if alive: 

1558 # Last attempt over processes survived so far. 

1559 # timeout == 0 won't make this function wait any further. 

1560 for proc in alive: 

1561 check_gone(proc, 0) 

1562 alive = alive - gone 

1563 

1564 return (list(gone), list(alive)) 

1565 

1566 

1567# ===================================================================== 

1568# --- CPU related functions 

1569# ===================================================================== 

1570 

1571 

1572def cpu_count(logical=True): 

1573 """Return the number of logical CPUs in the system (same as 

1574 os.cpu_count() in Python 3.4). 

1575 

1576 If *logical* is False return the number of physical cores only 

1577 (e.g. hyper thread CPUs are excluded). 

1578 

1579 Return None if undetermined. 

1580 

1581 The return value is cached after first call. 

1582 If desired cache can be cleared like this: 

1583 

1584 >>> psutil.cpu_count.cache_clear() 

1585 """ 

1586 if logical: 

1587 ret = _psplatform.cpu_count_logical() 

1588 else: 

1589 ret = _psplatform.cpu_count_cores() 

1590 if ret is not None and ret < 1: 

1591 ret = None 

1592 return ret 

1593 

1594 

1595def cpu_times(percpu=False): 

1596 """Return system-wide CPU times as a namedtuple. 

1597 Every CPU time represents the seconds the CPU has spent in the 

1598 given mode. The namedtuple's fields availability varies depending on the 

1599 platform: 

1600 

1601 - user 

1602 - system 

1603 - idle 

1604 - nice (UNIX) 

1605 - iowait (Linux) 

1606 - irq (Linux, FreeBSD) 

1607 - softirq (Linux) 

1608 - steal (Linux >= 2.6.11) 

1609 - guest (Linux >= 2.6.24) 

1610 - guest_nice (Linux >= 3.2.0) 

1611 

1612 When *percpu* is True return a list of namedtuples for each CPU. 

1613 First element of the list refers to first CPU, second element 

1614 to second CPU and so on. 

1615 The order of the list is consistent across calls. 

1616 """ 

1617 if not percpu: 

1618 return _psplatform.cpu_times() 

1619 else: 

1620 return _psplatform.per_cpu_times() 

1621 

1622 

1623try: 

1624 _last_cpu_times = cpu_times() 

1625except Exception: 

1626 # Don't want to crash at import time. 

1627 _last_cpu_times = None 

1628 

1629try: 

1630 _last_per_cpu_times = cpu_times(percpu=True) 

1631except Exception: 

1632 # Don't want to crash at import time. 

1633 _last_per_cpu_times = None 

1634 

1635 

1636def _cpu_tot_time(times): 

1637 """Given a cpu_time() ntuple calculates the total CPU time 

1638 (including idle time). 

1639 """ 

1640 tot = sum(times) 

1641 if LINUX: 

1642 # On Linux guest times are already accounted in "user" or 

1643 # "nice" times, so we subtract them from total. 

1644 # Htop does the same. References: 

1645 # https://github.com/giampaolo/psutil/pull/940 

1646 # http://unix.stackexchange.com/questions/178045 

1647 # https://github.com/torvalds/linux/blob/ 

1648 # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/ 

1649 # cputime.c#L158 

1650 tot -= getattr(times, "guest", 0) # Linux 2.6.24+ 

1651 tot -= getattr(times, "guest_nice", 0) # Linux 3.2.0+ 

1652 return tot 

1653 

1654 

1655def _cpu_busy_time(times): 

1656 """Given a cpu_time() ntuple calculates the busy CPU time. 

1657 We do so by subtracting all idle CPU times. 

1658 """ 

1659 busy = _cpu_tot_time(times) 

1660 busy -= times.idle 

1661 # Linux: "iowait" is time during which the CPU does not do anything 

1662 # (waits for IO to complete). On Linux IO wait is *not* accounted 

1663 # in "idle" time so we subtract it. Htop does the same. 

1664 # References: 

1665 # https://github.com/torvalds/linux/blob/ 

1666 # 447976ef4fd09b1be88b316d1a81553f1aa7cd07/kernel/sched/cputime.c#L244 

1667 busy -= getattr(times, "iowait", 0) 

1668 return busy 

1669 

1670 

1671def _cpu_times_deltas(t1, t2): 

1672 assert t1._fields == t2._fields, (t1, t2) 

1673 field_deltas = [] 

1674 for field in _psplatform.scputimes._fields: 

1675 field_delta = getattr(t2, field) - getattr(t1, field) 

1676 # CPU times are always supposed to increase over time 

1677 # or at least remain the same and that's because time 

1678 # cannot go backwards. 

1679 # Surprisingly sometimes this might not be the case (at 

1680 # least on Windows and Linux), see: 

1681 # https://github.com/giampaolo/psutil/issues/392 

1682 # https://github.com/giampaolo/psutil/issues/645 

1683 # https://github.com/giampaolo/psutil/issues/1210 

1684 # Trim negative deltas to zero to ignore decreasing fields. 

1685 # top does the same. Reference: 

1686 # https://gitlab.com/procps-ng/procps/blob/v3.3.12/top/top.c#L5063 

1687 field_delta = max(0, field_delta) 

1688 field_deltas.append(field_delta) 

1689 return _psplatform.scputimes(*field_deltas) 

1690 

1691 

1692def cpu_percent(interval=None, percpu=False): 

1693 """Return a float representing the current system-wide CPU 

1694 utilization as a percentage. 

1695 

1696 When *interval* is > 0.0 compares system CPU times elapsed before 

1697 and after the interval (blocking). 

1698 

1699 When *interval* is 0.0 or None compares system CPU times elapsed 

1700 since last call or module import, returning immediately (non 

1701 blocking). That means the first time this is called it will 

1702 return a meaningless 0.0 value which you should ignore. 

1703 In this case is recommended for accuracy that this function be 

1704 called with at least 0.1 seconds between calls. 

1705 

1706 When *percpu* is True returns a list of floats representing the 

1707 utilization as a percentage for each CPU. 

1708 First element of the list refers to first CPU, second element 

1709 to second CPU and so on. 

1710 The order of the list is consistent across calls. 

1711 

1712 Examples: 

1713 

1714 >>> # blocking, system-wide 

1715 >>> psutil.cpu_percent(interval=1) 

1716 2.0 

1717 >>> 

1718 >>> # blocking, per-cpu 

1719 >>> psutil.cpu_percent(interval=1, percpu=True) 

1720 [2.0, 1.0] 

1721 >>> 

1722 >>> # non-blocking (percentage since last call) 

1723 >>> psutil.cpu_percent(interval=None) 

1724 2.9 

1725 >>> 

1726 """ 

1727 global _last_cpu_times 

1728 global _last_per_cpu_times 

1729 blocking = interval is not None and interval > 0.0 

1730 if interval is not None and interval < 0: 

1731 raise ValueError("interval is not positive (got %r)" % interval) 

1732 

1733 def calculate(t1, t2): 

1734 times_delta = _cpu_times_deltas(t1, t2) 

1735 all_delta = _cpu_tot_time(times_delta) 

1736 busy_delta = _cpu_busy_time(times_delta) 

1737 

1738 try: 

1739 busy_perc = (busy_delta / all_delta) * 100 

1740 except ZeroDivisionError: 

1741 return 0.0 

1742 else: 

1743 return round(busy_perc, 1) 

1744 

1745 # system-wide usage 

1746 if not percpu: 

1747 if blocking: 

1748 t1 = cpu_times() 

1749 time.sleep(interval) 

1750 else: 

1751 t1 = _last_cpu_times 

1752 if t1 is None: 

1753 # Something bad happened at import time. We'll 

1754 # get a meaningful result on the next call. See: 

1755 # https://github.com/giampaolo/psutil/pull/715 

1756 t1 = cpu_times() 

1757 _last_cpu_times = cpu_times() 

1758 return calculate(t1, _last_cpu_times) 

1759 # per-cpu usage 

1760 else: 

1761 ret = [] 

1762 if blocking: 

1763 tot1 = cpu_times(percpu=True) 

1764 time.sleep(interval) 

1765 else: 

1766 tot1 = _last_per_cpu_times 

1767 if tot1 is None: 

1768 # Something bad happened at import time. We'll 

1769 # get a meaningful result on the next call. See: 

1770 # https://github.com/giampaolo/psutil/pull/715 

1771 tot1 = cpu_times(percpu=True) 

1772 _last_per_cpu_times = cpu_times(percpu=True) 

1773 for t1, t2 in zip(tot1, _last_per_cpu_times): 

1774 ret.append(calculate(t1, t2)) 

1775 return ret 

1776 

1777 

1778# Use separate global vars for cpu_times_percent() so that it's 

1779# independent from cpu_percent() and they can both be used within 

1780# the same program. 

1781_last_cpu_times_2 = _last_cpu_times 

1782_last_per_cpu_times_2 = _last_per_cpu_times 

1783 

1784 

1785def cpu_times_percent(interval=None, percpu=False): 

1786 """Same as cpu_percent() but provides utilization percentages 

1787 for each specific CPU time as is returned by cpu_times(). 

1788 For instance, on Linux we'll get: 

1789 

1790 >>> cpu_times_percent() 

1791 cpupercent(user=4.8, nice=0.0, system=4.8, idle=90.5, iowait=0.0, 

1792 irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0) 

1793 >>> 

1794 

1795 *interval* and *percpu* arguments have the same meaning as in 

1796 cpu_percent(). 

1797 """ 

1798 global _last_cpu_times_2 

1799 global _last_per_cpu_times_2 

1800 blocking = interval is not None and interval > 0.0 

1801 if interval is not None and interval < 0: 

1802 raise ValueError("interval is not positive (got %r)" % interval) 

1803 

1804 def calculate(t1, t2): 

1805 nums = [] 

1806 times_delta = _cpu_times_deltas(t1, t2) 

1807 all_delta = _cpu_tot_time(times_delta) 

1808 # "scale" is the value to multiply each delta with to get percentages. 

1809 # We use "max" to avoid division by zero (if all_delta is 0, then all 

1810 # fields are 0 so percentages will be 0 too. all_delta cannot be a 

1811 # fraction because cpu times are integers) 

1812 scale = 100.0 / max(1, all_delta) 

1813 for field_delta in times_delta: 

1814 field_perc = field_delta * scale 

1815 field_perc = round(field_perc, 1) 

1816 # make sure we don't return negative values or values over 100% 

1817 field_perc = min(max(0.0, field_perc), 100.0) 

1818 nums.append(field_perc) 

1819 return _psplatform.scputimes(*nums) 

1820 

1821 # system-wide usage 

1822 if not percpu: 

1823 if blocking: 

1824 t1 = cpu_times() 

1825 time.sleep(interval) 

1826 else: 

1827 t1 = _last_cpu_times_2 

1828 if t1 is None: 

1829 # Something bad happened at import time. We'll 

1830 # get a meaningful result on the next call. See: 

1831 # https://github.com/giampaolo/psutil/pull/715 

1832 t1 = cpu_times() 

1833 _last_cpu_times_2 = cpu_times() 

1834 return calculate(t1, _last_cpu_times_2) 

1835 # per-cpu usage 

1836 else: 

1837 ret = [] 

1838 if blocking: 

1839 tot1 = cpu_times(percpu=True) 

1840 time.sleep(interval) 

1841 else: 

1842 tot1 = _last_per_cpu_times_2 

1843 if tot1 is None: 

1844 # Something bad happened at import time. We'll 

1845 # get a meaningful result on the next call. See: 

1846 # https://github.com/giampaolo/psutil/pull/715 

1847 tot1 = cpu_times(percpu=True) 

1848 _last_per_cpu_times_2 = cpu_times(percpu=True) 

1849 for t1, t2 in zip(tot1, _last_per_cpu_times_2): 

1850 ret.append(calculate(t1, t2)) 

1851 return ret 

1852 

1853 

1854def cpu_stats(): 

1855 """Return CPU statistics.""" 

1856 return _psplatform.cpu_stats() 

1857 

1858 

1859if hasattr(_psplatform, "cpu_freq"): 

1860 

1861 def cpu_freq(percpu=False): 

1862 """Return CPU frequency as a namedtuple including current, 

1863 min and max frequency expressed in Mhz. 

1864 

1865 If *percpu* is True and the system supports per-cpu frequency 

1866 retrieval (Linux only) a list of frequencies is returned for 

1867 each CPU. If not a list with one element is returned. 

1868 """ 

1869 ret = _psplatform.cpu_freq() 

1870 if percpu: 

1871 return ret 

1872 else: 

1873 num_cpus = float(len(ret)) 

1874 if num_cpus == 0: 

1875 return None 

1876 elif num_cpus == 1: 

1877 return ret[0] 

1878 else: 

1879 currs, mins, maxs = 0.0, 0.0, 0.0 

1880 set_none = False 

1881 for cpu in ret: 

1882 currs += cpu.current 

1883 # On Linux if /proc/cpuinfo is used min/max are set 

1884 # to None. 

1885 if LINUX and cpu.min is None: 

1886 set_none = True 

1887 continue 

1888 mins += cpu.min 

1889 maxs += cpu.max 

1890 

1891 current = currs / num_cpus 

1892 

1893 if set_none: 

1894 min_ = max_ = None 

1895 else: 

1896 min_ = mins / num_cpus 

1897 max_ = maxs / num_cpus 

1898 

1899 return _common.scpufreq(current, min_, max_) 

1900 

1901 __all__.append("cpu_freq") 

1902 

1903 

1904if hasattr(os, "getloadavg") or hasattr(_psplatform, "getloadavg"): 

1905 # Perform this hasattr check once on import time to either use the 

1906 # platform based code or proxy straight from the os module. 

1907 if hasattr(os, "getloadavg"): 

1908 getloadavg = os.getloadavg 

1909 else: 

1910 getloadavg = _psplatform.getloadavg 

1911 

1912 __all__.append("getloadavg") 

1913 

1914 

1915# ===================================================================== 

1916# --- system memory related functions 

1917# ===================================================================== 

1918 

1919 

1920def virtual_memory(): 

1921 """Return statistics about system memory usage as a namedtuple 

1922 including the following fields, expressed in bytes: 

1923 

1924 - total: 

1925 total physical memory available. 

1926 

1927 - available: 

1928 the memory that can be given instantly to processes without the 

1929 system going into swap. 

1930 This is calculated by summing different memory values depending 

1931 on the platform and it is supposed to be used to monitor actual 

1932 memory usage in a cross platform fashion. 

1933 

1934 - percent: 

1935 the percentage usage calculated as (total - available) / total * 100 

1936 

1937 - used: 

1938 memory used, calculated differently depending on the platform and 

1939 designed for informational purposes only: 

1940 macOS: active + wired 

1941 BSD: active + wired + cached 

1942 Linux: total - free 

1943 

1944 - free: 

1945 memory not being used at all (zeroed) that is readily available; 

1946 note that this doesn't reflect the actual memory available 

1947 (use 'available' instead) 

1948 

1949 Platform-specific fields: 

1950 

1951 - active (UNIX): 

1952 memory currently in use or very recently used, and so it is in RAM. 

1953 

1954 - inactive (UNIX): 

1955 memory that is marked as not used. 

1956 

1957 - buffers (BSD, Linux): 

1958 cache for things like file system metadata. 

1959 

1960 - cached (BSD, macOS): 

1961 cache for various things. 

1962 

1963 - wired (macOS, BSD): 

1964 memory that is marked to always stay in RAM. It is never moved to disk. 

1965 

1966 - shared (BSD): 

1967 memory that may be simultaneously accessed by multiple processes. 

1968 

1969 The sum of 'used' and 'available' does not necessarily equal total. 

1970 On Windows 'available' and 'free' are the same. 

1971 """ 

1972 global _TOTAL_PHYMEM 

1973 ret = _psplatform.virtual_memory() 

1974 # cached for later use in Process.memory_percent() 

1975 _TOTAL_PHYMEM = ret.total 

1976 return ret 

1977 

1978 

1979def swap_memory(): 

1980 """Return system swap memory statistics as a namedtuple including 

1981 the following fields: 

1982 

1983 - total: total swap memory in bytes 

1984 - used: used swap memory in bytes 

1985 - free: free swap memory in bytes 

1986 - percent: the percentage usage 

1987 - sin: no. of bytes the system has swapped in from disk (cumulative) 

1988 - sout: no. of bytes the system has swapped out from disk (cumulative) 

1989 

1990 'sin' and 'sout' on Windows are meaningless and always set to 0. 

1991 """ 

1992 return _psplatform.swap_memory() 

1993 

1994 

1995# ===================================================================== 

1996# --- disks/paritions related functions 

1997# ===================================================================== 

1998 

1999 

2000def disk_usage(path): 

2001 """Return disk usage statistics about the given *path* as a 

2002 namedtuple including total, used and free space expressed in bytes 

2003 plus the percentage usage. 

2004 """ 

2005 return _psplatform.disk_usage(path) 

2006 

2007 

2008def disk_partitions(all=False): 

2009 """Return mounted partitions as a list of 

2010 (device, mountpoint, fstype, opts) namedtuple. 

2011 'opts' field is a raw string separated by commas indicating mount 

2012 options which may vary depending on the platform. 

2013 

2014 If *all* parameter is False return physical devices only and ignore 

2015 all others. 

2016 """ 

2017 def pathconf(path, name): 

2018 try: 

2019 return os.pathconf(path, name) 

2020 except (OSError, AttributeError): 

2021 pass 

2022 

2023 ret = _psplatform.disk_partitions(all) 

2024 if POSIX: 

2025 new = [] 

2026 for item in ret: 

2027 nt = item._replace( 

2028 maxfile=pathconf(item.mountpoint, 'PC_NAME_MAX'), 

2029 maxpath=pathconf(item.mountpoint, 'PC_PATH_MAX')) 

2030 new.append(nt) 

2031 return new 

2032 else: 

2033 return ret 

2034 

2035 

2036def disk_io_counters(perdisk=False, nowrap=True): 

2037 """Return system disk I/O statistics as a namedtuple including 

2038 the following fields: 

2039 

2040 - read_count: number of reads 

2041 - write_count: number of writes 

2042 - read_bytes: number of bytes read 

2043 - write_bytes: number of bytes written 

2044 - read_time: time spent reading from disk (in ms) 

2045 - write_time: time spent writing to disk (in ms) 

2046 

2047 Platform specific: 

2048 

2049 - busy_time: (Linux, FreeBSD) time spent doing actual I/Os (in ms) 

2050 - read_merged_count (Linux): number of merged reads 

2051 - write_merged_count (Linux): number of merged writes 

2052 

2053 If *perdisk* is True return the same information for every 

2054 physical disk installed on the system as a dictionary 

2055 with partition names as the keys and the namedtuple 

2056 described above as the values. 

2057 

2058 If *nowrap* is True it detects and adjust the numbers which overflow 

2059 and wrap (restart from 0) and add "old value" to "new value" so that 

2060 the returned numbers will always be increasing or remain the same, 

2061 but never decrease. 

2062 "disk_io_counters.cache_clear()" can be used to invalidate the 

2063 cache. 

2064 

2065 On recent Windows versions 'diskperf -y' command may need to be 

2066 executed first otherwise this function won't find any disk. 

2067 """ 

2068 kwargs = dict(perdisk=perdisk) if LINUX else {} 

2069 rawdict = _psplatform.disk_io_counters(**kwargs) 

2070 if not rawdict: 

2071 return {} if perdisk else None 

2072 if nowrap: 

2073 rawdict = _wrap_numbers(rawdict, 'psutil.disk_io_counters') 

2074 nt = getattr(_psplatform, "sdiskio", _common.sdiskio) 

2075 if perdisk: 

2076 for disk, fields in rawdict.items(): 

2077 rawdict[disk] = nt(*fields) 

2078 return rawdict 

2079 else: 

2080 return nt(*(sum(x) for x in zip(*rawdict.values()))) 

2081 

2082 

2083disk_io_counters.cache_clear = functools.partial( 

2084 _wrap_numbers.cache_clear, 'psutil.disk_io_counters') 

2085disk_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache" 

2086 

2087 

2088# ===================================================================== 

2089# --- network related functions 

2090# ===================================================================== 

2091 

2092 

2093def net_io_counters(pernic=False, nowrap=True): 

2094 """Return network I/O statistics as a namedtuple including 

2095 the following fields: 

2096 

2097 - bytes_sent: number of bytes sent 

2098 - bytes_recv: number of bytes received 

2099 - packets_sent: number of packets sent 

2100 - packets_recv: number of packets received 

2101 - errin: total number of errors while receiving 

2102 - errout: total number of errors while sending 

2103 - dropin: total number of incoming packets which were dropped 

2104 - dropout: total number of outgoing packets which were dropped 

2105 (always 0 on macOS and BSD) 

2106 

2107 If *pernic* is True return the same information for every 

2108 network interface installed on the system as a dictionary 

2109 with network interface names as the keys and the namedtuple 

2110 described above as the values. 

2111 

2112 If *nowrap* is True it detects and adjust the numbers which overflow 

2113 and wrap (restart from 0) and add "old value" to "new value" so that 

2114 the returned numbers will always be increasing or remain the same, 

2115 but never decrease. 

2116 "disk_io_counters.cache_clear()" can be used to invalidate the 

2117 cache. 

2118 """ 

2119 rawdict = _psplatform.net_io_counters() 

2120 if not rawdict: 

2121 return {} if pernic else None 

2122 if nowrap: 

2123 rawdict = _wrap_numbers(rawdict, 'psutil.net_io_counters') 

2124 if pernic: 

2125 for nic, fields in rawdict.items(): 

2126 rawdict[nic] = _common.snetio(*fields) 

2127 return rawdict 

2128 else: 

2129 return _common.snetio(*[sum(x) for x in zip(*rawdict.values())]) 

2130 

2131 

2132net_io_counters.cache_clear = functools.partial( 

2133 _wrap_numbers.cache_clear, 'psutil.net_io_counters') 

2134net_io_counters.cache_clear.__doc__ = "Clears nowrap argument cache" 

2135 

2136 

2137def net_connections(kind='inet'): 

2138 """Return system-wide socket connections as a list of 

2139 (fd, family, type, laddr, raddr, status, pid) namedtuples. 

2140 In case of limited privileges 'fd' and 'pid' may be set to -1 

2141 and None respectively. 

2142 The *kind* parameter filters for connections that fit the 

2143 following criteria: 

2144 

2145 +------------+----------------------------------------------------+ 

2146 | Kind Value | Connections using | 

2147 +------------+----------------------------------------------------+ 

2148 | inet | IPv4 and IPv6 | 

2149 | inet4 | IPv4 | 

2150 | inet6 | IPv6 | 

2151 | tcp | TCP | 

2152 | tcp4 | TCP over IPv4 | 

2153 | tcp6 | TCP over IPv6 | 

2154 | udp | UDP | 

2155 | udp4 | UDP over IPv4 | 

2156 | udp6 | UDP over IPv6 | 

2157 | unix | UNIX socket (both UDP and TCP protocols) | 

2158 | all | the sum of all the possible families and protocols | 

2159 +------------+----------------------------------------------------+ 

2160 

2161 On macOS this function requires root privileges. 

2162 """ 

2163 return _psplatform.net_connections(kind) 

2164 

2165 

2166def net_if_addrs(): 

2167 """Return the addresses associated to each NIC (network interface 

2168 card) installed on the system as a dictionary whose keys are the 

2169 NIC names and value is a list of namedtuples for each address 

2170 assigned to the NIC. Each namedtuple includes 5 fields: 

2171 

2172 - family: can be either socket.AF_INET, socket.AF_INET6 or 

2173 psutil.AF_LINK, which refers to a MAC address. 

2174 - address: is the primary address and it is always set. 

2175 - netmask: and 'broadcast' and 'ptp' may be None. 

2176 - ptp: stands for "point to point" and references the 

2177 destination address on a point to point interface 

2178 (typically a VPN). 

2179 - broadcast: and *ptp* are mutually exclusive. 

2180 

2181 Note: you can have more than one address of the same family 

2182 associated with each interface. 

2183 """ 

2184 has_enums = sys.version_info >= (3, 4) 

2185 if has_enums: 

2186 import socket 

2187 rawlist = _psplatform.net_if_addrs() 

2188 rawlist.sort(key=lambda x: x[1]) # sort by family 

2189 ret = collections.defaultdict(list) 

2190 for name, fam, addr, mask, broadcast, ptp in rawlist: 

2191 if has_enums: 

2192 try: 

2193 fam = socket.AddressFamily(fam) 

2194 except ValueError: 

2195 if WINDOWS and fam == -1: 

2196 fam = _psplatform.AF_LINK 

2197 elif (hasattr(_psplatform, "AF_LINK") and 

2198 _psplatform.AF_LINK == fam): 

2199 # Linux defines AF_LINK as an alias for AF_PACKET. 

2200 # We re-set the family here so that repr(family) 

2201 # will show AF_LINK rather than AF_PACKET 

2202 fam = _psplatform.AF_LINK 

2203 if fam == _psplatform.AF_LINK: 

2204 # The underlying C function may return an incomplete MAC 

2205 # address in which case we fill it with null bytes, see: 

2206 # https://github.com/giampaolo/psutil/issues/786 

2207 separator = ":" if POSIX else "-" 

2208 while addr.count(separator) < 5: 

2209 addr += "%s00" % separator 

2210 ret[name].append(_common.snicaddr(fam, addr, mask, broadcast, ptp)) 

2211 return dict(ret) 

2212 

2213 

2214def net_if_stats(): 

2215 """Return information about each NIC (network interface card) 

2216 installed on the system as a dictionary whose keys are the 

2217 NIC names and value is a namedtuple with the following fields: 

2218 

2219 - isup: whether the interface is up (bool) 

2220 - duplex: can be either NIC_DUPLEX_FULL, NIC_DUPLEX_HALF or 

2221 NIC_DUPLEX_UNKNOWN 

2222 - speed: the NIC speed expressed in mega bits (MB); if it can't 

2223 be determined (e.g. 'localhost') it will be set to 0. 

2224 - mtu: the maximum transmission unit expressed in bytes. 

2225 """ 

2226 return _psplatform.net_if_stats() 

2227 

2228 

2229# ===================================================================== 

2230# --- sensors 

2231# ===================================================================== 

2232 

2233 

2234# Linux, macOS 

2235if hasattr(_psplatform, "sensors_temperatures"): 

2236 

2237 def sensors_temperatures(fahrenheit=False): 

2238 """Return hardware temperatures. Each entry is a namedtuple 

2239 representing a certain hardware sensor (it may be a CPU, an 

2240 hard disk or something else, depending on the OS and its 

2241 configuration). 

2242 All temperatures are expressed in celsius unless *fahrenheit* 

2243 is set to True. 

2244 """ 

2245 def convert(n): 

2246 if n is not None: 

2247 return (float(n) * 9 / 5) + 32 if fahrenheit else n 

2248 

2249 ret = collections.defaultdict(list) 

2250 rawdict = _psplatform.sensors_temperatures() 

2251 

2252 for name, values in rawdict.items(): 

2253 while values: 

2254 label, current, high, critical = values.pop(0) 

2255 current = convert(current) 

2256 high = convert(high) 

2257 critical = convert(critical) 

2258 

2259 if high and not critical: 

2260 critical = high 

2261 elif critical and not high: 

2262 high = critical 

2263 

2264 ret[name].append( 

2265 _common.shwtemp(label, current, high, critical)) 

2266 

2267 return dict(ret) 

2268 

2269 __all__.append("sensors_temperatures") 

2270 

2271 

2272# Linux 

2273if hasattr(_psplatform, "sensors_fans"): 

2274 

2275 def sensors_fans(): 

2276 """Return fans speed. Each entry is a namedtuple 

2277 representing a certain hardware sensor. 

2278 All speed are expressed in RPM (rounds per minute). 

2279 """ 

2280 return _psplatform.sensors_fans() 

2281 

2282 __all__.append("sensors_fans") 

2283 

2284 

2285# Linux, Windows, FreeBSD, macOS 

2286if hasattr(_psplatform, "sensors_battery"): 

2287 

2288 def sensors_battery(): 

2289 """Return battery information. If no battery is installed 

2290 returns None. 

2291 

2292 - percent: battery power left as a percentage. 

2293 - secsleft: a rough approximation of how many seconds are left 

2294 before the battery runs out of power. May be 

2295 POWER_TIME_UNLIMITED or POWER_TIME_UNLIMITED. 

2296 - power_plugged: True if the AC power cable is connected. 

2297 """ 

2298 return _psplatform.sensors_battery() 

2299 

2300 __all__.append("sensors_battery") 

2301 

2302 

2303# ===================================================================== 

2304# --- other system related functions 

2305# ===================================================================== 

2306 

2307 

2308def boot_time(): 

2309 """Return the system boot time expressed in seconds since the epoch.""" 

2310 # Note: we are not caching this because it is subject to 

2311 # system clock updates. 

2312 return _psplatform.boot_time() 

2313 

2314 

2315def users(): 

2316 """Return users currently connected on the system as a list of 

2317 namedtuples including the following fields. 

2318 

2319 - user: the name of the user 

2320 - terminal: the tty or pseudo-tty associated with the user, if any. 

2321 - host: the host name associated with the entry, if any. 

2322 - started: the creation time as a floating point number expressed in 

2323 seconds since the epoch. 

2324 """ 

2325 return _psplatform.users() 

2326 

2327 

2328# ===================================================================== 

2329# --- Windows services 

2330# ===================================================================== 

2331 

2332 

2333if WINDOWS: 

2334 

2335 def win_service_iter(): 

2336 """Return a generator yielding a WindowsService instance for all 

2337 Windows services installed. 

2338 """ 

2339 return _psplatform.win_service_iter() 

2340 

2341 def win_service_get(name): 

2342 """Get a Windows service by *name*. 

2343 Raise NoSuchProcess if no service with such name exists. 

2344 """ 

2345 return _psplatform.win_service_get(name) 

2346 

2347 

2348# ===================================================================== 

2349 

2350 

2351def _set_debug(value): 

2352 """Enable or disable PSUTIL_DEBUG option, which prints debugging 

2353 messages to stderr. 

2354 """ 

2355 import psutil._common 

2356 psutil._common.PSUTIL_DEBUG = bool(value) 

2357 _psplatform.cext.set_debug(bool(value)) 

2358 

2359 

2360def test(): # pragma: no cover 

2361 from ._common import bytes2human 

2362 from ._compat import get_terminal_size 

2363 

2364 today_day = datetime.date.today() 

2365 templ = "%-10s %5s %5s %7s %7s %5s %6s %6s %6s %s" 

2366 attrs = ['pid', 'memory_percent', 'name', 'cmdline', 'cpu_times', 

2367 'create_time', 'memory_info', 'status', 'nice', 'username'] 

2368 print(templ % ("USER", "PID", "%MEM", "VSZ", "RSS", "NICE", # NOQA 

2369 "STATUS", "START", "TIME", "CMDLINE")) 

2370 for p in process_iter(attrs, ad_value=None): 

2371 if p.info['create_time']: 

2372 ctime = datetime.datetime.fromtimestamp(p.info['create_time']) 

2373 if ctime.date() == today_day: 

2374 ctime = ctime.strftime("%H:%M") 

2375 else: 

2376 ctime = ctime.strftime("%b%d") 

2377 else: 

2378 ctime = '' 

2379 if p.info['cpu_times']: 

2380 cputime = time.strftime("%M:%S", 

2381 time.localtime(sum(p.info['cpu_times']))) 

2382 else: 

2383 cputime = '' 

2384 

2385 user = p.info['username'] or '' 

2386 if not user and POSIX: 

2387 try: 

2388 user = p.uids()[0] 

2389 except Error: 

2390 pass 

2391 if user and WINDOWS and '\\' in user: 

2392 user = user.split('\\')[1] 

2393 user = user[:9] 

2394 vms = bytes2human(p.info['memory_info'].vms) if \ 

2395 p.info['memory_info'] is not None else '' 

2396 rss = bytes2human(p.info['memory_info'].rss) if \ 

2397 p.info['memory_info'] is not None else '' 

2398 memp = round(p.info['memory_percent'], 1) if \ 

2399 p.info['memory_percent'] is not None else '' 

2400 nice = int(p.info['nice']) if p.info['nice'] else '' 

2401 if p.info['cmdline']: 

2402 cmdline = ' '.join(p.info['cmdline']) 

2403 else: 

2404 cmdline = p.info['name'] 

2405 status = p.info['status'][:5] if p.info['status'] else '' 

2406 

2407 line = templ % ( 

2408 user[:10], 

2409 p.info['pid'], 

2410 memp, 

2411 vms, 

2412 rss, 

2413 nice, 

2414 status, 

2415 ctime, 

2416 cputime, 

2417 cmdline) 

2418 print(line[:get_terminal_size()[0]]) # NOQA 

2419 

2420 

2421del memoize_when_activated, division 

2422if sys.version_info[0] < 3: 

2423 del num, x 

2424 

2425if __name__ == "__main__": 

2426 test()